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
9 changes: 7 additions & 2 deletions .github/workflows/frontend_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,12 @@ jobs:
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium

- name: Run E2E tests (mock mode — no backend/secrets needed)
run: npx playwright test --project=mock
- name: Run E2E tests (mock and seeded — no credentials needed)
run: npx playwright test --fail-on-flaky-tests --project=mock --project=seeded
env:
CI: true
E2E_SEEDED_MODE: true
FAIL_ON_SKIPPED_TESTS: true

- name: Upload Playwright report
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
Expand Down Expand Up @@ -150,3 +152,6 @@ jobs:

- name: Run TypeScript type check
run: npx tsc --noEmit

- name: Build production frontend
run: npm run build
8 changes: 4 additions & 4 deletions frontend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,20 +91,20 @@ E2E flow tests run in two modes controlled by Playwright projects and an environ

- **Seeded** (`--project seeded`, default for CI): Messages are stored directly in the database with `send: false` using dummy credentials. No real API keys needed. Tests cover the full UI flow (display, branching, conversation switching, promoting) without calling any external service.

- **Live** (`--project live`, requires `E2E_LIVE_MODE=true`): Messages are sent to real OpenAI endpoints with `send: true`. Each target variant requires its own set of environment variables (e.g., `OPENAI_CHAT_ENDPOINT`, `OPENAI_CHAT_KEY`, `OPENAI_CHAT_MODEL`). Variants whose env vars are missing are automatically skipped. Tests verify that real target responses render correctly.
- **Live** (`--project live`, requires `E2E_LIVE_MODE=true`): Messages are sent to real OpenAI endpoints with `send: true`. Each target variant requires endpoint and model environment variables plus either an API key or an Azure endpoint accessible through the current Entra identity. Variants without a usable configuration are automatically skipped. Tests verify that real target responses render correctly.

```bash
# CI (seeded only — no credentials needed)
# Seeded integration (no credentials needed)
npx playwright test --project seeded

# Live integration (requires real API keys)
# Live integration (uses API keys when present, otherwise Entra authentication)
E2E_LIVE_MODE=true npx playwright test --project live

# Run both
E2E_LIVE_MODE=true npx playwright test
```

The seeded project runs in the **GitHub Actions** workflow. The live project is intended for an **Azure DevOps pipeline** that has the required secret API keys.
The mock and seeded projects run in the **GitHub Actions** pull-request workflow. The live project is intended for a protected pipeline with an Entra identity or API keys.

E2E tests use `dev.py` to automatically start both frontend and backend servers. If servers are already running, they will be reused.

Expand Down
24 changes: 9 additions & 15 deletions frontend/e2e/api.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { test, expect } from "@playwright/test";

// API tests go through the Vite dev server proxy (/api -> backend:8000)
// API tests go through the Vite dev server proxy (/api -> configured backend)
// rather than hitting the backend directly, so they work as soon as
// Playwright's webServer (port 3000) is ready.

Expand Down Expand Up @@ -68,26 +68,26 @@ test.describe("Targets API", () => {
});

test("should create and retrieve a target @seeded", async ({ request }) => {
test.setTimeout(90_000);
const createPayload = {
type: "OpenAIChatTarget",
auth_mode: "api_key",
params: {
endpoint: "https://e2e-test.openai.azure.com",
model_name: "gpt-4o-e2e-test",
api_key: "e2e-test-key",
},
};

const createResp = await request.post("/api/targets", { data: createPayload });
// The endpoint may require credentials or env setup that isn't available
// in CI. Skip gracefully rather than masking real regressions.
if (!createResp.ok()) {
test.skip(true, `POST /api/targets returned ${createResp.status()} — skipping`);
return;
}
const createResp = await request.post("/api/targets", {
data: createPayload,
timeout: 60_000,
});
expect(createResp.ok()).toBe(true);

const created = await createResp.json();
expect(created).toHaveProperty("target_registry_name");
expect(created.target_type).toBe("OpenAIChatTarget");
expect(created.identifier.class_name).toBe("OpenAIChatTarget");

// Retrieve via list and check it's there
const listResp = await request.get("/api/targets?limit=200");
Expand Down Expand Up @@ -120,12 +120,6 @@ test.describe("Attacks API", () => {

test("should list attacks @seeded", async ({ request }) => {
const response = await request.get("/api/attacks");
// Backend may return 500 due to stale DB schema or 404 if not implemented.
// Only assert when the endpoint is actually healthy.
if (!response.ok()) {
test.skip(true, `GET /api/attacks returned ${response.status()} — skipping`);
return;
}
expect(response.ok()).toBe(true);
});
});
Expand Down
3 changes: 1 addition & 2 deletions frontend/e2e/chat.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -500,8 +500,7 @@ test.describe("Multi-modal: Video response", () => {
},
]);

// Marking skipped for now because this should not use the getByRole query which is too general
test.skip("should display video player for video response", async ({ page }) => {
test("should display video player for video response", async ({ page }) => {
await setupVideoMock(page);
await page.goto("/");
await activateMockTarget(page);
Expand Down
Loading
Loading