Skip to content

Commit e516138

Browse files
committed
chore: upgrade jest and jsdom
This lets us remove a polyfill and some other hacks, and brings along some additional jsdom features which will facilitate testing fixes to submitter serialization. Note: * jsdom is making it harder to stub things, so we inject a jest-friendly window into the router. I'm not a huge fan of DI when used solely for the sake of testing, but this seems less terrible than other approaches (e.g. (patch-package-ing jsdom, or monkey-patching Object.defineProperty) 🙃 * We use a yarn resolution to get the latest jsdom, despite the latest jest pinning it at ^20.0.0. Per the maintainers, this is fine as jest doesn't need any code changes to work with new jsdom, and there are no concrete plans yet to ship a major version.
1 parent 4ccdc11 commit e516138

File tree

11 files changed

+894
-766
lines changed

11 files changed

+894
-766
lines changed

.changeset/stale-birds-travel.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@remix-run/router": patch
3+
---
4+
5+
upgrade jest and jsdom

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,15 @@
3232
"jest": {
3333
"projects": [
3434
"<rootDir>/packages/*"
35+
],
36+
"reporters": [
37+
"default"
3538
]
3639
},
3740
"resolutions": {
3841
"@types/react": "^18.0.0",
39-
"@types/react-dom": "^18.0.0"
42+
"@types/react-dom": "^18.0.0",
43+
"jsdom": "22.0.0"
4044
},
4145
"dependencies": {
4246
"@ampproject/filesize": "^4.3.0",

packages/react-router-dom-v5-compat/jest.config.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,4 @@ module.exports = {
2121
"^react-router$": "<rootDir>/../react-router/index.ts",
2222
"^react-router-dom-v5-compat$": "<rootDir>/index.ts",
2323
},
24-
reporters: ["default"],
2524
};

packages/react-router-dom/__tests__/polyfills/SubmitEvent.submitter.ts

Lines changed: 0 additions & 29 deletions
This file was deleted.

packages/react-router-dom/__tests__/setup.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import {
55
import { fetch, Request, Response, Headers } from "@remix-run/web-fetch";
66
import { AbortController as NodeAbortController } from "abort-controller";
77

8-
import "./polyfills/SubmitEvent.submitter";
9-
108
// https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html#configuring-your-testing-environment
119
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
1210

packages/react-router-dom/jest.config.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,4 @@ module.exports = {
2121
"^react-router$": "<rootDir>/../react-router/index.ts",
2222
"^react-router-dom$": "<rootDir>/index.tsx",
2323
},
24-
reporters: ["default"],
2524
};

packages/react-router-native/jest.config.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,4 @@ module.exports = {
2424
"^react-router$": "<rootDir>/../react-router/index.ts",
2525
"^react-router-native$": "<rootDir>/index.tsx",
2626
},
27-
reporters: ["default"],
2827
};

packages/router/__tests__/router-test.ts

Lines changed: 18 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ type SetupOpts = {
302302
future?: FutureConfig;
303303
};
304304

