From 2e7dc1ffff546899a55e4bf9cab48447d09e100d Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Fri, 10 Apr 2026 15:46:57 +0200 Subject: [PATCH 1/3] test(cloudflare): Unflake integration test --- dev-packages/cloudflare-integration-tests/runner.ts | 4 ++++ .../suites/tracing/durableobject-spans/test.ts | 10 ++++++++++ .../cloudflare-integration-tests/vite.config.mts | 3 +++ 3 files changed, 17 insertions(+) diff --git a/dev-packages/cloudflare-integration-tests/runner.ts b/dev-packages/cloudflare-integration-tests/runner.ts index e0a48dd33ff5..8f6f3e389149 100644 --- a/dev-packages/cloudflare-integration-tests/runner.ts +++ b/dev-packages/cloudflare-integration-tests/runner.ts @@ -242,6 +242,10 @@ export function createRunner(...paths: string[]) { `SENTRY_DSN:http://public@localhost:${mockServerPort}/1337`, '--var', `SERVER_URL:${serverUrl}`, + '--port', + '0', + '--inspector-port', + '0', ...extraWranglerArgs, ], { stdio, signal }, diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/durableobject-spans/test.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/durableobject-spans/test.ts index 1415950208cc..a1f33e7aeb23 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/durableobject-spans/test.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/durableobject-spans/test.ts @@ -46,10 +46,20 @@ it.skip('sends child spans on repeated Durable Object calls', async ({ signal }) // Expect 5 transaction envelopes — one per call. const runner = createRunner(__dirname).expectN(5, assertDoWorkEnvelope).start(signal); + // Small delay between requests to allow waitUntil to process in wrangler dev. + // This is needed because wrangler dev may not guarantee waitUntil completion + // the same way production Cloudflare does. Without this delay, the last + // envelope's HTTP request may not complete before the test moves on. + const delay = () => new Promise(resolve => setTimeout(resolve, 50)); + await runner.makeRequest('get', '/'); + await delay(); await runner.makeRequest('get', '/'); + await delay(); await runner.makeRequest('get', '/'); + await delay(); await runner.makeRequest('get', '/'); + await delay(); await runner.makeRequest('get', '/'); await runner.completed(); }); diff --git a/dev-packages/cloudflare-integration-tests/vite.config.mts b/dev-packages/cloudflare-integration-tests/vite.config.mts index a80bbbf63f32..0fdb560b8f11 100644 --- a/dev-packages/cloudflare-integration-tests/vite.config.mts +++ b/dev-packages/cloudflare-integration-tests/vite.config.mts @@ -28,6 +28,9 @@ export default defineConfig({ singleThread: true, }, }, + sequence: { + shuffle: true, + }, reporters: process.env.DEBUG ? ['default', { summary: false }] : process.env.GITHUB_ACTIONS From 26dda3779ef8d43491631a7bc4d031369075bbd6 Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Wed, 22 Apr 2026 16:21:42 +0200 Subject: [PATCH 2/3] fixup! test(cloudflare): Unflake integration test --- .../cloudflare-integration-tests/runner.ts | 37 +++++++++++++++++ .../tracing/durableobject-spans/test.ts | 41 +++++++------------ 2 files changed, 51 insertions(+), 27 deletions(-) diff --git a/dev-packages/cloudflare-integration-tests/runner.ts b/dev-packages/cloudflare-integration-tests/runner.ts index 8f6f3e389149..542ffe82b802 100644 --- a/dev-packages/cloudflare-integration-tests/runner.ts +++ b/dev-packages/cloudflare-integration-tests/runner.ts @@ -50,6 +50,12 @@ type StartResult = { path: string, options?: { headers?: Record; data?: BodyInit; expectError?: boolean }, ): Promise; + makeRequestAndWaitForEnvelope( + method: 'get' | 'post', + path: string, + expected: Expected | Expected[], + options?: { headers?: Record; data?: BodyInit; expectError?: boolean }, + ): Promise; }; /** Creates a test runner */ @@ -108,6 +114,7 @@ export function createRunner(...paths: string[]) { const expectedEnvelopeCount = expectedEnvelopes.length; let envelopeCount = 0; + const envelopeWaiters: { expected: Expected; resolve: () => void; reject: (e: unknown) => void }[] = []; const { resolve: setWorkerPort, promise: workerPortPromise } = deferredPromise(); let child: ReturnType | undefined; let childSubWorker: ReturnType | undefined; @@ -120,6 +127,12 @@ export function createRunner(...paths: string[]) { } } + function waitForEnvelope(expected: Expected): Promise { + return new Promise((resolveWaiter, rejectWaiter) => { + envelopeWaiters.push({ expected, resolve: resolveWaiter, reject: rejectWaiter }); + }); + } + function assertEnvelopeMatches(expected: Expected, envelope: Envelope): void { if (typeof expected === 'function') { expected(envelope); @@ -137,6 +150,18 @@ export function createRunner(...paths: string[]) { return; } + // Check per-request waiters first (FIFO order) + if (envelopeWaiters.length > 0) { + const waiter = envelopeWaiters.shift()!; + try { + assertEnvelopeMatches(waiter.expected, envelope); + waiter.resolve(); + } catch (e) { + waiter.reject(e); + } + return; + } + try { if (unordered) { // find any matching expected envelope @@ -308,6 +333,18 @@ export function createRunner(...paths: string[]) { return; } }, + makeRequestAndWaitForEnvelope: async function ( + method: 'get' | 'post', + path: string, + expected: Expected | Expected[], + options: { headers?: Record; data?: BodyInit; expectError?: boolean } = {}, + ): Promise { + const expectations = Array.isArray(expected) ? expected : [expected]; + const envelopePromises = expectations.map(e => waitForEnvelope(e)); + const result = await this.makeRequest(method, path, options); + await Promise.all(envelopePromises); + return result; + }, }; }, }; diff --git a/dev-packages/cloudflare-integration-tests/suites/tracing/durableobject-spans/test.ts b/dev-packages/cloudflare-integration-tests/suites/tracing/durableobject-spans/test.ts index a1f33e7aeb23..483b170936e4 100644 --- a/dev-packages/cloudflare-integration-tests/suites/tracing/durableobject-spans/test.ts +++ b/dev-packages/cloudflare-integration-tests/suites/tracing/durableobject-spans/test.ts @@ -25,15 +25,13 @@ it.skip('sends child spans on repeated Durable Object calls', async ({ signal }) // All 5 child spans should be present expect(transactionEvent.spans).toHaveLength(5); - expect(transactionEvent.spans).toEqual( - expect.arrayContaining([ - expect.objectContaining({ description: 'task-1', op: 'task' }), - expect.objectContaining({ description: 'task-2', op: 'task' }), - expect.objectContaining({ description: 'task-3', op: 'task' }), - expect.objectContaining({ description: 'task-4', op: 'task' }), - expect.objectContaining({ description: 'task-5', op: 'task' }), - ]), - ); + expect(transactionEvent.spans).toEqual([ + expect.objectContaining({ description: 'task-1', op: 'task' }), + expect.objectContaining({ description: 'task-2', op: 'task' }), + expect.objectContaining({ description: 'task-3', op: 'task' }), + expect.objectContaining({ description: 'task-4', op: 'task' }), + expect.objectContaining({ description: 'task-5', op: 'task' }), + ]); // All child spans share the root trace_id const rootTraceId = transactionEvent.contexts?.trace?.trace_id; @@ -43,23 +41,12 @@ it.skip('sends child spans on repeated Durable Object calls', async ({ signal }) } } - // Expect 5 transaction envelopes — one per call. - const runner = createRunner(__dirname).expectN(5, assertDoWorkEnvelope).start(signal); - - // Small delay between requests to allow waitUntil to process in wrangler dev. - // This is needed because wrangler dev may not guarantee waitUntil completion - // the same way production Cloudflare does. Without this delay, the last - // envelope's HTTP request may not complete before the test moves on. - const delay = () => new Promise(resolve => setTimeout(resolve, 50)); + const runner = createRunner(__dirname).start(signal); - await runner.makeRequest('get', '/'); - await delay(); - await runner.makeRequest('get', '/'); - await delay(); - await runner.makeRequest('get', '/'); - await delay(); - await runner.makeRequest('get', '/'); - await delay(); - await runner.makeRequest('get', '/'); - await runner.completed(); + // Each request waits for its envelope to be received and validated before proceeding. + await runner.makeRequestAndWaitForEnvelope('get', '/', assertDoWorkEnvelope); + await runner.makeRequestAndWaitForEnvelope('get', '/', assertDoWorkEnvelope); + await runner.makeRequestAndWaitForEnvelope('get', '/', assertDoWorkEnvelope); + await runner.makeRequestAndWaitForEnvelope('get', '/', assertDoWorkEnvelope); + await runner.makeRequestAndWaitForEnvelope('get', '/', assertDoWorkEnvelope); }); From 53cf59664387fa18815403b7621473f8b9b99788 Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Wed, 22 Apr 2026 19:30:03 +0200 Subject: [PATCH 3/3] fixup! test(cloudflare): Unflake integration test --- .../suites/public-api/startSpan-streamed/test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-packages/cloudflare-integration-tests/suites/public-api/startSpan-streamed/test.ts b/dev-packages/cloudflare-integration-tests/suites/public-api/startSpan-streamed/test.ts index 090142714d5b..d9c18431202b 100644 --- a/dev-packages/cloudflare-integration-tests/suites/public-api/startSpan-streamed/test.ts +++ b/dev-packages/cloudflare-integration-tests/suites/public-api/startSpan-streamed/test.ts @@ -197,7 +197,7 @@ it('sends a streamed span envelope with correct spans for a manually started spa }, 'url.port': { type: 'string', - value: '8787', + value: expect.stringMatching(/^\d{4,5}$/), }, 'url.scheme': { type: 'string', @@ -221,7 +221,7 @@ it('sends a streamed span envelope with correct spans for a manually started spa }, 'http.request.header.cf_connecting_ip': { type: 'string', - value: '::1', + value: expect.stringMatching(/^(::1|127\.0\.0\.1)$/), }, 'http.request.header.host': { type: 'string',