Skip to content

Commit 66ae158

Browse files
chargomemydea
authored andcommitted
test: add e2e test for stream timeouts
1 parent b7ec95c commit 66ae158

File tree

3 files changed

+52
-7
lines changed

3 files changed

+52
-7
lines changed

dev-packages/e2e-tests/test-applications/react-router-6/server/app.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const wait = time => {
1111
});
1212
};
1313

14-
async function eventsHandler(request, response) {
14+
async function sseHandler(request, response, timeout = false) {
1515
response.headers = {
1616
'Content-Type': 'text/event-stream',
1717
Connection: 'keep-alive',
@@ -30,12 +30,17 @@ async function eventsHandler(request, response) {
3030

3131
for (let index = 0; index < 10; index++) {
3232
response.write(`data: ${new Date().toISOString()}\n\n`);
33+
if (timeout) {
34+
await wait(10000);
35+
}
3336
}
3437

3538
response.end();
3639
}
3740

38-
app.get('/sse', eventsHandler);
41+
app.get('/sse', (req, res) => sseHandler(req, res));
42+
43+
app.get('/sse-timeout', (req, res) => sseHandler(req, res, true));
3944

4045
app.listen(PORT, () => {
4146
console.log(`SSE service listening at http://localhost:${PORT}`);

dev-packages/e2e-tests/test-applications/react-router-6/src/pages/SSE.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ import * as Sentry from '@sentry/react';
22
// biome-ignore lint/nursery/noUnusedImports: Need React import for JSX
33
import * as React from 'react';
44

5-
const fetchSSE = async () => {
5+
const fetchSSE = async ({ timeout }: { timeout: boolean }) => {
66
Sentry.startSpanManual({ name: 'sse stream using fetch' }, async span => {
77
const res = await Sentry.startSpan({ name: 'sse fetch call' }, async () => {
8-
return await fetch('http://localhost:8080/sse');
8+
const endpoint = `http://localhost:8080/${timeout ? 'sse-timeout' : 'sse'}`;
9+
return await fetch(endpoint);
910
});
1011

1112
const stream = res.body;
@@ -34,9 +35,14 @@ const fetchSSE = async () => {
3435

3536
const SSE = () => {
3637
return (
37-
<button id="fetch-button" onClick={fetchSSE}>
38-
Fetch SSE
39-
</button>
38+
<>
39+
<button id="fetch-button" onClick={() => fetchSSE({ timeout: false })}>
40+
Fetch SSE
41+
</button>
42+
<button id="fetch-timeout-button" onClick={() => fetchSSE({ timeout: true })}>
43+
Fetch timeout SSE
44+
</button>
45+
</>
4046
);
4147
};
4248

dev-packages/e2e-tests/test-applications/react-router-6/tests/sse.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,37 @@ test('Waits for sse streaming when creating spans', async ({ page }) => {
3333
expect(resolveDuration).toBe(0);
3434
expect(resolveBodyDuration).toBe(2);
3535
});
36+
37+
test('Aborts when stream takes longer than 5s', async ({ page }) => {
38+
await page.goto('/sse');
39+
40+
const transactionPromise = waitForTransaction('react-router-6', async transactionEvent => {
41+
return !!transactionEvent?.transaction && transactionEvent.contexts?.trace?.op === 'pageload';
42+
});
43+
44+
const fetchButton = page.locator('id=fetch-timeout-button');
45+
await fetchButton.click();
46+
47+
const rootSpan = await transactionPromise;
48+
const sseFetchCall = rootSpan.spans?.filter(span => span.description === 'sse fetch call')[0] as SpanJSON;
49+
const httpGet = rootSpan.spans?.filter(
50+
span => span.description === 'GET http://localhost:8080/sse-timeout',
51+
)[0] as SpanJSON;
52+
53+
expect(sseFetchCall).not.toBeUndefined();
54+
expect(httpGet).not.toBeUndefined();
55+
56+
expect(sseFetchCall?.timestamp).not.toBeUndefined();
57+
expect(sseFetchCall?.start_timestamp).not.toBeUndefined();
58+
expect(httpGet?.timestamp).not.toBeUndefined();
59+
expect(httpGet?.start_timestamp).not.toBeUndefined();
60+
61+
// http headers get sent instantly from the server
62+
const resolveDuration = Math.round((sseFetchCall.timestamp as number) - sseFetchCall.start_timestamp);
63+
64+
// body streams after 10s but client should abort reading after 5s
65+
const resolveBodyDuration = Math.round((httpGet.timestamp as number) - httpGet.start_timestamp);
66+
67+
expect(resolveDuration).toBe(0);
68+
expect(resolveBodyDuration).toBe(7);
69+
});

0 commit comments

Comments
 (0)