Skip to content

Commit 68d10fc

Browse files
testing behavior when there is an async client component
1 parent 3668ed4 commit 68d10fc

File tree

7 files changed

+134
-28
lines changed

7 files changed

+134
-28
lines changed

react_on_rails_pro/spec/dummy/app/views/pages/redis_receiver.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<%= stream_react_component("RedisReceiver",
2-
props: { requestId: @request_id },
2+
props: { requestId: @request_id, asyncToggleContainer: params[:async_toggle_container] },
33
prerender: true,
44
trace: true,
55
id: "RedisReceiver-react-component-0") %>

react_on_rails_pro/spec/dummy/client/app/components/RSCPostsPage/ToggleContainer.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const ToggleContainer = ({ children, childrenTitle }) => {
1010

1111
return (
1212
<div style={{ border: '1px solid black', margin: '10px', padding: '10px' }}>
13-
<button onClick={() => setIsVisible(!isVisible)} style={{ border: '1px solid black' }} type="button">
13+
<button className="toggle-button" onClick={() => setIsVisible(!isVisible)} style={{ border: '1px solid black' }} type="button">
1414
{showOrHideText}
1515
</button>
1616
{isVisible && children}

react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/RedisReceiver.jsx

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,21 @@ const RedisReceiver = ({ requestId, asyncToggleContainer }, railsContext) => {
3131
}
3232

3333
const UsedToggleContainer = asyncToggleContainer ? AsyncToggleContainer : ToggleContainer;
34+
const toggleContainerGetValueParam = asyncToggleContainer ? getValue : undefined;
3435

35-
return (
36+
return () => (
3637
<ErrorBoundary>
3738
<main className='redis-receiver-container'>
3839
<h1 className="redis-receiver-header">A list of items received from Redis:</h1>
39-
<UsedToggleContainer childrenTitle="Redis Items">
40-
<ol className='redis-items-container'>
41-
{
42-
[0,1,2,3,4].map(index => <RedisItemWithWrapper key={index} getValue={getValue} itemIndex={index} />)
43-
}
44-
</ol>
45-
</UsedToggleContainer>
40+
<Suspense fallback={<div>Loading ToggleContainer</div>}>
41+
<UsedToggleContainer childrenTitle="Redis Items" getValue={toggleContainerGetValueParam}>
42+
<ol className='redis-items-container'>
43+
{
44+
[0,1,2,3,4].map(index => <RedisItemWithWrapper key={index} getValue={getValue} itemIndex={index} />)
45+
}
46+
</ol>
47+
</UsedToggleContainer>
48+
</Suspense>
4649
</main>
4750
</ErrorBoundary>
4851
)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { test as base } from '@playwright/test';
2+
3+
type F = {
4+
h: string;
5+
}
6+
7+
type F2 = {
8+
h2: string;
9+
}
10+
11+
export const test1 = base.extend<F>({
12+
h: [async({}, use) => {
13+
console.log('F1')
14+
await use('F1');
15+
console.log('F1 end');
16+
}, { auto: true }]
17+
})
18+
19+
export const testmid = base.extend<F>({
20+
h: [async({}, use) => {
21+
console.log('Fm')
22+
await use('Fm');
23+
console.log('Fm end');
24+
}, { auto: true }]
25+
})
26+
27+
export const test2 = testmid.extend<F2>({
28+
h2: [async({ h }, use) => {
29+
console.log('F2')
30+
await use(h + 'F2');
31+
console.log('F2 end');
32+
}, { auto: true }]
33+
})
Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
1-
import { test, expect } from '@playwright/test';
2-
import { redisControlledTest } from './fixture';
3-
4-
redisControlledTest('test1', ({ redisRequestId, redisClient }) => {
5-
console.log('Test1 request id', redisRequestId);
6-
console.log(redisClient);
7-
});
8-
9-
redisControlledTest('test2', ({ redisRequestId, redisClient }) => {
10-
console.log('Test2 request id', redisRequestId);
11-
console.log(redisClient);
12-
});
1+
// import { test, expect } from '@playwright/test';
2+
// import { redisControlledTest } from './fixture';
3+
4+
// redisControlledTest('test1', ({ redisRequestId, redisClient }) => {
5+
// console.log('Test1 request id', redisRequestId);
6+
// console.log(redisClient);
7+
// });
8+
9+
// redisControlledTest('test2', ({ redisRequestId, redisClient }) => {
10+
// console.log('Test2 request id', redisRequestId);
11+
// console.log(redisClient);
12+
// });
13+
14+
import { mergeTests } from '@playwright/test';
15+
import { test1, test2 } from './dummt-fixture';
16+
17+
const test = mergeTests(test2);
18+
19+
test('eee', ({ h2 }) => {
20+
console.log('TEst', h2);
21+
})
22+

react_on_rails_pro/spec/dummy/e2e-tests/fixture.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export type RedisReceiverControllerFixture = {
1919
sendRedisValue: (key: string, value: unknown) => Promise<void>;
2020
sendRedisItemValue: (itemIndex: Number, value: unknown) => Promise<void>;
2121
matchPageSnapshot: (snapshotPath: string) => Promise<void>;
22+
waitForConsoleMessage: (msg: string) => Promise<void>;
2223
}
2324

2425
const redisControlledTest = base.extend<RedisRequestIdFixture, RedisClientFixture>({
@@ -36,7 +37,11 @@ const redisControlledTest = base.extend<RedisRequestIdFixture, RedisClientFixtur
3637
},
3738

3839
nonBlockingNavigateWithRequestId: async ({ redisRequestId, page }, use) => {
39-
await use((path) => page.goto(`${path}?request_id=${redisRequestId}`, { waitUntil: "commit" }))
40+
await use((path) => {
41+
const requestIdParam = `request_id=${redisRequestId}`;
42+
const fullPath = path.includes('?') ? `${path}&${requestIdParam}` : `${path}?${requestIdParam}`;
43+
return page.goto(fullPath, { waitUntil: "commit" })
44+
})
4045
},
4146
});
4247

@@ -57,6 +62,17 @@ const redisReceiverPageController = redisControlledTest.extend<RedisReceiverCont
5762
await expect(page.locator('.redis-receiver-container:visible').first()).toMatchAriaSnapshot({ name: `${snapshotPath}.aria.yml` });
5863
})
5964
},
65+
waitForConsoleMessage: async({ page }, use) =>{
66+
await use(async(msg) => {
67+
if ((await page.consoleMessages()).find(consoleMsg => consoleMsg.text().includes(msg))) {
68+
return;
69+
}
70+
71+
await page.waitForEvent('console', {
72+
predicate: (consoleMsg) => consoleMsg.text().includes(msg),
73+
})
74+
})
75+
}
6076
})
6177

