From 802cfc583add89787ed395ccb1d0deaa1eb91200 Mon Sep 17 00:00:00 2001 From: Jude Gao Date: Thu, 21 Nov 2024 15:29:24 -0500 Subject: [PATCH] hmr-test waits for compile signal (#73064) - The waitFor function now supports a predicate. Unlike retry, waitFor does not include a timeout. Use it only when the predicate is guaranteed to evaluate to true before proceeding to the next test. If it runs indefinitely, Jest enforces a 120-second timeout per test. - The getCliOutputFromHere utility provides a convenient string getter that captures CLI output in between. --- test/development/app-hmr/hmr.test.ts | 4 ++++ .../server-side-dev-errors/test/index.test.js | 5 +++-- test/lib/next-modes/base.ts | 7 +++++++ test/lib/next-test-utils.ts | 17 +++++++++++++++-- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/test/development/app-hmr/hmr.test.ts b/test/development/app-hmr/hmr.test.ts index 4f593363a1a2ea..924e2166fe5165 100644 --- a/test/development/app-hmr/hmr.test.ts +++ b/test/development/app-hmr/hmr.test.ts @@ -62,7 +62,11 @@ describe(`app-dir-hmr`, () => { await browser.eval('window.__TEST_NO_RELOAD = true') expect(await browser.elementByCss('p').text()).toBe('mac') + + const getCliOutput = next.getCliOutputFromHere() await next.patchFile(envFile, 'MY_DEVICE="ipad"', async () => { + await waitFor(() => getCliOutput().includes('Reload env')) + await retry(async () => { expect(await browser.elementByCss('p').text()).toBe('ipad') }) diff --git a/test/integration/server-side-dev-errors/test/index.test.js b/test/integration/server-side-dev-errors/test/index.test.js index 526c6554f9bb88..536259c7e3699a 100644 --- a/test/integration/server-side-dev-errors/test/index.test.js +++ b/test/integration/server-side-dev-errors/test/index.test.js @@ -10,6 +10,7 @@ import { launchApp, retry, getRedboxSource, + assertNoRedbox, } from 'next-test-utils' import stripAnsi from 'strip-ansi' @@ -93,7 +94,7 @@ describe('server-side dev errors', () => { expect(await getRedboxSource(browser)).toContain('missingVar') await fs.writeFile(gspPage, content, { flush: true }) - await assertHasRedbox(browser) + await assertNoRedbox(browser) } finally { await fs.writeFile(gspPage, content) } @@ -146,7 +147,7 @@ describe('server-side dev errors', () => { expect(await getRedboxSource(browser)).toContain('missingVar') await fs.writeFile(gsspPage, content) - await assertHasRedbox(browser) + await assertNoRedbox(browser) } finally { await fs.writeFile(gsspPage, content) } diff --git a/test/lib/next-modes/base.ts b/test/lib/next-modes/base.ts index 65c9fe9c50bb5a..8636a2d8d5f7d1 100644 --- a/test/lib/next-modes/base.ts +++ b/test/lib/next-modes/base.ts @@ -613,4 +613,11 @@ export class NextInstance { cb(...args) }) } + + public getCliOutputFromHere() { + const length = this.cliOutput.length + return () => { + return this.cliOutput.slice(length) + } + } } diff --git a/test/lib/next-test-utils.ts b/test/lib/next-test-utils.ts index c60068d7553a2f..38d005d312853f 100644 --- a/test/lib/next-test-utils.ts +++ b/test/lib/next-test-utils.ts @@ -647,8 +647,21 @@ export async function stopApp(server: http.Server | undefined) { await promisify(server.close).apply(server) } -export function waitFor(millis: number) { - return new Promise((resolve) => setTimeout(resolve, millis)) +export async function waitFor( + millisOrCondition: number | (() => boolean) +): Promise { + if (typeof millisOrCondition === 'number') { + return new Promise((resolve) => setTimeout(resolve, millisOrCondition)) + } + + return new Promise((resolve) => { + const interval = setInterval(() => { + if (millisOrCondition()) { + clearInterval(interval) + resolve() + } + }, 100) + }) } export async function startStaticServer(