website

#astro#js#html#css

git clone https://git.pyrossh.dev/website

木 Personal website of pyrossh. Built with astrojs, shiki, vite.


tests/pages.test.js
import { after, before, describe, test } from "node:test";
import assert from "node:assert/strict";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { chromium } from "playwright";
import { startStaticServer } from "./helpers/static-server.js";

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const distDir = path.join(__dirname, "..", "dist");

let server;
let browser;
let page;
const consoleErrors = [];

before(async () => {
  server = await startStaticServer(distDir);
  browser = await chromium.launch();
  page = await browser.newPage();
  page.on("console", (msg) => {
    if (msg.type() === "error") consoleErrors.push(`[${page.url()}] ${msg.text()}`);
  });
  page.on("pageerror", (err) => {
    consoleErrors.push(`[${page.url()}] ${err.message}`);
  });
});

after(async () => {
  await browser?.close();
  await server?.close();
});

async function goto(urlPath) {
  const response = await page.goto(`${server.url}${urlPath}`, { waitUntil: "domcontentloaded" });
  return response;
}

describe("static pages", () => {
  test("home page renders", async () => {
    const response = await goto("/");
    assert.equal(response.status(), 200);
    await assert.doesNotReject(page.locator("h1.title").waitFor());
    assert.match(await page.title(), /pyrossh/);
  });

  test("cv page renders", async () => {
    const response = await goto("/cv/");
    assert.equal(response.status(), 200);
    await assert.doesNotReject(page.locator("h1").waitFor());
    assert.equal(await page.locator("img[alt='Resume']").count(), 1);
  });

  test("posts index lists posts", async () => {
    const response = await goto("/posts/");
    assert.equal(response.status(), 200);
    const links = page.locator("main a[href^='/posts/']");
    assert.ok((await links.count()) > 0, "expected at least one post link");
  });

  test("a post page renders", async () => {
    const response = await goto("/posts/react-powertools-swr/");
    assert.equal(response.status(), 200);
    assert.match(await page.title(), /React Powertools/);
  });

  test("only-bible-app pages render", async () => {
    for (const url of ["/only-bible-app/", "/only-bible-app/privacy-policy/", "/only-bible-app/terms-and-conditions/"]) {
      const response = await goto(url);
      assert.equal(response.status(), 200, `expected 200 for ${url}`);
    }
  });

  test("robots.txt and rss.xml are served", async () => {
    const robots = await goto("/robots.txt");
    assert.equal(robots.status(), 200);
    assert.match(await page.content(), /User-agent/);

    const rss = await goto("/rss.xml");
    assert.equal(rss.status(), 200);
  });

  test("unknown route returns the 404 page", async () => {
    const response = await goto("/this-page-does-not-exist/");
    assert.equal(response.status(), 404);
    assert.match(await page.locator("h1").textContent(), /404/);
  });
});

describe("repo pages", () => {
  const repoId = "website";

  test("repo readme page renders", async () => {
    const response = await goto(`/repos/${repoId}/`);
    assert.equal(response.status(), 200);
    await assert.doesNotReject(page.locator(".repo .header h1").waitFor());
    assert.equal(await page.locator(".nav a.active-tab").textContent(), "Readme");
  });

  test("repo commits page lists commits", async () => {
    const response = await goto(`/repos/${repoId}/commits/`);
    assert.equal(response.status(), 200);
    const commitLinks = page.locator(`a[href^='/repos/${repoId}/commits/']`);
    assert.ok((await commitLinks.count()) > 0, "expected at least one commit link");
  });

  test("a single commit page renders", async () => {
    await goto(`/repos/${repoId}/commits/`);
    const firstCommitHref = await page.locator(`a[href^='/repos/${repoId}/commits/']`).first().getAttribute("href");
    const response = await goto(firstCommitHref);
    assert.equal(response.status(), 200);
    assert.equal(await page.locator(".nav a.active-tab").textContent(), "Commits");
  });

  test("repo files index renders the tree and a default file", async () => {
    const response = await goto(`/repos/${repoId}/files/`);
    assert.equal(response.status(), 200);
    assert.ok((await page.locator(".file-explorer-tree").count()) > 0);
  });

  test("a specific file, its history and blame views render", async () => {
    const filePath = "eleventy.config.js";
    const fileRes = await goto(`/repos/${repoId}/files/${filePath}/`);
    assert.equal(fileRes.status(), 200);

    const historyRes = await goto(`/repos/${repoId}/files/${filePath}/history/`);
    assert.equal(historyRes.status(), 200);

    const blameRes = await goto(`/repos/${repoId}/files/${filePath}/blame/`);
    assert.equal(blameRes.status(), 200);
  });

  test("repo nav tabs swap content via htmx without a full reload", async () => {
    await goto(`/repos/${repoId}/`);
    await page.click(".nav a[href='/repos/website/files/']");
    await page.waitForURL(`${server.url}/repos/${repoId}/files/`);
    assert.equal(await page.locator(".nav a.active-tab").textContent(), "Code");
  });
});

test("no unexpected console errors were logged across visited pages", () => {
  // The deliberate 404 test above triggers a browser-level "failed to load
  // resource" console entry for its own navigation request — that's the
  // behavior under test there, not a bug, so it's excluded here.
  const unexpected = consoleErrors.filter((msg) => !msg.includes("this-page-does-not-exist"));
  assert.deepEqual(unexpected, []);
});