Skip to content

Commit

Permalink
chore: upgrade jest and jsdom
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jenseng committed May 6, 2023
1 parent 4ccdc11 commit e516138
Show file tree
Hide file tree
Showing 11 changed files with 894 additions and 766 deletions.
5 changes: 5 additions & 0 deletions .changeset/stale-birds-travel.md
@@ -0,0 +1,5 @@
---
"@remix-run/router": patch
---

upgrade jest and jsdom
6 changes: 5 additions & 1 deletion package.json
Expand Up @@ -32,11 +32,15 @@
"jest": {
"projects": [
"<rootDir>/packages/*"
],
"reporters": [
"default"
]
},
"resolutions": {
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0"
"@types/react-dom": "^18.0.0",
"jsdom": "22.0.0"
},
"dependencies": {
"@ampproject/filesize": "^4.3.0",
Expand Down
1 change: 0 additions & 1 deletion packages/react-router-dom-v5-compat/jest.config.js
Expand Up @@ -21,5 +21,4 @@ module.exports = {
"^react-router$": "<rootDir>/../react-router/index.ts",
"^react-router-dom-v5-compat$": "<rootDir>/index.ts",
},
reporters: ["default"],
};

This file was deleted.

2 changes: 0 additions & 2 deletions packages/react-router-dom/__tests__/setup.ts
Expand Up @@ -5,8 +5,6 @@ import {
import { fetch, Request, Response, Headers } from "@remix-run/web-fetch";
import { AbortController as NodeAbortController } from "abort-controller";

import "./polyfills/SubmitEvent.submitter";

// https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html#configuring-your-testing-environment
globalThis.IS_REACT_ACT_ENVIRONMENT = true;

Expand Down
1 change: 0 additions & 1 deletion packages/react-router-dom/jest.config.js
Expand Up @@ -21,5 +21,4 @@ module.exports = {
"^react-router$": "<rootDir>/../react-router/index.ts",
"^react-router-dom$": "<rootDir>/index.tsx",
},
reporters: ["default"],
};
1 change: 0 additions & 1 deletion packages/react-router-native/jest.config.js
Expand Up @@ -24,5 +24,4 @@ module.exports = {
"^react-router$": "<rootDir>/../react-router/index.ts",
"^react-router-native$": "<rootDir>/index.tsx",
},
reporters: ["default"],
};
57 changes: 18 additions & 39 deletions packages/router/__tests__/router-test.ts
Expand Up @@ -302,6 +302,7 @@ type SetupOpts = {
future?: FutureConfig;
};

