Repository: vercel/next.js
Pull request: [test] Fix `app-static` deploy test

The test previously included the time for the boot of the function. We're only interested in not blocking on revalidating though.

This introduces a different problem if clocks between Client and Server aren't synced though.  A proper fix would leverage `Server-Timing` headers where Next.js would include when the first chunk was sent. We don't have that yet though so we have to pray the clocks are close enough.

Changed files:
filename: test/e2e/app-dir/app-static/app-static.test.ts
patch: @@ -2763,27 +2763,51 @@ describe('app-dir static/dynamic handling', () => {
     for (let i = 0; i < 6; i++) {
       await waitFor(1000)
 
-      const timings = {
-        start: Date.now(),
-        startedStreaming: 0,
-      }
-
       res = await next.fetch(path)
 
-      // eslint-disable-next-line no-loop-func
-      await new Promise<void>((resolve) => {
-        res.body.on('data', () => {
-          if (!timings.startedStreaming) {
-            timings.startedStreaming = Date.now()
-          }
-        })
-
-        res.body.on('end', () => {
-          resolve()
-        })
+      let data: any
+      let startedStreaming: number = -1
+      res.body.on('data', () => {
+        if (startedStreaming === -1) {
+          startedStreaming = Date.now()
+        }
       })
+      if (res.headers.get('content-type').includes('application/json')) {
+        data = await res.json()
+      } else {
+        const html = await res.text()
+        const $ = cheerio.load(html)
+        const dataJSON = $('#data').text()
+        try {
+          data = JSON.parse(dataJSON)
+        } catch (cause) {
+          throw new Error(
+            `Failed to parse JSON from data-start attribute: "${dataJSON}"`,
+            { cause }
+          )
+        }
+      }
 
-      expect(timings.startedStreaming - timings.start).toBeLessThan(3000)
+      const startedResponding = +data.start
+      if (Number.isNaN(startedResponding)) {
+        throw new Error(
+          `Expected start to be a number. Received: "${data.start}"`
+        )
+      }
+      if (startedStreaming === -1) {
+        throw new Error(
+          'Expected startedStreaming to be set. This is a bug in the test.'
+        )
+      }
+
+      // We just want to ensure the response isn't blocked on revalidating the fetch.
+      // So we use the start time when route started processing not when we
+      // send off the response because that includes cold boots of the infra.
+      if (startedStreaming - startedResponding >= 3000) {
+        throw new Error(
+          `Response #${i} took too long to complete: ${startedStreaming - startedResponding}ms`
+        )
+      }
     }
   })
 

filename: test/e2e/app-dir/app-static/app/stale-cache-serving-edge/app-page/page.tsx
patch: @@ -13,7 +13,7 @@ export default async function Page(props) {
   return (
     <>
       <p id="data">
-        {JSON.stringify({ fetchDuration, data, now: Date.now() })}
+        {JSON.stringify({ fetchDuration, data, now: Date.now(), start })}
       </p>
     </>
   )

filename: test/e2e/app-dir/app-static/app/stale-cache-serving-edge/route-handler/route.ts
patch: @@ -12,5 +12,5 @@ export async function GET(req: NextRequest) {
   ).then((res) => res.json())
   const fetchDuration = Date.now() - start
 
-  return NextResponse.json({ fetchDuration, data, now: Date.now() })
+  return NextResponse.json({ fetchDuration, data, now: Date.now(), start })
 }

filename: test/e2e/app-dir/app-static/app/stale-cache-serving/app-page/page.tsx
patch: @@ -13,7 +13,7 @@ export default async function Page(props) {
   return (
     <>
       <p id="data">
-        {JSON.stringify({ fetchDuration, data, now: Date.now() })}
+        {JSON.stringify({ fetchDuration, data, now: Date.now(), start })}
       </p>
     </>
   )

filename: test/e2e/app-dir/app-static/app/stale-cache-serving/route-handler/route.ts
patch: @@ -12,5 +12,5 @@ export async function GET(req: NextRequest) {
   ).then((res) => res.json())
   const fetchDuration = Date.now() - start
 
-  return NextResponse.json({ fetchDuration, data, now: Date.now() })
+  return NextResponse.json({ fetchDuration, data, now: Date.now(), start })
 }