Skip to content

Commit 6ec9dd7

Browse files
committed
Initial implementation of serverRender function
1 parent 3206e72 commit 6ec9dd7

File tree

2 files changed

+56
-2
lines changed

2 files changed

+56
-2
lines changed

app/serverRender.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { RenderOptions, render } from '@testing-library/react'
2+
import React from 'react'
3+
import { renderToPipeableStream } from 'react-dom/server'
4+
import { Writable } from 'stream'
5+
6+
class HtmlWritable extends Writable {
7+
chunks = new Array<any>()
8+
html = ''
9+
10+
_write(
11+
chunk: any,
12+
encoding: BufferEncoding,
13+
callback: (error?: Error) => void
14+
) {
15+
this.chunks.push(chunk)
16+
callback()
17+
}
18+
19+
_final(callback: () => void) {
20+
this.html = Buffer.concat(this.chunks).toString()
21+
callback()
22+
}
23+
}
24+
25+
export default async function serverRender(
26+
ui: React.ReactElement,
27+
{ wrapper: WrapperComponent, ...options }: Omit<RenderOptions, 'hydrate'> = {}
28+
) {
29+
const wrapUiIfNeeded = (innerElement: React.ReactNode) =>
30+
WrapperComponent
31+
? React.createElement(WrapperComponent, null, innerElement)
32+
: innerElement
33+
34+
document.write(
35+
await new Promise((resolve, reject) => {
36+
const { pipe } = renderToPipeableStream(wrapUiIfNeeded(ui), {
37+
async onAllReady() {
38+
const writable = new HtmlWritable()
39+
pipe(writable)
40+
writable.on('finish', () => resolve(writable.html))
41+
},
42+
onShellError(error) {
43+
reject(error)
44+
},
45+
onError(error) {
46+
reject(error)
47+
},
48+
})
49+
})
50+
)
51+
52+
return render(ui, { hydrate: true, ...options })
53+
}

app/test.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { render, screen } from '@testing-library/react'
1+
import { screen } from '@testing-library/react'
22
import Layout from './layout'
33
import Page from './page'
4+
import serverRender from './serverRender'
45

5-
beforeEach(() => render(<Page />, { wrapper: Layout }))
6+
beforeEach(() => serverRender(<Page />, { wrapper: Layout }))
67

78
test.each(['client', 'server', 'layout'])(`%s component`, (keyword) => {
89
expect(screen.getByText(keyword)).toBeInTheDocument()

0 commit comments

Comments
 (0)