Skip to content

Commit

Permalink
fix: wait for hydration via react effect
Browse files Browse the repository at this point in the history
  • Loading branch information
katywings committed Jun 30, 2024
1 parent 8600f15 commit b4bddb8
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 27 deletions.
20 changes: 12 additions & 8 deletions test/basic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@ testDevAndProd("basic", ({ createFixture }) => {
});
});

test("ssr", async () => {
let res = await fixture.requestDocument("/");
expect(res.status).toBe(200);
expect(res.headers.get("Content-Type")).toBe("text/html");
test("ssr", async ({ page }) => {
const app = new PlaywrightFixture(appFixture, page);
const res = await app.goto("/", true);
expect(res.status()).toBe(200);
const headers = await res.allHeaders();
expect(headers["content-type"]).toBe("text/html");
expect(selectHtml(await res.text(), "[data-test-id=content]")).toBe(
prettyHtml(`<h1 data-test-id="content">Hello from Vinxi</h1>`),
);
Expand All @@ -59,10 +61,12 @@ testDevAndProd("basic", ({ createFixture }) => {
);
});

test("api", async () => {
let res = await fixture.requestDocument("/api/hello");
expect(res.status).toBe(200);
expect(res.headers.get("Content-Type")).toBe("text/html");
test("api", async ({ page }) => {
const app = new PlaywrightFixture(appFixture, page);
const res = await app.goto("/api/hello", true);
expect(res.status()).toBe(200);
const headers = await res.allHeaders();
expect(headers["content-type"]).toBe("text/html");
expect(await res.text()).toBe("Hello world");
});
});
20 changes: 14 additions & 6 deletions test/fs-router.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,12 @@ testDevAndProd("fs-router", ({ createFixture }) => {
});

test("ssr", async ({ page }) => {
let res = await fixture.requestDocument("/");
expect(res.status).toBe(200);
expect(res.headers.get("Content-Type")).toBe("text/html");
let app = new PlaywrightFixture(appFixture, page);
let res = await app.goto("/", true);
let headers = await res.allHeaders();

expect(res.status()).toBe(200);
expect(headers["content-type"]).toBe("text/html");
let html = await res.text();
expect(selectHtml(html, "[data-test-id=title]")).toBe(
prettyHtml(`<h1 data-test-id="title">Vinxi Home</h1>`),
Expand All @@ -45,9 +48,11 @@ testDevAndProd("fs-router", ({ createFixture }) => {
prettyHtml(`<button data-test-id="counter">0</button>`),
);

res = await fixture.requestDocument("/hello");
expect(res.status).toBe(200);
expect(res.headers.get("Content-Type")).toBe("text/html");
res = await app.goto("/hello", true);
headers = await res.allHeaders();

expect(res.status()).toBe(200);
expect(headers["content-type"]).toBe("text/html");
html = await res.text();
expect(selectHtml(html, "[data-test-id=title]")).toBe(
prettyHtml(`<h1 data-test-id="title">Hello from Vinxi</h1>`),
Expand All @@ -60,6 +65,7 @@ testDevAndProd("fs-router", ({ createFixture }) => {
test("hydrates", async ({ page }) => {
let app = new PlaywrightFixture(appFixture, page);
await app.goto("/", true);
await app.isReady();

expect(await app.getHtml("[data-test-id=title]")).toBe(
prettyHtml(`<h1 data-test-id="title">Vinxi Home</h1>`),
Expand All @@ -76,6 +82,7 @@ testDevAndProd("fs-router", ({ createFixture }) => {

await app.clickElement("a[href='/hello']");
await app.waitForURL("/hello");
await app.isReady();
await new Promise((r) => setTimeout(r, 1000));

expect(await app.getHtml("[data-test-id=title]")).toBe(
Expand All @@ -87,6 +94,7 @@ testDevAndProd("fs-router", ({ createFixture }) => {

await app.clickElement("a[href='/']");
await app.waitForURL("/");
await app.isReady();
await new Promise((r) => setTimeout(r, 2000));

expect(await app.getHtml("[data-test-id=title]")).toBe(
Expand Down
2 changes: 2 additions & 0 deletions test/helpers/create-fixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,10 @@ export async function createDevFixture(init: FixtureInit) {
await fse.remove(path.join(projectDir, filename));
} else {
await fse.writeFile(path.join(projectDir, filename), prevValue);
await new Promise((r) => setTimeout(r, 1000));
}
}
cache.clear();
// await fse.remove(projectDir);
// projectDir = await createFixtureProject(init);
},
Expand Down
8 changes: 8 additions & 0 deletions test/helpers/playwright-fixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,14 @@ export class PlaywrightFixture {
cp.exec(`open ${this.app.serverUrl}${href}`);
return new Promise(res => setTimeout(res, ms));
}

/**
* Checks if the page is hydrated via a data-ready attribute,
* that is being set with useEffect.
*/
async isReady () {
return this.page.locator('[data-ready]').waitFor({ state: "attached" });

Check failure on line 199 in test/helpers/playwright-fixture.ts

View workflow job for this annotation

GitHub Actions / 👀 (os: ubuntu-latest, node: 18)

[chromium] › fs-router.test.ts:65:2 › fs-router-dev › hydrates

1) [chromium] › fs-router.test.ts:65:2 › fs-router-dev › hydrates ──────────────────────────────── Error: locator.waitFor: Page closed =========================== logs =========================== waiting for locator('[data-ready]') ============================================================ at helpers/playwright-fixture.ts:199 197 | */ 198 | async isReady () { > 199 | return this.page.locator('[data-ready]').waitFor({ state: "attached" }); | ^ 200 | } 201 | } 202 | at PlaywrightFixture.isReady (/home/runner/work/vinxi/vinxi/test/helpers/playwright-fixture.ts:199:46) at /home/runner/work/vinxi/vinxi/test/fs-router.test.ts:68:13

Check failure on line 199 in test/helpers/playwright-fixture.ts

View workflow job for this annotation

GitHub Actions / 👀 (os: macos-latest, node: 18)

[chromium] › hmr.test.ts:91:2 › hmr › client hmr

2) [chromium] › hmr.test.ts:91:2 › hmr › client hmr ────────────────────────────────────────────── Error: locator.waitFor: Page closed =========================== logs =========================== waiting for locator('[data-ready]') ============================================================ at helpers/playwright-fixture.ts:199 197 | */ 198 | async isReady () { > 199 | return this.page.locator('[data-ready]').waitFor({ state: "attached" }); | ^ 200 | } 201 | } 202 | at PlaywrightFixture.isReady (/Users/runner/work/vinxi/vinxi/test/helpers/playwright-fixture.ts:199:46) at /Users/runner/work/vinxi/vinxi/test/hmr.test.ts:94:13
}
}

export async function getHtml(page: Page, selector?: string) {
Expand Down
19 changes: 12 additions & 7 deletions test/hmr.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,13 @@ test.describe("hmr", () => {
await fixture.reset();
});

test("hmr ssr", async () => {
let res = await fixture.requestDocument("/");
expect(res.status).toBe(200);
expect(res.headers.get("Content-Type")).toBe("text/html");
test("hmr ssr", async ({ page }) => {
let app = new PlaywrightFixture(appFixture, page);
let res = await app.goto("/", true);
let headers = await res.allHeaders();

expect(res.status()).toBe(200);
expect(headers["content-type"]).toBe("text/html");
expect(await selectHtml(await res.text(), "[data-test-id=content]")).toBe(
prettyHtml(`<h1 data-test-id="content">Hello from Vinxi</h1>`),
);
Expand Down Expand Up @@ -76,9 +79,10 @@ test.describe("hmr", () => {

await new Promise((r) => setTimeout(r, 1000));

res = await fixture.requestDocument("/");
expect(res.status).toBe(200);
expect(res.headers.get("Content-Type")).toBe("text/html");
res = await app.goto("/", true);
headers = await res.allHeaders();
expect(res.status()).toBe(200);
expect(headers["content-type"]).toBe("text/html");
expect(selectHtml(await res.text(), "[data-test-id=content]")).toBe(
prettyHtml(`<h1 data-test-id="content">Hello from Vinxi too</h1>`),
);
Expand All @@ -87,6 +91,7 @@ test.describe("hmr", () => {
test("client hmr", async ({ page }) => {
let app = new PlaywrightFixture(appFixture, page);
await app.goto("/", true);
await app.isReady();

expect(await app.getHtml("[data-test-id=content]")).toBe(
prettyHtml(`<h1 data-test-id="content">Hello from Vinxi</h1>`),
Expand Down
2 changes: 1 addition & 1 deletion test/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const config: PlaywrightTestConfig = {
testDir: ".",
testMatch: ["**/*.test.ts"],
fullyParallel: false,
timeout: process.env.CI ? 120_000 : 30_000, // 2 minutes in CI, 30 seconds locally
timeout: process.env.CI ? 360_000 : 30_000, // 5 minutes in CI, 30 seconds locally
expect: {
timeout: 5_000, // 5 second retries for assertions
},
Expand Down
16 changes: 14 additions & 2 deletions test/templates/react-ssr-fs/app/app.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
import React from "react";
import React, { useEffect, useRef } from "react";

import { Counter } from "./Counter";
import "./style.css";

const useReadyRef = <T extends HTMLElement,>() => {
const ref = useRef<T>();
useEffect(() => {
ref.current.dataset.ready = "";
return () => {
ref.current.dataset.ready = null;
}
}, []);
return ref;
}

export default function App({ assets, children }) {
const [count, setCount] = React.useState(0);
const ref = useReadyRef<HTMLHtmlElement>();
return (
<html lang="en">
<html lang="en" ref={ref}>
<head>
<link rel="icon" href="/favicon.ico" />
{assets}
Expand Down
17 changes: 14 additions & 3 deletions test/templates/react/app/root.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
import React from "react";

import React, { useEffect, useRef } from "react";
import { Counter } from "./Counter";

const useReadyRef = <T extends HTMLElement,>() => {
const ref = useRef<T>();
useEffect(() => {
ref.current.dataset.ready = "";
return () => {
ref.current.dataset.ready = null;
}
}, []);
return ref;
}

export default function App({ assets }) {
const ref = useReadyRef<HTMLHtmlElement>();
return (
<html lang="en">
<html lang="en" ref={ref}>
<head>
<link rel="icon" href="/favicon.ico" />
{assets}
Expand Down

0 comments on commit b4bddb8

Please sign in to comment.