Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 11 additions & 11 deletions rivet-core/src/junit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,17 +250,17 @@ fn parse_suites(xml: &str) -> Result<Vec<ParsedSuite>, Error> {
}
}

Ok(Event::Text(ref e)) => {
if text_ctx == TextContext::Failure || text_ctx == TextContext::Error {
if let Some(ref mut c) = current_case {
if c.body.is_none() {
let text = e
.unescape()
.map(|s| s.trim().to_string())
.unwrap_or_default();
if !text.is_empty() {
c.body = Some(text);
}
Ok(Event::Text(ref e))
if text_ctx == TextContext::Failure || text_ctx == TextContext::Error =>
{
if let Some(ref mut c) = current_case {
if c.body.is_none() {
let text = e
.unescape()
.map(|s| s.trim().to_string())
.unwrap_or_default();
if !text.is_empty() {
c.body = Some(text);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/playwright/api.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ test.describe("API v1: Artifacts — Grafana table data", () => {

const art = data.artifacts[0];
expect(art.id).toBeTruthy();
expect(art.title).toBeTruthy();
// Title may be empty for some types (e.g., control-actions use name/action)
expect(art.type).toBeTruthy();
expect(art.origin).toBe("local");
expect(typeof art.links_out).toBe("number");
Expand Down
3 changes: 2 additions & 1 deletion tests/playwright/audit-regression.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ test.describe("Audit Regression: Consistency", () => {
});

test("every page returns 200", async ({ page }) => {
test.setTimeout(180_000);
const pages = [
"/",
"/artifacts",
Expand All @@ -167,7 +168,7 @@ test.describe("Audit Regression: Consistency", () => {
"/help",
];
for (const path of pages) {
const resp = await page.request.get(path);
const resp = await page.request.get(path, { timeout: 90_000 });
expect(resp.status(), `${path} should return 200`).toBe(200);
}
});
Expand Down
18 changes: 10 additions & 8 deletions tests/playwright/coverage-view.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,17 @@ test.describe("Coverage View", () => {
test("shows coverage table with rule details", async ({ page }) => {
await page.goto("/coverage");
await waitForHtmx(page);
const table = page.locator("table");
const tableCount = await table.count();
const tables = page.locator("table");
const tableCount = await tables.count();
if (tableCount === 0) {
// No traceability rules defined — the card message should explain
await expect(page.locator("body")).toContainText(
"No traceability rules",
);
return;
}
// Use first table — the coverage rules table
const table = tables.first();
// Table should have expected columns
await expect(table.locator("thead")).toContainText("Rule");
await expect(table.locator("thead")).toContainText("Source Type");
Expand All @@ -44,23 +46,23 @@ test.describe("Coverage View", () => {
test("coverage bars have progress indicators", async ({ page }) => {
await page.goto("/coverage");
await waitForHtmx(page);
const table = page.locator("table");
const tableCount = await table.count();
const tables = page.locator("table");
const tableCount = await tables.count();
if (tableCount === 0) {
test.skip();
return;
}
// Each row should have a progress bar div
const rows = page.locator("table tbody tr");
// Each row in the first table should have a progress bar div
const rows = tables.first().locator("tbody tr");
const rowCount = await rows.count();
expect(rowCount).toBeGreaterThan(0);
});

test("coverage badges link to artifact types", async ({ page }) => {
await page.goto("/coverage");
await waitForHtmx(page);
const table = page.locator("table");
const tableCount = await table.count();
const tables = page.locator("table");
const tableCount = await tables.count();
if (tableCount === 0) {
test.skip();
return;
Expand Down
3 changes: 2 additions & 1 deletion tests/playwright/graph.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ test.describe("Graph View", () => {
});

test("node budget prevents crash on full graph", async ({ page }) => {
test.setTimeout(120_000);
await page.goto("/graph");
await waitForHtmx(page);
// Should render without timeout — either SVG or budget message
const content = page.locator("svg, :text('budget')");
await expect(content.first()).toBeVisible({ timeout: 30_000 });
await expect(content.first()).toBeVisible({ timeout: 60_000 });
});

test("graph controls are visible", async ({ page }) => {
Expand Down
4 changes: 2 additions & 2 deletions tests/playwright/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Page, expect } from "@playwright/test";

/** Wait for HTMX to finish all pending requests. */
export async function waitForHtmx(page: Page) {
export async function waitForHtmx(page: Page, timeout = 10_000) {
await page.waitForFunction(
() => !document.querySelector(".htmx-request"),
{ timeout: 10_000 },
{ timeout },
);
}

Expand Down
4 changes: 3 additions & 1 deletion tests/playwright/navigation.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@ test.describe("Navigation", () => {
});

test("all major nav links are reachable via direct URL", async ({ page }) => {
test.setTimeout(120_000);
// Test via direct URL access (more reliable than HTMX click)
const routes = ["/artifacts", "/validate", "/matrix", "/graph", "/coverage"];
for (const route of routes) {
const response = await page.goto(route);
const response = await page.goto(route, { timeout: 90_000 });
expect(response?.status()).toBe(200);
}
});

test("direct URL access works without redirect loop", async ({ page }) => {
test.setTimeout(60_000);
await page.goto("/artifacts");
await expect(page.locator("table")).toBeVisible();
await page.goto("/stpa");
Expand Down
3 changes: 2 additions & 1 deletion tests/playwright/print-and-errors.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,11 @@ test.describe("Console Error Hygiene", () => {

for (const path of pagesToCheck) {
test(`no JS errors on ${path}`, async ({ page }) => {
test.setTimeout(120_000);
const errors: string[] = [];
page.on("pageerror", (err) => errors.push(err.message));

await page.goto(path);
await page.goto(path, { timeout: 90_000 });
await waitForHtmx(page);
await page.waitForLoadState("networkidle");

Expand Down
3 changes: 2 additions & 1 deletion tests/playwright/self-contained.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ test.describe("Self-contained assets (no CDN)", () => {
});

test("clicking multiple nav links navigates correctly", async ({ page }) => {
test.setTimeout(120_000);
await page.goto("/");
await waitForHtmx(page);

Expand All @@ -109,7 +110,7 @@ test.describe("Self-contained assets (no CDN)", () => {

for (const { selector, path } of routes) {
await page.click(selector);
await waitForHtmx(page);
await waitForHtmx(page, 60_000);
const url = new URL(page.url());
expect(url.pathname).toBe(path);
expect(url.hash).toBe("");
Expand Down
Loading