Render the Solid component on the server, then pass the resulting HTML string to Pyppeteer with await page.setContent(html). Use Solid’s renderToString for synchronous output or renderToStringAsync when server-side Suspense work must finish first. If you need to test the running application’s real browser resources, scripts, and URL behavior, navigate to its URL with page.goto() instead. Loading server-rendered markup alone does not hydrate it or make Solid’s client-side interactions work.
Choose the right way to load the Solid output
The key decision is what you mean by “load.” Pyppeteer can open an HTML string you already obtained, navigate to an app served at a URL, or exercise a server-rendered page after its client bundle hydrates it. Those paths test different things.
| What you need to test | Solid rendering path | Pyppeteer action | What the test covers |
|---|---|---|---|
| Synchronous server-rendered markup | renderToString(() => <App />) |
await page.setContent(html) |
The HTML string supplied to a browser page; synchronous server output. |
| Markup after asynchronous Suspense work | await renderToStringAsync(() => <App />) |
await page.setContent(html) |
The resulting string after server Suspense boundaries settle. |
| The deployed or locally served application | Run the app’s server as usual | await page.goto(url, ...) |
Navigation to the real URL and browser loading of its resources. |
| Streamed server rendering | renderToStream(() => <App />) |
Navigate to its endpoint, then wait for the expected page state | An initial shell and later asynchronous fragments; readiness depends on the app. |
| Client-side interactions on server-rendered markup | Server output plus matching client app and hydration setup | Load the document and wait for hydration and the tested behavior | DOM reuse and client behavior, if server markup matches client JSX. |
Solid documents renderToString as synchronous server rendering and renderToStringAsync as the server-rendering option that waits for asynchronous Suspense boundaries. Both are server APIs, not browser-bundle APIs.
Render Solid HTML on the server, then pass it to Pyppeteer
Keep the server-rendering step in a Solid server build and the browser automation step in the Python test process. The first produces a string; the second gives that string to a page.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
#1 Best Overall
1. Generate the HTML string
For a component whose server output is synchronous:
// Server-side Solid module, compiled and run in a server build
import { renderToString } from "solid-js/web";
import App from "./App";
const html = renderToString(() => <App />);
// Send `html` to the test process, or put it in a complete document.
If server-side Suspense boundaries need to resolve before the string is ready, use the asynchronous renderer:
// Server-side Solid module
import { renderToStringAsync } from "solid-js/web";
import App from "./App";
const html = await renderToStringAsync(() => <App />);
// Send `html` to the test process, or put it in a complete document.
renderToString does not wait for asynchronous Suspense boundaries. renderToStringAsync returns a promise and supports timeoutMs as a maximum wait. Choose the renderer based on whether the content your test asserts depends on that asynchronous server work.
2. Load the string in a Pyppeteer page
Once your test has obtained the string—for example, by calling your own renderer service—create a page and set its content:
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Rank #2
import asyncio
from pyppeteer import launch
async def main():
html = await get_html_from_your_server_renderer()
browser = await launch()
try:
page = await browser.newPage()
await page.setContent(html)
await page.waitForSelector("#app .expected-result")
result = await page.querySelectorEval(
"#app .expected-result",
"element => element.textContent"
)
print(result)
finally:
await browser.close()
asyncio.run(main())
get_html_from_your_server_renderer() represents the transport your project uses to obtain the string; it is not a Pyppeteer function. Replace the selector with content that exists in your rendered app. The assertion should target the output you actually need, rather than treating the successful setContent call as proof that rendering or application work completed correctly.
Solid’s server output may be a fragment. If the page needs document-level elements, styles, or scripts for your test, have the server provide a complete HTML document and pass that document to setContent. Pyppeteer’s page API describes setContent as setting the page content; it is distinct from navigating to a URL. See the Pyppeteer Page source.
Use page.goto() when the app is served at a URL
If the goal is to exercise the application as it is served—including relative resource URLs, browser-loaded scripts, and the navigation path—navigate to its HTTP URL instead of handing Pyppeteer a string.
import asyncio
from pyppeteer import launch
async def main():
browser = await launch()
try:
page = await browser.newPage()
await page.goto(
"http://127.0.0.1:3000",
{"waitUntil": "domcontentloaded"}
)
await page.waitForSelector("#app .expected-result")
result = await page.querySelectorEval(
"#app .expected-result",
"element => element.textContent"
)
print(result)
finally:
await browser.close()
asyncio.run(main())
Start the server before running the test and use the URL and selector appropriate to your project. Pyppeteer’s source lists load, domcontentloaded, and networkidle0 as navigation conditions. Its networkidle0 condition means there are no network connections for at least 500 ms; it does not establish that a particular Solid component has completed its application-specific work. Waiting for a meaningful selector or checking an explicit ready signal is more closely tied to the state under test.
Know what server-rendered HTML does—and does not—test
Server rendering produces markup. It does not, by itself, run the Solid client application in the page. If your test only checks static text or element structure, setting the HTML content may be sufficient. If it clicks controls or expects reactive updates, the document must also load the matching client-side code and complete hydration.
Hydration requires matching output and client code
Solid’s hydrate API attaches client behavior to DOM already produced by Solid’s server renderer. The DOM and the JSX returned by the hydration function must match. A test that only calls setContent(html) has not demonstrated that hydration ran or that client events work.
When hydrating a server-rendered document, include the client bundle and the appropriate hydration bootstrap. Solid’s hydrationScript documentation describes initializing window._$HY and bootstrapping delegated event replay; include that script once in the server-rendered document when the page will hydrate. Then wait for a client-visible condition before testing an interaction.
Streaming needs an application-specific ready condition
renderToStream can flush an initial shell, including Suspense fallback content, and write later asynchronous content as it resolves. For a streamed endpoint, navigation reaching a browser milestone does not necessarily mean the fragment your test needs is present. Wait for the final content or another explicit readiness condition rather than assuming the shell is the finished page.
Choose a test boundary that answers your question
- Testing server markup: render to a string, use
setContent, and assert a stable DOM or text result. - Testing the hosted application: navigate to the app URL and wait for the relevant UI state.
- Testing hydration: load the server document with its matching client bundle and hydration setup, then assert an interaction or reactive update.
- Testing streamed output: navigate to the stream endpoint and wait for the expected post-stream state.
This separation makes failures easier to interpret: a missing string result points toward server rendering or transport; a missing browser resource points toward the served page setup; a static page with nonworking controls points toward client loading or hydration.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Troubleshoot common failures
The page is blank or expected text is missing
- Confirm the server renderer returned the HTML you intended to send to Pyppeteer, rather than an empty value or an error page.
- If the content depends on asynchronous Suspense work, use
renderToStringAsyncand handle its completion or timeout instead of expecting synchronous rendering to wait. - Check that the selector and expected text match the actual server output. A selector for client-only content will not match markup that was never rendered on the server.
Relative assets or browser scripts do not load after setContent
setContent supplies markup; it is not a navigation to the app’s normal URL. If your test depends on the site’s real URL and resource loading, use page.goto(url, ...) against the served application. For string-based testing, provide the document and resource setup the test requires.
Controls appear but clicks do not update the page
Static server HTML does not prove Solid’s client behavior is active. Check that the page includes and loads the client bundle, that hydration is invoked, and that the server DOM matches the client JSX returned by the hydration function. If only static markup is required, avoid treating an interaction failure as a failure of server rendering.
The test sees fallback content instead of the resolved content
For string rendering, use renderToStringAsync when the required content depends on server Suspense boundaries. For streamed output, wait for the expected fragment or app-ready state; the initial shell can contain fallback content while asynchronous work continues.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Best Value
Navigation completes before the UI is ready
Change the navigation condition only if it fits the test, and separately wait for the selector or state that proves the UI is ready. In particular, networkidle0 is a network-activity condition, not a universal signal that Solid’s application logic has finished.
Or skip the browser setup
If your page is already available at a URL and you want a screenshot rather than a Pyppeteer test, ScreenshotNeo can capture it with one GET request. It removes cookie banners, newsletter popups, and chat widgets before the shot; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots, and 1,000 screenshots a month are free with no card; paid plans start at $5 for 3,000.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://your-site.example -o shot.webp
See the ScreenshotNeo API documentation for request options. This captures a URL; it does not replace Solid server rendering, test arbitrary HTML strings, or verify hydration behavior. Visit ScreenshotNeo for the service, or sign up free for 1,000 screenshots a month with no card.
Cost and reliability considerations for browser tests
For repeatable tests, choose the smallest boundary that exercises the behavior you care about. Passing a server-rendered string avoids involving the application’s HTTP navigation path, while a URL-based test covers the served page and its browser-loaded resources. Hydration and streamed rendering need explicit readiness assertions so the test does not mistake initial markup or fallback content for the final interactive state.
Keep the server renderer and browser test aligned with the versions and build configuration installed in your project. Solid’s rendering APIs are intended for server builds; do not import them as though they were browser APIs. The cited Pyppeteer source is on its mutable dev branch, so check the API behavior against the Pyppeteer version in your environment.
Frequently Asked Questions
Does Pyppeteer execute Solid JSX?
No. Solid renders JSX through its own rendering runtime. Pyppeteer controls a browser page after you provide markup or navigate to an application.
Can I use Pyppeteer to capture a screenshot of the page?
Yes. Pyppeteer automates a browser page, so it can be used in a workflow that captures the page after loading and waiting for the required state.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minute

