Skip to content

Commit 741a127

Browse files
authored
Export __N_SSG and __N_SSP from the error component (vercel#3574)
`export *` would be preferable once supported.
1 parent e794df4 commit 741a127

File tree

15 files changed

+751
-119
lines changed

15 files changed

+751
-119
lines changed
+7-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import Error, { getStaticProps } from "@vercel/turbopack-next/internal/_error";
2-
3-
export default Error;
4-
export { getStaticProps };
1+
// TODO(alexkirsz) export * would be preferrable here once supported.
2+
export {
3+
default,
4+
getStaticProps,
5+
__N_SSG,
6+
__N_SSP,
7+
} from "@vercel/turbopack-next/internal/_error";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import * as jest from "jest-circus-browser/dist/umd/jest-circus";
2+
import expectMod from "expect/build-es5/index";
3+
4+
type CallSignature<T extends (...a: any[]) => unknown> = (
5+
...a: Parameters<T>
6+
) => ReturnType<T>;
7+
8+
declare global {
9+
var __jest__: typeof jest;
10+
var expect: typeof expectMod;
11+
// We need to extract only the call signature as `autoReady(jest.describe)` drops all the other properties
12+
var describe: CallSignature<typeof jest.describe>;
13+
var it: CallSignature<typeof jest.it>;
14+
var READY: (arg: string) => void;
15+
var nsObj: (obj: any) => any;
16+
17+
interface Window {
18+
NEXT_HYDRATED?: boolean;
19+
onNextHydrated?: () => void;
20+
}
21+
}
22+
23+
let isReady = false;
24+
function autoReady<T extends (...a: any[]) => unknown>(
25+
fn: (...args: Parameters<T>) => ReturnType<T>
26+
): (...args: Parameters<T>) => ReturnType<T> {
27+
return (...args) => {
28+
if (!isReady) {
29+
isReady = true;
30+
setImmediate(() => {
31+
READY("");
32+
});
33+
}
34+
return fn(...args);
35+
};
36+
}
37+
38+
globalThis.__jest__ = jest;
39+
globalThis.expect = expectMod;
40+
globalThis.describe = autoReady(jest.describe);
41+
globalThis.it = autoReady(jest.it);
42+
43+
// From https://github.com/webpack/webpack/blob/9fcaa243573005d6fdece9a3f8d89a0e8b399613/test/TestCases.template.js#L422
44+
globalThis.nsObj = function nsObj(obj) {
45+
Object.defineProperty(obj, Symbol.toStringTag, {
46+
value: "Module",
47+
});
48+
return obj;
49+
};
50+
51+
function wait(ms: number): Promise<void> {
52+
return new Promise((resolve) => {
53+
setTimeout(resolve, ms);
54+
});
55+
}
56+
57+
async function waitForPath(contentWindow: Window, path: string): Promise<void> {
58+
while (true) {
59+
if (contentWindow.location.pathname === path) {
60+
break;
61+
}
62+
63+
await wait(1);
64+
}
65+
}
66+
67+
export function waitForHydration(
68+
iframe: HTMLIFrameElement,
69+
path: string
70+
): Promise<void> {
71+
return new Promise((resolve) => {
72+
if (
73+
iframe.contentDocument != null &&
74+
iframe.contentDocument.readyState === "complete"
75+
) {
76+
waitForHydrationAndResolve(iframe.contentWindow!, path).then(resolve);
77+
} else {
78+
iframe.addEventListener("load", () => {
79+
waitForHydrationAndResolve(iframe.contentWindow!, path).then(resolve);
80+
});
81+
}
82+
});
83+
}
84+
85+
async function waitForHydrationAndResolve(
86+
contentWindow: Window,
87+
path: string
88+
): Promise<void> {
89+
await waitForPath(contentWindow, path);
90+
91+
return await new Promise((resolve) => {
92+
if (contentWindow.NEXT_HYDRATED) {
93+
resolve();
94+
} else {
95+
contentWindow.onNextHydrated = () => {
96+
resolve();
97+
};
98+
}
99+
});
100+
}
101+
102+
export function markAsHydrated() {
103+
window.NEXT_HYDRATED = true;
104+
if (typeof window.onNextHydrated === "function") {
105+
window.onNextHydrated();
106+
}
107+
}

crates/next-dev/test-harness/package.json crates/next-dev-tests/test-harness/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
"name": "@turbo/pack-test-harness",
33
"private": true,
44
"version": "0.0.1",
5-
"main": "./harness.js",
5+
"main": "./harness.ts",
66
"dependencies": {
77
"expect": "^24.5.0",
8+
"jest-circus": "^29.4.1",
89
"jest-circus-browser": "^1.0.7"
910
}
1011
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
declare module "jest-circus-browser/dist/umd/jest-circus" {
2+
export * from "jest-circus";
3+
}
4+
5+
declare module "expect/build-es5/index" {
6+
export { default } from "expect";
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { useEffect } from "react";
2+
3+
export default function ErrorPage(props: { static: "static" }) {
4+
useEffect(() => {
5+
import("@turbo/pack-test-harness").then((harness) =>
6+
harness.markAsHydrated()
7+
);
8+
});
9+
10+
return <div data-test-error>{props.static}</div>;
11+
}
12+
13+
export function getStaticProps() {
14+
return {
15+
props: {
16+
static: "static",
17+
},
18+
};
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { useEffect, useRef } from "react";
2+
3+
export default function Page() {
4+
const iframeRef = useRef<HTMLIFrameElement | null>(null);
5+
6+
useEffect(() => {
7+
// Only run on client
8+
import("@turbo/pack-test-harness").then((mod) =>
9+
runTests(mod, iframeRef.current!)
10+
);
11+
});
12+
13+
return (
14+
<iframe style={{ width: 800, height: 600 }} src="/link" ref={iframeRef} />
15+
);
16+
}
17+
18+
type Harness = typeof import("@turbo/pack-test-harness");
19+
20+
function runTests(harness: Harness, iframe: HTMLIFrameElement) {
21+
it("returns a 404 status code", async () => {
22+
const res = await fetch("/not-found");
23+
expect(res.status).toBe(404);
24+
});
25+
26+
it("navigates to the 404 page", async () => {
27+
await harness.waitForHydration(iframe, "/link");
28+
29+
const link = iframe.contentDocument!.querySelector("a[data-test-link]");
30+
expect(link).not.toBeNull();
31+
expect(link!).toBeInstanceOf(
32+
(iframe.contentWindow as any).HTMLAnchorElement
33+
);
34+
expect(link!.textContent).toBe("Not found");
35+
36+
(link as HTMLAnchorElement).click();
37+
38+
await harness.waitForHydration(iframe, "/not-found");
39+
40+
const error = iframe.contentDocument!.querySelector("[data-test-error]");
41+
expect(error).not.toBeNull();
42+
expect(error!.textContent).toBe("static");
43+
});
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import Link from "next/link";
2+
import { useEffect } from "react";
3+
4+
export default function Page() {
5+
useEffect(() => {
6+
import("@turbo/pack-test-harness").then((mod) => mod.markAsHydrated());
7+
});
8+
9+
return (
10+
<Link href="/not-found" data-test-link>
11+
Not found
12+
</Link>
13+
);
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export default function Page() {
2+
return <div>Page</div>;
3+
}
4+
5+
export function getStaticProps() {
6+
return {
7+
notFound: true,
8+
};
9+
}

crates/next-dev-tests/tests/integration/next/app/metadata/input/tsconfig.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@
1919
{
2020
"name": "next"
2121
}
22-
]
22+
],
23+
"paths": {
24+
"@turbo/pack-test-harness": ["../../../../../../test-harness"]
25+
}
2326
},
2427
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
2528
"exclude": ["node_modules"]

crates/next-dev-tests/tests/integration/next/tailwind/basic/input/tsconfig.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313
"resolveJsonModule": true,
1414
"isolatedModules": true,
1515
"jsx": "preserve",
16-
"incremental": true
16+
"incremental": true,
17+
"paths": {
18+
"@turbo/pack-test-harness": ["../../../../../../test-harness"]
19+
}
1720
},
1821
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "pages/index.jsx"],
1922
"exclude": ["node_modules"]

