Files
vercel__next.js/test/development/acceptance/server-component-compiler-errors-in-pages.test.ts
Niklas Mischkulnig 9b8a7a1055 Turbopack: improve issue printing colors (#94858)
1. Align the code highlight marker color with the issue severity
2. Make the issue title colored
3. Prefix issues with `Warning` or `Error`


<img width="1383" height="862" alt="Bildschirmfoto 2026-06-16 um 18 59
03"
src="https://github.com/user-attachments/assets/f98c606d-4ea8-40c2-836d-e395f1df904c"
/>


<img width="1039" height="450" alt="Bildschirmfoto 2026-06-16 um 19 03
39"
src="https://github.com/user-attachments/assets/2747f914-0587-4178-a87d-344f24715c96"
/>



<details>
<summary>Old</summary>

<img width="1267" height="745" alt="Bildschirmfoto 2026-06-16 um 17 04
35"
src="https://github.com/user-attachments/assets/837739ff-82f7-4ea2-8767-ca7d866a8570"
/>

</details>
2026-06-16 21:29:37 +02:00

438 lines
14 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* eslint-env jest */
import { nextTestSetup } from 'e2e-utils'
import { createSandbox } from 'development-sandbox'
import { outdent } from 'outdent'
const isRspack = process.env.NEXT_RSPACK !== undefined
const initialFiles = new Map([
['app/_.js', ''], // app dir need to exists, otherwise the SWC RSC checks will not run
[
'pages/index.js',
outdent`
import Comp from '../components/Comp'
export default function Page() { return <Comp /> }
`,
],
[
'components/Comp.js',
outdent`
export default function Comp() {
return <p>Hello world</p>
}
`,
],
])
describe('Error Overlay for server components compiler errors in pages', () => {
const { next } = nextTestSetup({
files: {},
skipStart: true,
})
test("importing 'next/headers' in pages", async () => {
await using sandbox = await createSandbox(next, initialFiles)
const { session } = sandbox
await session.patch(
'components/Comp.js',
outdent`
import { cookies } from 'next/headers'
export default function Page() {
return <p>hello world</p>
}
`
)
await session.waitForRedbox()
await expect(session.getRedboxSource()).resolves.toMatch(
/This API is only available in Server Components/
)
if (process.env.IS_TURBOPACK_TEST) {
expect(next.normalizeTestDirContent(await session.getRedboxSource()))
.toMatchInlineSnapshot(`
"./components/Comp.js (1:1)
Error: You're importing a module that depends on "next/headers". This API is only available in Server Components in the App Router, but you are using it in the Pages Router.
Learn more: https://nextjs.org/docs/app/building-your-application/rendering/server-components
> 1 | import { cookies } from 'next/headers'
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2 |
3 | export default function Page() {
4 | return <p>hello world</p>
Ecmascript file had an error
Import traces:
Browser:
./components/Comp.js
./pages/index.js
SSR:
./components/Comp.js
./pages/index.js"
`)
} else if (isRspack) {
expect(
takeUpToString(
next.normalizeTestDirContent(await session.getRedboxSource()),
'----'
)
).toMatchInlineSnapshot(`
"./components/Comp.js
╰─▶ × Error: x You're importing a module that depends on "next/headers". This API is only available in Server Components in the App Router, but you are using it in the Pages Router.
│ | Learn more: https://nextjs.org/docs/app/building-your-application/rendering/server-components
│ |
│
│ ,-[1:1]
│ 1 | import { cookies } from 'next/headers'
│ : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
│ 2 |
│ 3 | export default function Page() {
│ 4 | return <p>hello world</p>
│ \`----"
`)
} else {
expect(next.normalizeTestDirContent(await session.getRedboxSource()))
.toMatchInlineSnapshot(`
"./components/Comp.js
Error: x You're importing a module that depends on "next/headers". This API is only available in Server Components in the App Router, but you are using it in the Pages Router.
| Learn more: https://nextjs.org/docs/app/building-your-application/rendering/server-components
|
,-[1:1]
1 | import { cookies } from 'next/headers'
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2 |
3 | export default function Page() {
4 | return <p>hello world</p>
\`----
Import trace for requested module:
./components/Comp.js
./pages/index.js"
`)
}
})
test("importing 'server-only' in pages", async () => {
await using sandbox = await createSandbox(next, initialFiles)
const { session } = sandbox
await next.patchFile(
'components/Comp.js',
outdent`
import 'server-only'
export default function Page() {
return 'hello world'
}
`
)
await session.waitForRedbox()
await expect(session.getRedboxSource()).resolves.toMatch(
/This API is only available in Server Components/
)
if (process.env.IS_TURBOPACK_TEST) {
expect(next.normalizeTestDirContent(await session.getRedboxSource()))
.toMatchInlineSnapshot(`
"./components/Comp.js (1:1)
Error: You're importing a module that depends on "server-only". This API is only available in Server Components in the App Router, but you are using it in the Pages Router.
Learn more: https://nextjs.org/docs/app/building-your-application/rendering/server-components
> 1 | import 'server-only'
| ^^^^^^^^^^^^^^^^^^^^
2 |
3 | export default function Page() {
4 | return 'hello world'
Ecmascript file had an error
Import traces:
Browser:
./components/Comp.js
./pages/index.js
SSR:
./components/Comp.js
./pages/index.js"
`)
} else if (isRspack) {
expect(
takeUpToString(
next.normalizeTestDirContent(await session.getRedboxSource()),
'----'
)
).toMatchInlineSnapshot(`
"./components/Comp.js
╰─▶ × Error: x You're importing a module that depends on "server-only". This API is only available in Server Components in the App Router, but you are using it in the Pages Router.
│ | Learn more: https://nextjs.org/docs/app/building-your-application/rendering/server-components
│ |
│
│ ,-[1:1]
│ 1 | import 'server-only'
│ : ^^^^^^^^^^^^^^^^^^^^
│ 2 |
│ 3 | export default function Page() {
│ 4 | return 'hello world'
│ \`----"
`)
} else {
expect(
takeUpToString(
next.normalizeTestDirContent(await session.getRedboxSource()),
'Import trace for requested module:'
)
).toMatchInlineSnapshot(`
"./components/Comp.js
Error: x You're importing a module that depends on "server-only". This API is only available in Server Components in the App Router, but you are using it in the Pages Router.
| Learn more: https://nextjs.org/docs/app/building-your-application/rendering/server-components
|
,-[1:1]
1 | import 'server-only'
: ^^^^^^^^^^^^^^^^^^^^
2 |
3 | export default function Page() {
4 | return 'hello world'
\`----
Import trace for requested module:"
`)
}
})
test("importing after from 'next/server' in pages", async () => {
await using sandbox = await createSandbox(next, initialFiles)
const { session } = sandbox
await next.patchFile(
'components/Comp.js',
outdent`
import { after } from 'next/server'
export default function Page() {
return 'hello world'
}
`
)
await session.waitForRedbox()
await expect(session.getRedboxSource()).resolves.toMatch(
/This API is only available in Server Components/
)
if (process.env.IS_TURBOPACK_TEST) {
expect(next.normalizeTestDirContent(await session.getRedboxSource()))
.toMatchInlineSnapshot(`
"./components/Comp.js (1:10)
Error: You're importing a module that depends on "after". This API is only available in Server Components in the App Router, but you are using it in the Pages Router.
Learn more: https://nextjs.org/docs/app/building-your-application/rendering/server-components
> 1 | import { after } from 'next/server'
| ^^^^^
2 |
3 | export default function Page() {
4 | return 'hello world'
Ecmascript file had an error
Import traces:
Browser:
./components/Comp.js
./pages/index.js
SSR:
./components/Comp.js
./pages/index.js"
`)
} else if (isRspack) {
expect(
takeUpToString(
next.normalizeTestDirContent(await session.getRedboxSource()),
'----'
)
).toMatchInlineSnapshot(`
"./components/Comp.js
╰─▶ × Error: x You're importing a module that depends on "after". This API is only available in Server Components in the App Router, but you are using it in the Pages Router.
│ | Learn more: https://nextjs.org/docs/app/building-your-application/rendering/server-components
│ |
│
│ ,-[1:1]
│ 1 | import { after } from 'next/server'
│ : ^^^^^
│ 2 |
│ 3 | export default function Page() {
│ 4 | return 'hello world'
│ \`----"
`)
} else {
expect(
takeUpToString(
next.normalizeTestDirContent(await session.getRedboxSource()),
'Import trace for requested module:'
)
).toMatchInlineSnapshot(`
"./components/Comp.js
Error: x You're importing a module that depends on "after". This API is only available in Server Components in the App Router, but you are using it in the Pages Router.
| Learn more: https://nextjs.org/docs/app/building-your-application/rendering/server-components
|
,-[1:1]
1 | import { after } from 'next/server'
: ^^^^^
2 |
3 | export default function Page() {
4 | return 'hello world'
\`----
Import trace for requested module:"
`)
}
})
test("importing 'next/root-params' in pages", async () => {
const files = new Map([
...initialFiles,
[
'components/Comp.js',
outdent`
import { foo } from 'next/root-params'
export default function Page() {
return 'hello world'
}
`,
],
])
await using sandbox = await createSandbox(next, files)
const { session } = sandbox
await session.waitForRedbox()
await expect(session.getRedboxSource()).resolves.toMatch(
/This API is only available in Server Components/
)
if (process.env.IS_TURBOPACK_TEST) {
expect(next.normalizeTestDirContent(await session.getRedboxSource()))
.toMatchInlineSnapshot(`
"./components/Comp.js (1:1)
Error: You're importing a module that depends on "next/root-params". This API is only available in Server Components in the App Router, but you are using it in the Pages Router.
Learn more: https://nextjs.org/docs/app/building-your-application/rendering/server-components
> 1 | import { foo } from 'next/root-params'
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2 |
3 | export default function Page() {
4 | return 'hello world'
Ecmascript file had an error
Import traces:
Browser:
./components/Comp.js
./pages/index.js
SSR:
./components/Comp.js
./pages/index.js"
`)
} else if (isRspack) {
expect(
takeUpToString(
next.normalizeTestDirContent(await session.getRedboxSource()),
'----'
)
).toMatchInlineSnapshot(`
"./components/Comp.js
╰─▶ × Error: x You're importing a module that depends on "next/root-params". This API is only available in Server Components in the App Router, but you are using it in the Pages Router.
│ | Learn more: https://nextjs.org/docs/app/building-your-application/rendering/server-components
│ |
│
│ ,-[1:1]
│ 1 | import { foo } from 'next/root-params'
│ : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
│ 2 |
│ 3 | export default function Page() {
│ 4 | return 'hello world'
│ \`----"
`)
} else {
expect(
takeUpToString(
next.normalizeTestDirContent(await session.getRedboxSource()),
'Import trace for requested module:'
)
).toMatchInlineSnapshot(`
"./components/Comp.js
Error: x You're importing a module that depends on "next/root-params". This API is only available in Server Components in the App Router, but you are using it in the Pages Router.
| Learn more: https://nextjs.org/docs/app/building-your-application/rendering/server-components
|
,-[1:1]
1 | import { foo } from 'next/root-params'
: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2 |
3 | export default function Page() {
4 | return 'hello world'
\`----"
`)
}
})
describe("importing 'next/cache' APIs in pages", () => {
test.each([
'revalidatePath',
'revalidateTag',
'cacheLife',
'cacheTag',
'revalidatePath',
'revalidateTag',
])('%s is not allowed', async (api) => {
await using sandbox = await createSandbox(next, initialFiles)
const { session } = sandbox
await next.patchFile(
'components/Comp.js',
outdent`
import { ${api} } from 'next/cache'
export default function Page() {
return 'hello world'
}
`
)
await session.waitForRedbox()
await expect(session.getRedboxSource()).resolves.toMatch(
`You're importing a module that depends on "${api}". This API is only available in Server Components in the App Router, but you are using it in the Pages Router.`
)
})
test.each([
'unstable_cache', // useless in client, but doesn't technically error
'unstable_noStore', // no-op in client, but allowed for legacy reasons
])('%s is allowed', async (api) => {
await using sandbox = await createSandbox(next, initialFiles)
const { session } = sandbox
await next.patchFile(
'components/Comp.js',
outdent`
import { ${api} } from 'next/cache'
export default function Page() {
return 'hello world'
}
`
)
await session.waitForNoRedbox()
})
})
})
const takeUpToString = (text: string, str: string): string =>
text.includes(str) ? text.slice(0, text.indexOf(str) + str.length) : text