You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Executes `fn` exactly once per test run, even across worker restarts. Returns `true` if executed, `false` if skipped.
90
+
91
+
::: tip
92
+
`rhdh.deploy()` already uses `runOnce` internally, so you don't need to wrap simple deployments. Use `test.runOnce` when you have **additional expensive operations** (external services, scripts, data seeding) alongside `deploy()`.
93
+
:::
94
+
95
+
| Parameter | Type | Description |
96
+
|-----------|------|-------------|
97
+
|`key`|`string`| Unique identifier for this operation |
98
+
|`fn`|`() => Promise<void> \| void`| Function to execute once |
99
+
100
+
```typescript
101
+
// Wrap pre-deploy setup that shouldn't repeat
102
+
test.beforeAll(async ({ rhdh }) => {
103
+
awaittest.runOnce("full-setup", async () => {
104
+
await$`bash deploy-external-service.sh`;
105
+
awaitrhdh.configure({ auth: "keycloak" });
106
+
awaitrhdh.deploy(); // safe to nest, has its own internal protection
107
+
});
108
+
});
109
+
```
110
+
111
+
See [Deployment Protection](/guide/core-concepts/playwright-fixtures#deployment-protection-built-in) and [`test.runOnce`](/guide/core-concepts/playwright-fixtures#test-runonce-—-run-any-expensive-operation-once) for details.
Copy file name to clipboardExpand all lines: docs/changelog.md
+12-1Lines changed: 12 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,7 +2,18 @@
2
2
3
3
All notable changes to this project will be documented in this file.
4
4
5
-
## [1.1.13] - Current
5
+
## [1.1.14] - Current
6
+
7
+
### Added
8
+
-**`deploy()` built-in protection**: `rhdh.deploy()` now automatically skips if the deployment already succeeded in the current test run. No code changes needed — existing `beforeAll` patterns work as before, but deployments are no longer repeated when Playwright restarts workers after test failures.
9
+
-**`test.runOnce(key, fn)`**: Execute any function exactly once per test run, even across worker restarts. Use for expensive pre-deploy operations (external services, setup scripts, data seeding) that `deploy()` alone doesn't cover. Safe to nest with `deploy()`'s built-in protection.
10
+
-**Teardown reporter**: Built-in Playwright reporter that automatically deletes Kubernetes namespaces after all tests complete. Active only in CI (`process.env.CI`).
11
+
-**`registerTeardownNamespace(projectName, namespace)`**: Register custom namespaces for automatic cleanup. Import from `@red-hat-developer-hub/e2e-test-utils/teardown`.
12
+
13
+
### Changed
14
+
- Namespace cleanup moved from worker fixture to teardown reporter to prevent premature deletion on test failures.
In CI environments (when `CI` environment variable is set):
159
+
`rhdh.deploy()` is automatically protected against redundant re-execution. When a test fails and Playwright restarts the worker, `deploy()` detects that the deployment already succeeded and skips — no re-deployment, no wasted time.
160
160
161
-
- Namespaces are automatically deleted after tests complete
162
-
- Prevents resource accumulation on shared clusters
161
+
This works out of the box. A simple `beforeAll` is all you need:
163
162
164
-
For local development:
165
-
- Namespaces are preserved for debugging
166
-
- Manual cleanup may be required
163
+
```typescript
164
+
test.beforeAll(async ({ rhdh }) => {
165
+
awaitrhdh.configure({ auth: "keycloak" });
166
+
awaitrhdh.deploy(); // runs once, skips on worker restart
167
+
});
168
+
```
169
+
170
+
::: tip Why is this needed?
171
+
Playwright's `beforeAll` runs once **per worker**, not once per test run. When a test fails, Playwright kills the worker and creates a new one for remaining tests — causing `beforeAll` to run again. Without protection, this would re-deploy RHDH from scratch every time a test fails.
172
+
:::
173
+
174
+
## `test.runOnce` — Run Any Expensive Operation Once
175
+
176
+
While `rhdh.deploy()` has built-in protection, you may have **other expensive operations** in your `beforeAll` that also shouldn't repeat on worker restart — deploying external services, seeding databases, running setup scripts, etc.
177
+
178
+
`test.runOnce` ensures any function executes **exactly once per test run**, even across worker restarts:
`test.runOnce` can be safely nested. Since `rhdh.deploy()` uses `runOnce` internally, wrapping it in an outer `test.runOnce` is harmless — the outer call skips everything on worker restart, and the inner one never runs:
265
+
266
+
```typescript
267
+
awaittest.runOnce("full-setup", async () => {
268
+
await$`bash setup.sh`; // protected by outer runOnce
269
+
awaitrhdh.deploy(); // has its own internal runOnce (harmless)
270
+
});
271
+
```
272
+
273
+
## Namespace Cleanup (Teardown)
274
+
275
+
In CI environments (`CI` environment variable is set), namespaces are automatically deleted after all tests complete. This is handled by a built-in **teardown reporter** that:
276
+
277
+
1. Runs in the main Playwright process (survives worker restarts)
278
+
2. Waits for **all tests** to finish
279
+
3. Deletes the namespace matching the project name
280
+
281
+
### Default Behavior
282
+
283
+
No configuration needed. The namespace is derived from your project name:
284
+
285
+
```typescript
286
+
// playwright.config.ts
287
+
projects: [
288
+
{ name: "tech-radar" }, // Namespace "tech-radar" deleted after all tests
289
+
{ name: "catalog" }, // Namespace "catalog" deleted after all tests
290
+
]
291
+
```
292
+
293
+
### Custom Namespaces
294
+
295
+
If you deploy to a namespace that differs from the project name, register it for cleanup:
Copy file name to clipboardExpand all lines: docs/guide/deployment/rhdh-deployment.md
+19-14Lines changed: 19 additions & 14 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -34,7 +34,7 @@ import { test } from "@red-hat-developer-hub/e2e-test-utils/test";
34
34
test.beforeAll(async ({ rhdh }) => {
35
35
// rhdh is already instantiated with namespace from project name
36
36
awaitrhdh.configure({ auth: "keycloak" });
37
-
awaitrhdh.deploy();
37
+
awaitrhdh.deploy();// automatically skips if already deployed
38
38
});
39
39
40
40
test("example", async ({ rhdh }) => {
@@ -110,6 +110,8 @@ test.setTimeout(900_000);
110
110
awaitrhdh.deploy({ timeout: null });
111
111
```
112
112
113
+
`deploy()` automatically skips if the deployment already succeeded in the current test run (e.g., after a worker restart due to test failure). This prevents expensive re-deployments.
2.[Injects plugin metadata](/guide/configuration/config-files#plugin-metadata-injection) into dynamic plugins config
@@ -176,7 +178,7 @@ await deployment.teardown();
176
178
```
177
179
178
180
::: warning
179
-
This permanently deletes all resources in the namespace. In CI, this happens automatically.
181
+
You typically don't need to call this manually. In CI, the built-in teardown reporter automatically deletes namespaces after all tests complete. See [Namespace Cleanup](/guide/core-concepts/playwright-fixtures#namespace-cleanup-teardown).
180
182
:::
181
183
182
184
## Properties
@@ -259,21 +261,24 @@ import { test } from "@red-hat-developer-hub/e2e-test-utils/test";
0 commit comments