6278
const redisReceiverPageTest = redisReceiverPageController.extend<RedisReceiverPageFixture>({
@@ -67,6 +83,20 @@ const redisReceiverPageTest = redisReceiverPageController.extend<RedisReceiverPa
6783
}, { auto: true }]
6884
})
6985

86+
const redisReceiverPageWithAsyncClientComponentTest = redisReceiverPageController.extend<RedisReceiverPageFixture>({
87+
pagePath: [async({ page, nonBlockingNavigateWithRequestId, sendRedisValue }, use) => {
88+
const pagePath = '/redis_receiver_for_testing?async_toggle_container=true';
89+
await nonBlockingNavigateWithRequestId(pagePath);
90+
91+
await expect(page.getByText("Loading ToggleContainer")).toBeVisible();
92+
await expect(page.locator('.toggle-button')).not.toBeVisible();
93+
94+
await sendRedisValue('ToggleContainer', 'anything');
95+
await expect(page.locator('.toggle-button')).toBeVisible();
96+
await use(pagePath);
97+
}, { auto: true }]
98+
})
99+
70100
const redisReceiverInsideRouterPageTest = redisReceiverPageController.extend<RedisReceiverPageFixture>({
71101
pagePath: [async({ nonBlockingNavigateWithRequestId }, use) => {
72102
const pagePath = '/server_router/redis-receiver-for-testing';
@@ -85,8 +115,8 @@ const redisReceiverPageAfterNavigationTest = redisReceiverPageController.extend<
85115
})
86116

87117
export {
88-
redisControlledTest,
89118
redisReceiverPageTest,
90119
redisReceiverInsideRouterPageTest,
91120
redisReceiverPageAfterNavigationTest,
121+
redisReceiverPageWithAsyncClientComponentTest,
92122
};

react_on_rails_pro/spec/dummy/e2e-tests/streaming.spec.ts

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1+
import { expect } from '@playwright/test';
12
import {
23
redisReceiverPageTest,
34
redisReceiverInsideRouterPageTest,
45
redisReceiverPageAfterNavigationTest,
6+
redisReceiverPageWithAsyncClientComponentTest,
57
} from './fixture';
68

7-
// Can be used to delay the execution
8-
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
9-
109
// Snapshot testing the best testing strategy for our use case
1110
// Because we need to ensure that any transformation done on the HTML or RSC payload stream won't affect
1211
// - Order of fallback or components at the page
@@ -17,8 +16,39 @@ const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
1716
['RedisReceiver', redisReceiverPageTest],
1817
['RedisReceiver inside router page', redisReceiverInsideRouterPageTest],
1918
['RedisReceiver inside router after navigation', redisReceiverPageAfterNavigationTest],
19+
['RedisReceiver with Async Toggle Container Client Component', redisReceiverPageWithAsyncClientComponentTest],
2020
] as const).forEach(([pageName, test]) => {
21-
test(`snapshot for page ${pageName}`, async ({ matchPageSnapshot, sendRedisItemValue }) => {
21+
test(`incremental rendering of page: ${pageName}`, async ({ matchPageSnapshot, sendRedisItemValue }) => {
22+
await matchPageSnapshot('stage0');
23+
24+
sendRedisItemValue(0, 'Incremental Value1');
25+
await matchPageSnapshot('stage1');
26+
27+
sendRedisItemValue(3, 'Incremental Value4');
28+
await matchPageSnapshot('stage2');
29+
30+
sendRedisItemValue(1, 'Incremental Value2');
31+
await matchPageSnapshot('stage3');
32+
33+
sendRedisItemValue(2, 'Incremental Value3');
34+
await matchPageSnapshot('stage4');
35+
36+
sendRedisItemValue(4, 'Incremental Value5');
37+
await matchPageSnapshot('stage5');
38+
});
39+
40+
test(`early hydration of page: ${pageName}`, async ({ page, waitForConsoleMessage, matchPageSnapshot, sendRedisItemValue }) => {
41+
waitForConsoleMessage('ToggleContainer with title');
42+
43+
await page.click('.toggle-button');
44+
await expect(page.getByText(/Waiting for the key "Item\d"/)).not.toBeVisible();
45+
46+
await page.click('.toggle-button');
47+
const fallbackElements = page.getByText(/Waiting for the key "Item\d"/);
48+
await expect(fallbackElements).toHaveCount(5);
49+
for (const el of await fallbackElements.all()) {
50+
await expect(el).toBeVisible();
51+
}
2252
await matchPageSnapshot('stage0');
2353

2454
sendRedisItemValue(0, 'Incremental Value1');

0 commit comments

Comments
 (0)