-
Notifications
You must be signed in to change notification settings - Fork 39
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
:active and :hover always returning true since 2.2.10 #119
Comments
2.2.12 does not work for me either |
@Maxim-Mazurok @Waley-Z |
Thanks for looking into this, I was using minimal reproduction from the following issue: jsdom/jsdom#3607 (comment) Unfortunately I don't know how to use nwsapi without jsdom, so I hope that linked repro is fine. Hope this helps, cheers! |
Agreed, can definitely reproduce this with the example from the other ticket: |
Thanks for the reply. I used jsdom as well. |
@Maxim-Mazurok , @Waley-Z, @alopix https://www.w3.org/TR/selectors-4/#the-active-pseudo https://www.w3.org/TR/selectors-4/#the-hover-pseudo As simple examples, please run these lines in the browser console: The result of the last line above will be different since div elements are not focusable, so the console textarea will be the result of querying the active element, since it was the last active element before running the test and it willnot change. My knowledge about what you are trying to achieve in jsdom is scarce. |
I basically just copied the code from the other PR but remember having had this issue in live tests in previous versions. Basically the result of the example code is, that nwsapi reports the button’s background colour to be the value set via the though the button would not be hovered, so it should return the button’s normal non-hover background colour. |
@dperini the JSDOM reproduction code that relies on nwsapi is this: const { JSDOM } = require("jsdom");
const dom = new JSDOM('<div>hello</div>');
const element = dom.window.document.querySelector('div');
console.log('active', element.matches(':active')); I copied it from here: jsdom/jsdom#3610 (comment) Same as in the issue linked above, it logs I think that Hope that this helps to reproduce and narrow down the issue, cheers! |
Actually I recognise it's not very fair to ask you look into other project code to figure this out. So here's just NWSAPI reproduction: <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/src/nwsapi.min.js"></script>
</head>
<body>
<div id="test">test</div>
<script>
const element = NW.Dom.byId("test", document);
const isActive = NW.Dom.match(":active", element);
document.write("isActive: " + isActive);
</script>
</body>
</html> Important note: it will only reproduce the issue (report div as Hope this is more concrete now, cheers! |
@Maxim-Mazurok If every issue had code showing the problem like you did it would be easier for me to invest some time trying to fix it but things are not like that most of the times and it will take too much resources starting like a blind on other's code. Will be back to you soon, hopefully with a solution but most probably with more questions. |
@Maxim-Mazurok First, I see that you are incorrectly using "nwsapi.js" as a standalone library in a browser, you have to invoke the "NW.Dom.install" method to initialize the environment and have "nwsapi.js" replacing the browser original Selector API. This has to be done as follows:
Second, the "NW.Dom.byId" api call returns an array of matching elements and that is following the specifications. Given the above I fixed the sample code you submitted as follow:
The two changes I did to your sample code are the addition of "[0]" at the end of the "NW.Dom.byId" api call, which limit the return value to only one element and I added the correct initialization of the "nwsapi.js" library by adding the "onload" attribute, thus invoking "NW.Dom.install" after the script "load" event is triggered. |
Not really, our original use-case is outside of the browser environment, in NodeJS where we're using JSDOM. The reason why I mentioned the focused console is because that's the way I was able to reproduce the issue in the browser. I couldn't reproduce it in NodeJS because that would involve using JSDOM for
Makes sense! It was working the same with/without |
It doesn't matter whether the element is focusable or not. However, the In any case, it can only be determined inside the event listeners, e.g. MouseEvent.
Ref https://w3c.github.io/uievents/#events-mouseevent-event-order Test case: <!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="target" style="border: 1px solid">
Click Me
</div>
<script>
const sleep = () => new Promise((resolve, reject) => {
setTimeout(resolve, 0);
});
const node = document.getElementById('target');
node.addEventListener('mousedown', async evt => {
const { target, type } = evt;
await sleep();
console.log(`target matches :active on ${type}: ${target.matches(':active')}`); // true
});
node.addEventListener('mouseup', async evt => {
const { target, type } = evt;
await sleep();
console.log(`target matches :active on ${type}: ${target.matches(':active')}`); // false
});
node.addEventListener('click', async evt => {
const { target, type } = evt;
await sleep();
console.log(`target matches :active on ${type}: ${target.matches(':active')}`); // false
});
node.addEventListener('mouseover', async evt => {
const { target, type } = evt;
await sleep();
console.log(`target matches :hover on ${type}: ${target.matches(':hover')}`); // true
});
node.addEventListener('mouseout', async evt => {
const { target, type } = evt;
await sleep();
console.log(`target matches :hover on ${type}: ${target.matches(':hover')}`); // false
});
</script>
</body>
</html> |
I've encountered this bug today while debugging a test case that in my opinion should have been passing but it was not, and I can confirm it's a regression introduced by this commit. In 2.2.9 everything works fine, in 2.2.10 it does not. tl;dr it's a test case in jest using jsdom which under the hood uses nwsapi to calculate computed styles. Test case installs a spreadsheet which defines different styles for element when it's Now I'm no expert in nwsapi code and don't know how to fix it (otherwise than just reverting the commit I mentioned), but since I already spent much time trying to find out why my test was failing when I was certain it should pass, it would be a shame if I did not share my findings on the bug's root cause. When compiling selector, nwsapi partially matches a part of the selector, handles the matched part (by producing some code that will get executed later), "pops" the part from the selector and repeats the process until the selector is empty. When it stumbles upon a selector // it's basically gonna grab "class" attribute of e and check if it matches "hoverable"
if((/(^|\s)hoverable(\s|$)/.test(e.getAttribute("class")))){r=true;} It pops the matched part and begin inspecting selector ":hover" and this leads us to following code: case 'hover':
source = 'hasFocus' in doc && doc.hasFocus() ?
'if((e===s.doc.hoverElement)){' + source + '}' : source;
hasFocus() {
return Boolean(this._lastFocusedElement);
}
Now let's also explain why it works in 2.2.9. The difference lays in the code produced when matching case 'hover':
source = 'hasFocus' in doc && doc.hasFocus() ?
'if((e===s.doc.hoverElement)){' + source + '}' :
'if(false){' + source + '}'; In this case, the value assigned to So to recap: // in 2.2.10 ".hoverable:hover" compiles to following code (whitespaces added by me):
"use strict";
return function Resolver(c, f, x, r) {
var e, n, o;
e = c;
if (/(^|\s)hoverable(\s|$)/.test(e.getAttribute("class"))) {
r = true;
}
return r;
};
//...which returns true because it only checks for ".hoverable" part,
// while in 2.2.9 the same selector compiles to following code:
"use strict";
return function Resolver(c, f, x, r) {
var e, n, o;
e = c;
if (false) {
if (/(^|\s)hoverable(\s|$)/.test(e.getAttribute("class"))) {
r = true;
}
}
return r;
};
// which does not return true because the check for ".hoverable" is not executed To me this points that how nwsapi handles Cheers! |
@JakubJagoda |
Not sure if this is related, but I have modified one of the examples above to reproduce it: <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/src/nwsapi.min.js" onload="NW.Dom.install"></script>
</head>
<body>
<div id="test">test</div>
<script>
const element = NW.Dom.byId("test", document)[0];
const isAutofill = NW.Dom.match(":autofill", element);
document.write("isAutofill: " + isAutofill);
</script>
</body>
</html> Autofill pseudo class: https://developer.mozilla.org/en-US/docs/Web/CSS/:autofill UPD: created separate ticket to track this: #129 |
@JakubJagoda @asamuzaK thank you both for the extensive testing and accompanying explanations. Your help, @alopix and @Maxim-Mazurok contributions and @zuzusik review were much appreciated by me and they will be appreciated by nwsapi users as soon as I get the time to transform them in useful code. |
Hmmm... something went wrong during the process, I have been working too much without sleeping. @JakubJagoda @Maxim-Mazurok @asamuzaK @alopix |
Ok I fixed typos and mangled line in 38e566f |
38e566f#diff-8081ec5523d50813a65b2ec303d10ae06a5ba508866607db3700779f9bb62f07R1146 It should be |
@asamuzaK |
Regression of #99
I can confirm, also see regression in the latest v2.2.12
The text was updated successfully, but these errors were encountered: