Repository: vercel/next.js
Pull request: fix(test/e2e/prerender): Remove race condition in test

Fixed `setTimeout`s in tests are bad for flakiness, as they introduce potential race conditions.

https://vercel.slack.com/archives/C07UCHRBWGK/p1742074798403739

Instead of using a fixed timeout, check for a special marker file in a loop every 100ms.

Closes PACK-4177

Changed files:
filename: test/e2e/prerender.test.ts
patch: @@ -551,7 +551,7 @@ describe('Prerender', () => {
     })
   }
 
-  const runTests = (isDev = false, isDeploy) => {
+  const runTests = (isDev: boolean = false, isDeploy: boolean) => {
     navigateTest(isDev)
 
     it('should respond with 405 for POST to static page', async () => {
@@ -926,33 +926,45 @@ describe('Prerender', () => {
       const text = await browser.elementByCss('p').text()
       expect(text).toContain('hi fallback')
 
-      // wait for fallback data to load
-      await check(() => browser.elementByCss('p').text(), /Post/)
+      if (isDeploy) {
+        // patchFile does not work with deploy tests
+        return
+      }
+
+      await next.patchFile('resolve-static-props', '', async () => {
+        // wait for fallback data to load
+        await check(() => browser.elementByCss('p').text(), /Post/)
 
-      // check fallback data
-      const post = await browser.elementByCss('p').text()
-      const query = JSON.parse(await browser.elementByCss('#query').text())
-      const params = JSON.parse(await browser.elementByCss('#params').text())
+        // check fallback data
+        const post = await browser.elementByCss('p').text()
+        const query = JSON.parse(await browser.elementByCss('#query').text())
+        const params = JSON.parse(await browser.elementByCss('#params').text())
 
-      expect(post).toContain('first/post')
-      expect(params).toEqual({
-        slug: 'first/post',
+        expect(post).toContain('first/post')
+        expect(params).toEqual({
+          slug: 'first/post',
+        })
+        expect(query).toEqual(params)
       })
-      expect(query).toEqual(params)
     })
 
-    it('should handle fallback only page correctly data', async () => {
-      const data = JSON.parse(
-        await renderViaHTTP(
-          next.url,
-          `/_next/data/${next.buildId}/fallback-only/second%2Fpost.json`
-        )
-      )
+    // patchFile does not work with deploy tests
+    if (!isDeploy) {
+      it('should handle fallback only page correctly data', async () => {
+        await next.patchFile('resolve-static-props', '', async () => {
+          const data = JSON.parse(
+            await renderViaHTTP(
+              next.url,
+              `/_next/data/${next.buildId}/fallback-only/second%2Fpost.json`
+            )
+          )
 
-      expect(data.pageProps.params).toEqual({
-        slug: 'second/post',
+          expect(data.pageProps.params).toEqual({
+            slug: 'second/post',
+          })
+        })
       })
-    })
+    }
 
     it('should 404 for a missing catchall explicit route', async () => {
       const res = await fetchViaHTTP(

filename: test/e2e/prerender/pages/fallback-only/[slug].js
patch: @@ -1,6 +1,7 @@
 import React from 'react'
 import Link from 'next/link'
 import { useRouter } from 'next/router'
+import fs from 'node:fs/promises'
 
 export async function getStaticPaths() {
   return {
@@ -10,7 +11,13 @@ export async function getStaticPaths() {
 }
 
 export async function getStaticProps({ params }) {
-  await new Promise((resolve) => setTimeout(resolve, 1000))
+  while (true) {
+    try {
+      await fs.stat('resolve-static-props')
+      break
+    } catch (e) {}
+    await new Promise((resolve) => setTimeout(resolve, 100))
+  }
 
   return {
     props: {