Skip to content

Commit

Permalink
Add a test for issue facebook#28595
Browse files Browse the repository at this point in the history
The added test, intended to fail and reproduce the reported issue,
unexpectedly passes in its current state. I see three possible reasons:

1. The bug report could be invalid.
2. How I've structured of the test might be insufficient to replicate
   what `ai/rsc` is doing.
3. Something in the test setup could be obscuring the actual error.

If the problem lies in reason 2 or 3, this test could possibly serve as
a foundation for further investigation.
  • Loading branch information
unstubbable committed Mar 20, 2024
1 parent a493901 commit efdd474
Showing 1 changed file with 104 additions and 0 deletions.
104 changes: 104 additions & 0 deletions packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,110 @@ describe('ReactFlightDOM', () => {
expect(reportedErrors).toEqual([]);
});

it('should handle streaming async server components', async () => {
const reportedErrors = [];

const Row = async ({current, next}) => {
const chunk = await next;

if (chunk.done) {
return chunk.value;
}

return (
<Suspense fallback={chunk.value}>
<Row current={chunk.value} next={chunk.next} />
</Suspense>
);
};

function createResolvablePromise() {
let _resolve, _reject;

const promise = new Promise((resolve, reject) => {
_resolve = resolve;
_reject = reject;
});

return {promise, resolve: _resolve, reject: _reject};
}

function createSuspensedChunk(initialValue) {
const {promise, resolve, reject} = createResolvablePromise();

return {
row: (
<Suspense fallback={initialValue}>
<Row current={initialValue} next={promise} />
</Suspense>
),
resolve,
reject,
};
}

function Text({children}) {
return <div>{children}</div>;
}

function makeDelayedText() {
const {promise, resolve, reject} = createResolvablePromise();
async function DelayedText() {
const data = await promise;
return <Text>{data}</Text>;
}
return [DelayedText, resolve, reject];
}

const [Posts, resolvePostsData] = makeDelayedText();
const suspendedChunk = createSuspensedChunk(<p>loading</p>);
const model = {rootContent: suspendedChunk.row};

function ProfilePage({response}) {
return use(response).rootContent;
}

const {writable, readable} = getTestStream();
const {pipe} = ReactServerDOMServer.renderToPipeableStream(
model,
webpackMap,
{
onError(x) {
reportedErrors.push(x);
},
},
);
pipe(writable);
const response = ReactServerDOMClient.createFromReadableStream(readable);
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);

await act(() => {
root.render(<ProfilePage response={response} />);
});

expect(container.innerHTML).toBe('<p>loading</p>');

const resolvable = createResolvablePromise();
const value = <Posts />;

await act(async () => {
suspendedChunk.resolve({value, done: false, next: resolvable.promise});
await Promise.resolve();
resolvable.resolve({value, done: true});
});

expect(container.innerHTML).toBe('<p>loading</p>');

await act(async () => {
await resolvePostsData('posts');
await 'the inner async function';
});

expect(container.innerHTML).toBe('<div>posts</div>');
expect(reportedErrors).toEqual([]);
});

it('should preserve state of client components on refetch', async () => {
// Client

Expand Down

0 comments on commit efdd474

Please sign in to comment.