admin管理员组文章数量:1394099
While learning React, I'm trying to understand custom hooks.
I've created a simple one updating an internal "step" on creation, cleanup, and allows for external updates.
But I'm struggling to successfully implements its unit tests on "step" update and cleanup. It's as if the the returned "step" value is not updated anymore after the hook creation.
How can fix the tests? Did I miss some key concepts?
Here is the custom hook:
const useCustomHook = (stepToSet: string) => {
const [step, setStep, ] = useState('');
useEffect(() => {
if (stepToSet) {
setStep(stepToSet);
}
return () => {
setStep('cleanup');
};
}, [stepToSet, ]);
const externalCb = (externalStepToSet: string) => {
setStep(externalStepToSet);
};
return {
step,
externalCb,
};
};
Jest unit test:
import {
act, renderHook,
} from '@testing-library/react-hooks';
import { expect, } from 'chai';
describe('useCustomHook Hook', () => {
it('step updates test', async () => {
const {
result,
unmount,
waitFor,
} = renderHook(() => {
return useCustomHook('created');
});
const {
step,
externalCb,
} = result.current;
expect(step).to.be.equal('created');
act(() => externalCb('updated'));
await waitFor(() => {});
expect(step).to.be.equal('updated');
act(() => unmount());
await waitFor(() => {});
expect(step).to.be.equal('cleaned');
});
});
The test keeps failing with the message:
assert.strictEqual(received, expected)
Expected value to strictly be equal to:
"updated"
Received:
"created"
Message:
expected 'created' to equal 'updated'
Difference:
- Expected
+ Received
- updated
+ created
...
The test still fails with the same message if I remove async
and the await
lines.
While learning React, I'm trying to understand custom hooks.
I've created a simple one updating an internal "step" on creation, cleanup, and allows for external updates.
But I'm struggling to successfully implements its unit tests on "step" update and cleanup. It's as if the the returned "step" value is not updated anymore after the hook creation.
How can fix the tests? Did I miss some key concepts?
Here is the custom hook:
const useCustomHook = (stepToSet: string) => {
const [step, setStep, ] = useState('');
useEffect(() => {
if (stepToSet) {
setStep(stepToSet);
}
return () => {
setStep('cleanup');
};
}, [stepToSet, ]);
const externalCb = (externalStepToSet: string) => {
setStep(externalStepToSet);
};
return {
step,
externalCb,
};
};
Jest unit test:
import {
act, renderHook,
} from '@testing-library/react-hooks';
import { expect, } from 'chai';
describe('useCustomHook Hook', () => {
it('step updates test', async () => {
const {
result,
unmount,
waitFor,
} = renderHook(() => {
return useCustomHook('created');
});
const {
step,
externalCb,
} = result.current;
expect(step).to.be.equal('created');
act(() => externalCb('updated'));
await waitFor(() => {});
expect(step).to.be.equal('updated');
act(() => unmount());
await waitFor(() => {});
expect(step).to.be.equal('cleaned');
});
});
The test keeps failing with the message:
assert.strictEqual(received, expected)
Expected value to strictly be equal to:
"updated"
Received:
"created"
Message:
expected 'created' to equal 'updated'
Difference:
- Expected
+ Received
- updated
+ created
...
The test still fails with the same message if I remove async
and the await
lines.
1 Answer
Reset to default 1Issues
- The
result
is holds a reference to the hook's current return value, but in your test you only access the initial value before effecting any changes, the later assertions don't have the updated hook value. - When a hook/component unmounts, any enqueued state updates are a non-operation. After unmounting no state updates will be processed.
Solution Suggestions
- Update the test cases to access
result.current
each time after anact
. - Remove any assertions after unmounting the hook.
- The
waitFor
calls appear to be superfluous since they are empty and could/should probably be removed. AFAIKact
is sufficient for triggering a re-render and hook update.
import { act, renderHook } from "@testing-library/react";
import { expect } from "chai";
import { useCustomHook } from "./useCustomHook";
describe("useCustomHook Hook", () => {
it("step updates test", () => {
const { result, unmount } = renderHook(useCustomHook, {
initialProps: "created",
});
// Initial step value when mounted
expect(result.current.step).to.be.equal("created");
// Update state
act(() => result.current.externalCb("updated"));
expect(result.current.step).to.be.equal("updated");
// Unmount
act(() => unmount());
// No update is expected here, I guess you could assert
// nothing changed in the hook state
expect(result.current.step).to.be.equal("updated");
});
});
If you need to waitFor
any updates though, the correct usage would be similar to the following:
import { act, renderHook, waitFor } from "@testing-library/react";
import { expect } from "chai";
import { useCustomHook } from "./useCustomHook";
describe("useCustomHook Hook", () => {
it("step updates test", async () => {
const { result, unmount } = renderHook(useCustomHook, {
initialProps: "created",
});
expect(result.current.step).to.be.equal("created");
act(() => result.current.externalCb("updated"));
await waitFor(() => {
expect(result.current.step).to.be.equal("updated");
});
act(() => unmount());
await waitFor(() => {
expect(result.current.step).to.be.equal("updated");
});
});
});
本文标签: javascriptCan39t successfully test a custom hook using useState and useEffectStack Overflow
版权声明:本文标题:javascript - Can't successfully test a custom hook using useState and useEffect - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744688530a2619848.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论