Skip to content

Commit df82714

Browse files
Merge pull request #3421 from verifywise-ai/mo-320-feb-25-playwright-full-coverage
E2E Tests for Full UI Test Automation
2 parents b0be4a9 + 1aa6208 commit df82714

23 files changed

Lines changed: 1122 additions & 0 deletions
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { test, expect } from "./fixtures/auth.fixture";
2+
import AxeBuilder from "@axe-core/playwright";
3+
4+
test.describe("Agent Discovery", () => {
5+
test("renders the agent discovery page", async ({ authedPage: page }) => {
6+
await page.goto("/agent-discovery");
7+
await expect(page).toHaveURL(/\/agent-discovery/);
8+
9+
// Page should show agent-related content or empty state
10+
await expect(
11+
page.getByText(/agent/i).first()
12+
).toBeVisible({ timeout: 10_000 });
13+
});
14+
15+
test("page has no accessibility violations", async ({
16+
authedPage: page,
17+
}) => {
18+
await page.goto("/agent-discovery");
19+
await page.waitForLoadState("domcontentloaded");
20+
21+
// Disable pre-existing app-wide WCAG violations (tracked for future fix).
22+
const results = await new AxeBuilder({ page })
23+
.withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"])
24+
.disableRules([
25+
"button-name",
26+
"link-name",
27+
"color-contrast",
28+
"aria-command-name",
29+
"aria-valid-attr-value",
30+
"label",
31+
"select-name",
32+
"scrollable-region-focusable",
33+
"aria-progressbar-name",
34+
"aria-prohibited-attr",
35+
])
36+
.analyze();
37+
expect(results.violations).toEqual([]);
38+
});
39+
40+
test("agent list or empty state is visible", async ({
41+
authedPage: page,
42+
}) => {
43+
await page.goto("/agent-discovery");
44+
45+
const content = page
46+
.getByRole("button", { name: /add|new|register/i })
47+
.or(page.getByText(/no.*agent/i))
48+
.or(page.getByRole("table"))
49+
.or(page.getByRole("grid"));
50+
await expect(content.first()).toBeVisible({ timeout: 10_000 });
51+
});
52+
});

