Skip to content

Commit cdcc7d0

Browse files
chore(docs) : 1.1.24 docs update (#73)
1 parent 74723a1 commit cdcc7d0

17 files changed

Lines changed: 1104 additions & 227 deletions

File tree

CLAUDE.md

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to AI coding tools when working with the `@red-hat-developer-hub/e2e-test-utils` package.
4+
5+
## Package Purpose
6+
7+
A shared npm package (`@red-hat-developer-hub/e2e-test-utils`) that provides everything needed to write and run E2E tests for Red Hat Developer Hub (RHDH) plugins. It handles:
8+
9+
- Deploying RHDH to OpenShift (Helm or Operator)
10+
- Deploying Keycloak for authentication
11+
- Playwright test fixtures, helpers, and page objects
12+
- Dynamic plugin configuration with metadata-based OCI resolution
13+
- Config file merging (common defaults + auth + user overrides)
14+
- Kubernetes API operations
15+
- Per-project namespace teardown in CI
16+
17+
Published to npm under `@red-hat-developer-hub` scope. Primary consumers are overlay workspaces in `rhdh-plugin-export-overlays`.
18+
19+
## Project Structure
20+
21+
```
22+
src/
23+
├── deployment/
24+
│ ├── rhdh/ # RHDHDeployment class — core deployment orchestration
25+
│ │ ├── deployment.ts # Main class (configure, deploy, waitUntilReady, teardown)
26+
│ │ ├── types.ts # DeploymentOptions, DeploymentConfig
27+
│ │ ├── constants.ts # Config paths, auth providers, chart URLs
28+
│ │ └── config/ # YAML templates (common/, auth/, helm/, operator/)
29+
│ ├── keycloak/ # KeycloakHelper — Keycloak Helm deployment + OIDC setup
30+
│ └── orchestrator/ # Workflow orchestrator installer
31+
├── playwright/
32+
│ ├── fixtures/test.ts # Custom fixtures: rhdh, uiHelper, loginHelper, baseURL
33+
│ ├── base-config.ts # Base Playwright config (reporters, timeouts, video/trace)
34+
│ ├── global-setup.ts # Pre-test: check binaries, detect cluster, deploy Keycloak
35+
│ ├── run-once.ts # Cross-worker one-time execution with file locking
36+
│ ├── teardown-reporter.ts # Per-project namespace cleanup (CI only)
37+
│ ├── teardown-namespaces.ts # Custom namespace registry for teardown
38+
│ ├── helpers/ # LoginHelper, UIhelper, APIHelper, RbacApiHelper, etc.
39+
│ ├── pages/ # Page objects: CatalogPage, HomePage, ExtensionsPage, etc.
40+
│ └── page-objects/ # Shared element selectors/constants
41+
├── utils/
42+
│ ├── plugin-metadata.ts # Plugin discovery, OCI resolution, PR/nightly modes
43+
│ ├── workspace-paths.ts # Path resolution from Playwright testDir (not CWD)
44+
│ ├── kubernetes-client.ts # KubernetesClientHelper (K8s API wrapper)
45+
│ ├── merge-yamls.ts # Deep merge with array strategies (replace, concat, byKey)
46+
│ ├── bash.ts # zx shell wrapper ($, runQuietUnlessFailure)
47+
│ └── common.ts # envsubst, requireEnv helpers
48+
└── eslint/
49+
└── base.config.ts # createEslintConfig() factory for consumers
50+
```
51+
52+
## Package Exports
53+
54+
| Import Path | What It Provides |
55+
| --------------------- | ------------------------------------------------------------------------------ |
56+
| `./test` | `test`, `expect` — Playwright fixtures with RHDH-specific fixtures |
57+
| `./playwright-config` | `defineConfig`, `baseConfig` — base Playwright configuration |
58+
| `./rhdh` | `RHDHDeployment` — deployment orchestration class |
59+
| `./utils` | `$`, `KubernetesClientHelper`, `WorkspacePaths`, `envsubst`, `mergeYamlFiles` |
60+
| `./helpers` | `UIhelper`, `LoginHelper`, `APIHelper`, `RbacApiHelper`, `AccessibilityHelper` |
61+
| `./pages` | `CatalogPage`, `HomePage`, `ExtensionsPage`, etc. |
62+
| `./keycloak` | `KeycloakHelper` — Keycloak deployment and OIDC configuration |
63+
| `./teardown` | `registerTeardownNamespace` — custom namespace cleanup registration |
64+
| `./orchestrator` | `installOrchestrator` — workflow orchestrator deployment |
65+
| `./eslint` | `createEslintConfig` — ESLint config factory |
66+
| `./tsconfig` | Base TypeScript configuration (JSON, not code) |
67+
68+
## Build System
69+
70+
```bash
71+
yarn build # Clean + tsc + copy config YAML files + copy shell scripts to dist/
72+
yarn test # node --test "dist/**/*.test.js" (must build first)
73+
yarn check # typecheck + lint + prettier
74+
```
75+
76+
- **TypeScript**: ES2022 target, ESNext modules, strict mode
77+
- **Module system**: ESM (`"type": "module"`)
78+
- **Build output**: `dist/` (JS + .d.ts declarations + config YAMLs)
79+
- **Config files**: Copied as-is from `src/deployment/*/config/` to `dist/` during build
80+
- **Package manager**: Yarn v3.8.7, Node >= 22.18.0
81+
82+
## Key Architectural Concepts
83+
84+
### Configuration Merging (3-level cascade)
85+
86+
```
87+
Package defaults (config/common/)
88+
↓ deep merge
89+
Auth-specific (config/auth/{keycloak|guest|github}/)
90+
↓ deep merge
91+
User config (workspace's tests/config/*.yaml)
92+
93+
= Final merged config
94+
```
95+
96+
Array merge uses "replace" strategy by default. Plugin arrays use `byKey: "package"` with normalized keys (strips trailing `-dynamic`).
97+
98+
### Plugin Metadata Resolution
99+
100+
`RHDHDeployment.deploy()` internally calls `processPluginsForDeployment()` which operates in two modes:
101+
102+
| Mode | Detection | Behavior |
103+
| ------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
104+
| **PR check** | `GIT_PR_NUMBER` is set | Injects metadata configs + resolves to PR-built OCI URLs (`pr_{number}__{version}`) |
105+
| **Nightly** | `E2E_NIGHTLY_MODE=true` or `JOB_NAME` contains `periodic-` | Resolves to released OCI refs from `spec.dynamicArtifact` in metadata; skips config injection |
106+
| **Local dev** | Neither set | Uses local paths as-is; injects metadata configs |
107+
108+
Priority: `GIT_PR_NUMBER` (forces PR mode) > `E2E_NIGHTLY_MODE` > `JOB_NAME`
109+
110+
When no `dynamic-plugins.yaml` exists in the workspace, plugins are auto-generated from `metadata/*.yaml` files.
111+
112+
### WorkspacePaths
113+
114+
Static utility that resolves config file paths from `test.info().project.testDir` (Playwright-provided absolute path) instead of `process.cwd()`. This is critical because tests can run from two contexts:
115+
116+
- Workspace level: `cd workspaces/tech-radar/e2e-tests && yarn test`
117+
- Repo root: `./run-e2e.sh -w tech-radar`
118+
119+
The worker fixture also does `process.chdir(e2eRoot)` as a complementary safety net.
120+
121+
### Playwright Fixtures
122+
123+
Worker fixture creates `RHDHDeployment(projectName)` from the Playwright project name (which becomes the K8s namespace) and sets CWD to the workspace e2e-tests directory. Test-scoped fixtures (`uiHelper`, `loginHelper`, `baseURL`) are created fresh per test. See the [consumer code example](#typical-test-structure) for usage.
124+
125+
### runOnce — Cross-Worker Deduplication
126+
127+
`deploy()` uses `runOnce()` internally to execute exactly once per test run, even when Playwright restarts workers after test failures. Uses file-based flags with `proper-lockfile` in `/tmp/playwright-once-{ppid}/`.
128+
129+
### Teardown Reporter
130+
131+
Custom Playwright reporter that deletes namespaces per-project (not per-suite) as tests complete. Only active when `CI=true`. Needed because:
132+
133+
- `afterAll` hooks fire on worker restart (before retries can run)
134+
- Worker fixture teardown has the same problem
135+
- `globalTeardown` has no visibility into which projects ran
136+
137+
### Global Setup
138+
139+
Runs once before all tests:
140+
141+
1. Checks required binaries (`oc`, `kubectl`, `helm`)
142+
2. Auto-detects cluster domain (`K8S_CLUSTER_ROUTER_BASE`)
143+
3. Deploys Keycloak (unless `SKIP_KEYCLOAK_DEPLOYMENT=true`)
144+
145+
### RHDHDeployment.deploy() Flow
146+
147+
1. Merges config files (common + auth + user)
148+
2. Injects plugin metadata into dynamic plugins config (PR/local mode)
149+
3. Applies ConfigMaps (app-config, dynamic-plugins)
150+
4. Applies Secrets (with `envsubst` for environment variable substitution)
151+
5. Installs RHDH via Helm or Operator
152+
6. Waits for readiness: pod `Ready=True` + route HTTP health check
153+
7. Sets `RHDH_BASE_URL` environment variable
154+
155+
Helm upgrades perform `scaleDownAndRestart()` to avoid `MigrationLocked` errors. Fresh installs skip this.
156+
157+
## Key Environment Variables
158+
159+
| Variable | Purpose | Default |
160+
| ------------------------------------- | ------------------------------------------------ | -------- |
161+
| `RHDH_VERSION` | RHDH version to deploy | `"next"` |
162+
| `INSTALLATION_METHOD` | `"helm"` or `"operator"` | `"helm"` |
163+
| `GIT_PR_NUMBER` | PR number — triggers PR-mode OCI resolution | - |
164+
| `E2E_NIGHTLY_MODE` | `"true"` or `"1"` — nightly mode | - |
165+
| `JOB_NAME` | CI job name; `periodic-` prefix triggers nightly | - |
166+
| `SKIP_KEYCLOAK_DEPLOYMENT` | Skip Keycloak in global setup | - |
167+
| `K8S_CLUSTER_ROUTER_BASE` | Cluster domain (auto-detected) | - |
168+
| `CI` | Enables `forbidOnly`, teardown reporter | - |
169+
| `RHDH_SKIP_PLUGIN_METADATA_INJECTION` | Skip metadata config injection in PR mode | - |
170+
| `CATALOG_INDEX_IMAGE` | Override catalog index image | - |
171+
172+
## Consumer Perspective (Overlay Workspaces)
173+
174+
Changes to this package affect ~67 overlay workspaces. Understanding how they use the package is critical before modifying APIs.
175+
176+
### Typical Test Structure
177+
178+
```typescript
179+
import { test, expect } from "@red-hat-developer-hub/e2e-test-utils/test";
180+
import { $ } from "@red-hat-developer-hub/e2e-test-utils/utils";
181+
182+
test.describe("My Plugin", () => {
183+
test.beforeAll(async ({ rhdh }) => {
184+
// 1. Pre-deployment setup (external services, K8s resources)
185+
await $`bash ${setupScript} ${rhdh.deploymentConfig.namespace}`;
186+
process.env.SERVICE_URL = await rhdh.k8sClient.getRouteLocation(
187+
namespace,
188+
"my-svc",
189+
);
190+
191+
// 2. Configure + deploy RHDH
192+
await rhdh.configure({ auth: "keycloak" });
193+
await rhdh.deploy();
194+
});
195+
196+
test.beforeEach(async ({ loginHelper }) => {
197+
await loginHelper.loginAsKeycloakUser();
198+
});
199+
200+
test("verify feature", async ({ uiHelper }) => {
201+
await uiHelper.openSidebar("My Plugin");
202+
await uiHelper.verifyHeading("Expected Title");
203+
});
204+
});
205+
```
206+
207+
### Consumer Gotchas
208+
209+
- **Config paths are workspace-relative**`appConfig: "tests/config/app-config.yaml"` resolves from the workspace's `e2e-tests/` directory via `WorkspacePaths`, not from `process.cwd()`.
210+
- **`$` shell is for setup, not assertions** — used in `beforeAll` for deployment scripts. Use `$({ stdio: "pipe" })` to capture output.
211+
- **`rhdh.configure()` must precede `rhdh.deploy()`** — every workspace follows this order.
212+
- **`defineConfig` only needs `projects`** — base config handles reporters, timeouts, video/trace, global setup. Consumers just specify project names (which become K8s namespaces).
213+
214+
### What Consumers Use vs What's Internal
215+
216+
| Consumer-facing (public API) | Internal (used by deploy()) |
217+
| ----------------------------------------------- | ------------------------------- |
218+
| `test`, `expect` fixtures | `processPluginsForDeployment()` |
219+
| `rhdh.configure()`, `rhdh.deploy()` | `isNightlyJob()` |
220+
| `UIhelper`, `LoginHelper`, `APIHelper` | `generatePluginsFromMetadata()` |
221+
| `$`, `WorkspacePaths`, `KubernetesClientHelper` | `injectMetadataConfig()` |
222+
| `defineConfig` from `./playwright-config` | `resolvePluginPackages()` |
223+
| `registerTeardownNamespace` from `./teardown` | `disablePluginWrappers()` |
224+
225+
## Testing
226+
227+
Tests use Node.js built-in `node:test` module (not Playwright):
228+
229+
```bash
230+
yarn build && yarn test
231+
```
232+
233+
Test files:
234+
235+
- `src/deployment/rhdh/deployment.test.ts` — plugin merge behavior
236+
- `src/utils/merge-yamls.test.ts` — YAML merge strategies
237+
- `src/utils/tests/plugin-metadata.*.test.ts` — metadata resolution (PR, nightly, fixtures)
238+
239+
## Naming Conventions
240+
241+
- **Class**: `UIhelper` (capital U, lowercase h) — matches source code
242+
- **Fixture**: `uiHelper` (camelCase) — used in test fixtures
243+
- **Method names**: Follow source exactly (e.g., `verifyTextinCard` not `verifyTextInCard`)
244+
245+
## Documentation
246+
247+
VitePress docs in `docs/` — standalone package with its own `package.json`. See `docs/CLAUDE.md` for documentation-specific guidance.
248+
249+
```bash
250+
cd docs && yarn install && yarn dev # http://localhost:5173
251+
```
252+
253+
Deployed to GitHub Pages via `.github/workflows/deploy-docs.yml` on pushes to `main`.
254+
255+
## Common Tasks
256+
257+
### Adding a New Export Path
258+
259+
1. Add the entry to `package.json` `exports` with `types` and `default`
260+
2. Create the source file and its `index.ts` barrel export
261+
3. Document in the VitePress docs (guide + API sections)
262+
263+
### Adding a New Auth Provider
264+
265+
1. Create config files in `src/deployment/rhdh/config/auth/<provider>/`
266+
2. Add the provider to the `AUTH_PROVIDERS` constant in `constants.ts`
267+
3. Update the `auth` type in `types.ts`
268+
269+
### Modifying Config Merging
270+
271+
Config merge order is defined in `deployment.ts` `_buildDeploymentConfig()`. Array merge strategies are in `merge-yamls.ts`. Plugin-specific merging uses `getNormalizedPluginMergeKey()` to deduplicate entries with/without `-dynamic` suffix.
272+
273+
### Updating Plugin Metadata Logic
274+
275+
All in `src/utils/plugin-metadata.ts`. Key functions:
276+
277+
- `isNightlyJob()` — mode detection
278+
- `processPluginsForDeployment()` — unified entry point for PR + nightly
279+
- `generatePluginsFromMetadata()` — auto-generate from metadata files
280+
- `resolvePluginPackages()` — OCI URL resolution
281+
- `injectMetadataConfig()` — merge metadata configs into plugin entries
282+
- `disablePluginWrappers()` — disable local wrappers when using OCI images
283+
284+
Test thoroughly — changes affect all overlay workspaces. Run `yarn build && yarn test` to verify.

docs/.vitepress/config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,10 @@ export default defineConfig({
395395
text: "Environment Variables",
396396
link: "/overlay/reference/environment-variables",
397397
},
398+
{
399+
text: "Unified Test Runner (run-e2e.sh)",
400+
link: "/overlay/reference/run-e2e",
401+
},
398402
{
399403
text: "Local OCI Testing",
400404
link: "/overlay/reference/local-oci-testing",

0 commit comments

Comments
 (0)