| | import { nextTestSetup } from 'e2e-utils' |
| | import { retry } from 'next-test-utils' |
| | import * as nodePath from 'node:path' |
| | import type { Playwright } from '../../../lib/next-webdriver' |
| |
|
| | describe.each([ |
| | { |
| | description: 'without runtime prefetch configs', |
| | hasRuntimePrefetch: false, |
| | fixturePath: 'fixtures/without-prefetch-config', |
| | }, |
| | { |
| | description: 'with runtime prefetch configs', |
| | hasRuntimePrefetch: true, |
| | fixturePath: 'fixtures/with-prefetch-config', |
| | }, |
| | ])( |
| | 'cache-components-tasks - $description', |
| | ({ fixturePath, hasRuntimePrefetch }) => { |
| | const { next, isTurbopack, isNextDev } = nextTestSetup({ |
| | files: nodePath.join(__dirname, fixturePath), |
| | }) |
| |
|
| | function assertLog( |
| | logs: Array<{ source: string; message: string }>, |
| | message: string, |
| | expectedEnvironment: string |
| | ) { |
| | |
| | const logPattern = new RegExp( |
| | `^(?=.*\\b${message}\\b)(?=.*\\b(Cache|Prerender|Prefetch|Prefetchable|Server)\\b).*` |
| | ) |
| | const logMessages = logs.map((log) => log.message) |
| | const messages = logMessages.filter((message) => logPattern.test(message)) |
| |
|
| | |
| | if (messages.length === 0) { |
| | throw new Error( |
| | `Found no logs matching '${message}':\n\n${logMessages.map((s, i) => `${i}. ${s}`).join('\n')}}` |
| | ) |
| | } |
| | if (messages.length > 1) { |
| | throw new Error( |
| | `Found multiple logs matching '${message}':\n\n${messages.map((s, i) => `${i}. ${s}`).join('\n')}` |
| | ) |
| | } |
| |
|
| | |
| | const actualMessageText = messages[0] |
| | const [, actualEnvironment] = actualMessageText.match(logPattern)! |
| | expect([actualEnvironment, actualMessageText]).toEqual([ |
| | expectedEnvironment, |
| | expect.stringContaining(message), |
| | ]) |
| | } |
| |
|
| | function assertNoUnexpectedErrorsInCli() { |
| | |
| | expect(next.cliOutput).not.toContain( |
| | 'AbortError: This operation was aborted' |
| | ) |
| | |
| | expect(next.cliOutput).not.toContain( |
| | "Next.js cannot guarantee that Cache Components will run as expected due to the current runtime's implementation of `setTimeout()`" |
| | ) |
| | } |
| |
|
| | async function testInitialLoad( |
| | path: string, |
| | assertLogs: (browser: Playwright) => Promise<void> |
| | ) { |
| | const browser = await next.browser(path) |
| |
|
| | |
| | await retry(() => assertLogs(browser)) |
| | assertNoUnexpectedErrorsInCli() |
| |
|
| | |
| | await browser.loadPage(next.url + path) |
| | await retry(() => assertLogs(browser)) |
| | assertNoUnexpectedErrorsInCli() |
| |
|
| | if (isNextDev && isTurbopack) { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | console.log('WARNING: skipping revalidation assertions in turbopack') |
| | return |
| | } |
| |
|
| | |
| | |
| | |
| | await revalidatePath(path) |
| |
|
| | await browser.loadPage(next.url + path) |
| | await retry(() => assertLogs(browser)) |
| | assertNoUnexpectedErrorsInCli() |
| | } |
| |
|
| | async function testNavigation( |
| | path: string, |
| | assertLogs: (browser: Playwright) => Promise<void> |
| | ) { |
| | const browser = await next.browser('/') |
| |
|
| | |
| | await browser.elementByCss(`a[href="${path}"]`).click() |
| | await retry(() => assertLogs(browser)) |
| | assertNoUnexpectedErrorsInCli() |
| |
|
| | |
| | await browser.loadPage(next.url + '/') |
| | await browser.elementByCss(`a[href="${path}"]`).click() |
| | await retry(() => assertLogs(browser)) |
| | assertNoUnexpectedErrorsInCli() |
| |
|
| | if (isNextDev && isTurbopack) { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | console.log('WARNING: skipping revalidation assertions in turbopack') |
| | return |
| | } |
| |
|
| | |
| | |
| | |
| | await revalidatePath(path) |
| |
|
| | await browser.loadPage(next.url + '/') |
| | await browser.elementByCss(`a[href="${path}"]`).click() |
| | await retry(() => assertLogs(browser)) |
| | assertNoUnexpectedErrorsInCli() |
| | } |
| |
|
| | async function revalidatePath(path: string) { |
| | const response = await next.fetch( |
| | `/revalidate?path=${encodeURIComponent(path)}` |
| | ) |
| | if (!response.ok) { |
| | throw new Error( |
| | `Failed to revalidate path: '${path}' - server responded with status ${response.status}` |
| | ) |
| | } |
| | } |
| |
|
| | const RUNTIME_ENV = hasRuntimePrefetch ? 'Prefetch' : 'Prefetchable' |
| |
|
| | describe.each([ |
| | { description: 'initial load', isInitialLoad: true }, |
| | { description: 'navigation', isInitialLoad: false }, |
| | ])('$description', ({ isInitialLoad }) => { |
| | it('setImmediate resolves between tasks', async () => { |
| | const path = '/simple' |
| | const assertLogs = async (browser: Playwright) => { |
| | const logs = await browser.log() |
| | assertLog(logs, 'after immediate - static - layout', 'Prerender') |
| | assertLog(logs, 'after immediate - static - page', 'Prerender') |
| |
|
| | assertLog(logs, 'after cookies - layout', RUNTIME_ENV) |
| | assertLog(logs, 'after cookies - page', RUNTIME_ENV) |
| | assertLog(logs, 'after immediate - runtime - layout', RUNTIME_ENV) |
| | assertLog(logs, 'after immediate - runtime - page', RUNTIME_ENV) |
| |
|
| | assertLog(logs, 'after connection - layout', 'Server') |
| | assertLog(logs, 'after connection - page', 'Server') |
| | assertLog(logs, 'after immediate - dynamic - layout', 'Server') |
| | assertLog(logs, 'after immediate - dynamic - page', 'Server') |
| | } |
| |
|
| | if (isInitialLoad) { |
| | await testInitialLoad(path, assertLogs) |
| | } else { |
| | await testNavigation(path, assertLogs) |
| | } |
| | }) |
| | }) |
| | } |
| | ) |
| |
|