Files
saltbo__agent-kanban/playwright.isolated.config.ts
realmroot[bot] 96fdd70d2c feat(api)!: redesign task resource operations (#265)
* feat(api)!: redesign task resource operations

Publish the complete resource-oriented OpenAPI contract, enforce scope-based authorization at the HTTP boundary, and replace lifecycle command routes with Task PATCH and nested Claim/Event resources.

Add server-side Task CAS, migration coverage, updated Agent Skills, and browser/API regression tests.

BREAKING CHANGE: remove the legacy task lifecycle endpoints and move bounded waits to /tasks/{taskId}/events.

* refactor(tasks)!: make claims create-only

Remove Task Claim retrieval and deletion routes, the release scope, live deletion logic, and release workflow guidance.

Keep historical release records readable for migration and audit compatibility.

BREAKING CHANGE: remove GET and DELETE /tasks/{taskId}/claims/{claimId} and the task:release scope.

* test(ci): align actor and projection contracts

Cover machine and service Task Action writes and update Agent detail fixtures to the canonical assignedTo query and paged lowerCamelCase response.

* fix(api): preserve merge patch fields and consume browser pagination

* test(ui): include terminal pagination in agent task fixture

---------

Co-authored-by: jarvis <jarvis@agents.realmroot.dev>
2026-09-05 02:40:42 +00:00

64 lines
2.5 KiB
TypeScript

import { mkdtempSync, writeFileSync } from "node:fs";
import { createServer } from "node:net";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { defineConfig, devices } from "@playwright/test";
if (!process.env.AK_E2E_PORT) {
const socket = createServer();
await new Promise<void>((resolve) => socket.listen(0, "127.0.0.1", resolve));
const address = socket.address();
if (!address || typeof address === "string") throw new Error("Failed to allocate E2E port");
process.env.AK_E2E_PORT = String(address.port);
await new Promise<void>((resolve, reject) => socket.close((error) => (error ? reject(error) : resolve())));
}
const port = Number(process.env.AK_E2E_PORT);
const stateDir = process.env.AK_E2E_STATE_DIR ?? mkdtempSync(join(tmpdir(), "ak-e2e-"));
process.env.AK_E2E_STATE_DIR = stateDir;
const baseURL = `http://localhost:${port}`;
const wranglerConfig = join(stateDir, "wrangler.json");
writeFileSync(
wranglerConfig,
JSON.stringify({
name: "agent-kanban-e2e",
main: join(import.meta.dirname, "server/worker/index.ts"),
compatibility_date: "2026-04-13",
compatibility_flags: ["nodejs_compat"],
assets: { binding: "ASSETS", not_found_handling: "single-page-application" },
vars: {
AK_PUBLIC_ORIGIN: baseURL,
OIDC_ISSUER: "https://issuer.example.test",
OIDC_WEB_CLIENT_ID: "ak-e2e",
OIDC_WEB_CLIENT_SECRET: "local-test-only",
AK_SESSION_ENCRYPTION_KEY: Buffer.from("01234567890123456789012345678901").toString("base64"),
AK_SIGNING_KEY: Buffer.from("01234567890123456789012345678901").toString("base64"),
AGENCY_ORIGIN: "https://agency.example.test",
},
d1_databases: [{ binding: "DB", database_name: "agent-kanban-e2e", database_id: "13cdf435-a99c-4744-9eca-9ed22b232581" }],
}),
);
export default defineConfig({
testDir: "./tests/e2e",
testMatch: "**/*.spec.ts",
forbidOnly: !!process.env.CI,
retries: 0,
workers: 1,
reporter: "list",
globalTeardown: "./tests/e2e/support/cleanup.ts",
use: { baseURL, trace: "retain-on-failure", screenshot: "only-on-failure" },
projects: [{ name: "chromium", use: { ...devices["Desktop Chrome"] } }],
webServer: {
command: `pnpm exec tsx tests/e2e/support/migrate.ts && pnpm exec vite dev --config vite.e2e.config.ts --port ${port}`,
url: baseURL,
reuseExistingServer: false,
env: {
AK_E2E_STATE_DIR: stateDir,
AK_E2E_WRANGLER_CONFIG: wranglerConfig,
VITE_DEV_PORT: String(port),
CLOUDFLARE_LOAD_DEV_VARS_FROM_DOT_ENV: "false",
},
timeout: 120_000,
},
});