crates/next-dev-tests/tests/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
"name": "next-dev-tests",
33
"private": true,
44
"devDependencies": {
5-
"@turbo/pack-test-harness": "*",
5+
"@types/jest": "29.4.0",
6+
"@turbo/pack-test-harness": "file:../test-harness",
67
"autoprefixer": "^10.4.13",
78
"loader-runner": "^4.3.0",
89
"next": "13.1.7-canary.2",
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"compilerOptions": {
3+
// type checking
4+
"strict": true,
5+
"noFallthroughCasesInSwitch": true,
6+
"skipLibCheck": true,
7+
8+
// interop constraints
9+
"allowSyntheticDefaultImports": true,
10+
"esModuleInterop": true,
11+
12+
// js support
13+
"allowJs": true,
14+
"checkJs": false,
15+
16+
// environment
17+
"jsx": "react-jsx",
18+
"lib": ["ESNext", "DOM"],
19+
"target": "esnext",
20+
21+
// modules
22+
"baseUrl": ".",
23+
"module": "esnext",
24+
"moduleResolution": "node",
25+
26+
"paths": {
27+
"@turbo/pack-test-harness": ["../test-harness"]
28+
},
29+
30+
// emit
31+
"noEmit": true,
32+
"stripInternal": true
33+
},
34+
"include": ["integration"]
35+
}

crates/next-dev/test-harness/harness.js

-28
This file was deleted.

0 commit comments

Comments
 (0)