jest-react-hooks-shallow
jest-react-hooks-shallow copied to clipboard
withHooks and withoutHooks do not support async tests / promises
Thanks for this package. I'm currently trying to get this to work with an async test, but that doesn't seem to be supported yet. Could this be added?
Example usage:
it('does something async', async () => {
await withHooks(async () => {
const wrapper = shallow(<App />);
await something();
});
});
I'm currently using this as a workaround:
export default function withHooksAsync(test: () => Promise<void>): Promise<void> {
return new Promise<void>((resolve, reject) => {
withHooks(() => {
test().then(resolve).catch(reject);
});
});
}
Hi @d-luk ,
Thanks for reporting this. I'll have a look!
Did you by any chance found a solution for this? I'm stuck at the same problem.
Hi @dunklesToast ,
Sorry, I've been busy with work. I'll have a look at it tonight.
Okay awesome. I tried to understand the library yesterday to create a Pull Request but unfortunately did not :( If you could also add some comments that would be awesome 👍🏻
@d-luk , @dunklesToast ,
Could you possibly provide a more specific example that outlines:
- expected behaviour
- actual behaviour / error, if any
@d-luk,
Looking at your code snippet, it's hard to say what was expected and what went wrong. I tried a similar example - and it worked.
Hey!
I’ll send you the snippet tomorrow. It could also be that I have a wrong understanding of what this library does but I guess we’ll see tomorrow
So let's say you've got this component:
import React, { useEffect, useState } from 'react';
function someAsyncCode() {
return new Promise((resolve) =>
setTimeout(() => {
console.log('Resolving');
resolve(true);
}, 3000)
);
}
export default function Test(): JSX.Element {
const [text, setText] = useState('Not Effected');
useEffect(() => {
someAsyncCode().then(() => {
console.log('Hooked');
setText('Effected');
});
}, []);
return <p>{text}</p>;
}
This will show the Text "Effected" after three seconds (i sped up the video):
If I use this test-suite: Test Setup
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import enableHooks from 'jest-react-hooks-shallow';
configure({ adapter: new Adapter() });
enableHooks(jest);
Component.test.tsx
import * as React from 'react';
import { mount } from 'enzyme';
import Test from './Test';
describe('Test Test', () => {
const wrapper = mount(<Test />);
it('Should render private route', async () => {
console.log(wrapper.html());
expect(wrapper..text).toBe("Effected");
});
});
The expected result is that the test succeeds and it'll wait for the useEffect to run through. Unfortunately, it does not.
Could you have a look at this?
+1! As a workaround, disableHooks
and reenableHooks
do the trick.
it("does what it should do", async () => {
disableHooks();
await ...
reenableHooks();
});
+1! As a workaround,
disableHooks
andreenableHooks
do the trick.it("does what it should do", async () => { disableHooks(); await ... reenableHooks(); });
But it's recommended not to use it.
@dunklesToast have you found a solution for this?
I have a need for the proposed solution as well.
Here's my workaround for the time being:
async function withoutHooksPromise(fn) {
const mockedConsole = jest.spyOn(console, 'warn').mockImplementation();
disableHooks();
await fn().finally(() => {
reenableHooks();
mockedConsole.mockRestore();
});
}
Is there any news related to this? It is a crucial functionality, as often there will be async calls being ran in useEffect. A very "cheap" workaround would be to wrap what you expect to happen after a mock promise resolves in a "setTimeout" set to run after zero milliseconds, this will run the code after the jest mock promise resolves, sort of like "awaiting".