test: validate packaged Pages application subpaths

This commit is contained in:
vorotamoroz
2026-07-29 11:13:10 +00:00
parent 72197a5df0
commit 29c26c43b7
4 changed files with 96 additions and 0 deletions
+3
View File
@@ -81,6 +81,9 @@ jobs:
test -s _site/webpeer/index.html test -s _site/webpeer/index.html
touch _site/.nojekyll touch _site/.nojekyll
- name: Validate packaged Pages site
run: npm run test:browser-apps:pages
- name: Configure GitHub Pages - name: Configure GitHub Pages
uses: actions/configure-pages@v5 uses: actions/configure-pages@v5
+1
View File
@@ -32,6 +32,7 @@
"test:unit": "vitest run --config vitest.config.unit.ts", "test:unit": "vitest run --config vitest.config.unit.ts",
"build:browser-apps": "npm run build --workspace livesync-webapp --workspace webpeer", "build:browser-apps": "npm run build --workspace livesync-webapp --workspace webpeer",
"test:browser-apps": "npm run test:browser --workspace livesync-webapp && npm run test:browser --workspace webpeer", "test:browser-apps": "npm run test:browser --workspace livesync-webapp && npm run test:browser --workspace webpeer",
"test:browser-apps:pages": "deno test -A --no-check --frozen --config test/browser-apps/deno.json --lock test/browser-apps/deno.lock test/browser-apps/pages/browser-smoke.test.ts",
"test:e2e:browser-apps": "npm run test:browser-apps", "test:e2e:browser-apps": "npm run test:browser-apps",
"pretest:e2e:browser-apps:interop": "npm run build:browser-apps && npm run build --workspace self-hosted-livesync-cli", "pretest:e2e:browser-apps:interop": "npm run build:browser-apps && npm run build --workspace self-hosted-livesync-cli",
"test:e2e:browser-apps:interop": "deno run -A --no-check --frozen --config test/browser-apps/deno.json --lock test/browser-apps/deno.lock test/browser-apps/run-compose-interop.ts", "test:e2e:browser-apps:interop": "deno run -A --no-check --frozen --config test/browser-apps/deno.json --lock test/browser-apps/deno.lock test/browser-apps/run-compose-interop.ts",
+9
View File
@@ -8,6 +8,7 @@ Each application has its own production-bundle smoke-test directory outside `src
- `test/browser-apps/webapp/` covers Vault selection, OPFS start-up, and isolation between optional P2P settings and the main remote. - `test/browser-apps/webapp/` covers Vault selection, OPFS start-up, and isolation between optional P2P settings and the main remote.
- `test/browser-apps/webpeer/` covers start-up, settings persistence, and reload. - `test/browser-apps/webpeer/` covers start-up, settings persistence, and reload.
- `test/browser-apps/pages/` covers the final GitHub Pages layout, application subpaths, and relative assets.
Run both app-owned tests with: Run both app-owned tests with:
@@ -23,4 +24,12 @@ Run the isolated relay and TURN scenario in Compose with:
npm run test:e2e:browser-apps:interop npm run test:e2e:browser-apps:interop
``` ```
After assembling the GitHub Pages files in `_site`, run the package smoke test with:
```bash
npm run test:browser-apps:pages
```
Set `PAGES_SITE_ROOT` to test an assembled site in another directory.
The Deno dependency lock is shared only by these browser application tests. The Deno dependency lock is shared only by these browser application tests.
@@ -0,0 +1,83 @@
import { assertEquals } from "@std/assert";
import { resolve } from "@std/path";
import { chromium, type Page } from "playwright";
import { observePageFailures, startStaticServer } from "../helpers/browser.ts";
const pagesSiteRoot = resolve(Deno.env.get("PAGES_SITE_ROOT") ?? resolve(import.meta.dirname!, "../../../_site"));
function observeNetworkFailures(page: Page): () => void {
const failures: string[] = [];
page.on("requestfailed", (request) => {
failures.push(`${request.method()} ${request.url()}: ${request.failure()?.errorText ?? "request failed"}`);
});
page.on("response", (response) => {
if (response.status() >= 400) {
failures.push(`${response.request().method()} ${response.url()}: HTTP ${response.status()}`);
}
});
return () => assertEquals(failures, [], failures.join("\n"));
}
Deno.test({
name: "GitHub Pages package serves browser applications from their final subpaths",
sanitizeOps: false,
sanitizeResources: false,
async fn() {
const server = await startStaticServer(pagesSiteRoot);
const browser = await chromium.launch({ headless: true });
try {
const aggregator = await browser.newPage();
const assertNoAggregatorFailures = observePageFailures(aggregator);
const assertNoAggregatorNetworkFailures = observeNetworkFailures(aggregator);
await aggregator.goto(new URL("aggregator.html#id=pages-smoke&n=2&i=0&d=first-", server.baseUrl).href);
await aggregator.getByText("1 / 2 Loaded", { exact: true }).waitFor();
await aggregator.goto(new URL("aggregator.html#id=pages-smoke&n=2&i=1&d=second", server.baseUrl).href);
assertEquals(
await aggregator.getByRole("link", { name: "Open Obsidian to complete setup" }).getAttribute("href"),
"obsidian://setuplivesync?settingsQR=first-second"
);
assertNoAggregatorFailures();
assertNoAggregatorNetworkFailures();
await aggregator.close();
const webApp = await browser.newPage();
const assertNoWebAppFailures = observePageFailures(webApp);
const assertNoWebAppNetworkFailures = observeNetworkFailures(webApp);
await webApp.addInitScript(`
Object.defineProperty(globalThis, "showDirectoryPicker", {
configurable: true,
value: async () => {
throw new DOMException("Cancelled by Pages browser test", "AbortError");
},
});
`);
await webApp.goto(new URL("webapp/", server.baseUrl).href);
await webApp.waitForURL(/\/webapp\/webapp\.html$/);
const vaultPicker = webApp.getByRole("button", { name: "Choose new vault folder" });
await vaultPicker.click();
await webApp.locator("#status.warning").filter({ hasText: "Vault selection was cancelled" }).waitFor();
assertEquals(await vaultPicker.isEnabled(), true);
assertNoWebAppFailures();
assertNoWebAppNetworkFailures();
await webApp.close();
const webPeer = await browser.newPage();
const assertNoWebPeerFailures = observePageFailures(webPeer);
const assertNoWebPeerNetworkFailures = observeNetworkFailures(webPeer);
await webPeer.goto(new URL("webpeer/", server.baseUrl).href);
await webPeer.getByRole("heading", { name: "Peer to Peer Replicator", exact: true }).waitFor({
timeout: 30_000,
});
await webPeer.getByText("No Connection", { exact: true }).waitFor();
assertEquals(new URL(webPeer.url()).pathname, "/webpeer/");
const manifest = await webPeer.request.get(new URL("webpeer/manifest.json", server.baseUrl).href);
assertEquals(manifest.status(), 200);
assertNoWebPeerFailures();
assertNoWebPeerNetworkFailures();
} finally {
await browser.close();
await server.close();
}
},
});