feat: add toolbox contract shell and testkit
This commit is contained in:
118
packages/testkit/test/check.test.ts
Normal file
118
packages/testkit/test/check.test.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
// @vitest-environment node
|
||||
|
||||
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
|
||||
import { checkToolboxDist } from "../src/index.js";
|
||||
|
||||
const temporaryDirectories: string[] = [];
|
||||
|
||||
const manifest = (overrides: Record<string, unknown> = {}) => ({
|
||||
schemaVersion: 1,
|
||||
id: "de.add-ideas.example",
|
||||
name: "Example",
|
||||
version: "1.2.3",
|
||||
description: "Example app",
|
||||
entry: "./",
|
||||
icon: "./icon.svg",
|
||||
categories: ["example"],
|
||||
tags: ["test"],
|
||||
integration: {
|
||||
contextVersion: 1,
|
||||
launchModes: ["navigate"],
|
||||
embedding: "unsupported",
|
||||
},
|
||||
requirements: {
|
||||
secureContext: false,
|
||||
workers: false,
|
||||
indexedDb: false,
|
||||
crossOriginIsolated: false,
|
||||
},
|
||||
privacy: {
|
||||
processing: "local",
|
||||
fileUploads: false,
|
||||
telemetry: false,
|
||||
},
|
||||
source: {
|
||||
repository: "https://git.example.test/example",
|
||||
license: "MIT",
|
||||
},
|
||||
assets: ["./app.js"],
|
||||
...overrides,
|
||||
});
|
||||
|
||||
async function fixture(document = manifest()): Promise<string> {
|
||||
const root = await mkdtemp(join(tmpdir(), "toolbox-check-"));
|
||||
temporaryDirectories.push(root);
|
||||
await Promise.all([
|
||||
writeFile(join(root, "toolbox-app.json"), JSON.stringify(document)),
|
||||
writeFile(
|
||||
join(root, "index.html"),
|
||||
'<!doctype html><link rel="manifest" href="./site.webmanifest"><link rel="icon" href="./icon.svg"><link rel="stylesheet" href="./style.css"><img src="./image.png" alt=""><script type="module" src="./app.js"></script><title>Example</title>',
|
||||
),
|
||||
writeFile(
|
||||
join(root, "icon.svg"),
|
||||
'<svg xmlns="http://www.w3.org/2000/svg"/>',
|
||||
),
|
||||
writeFile(join(root, "app.js"), "console.log('ok')"),
|
||||
writeFile(join(root, "style.css"), "body { color: black; }"),
|
||||
writeFile(join(root, "image.png"), "not-a-real-png"),
|
||||
writeFile(
|
||||
join(root, "site.webmanifest"),
|
||||
JSON.stringify({ icons: [{ src: "./icon.svg" }] }),
|
||||
),
|
||||
]);
|
||||
return root;
|
||||
}
|
||||
|
||||
afterEach(async () => {
|
||||
await Promise.all(
|
||||
temporaryDirectories
|
||||
.splice(0)
|
||||
.map((path) => rm(path, { recursive: true, force: true })),
|
||||
);
|
||||
});
|
||||
|
||||
describe("toolbox-check", () => {
|
||||
it("validates files and smoke-fetches nested standalone and context URLs", async () => {
|
||||
const report = await checkToolboxDist(await fixture());
|
||||
|
||||
expect(report.app.id).toBe("de.add-ideas.example");
|
||||
expect(report.checkedFiles).toHaveLength(3);
|
||||
expect(new URL(report.smoke.standaloneUrl).pathname).toBe(
|
||||
"/__toolbox-check__/deep/nested/app/",
|
||||
);
|
||||
expect(
|
||||
new URL(report.smoke.contextualUrl).searchParams.get("toolbox"),
|
||||
).toBe("/toolbox.catalog.json");
|
||||
expect(report.smoke.fetchedUrls).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.stringContaining("/site.webmanifest"),
|
||||
expect.stringContaining("/style.css"),
|
||||
expect.stringContaining("/app.js"),
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects traversal in declared assets", async () => {
|
||||
const root = await fixture(manifest({ assets: ["../secret.txt"] }));
|
||||
await expect(checkToolboxDist(root)).rejects.toThrow(/unsafe path/u);
|
||||
});
|
||||
|
||||
it("rejects a non-SemVer manifest version", async () => {
|
||||
const root = await fixture(manifest({ version: "next" }));
|
||||
await expect(checkToolboxDist(root)).rejects.toThrow(/not SemVer/u);
|
||||
});
|
||||
|
||||
it("rejects root-absolute HTML assets that break nested deployment", async () => {
|
||||
const root = await fixture();
|
||||
await writeFile(
|
||||
join(root, "index.html"),
|
||||
'<!doctype html><script src="/app.js"></script>',
|
||||
);
|
||||
await expect(checkToolboxDist(root)).rejects.toThrow(/not relocatable/u);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user