{"action":"closed","issue":{"url":"https://api.github.com/repos/DevExpress/testcafe/issues/771","repository_url":"https://api.github.com/repos/DevExpress/testcafe","labels_url":"https://api.github.com/repos/DevExpress/testcafe/issues/771/labels{/name}","comments_url":"https://api.github.com/repos/DevExpress/testcafe/issues/771/comments","events_url":"https://api.github.com/repos/DevExpress/testcafe/issues/771/events","html_url":"https://github.com/DevExpress/testcafe/issues/771","id":175466388,"number":771,"title":"Node snapshot properties shorthands for Selector","user":{"login":"inikulin","id":453071,"avatar_url":"https://avatars.githubusercontent.com/u/453071?v=3","gravatar_id":"","url":"https://api.github.com/users/inikulin","html_url":"https://github.com/inikulin","followers_url":"https://api.github.com/users/inikulin/followers","following_url":"https://api.github.com/users/inikulin/following{/other_user}","gists_url":"https://api.github.com/users/inikulin/gists{/gist_id}","starred_url":"https://api.github.com/users/inikulin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/inikulin/subscriptions","organizations_url":"https://api.github.com/users/inikulin/orgs","repos_url":"https://api.github.com/users/inikulin/repos","events_url":"https://api.github.com/users/inikulin/events{/privacy}","received_events_url":"https://api.github.com/users/inikulin/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/DevExpress/testcafe/labels/API%20MODIFICATION%20LEVEL:%20non-breaking%20changes","name":"API MODIFICATION LEVEL: non-breaking changes","color":"fbca04"},{"url":"https://api.github.com/repos/DevExpress/testcafe/labels/AREA:%20client","name":"AREA: client","color":"fef2c0"},{"url":"https://api.github.com/repos/DevExpress/testcafe/labels/AREA:%20server","name":"AREA: server","color":"fef2c0"},{"url":"https://api.github.com/repos/DevExpress/testcafe/labels/DOCUMENTATION:%20required","name":"DOCUMENTATION: required","color":"006b75"},{"url":"https://api.github.com/repos/DevExpress/testcafe/labels/SYSTEM:%20API","name":"SYSTEM: API","color":"bfe5bf"},{"url":"https://api.github.com/repos/DevExpress/testcafe/labels/TYPE:%20enhancement","name":"TYPE: enhancement","color":"f7c6c7"}],"state":"closed","locked":false,"assignee":{"login":"inikulin","id":453071,"avatar_url":"https://avatars.githubusercontent.com/u/453071?v=3","gravatar_id":"","url":"https://api.github.com/users/inikulin","html_url":"https://github.com/inikulin","followers_url":"https://api.github.com/users/inikulin/followers","following_url":"https://api.github.com/users/inikulin/following{/other_user}","gists_url":"https://api.github.com/users/inikulin/gists{/gist_id}","starred_url":"https://api.github.com/users/inikulin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/inikulin/subscriptions","organizations_url":"https://api.github.com/users/inikulin/orgs","repos_url":"https://api.github.com/users/inikulin/repos","events_url":"https://api.github.com/users/inikulin/events{/privacy}","received_events_url":"https://api.github.com/users/inikulin/received_events","type":"User","site_admin":false},"assignees":[{"login":"inikulin","id":453071,"avatar_url":"https://avatars.githubusercontent.com/u/453071?v=3","gravatar_id":"","url":"https://api.github.com/users/inikulin","html_url":"https://github.com/inikulin","followers_url":"https://api.github.com/users/inikulin/followers","following_url":"https://api.github.com/users/inikulin/following{/other_user}","gists_url":"https://api.github.com/users/inikulin/gists{/gist_id}","starred_url":"https://api.github.com/users/inikulin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/inikulin/subscriptions","organizations_url":"https://api.github.com/users/inikulin/orgs","repos_url":"https://api.github.com/users/inikulin/repos","events_url":"https://api.github.com/users/inikulin/events{/privacy}","received_events_url":"https://api.github.com/users/inikulin/received_events","type":"User","site_admin":false}],"milestone":{"url":"https://api.github.com/repos/DevExpress/testcafe/milestones/13","html_url":"https://github.com/DevExpress/testcafe/milestones/Sprint%20%231","labels_url":"https://api.github.com/repos/DevExpress/testcafe/milestones/13/labels","id":2076588,"number":13,"title":"Sprint #1","description":"","creator":{"login":"AlexanderMoskovkin","id":12047804,"avatar_url":"https://avatars.githubusercontent.com/u/12047804?v=3","gravatar_id":"","url":"https://api.github.com/users/AlexanderMoskovkin","html_url":"https://github.com/AlexanderMoskovkin","followers_url":"https://api.github.com/users/AlexanderMoskovkin/followers","following_url":"https://api.github.com/users/AlexanderMoskovkin/following{/other_user}","gists_url":"https://api.github.com/users/AlexanderMoskovkin/gists{/gist_id}","starred_url":"https://api.github.com/users/AlexanderMoskovkin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AlexanderMoskovkin/subscriptions","organizations_url":"https://api.github.com/users/AlexanderMoskovkin/orgs","repos_url":"https://api.github.com/users/AlexanderMoskovkin/repos","events_url":"https://api.github.com/users/AlexanderMoskovkin/events{/privacy}","received_events_url":"https://api.github.com/users/AlexanderMoskovkin/received_events","type":"User","site_admin":false},"open_issues":9,"closed_issues":3,"state":"open","created_at":"2016-10-18T08:26:28Z","updated_at":"2016-10-24T09:54:36Z","due_on":"2016-11-02T00:00:00Z","closed_at":null},"comments":15,"created_at":"2016-09-07T10:21:28Z","updated_at":"2016-10-24T09:54:36Z","closed_at":"2016-10-24T09:54:36Z","body":"# Feature summary\r\nFor @DevExpress/testcafe-docs \r\n**Important:** We need to update all docs examples to use this approach.\r\n\r\n### Shorthands\r\nIf you need to obtain just single property from snapshot you need to use two assignments:\r\n```js\r\nconst snapshot = await selector();\r\nconst nodeType = snapshot.nodeType;\r\n```\r\nor use awkward single-line expression which is hard to write and read due to lots of parenthesis:\r\n```js\r\nconst nodeType = (await selector()).nodeType;\r\n```\r\n\r\nThis features introduces shorthands - async snapshot property getters on selector itself (and selector promise as well), so now you can write:\r\n```js\r\nconst nodeType = await selector.nodeType;\r\n\r\n// Selector promise has shorthands as well - useful for parametrized selectors\r\nconst nodeType = await selector('someParam').nodeType;\r\n```\r\n\r\nYou can obtain all first-level snapshot properties this way.\r\n\r\n### Dictionary shorthand methods\r\n\r\nSnapshots contain some useful dictionaries: `style`, `attributes`, `boudingClientRect`. But even with shorthands we can't obtain their keys in single expression:\r\n```js\r\nconst width = (await selector.style)['width'];\r\n``` \r\nSo we introduce 3 shorthand methods for this dictionaries: `getStyleProperty`, `getAttribute`, `getBoundingClientRectProperty`:\r\n```js\r\nconst width = await selector.getStyleProperty('width');\r\nconst id = await selector.getAttribute('id');\r\nconst left = await selector.getBoundingClientRectProperty('left');\r\n```\r\n\r\n### hasClass\r\n\r\nIn addition we added `hasClass` method:\r\n```js\r\nif (await selector.hasClass('yo')) {\r\n  ...\r\n}\r\n```\r\n\r\n\r\n# Original proposal \r\n\r\nCurrently, you need to re-select node to get access to it's snapshot properties, so you may end up with awkward constructs which involves `await`, e.g.:\r\n```js\r\ntest('Moving the slider', async t => {\r\n    const initialOffset = (await page.slider.handle()).offsetLeft;\r\n\r\n    await t\r\n        .click(page.triedTestCafeCheckbox)\r\n        .dragToElement(page.slider.handle, page.slider.tick.with({ text: '7' }));\r\n\r\n    const newOffset = (await page.slider.handle()).offsetLeft;\r\n\r\n    expect(newOffset).gt(initialOffset);\r\n});\r\n```\r\n\r\nThe idea is to expose snapshot properties on `Selector` which will return promise for the given propety value (it will execute selector and return required property under the hood), so we will have:\r\n```js\r\ntest('Moving the slider', async t => {\r\n    const initialOffset = await page.slider.handle.offsetLeft;\r\n\r\n    await t\r\n        .click(page.triedTestCafeCheckbox)\r\n        .dragToElement(page.slider.handle, page.slider.tick.with({ text: '7' }));\r\n\r\n    const newOffset = await page.slider.handle.offsetLeft;\r\n\r\n    expect(newOffset).gt(initialOffset);\r\n});\r\n```\r\n\r\n\\cc @DevExpress/testcafe \r\nWhat do you guys think?\r\n\r\n**Update note:**\r\nThis will really play well with [chai-as-promised](http://chaijs.com/plugins/chai-as-promised/) assertions.\r\n\r\n**TODO:**\r\n- [x] Shorthands on selector\r\n- [x] `getStyleProperty`\r\n- [x] `getAttribute`\r\n- [x] `getBoundingClientRectProperty`\r\n- [x] `hasClass`\r\n- [x] Shorthands on selector result promise (parametrized selectors)\r\n- [x] Error for selector not matching any node\r\n- [x] Proper callsites for selector errors (basic and parametrized)"}}
{"actor":{"display_login":"inikulin"}}