From 7b402809539f850989052befa179dc1d72d66628 Mon Sep 17 00:00:00 2001 From: Nikhil Saraf Date: Tue, 1 Aug 2023 00:11:51 +0530 Subject: [PATCH] add tests --- packages/vinxi/bin/cli.mjs | 2 +- test/basic-dev.test.ts | 91 ++++++++++++++++++++++++++++++++++ test/helpers/create-fixture.ts | 90 ++++++++++++++++++++++++++++++++- 3 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 test/basic-dev.test.ts diff --git a/packages/vinxi/bin/cli.mjs b/packages/vinxi/bin/cli.mjs index 4499d668..cf868328 100755 --- a/packages/vinxi/bin/cli.mjs +++ b/packages/vinxi/bin/cli.mjs @@ -17,7 +17,7 @@ async function main() { const { createDevServer } = await import("../lib/dev-server.js"); await createDevServer(config, { dev: true, - port: 3000, + port: Number(process.env.PORT ?? 3000), }); } else if (command === "build") { process.env.NODE_ENV = "production"; diff --git a/test/basic-dev.test.ts b/test/basic-dev.test.ts new file mode 100644 index 00000000..a9cae7db --- /dev/null +++ b/test/basic-dev.test.ts @@ -0,0 +1,91 @@ +import { expect, test } from "@playwright/test"; + +import type { AppFixture, Fixture } from "./helpers/create-fixture.js"; +import { + createDevFixture, + createFixture, + js, +} from "./helpers/create-fixture.js"; +import { + PlaywrightFixture, + prettyHtml, + selectHtml, +} from "./helpers/playwright-fixture.js"; + +test.describe("rendering", () => { + let fixture: Fixture; + let appFixture: AppFixture; + // test.skip(process.env.START_ADAPTER !== "solid-start-node"); + + test.beforeAll(async () => { + fixture = await createDevFixture({ + files: { + "app/root.tsx": js` + import { useState } from "react"; + + export default function App({ assets }) { + const [count, setCount] = useState(0); + return ( + + + + {assets} + + +
+

Hello from Vinxi

+ + {count} +
+ + + ); + } + `, + }, + }); + + appFixture = await fixture.createServer(); + }); + + test.afterAll(async () => { + await appFixture.close(); + }); + + let logs: string[] = []; + + test.beforeEach(({ page }) => { + page.on("console", (msg) => { + logs.push(msg.text()); + }); + }); + + test("ssr", async () => { + let res = await fixture.requestDocument("/"); + expect(res.status).toBe(200); + expect(res.headers.get("Content-Type")).toBe("text/html"); + expect(selectHtml(await res.text(), "[data-test-id=content]")).toBe( + prettyHtml(`

Hello from Vinxi

`), + ); + }); + + test("hydrates", async ({ page }) => { + let app = new PlaywrightFixture(appFixture, page); + await app.goto("/", true); + + expect(await app.getHtml("[data-test-id=content]")).toBe( + prettyHtml(`

Hello from Vinxi

`), + ); + expect(await app.getHtml("[data-test-id=count]")).toBe( + prettyHtml(`0`), + ); + + await app.clickElement("[data-test-id=button]"); + + expect(await app.getHtml("[data-test-id=count]")).toBe( + prettyHtml(`1`), + ); + }); +}); diff --git a/test/helpers/create-fixture.ts b/test/helpers/create-fixture.ts index f6008104..ad904ef2 100644 --- a/test/helpers/create-fixture.ts +++ b/test/helpers/create-fixture.ts @@ -33,8 +33,97 @@ export function json(value: object) { return JSON.stringify(value, null, 2); } +export async function createDevFixture(init: FixtureInit) { + let projectDir = await createFixtureProject(init); + + let ip = "localhost"; + let port = await getPort(); + let proc = spawn("npm", ["run", "dev"], { + cwd: projectDir, + env: { + ...process.env, + PORT: `${port}`, + IP: ip, + }, + }); + + proc.stdout?.pipe(process.stdout); + proc.stderr?.pipe(process.stderr); + + await waitOn( + { + resources: [`http://${ip}:${port}/favicon.ico`], + validateStatus: function (status) { + return status >= 200 && status < 310; // default if not provided + }, + }, + undefined, + ); + + let getStaticHTML = async () => { + let text = await readFile( + path.join(projectDir, "dist", "client", "index.html"), + "utf8", + ); + return new Response(text, { + headers: { + "content-type": "text/html", + }, + }); + }; + + let requestDocument = async (href: string, init?: RequestInit) => { + let url = new URL(href, `http://${ip}:${port}`); + let request = new Request(url, init); + try { + return await fetch(request); + } catch (err) { + console.error(err); + return new Response(err.message, { + status: 500, + }); + } + }; + + let postDocument = async (href: string, data: URLSearchParams | FormData) => { + return await requestDocument(href, { + method: "POST", + body: data, + headers: { + "Content-Type": + data instanceof URLSearchParams + ? "application/x-www-form-urlencoded" + : "multipart/form-data", + }, + }); + }; + + let getBrowserAsset = async (asset: string) => { + return await fse.readFile( + path.join(projectDir, "public", asset.replace(/^\//, "")), + "utf8", + ); + }; + + return { + projectDir, + requestDocument, + postDocument, + getBrowserAsset, + createServer: async () => { + return { + serverUrl: `http://${ip}:${port}`, + close: async () => { + proc.kill(); + }, + }; + }, + }; +} + export async function createFixture(init: FixtureInit) { let projectDir = await createFixtureProject(init); + await build(projectDir, init.buildStdio); let buildPath = path.resolve(projectDir, ".output", "server", "index.mjs"); if (!fse.existsSync(buildPath)) { throw new Error( @@ -151,7 +240,6 @@ export async function createFixtureProject(init: FixtureInit): Promise { await fse.copy(integrationTemplateDir, projectDir); await writeTestFiles(init, projectDir); - await build(projectDir, init.buildStdio); return projectDir; }