I'm not able to use selectors with pseudo classes in a jsdom test environment. Is there any trick to do this or some mandatory configuration?
For example, if I do $("button:hover")
I get the error:
Syntax error, unrecognized expression: unsupported pseudo: hover
And if I do document.querySelectorAll("div.testingDivs:not(:visible)")
I get the error:
unknown pseudo-class selector ':visible'
Here is some code with examples: demo project
I already notice this problem is related to nwsapi plugin. Seems jsdom is not registering the pseudo-classes selectors and I think this should be doing in the file jsdom\lib\jsdom\living\helpers\selectors.js
.
In this file the nwsapi plugin is only initialized and in the nwsapi.js
file the selectors are saved in the property Selectors
. As the nwsapi is only initialized without any selector registered, then the Selectors
are empty all the time and I get the "unknown pseudo-class selector ':visible'
" error message.
I already tried to do this before the Jest test setup:
const _nwsapi = require("nwsapi"),
NW = _nwsapi({
document: window.document,
DOMException: global.DOMException
});
window.NW = {Dom: NW};
require("nwsapi/src/modules/nwsapi-jquery");
And almost worked, the Selectors
were filled with the cases in that file. However, when I use a selector, the jsdom initialize the nwsapi and the Selectors
are set to an empty object again.
My project have that kind of selectors inside a component, not inside a test.
Anyone have a solution for this?
Issue opened: https://github.com/jsdom/jsdom/issues/3477
I found this really helpful link https://levelup.gitconnected.com/when-jsdom-for-testing-ui-its-not-enough-c53a8f8c4638 which says:
Let’s say you have a Slider component and you want to drag one of the handle by some pixels and check that something has changed. You can’t really do it in JSDOM. Cause you can’t really drag your handle. The same for an infinite scroll component. Or testing pseudo states like :hover, :active. You simply can’t. Well. You can…but you should mock everything…and sometimes the result it’s not good enough.
The reason why it’s difficult to test such kind of components it’s pretty simple: the lack of layouting functionality. JSDOM is a pure javascript implementation of the DOM so it’s not even designed to act like a real browser. It’s for doing some unit testing. And it’s great on doing it, it’s fast. But for some special components we need more. We need a real browser. Better if we could have all the three main engines :)
I still believe if JSDOM change the file jsdom\lib\jsdom\living\helpers\selectors.js
to something like this, at least the pseudo classes problem will be resolved:
function initNwsapi(node) {
const { _globalObject, _ownerDocument } = node,
apiResult = nwsapi({
document: _ownerDocument,
DOMException: _globalObject.DOMException
});
require("nwsapi/src/modules/nwsapi-jquery");
return apiResult;
}
Anyway, some other problems remain.
So I tried to change the selector by removing the pseudo class and search for a class like "isHovered
". Remembering that the selector is being used inside a component, not inside a test.
In some cases, that class exists in another elements not ":hover
" so I tried to bind a focus
event and a mouseover
event to that element and add class like "thisIsReallyHovered
". But this didn't work well and I also tried to use document.activeElement
but without greater success.
So like suggested the that article, I searched a bit about other kinds of test environments, like: Selenium, Puppeteer, Playwright, Cypress...
I tried to implement Puppeteer at my project with jest, but I found other problems.
So, since (in my case) the implementation of this kind of test environment is not desirable, we agree to re-think the test to avoid that part of the code, until our code migration be completed and we change that component, implementing only unit tests.