305+
let globalWindow = window;
305306
function setup({
306307
routes,
307308
basename,
@@ -428,6 +429,15 @@ function setup({
428429
});
429430
}
430431

432+
// jsdom is making more and more properties non-configurable, so we inject our own jest-friendly window 😅
433+
let window = {
434+
...globalWindow,
435+
location: {
436+
...globalWindow.location,
437+
assign: jest.fn(),
438+
replace: jest.fn(),
439+
},
440+
} as unknown as Window; // spread makes TS sad, since `window.NaN` conflicts with the `[index: number]: Window` index signature
431441
let history = createMemoryHistory({ initialEntries, initialIndex });
432442
jest.spyOn(history, "push");
433443
jest.spyOn(history, "replace");
@@ -437,6 +447,7 @@ function setup({
437447
routes: enhanceRoutes(routes),
438448
hydrationData,
439449
future,
450+
window,
440451
}).initialize();
441452

442453
function getRouteHelpers(
@@ -843,6 +854,7 @@ function setup({
843854
}
844855

845856
return {
857+
window,
846858
history,
847859
router: currentRouter,
848860
navigate,
@@ -6496,15 +6508,6 @@ describe("a router", () => {
64966508
];
64976509

64986510
for (let url of urls) {
6499-
// This is gross, don't blame me, blame SO :)
6500-
// https://stackoverflow.com/a/60697570
6501-
let oldLocation = window.location;
6502-
const location = new URL(window.location.href) as unknown as Location;
6503-
location.assign = jest.fn();
6504-
location.replace = jest.fn();
6505-
delete (window as any).location;
6506-
window.location = location as unknown as Location;
6507-
65086511
let t = setup({ routes: REDIRECT_ROUTES });
65096512

65106513
let A = await t.navigate("/parent/child", {
@@ -6513,10 +6516,8 @@ describe("a router", () => {
65136516
});
65146517

65156518
await A.actions.child.redirectReturn(url);
6516-
expect(window.location.assign).toHaveBeenCalledWith(url);
6517-
expect(window.location.replace).not.toHaveBeenCalled();
6518-
6519-
window.location = oldLocation;
6519+
expect(t.window.location.assign).toHaveBeenCalledWith(url);
6520+
expect(t.window.location.replace).not.toHaveBeenCalled();
65206521
}
65216522
});
65226523

@@ -6529,15 +6530,6 @@ describe("a router", () => {
65296530
];
65306531

65316532
for (let url of urls) {
6532-
// This is gross, don't blame me, blame SO :)
6533-
// https://stackoverflow.com/a/60697570
6534-
let oldLocation = window.location;
6535-
const location = new URL(window.location.href) as unknown as Location;
6536-
location.assign = jest.fn();
6537-
location.replace = jest.fn();
6538-
delete (window as any).location;
6539-
window.location = location as unknown as Location;
6540-
65416533
let t = setup({ routes: REDIRECT_ROUTES });
65426534

65436535
let A = await t.navigate("/parent/child", {
@@ -6547,10 +6539,8 @@ describe("a router", () => {
65476539
});
65486540

65496541
await A.actions.child.redirectReturn(url);
6550-
expect(window.location.replace).toHaveBeenCalledWith(url);
6551-
expect(window.location.assign).not.toHaveBeenCalled();
6552-
6553-
window.location = oldLocation;
6542+
expect(t.window.location.replace).toHaveBeenCalledWith(url);
6543+
expect(t.window.location.assign).not.toHaveBeenCalled();
65546544
}
65556545
});
65566546

@@ -6605,15 +6595,6 @@ describe("a router", () => {
66056595
});
66066596

66076597
it("treats same-origin absolute URLs as external if they don't match the basename", async () => {
6608-
// This is gross, don't blame me, blame SO :)
6609-
// https://stackoverflow.com/a/60697570
6610-
let oldLocation = window.location;
6611-
const location = new URL(window.location.href) as unknown as Location;
6612-
location.assign = jest.fn();
6613-
location.replace = jest.fn();
6614-
delete (window as any).location;
6615-
window.location = location as unknown as Location;
6616-
66176598
let t = setup({ routes: REDIRECT_ROUTES, basename: "/base" });
66186599

66196600
let A = await t.navigate("/base/parent/child", {
@@ -6623,10 +6604,8 @@ describe("a router", () => {
66236604

66246605
let url = "http://localhost/not/the/same/basename";
66256606
await A.actions.child.redirectReturn(url);
6626-
expect(window.location.assign).toHaveBeenCalledWith(url);
6627-
expect(window.location.replace).not.toHaveBeenCalled();
6628-
6629-
window.location = oldLocation;
6607+
expect(t.window.location.assign).toHaveBeenCalledWith(url);
6608+
expect(t.window.location.replace).not.toHaveBeenCalled();
66306609
});
66316610

66326611
describe("redirect status code handling", () => {

packages/router/jest.config.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,4 @@ module.exports = {
1616
"@web3-storage/multipart-parser"
1717
),
1818
},
19-
reporters: ["default"],
2019
};

packages/router/router.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@ export interface RouterInit {
352352
mapRouteProperties?: MapRoutePropertiesFunction;
353353
future?: Partial<FutureConfig>;
354354
hydrationData?: HydrationState;
355+
window?: Window;
355356
}
356357

357358
/**
@@ -661,11 +662,7 @@ export const IDLE_BLOCKER: BlockerUnblocked = {
661662

662663
const ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
663664

664-
const isBrowser =
665-
typeof window !== "undefined" &&
666-
typeof window.document !== "undefined" &&
667-
typeof window.document.createElement !== "undefined";
668-
const isServer = !isBrowser;
665+
const globalWindow = typeof window !== "undefined" ? window : undefined;
669666

670667
const defaultMapRouteProperties: MapRoutePropertiesFunction = (route) => ({
671668
hasErrorBoundary: Boolean(route.hasErrorBoundary),
@@ -680,7 +677,16 @@ const defaultMapRouteProperties: MapRoutePropertiesFunction = (route) => ({
680677
/**
681678
* Create a router and listen to history POP navigations
682679
*/
683-
export function createRouter(init: RouterInit): Router {
680+
export function createRouter({
681+
window = globalWindow,
682+
...init
683+
}: RouterInit): Router {
684+
const isBrowser =
685+
typeof window !== "undefined" &&
686+
typeof window.document !== "undefined" &&
687+
typeof window.document.createElement !== "undefined";
688+
const isServer = !isBrowser;
689+
684690
invariant(
685691
init.routes.length > 0,
686692
"You must provide a non-empty routes array to createRouter"

0 commit comments

Comments
 (0)