I have written unit test using jest version 26.0.0
with react-testing-library and node version 14.2.0
. Below is my React functional component which has a button, on clicking makes an ajax call to download a report file.
const ReportListTable = () => {
const { downloadReports } = useReports();
const onClickDownload = () => {
let fileName = `Report.zip`;
downloadReports()
.then((response) => response.arrayBuffer())
.then((data) => {
const blob = new Blob([data], { type: "octet/stream", endings: "native" });
const url = window.URL.createObjectURL(blob);
const anchor = document.createElement("a");
anchor.setAttribute("href", url);
anchor.setAttribute("download", fileName);
anchor.click();
window.URL.revokeObjectURL(url);
})
.catch((error?: Error | Response) => {
if (error instanceof Error) {
message.error(error?.message);
}
});
};
return (
<div>
<Button data-testid="download-btn" onClick={onClickDownload}>
Download
</Button>
</div>
);
};
And I have below test suite where the createObjectURL
and revokeObjectURL
before the test runs.
describe("Test Reports List Table component", () => {
const { URL } = window;
beforeAll(() => {
window.URL.createObjectURL = jest.fn();
window.URL.revokeObjectURL = jest.fn();
jest.spyOn(useReportsHook, "useReports").mockReturnValue(useReportsMockValue);
});
afterAll(() => {
window.URL = URL;
jest.clearAllMocks();
});
it("should handle row button enabled and download on button clicked", async () => {
jest.spyOn(useReportsContextHook, "useReportsContext").mockReturnValue([{ checkedIds: ["report_1"] }, jest.fn]);
const { asFragment } = render(<ReportListTable />);
fireEvent.click(await screen.getByTestId(elements.downloadTestId));
await waitFor(() => expect(window.URL.createObjectURL).toHaveBeenCalled());
await waitFor(() => expect(window.URL.revokeObjectURL).toHaveBeenCalled());
expect(asFragment).toMatchSnapshot();
});
});
The test case is passed however it throws the below error.
console.error
Error: Not implemented: navigation (except hash changes)
at module.exports (/Users/user/Documents/lydia-github/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/browser/not-implemented.js:9:17)
at navigateFetch (/Users/user/Documents/lydia-github/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/window/navigation.js:76:3)
at exports.navigate (/Users/user/Documents/lydia-github/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/window/navigation.js:54:3)
at Timeout._onTimeout (/Users/user/Documents/lydia-github/node_modules/jest-environment-jsdom/node_modules/jsdom/lib/jsdom/living/nodes/HTMLHyperlinkElementUtils-impl.js:81:7)
at listOnTimeout (internal/timers.js:549:17)
at processTimers (internal/timers.js:492:7) undefined
I tried to mock the location
object after referring this thread How to fix Error: Not implemented: navigation (except hash changes), however it didn't help. I need help to resolve this error.
I've worked out the problem:
JSDom doesn't like you to do navigation - cf., https://github.com/jsdom/jsdom/issues/2112#issuecomment-359297866
The issue we have here is that the code is performing a click event on an anchor:
const anchor = document.createElement("a");
anchor.setAttribute("href", url);
anchor.setAttribute("download", fileName);
anchor.click();
A click on an anchor is a navigation, usually, which I presume JSDom is taking exception to.
To solve the annoying logging, rather than mocking the location
, mock the click()
:
HTMLAnchorElement.prototype.click = jest.fn();
This worked for me.
Incidentally, I also had to mock the window.URL.createObjectUrl
call as I was getting:
TypeError: window.URL.createObjectURL is not a function
...so:
global.window.URL.createObjectURL = jest.fn();
Hope this works for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With