Repository: preactjs/preact-render-to-string (js)

Issue:
dangerouslySetInnerHTML={undefined} throws
The [type of `dangerouslySetInnerHTML`](https://github.com/preactjs/preact/blob/f5738915a0d67c87f54f0ccd5b946e7a4ce0d5c1/src/index.d.ts#L66-L68) is:

```js
dangerouslySetInnerHTML?: {
  __html: string;
};
```

However, when setting `dangerouslySetInnerHTML` to `undefined` I hit this code here:

https://github.com/preactjs/preact-render-to-string/blob/c8e54a19deb37d8060b01377172ec65bf285b4bf/src/index.js#L122-L135

Here `element` is `undefined` and I get `Cannot read properties of undefined (reading 'then')`.

Using `typeof element?.then === 'function'` seems to fix it for me.

Pull request:
fix: Support `dangerouslySetInnerHTML={undefined}` with `renderToStringAsync`
Closes #380

Patch:
diff --git a/.changeset/chilly-ladybugs-think.md b/.changeset/chilly-ladybugs-think.md
new file mode 100644
index 0000000..94172cf
--- /dev/null
+++ b/.changeset/chilly-ladybugs-think.md
@@ -0,0 +1,5 @@
+---
+'preact-render-to-string': patch
+---
+
+Support `dangerouslySetInnerHTML={undefined}` with `renderToStringAsync`
diff --git a/src/index.js b/src/index.js
index 743f25a..ab4146f 100644
--- a/src/index.js
+++ b/src/index.js
@@ -125,7 +125,9 @@ export async function renderToStringAsync(vnode, context) {
 
 			// Resolving nested Promises with a maximum depth of 25
 			while (
-				resolved.some((element) => typeof element.then === 'function') &&
+				resolved.some(
+					(element) => element && typeof element.then === 'function'
+				) &&
 				count++ < 25
 			) {
 				resolved = (await Promise.all(resolved)).flat();


Test patch:
diff --git a/test/compat/async.test.jsx b/test/compat/async.test.jsx
index 968c12b..12e9ac5 100644
--- a/test/compat/async.test.jsx
+++ b/test/compat/async.test.jsx
@@ -226,4 +226,47 @@ describe('Async renderToString', () => {
 
 		expect(rendered).to.equal(`<div>2</div>`);
 	});
+
+	describe('dangerouslySetInnerHTML', () => {
+		it('should support dangerouslySetInnerHTML', async () => {
+			// some invalid HTML to make sure we're being flakey:
+			let html = '<a href="foo">asdf</a> some text <ul><li>foo<li>bar</ul>';
+			let rendered = await renderToStringAsync(
+				<div id="f" dangerouslySetInnerHTML={{ __html: html }} />
+			);
+			expect(rendered).to.equal(`<div id="f">${html}</div>`);
+		});
+
+		it('should accept undefined dangerouslySetInnerHTML', async () => {
+			const Test = () => (
+				<Fragment>
+					<div>hi</div>
+					<div dangerouslySetInnerHTML={undefined} />
+				</Fragment>
+			);
+
+			const rendered = await renderToStringAsync(<Test />);
+			expect(rendered).to.equal('<div>hi</div><div></div>');
+		});
+
+		it('should accept null __html', async () => {
+			const Test = () => (
+				<Fragment>
+					<div>hi</div>
+					<div dangerouslySetInnerHTML={{ __html: null }} />
+				</Fragment>
+			);
+			const rendered = await renderToStringAsync(<Test />);
+			expect(rendered).to.equal('<div>hi</div><div></div>');
+		});
+
+		it('should override children', async () => {
+			let rendered = await renderToStringAsync(
+				<div dangerouslySetInnerHTML={{ __html: 'foo' }}>
+					<b>bar</b>
+				</div>
+			);
+			expect(rendered).to.equal('<div>foo</div>');
+		});
+	});
 });
diff --git a/test/render.test.jsx b/test/render.test.jsx
index 134bdb0..db418c2 100644
--- a/test/render.test.jsx
+++ b/test/render.test.jsx
@@ -387,16 +387,6 @@ describe('render', () => {
 			);
 		});
 
-		it('should accept nullish __html', () => {
-			const Test = (props) => (
-				<Fragment>
-					<div>hi</div>
-					<div dangerouslySetInnerHTML={{ __html: null }} />
-				</Fragment>
-			);
-			expect(render(<Test />)).to.equal('<div>hi</div><div></div>');
-		});
-
 		it('should apply defaultProps', () => {
 			const Test = (props) => <div {...props} />;
 			Test.defaultProps = {
@@ -835,6 +825,26 @@ describe('render', () => {
 			expect(rendered).to.equal(`<div id="f">${html}</div>`);
 		});
 
+		it('should accept undefined dangerouslySetInnerHTML', () => {
+			const Test = () => (
+				<Fragment>
+					<div>hi</div>
+					<div dangerouslySetInnerHTML={undefined} />
+				</Fragment>
+			);
+			expect(render(<Test />)).to.equal('<div>hi</div><div></div>');
+		});
+
+		it('should accept null __html', () => {
+			const Test = () => (
+				<Fragment>
+					<div>hi</div>
+					<div dangerouslySetInnerHTML={{ __html: null }} />
+				</Fragment>
+			);
+			expect(render(<Test />)).to.equal('<div>hi</div><div></div>');
+		});
+
 		it('should override children', () => {
 			let rendered = render(
 				<div dangerouslySetInnerHTML={{ __html: 'foo' }}>