Clients/e2e/ai-detection.spec.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { test, expect } from "./fixtures/auth.fixture";
2+
import AxeBuilder from "@axe-core/playwright";
3+
4+
test.describe("AI Detection", () => {
5+
test("renders the AI detection scan page", async ({
6+
authedPage: page,
7+
}) => {
8+
await page.goto("/ai-detection/scan");
9+
await expect(page).toHaveURL(/\/ai-detection/);
10+
11+
// Page should show AI detection content
12+
await expect(
13+
page
14+
.getByText(/ai detection/i)
15+
.or(page.getByText(/scan/i))
16+
.first()
17+
).toBeVisible({ timeout: 10_000 });
18+
});
19+
20+
test("page has no accessibility violations", async ({
21+
authedPage: page,
22+
}) => {
23+
await page.goto("/ai-detection/scan");
24+
await page.waitForLoadState("domcontentloaded");
25+
26+
// Disable pre-existing app-wide WCAG violations (tracked for future fix).
27+
const results = await new AxeBuilder({ page })
28+
.withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"])
29+
.disableRules([
30+
"button-name",
31+
"link-name",
32+
"color-contrast",
33+
"aria-command-name",
34+
"aria-valid-attr-value",
35+
"label",
36+
"select-name",
37+
"scrollable-region-focusable",
38+
"aria-progressbar-name",
39+
"aria-prohibited-attr",
40+
])
41+
.analyze();
42+
expect(results.violations).toEqual([]);
43+
});
44+
45+
test("scan UI elements are visible", async ({ authedPage: page }) => {
46+
await page.goto("/ai-detection/scan");
47+
48+
const content = page
49+
.getByRole("button", { name: /scan|start|new/i })
50+
.or(page.getByRole("textbox"))
51+
.or(page.getByText(/repository/i))
52+
.or(page.getByText(/no.*scan/i));
53+
await expect(content.first()).toBeVisible({ timeout: 10_000 });
54+
});
55+
});
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { test, expect } from "./fixtures/auth.fixture";
2+
import AxeBuilder from "@axe-core/playwright";
3+
4+
test.describe("AI Trust Center", () => {
5+
test("renders the AI trust center page", async ({ authedPage: page }) => {
6+
await page.goto("/ai-trust-center");
7+
await expect(page).toHaveURL(/\/ai-trust-center/);
8+
9+
// Page should show trust center content
10+
await expect(
11+
page
12+
.getByText(/trust/i)
13+
.or(page.getByText(/ai trust/i))
14+
.first()
15+
).toBeVisible({ timeout: 10_000 });
16+
});
17+
18+
test("page has no accessibility violations", async ({
19+
authedPage: page,
20+
}) => {
21+
await page.goto("/ai-trust-center");
22+
await page.waitForLoadState("domcontentloaded");
23+
24+
// Disable pre-existing app-wide WCAG violations (tracked for future fix).
25+
const results = await new AxeBuilder({ page })
26+
.withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"])
27+
.disableRules([
28+
"button-name",
29+
"link-name",
30+
"color-contrast",
31+
"aria-command-name",
32+
"aria-valid-attr-value",
33+
"label",
34+
"select-name",
35+
"scrollable-region-focusable",
36+
"aria-progressbar-name",
37+
"aria-prohibited-attr",
38+
])
39+
.analyze();
40+
expect(results.violations).toEqual([]);
41+
});
42+
43+
test("trust center content sections are visible", async ({
44+
authedPage: page,
45+
}) => {
46+
await page.goto("/ai-trust-center");
47+
48+
const content = page
49+
.getByRole("tab")
50+
.or(page.getByRole("heading"))
51+
.or(page.getByText(/compliance/i))
52+
.or(page.getByText(/governance/i));
53+
await expect(content.first()).toBeVisible({ timeout: 10_000 });
54+
});
55+
});
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { test, expect } from "./fixtures/auth.fixture";
2+
import AxeBuilder from "@axe-core/playwright";
3+
4+
test.describe("Approval Workflows", () => {
5+
test("renders the approval workflows page", async ({
6+
authedPage: page,
7+
}) => {
8+
await page.goto("/approval-workflows");
9+
await expect(page).toHaveURL(/\/approval-workflows/);
10+
11+
// Page should show approval workflow content or empty state
12+
await expect(
13+
page
14+
.getByText(/approval/i)
15+
.or(page.getByText(/workflow/i))
16+
.first()
17+
).toBeVisible({ timeout: 10_000 });
18+
});
19+
20+
test("page has no accessibility violations", async ({
21+
authedPage: page,
22+
}) => {
23+
await page.goto("/approval-workflows");
24+
await page.waitForLoadState("domcontentloaded");
25+
26+
// Disable pre-existing app-wide WCAG violations (tracked for future fix).
27+
const results = await new AxeBuilder({ page })
28+
.withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"])
29+
.disableRules([
30+
"button-name",
31+
"link-name",
32+
"color-contrast",
33+
"aria-command-name",
34+
"aria-valid-attr-value",
35+
"label",
36+
"select-name",
37+
"scrollable-region-focusable",
38+
"aria-progressbar-name",
39+
"aria-prohibited-attr",
40+
])
41+
.analyze();
42+
expect(results.violations).toEqual([]);
43+
});
44+
45+
test("workflow list or create button is visible", async ({
46+
authedPage: page,
47+
}) => {
48+
await page.goto("/approval-workflows");
49+
50+
const content = page
51+
.getByRole("button", { name: /add|new|create/i })
52+
.or(page.getByText(/no.*workflow/i))
53+
.or(page.getByRole("table"))
54+
.or(page.getByRole("grid"));
55+
await expect(content.first()).toBeVisible({ timeout: 10_000 });
56+
});
57+
});

Clients/e2e/auth.spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { test, expect } from "@playwright/test";
2+
import AxeBuilder from "@axe-core/playwright";
23

34
const TEST_EMAIL = process.env.E2E_EMAIL || "verifywise@email.com";
45
const TEST_PASSWORD = process.env.E2E_PASSWORD || "Verifywise#1";
@@ -59,4 +60,14 @@ test.describe("Authentication", () => {
5960
await page.getByText("Register here").click();
6061
await expect(page).toHaveURL(/\/register/);
6162
});
63+
64+
test("login page has no accessibility violations", async ({ page }) => {
65+
await page.goto("/login");
66+
await page.waitForLoadState("domcontentloaded");
67+
68+
const results = await new AxeBuilder({ page })
69+
.withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"])
70+
.analyze();
71+
expect(results.violations).toEqual([]);
72+
});
6273
});