let globalWindow = window;
function setup({
routes,
basename,
Expand Down Expand Up @@ -428,6 +429,15 @@ function setup({
});
}

// jsdom is making more and more properties non-configurable, so we inject our own jest-friendly window 😅
let window = {
...globalWindow,
location: {
...globalWindow.location,
assign: jest.fn(),
replace: jest.fn(),
},
} as unknown as Window; // spread makes TS sad, since `window.NaN` conflicts with the `[index: number]: Window` index signature
let history = createMemoryHistory({ initialEntries, initialIndex });
jest.spyOn(history, "push");
jest.spyOn(history, "replace");
Expand All @@ -437,6 +447,7 @@ function setup({
routes: enhanceRoutes(routes),
hydrationData,
future,
window,
}).initialize();

function getRouteHelpers(
Expand Down Expand Up @@ -843,6 +854,7 @@ function setup({
}

return {
window,
history,
router: currentRouter,
navigate,
Expand Down Expand Up @@ -6496,15 +6508,6 @@ describe("a router", () => {
];

for (let url of urls) {
// This is gross, don't blame me, blame SO :)
// https://stackoverflow.com/a/60697570
let oldLocation = window.location;
const location = new URL(window.location.href) as unknown as Location;
location.assign = jest.fn();
location.replace = jest.fn();
delete (window as any).location;
window.location = location as unknown as Location;

let t = setup({ routes: REDIRECT_ROUTES });

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

await A.actions.child.redirectReturn(url);
expect(window.location.assign).toHaveBeenCalledWith(url);
expect(window.location.replace).not.toHaveBeenCalled();

window.location = oldLocation;
expect(t.window.location.assign).toHaveBeenCalledWith(url);
expect(t.window.location.replace).not.toHaveBeenCalled();
}
});

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

for (let url of urls) {
// This is gross, don't blame me, blame SO :)
// https://stackoverflow.com/a/60697570
let oldLocation = window.location;
const location = new URL(window.location.href) as unknown as Location;
location.assign = jest.fn();
location.replace = jest.fn();
delete (window as any).location;
window.location = location as unknown as Location;

let t = setup({ routes: REDIRECT_ROUTES });

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

await A.actions.child.redirectReturn(url);
expect(window.location.replace).toHaveBeenCalledWith(url);
expect(window.location.assign).not.toHaveBeenCalled();

window.location = oldLocation;
expect(t.window.location.replace).toHaveBeenCalledWith(url);
expect(t.window.location.assign).not.toHaveBeenCalled();
}
});

Expand Down Expand Up @@ -6605,15 +6595,6 @@ describe("a router", () => {
});

it("treats same-origin absolute URLs as external if they don't match the basename", async () => {
// This is gross, don't blame me, blame SO :)
// https://stackoverflow.com/a/60697570
let oldLocation = window.location;
const location = new URL(window.location.href) as unknown as Location;
location.assign = jest.fn();
location.replace = jest.fn();
delete (window as any).location;
window.location = location as unknown as Location;

let t = setup({ routes: REDIRECT_ROUTES, basename: "/base" });

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

let url = "http://localhost/not/the/same/basename";
await A.actions.child.redirectReturn(url);
expect(window.location.assign).toHaveBeenCalledWith(url);
expect(window.location.replace).not.toHaveBeenCalled();

window.location = oldLocation;
expect(t.window.location.assign).toHaveBeenCalledWith(url);
expect(t.window.location.replace).not.toHaveBeenCalled();
});

describe("redirect status code handling", () => {
Expand Down
1 change: 0 additions & 1 deletion packages/router/jest.config.js
Expand Up @@ -16,5 +16,4 @@ module.exports = {
"@web3-storage/multipart-parser"
),
},
reporters: ["default"],
};
18 changes: 12 additions & 6 deletions packages/router/router.ts
Expand Up @@ -352,6 +352,7 @@ export interface RouterInit {
mapRouteProperties?: MapRoutePropertiesFunction;
future?: Partial<FutureConfig>;
hydrationData?: HydrationState;
window?: Window;
}

/**
Expand Down Expand Up @@ -661,11 +662,7 @@ export const IDLE_BLOCKER: BlockerUnblocked = {

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

const isBrowser =
typeof window !== "undefined" &&
typeof window.document !== "undefined" &&
typeof window.document.createElement !== "undefined";
const isServer = !isBrowser;
const globalWindow = typeof window !== "undefined" ? window : undefined;

const defaultMapRouteProperties: MapRoutePropertiesFunction = (route) => ({
hasErrorBoundary: Boolean(route.hasErrorBoundary),
Expand All @@ -680,7 +677,16 @@ const defaultMapRouteProperties: MapRoutePropertiesFunction = (route) => ({
/**
* Create a router and listen to history POP navigations
*/
export function createRouter(init: RouterInit): Router {
export function createRouter({
window = globalWindow,
...init
}: RouterInit): Router {
const isBrowser =
typeof window !== "undefined" &&
typeof window.document !== "undefined" &&
typeof window.document.createElement !== "undefined";
const isServer = !isBrowser;

invariant(
init.routes.length > 0,
"You must provide a non-empty routes array to createRouter"
Expand Down

0 comments on commit e516138

Please sign in to comment.