Skip to content
Merged
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
23 changes: 19 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ Playwright's `beforeAll` runs once **per worker**, not once per test run. When a

```typescript
test.beforeAll(async ({ rhdh }) => {
await test.runOnce("tech-radar-setup", async () => {
await test.runOnce(`tech-radar-setup-${rhdh.deploymentConfig.namespace}`, async () => {
await rhdh.configure({ auth: "keycloak" });

// Expensive: deploys an external service to the cluster
Expand All @@ -244,7 +244,7 @@ If a test **does** need an env var that was set inside `runOnce`, extract it fro

```typescript
test.beforeAll(async ({ rhdh }) => {
await test.runOnce("my-setup", async () => {
await test.runOnce(`my-setup-${rhdh.deploymentConfig.namespace}`, async () => {
await rhdh.configure({ auth: "keycloak" });
await $`bash deploy-service.sh ${rhdh.deploymentConfig.namespace}`;
await rhdh.deploy();
Expand All @@ -258,8 +258,23 @@ test.beforeAll(async ({ rhdh }) => {
```

**Key rules:**
- The `key` (first argument) must be **globally unique** across all spec files and projects. Prefix with workspace name: `"tech-radar-setup"`, `"argocd-deploy"`.
- Nesting is safe — `deploy()` uses `runOnce` internally, wrapping it in an outer `runOnce` is harmless.
- The `key` (first argument) must be **globally unique** across all spec files **and projects**. A workspace prefix covers the first half; the second half is what bit us. The flag file is keyed by the key string alone, in a directory keyed only on the Playwright runner PID:

```ts
const flagDir = path.join(os.tmpdir(), `playwright-once-${process.ppid}`);
const flagFile = path.join(flagDir, `${key}.done`);
```

Nothing in that path comes from the project. So when one spec runs in two projects — which is what adding an `-app-next` lane does — the first project's setup satisfies the second, and the second skips its own. For a block that deploys, that means no deployment at all, then a failure much later on a missing element with nothing pointing at the cause (#3318).

- **End the key with the namespace whenever the setup belongs to one project**, which is what `deploy()` does internally (`deploy-${namespace}`) and why `deploy()` was never affected:

```typescript
await test.runOnce(`my-plugin-setup-${rhdh.deploymentConfig.namespace}`, async () => { ... });
```

A literal key is right when the setup really is shared — an operator installed once into a fixed namespace every project then uses. `bulk-import` has one of each, deliberately. The key is where you say which you mean.
- Nesting is safe — `deploy()` uses `runOnce` internally, wrapping it in an outer `runOnce` is harmless. It does **not** rescue a project-shared outer key, though: that skips before `deploy()` is reached, so its own protection never gets a say.
- Uses file-based flags in `/tmp/` scoped to the Playwright runner process. Flags reset automatically between test runs.

### RHDH Deployment Flow
Expand Down
Loading