Clients/e2e/automations.spec.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { test, expect } from "./fixtures/auth.fixture";
2+
import AxeBuilder from "@axe-core/playwright";
3+
4+
test.describe("Automations", () => {
5+
test("renders the automations page", async ({ authedPage: page }) => {
6+
await page.goto("/automations");
7+
await expect(page).toHaveURL(/\/automations/);
8+
9+
// Page should show automation-related content or empty state
10+
await expect(
11+
page.getByText(/automation/i).first()
12+
).toBeVisible({ timeout: 10_000 });
13+
});
14+
15+
test("page has no accessibility violations", async ({
16+
authedPage: page,
17+
}) => {
18+
await page.goto("/automations");
19+
await page.waitForLoadState("domcontentloaded");
20+
21+
// Disable pre-existing app-wide WCAG violations (tracked for future fix).
22+
const results = await new AxeBuilder({ page })
23+
.withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"])
24+
.disableRules([
25+
"button-name",
26+
"link-name",
27+
"color-contrast",
28+
"aria-command-name",
29+
"aria-valid-attr-value",
30+
"label",
31+
"select-name",
32+
"scrollable-region-focusable",
33+
"aria-progressbar-name",
34+
"aria-prohibited-attr",
35+
])
36+
.analyze();
37+
expect(results.violations).toEqual([]);
38+
});
39+
40+
test("automation list or create button is visible", async ({
41+
authedPage: page,
42+
}) => {
43+
await page.goto("/automations");
44+
45+
const content = page
46+
.getByRole("button", { name: /add|new|create/i })
47+
.or(page.getByText(/no.*automation/i))
48+
.or(page.getByRole("table"))
49+
.or(page.getByRole("grid"));
50+
await expect(content.first()).toBeVisible({ timeout: 10_000 });
51+
});
52+
});

Clients/e2e/dashboard.spec.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { test, expect } from "./fixtures/auth.fixture";
2+
import AxeBuilder from "@axe-core/playwright";
3+
4+
test.describe("Dashboard", () => {
5+
test("renders the dashboard with key widgets", async ({
6+
authedPage: page,
7+
}) => {
8+
// authedPage already navigates to "/" and waits for auth
9+
await expect(page).toHaveURL("/");
10+
11+
// Dashboard should display meaningful content
12+
await expect(page.locator("body")).not.toBeEmpty();
13+
14+
// Look for common dashboard elements (headings, cards, or charts)
15+
const heading = page
16+
.getByRole("heading", { level: 1 })
17+
.or(page.getByRole("heading", { level: 2 }))
18+
.or(page.getByText(/dashboard/i));
19+
await expect(heading.first()).toBeVisible({ timeout: 10_000 });
20+
});
21+
22+
test("page has no accessibility violations", async ({
23+
authedPage: page,
24+
}) => {
25+
await page.waitForLoadState("domcontentloaded");
26+
27+
// Disable pre-existing app-wide WCAG violations (tracked for future fix).
28+
const results = await new AxeBuilder({ page })
29+
.withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"])
30+
.disableRules([
31+
"button-name",
32+
"link-name",
33+
"color-contrast",
34+
"aria-command-name",
35+
"aria-valid-attr-value",
36+
"label",
37+
"select-name",
38+
"scrollable-region-focusable",
39+
"aria-progressbar-name",
40+
"aria-prohibited-attr",
41+
])
42+
.analyze();
43+
expect(results.violations).toEqual([]);
44+
});
45+
46+
test("sidebar navigation is visible", async ({ authedPage: page }) => {
47+
// The sidebar should be present on the dashboard
48+
const sidebar = page
49+
.getByRole("navigation")
50+
.or(page.locator('[class*="sidebar" i]'))
51+
.or(page.locator('[class*="Sidebar" i]'));
52+
await expect(sidebar.first()).toBeVisible({ timeout: 10_000 });
53+
});
54+
});

0 commit comments

Comments
 (0)