jest-location-mock
jest-location-mock copied to clipboard
Conflicts with other tests, Possibly React Router v6
it works but changes the window globally which causes crashes at another test, so can be used to modify the window inside every single test spirality without reflection on other files?
Hi @muhammedmoussa1! π
Conflict
Conflicts shouldn't be common with this mock so that's unexpected! I'm happy to see if there's something I can do to improve the mock here. Could you create a minimal reproduction of the conflict? Using a tool like Codesandbox (you can add the mock import in setupTests.js
if you're using the React templates, for example) or including the related files here helps me out. I am curious to know the cause as the mock is nearly identical to the object in a browser.
Using Jest Location Mock In a Single File or Test
Jest Location Mock is intended to be used across an entire project so that the assumptions of the location object don't change from test to test.
That said, it's worth a try to import it only in each test file you want to have a mocked location and then remove the import from the Jest config setup file.
import "jest-location-mock";
// [tests...]
While not recommended, you can also manually execute the replace hook if all else fails. This may unblock you while we figure out the root of the conflict. Below is an example idea of what this would look like, but I wrote it on my phone from memory, so it may need some adjusting.
// Pull in the location mock setup hook
import {replaceLocation} from "jest-location-mock/lib/hooks";
// Extend the expect matchers for use with the mocked location
// - `expect(window.location).toBeAt("/test");`
import "jest-location-mock/lib/extend-expect";
describe("native location", () => {
test("should use native location", () => {
// [expectations...]
});
});
describe("mocked location", () => {
// Store the native location stub
let originalLocation;
beforeAll(() => {
originalLocation = Object.getOwnPropertyDescriptor(window, "location");
});
// Replace the location property with a clean mock for every each in this describe block
beforeEach(replaceLocation);
// Reset the location object back to the native stub after all tests complete
afterAll(() => {
Object.defineProperty(window, "location", originalLocation);
});
test("should use mocked location", () => {
// [expectations...]
});
});
for what it's worth, i just encountered an issue when using it with react-router-dom
v6 - using it seemed to break react router's ability to update window.location.href
, so i imported this package in the specific test suites where we were interacting with the location state directly and avoided the issue entirely.
no specific errors were reported, so i didn't deem it worth time to dig deeper π€·
I think others may be having similar issues with React Router v6 per the comments on this answer on StackOverflow.
I still need to dive into how to reproduce this. Reproduction projects welcome if someone else runs into this.
I tried to reproduce this issue with just React Router DOM v6, Create React App, and jest-location-mock; and I didn't get any errors when using createBrowserRouter()
, <BrowserRouter>
, or <MemoryRouter>
.
If anyone knows how to reproduce the issues, that'd be perfection! π
I tried out the sandbox and see you have some comments saying:
// React Router doesn't update `window.location`
I don't think this is true from my own testing, at least for createBrowserRouter
. I modified your sandbox and window.location.pathname
does appear to be updated: https://codesandbox.io/s/jest-location-mock-with-react-router-forked-s2zghz?file=/src/App.test.tsx
@maxrchung Nice catch! You're right. I must've had some incorrect or outdated assumptions about how their browser routers worked in tests. I'll look into this more.
Funnily enough this would be fixed alongside #158. Jest + JSDOM allows for window.history
changes, and window.location
correct updates without jest-location-mock
. But when jest-location-mock
is activated, the internal reference that window.history
refers to to update window.location
does not match the mocked version.
The effect is that jest-location-mock
hides all changes to the location performed by native history because it currently does not even register them. We could mock window.history
(this gets close to just writing JSDOM in my opinion), or we can figure out how to add on to the implementation that JSDOM has:
- Using events maybe? It could be a small spec deviation to use
popstate
and the like, but would work for most cases - I would love it we could just move the spies around to a better place
- Spy/proxy
window.history
as well, passing through everything, and then perform a check to our internal copy of the originalwindow.location
to check if an update to our side needs to be performed oncewindow.history.*
is done. This would also fix #158