Test CI job results end to end

Build rad-job from the radicle-job version the app uses, so tests can
record runs. Check the status summary and that runs link to their logs.
This commit is contained in:
Rūdolfs Ošiņš
2026-10-01 18:20:25 +02:00
parent 49cf789cbc
commit 1f95ad0bb2
3 changed files with 90 additions and 0 deletions
+80
View File
@@ -0,0 +1,80 @@
import type { RadiclePeer } from "@tests/support/peerManager.js";
import { expect, test } from "@tests/support/fixtures.js";
import { createRepo } from "@tests/support/repo.js";
import { radJobBinary } from "@tests/support/support.js";
async function recordRun(
peer: RadiclePeer,
repoFolder: string,
head: string,
log: string,
outcome: "succeeded" | "failed" | "started",
) {
const job = (args: string[]) =>
peer.spawn(radJobBinary, ["--no-sync", ...args], { cwd: repoFolder });
const { stdout: runId } = await job(["run", head, log]);
if (outcome !== "started") {
await job([outcome, head, runId.trim()]);
}
}
test("CI runs are summarised and link to their logs", async ({
page,
peer,
}) => {
const { rid, repoFolder } = await createRepo(peer, { name: "ci" });
const { stdout: head } = await peer.git(["rev-parse", "HEAD"], {
cwd: repoFolder,
});
await peer.spawn(radJobBinary, ["--no-sync", "new", head.trim()], {
cwd: repoFolder,
});
await recordRun(
peer,
repoFolder,
head.trim(),
"https://ci.example.com/runs/passing",
"succeeded",
);
await recordRun(
peer,
repoFolder,
head.trim(),
"https://github.com/o/r/actions/runs/12345/job/1",
"failed",
);
await page.goto(`/repos/${rid}/home`);
const summary = page.getByRole("button", { name: /1 passed · 1 failed/ });
await expect(summary).toBeVisible();
await summary.click();
await expect(page.getByRole("link", { name: /run 12345/ })).toHaveAttribute(
"href",
"https://github.com/o/r/actions/runs/12345/job/1",
);
await expect(
page.locator('a[href="https://ci.example.com/runs/passing"]'),
).toBeVisible();
});
test("a running job is shown as running", async ({ page, peer }) => {
const { rid, repoFolder } = await createRepo(peer, { name: "ci" });
const { stdout: head } = await peer.git(["rev-parse", "HEAD"], {
cwd: repoFolder,
});
await peer.spawn(radJobBinary, ["--no-sync", "new", head.trim()], {
cwd: repoFolder,
});
await recordRun(
peer,
repoFolder,
head.trim(),
"https://ci.example.com/runs/slow",
"started",
);
await page.goto(`/repos/${rid}/home`);
await expect(page.getByRole("button", { name: /1 running/ })).toBeVisible();
});
+2
View File
@@ -50,6 +50,8 @@ export default async function globalSetup(): Promise<() => void> {
"--manifest-path",
"./crates/test-http-api/Cargo.toml",
]);
// The job COB CLI, at the version of radicle-job the app is built with.
await execa("cargo", ["build", "-p", "radicle-job", "--bin", "rad-job"]);
// Keeps test keys out of the developer's ssh-agent.
delete process.env.SSH_AUTH_SOCK;
+8
View File
@@ -31,6 +31,14 @@ export const testHttpApiBinary = Path.resolve(
"debug",
"test-http-api",
);
export const radJobBinary = Path.resolve(
supportDir,
"../..",
process.env.CARGO_TARGET_DIR ?? "target",
"debug",
"rad-job",
);
const workspacePaths = [Path.join(tmpDir, "peers"), Path.join(tmpDir, "repos")];
export const heartwoodRelease = (