Skip to content

Commit

Permalink
Export __N_SSG and __N_SSP from the error component (vercel#3574)
Browse files Browse the repository at this point in the history
`export *` would be preferable once supported.
  • Loading branch information
alexkirsz authored Feb 7, 2023
1 parent e794df4 commit 741a127
Show file tree
Hide file tree
Showing 15 changed files with 751 additions and 119 deletions.
11 changes: 7 additions & 4 deletions crates/next-core/js/src/entry/error.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import Error, { getStaticProps } from "@vercel/turbopack-next/internal/_error";

export default Error;
export { getStaticProps };
// TODO(alexkirsz) export * would be preferrable here once supported.
export {
default,
getStaticProps,
__N_SSG,
__N_SSP,
} from "@vercel/turbopack-next/internal/_error";
107 changes: 107 additions & 0 deletions crates/next-dev-tests/test-harness/harness.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import * as jest from "jest-circus-browser/dist/umd/jest-circus";
import expectMod from "expect/build-es5/index";

type CallSignature<T extends (...a: any[]) => unknown> = (
...a: Parameters<T>
) => ReturnType<T>;

declare global {
var __jest__: typeof jest;
var expect: typeof expectMod;
// We need to extract only the call signature as `autoReady(jest.describe)` drops all the other properties
var describe: CallSignature<typeof jest.describe>;
var it: CallSignature<typeof jest.it>;
var READY: (arg: string) => void;
var nsObj: (obj: any) => any;

interface Window {
NEXT_HYDRATED?: boolean;
onNextHydrated?: () => void;
}
}

let isReady = false;
function autoReady<T extends (...a: any[]) => unknown>(
fn: (...args: Parameters<T>) => ReturnType<T>
): (...args: Parameters<T>) => ReturnType<T> {
return (...args) => {
if (!isReady) {
isReady = true;
setImmediate(() => {
READY("");
});
}
return fn(...args);
};
}

globalThis.__jest__ = jest;
globalThis.expect = expectMod;
globalThis.describe = autoReady(jest.describe);
globalThis.it = autoReady(jest.it);

// From https://github.com/webpack/webpack/blob/9fcaa243573005d6fdece9a3f8d89a0e8b399613/test/TestCases.template.js#L422
globalThis.nsObj = function nsObj(obj) {
Object.defineProperty(obj, Symbol.toStringTag, {
value: "Module",
});
return obj;
};

function wait(ms: number): Promise<void> {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}

async function waitForPath(contentWindow: Window, path: string): Promise<void> {
while (true) {
if (contentWindow.location.pathname === path) {
break;
}

await wait(1);
}
}

export function waitForHydration(
iframe: HTMLIFrameElement,
path: string
): Promise<void> {
return new Promise((resolve) => {
if (
iframe.contentDocument != null &&
iframe.contentDocument.readyState === "complete"
) {
waitForHydrationAndResolve(iframe.contentWindow!, path).then(resolve);
} else {
iframe.addEventListener("load", () => {
waitForHydrationAndResolve(iframe.contentWindow!, path).then(resolve);
});
}
});
}

async function waitForHydrationAndResolve(
contentWindow: Window,
path: string
): Promise<void> {
await waitForPath(contentWindow, path);

return await new Promise((resolve) => {
if (contentWindow.NEXT_HYDRATED) {
resolve();
} else {
contentWindow.onNextHydrated = () => {
resolve();
};
}
});
}

export function markAsHydrated() {
window.NEXT_HYDRATED = true;
if (typeof window.onNextHydrated === "function") {
window.onNextHydrated();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
"name": "@turbo/pack-test-harness",
"private": true,
"version": "0.0.1",
"main": "./harness.js",
"main": "./harness.ts",
"dependencies": {
"expect": "^24.5.0",
"jest-circus": "^29.4.1",
"jest-circus-browser": "^1.0.7"
}
}
7 changes: 7 additions & 0 deletions crates/next-dev-tests/test-harness/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
declare module "jest-circus-browser/dist/umd/jest-circus" {
export * from "jest-circus";
}

declare module "expect/build-es5/index" {
export { default } from "expect";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { useEffect } from "react";

export default function ErrorPage(props: { static: "static" }) {
useEffect(() => {
import("@turbo/pack-test-harness").then((harness) =>
harness.markAsHydrated()
);
});

return <div data-test-error>{props.static}</div>;
}

export function getStaticProps() {
return {
props: {
static: "static",
},
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { useEffect, useRef } from "react";

export default function Page() {
const iframeRef = useRef<HTMLIFrameElement | null>(null);

useEffect(() => {
// Only run on client
import("@turbo/pack-test-harness").then((mod) =>
runTests(mod, iframeRef.current!)
);
});

return (
<iframe style={{ width: 800, height: 600 }} src="/link" ref={iframeRef} />
);
}

type Harness = typeof import("@turbo/pack-test-harness");

function runTests(harness: Harness, iframe: HTMLIFrameElement) {
it("returns a 404 status code", async () => {
const res = await fetch("/not-found");
expect(res.status).toBe(404);
});

it("navigates to the 404 page", async () => {
await harness.waitForHydration(iframe, "/link");

const link = iframe.contentDocument!.querySelector("a[data-test-link]");
expect(link).not.toBeNull();
expect(link!).toBeInstanceOf(
(iframe.contentWindow as any).HTMLAnchorElement
);
expect(link!.textContent).toBe("Not found");

(link as HTMLAnchorElement).click();

await harness.waitForHydration(iframe, "/not-found");

const error = iframe.contentDocument!.querySelector("[data-test-error]");
expect(error).not.toBeNull();
expect(error!.textContent).toBe("static");
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Link from "next/link";
import { useEffect } from "react";

export default function Page() {
useEffect(() => {
import("@turbo/pack-test-harness").then((mod) => mod.markAsHydrated());
});

return (
<Link href="/not-found" data-test-link>
Not found
</Link>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default function Page() {
return <div>Page</div>;
}

export function getStaticProps() {
return {
notFound: true,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
{
"name": "next"
}
]
],
"paths": {
"@turbo/pack-test-harness": ["../../../../../../test-harness"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true
"incremental": true,
"paths": {
"@turbo/pack-test-harness": ["../../../../../../test-harness"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "pages/index.jsx"],
"exclude": ["node_modules"]
Expand Down
3 changes: 2 additions & 1 deletion crates/next-dev-tests/tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"name": "next-dev-tests",
"private": true,
"devDependencies": {
"@turbo/pack-test-harness": "*",
"@types/jest": "29.4.0",
"@turbo/pack-test-harness": "file:../test-harness",
"autoprefixer": "^10.4.13",
"loader-runner": "^4.3.0",
"next": "13.1.7-canary.2",
Expand Down
35 changes: 35 additions & 0 deletions crates/next-dev-tests/tests/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"compilerOptions": {
// type checking
"strict": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,

// interop constraints
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,

// js support
"allowJs": true,
"checkJs": false,

// environment
"jsx": "react-jsx",
"lib": ["ESNext", "DOM"],
"target": "esnext",

// modules
"baseUrl": ".",
"module": "esnext",
"moduleResolution": "node",

"paths": {
"@turbo/pack-test-harness": ["../test-harness"]
},

// emit
"noEmit": true,
"stripInternal": true
},
"include": ["integration"]
}
28 changes: 0 additions & 28 deletions crates/next-dev/test-harness/harness.js

This file was deleted.

Loading

0 comments on commit 741a127

Please sign in to comment.