diff --git a/tests/integration/commands/dev/dev-miscellaneous.test.ts b/tests/integration/commands/dev/dev-miscellaneous.test.ts index 709645b353c..fcefa044660 100644 --- a/tests/integration/commands/dev/dev-miscellaneous.test.ts +++ b/tests/integration/commands/dev/dev-miscellaneous.test.ts @@ -17,7 +17,6 @@ import js from 'dedent' import { cliPath } from '../../utils/cli-path.js' import { getExecaOptions, withDevServer } from '../../utils/dev-server.js' import { withMockApi } from '../../utils/mock-api.js' -import { pause } from '../../utils/pause.js' import { withSiteBuilder, type SiteBuilder } from '../../utils/site-builder.js' import { normalize } from '../../utils/snapshots.js' @@ -848,7 +847,7 @@ describe.concurrent('commands/dev-miscellaneous', () => { await builder.build() - await withDevServer({ cwd: builder.directory }, async ({ port }) => { + await withDevServer({ cwd: builder.directory }, async ({ port, waitForLogMatching }) => { const helloWorldMessage = await fetch(`http://localhost:${port}/hello`).then((res) => res.text()) await builder @@ -858,8 +857,7 @@ describe.concurrent('commands/dev-miscellaneous', () => { }) .build() - const DETECT_FILE_CHANGE_DELAY = 500 - await pause(DETECT_FILE_CHANGE_DELAY) + await waitForLogMatching('Reloaded edge function', { timeout: 500 }) const helloBuilderMessage = await fetch(`http://localhost:${port}/hello`, {}).then((res) => res.text()) @@ -894,7 +892,7 @@ describe.concurrent('commands/dev-miscellaneous', () => { await builder.build() - await withDevServer({ cwd: builder.directory }, async ({ port }) => { + await withDevServer({ cwd: builder.directory }, async ({ port, waitForLogMatching }) => { const authResponseMessage = await fetch(`http://localhost:${port}/auth`).then((response) => response.text()) await builder @@ -903,8 +901,7 @@ describe.concurrent('commands/dev-miscellaneous', () => { }) .build() - const DETECT_FILE_CHANGE_DELAY = 500 - await pause(DETECT_FILE_CHANGE_DELAY) + await waitForLogMatching('Removed edge function', { timeout: 500 }) const authNotFoundMessage = await fetch(`http://localhost:${port}/auth`).then((response) => response.text()) @@ -940,9 +937,7 @@ describe.concurrent('commands/dev-miscellaneous', () => { t.expect(res1.status).toBe(200) t.expect(await res1.text()).toEqual('Hello world') - // wait for file watcher to be up and running, which might take a little - // if we do not wait, the next file change will not be picked up - await pause(500) + await waitForLogMatching('Loaded edge function', { timeout: 500 }) await builder .withEdgeFunction({ @@ -952,7 +947,7 @@ describe.concurrent('commands/dev-miscellaneous', () => { }) .build() - await waitForLogMatching('Reloaded edge function') + await waitForLogMatching('Reloaded edge function', { timeout: 500 }) const [res2, res3, res4] = await Promise.all([ fetch(`http://localhost:${port}/hello-1`), @@ -1075,9 +1070,7 @@ describe.concurrent('commands/dev-miscellaneous', () => { t.expect(res1.status).toBe(200) t.expect(await res1.text()).toEqual('Hello from an internal function') - // wait for file watcher to be up and running, which might take a little - // if we do not wait, the next file change will not be picked up - await pause(500) + await waitForLogMatching('Loaded edge function', { timeout: 500 }) await builder .withEdgeFunction({ @@ -1088,7 +1081,7 @@ describe.concurrent('commands/dev-miscellaneous', () => { }) .build() - await waitForLogMatching('Reloaded edge function') + await waitForLogMatching('Reloaded edge function', { timeout: 500 }) const [res2, res3] = await Promise.all([ fetch(`http://localhost:${port}/internal-1`), diff --git a/tests/integration/commands/dev/edge-functions.test.ts b/tests/integration/commands/dev/edge-functions.test.ts index ab4683a8423..4bdc83a2e8d 100644 --- a/tests/integration/commands/dev/edge-functions.test.ts +++ b/tests/integration/commands/dev/edge-functions.test.ts @@ -8,7 +8,6 @@ import { describe, expect, test } from 'vitest' import { withDevServer } from '../../utils/dev-server.js' import { FixtureTestContext, setupFixtureTests } from '../../utils/fixture.js' -import { pause } from '../../utils/pause.js' import { withSiteBuilder } from '../../utils/site-builder.js' // Skipping tests on Windows because of an issue with the Deno CLI throwing IO @@ -184,8 +183,7 @@ describe.skipIf(isWindows)('edge functions', async () => { await setupFixtureTests('dev-server-with-edge-functions', { devServer: true, mockApi: { routes } }, () => { test('should not remove other edge functions on change', async ({ devServer, fixture }) => { - // we need to wait till file watchers are loaded - await pause(500) + await devServer!.waitForLogMatching('Loaded edge function', { timeout: 500 }) await fixture.builder .withEdgeFunction({ @@ -234,7 +232,7 @@ describe.skipIf(isWindows)('edge functions', async () => { }) .build() - await pause(500) + await server.waitForLogMatching('Reloaded edge function', { timeout: 500 }) const response2 = await fetch(server.url, {}).then((res) => res.text()) t.expect(response2).toEqual('bar') diff --git a/tests/integration/commands/dev/scheduled-functions.test.ts b/tests/integration/commands/dev/scheduled-functions.test.ts index d2063cf48d4..f804684dc9a 100644 --- a/tests/integration/commands/dev/scheduled-functions.test.ts +++ b/tests/integration/commands/dev/scheduled-functions.test.ts @@ -2,7 +2,6 @@ import { describe, expect, test } from 'vitest' import { FixtureTestContext, setupFixtureTests } from '../../utils/fixture.js' import fetch from 'node-fetch' -import { pause } from '../../utils/pause.js' describe('scheduled functions', async () => { await setupFixtureTests('dev-server-with-functions', { devServer: true }, () => { @@ -36,8 +35,7 @@ describe('scheduled functions', async () => { }) .build() - const DETECT_FILE_CHANGE_DELAY = 500 - await pause(DETECT_FILE_CHANGE_DELAY) + await devServer!.waitForLogMatching('Reloaded function ping', { timeout: 500 }) const warning = await fetch(`http://localhost:${devServer!.port}/.netlify/functions/ping`, {}).then((res) => res.text(), diff --git a/tests/integration/commands/functions-with-args/functions-with-args.test.ts b/tests/integration/commands/functions-with-args/functions-with-args.test.ts index 8279b23aa01..46f51c961d0 100644 --- a/tests/integration/commands/functions-with-args/functions-with-args.test.ts +++ b/tests/integration/commands/functions-with-args/functions-with-args.test.ts @@ -16,6 +16,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)) const testMatrix = [{ args: [] }, { args: ['esbuild'] }] const WAIT_WRITE = 3000 +const DEBOUNCE_WAIT = 150 describe.concurrent.each(testMatrix)('withSiteBuilder with args: $args', ({ args }) => { test('Updates a JavaScript function when its main file is modified', async (t) => { @@ -48,7 +49,7 @@ describe.concurrent.each(testMatrix)('withSiteBuilder with args: $args', ({ args ).toEqual('Hello') }, outputBuffer) - await pause(WAIT_WRITE) + await waitForLogMatching('Loaded function hello', { timeout: WAIT_WRITE }) await builder .withFunction({ @@ -61,7 +62,7 @@ describe.concurrent.each(testMatrix)('withSiteBuilder with args: $args', ({ args }) .build() - await waitForLogMatching('Reloaded function hello') + await waitForLogMatching('Reloaded function hello', { timeout: WAIT_WRITE }) const response = await fetch(`http://localhost:${port.toString()}/.netlify/functions/hello`) @@ -115,7 +116,7 @@ describe.concurrent.each(testMatrix)('withSiteBuilder with args: $args', ({ args ).toEqual('Modern Web Development on the JAMStack') }, outputBuffer) - await pause(WAIT_WRITE) + await waitForLogMatching('Loaded function hello', { timeout: WAIT_WRITE }) await builder .withContentFile({ @@ -143,7 +144,7 @@ describe.concurrent.each(testMatrix)('withSiteBuilder with args: $args', ({ args }) .build() - await waitForLogMatching('Reloaded function hello') + await waitForLogMatching('Reloaded function hello', { timeout: WAIT_WRITE }) const response = await fetch(`http://localhost:${port.toString()}/.netlify/functions/hello`) @@ -180,16 +181,16 @@ describe.concurrent.each(testMatrix)('withSiteBuilder with args: $args', ({ args ).toEqual('WOOF!') }, outputBuffer) - await pause(WAIT_WRITE) + await waitForLogMatching('Loaded function hello', { timeout: WAIT_WRITE }) await builder .withContentFile({ path: 'functions/lib/util.js', content: js`exports.bark = () => 'WOOF WOOF!'` }) .build() if (args.includes('esbuild')) { - await waitForLogMatching('Reloaded function hello') + await waitForLogMatching('Reloaded function hello', { timeout: WAIT_WRITE }) } else { - // no message printed when using not esbuild + // no message printed when not using esbuild await pause(WAIT_WRITE) } @@ -258,7 +259,7 @@ describe.concurrent.each(testMatrix)('withSiteBuilder with args: $args', ({ args ).toEqual('Modern Web Development on the JAMStack') }, outputBuffer) - await pause(WAIT_WRITE) + await waitForLogMatching('Loaded function hello', { timeout: WAIT_WRITE }) await builder .withContentFile({ @@ -271,7 +272,7 @@ describe.concurrent.each(testMatrix)('withSiteBuilder with args: $args', ({ args }) .build() - await waitForLogMatching('Reloaded function hello') + await waitForLogMatching('Reloaded function hello', { timeout: WAIT_WRITE }) const response = await fetch(`http://localhost:${port.toString()}/.netlify/functions/hello`).then((res) => res.text(), @@ -317,7 +318,7 @@ describe.concurrent.each(testMatrix)('withSiteBuilder with args: $args', ({ args }) .build() - await waitForLogMatching('Loaded function hello') + await waitForLogMatching('Loaded function hello', { timeout: WAIT_WRITE }) const response = await fetch(`http://localhost:${port.toString()}/.netlify/functions/hello`).then((res) => res.text(), @@ -359,7 +360,7 @@ describe.concurrent.each(testMatrix)('withSiteBuilder with args: $args', ({ args t.expect(unauthenticatedResponse.status).toBe(404) }, outputBuffer) - await pause(WAIT_WRITE) + await waitForLogMatching('Loaded function help', { timeout: WAIT_WRITE }) await builder .withContentFile({ @@ -387,7 +388,7 @@ describe.concurrent.each(testMatrix)('withSiteBuilder with args: $args', ({ args }) .build() - await waitForLogMatching('Loaded function hello') + await waitForLogMatching('Loaded function hello', { timeout: WAIT_WRITE }) const response = await fetch(`http://localhost:${port.toString()}/.netlify/functions/hello`).then((res) => res.text(), @@ -428,7 +429,7 @@ describe.concurrent.each(testMatrix)('withSiteBuilder with args: $args', ({ args ).toEqual('Hello') }, outputBuffer) - await pause(WAIT_WRITE) + await waitForLogMatching('Loaded function hello', { timeout: WAIT_WRITE }) await builder .withoutFile({ @@ -436,7 +437,7 @@ describe.concurrent.each(testMatrix)('withSiteBuilder with args: $args', ({ args }) .build() - await waitForLogMatching('Removed function hello') + await waitForLogMatching('Removed function hello', { timeout: WAIT_WRITE }) const { status } = await fetch(`http://localhost:${port.toString()}/.netlify/functions/hello`) @@ -491,7 +492,6 @@ describe.concurrent.each(testMatrix)('withSiteBuilder with args: $args', ({ args }) .build() - const DEBOUNCE_WAIT = 150 await pause(DEBOUNCE_WAIT) const resp2 = await fetch(`${server.url}/.netlify/functions/hello`) @@ -528,7 +528,7 @@ describe.concurrent.each(testMatrix)('withSiteBuilder with args: $args', ({ args }) .build() - await pause(WAIT_WRITE) + await waitForLogMatching('Loaded function hello', { timeout: WAIT_WRITE }) await tryAndLogOutput(async () => { t.expect( @@ -536,8 +536,6 @@ describe.concurrent.each(testMatrix)('withSiteBuilder with args: $args', ({ args ).toEqual('Internal') }, outputBuffer) - await pause(WAIT_WRITE) - await builder .withFunction({ path: 'hello.js', @@ -550,7 +548,7 @@ describe.concurrent.each(testMatrix)('withSiteBuilder with args: $args', ({ args }) .build() - await waitForLogMatching('Reloaded function hello') + await waitForLogMatching('Reloaded function hello', { timeout: WAIT_WRITE }) const response = await fetch(`http://localhost:${port.toString()}/.netlify/functions/hello`).then((res) => res.text(), @@ -603,7 +601,7 @@ describe.concurrent.each(testMatrix)('withSiteBuilder with args: $args', ({ args ).toEqual('User') }, outputBuffer) - await pause(WAIT_WRITE) + await waitForLogMatching('Loaded function hello', { timeout: WAIT_WRITE }) await builder .withFunction({ @@ -625,7 +623,7 @@ describe.concurrent.each(testMatrix)('withSiteBuilder with args: $args', ({ args }) .build() - await waitForLogMatching('Reloaded function hello') + await waitForLogMatching('Reloaded function hello', { timeout: WAIT_WRITE }) const response = await fetch(`http://localhost:${port.toString()}/.netlify/functions/hello`).then((res) => res.text(), @@ -979,7 +977,8 @@ describe.concurrent('serving functions', () => { }) .build() - await withDevServer({ cwd: builder.directory }, async ({ outputBuffer, port }) => { + // eslint-disable-next-line @typescript-eslint/unbound-method + await withDevServer({ cwd: builder.directory }, async ({ outputBuffer, port, waitForLogMatching }) => { await tryAndLogOutput(async () => { const [responseHelloNameOne, responseHelloNameTwo] = await Promise.all([ fetch(`http://localhost:${port.toString()}/.netlify/functions/hello?name=one`).then((res) => res.text()), @@ -1002,9 +1001,7 @@ describe.concurrent('serving functions', () => { ]) .build() - // wait for the watcher to rebuild the function - const delay = 1000 - await pause(delay) + await waitForLogMatching('Reloaded function hello', { timeout: 1000 }) t.expect(outputBuffer.some((buffer) => /.*Reloaded function hello.*/.test(buffer.toString()))).toBe(true) await tryAndLogOutput(async () => { diff --git a/tests/integration/serve/functions-go.test.ts b/tests/integration/serve/functions-go.test.ts index 9126467ca21..ab6a8104b7f 100644 --- a/tests/integration/serve/functions-go.test.ts +++ b/tests/integration/serve/functions-go.test.ts @@ -3,11 +3,8 @@ import { describe, test } from 'vitest' import { tryAndLogOutput, withDevServer } from '../utils/dev-server.js' import { createMock as createExecaMock } from '../utils/mock-execa.js' -import { pause } from '../utils/pause.js' import { withSiteBuilder } from '../utils/site-builder.js' -const WAIT_WRITE = 1000 - describe.concurrent('serve/functions-go', () => { test('Updates a Go function when a file is modified', async (t) => { const originalBody = 'Hello, world!' @@ -89,13 +86,13 @@ describe.concurrent('serve/functions-go', () => { t.expect(response).toEqual(originalBody) }, outputBuffer) - await pause(WAIT_WRITE) + await waitForLogMatching('Loaded function go-func', { timeout: 1000 }) await builder .withContentFile({ path: 'functions/go-func/main.go', content: `` }) .build() - await waitForLogMatching('Reloaded function go-func') + await waitForLogMatching('Reloaded function go-func', { timeout: 1000 }) const response = await fetch(`http://localhost:${port.toString()}/.netlify/functions/go-func`).then((res) => res.text(), diff --git a/tests/integration/serve/functions-rust.test.ts b/tests/integration/serve/functions-rust.test.ts index bc16040acfe..f96120f0e43 100644 --- a/tests/integration/serve/functions-rust.test.ts +++ b/tests/integration/serve/functions-rust.test.ts @@ -3,11 +3,8 @@ import { test } from 'vitest' import { tryAndLogOutput, withDevServer } from '../utils/dev-server.js' import { createMock as createExecaMock } from '../utils/mock-execa.js' -import { pause } from '../utils/pause.js' import { withSiteBuilder } from '../utils/site-builder.js' -const WAIT_WRITE = 1000 - test('Updates a Rust function when a file is modified', async (t) => { await withSiteBuilder(t, async (builder) => { const originalBody = 'Netlify likes Rust' @@ -83,13 +80,13 @@ test('Updates a Rust function when a file is modified', async (t) => { t.expect(response).toEqual(originalBody) }, outputBuffer) - await pause(WAIT_WRITE) + await waitForLogMatching('Loaded function rust-func', { timeout: 1000 }) await builder .withContentFile({ path: 'functions/rust-func/src/main.rs', content: `` }) .build() - await waitForLogMatching('Reloaded function rust-func') + await waitForLogMatching('Reloaded function rust-func', { timeout: 1000 }) const response = await fetch(`http://localhost:${port.toString()}/.netlify/functions/rust-func`).then((res) => res.text(), diff --git a/tests/integration/utils/dev-server.ts b/tests/integration/utils/dev-server.ts index d77ce42ebaa..86d9e2c6000 100644 --- a/tests/integration/utils/dev-server.ts +++ b/tests/integration/utils/dev-server.ts @@ -28,7 +28,7 @@ export interface DevServer { port: number errorBuffer: Buffer[] outputBuffer: Buffer[] - waitForLogMatching(match: string): Promise + waitForLogMatching(match: string, options?: { timeout?: number }): Promise output: string error: string close(): Promise @@ -137,14 +137,27 @@ const startServer = async ({ port, errorBuffer, outputBuffer, - waitForLogMatching(match: string) { - return new Promise((resolveWait) => { + waitForLogMatching(match: string, options?: { timeout?: number }) { + const timeout = options?.timeout ?? 30_000 + return new Promise((resolveWait, rejectWait) => { + if (outputBuffer.join('').includes(match)) { + resolveWait() + return + } + const listener = (stdoutData: string) => { if (stdoutData.includes(match)) { - ps.removeListener('data', listener) + clearTimeout(timeoutId) + ps.stdout!.removeListener('data', listener) resolveWait() } } + + const timeoutId = setTimeout(() => { + ps.stdout!.removeListener('data', listener) + rejectWait(new Error(`Timeout waiting for log matching "${match}" after ${timeout}ms`)) + }, timeout) + ps.stdout!.on('data', listener) }) },