"Look Dave, I can see you're really upset about this. I honestly think you ought to sit down calmly, take a stress pill, and think things over." — HAL 9000, 2001: A Space Odyssey
Named after astronaut Dave Bowman, the only one who could keep HAL in check. In the same spirit, dave keeps an eye on halOP — the WildFly management console — making sure it behaves as expected.
UI test suite for halOP, the WildFly management console. Built with Playwright and TypeScript.
dave automatically starts a WildFly server and halOP container, runs end-to-end tests against the management console, and tears everything down when finished.
- Node.js 22+
- pnpm (corepack-enabled, see
packageManagerinpackage.json) - Podman or Docker — runs WildFly and halOP containers (auto-detected)
# Install dependencies
pnpm install
# Install Playwright browsers
pnpm exec playwright install chromium firefox webkit
# Run all tests (headless)
pnpm test| Command | Description |
|---|---|
pnpm test |
Run all tests headless (all browsers) |
pnpm test:headed |
Run with a visible browser window |
pnpm test:ui |
Playwright interactive UI mode |
pnpm test:debug |
Debug mode with Playwright inspector |
pnpm report |
Open the last HTML test report |
pnpm allure:generate |
Generate Allure report from results |
pnpm allure:serve |
Serve Allure report with live reload |
pnpm allure:open |
Open a generated Allure report |
pnpm test:smoke |
Run only @smoke tests |
pnpm test:dashboard |
Run only @dashboard tests |
pnpm test:navigation |
Run only @navigation tests |
pnpm test:model-browser |
Run only @model-browser tests |
Filter tests by pattern, file, or browser:
pnpm test -- --grep "dashboard"
pnpm test -- src/tests/smoke/app-loads.spec.ts
pnpm test -- --project=chromium
pnpm test -- --project=firefox
pnpm test -- --project=webkitTests are tagged by feature area using Playwright's tag API. Tags are defined as typed constants in src/tags.ts.
| Tag | Group | Test Files |
|---|---|---|
@smoke |
Smoke tests | app-loads, dashboard, navigation |
@dashboard |
Dashboard feature | dashboard |
@navigation |
Navigation feature | navigation |
@model-browser |
Model browser feature | model-browser |
Tests can belong to multiple groups. Combine groups with OR logic:
pnpm test -- --grep "@smoke|@model-browser"Exclude a group:
pnpm test -- --grep-invert @smokeTags are displayed as badges in the HTML test report and can be used to filter results.
To add a new group, add a constant to src/tags.ts and apply it to test files via the tag option on test.describe().
Environment variables can be set in a .env file (see .env.example):
| Variable | Default | Description |
|---|---|---|
WILDFLY_IMAGE |
quay.io/wado/wado-sa:development |
WildFly container image |
HALOP_IMAGE |
quay.io/halconsole/hal-op:test-suite |
halOP container image |
HALOP_PORT |
9090 |
Host port mapped to the halOP container |
| Image | Description |
|---|---|
quay.io/halconsole/hal-op:test-suite |
halOP image used by the test suite |
quay.io/wado/wado-sa:development |
WildFly image used for test containers |
| Project | Description |
|---|---|
| halOP | WildFly management console (the application under test) |
| WildFly | The application server managed by halOP |
| testcontainers | Container management for integration tests |
global-setup.ts starts halOP container
writes state to /tmp/dave-state.json
sets HALOP_URL env var
worker-scoped fixture starts a WildFly container per worker
(via testcontainers)
src/fixtures/wildfly.fixture.ts WildFly container lifecycle (worker-scoped)
src/fixtures/pages.fixture.ts enables OUIA, navigates to halOP, creates page objects
src/tests/**/*.spec.ts test execution
worker teardown stops the WildFly container
global-teardown.ts stops halOP container, cleans state file
Spec files run in parallel across multiple workers (4 locally, 2 in CI). Tests within a spec file are sequential. Each test file gets its own isolated WildFly container per browser project via a worker-scoped Playwright fixture backed by testcontainers. Tests run in Chromium, Firefox, and WebKit.
WildFly containers are managed by a worker-scoped Playwright fixture defined in src/fixtures/wildfly.fixture.ts. Spec files that need WildFly and page objects import test from pages.fixture.ts and declare their spec path:
import { test, expect } from "../../fixtures/pages.fixture.js";
test.use({ specPath: "smoke/dashboard" });The fixture starts a container before any test in the worker runs and stops it after the last test finishes. Container names follow the pattern dave_<path>_<project> (e.g., dave_smoke_dashboard_chromium). Ports are dynamically allocated.
Spec files that don't need WildFly (e.g., app-loads.spec.ts) import test and expect from wildfly.fixture.ts.
Custom Playwright fixtures in src/fixtures/pages.fixture.ts provide page objects to each test. Page objects are pure UI concerns (locators and actions) — they don't know about WildFly URLs or infrastructure. The fixture layer handles navigation via openHalOp(page, managementUrl) before handing each page object to the test, so tests receive ready-to-use pages:
| Fixture | Purpose |
|---|---|
basePage |
Base page with shared page accessor |
dashboardPage |
Dashboard heading assertions |
modelBrowserPage |
Model browser tree and resource assertions |
navigationPage |
Sidebar navigation (Dashboard, Deployments, Configuration, Runtime, etc.) |
Tests import test and expect from ../fixtures/pages.fixture instead of @playwright/test.
Tests use OUIA attributes for element selection, following PatternFly's testing conventions. The OUIA component IDs defined in halOP are collected and published as the @halconsole/ouia npm package, which dave consumes to reference UI elements by stable, well-known identifiers.
-
Create
src/pages/foo.page.tsextendingBasePage:import type { Page } from "@playwright/test"; import { BasePage } from "./base.page.js"; export class FooPage extends BasePage { constructor(page: Page) { super(page); } }
-
Register the fixture in
src/fixtures/pages.fixture.ts— add the import, the interface entry, and the fixture:import { FooPage } from "../pages/foo.page.js"; interface PageFixtures { // ...existing entries... fooPage: FooPage; } export const test = testWithWildFly.extend<PageFixtures>({ // ...existing entries... fooPage: async ({ page, wildfly }, use) => { await openHalOp(page, wildfly.managementUrl); await use(new FooPage(page)); }, });
No other files need to change. OUIA enablement and navigation are handled by pages.fixture.ts, WildFly container lifecycle by wildfly.fixture.ts.
Create a spec file under src/tests/ and import from the appropriate fixture:
-
With WildFly + page objects — import from
pages.fixture.ts:import { test, expect } from "../../fixtures/pages.fixture.js"; import { Tag } from "../../tags.js"; test.use({ specPath: "category/foo" }); test.describe("Foo", { tag: [Tag.SMOKE] }, () => { test("does something", async ({ fooPage }) => { // page is already navigated — start asserting... }); });
-
Without WildFly — import from
wildfly.fixture.ts:import { test, expect } from "../../fixtures/wildfly.fixture.js";
To add a new test group, add a constant to src/tags.ts and optionally a pnpm script to package.json.
dave/
global-setup.ts # Start halOP before tests
global-teardown.ts # Stop halOP after tests
playwright.config.ts # Playwright configuration
src/
fixtures/
wildfly.fixture.ts # WildFly container lifecycle (worker-scoped)
pages.fixture.ts # OUIA enablement, navigation, page object registry
pages/
base.page.ts # Base page object
dashboard.page.ts # Dashboard page object
model-browser.page.ts # Model browser page object
navigation.page.ts # Navigation page object
tags.ts # Tag constants for test grouping
tests/
smoke/ # Smoke tests
app-loads.spec.ts
dashboard.spec.ts
navigation.spec.ts
model-browser/ # Model browser tests
model-browser.spec.ts
utils/
configure-testcontainers.ts # Testcontainers config
container-runtime.ts # Auto-detect Podman or Docker
ouia.ts # OUIA attribute selector helper
wildfly-container.ts # WildFly container lifecycle
| Command | Description |
|---|---|
pnpm lint |
Run ESLint |
pnpm lint:fix |
Run ESLint with auto-fix |
pnpm format |
Format all files with Prettier |
pnpm format:check |
Check formatting without changing |
ESLint is configured with TypeScript and Playwright-specific rules. Prettier handles all formatting. See eslint.config.js and .prettierrc for details.
GitHub Actions workflows in .github/workflows/:
| Workflow | Trigger | What it does |
|---|---|---|
| Lint | Push / PR to main |
Checks formatting (Prettier) and linting (ESLint) |
| Smoke | Push / PR to main |
Runs @smoke tests in Chromium only — fast pass/fail gate, no reports |
| Test | Push to main (path-filtered), daily at 05:00 UTC, manual |
Full suite across Chromium, Firefox, and WebKit; uploads artifacts and deploys reports to GitHub Pages |
The Test workflow only triggers on pushes to main that change test or config files (src/**, playwright.config.ts, global-setup.ts, global-teardown.ts, package.json, pnpm-lock.yaml). A daily schedule catches regressions from upstream WildFly or halOP image changes. It can also be triggered manually via workflow_dispatch.
The latest test reports from main are published to GitHub Pages:
- Allure report — includes trend charts that track pass/fail rates across runs
- Playwright report — built-in Playwright HTML report
Dependency updates are managed by Dependabot, configured for weekly npm and GitHub Actions updates.