Files
openwork/evals/specs/testkit-app-boot.e2e.test.ts

76 lines
2.9 KiB
TypeScript

import { createServer } from "node:net";
import { readFile } from "node:fs/promises";
import { join } from "node:path";
import { expect } from "vitest";
import { screenshot, validate } from "@openwork/test-evidence";
import { expectVisualEvidence } from "@openwork/test-evidence/vitest";
import { app, localMysqlIsRunning, needs, server, test } from "@openwork/testkit";
const expectation = "The OpenWork workspace shell is visible and ready for a task";
const e2eTestsEnabled = process.env.OPENWORK_EVAL_E2E_TESTS === "1";
const localPlacement = process.env.OPENWORK_EVAL_DAYTONA !== "1" && !process.env.OPENWORK_EVAL_DEN_API_URL?.trim();
const mysqlOpen = await localMysqlIsRunning();
const title = !e2eTestsEnabled
? "testkit app boot skipped — needs: set OPENWORK_EVAL_E2E_TESTS=1"
: !localPlacement
? "testkit app boot skipped — needs local placement without OPENWORK_EVAL_DEN_API_URL"
: !mysqlOpen
? "testkit app boot skipped — needs MySQL on 127.0.0.1:3306"
: "testkit boots a local Den and signed-in app with ambient evidence";
async function portCanBind(port: number): Promise<boolean> {
return new Promise((resolve) => {
const probe = createServer();
probe.once("error", () => resolve(false));
probe.listen(port, "127.0.0.1", () => probe.close(() => resolve(true)));
});
}
test.skipIf(!e2eTestsEnabled || !localPlacement || !mysqlOpen)(title, async ({ evidence, place }) => {
needs({ optIn: ["OPENWORK_EVAL_E2E_TESTS"] });
let apiPort = 0;
let webPort = 0;
{
await using den = await server({ place });
expect(den.ports).toBeDefined();
if (!den.ports) throw new Error("The local testkit Den did not expose its ports.");
apiPort = den.ports.api;
webPort = den.ports.web;
await using desktopApp = await app({ den, as: "admin", place });
const shot = await screenshot(desktopApp);
const seen = await validate(shot, [expectation], {
ask: async (request) => request.prompt.startsWith("Objectively describe")
? JSON.stringify({ description: "An OpenWork workspace shell with navigation and a task composer." })
: JSON.stringify({
results: [{
expectation,
passed: true,
evidence: "The workspace navigation and task composer are visible.",
}],
}),
});
expectVisualEvidence(seen);
}
expect(await portCanBind(apiPort)).toBe(true);
expect(await portCanBind(webPort)).toBe(true);
await evidence.close();
const testRun: unknown = JSON.parse(await readFile(join(evidence.dir, "test-run.json"), "utf8"));
expect(testRun).toMatchObject({
summary: {
ok: true,
totalArtifacts: 1,
passedArtifacts: 1,
unvalidatedArtifacts: 0,
},
artifacts: [{
caption: expectation,
fileName: expect.stringMatching(/\.png$/),
hash: expect.stringMatching(/^[a-f0-9]{64}$/),
ok: true,
}],
});
});