New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implemented DOM Node extensions mechanism (closes #749) #795
Implemented DOM Node extensions mechanism (closes #749) #795
Conversation
Wow, it was quick, but unfortunately not on time. We're on code freeze right now, so let's merge it after release, ok? Also, we have a new rule of adding/modifying basic example tests to demonstrate new feature. Can you add such example for |
Of course, I'll switch on the actual tasks now and will add an example later. |
lgtm, meanwhile |
b15426e
to
cc2f714
Compare
✅ Tests for the commit cc2f714 have passed. See details: |
cc2f714
to
e1325a5
Compare
✅ Tests for the commit e1325a5 have passed. See details: |
@inikulin @AlexanderMoskovkin const el1 = Selector('.my-class').extendSnapshot({
prop1: node => ...
});
expect(await el1.prop1).eql(...);
const el2 = el1.extendSnapshot({
prop2: node => ...
})
expect(await el2.prop1).eql(...);
expect(await el2.prop2).eql(...); I.e. we add |
e1325a5
to
5e34753
Compare
❌ Tests for the commit 5e34753 have failed. See details: |
@testcafe-build-bot \retest |
❌ Tests for the commit 5e34753 have failed. See details: |
@testcafe-build-bot \retest |
❌ Tests for the commit 5e34753 have failed. See details: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
\r-
} | ||
|
||
function addSnapshotPropertyShorthands (obj, getSelector, snapshotExtensions) { | ||
var properties = SNAPSHOT_PROPERTIES.concat(snapshotExtensions ? Object.keys(snapshotExtensions) : []); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it's better be rewritten as:
var properties = SNAPSHOT_PROPERTIES;
if (snapshotExtensions)
properties = properties.concat(Object.keys(snapshotExtensions));
@@ -223,7 +237,17 @@ function addFilterMethods (obj, getSelector, SelectorBuilder) { | |||
}; | |||
} | |||
|
|||
function createHierachicalSelector (getSelector, SelectorBuilder, selectorFn, filter, additionalDependencies) { | |||
function addSnapshotExtensionMethods (obj, getSelector, SelectorBuilder) { | |||
obj.extendSnapshot = extensions => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are getting rid of snapshot term in the first place. Maybe we'll rename it to addCustomDomProperty
?
assertObject('extendSnapshot', '"extendSnapshot" option', extensions); | ||
|
||
Object.keys(extensions).forEach(prop => { | ||
assertFunction('extendSnapshot', `extendSnapshot '${prop.replace(/'/g, "\\'")}'`, extensions[prop]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why we need to escape '
in property name here? Also I guess it's better to change text to Snapshot extensions method
or smthg like that
@@ -40,6 +41,12 @@ export default class SelectorExecutor extends ClientFunctionExecutor { | |||
} | |||
} | |||
|
|||
_extendSnapshot (snapshot, node, extensions) { | |||
Object.keys(extensions).forEach(prop => { | |||
snapshot[prop] = extensions[prop](node); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be good to catch errors from extension methods and report them appropriately, e.g.:
`someProp` custom selector DOM property error:
[error text]
.getResult() | ||
.then(result => { | ||
var node = result; | ||
var snapshot = this.replicator.encode(result)[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to pass extensions to replicator and appropriate transformers somehow. If you attach them afterwards, newly added properties will not be processed by replicator and thus circular references will throw errors and you will not be able to encode advanced data types. Also, note that selector can work in counter
and collection
modes: https://github.com/kirovboris/testcafe-phoenix/blob/5e34753e68f732c0ad639f9076c349330422014f/src/client/driver/command-executors/client-functions/selector-executor/filter.js#L101 First one used to calculate .exists
and .count
and the second one is used in chains. Make sure everything works correctly with extensions in this mode.
❌ Tests for the commit 5e34753 have failed. See details: |
5e34753
to
b63632c
Compare
❌ Tests for the commit b63632c have failed. See details: |
@testcafe-build-bot \retest |
❌ Tests for the commit b63632c have failed. See details: |
@testcafe-build-bot \retest |
✅ Tests for the commit b63632c have passed. See details: |
FPR |
As far as I understand your recent changes in the docs, we now use the term snapshot for an object that is explicitly awaited, When talking about DOM node properties accessed by using a selector in general, we say state. Since custom properties can also be accessed through shorthands, we may need to rename the method to Does it make sense? |
Yes, i agree, also |
@@ -244,7 +262,17 @@ function addFilterMethods (obj, getSelector, SelectorBuilder) { | |||
}; | |||
} | |||
|
|||
function addHierachicalSelectors (obj, getSelector, SelectorBuilder) { | |||
function addCustomDomProperty (obj, getSelector, SelectorBuilder) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's wrong naming.
It should be what we are adding to selector object
(as addFilterMethods
). So, it should be like addExtendMethod
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
\r-
@@ -88,8 +90,23 @@ async function getSnapshot (getSelector, callsite) { | |||
return node; | |||
} | |||
|
|||
function addSnapshotPropertyShorthands (obj, getSelector) { | |||
SNAPSHOT_PROPERTIES.forEach(prop => { | |||
function assertSnapshotExtensionOptions (extensions) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've discussed it with @VasilyStrelyaev, he didn't see addCustomDOMProperties
variant. Let's stick with it. Also, make sure that naming is consistent across codebase
@@ -78,6 +78,12 @@ export default { | |||
${escapeHtml(err.errMsg)} | |||
`), | |||
|
|||
[TYPE.uncaughtErrorInSnapshotExtensionCode]: err => markup(err, ` | |||
An error occurred when trying to calculate a custom ${err.property} property: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Custom property of what?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of selector? Don't think so. I have no other thoughts though. Custom DOM element state property?
@kirovboris, whose property is this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we write something like "... custom Selector property <prop>"?
@inikulin
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kirovboris yes
new FunctionTransform() | ||
]); | ||
//Overridable methods | ||
_addReplicatorTransform () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to extract methods this way for replicator, just keep it as is. In selector constructor just create SelectorTransform
and add it to replicator manually.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understood your comment. If I add ClientFunctionTransform
in constructor of the base class ClientFunctionExecutor
, I can't add SelectorTransform
in SelectorExecutor
constructor, because we can't add two transforms with the same type Node
to the replicator.
prop2: node => 'tagName: ' + node.tagName | ||
}); | ||
|
||
expect(await el.prop1).eql(42); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use built-in assertons
ed40d0c
to
541d615
Compare
✅ Tests for the commit 541d615 have passed. See details: |
FPR, we've discussed with @VasilyStrelyaev the name of method and decided to keep |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, lgtm. Just some minor issues left. Also, would you mind adding feature summary?
this.type = 'Node'; | ||
constructor (customDOMProperties) { | ||
this.type = 'Node'; | ||
this.customDOMProperties = customDOMProperties || {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Formatting issue, assignments should be aligned
@@ -78,6 +78,12 @@ export default { | |||
${escapeHtml(err.errMsg)} | |||
`), | |||
|
|||
[TYPE.uncaughtErrorInCustomDOMPropertyCode]: err => markup(err, ` | |||
An error occurred when trying to calculate a custom Selector property ${err.property}: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
custom Selector DOM property
? I guess it's worth enclosing property name into quotes: "${err.property}"
@@ -59,6 +59,13 @@ export function assertNonNullObject (callsiteName, what, value) { | |||
} | |||
} | |||
|
|||
export function assertFunction (callsiteName, what, value) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be implemented already, try to rebase onto latest changes
541d615
to
53d31bb
Compare
So, we can extend a snapshot / //Add the new property 'contentEditable' to the Selector
const el = Selector('.my-el').addCustomDOMProperties({
contentEditable: node => node.contentEditable
});
//Now, we can use it as shorthand property
await t.expect(await el.contentEditable).eql(...);
//Or as a snapshot's property
const snapshot = await el();
await t.expect(await snapshot.contentEditable).eql(...);
//Also we can extend / override custom properties
el = el.addCustomDOMProperties({
contentEditable: node => /*some_new_logic*/,
tabIndex: node => node.tabIndex
}); |
@testcafe-build-bot \retest |
❌ Tests for the commit 53d31bb have failed. See details: |
@testcafe-build-bot \retest |
✅ Tests for the commit 53d31bb have passed. See details: |
FPR |
❌ Tests for the commit 04bd388 have failed. See details: |
@testcafe-build-bot \retest |
✅ Tests for the commit 04bd388 have passed. See details: |
FPR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
…vExpress#795) * Implemented DOM Node extensions mechanism (closes DevExpress#749) * Fixed remarks * Renamed extendSnapshot method * Fixed remark * Fixed remarks * Fixed remarks * Added the possibility of extending non ElementNode snapshots
\cc @inikulin @AlexanderMoskovkin @VasilyStrelyaev