Closed dbasilio closed 2 years ago
For those looking for a workaround to the problem:
it('does not hit a timeout', (done) => {
const wrapper = mount(<MyComponent />)
axe(wrapper.getDOMNode()).then(axeResult => {
expect(axeResult).toHaveNoViolations()
done()
})
jest.advanceTimersByTime(1000)
})
The jest.advanceTimersByTime
will log a console error if fakeTimers is not being used.
@dbasilio I had similar issue. Simply putting jest.useRealTimers();
in the axe test helped.
Interestingly afterEach(() => jest.useRealTimers());
doesn't work.
@dsamburskyi If your jest.useFakeTimers()
call appears in a beforeAll
instead of a beforeEach
then calling jest.useRealTimers()
could make tests non-deterministic depending on the order run. afterEach
runs after the test has completed, so the timeout would have already occurred.
My solution is to just.useRealTimers()
run my axe tests, then call jest.useFakeTimers
within the same test block. Even with jest.useFakeTimers()
in a beforeEach
block, I ran into issues where jest.advanceTimersByTime()
would execute twice and throw off my tests if I did not close out the axe tests with jest.useFakeTimers()
!
This seems to be an issue that is caused by timers in your own code being tested so will close this out unless you know of something we should change in this package itself :)
Thank you for posting the useful workarounds for people Googling to find, appreciated.
Well ideally using fake timers doesn't cause the test to time out. This is an annoying issue to run into and annoying to solve. It points to something being done with timers in this package that is causing that behaviour.
Without my solution posted above (which is a fairly un-intuitive piece of code IMO), you need to isolate a11y tests to a separate test file, or a separate describe block. Both of those are not ideal solutions. The package is jest-axe
but if you use a fairly common jest feature in your other tests this package breaks.
We've added a wrapper function that makes usage seamless in our repo (we have timers: 'modern'
in our config).
export async function axe(...args: Parameters<JestAxe>): ReturnType<JestAxe> {
const [results] = await Promise.all([
jestAxe(...args),
new Promise<void>((resolve) => {
jest.runAllTimers();
resolve();
}),
]);
return results;
}
This works with both real and fake timers, but Jest warns for real timers because runAllTimers
is a noop then. Unfortunately, Jest doesn't appear to expose a way to programmatically detect what type of timers currently are in use. This "worked" as a way to detect fake timers silence the error:
if (jest.getRealSystemTime() !== Date.now()) {
jest.runAllTimers();
}
resolve();
but it's pretty brittle for a variety of reasons. Maybe just exposing a second export that covers the Fake Timers use-case would be the best path forward? I'd be happy to PR that if there's interest. The hardest part of that would be the naming (axeFT
, axeFake
, etc) 🤔.
It looks like this is actually an issue that's introduced by axe-core. axe-core uses setTimeout under the hood.
Here is a simple repro, the test below passes. If you uncomment the
jest.useFakeTimers()
in thebeforeEach
the test will timeout no matter what else you do.Version Details: jest-axe: 4.1.0 jest: 26.6.3 axe-core: 4.1.1