Skip to content

Commit f60d0fb

Browse files
committed
add e2e for streaming
1 parent 02e6d04 commit f60d0fb

File tree

2 files changed

+108
-0
lines changed

2 files changed

+108
-0
lines changed

Diff for: packages/tests-e2e/tests/appRouter/streaming.test.ts

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { expect, test } from "@playwright/test";
2+
3+
test("streaming should work in route handler", async ({ page }) => {
4+
const ITERATOR_LENGTH = 10;
5+
6+
const res = await page.goto("/streaming", {
7+
// we set waitUntil: "commit" to ensure that the response is streamed
8+
// without this option, the response would be buffered and sent all at once
9+
// we could also drop the `await` aswell, but then we can't see the headers first.
10+
waitUntil: "commit",
11+
});
12+
13+
expect(res?.headers()["content-type"]).toBe("text/html; charset=utf-8");
14+
expect(res?.headers()["cache-control"]).toBe("no-cache, no-transform");
15+
// AWS API Gateway remaps the connection header to `x-amzn-remapped-connection`
16+
expect(res?.headers()["x-amzn-remapped-connection"]).toBe("keep-alive");
17+
18+
// wait for first number to be present
19+
await page.getByTestId("iteratorCount").first().waitFor();
20+
21+
const seenNumbers: Array<{ number: string; time: number }> = [];
22+
const startTime = Date.now();
23+
24+
const initialParagraphs = await page.getByTestId("iteratorCount").count();
25+
// fail if all paragraphs appear at once
26+
// this is a safeguard to ensure that the response is streamed and not buffered all at once
27+
expect(initialParagraphs).toBe(1);
28+
29+
while (
30+
seenNumbers.length < ITERATOR_LENGTH &&
31+
Date.now() - startTime < 11000
32+
) {
33+
const paragraphs = await page.getByTestId("iteratorCount").allInnerTexts();
34+
if (paragraphs.length > seenNumbers.length) {
35+
// ensure that the numbers are streamed one by one
36+
expect(paragraphs.length).toBe(seenNumbers.length + 1);
37+
seenNumbers.push({
38+
number: paragraphs[seenNumbers.length],
39+
time: Date.now() - startTime,
40+
});
41+
}
42+
await page.waitForTimeout(100);
43+
}
44+
45+
expect(seenNumbers.map((n) => n.number)).toEqual(
46+
[...Array(ITERATOR_LENGTH)].map((_, i) => String(i + 1)),
47+
);
48+
49+
// verify streaming timing
50+
for (let i = 1; i < seenNumbers.length; i++) {
51+
const timeDiff = seenNumbers[i].time - seenNumbers[i - 1].time;
52+
expect(timeDiff).toBeGreaterThanOrEqual(900);
53+
}
54+
});
+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { expect, test } from "@playwright/test";
2+
3+
test("streaming should work in api route", async ({ page }) => {
4+
const ITERATOR_LENGTH = 10;
5+
6+
const res = await page.goto("/api/streaming", {
7+
// we set waitUntil: "commit" to ensure that the response is streamed
8+
// without this option, the response would be buffered and sent all at once
9+
// we could also drop the `await` aswell, but then we can't see the headers first.
10+
waitUntil: "commit",
11+
});
12+
13+
expect(res?.headers()["content-type"]).toBe("text/html; charset=utf-8");
14+
expect(res?.headers()["cache-control"]).toBe("no-cache, no-transform");
15+
// AWS API Gateway remaps the connection header to `x-amzn-remapped-connection`
16+
expect(res?.headers()["x-amzn-remapped-connection"]).toBe("keep-alive");
17+
18+
// wait for first number to be present
19+
await page.getByTestId("iteratorCount").first().waitFor();
20+
21+
const seenNumbers: Array<{ number: string; time: number }> = [];
22+
const startTime = Date.now();
23+
24+
const initialParagraphs = await page.getByTestId("iteratorCount").count();
25+
// fail if all paragraphs appear at once
26+
// this is a safeguard to ensure that the response is streamed and not buffered all at once
27+
expect(initialParagraphs).toBe(1);
28+
29+
while (
30+
seenNumbers.length < ITERATOR_LENGTH &&
31+
Date.now() - startTime < 11000
32+
) {
33+
const paragraphs = await page.getByTestId("iteratorCount").allInnerTexts();
34+
if (paragraphs.length > seenNumbers.length) {
35+
// ensure that the numbers are streamed one by one
36+
expect(paragraphs.length).toBe(seenNumbers.length + 1);
37+
seenNumbers.push({
38+
number: paragraphs[seenNumbers.length],
39+
time: Date.now() - startTime,
40+
});
41+
}
42+
await page.waitForTimeout(100);
43+
}
44+
45+
expect(seenNumbers.map((n) => n.number)).toEqual(
46+
[...Array(ITERATOR_LENGTH)].map((_, i) => String(i + 1)),
47+
);
48+
49+
// verify streaming timing
50+
for (let i = 1; i < seenNumbers.length; i++) {
51+
const timeDiff = seenNumbers[i].time - seenNumbers[i - 1].time;
52+
expect(timeDiff).toBeGreaterThanOrEqual(900);
53+
}
54+
});

0 commit comments

Comments
 (0)