Skip to content

Commit 054dae0

Browse files
Fix instance where renderToStringAsync returns a promise of a promise (#378)
* Fix issue where rendered is a promise I want to test this in my project to see if this change fixes it. All being well, I'll then add a test here and submit it for review * Different syntax, but more success I'm unclear why the previous didn't seem to work for me * Attempt to write a test for the case based on my app So far no luck actually reproducing the issue. I will take a different tact and remove code from my app until the issue goes away, to figure out what causes the behaviour. * Add test that tests behaviour * Further simplify test case * Further simplify test case * Create the test I want * Revert unrelated change * Add changeset * Add missing imports * Reproduce without useClient But I still need the provider * Avoid using urql * Better description * Update test/compat/async.test.jsx --------- Co-authored-by: Jovi De Croock <[email protected]>
1 parent ae6450b commit 054dae0

File tree

3 files changed

+73
-17
lines changed

3 files changed

+73
-17
lines changed

.changeset/famous-experts-decide.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'preact-render-to-string': patch
3+
---
4+
5+
Fix issue where preactRenderToString returns a promise of a promise

src/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ export async function renderToStringAsync(vnode, context) {
109109
parent[CHILDREN] = [vnode];
110110

111111
try {
112-
const rendered = _renderToString(
112+
const rendered = await _renderToString(
113113
vnode,
114114
context || EMPTY_OBJ,
115115
false,

test/compat/async.test.jsx

+67-16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { renderToStringAsync } from '../../src/index.js';
2-
import { h } from 'preact';
3-
import { Suspense, useId } from 'preact/compat';
2+
import { h, Fragment } from 'preact';
3+
import { Suspense, useId, lazy, createContext } from 'preact/compat';
44
import { expect } from 'chai';
55
import { createSuspender } from '../utils.jsx';
66

@@ -26,10 +26,14 @@ describe('Async renderToString', () => {
2626
});
2727

2828
it('should render JSX with nested suspended components', async () => {
29-
const { Suspender: SuspenderOne, suspended: suspendedOne } =
30-
createSuspender();
31-
const { Suspender: SuspenderTwo, suspended: suspendedTwo } =
32-
createSuspender();
29+
const {
30+
Suspender: SuspenderOne,
31+
suspended: suspendedOne
32+
} = createSuspender();
33+
const {
34+
Suspender: SuspenderTwo,
35+
suspended: suspendedTwo
36+
} = createSuspender();
3337

3438
const promise = renderToStringAsync(
3539
<ul>
@@ -56,10 +60,14 @@ describe('Async renderToString', () => {
5660
});
5761

5862
it('should render JSX with nested suspense boundaries', async () => {
59-
const { Suspender: SuspenderOne, suspended: suspendedOne } =
60-
createSuspender();
61-
const { Suspender: SuspenderTwo, suspended: suspendedTwo } =
62-
createSuspender();
63+
const {
64+
Suspender: SuspenderOne,
65+
suspended: suspendedOne
66+
} = createSuspender();
67+
const {
68+
Suspender: SuspenderTwo,
69+
suspended: suspendedTwo
70+
} = createSuspender();
6371

6472
const promise = renderToStringAsync(
6573
<ul>
@@ -88,12 +96,18 @@ describe('Async renderToString', () => {
8896
});
8997

9098
it('should render JSX with multiple suspended direct children within a single suspense boundary', async () => {
91-
const { Suspender: SuspenderOne, suspended: suspendedOne } =
92-
createSuspender();
93-
const { Suspender: SuspenderTwo, suspended: suspendedTwo } =
94-
createSuspender();
95-
const { Suspender: SuspenderThree, suspended: suspendedThree } =
96-
createSuspender();
99+
const {
100+
Suspender: SuspenderOne,
101+
suspended: suspendedOne
102+
} = createSuspender();
103+
const {
104+
Suspender: SuspenderTwo,
105+
suspended: suspendedTwo
106+
} = createSuspender();
107+
const {
108+
Suspender: SuspenderThree,
109+
suspended: suspendedThree
110+
} = createSuspender();
97111

98112
const promise = renderToStringAsync(
99113
<ul>
@@ -175,4 +189,41 @@ describe('Async renderToString', () => {
175189
const rendered = await promise;
176190
expect(rendered).to.equal('<p>ok</p>');
177191
});
192+
193+
it('should work with an in-render suspension', async () => {
194+
const Context = createContext();
195+
196+
let c = 0;
197+
198+
const Fetcher = ({ children }) => {
199+
c++;
200+
if (c === 1) {
201+
throw Promise.resolve();
202+
}
203+
return <Fragment>{children}</Fragment>;
204+
};
205+
206+
const LazyComponent = lazy(
207+
async () =>
208+
function ImportedComponent() {
209+
return <div>2</div>;
210+
}
211+
);
212+
213+
const LoadableComponent = ({}) => (
214+
<Suspense fallback={'...loading'}>
215+
<LazyComponent />
216+
</Suspense>
217+
);
218+
219+
const rendered = await renderToStringAsync(
220+
<Context.Provider>
221+
<Fetcher>
222+
<LoadableComponent />
223+
</Fetcher>
224+
</Context.Provider>
225+
);
226+
227+
expect(rendered).to.equal(`<div>2</div>`);
228+
});
178229
});

0 commit comments

Comments
 (0)