I am trying to render some html in playwright using page.setContent which has some react component inside it. This html works and renders on its own, but does not render react inside playwright.
await page.setContent(finalHtml, { waitUntil: "networkidle" });
await sleep(5000);
const buffer = await page.screenshot({
omitBackground: true,
});
HTML code –
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<style>
body {
margin: 0;
overflow: hidden;
background-color: #535bf2;
}
canvas {
display: block;
height: 1000px;
}
</style>
<script type="importmap">
{
"imports": {
"@jsxImportSource": "https://esm.sh/[email protected]",
"react": "https://esm.sh/[email protected]",
"react-dom/client": "https://esm.sh/[email protected]/client"
}
}
</script>
<script type="module" src="https://esm.sh/run"></script>
<title>Document</title>
</head>
<body>
<div id="root"></div>
<script type="text/babel" >
import {createRoot} from 'react-dom/client';
function App() {
return (
<h1>Hello World!</h1>
);
}
createRoot(window.root).render(<App />);
</script>
</body>
</html>
I can see the body being rendered due to the background color though.
I have also set waitUntil and sleep for 5 seconds just to wait for everything to load and render, but that has no effect.
How can I render react this way?
2
There’s an error: Uncaught DOMException: The operation is insecure. <anonymous> https://esm.sh/run:5
. You can debug this by rewiring browser console logs to appear in Node, or run headfully and examine the dev tools console by hand.
Note that esm.sh doesn’t seem to work on localhost even on its own, notwithstanding Playwright.
A workaround is to not use esm.run, and instead use a standard CDN:
const playwright = require("playwright"); // ^1.46.1
const html = `<!DOCTYPE html><html lang="en"><head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<style>
body {
margin: 0;
background-color: #535bf2;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/react@18/umd/react.development.js"></script>
<script src="https://cdn.jsdelivr.net/npm/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@babel/[email protected]/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const App = () => <h1>Hello World!</h1>;
ReactDOM.render(<App />, document.getElementById("root"));
</script></body></html>`;
let browser;
(async () => {
browser = await playwright.firefox.launch({headless: false});
const page = await browser.newPage();
await page.setContent(html, {waitUntil: "commit"});
await page.getByText("Hello World").waitFor();
await page.screenshot({path: "test.png"});
})()
.catch(err => console.error(err))
.finally(() => browser?.close());
I’m not sure what your actual use case is, but avoid sleeping and networkidle, which are slow and cause race conditions. Instead, wait for specific resources to load.
0