Some checks failed
Test examples / Test Examples (20) (push) Has been cancelled
Test examples / Test Examples (22) (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Trigger Release / start (push) Has been cancelled
Stale issue handler / stale (push) Has been cancelled
Update Font Data / create-pull-request (push) Has been cancelled
build-and-deploy / deploy-target (push) Has been cancelled
build-and-deploy / build (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / build-wasm (nodejs) (push) Has been cancelled
build-and-deploy / build-wasm (web) (push) Has been cancelled
build-and-deploy / Deploy preview tarball (push) Has been cancelled
build-and-deploy / Potentially publish release (push) Has been cancelled
build-and-deploy / publish-turbopack-npm-packages (push) Has been cancelled
build-and-deploy / Deploy examples (push) Has been cancelled
build-and-deploy / thank you, build (push) Has been cancelled
build-and-deploy / Upload Turbopack Bytesize metrics to Datadog (push) Has been cancelled
Rspack Next.js development integration tests / Rspack integration tests (push) Has been cancelled
Rspack Next.js production integration tests / Rspack integration tests (push) Has been cancelled
Turbopack Next.js development integration tests / Next.js integration tests (push) Has been cancelled
Turbopack Next.js production integration tests / Next.js integration tests (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack development test manifest (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack production test manifest (push) Has been cancelled
Upload bundler test manifests to areweturboyet.com / Upload test results (push) Has been cancelled
Update React / create-pull-request (push) Has been cancelled
test-e2e-project-reset-cron / reset-test-project (push) Has been cancelled
Notify about the top 15 issues/PRs/feature requests (most reacted) in the last 90 days / run (push) Has been cancelled
198 lines
6.8 KiB
TypeScript
198 lines
6.8 KiB
TypeScript
import { nextTestSetup } from 'e2e-utils'
|
|
import escapeStringRegexp from 'escape-string-regexp'
|
|
import {
|
|
getRedboxDescription,
|
|
getRedboxSource,
|
|
openRedbox,
|
|
waitForRedbox,
|
|
getRedboxTitle,
|
|
getRedboxTotalErrorCount,
|
|
} from 'next-test-utils'
|
|
import stripAnsi from 'strip-ansi'
|
|
|
|
const expectedTimeoutErrorMessage =
|
|
'Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or dynamic data were used inside "use cache".'
|
|
|
|
describe('use-cache-hanging-inputs', () => {
|
|
const { next, isNextDev, skipped } = nextTestSetup({
|
|
files: __dirname,
|
|
skipDeployment: true,
|
|
skipStart: process.env.NEXT_TEST_MODE !== 'dev',
|
|
})
|
|
|
|
if (skipped) {
|
|
return
|
|
}
|
|
|
|
if (isNextDev) {
|
|
// TODO(restart-on-cache-miss): reenable when fixed
|
|
describe.skip('when an uncached promise is used inside of "use cache"', () => {
|
|
it('should show an error toast after a timeout', async () => {
|
|
const outputIndex = next.cliOutput.length
|
|
const browser = await next.browser('/uncached-promise')
|
|
|
|
// The request is pending while we stall on the hanging inputs, and
|
|
// playwright will wait for the load even before continuing. So we don't
|
|
// need to wait for the "use cache" timeout of 50 seconds here.
|
|
|
|
await openRedbox(browser)
|
|
|
|
const errorCount = await getRedboxTotalErrorCount(browser)
|
|
const errorDescription = await getRedboxDescription(browser)
|
|
const errorSource = await getRedboxSource(browser)
|
|
|
|
expect(errorCount).toBe(1)
|
|
expect(errorDescription).toBe(expectedTimeoutErrorMessage)
|
|
|
|
const cliOutput = stripAnsi(next.cliOutput.slice(outputIndex))
|
|
|
|
expect(errorSource).toMatchInlineSnapshot(`
|
|
"app/uncached-promise/page.tsx (10:13) @ Foo
|
|
|
|
8 | }
|
|
9 |
|
|
> 10 | const Foo = async ({ promise }) => {
|
|
| ^
|
|
11 | 'use cache'
|
|
12 |
|
|
13 | return ("
|
|
`)
|
|
|
|
expect(cliOutput).toContain(`Error: ${expectedTimeoutErrorMessage}
|
|
at Foo (app/uncached-promise/page.tsx:10:13)`)
|
|
}, 180_000)
|
|
})
|
|
|
|
// TODO(restart-on-cache-miss): reenable when fixed
|
|
describe.skip('when an uncached promise is used inside of a nested "use cache"', () => {
|
|
it('should show an error toast after a timeout', async () => {
|
|
const outputIndex = next.cliOutput.length
|
|
const browser = await next.browser('/uncached-promise-nested')
|
|
|
|
// The request is pending while we stall on the hanging inputs, and
|
|
// playwright will wait for the load even before continuing. So we don't
|
|
// need to wait for the "use cache" timeout of 50 seconds here.
|
|
|
|
await openRedbox(browser)
|
|
|
|
const errorCount = await getRedboxTotalErrorCount(browser)
|
|
const errorDescription = await getRedboxDescription(browser)
|
|
const errorSource = await getRedboxSource(browser)
|
|
|
|
expect(errorCount).toBe(1)
|
|
expect(errorDescription).toBe(expectedTimeoutErrorMessage)
|
|
|
|
const cliOutput = stripAnsi(next.cliOutput.slice(outputIndex))
|
|
|
|
expect(errorSource).toMatchInlineSnapshot(`
|
|
"app/uncached-promise-nested/page.tsx (16:1) @ indirection
|
|
|
|
14 | }
|
|
15 |
|
|
> 16 | async function indirection(promise: Promise<number>) {
|
|
| ^
|
|
17 | 'use cache'
|
|
18 |
|
|
19 | return getCachedData(promise)"
|
|
`)
|
|
|
|
expect(cliOutput).toContain(`Error: ${expectedTimeoutErrorMessage}
|
|
at indirection (app/uncached-promise-nested/page.tsx:16:1)
|
|
at Page (app/uncached-promise-nested/page.tsx:23:22)`)
|
|
}, 180_000)
|
|
})
|
|
|
|
// TODO(restart-on-cache-miss): reenable when fixed
|
|
describe.skip('when a "use cache" function is closing over an uncached promise', () => {
|
|
it('should show an error toast after a timeout', async () => {
|
|
const outputIndex = next.cliOutput.length
|
|
const browser = await next.browser('/bound-args')
|
|
|
|
// The request is pending while we stall on the hanging inputs, and
|
|
// playwright will wait for the load even before continuing. So we don't
|
|
// need to wait for the "use cache" timeout of 50 seconds here.
|
|
|
|
await openRedbox(browser)
|
|
|
|
const errorCount = await getRedboxTotalErrorCount(browser)
|
|
const errorDescription = await getRedboxDescription(browser)
|
|
const errorSource = await getRedboxSource(browser)
|
|
|
|
expect(errorCount).toBe(1)
|
|
|
|
const cliOutput = stripAnsi(next.cliOutput.slice(outputIndex))
|
|
|
|
expect(errorDescription).toBe(expectedTimeoutErrorMessage)
|
|
|
|
expect(errorSource).toMatchInlineSnapshot(`
|
|
"app/bound-args/page.tsx (13:15) @ Foo
|
|
|
|
11 | const uncachedDataPromise = fetchUncachedData()
|
|
12 |
|
|
> 13 | const Foo = async () => {
|
|
| ^
|
|
14 | 'use cache'
|
|
15 |
|
|
16 | return ("
|
|
`)
|
|
|
|
expect(cliOutput).toContain(`Error: ${expectedTimeoutErrorMessage}
|
|
at Foo (app/bound-args/page.tsx:13:15)`)
|
|
}, 180_000)
|
|
})
|
|
|
|
describe('when an error is thrown', () => {
|
|
it('should show an error overlay with only one error', async () => {
|
|
const browser = await next.browser('/error')
|
|
|
|
await waitForRedbox(browser)
|
|
|
|
const count = await getRedboxTotalErrorCount(browser)
|
|
const title = await getRedboxTitle(browser)
|
|
const description = await getRedboxDescription(browser)
|
|
|
|
expect({ count, title, description }).toEqual({
|
|
count: 1,
|
|
// TODO(restart-on-cache-miss): fix environment labelling
|
|
// title: 'Runtime Error\nCache',
|
|
title: 'Runtime Error\nPrerender',
|
|
description: 'kaputt!',
|
|
})
|
|
})
|
|
})
|
|
} else {
|
|
// TODO: Be more precise about the expected error messages and stacks.
|
|
it('should fail the build with errors after a timeout', async () => {
|
|
const { cliOutput } = await next.build()
|
|
|
|
expect(cliOutput).toInclude(createExpectedBuildErrorMessage('/error'))
|
|
expect(cliOutput).toInclude('Error: kaputt!')
|
|
|
|
expect(cliOutput).toIncludeRepeated(
|
|
escapeStringRegexp(expectedTimeoutErrorMessage),
|
|
4
|
|
)
|
|
|
|
expect(cliOutput).toInclude(
|
|
createExpectedBuildErrorMessage('/bound-args')
|
|
)
|
|
|
|
expect(cliOutput).toInclude(
|
|
createExpectedBuildErrorMessage('/transformed-params/[slug]')
|
|
)
|
|
|
|
expect(cliOutput).toInclude(
|
|
createExpectedBuildErrorMessage('/uncached-promise')
|
|
)
|
|
|
|
expect(cliOutput).toInclude(
|
|
createExpectedBuildErrorMessage('/uncached-promise-nested')
|
|
)
|
|
}, 180_000)
|
|
}
|
|
})
|
|
|
|
function createExpectedBuildErrorMessage(pathname: string) {
|
|
return `Error occurred prerendering page "${pathname}". Read more: https://nextjs.org/docs/messages/prerender-error`
|
|
}
|