Skip to content

Commit 26dda37

Browse files
committed
fixup! test(cloudflare): Unflake integration test
1 parent 2e7dc1f commit 26dda37

2 files changed

Lines changed: 51 additions & 27 deletions

File tree

  • dev-packages/cloudflare-integration-tests

dev-packages/cloudflare-integration-tests/runner.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ type StartResult = {
5050
path: string,
5151
options?: { headers?: Record<string, string>; data?: BodyInit; expectError?: boolean },
5252
): Promise<T | undefined>;
53+
makeRequestAndWaitForEnvelope<T>(
54+
method: 'get' | 'post',
55+
path: string,
56+
expected: Expected | Expected[],
57+
options?: { headers?: Record<string, string>; data?: BodyInit; expectError?: boolean },
58+
): Promise<T | undefined>;
5359
};
5460

5561
/** Creates a test runner */
@@ -108,6 +114,7 @@ export function createRunner(...paths: string[]) {
108114
const expectedEnvelopeCount = expectedEnvelopes.length;
109115

110116
let envelopeCount = 0;
117+
const envelopeWaiters: { expected: Expected; resolve: () => void; reject: (e: unknown) => void }[] = [];
111118
const { resolve: setWorkerPort, promise: workerPortPromise } = deferredPromise<number>();
112119
let child: ReturnType<typeof spawn> | undefined;
113120
let childSubWorker: ReturnType<typeof spawn> | undefined;
@@ -120,6 +127,12 @@ export function createRunner(...paths: string[]) {
120127
}
121128
}
122129

130+
function waitForEnvelope(expected: Expected): Promise<void> {
131+
return new Promise((resolveWaiter, rejectWaiter) => {
132+
envelopeWaiters.push({ expected, resolve: resolveWaiter, reject: rejectWaiter });
133+
});
134+
}
135+
123136
function assertEnvelopeMatches(expected: Expected, envelope: Envelope): void {
124137
if (typeof expected === 'function') {
125138
expected(envelope);
@@ -137,6 +150,18 @@ export function createRunner(...paths: string[]) {
137150
return;
138151
}
139152

153+
// Check per-request waiters first (FIFO order)
154+
if (envelopeWaiters.length > 0) {
155+
const waiter = envelopeWaiters.shift()!;
156+
try {
157+
assertEnvelopeMatches(waiter.expected, envelope);
158+
waiter.resolve();
159+
} catch (e) {
160+
waiter.reject(e);
161+
}
162+
return;
163+
}
164+
140165
try {
141166
if (unordered) {
142167
// find any matching expected envelope
@@ -308,6 +333,18 @@ export function createRunner(...paths: string[]) {
308333
return;
309334
}
310335
},
336+
makeRequestAndWaitForEnvelope: async function <T>(
337+
method: 'get' | 'post',
338+
path: string,
339+
expected: Expected | Expected[],
340+
options: { headers?: Record<string, string>; data?: BodyInit; expectError?: boolean } = {},
341+
): Promise<T | undefined> {
342+
const expectations = Array.isArray(expected) ? expected : [expected];
343+
const envelopePromises = expectations.map(e => waitForEnvelope(e));
344+
const result = await this.makeRequest<T>(method, path, options);
345+
await Promise.all(envelopePromises);
346+
return result;
347+
},
311348
};
312349
},
313350
};

dev-packages/cloudflare-integration-tests/suites/tracing/durableobject-spans/test.ts

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,13 @@ it.skip('sends child spans on repeated Durable Object calls', async ({ signal })
2525

2626
// All 5 child spans should be present
2727
expect(transactionEvent.spans).toHaveLength(5);
28-
expect(transactionEvent.spans).toEqual(
29-
expect.arrayContaining([
30-
expect.objectContaining({ description: 'task-1', op: 'task' }),
31-
expect.objectContaining({ description: 'task-2', op: 'task' }),
32-
expect.objectContaining({ description: 'task-3', op: 'task' }),
33-
expect.objectContaining({ description: 'task-4', op: 'task' }),
34-
expect.objectContaining({ description: 'task-5', op: 'task' }),
35-
]),
36-
);
28+
expect(transactionEvent.spans).toEqual([
29+
expect.objectContaining({ description: 'task-1', op: 'task' }),
30+
expect.objectContaining({ description: 'task-2', op: 'task' }),
31+
expect.objectContaining({ description: 'task-3', op: 'task' }),
32+
expect.objectContaining({ description: 'task-4', op: 'task' }),
33+
expect.objectContaining({ description: 'task-5', op: 'task' }),
34+
]);
3735

3836
// All child spans share the root trace_id
3937
const rootTraceId = transactionEvent.contexts?.trace?.trace_id;
@@ -43,23 +41,12 @@ it.skip('sends child spans on repeated Durable Object calls', async ({ signal })
4341
}
4442
}
4543

46-
// Expect 5 transaction envelopes — one per call.
47-
const runner = createRunner(__dirname).expectN(5, assertDoWorkEnvelope).start(signal);
48-
49-
// Small delay between requests to allow waitUntil to process in wrangler dev.
50-
// This is needed because wrangler dev may not guarantee waitUntil completion
51-
// the same way production Cloudflare does. Without this delay, the last
52-
// envelope's HTTP request may not complete before the test moves on.
53-
const delay = () => new Promise(resolve => setTimeout(resolve, 50));
44+
const runner = createRunner(__dirname).start(signal);
5445

55-
await runner.makeRequest('get', '/');
56-
await delay();
57-
await runner.makeRequest('get', '/');
58-
await delay();
59-
await runner.makeRequest('get', '/');
60-
await delay();
61-
await runner.makeRequest('get', '/');
62-
await delay();
63-
await runner.makeRequest('get', '/');
64-
await runner.completed();
46+
// Each request waits for its envelope to be received and validated before proceeding.
47+
await runner.makeRequestAndWaitForEnvelope('get', '/', assertDoWorkEnvelope);
48+
await runner.makeRequestAndWaitForEnvelope('get', '/', assertDoWorkEnvelope);
49+
await runner.makeRequestAndWaitForEnvelope('get', '/', assertDoWorkEnvelope);
50+
await runner.makeRequestAndWaitForEnvelope('get', '/', assertDoWorkEnvelope);
51+
await runner.makeRequestAndWaitForEnvelope('get', '/', assertDoWorkEnvelope);
6552
});

0 commit comments

Comments
 (0)