diff --git a/test/e2e/app-dir/actions/app-action.test.ts b/test/e2e/app-dir/actions/app-action.test.ts index 34f9127ab77ab..a6c895392862f 100644 --- a/test/e2e/app-dir/actions/app-action.test.ts +++ b/test/e2e/app-dir/actions/app-action.test.ts @@ -8,10 +8,10 @@ import { getRedboxSource, } from 'next-test-utils' import type { Request, Response } from 'playwright' -import fs from 'fs-extra' -import nodeFs from 'fs' -import { join } from 'path' +import fs from 'node:fs/promises' +import { join } from 'node:path' import { outdent } from 'outdent' +import { setTimeout } from 'node:timers/promises' const GENERIC_RSC_ERROR = 'Error: An error occurred in the Server Components render. The specific message is omitted in production builds to avoid leaking sensitive details. A digest property is included on this error instance which may provide additional details about the nature of the error.' @@ -540,10 +540,10 @@ describe('app-dir action handling', () => { // this triggers a revalidate + redirect in a client component await browser.elementById('redirect-revalidate-client').click() await retry(async () => { + expect(await browser.url()).toBe(`${next.url}/revalidate?foo=bar`) + const newJustPutIt = await browser.elementById('justputit').text() expect(newJustPutIt).not.toBe(initialJustPutit) - - expect(await browser.url()).toBe(`${next.url}/revalidate?foo=bar`) }) // this triggers a revalidate + redirect in a server component @@ -593,7 +593,8 @@ describe('app-dir action handling', () => { beforePageLoad(page) { page.on('request', (request) => { const url = new URL(request.url()) - if (url.pathname === '/server') { + // Only count POST requests to /server (form submissions) + if (url.pathname === '/server' && request.method() === 'POST') { requestCount++ } }) @@ -963,16 +964,21 @@ describe('app-dir action handling', () => { if (isNextStart) { it('should not expose action content in sourcemaps', async () => { // We check all sourcemaps in the `static` folder for sensitive information given that chunking - const sourcemaps = nodeFs - .readdirSync(join(next.testDir, '.next', 'static'), { + const sourcemaps = await fs + .readdir(join(next.testDir, '.next', 'static'), { recursive: true, encoding: 'utf8', }) - .filter((f) => f.endsWith('.js.map')) - .map((f) => - nodeFs.readFileSync(join(next.testDir, '.next', 'static', f), { - encoding: 'utf8', - }) + .then((files) => + Promise.all( + files + .filter((f) => f.endsWith('.js.map')) + .map((f) => + fs.readFile(join(next.testDir, '.next', 'static', f), { + encoding: 'utf8', + }) + ) + ) ) expect(sourcemaps).not.toBeEmpty() @@ -1046,23 +1052,22 @@ describe('app-dir action handling', () => { it('should bundle external libraries if they are on the action layer', async () => { await next.fetch('/client') const pageBundle = await fs.readFile( - join(next.testDir, '.next', 'server', 'app', 'client', 'page.js') + join(next.testDir, '.next', 'server', 'app', 'client', 'page.js'), + { encoding: 'utf8' } ) if (isTurbopack) { - const chunkPaths = pageBundle - .toString() - .matchAll(/loadChunk\("([^"]*)"\)/g) - // @ts-ignore + const chunkPaths = pageBundle.matchAll(/loadChunk\("([^"]*)"\)/g) const reads = [...chunkPaths].map(async (match) => { const bundle = await fs.readFile( - join(next.testDir, '.next', ...match[1].split(/[\\/]/g)) + join(next.testDir, '.next', ...match[1].split(/[\\/]/g)), + { encoding: 'utf8' } ) - return bundle.toString().includes('node_modules/nanoid/index.js') + return bundle.includes('node_modules/nanoid/index.js') }) expect(await Promise.all(reads)).toContain(true) } else { - expect(pageBundle.toString()).toContain('node_modules/nanoid/index.js') + expect(pageBundle).toContain('node_modules/nanoid/index.js') } }) } @@ -1526,7 +1531,7 @@ describe('app-dir action handling', () => { const browser = await next.browser('/revalidate') await browser.refresh() - const thankYouNext = await browser.elementByCss('#thankyounext').text() + const original = await browser.elementByCss('#thankyounext').text() await browser.elementByCss('#another').click() await retry(async () => { @@ -1535,47 +1540,54 @@ describe('app-dir action handling', () => { ) }) - const newThankYouNext = await browser - .elementByCss('#thankyounext') - .text() - - // Should be the same number although in serverless - // it might be eventually consistent + // Should be the same number although in serverless it might be + // eventually consistent. if (!isNextDeploy) { - expect(thankYouNext).toEqual(newThankYouNext) + await retry(async () => { + const another = await browser.elementByCss('#thankyounext').text() + expect(another).toEqual(original) + }) } await browser.elementByCss('#back').click() - - // Should be different - let revalidatedThankYouNext await retry(async () => { - switch (type) { - case 'tag': - await browser.elementByCss('#revalidate-thankyounext').click() - break - case 'path': - await browser.elementByCss('#revalidate-path').click() - break - default: - throw new Error(`Invalid type: ${type}`) - } + expect(await browser.elementByCss('#title').text()).toBe('revalidate') + }) - revalidatedThankYouNext = await browser - .elementByCss('#thankyounext') - .text() + switch (type) { + case 'tag': + await browser.elementByCss('#revalidate-thankyounext').click() + break + case 'path': + await browser.elementByCss('#revalidate-path').click() + break + default: + throw new Error(`Invalid type: ${type}`) + } - expect(thankYouNext).not.toBe(revalidatedThankYouNext) + // Give some time for it to be revalidated. + if (isNextDeploy) { + await setTimeout(5000) + } + + // Should be different + let revalidated + await retry(async () => { + revalidated = await browser.elementByCss('#thankyounext').text() + expect(revalidated).not.toBe(original) }) await browser.elementByCss('#another').click() + await retry(async () => { + expect(await browser.elementByCss('#title').text()).toBe( + 'another route' + ) + }) // The other page should be revalidated too await retry(async () => { - const newThankYouNext = await browser - .elementByCss('#thankyounext') - .text() - expect(revalidatedThankYouNext).toBe(newThankYouNext) + const another = await browser.elementByCss('#thankyounext').text() + expect(another).toBe(revalidated) }) } ) diff --git a/test/e2e/app-dir/actions/app/revalidate-2/page.js b/test/e2e/app-dir/actions/app/revalidate-2/page.js index 32f21e443a39c..0d348ab19a6bf 100644 --- a/test/e2e/app-dir/actions/app/revalidate-2/page.js +++ b/test/e2e/app-dir/actions/app/revalidate-2/page.js @@ -3,6 +3,7 @@ import { cookies } from 'next/headers' import Link from 'next/link' export default async function Page() { + const randomCookie = (await cookies()).get('random') const data = await fetch( 'https://next-data-api-endpoint.vercel.app/api/random?page', { @@ -33,9 +34,7 @@ export default async function Page() {
random cookie:{' '} -
> ) diff --git a/test/e2e/app-dir/actions/app/revalidate/page.js b/test/e2e/app-dir/actions/app/revalidate/page.js index 800fae31ef83e..7e3de04841b53 100644 --- a/test/e2e/app-dir/actions/app/revalidate/page.js +++ b/test/e2e/app-dir/actions/app/revalidate/page.js @@ -6,6 +6,7 @@ import { cookies } from 'next/headers' import RedirectClientComponent from './client' export default async function Page() { + const cookie = (await cookies()).get('random') const data = await fetch( 'https://next-data-api-endpoint.vercel.app/api/random?page', { @@ -22,7 +23,7 @@ export default async function Page() { return ( <> - +/revalidate
+{' '} revalidate (tags: thankyounext): @@ -39,10 +40,7 @@ export default async function Page() { {data2}
- random cookie:{' '} -
+ random cookie: