-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Fix descendant selector #1680
Fix descendant selector #1680
Conversation
(Selectors like '.foo div' should not match on `<div className="foo" />`)
e362dd1
to
2d1b097
Compare
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.
This is intentional; if you want to restrict to the children, you'd do .children().find(…)
packages/enzyme/src/selectors.js
Outdated
@@ -334,7 +334,7 @@ function matchDirectChild(nodes, predicate) { | |||
function matchDescendant(nodes, predicate) { | |||
return uniqueReduce( | |||
(matches, node) => matches.concat(treeFilter(node, predicate)), | |||
nodes, | |||
flatten(nodes.map(childrenOfNode)), |
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.
this would be a breaking change.
428f6f5
to
938005f
Compare
@ljharb Ah, I see. I'm glad for the workaround, thanks! ...But, this doesn't match CSS behaviour because the outer div has no ancestor that matches.
Is this a 'breaking change' meaning:
the docs currently just say:
Thanks. |
It already doesn't match CSS behavior because there's both host nodes and Component instances in the tree :-) It's a breaking change meaning, I don't think it's worth accepting it at this time - and I don't think it'd be an improvement. As for |
Ah, I see. I'll close this PR and open one to update the docs then. The component was mapping pseudo-markdown so it could be styled easier: export default class Section extends React.Component {
renderLine(line, index) {
switch (line.slice(0, 2)) {
case "# ":
return <div key={`${index}`} className={"heading"}>{line.slice(2)}</div>
default:
return <div key={`${index}`} className={"paragraph"}>{line}</div>
}
}
render() {
return (
<div className={"section"}>
{this.props.lines.map(this.renderLine)}
</div>
)
}
} The test was: it("should display the expected number of results", () => {
const LINES = [ "# Hello world", "Hello world" ]
const component = shallow(<Section lines={LINES} />)
expect(component.find(".section div").length).toEqual(LINES.length)
}) which I expected to return the inner divs generated by the (I could have used |
Clarify where Enzyme descendant selectors diverge from CSS descendant selectors, referencing enzymejs#1680 .
As discussed in #1700 , there is a bug here, but it needs updating to handle both host-nodes and components first. Next step is a test case to define that behaviour. |
@ReactiveRaven any update on updating the test cases? |
(and now from the correct account) @ljharb Hey sorry, just realised I posted it in #1700 but didn't make it clear here:
So, I need from you an example situation that you are concerned about this change breaking. Then I can turn that into the test case and make sure nothing breaks. |
ahhh thanks for clarifying. In this case, I suspect if you rebase your branch, existing tests will fail if it's indeed breaking. |
c1ebd3a
to
d3fcda2
Compare
I was rebasing off |
d3fcda2
to
d430fb5
Compare
Good news: Now the only failure is a timeout! 🎉 Using the right remote really helps. Bad news: I'm worried the test command might not be running all the tests? The last successful push shows only three tests, and <25% branch coverage - locally, I tried editing a test to deliberately make it fail ( I took a look, and it looks like a |
d430fb5
to
4a8dada
Compare
That's now merged, and I've rebased this one. |
@ljharb Thanks! Looks like you have better luck with timeouts, we have a green tick :) |
4a8dada
to
8593eec
Compare
Yes, I think an additional test that deals with custom components would be helpful. |
OK sure. Can you describe what that test should look like? |
@ReactiveRaven i think just something that's not selecting on just html - ie like |
6a4cfa9
to
40a2ce3
Compare
Thanks; I've tweaked the test a bit; will merge once it passes. |
Thanks 😄 🎉 |
Hello! 👋 We had some tests that were broken by this change. I can see why this was packaged as a patch release, but it is functionally a breaking change. I think ideally the way this should have been handled is:
However it's not a big deal. |
@tvararu if the standard for “breaking” is “made any previously passing tests fail” then a huge class of bugs wouldn’t be able to be fixed. In this case, the tests that failed never should have passed in the first place, and it was a bug that they did. |
@ljharb I want to avoid a debate about the meaning of SEMVER and bugs vs features in software. The fact is that the API changed in a way that is not backwards compatible. It doesn't matter if this was to address an existing bug / an incorrectly documented API; it just is. For what it's worth, jQuery did the same thing by doing a patch release for a backwards incompatible bug fix in one of its functions. That function was being used in that specific incorrect way in the jquery-tabs library, and it ended up breaking the GOV.UK bank holiday page. There's a relevant GitHub issue thread about this on the jQuery project but I can't find it right now. Those are my full thoughts on this issue; I believe that in perspective the impact of this change is quite a lot smaller, and I'm not looking for someone else to blame for why our builds were broken for 2 hours. I was simply suggesting how I think this would have been handled if SEMVER was indeed followed to the letter. All the best. :) |
It definitely matters; because you’re invoking the meaning of semver if you’re claiming it’s a breaking change. Semver is very fuzzy, it does not have a “letter” here - and if it did, the documented api of our selectors was broken, and this fixes it, making it objectively a patch. That it broke your build is actually irrelevant to semver. |
@tvararu Hi! While I agree it sucks that your tests started failing, according to SemVer, this change actually is 'backwards compatible', because it behaves the way the documentation says it should. SemVer refers only to the 'public API', which for Enzyme is defined in the documentation (semver 2.0.0 item 1). The implementation is distinct from the public API, which allows for 'bug fixes' to update incorrect behavior in the implementation (item 6) as long as it does not change the public API. It is not a major change, because the public API has not changed (item 8). In this case, if your project broke as a result of this change, it was depending on an internal implementation detail (in this case, a 🐛, like ljharb says), not the public API as defined by Enzyme's documentation. The easiest way to avoid this in future would be to note when a feature of a project diverges from the stated public API, immediately raise an issue/ticket (or subscribe to/vote on existing ones), then not use that feature in your project so you avoid writing code that depends on a bug. Anyway. Thank you for the excuse to go refresh myself on SemVer, and congrats on the new, more correct, test suite. All the best :) |
@ljharb this is true, but nobody likes having their stuff broken, regardless of the issue. @ReactiveRaven your explanation makes perfect sense. Thank you!
I agree. The reason this didn't happen in this particular situation was that the original code actually contained a typo: // What was written
component.find('.class .another-class');
// What was intended
component.find('.class.another-class'); So we didn't realise we were relying on a bug. Went unnoticed for months before this. I take back my comment about "SEMVER being followed to the letter." Genuinely all the best and carry on the good open sourcing. 👌 |
To be quite honest, we had one or two tests inside @airbnb that suffered from that exact same bug, that this update helped us catch 😌 |
When running against versions of enzyme > 3.3.0, one of the frontend tests fails. The test actually had an error: it was erroneously trying to select a <button class=".o-expandable_cue"> using a ".o-expandable_cue button" selector. This worked in enzyme <= 3.3.0 but was fixed in 3.4.0, in enzymejs/enzyme#1680. See this comment for someone else encountering the same thing: enzymejs/enzyme#1680 (comment) To test, disable the use of package-lock with "npm config set package-lock false", then run "npm install", then "npm test". This will fail without the test to the change and pass with this change. Thanks to @wpears for assistance with this.
When running against versions of enzyme > 3.3.0, one of the frontend tests fails. The test actually had an error: it was erroneously trying to select a <button class=".o-expandable_cue"> using a ".o-expandable_cue button" selector. This worked in enzyme <= 3.3.0 but was fixed in 3.4.0, in enzymejs/enzyme#1680. See this comment for someone else encountering the same thing: enzymejs/enzyme#1680 (comment) To test, disable the use of package-lock with "npm config set package-lock false", then run "npm install", then "npm test". This will fail without the test to the change and pass with this change. Thanks to @wpears for assistance with this.
Given a node like:
a selector like
.find(".test div")
or.find("div div")
unexpectedly matches the outer div, as well as the inner div.The patch uses child nodes of current matches, which excludes the 'parent' match.