Skip to content

Automation, Devkit & E2E

A platform that asks teams to self-serve only works if it gives them fast feedback on whether they did it right. None of the mechanisms below gate a developer’s work — they give a “here’s what’s wrong, here’s the exact command to fix it” surface instead.

For why Playwright (and which AI-assisted tools were considered), see ADR 0007 — Adopt Playwright for E2E.

Run on demand or invoked by whisker dev. Implemented as pure functions that return { id, status: 'ok'|'warn'|'fail', detail, remediation? }, so the same engine can eventually drive both the CLI and a future live UI. The check count varies per project (shared-package placement and port checks scale with config), but covers:

Check Fails because
Node version Installed Node < required floor (24+)
BFF URLs (declared + effective, test/prod) Empty config, or surfaces a developer’s VITE_BFF_URL override
Host path / host package.json whisker-host not resolvable (via WHISKER_HOST_PATH or a sibling directory), or the resolved directory has no package.json
Host script contract whisker:prep / whisker:rebuild-loader / whisker:restore missing — the host is too old for the kit’s orchestration
Shared-package placement A host-shared package (per module-federation.config.ts#shared) found in dependencies instead of devDependencies, or missing entirely
Port availability A configured port is in use — prints the lsof kill command
BFF reachability HEAD request fails — often “you need VPN”

Doctor is iframe-aware: for iframe consumers, the host-script-contract checks are skipped. The worst status across all checks sets the exit code so CI can gate on it if a team chooses.

Every scaffold wires pre-commit and post-commit hooks to the kit:

.husky/pre-commit → pnpm exec whisker pre-commit
.husky/post-commit → pnpm exec whisker post-commit

pre-commit regenerates config/module-manifest.json from src/moduleManifest.ts and validates it — a schema violation fails the commit before it ever reaches CI. post-commit updates provenance fields. This makes config/module-manifest.json an artifact that’s always correct relative to src/moduleManifest.ts on any commit, on any branch.

The runner is fully built and live at whisker-host/Jenkinsfile.nightly, running H 2 * * *.

Host-level suites (shipped, in whisker-host/tests/e2e/): auth, dashboard, nav, module-routes — all backed by a shared authedPage fixture (tests/e2e/fixtures/auth.ts) that drives the BERM login flow and yields an authenticated page. Credentials come from Cerberus in CI, from .env.local locally.

Pipeline phases:

1. Fetch credentials from Cerberus (one shared dummy account)
2. Host-level E2E: auth, dashboard, nav, module-routes specs
3. Per-module E2E: snapshot the live registry once, git clone each
module's repo (from its manifest's `repository` field), run its own
pnpm test:e2e against the running host
4. Merge + publish: playwright merge-reports → S3 nightly/latest + nightly/{date}
5. Notify: #platform-e2e aggregate + per-module Slack channel on failure

The phrase that matters: the runner never needs to change when a module is added, removed, or rewrites its tests — it iterates over whatever’s registered at run time, and each module’s manifest tells it where to clone from and which Slack channel to notify.

Iframe consumers can be targeted deterministically in Playwright via the iframe’s title attribute (set to the module name by IframeRenderer):

const frame = page.frameLocator('iframe[title="sim-web-ui"]');

Reports land at:

s3://whisker-e2e-reports/nightly/latest/{report.json, index.html}
s3://whisker-e2e-reports/nightly/{date}/...same shape...

Vitest is the unit-test framework for both modules and services scaffolded from create-whisker. The historical Japa setup in sim-bff stays as-is until the platform concerns are carved into whisker-bff. One framework keeps developer mobility between modules and services cheap.

These genuinely require a human and live in docs/manual-setup-required.md: developer-workstation setup (Playwright browsers, @playwright/mcp, gimme-creds), per-project scaffold-time items (NPE account IDs, OSCAR scopes, initial Jenkins approval), and platform infrastructure (the dummy test Okta account, Jenkins org credentials, the E2E reports bucket).

A read-only, non-blocking compliance status surface, opened next to whisker-host during whisker dev. Design is settled; no implementation exists yet — no server, no UI, no compliance-check module in the kit.

The plan: an Express server on port 3009, started by whisker dev once the main servers are healthy, pushing check results over SSE. Planned sections: services status (PID/uptime/port for host, module dev server, devkit itself), a compliance list with remediation links, the nightly E2E report (this module’s row + platform aggregate, proxied to sidestep browser CORS), the manual-setup checklist, and the currently-pinned contract version.

Eight planned compliance checks (pure functions, meant to be shared by whisker doctor and the panel — not yet coded):

1. E2E tests exist (tests/e2e/*.spec.ts present)
2. playwright.config.ts present
3. module-manifest.json is current (hash of src/moduleManifest vs generated file)
4. whisker-contract version is up to date
5. whisker.config.json passes Zod schema
6. Node version satisfies engines.node
7. @playwright/mcp present in ~/.cursor/mcp.json (workstation check)
8. NPE account IDs are not still "TODO" placeholder strings

All non-blocking by design — whisker.config.json#compliance may later let a team opt a specific check into CI-blocking, but the default stays advisory.

Planned, not shipped: @nike/whisker-module-kit doesn’t yet export an ./e2e subpath. The intended shape:

import { whiskerTest as test, expect } from '@nike/whisker-module-kit/e2e';
test('inventory table loads', async ({ authedPage }) => {
await authedPage.goto('/inventory');
await expect(authedPage.getByRole('table')).toBeVisible();
});

authedPage would read WHISKER_HOST_URL, log in with WHISKER_TEST_USER/WHISKER_TEST_PASS, wait for the host shell, and yield the page — mirroring the host’s own fixture so module teams don’t write auth boilerplate. Also planned: whisker test:e2e (boots the dev stack, runs Playwright, tears down) and whisker add-e2e (scaffolds a starter suite into an existing repo).

See Risks & improvements for priority on both items.