Wait for Hydration in Automated SvelteKit Browser Tests

We’re using SvelteKit on my current software development project, along with Playwright for end-to-end browser testing. Some tests would intermittently fail – so I spent some time investigating.

The Issue

The problem arose on pages where text was being entered into a form. Playwright starts filling out the form as soon as the page is loaded in the browser (coming back from SSR). However, when the page is hydrated moments later, the text in the form is cleared out!

Although Playwright is able to start entering data into a form much faster than a human could, it’s not out of the question that something might get delayed, causing a human user to experience the same issue. So it seems this might be a bug but perhaps one with such a low chance of occurrence that it’s not really an issue. The only mention I’ve been able to find of this is related to automated test frameworks.

The Workaround

After some searching, I found a workaround mentioned in a GitHub issue. The first step is to use an onMount callback that adds a class to the body tag. This will be executed during hydration. The following code snippet can be added to the layout.svelte file so it will be run regardless of the page that’s first loaded by the browser.

  onMount(() => {
    // Indicate that the SvelteKit app has started

We now have a way of knowing when the page has been hydrated. The next step is to wait for the started class to be added to the body when doing initial page navigation in the tests.

In the SvelteKit project tests, this has been done by enhancing the Playwright navigation helpers. I chose to go a different route. Instead, I added a goto helper to my TestUtils module:

  const goto = async (page: Page, url: string, opts?: { waitForStarted?: boolean }) => {
    await page.goto(url);
    if (opts?.waitForStarted !== false) {
      await page.waitForSelector("body.started", { timeout: 5000 });

Hydration Problem Solved

Now, when making an initial page navigation, I use TestUtils.goto('/'), and I know that Playwright won’t start entering text into form fields until after hydration has completed. Problem solved!

  • Mikhail Lapshin says:

    Thanks a million Patric! I had been looking for the solution of such issue for a long time. I tried different approaches and they worked only partial or didn’t work at all.

    This solution is so simple and elegant. It’s a brilliant!

  • Brian Dueck says:

    Just hit this problem myself and your post was immensely helpful. I’m surprised more isn’t done to make this problem less of a stumbling block for SvelteKit developers. I haven’t found anything in the official docs or a built in SvelteKit that would make it easier to avoid this.

  • Patrick Bacon Patrick Bacon says:

    I was similarly surprised Brian – glad this was helpful!

  • Join the conversation

    Your email address will not be published. Required fields are marked *