@camunda/e2e-test-suite 0.0.633 → 0.0.635

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -63,21 +63,37 @@ class ClusterSecretsPage {
63
63
  return; //No Connector Secrets found in the list
64
64
  }
65
65
  try {
66
- let options = await this.optionsButton.all();
67
- while (options.length > 0) {
68
- const optionButton = options[0];
69
- if (await optionButton.isVisible()) {
66
+ for (let sweep = 0; sweep < 20; sweep++) {
67
+ const options = await this.optionsButton.all();
68
+ if (options.length === 0) {
69
+ break;
70
+ }
71
+ let deletedAny = false;
72
+ for (const optionButton of options) {
73
+ if (!(await optionButton.isVisible().catch(() => false))) {
74
+ continue;
75
+ }
70
76
  await optionButton.click({ timeout: 60000 });
77
+ await (0, test_1.expect)(this.deleteConnectorSecretButton).toBeVisible({
78
+ timeout: 15000,
79
+ });
80
+ if (await this.deleteConnectorSecretButton.isDisabled()) {
81
+ await this.page.keyboard.press('Escape').catch(() => { });
82
+ continue;
83
+ }
71
84
  await this.deleteConnectorSecretButton.click({ timeout: 60000 });
72
85
  await (0, test_1.expect)(this.dialog).toBeVisible({ timeout: 40000 });
73
86
  await this.deleteConnectorSecretSubButton.click();
74
87
  await (0, test_1.expect)(this.page.getByText('Deleting...')).not.toBeVisible({
75
88
  timeout: 60000,
76
89
  });
90
+ deletedAny = true;
91
+ await (0, sleep_1.sleep)(3000);
92
+ break;
93
+ }
94
+ if (!deletedAny) {
95
+ break;
77
96
  }
78
- const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
79
- await sleep(3000);
80
- options = await this.optionsButton.all();
81
97
  }
82
98
  await (0, test_1.expect)(this.optionsButton).not.toBeVisible({
83
99
  timeout: 30000,
@@ -194,7 +194,16 @@ class ConsoleOrganizationPage {
194
194
  }
195
195
  }
196
196
  async clickUsersTab() {
197
- await (0, test_1.expect)(this.usersTab).toBeVisible({ timeout: 60000 });
197
+ // The Users tab can fail to render if the Org page is mid-load when we
198
+ // arrive. Try once with a shorter window, reload on failure, then give
199
+ // the second attempt the full timeout before surfacing the error.
200
+ try {
201
+ await (0, test_1.expect)(this.usersTab).toBeVisible({ timeout: 30000 });
202
+ }
203
+ catch {
204
+ await this.page.reload();
205
+ await (0, test_1.expect)(this.usersTab).toBeVisible({ timeout: 60000 });
206
+ }
198
207
  await this.usersTab.click({ timeout: 60000 });
199
208
  await (0, expectLocatorWithRetry_1.expectLocatorWithRetry)(this.page, this.filterTableSearchbox, {
200
209
  postAction: async () => {
@@ -74,7 +74,13 @@ class HomePage {
74
74
  if (!(await next.isVisible({ timeout: visibleTimeout }))) {
75
75
  return;
76
76
  }
77
- await next.click({ timeout: 30000, force: true });
77
+ try {
78
+ await next.click({ timeout: 30000, force: true });
79
+ }
80
+ catch {
81
+ // Close buttons are occasionally replaced during modal animation;
82
+ // continue and retry with the latest visible control.
83
+ }
78
84
  }
79
85
  }
80
86
  organizationUuid() {
@@ -89,15 +95,13 @@ class HomePage {
89
95
  await this.openOrganizationButton.click({ timeout: 60000 });
90
96
  }
91
97
  async clickSkipCustomization() {
92
- try {
93
- await (0, test_1.expect)(this.buttonSkipCustomization).toBeVisible({ timeout: 30000 });
94
- await this.buttonSkipCustomization.click({ timeout: 60000 });
95
- await this.closeInformationDialog();
96
- return;
97
- }
98
- catch (error) {
99
- console.error(error);
98
+ const hasCustomizationModal = await this.buttonSkipCustomization
99
+ .isVisible({ timeout: 30000 })
100
+ .catch(() => false);
101
+ if (hasCustomizationModal) {
102
+ await this.buttonSkipCustomization.click({ timeout: 60000, force: true });
100
103
  }
104
+ await this.closeInformationDialog();
101
105
  }
102
106
  }
103
107
  exports.HomePage = HomePage;
@@ -19,8 +19,11 @@ class LoginPage {
19
19
  // resolves to the auth0 email input, regardless of redirect timing.
20
20
  this.usernameInput = page
21
21
  .getByLabel('Email address')
22
- .and(page.locator(':not(#c4-invite-email)'));
23
- this.passwordInput = page.getByLabel('Password *');
22
+ .and(page.locator(':not([id="c4-invite-email"])'));
23
+ this.passwordInput = page
24
+ .getByLabel(/^Password\s*\*?$/i)
25
+ .or(page.locator('input[type="password"]'))
26
+ .first();
24
27
  this.continueButton = page.getByRole('button', {
25
28
  name: 'Continue',
26
29
  exact: true,
@@ -62,6 +65,9 @@ class LoginPage {
62
65
  const { username = process.env.C8_USERNAME_TEST, password = process.env.C8_PASSWORD_TEST, } = credentials;
63
66
  // Navigate to app root to start the auth flow.
64
67
  await this.page.goto('/');
68
+ await this.page
69
+ .waitForURL((url) => !url.hostname.includes('console'), { timeout: 60000 })
70
+ .catch(() => { });
65
71
  // SSO re-auth may silently log us back in as the previous user after
66
72
  // logout/session-reset, keeping the page on Console instead of redirecting
67
73
  // to the Auth0 login form. Detect Console (settings button visible) and
@@ -81,9 +87,16 @@ class LoginPage {
81
87
  await this.page.waitForLoadState('domcontentloaded', { timeout: 30000 });
82
88
  }
83
89
  }
84
- await (0, test_1.expect)(this.usernameInput).toBeVisible({ timeout: 120000 });
85
- await this.fillUsername(username);
86
- await this.clickContinueButton();
90
+ const onPasswordStep = (await this.passwordHeading
91
+ .isVisible({ timeout: 5000 })
92
+ .catch(() => false)) ||
93
+ (await this.passwordInput.isVisible({ timeout: 5000 }).catch(() => false));
94
+ if (!onPasswordStep) {
95
+ await (0, test_1.expect)(this.usernameInput).toBeVisible({ timeout: 120000 });
96
+ await this.fillUsername(username);
97
+ await this.clickContinueButton();
98
+ }
99
+ await (0, test_1.expect)(this.passwordInput).toBeVisible({ timeout: 180000 });
87
100
  await this.fillPassword(password);
88
101
  await (0, test_1.expect)(this.loginButton).toBeVisible({ timeout: 120000 });
89
102
  await this.clickLoginButton();
@@ -1,8 +1,12 @@
1
1
  import { Page, Locator } from '@playwright/test';
2
2
  declare class PlayPage {
3
3
  private page;
4
+ readonly diagram: Locator;
5
+ readonly playTab: Locator;
4
6
  readonly completeJobButton: Locator;
5
- readonly startInstanceButton: Locator;
7
+ readonly configureTestPanel: Locator;
8
+ readonly configureTestPanelStartButton: Locator;
9
+ readonly startInstanceOverlayButton: Locator;
6
10
  constructor(page: Page);
7
11
  waitForCompleteJobButtonToBeAvailable(): Promise<void>;
8
12
  clickCompleteJobButton(): Promise<void>;
@@ -2,19 +2,35 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PlayPage = void 0;
4
4
  const test_1 = require("@playwright/test");
5
+ const clickLocatorWithRetry_1 = require("../../utils/assertionHelpers/clickLocatorWithRetry");
5
6
  const maxWaitTimeSeconds = 180000;
6
7
  class PlayPage {
7
8
  page;
9
+ diagram;
10
+ playTab;
8
11
  completeJobButton;
9
- startInstanceButton;
12
+ configureTestPanel;
13
+ configureTestPanelStartButton;
14
+ startInstanceOverlayButton;
10
15
  constructor(page) {
11
16
  this.page = page;
12
- this.completeJobButton = page
13
- .getByTestId('diagram')
14
- .getByLabel('Complete job');
15
- this.startInstanceButton = this.page
16
- .getByTestId('diagram')
17
- .getByLabel('Start instance', { exact: true });
17
+ this.diagram = page.getByTestId('diagram');
18
+ this.playTab = page.getByRole('tab', { name: 'Play' });
19
+ this.completeJobButton = this.diagram.getByLabel('Complete job');
20
+ // Newer Modeler Play UI: the "Configure Scenario" floating card hosts a
21
+ // primary "Start" Carbon button (variants: "Start", "Start with
22
+ // variables", "Start with a form"). Source:
23
+ // camunda-hub frontend/packages/modeler/play/src/Definition/
24
+ // ConfigureTestPanel/index.tsx — renders <FloatingCard
25
+ // data-testid="configure-test-panel"> with a <Button> whose visible
26
+ // text starts with "Start".
27
+ this.configureTestPanel = page.getByTestId('configure-test-panel');
28
+ this.configureTestPanelStartButton = this.configureTestPanel.getByRole('button', { name: /^Start( with .*)?$/, exact: false });
29
+ // Legacy bpmn-js canvas overlay button (still emitted by older Modeler
30
+ // builds, also relabeled with cached/example-data suffixes). Kept as a
31
+ // fallback for environments that haven't shipped the ConfigureTestPanel
32
+ // yet.
33
+ this.startInstanceOverlayButton = this.diagram.getByLabel('Start instance', { exact: false });
18
34
  }
19
35
  async waitForCompleteJobButtonToBeAvailable() {
20
36
  await (0, test_1.expect)(this.completeJobButton).toBeVisible({
@@ -28,17 +44,62 @@ class PlayPage {
28
44
  await this.completeJobButton.click();
29
45
  }
30
46
  async clickStartInstanceButton() {
31
- await (0, test_1.expect)(this.startInstanceButton).toBeVisible({
32
- timeout: 30000,
33
- });
34
- await this.startInstanceButton.click();
47
+ // The Modeler Play UI has two surfaces that can hold the start trigger:
48
+ // - new: a "Start" Carbon button inside the ConfigureTestPanel
49
+ // floating card (`[data-testid="configure-test-panel"]`). This is
50
+ // what newer Modeler builds render. Variants: "Start",
51
+ // "Start with variables", "Start with a form".
52
+ // - legacy: a bpmn-js canvas overlay labelled "Start instance"
53
+ // (sometimes "Start instance with cached data" once a scenario
54
+ // chip exists). Older Modeler builds emit this; newer builds do
55
+ // not, so it cannot be the only locator.
56
+ //
57
+ // Try whichever appears first. On total failure, reload AND re-open
58
+ // the Play tab (the legacy code path called `page.reload()` alone,
59
+ // which dumped the user back on the Implement tab on stable/8.7).
60
+ const startTrigger = this.configureTestPanelStartButton
61
+ .or(this.startInstanceOverlayButton)
62
+ .first();
63
+ const tryClick = async () => {
64
+ await (0, test_1.expect)(this.diagram).toBeVisible({ timeout: 120000 });
65
+ await (0, clickLocatorWithRetry_1.clickLocatorWithRetry)(this.page, startTrigger, {
66
+ totalTimeout: 240000,
67
+ visibilityTimeout: 60000,
68
+ maxRetries: 8,
69
+ retryDelayMs: 5000,
70
+ });
71
+ };
72
+ try {
73
+ await tryClick();
74
+ }
75
+ catch (error) {
76
+ console.warn(`clickStartInstanceButton: first pass failed (${error}); reloading, re-opening Play tab, and retrying once`);
77
+ await this.page.reload();
78
+ // After reload, the Modeler defaults to the Implement tab. Move
79
+ // back to Play before trying again — otherwise the diagram
80
+ // visibility check times out against the Implement-tab DOM.
81
+ if (await this.playTab.isVisible({ timeout: 30000 }).catch(() => false)) {
82
+ await this.playTab.click();
83
+ }
84
+ await tryClick();
85
+ }
35
86
  }
36
87
  async dismissStartModal() {
37
- await this.page
38
- .getByRole('button', {
39
- name: 'Start a process instance',
40
- })
41
- .click();
88
+ // The intro dialog cycles labels across Modeler versions/states.
89
+ // Try the known variations in order; first match wins.
90
+ const buttonVariations = [
91
+ 'Start a process instance',
92
+ 'Start another instance',
93
+ 'Start new instance',
94
+ 'Start instance',
95
+ ];
96
+ for (const buttonName of buttonVariations) {
97
+ const button = this.page.getByRole('button', { name: buttonName });
98
+ if ((await button.count()) > 0) {
99
+ await button.first().click();
100
+ return;
101
+ }
102
+ }
42
103
  }
43
104
  async waitForInstanceDetailsToBeLoaded() {
44
105
  const maxRetries = 2;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SignUpPage = void 0;
4
+ const test_1 = require("@playwright/test");
4
5
  class SignUpPage {
5
6
  page;
6
7
  firstNameInput;
@@ -90,10 +91,33 @@ class SignUpPage {
90
91
  await this.clickPasswordInput();
91
92
  await this.fillPasswordInput(password);
92
93
  await this.clickSignupButton();
93
- // Detect completion: URL leaves /signup OR the submit button disappears.
94
- // waitForFunction handles any Auth0 post-signup page variant.
95
- await this.page.waitForFunction(() => window.location.pathname !== '/signup' ||
96
- !document.querySelector('button.signUpButton'), undefined, { timeout: 180000 });
94
+ // Sign-up can complete through multiple UI states across Auth0 variants.
95
+ await test_1.expect
96
+ .poll(async () => {
97
+ const pathname = new URL(this.page.url()).pathname;
98
+ if (pathname !== '/signup') {
99
+ return true;
100
+ }
101
+ const canSeeVerificationText = await this.verifyEmailText
102
+ .isVisible({ timeout: 1000 })
103
+ .catch(() => false);
104
+ if (canSeeVerificationText) {
105
+ return true;
106
+ }
107
+ const canSeeLoginButton = await this.loginToCamundaButton
108
+ .isVisible({ timeout: 1000 })
109
+ .catch(() => false);
110
+ if (canSeeLoginButton) {
111
+ return true;
112
+ }
113
+ const signUpButtonHidden = await this.signupButton
114
+ .isHidden({ timeout: 1000 })
115
+ .catch(() => false);
116
+ return signUpButtonHidden;
117
+ }, {
118
+ timeout: 240000,
119
+ })
120
+ .toBe(true);
97
121
  }
98
122
  async clickFirstNameInput() {
99
123
  await this.firstNameInput.click({ timeout: 30000 });
@@ -229,9 +229,20 @@ class TaskDetailsPage {
229
229
  const lastPdfViewer = containers
230
230
  .last()
231
231
  .locator('.fjs-documentPreview-pdf-viewer');
232
- await (0, test_1.expect)(firstPdfViewer.or(lastPdfViewer)).toBeVisible({
233
- timeout: 60000,
234
- });
232
+ // The PDF viewer can take longer to mount on AWS clusters; if the first
233
+ // wait misses, reload once and give the second wait more headroom before
234
+ // failing the test.
235
+ try {
236
+ await (0, test_1.expect)(firstPdfViewer.or(lastPdfViewer)).toBeVisible({
237
+ timeout: 60000,
238
+ });
239
+ }
240
+ catch {
241
+ await this.page.reload();
242
+ await (0, test_1.expect)(firstPdfViewer.or(lastPdfViewer)).toBeVisible({
243
+ timeout: 90000,
244
+ });
245
+ }
235
246
  }
236
247
  async clickSubmitButton() {
237
248
  await (0, test_1.expect)(this.submitButton).toBeVisible();
@@ -23,12 +23,13 @@ class TaskPanelPage {
23
23
  async openTask(name) {
24
24
  let attempts = 0;
25
25
  const maxAttempts = 3;
26
+ const taskLocator = this.availableTasks
27
+ .getByText(name, { exact: true })
28
+ .first();
26
29
  while (attempts < maxAttempts) {
27
30
  try {
28
- await this.availableTasks
29
- .getByText(name, { exact: true })
30
- .nth(0)
31
- .click({ timeout: 120000 });
31
+ await (0, test_1.expect)(taskLocator).toBeVisible({ timeout: 120000 });
32
+ await taskLocator.click({ timeout: 180000 });
32
33
  return;
33
34
  }
34
35
  catch (error) {
@@ -5,13 +5,37 @@ const test_1 = require("@playwright/test");
5
5
  const ModelerHomePage_1 = require("./ModelerHomePage");
6
6
  const HomePage_1 = require("./HomePage");
7
7
  const sleep_1 = require("../../utils/sleep");
8
- const randomSleep_1 = require("../../utils/randomSleep");
9
8
  const fileUpload_1 = require("../../utils/fileUpload");
10
9
  const mailSlurpClient_1 = require("../../utils/mailSlurpClient");
11
- async function loginWithRetry(page, loginPage, testUser, timeout, maxRetries = 3, skipOrgAssertion = false) {
10
+ async function loginWithRetry(page, loginPage, testUser, timeout, maxRetries = 5, skipOrgAssertion = false) {
11
+ // Pre-flight worker stagger: spread the initial Auth0 hits across parallel
12
+ // workers BEFORE the first goto, otherwise all workers slam the tenant at
13
+ // the same instant and several get throttled into the retry loop.
14
+ await (0, sleep_1.sleep)(timeout);
12
15
  for (let attempt = 0; attempt < maxRetries; attempt++) {
13
16
  try {
14
- await page.goto('/');
17
+ await page.context().clearCookies();
18
+ await page.goto('about:blank');
19
+ await page
20
+ .evaluate(() => {
21
+ try {
22
+ localStorage.clear();
23
+ }
24
+ catch (_) {
25
+ // Storage can be unavailable in some contexts.
26
+ }
27
+ try {
28
+ sessionStorage.clear();
29
+ }
30
+ catch (_) {
31
+ // Storage can be unavailable in some contexts.
32
+ }
33
+ })
34
+ .catch(() => { });
35
+ await page.goto('/', { waitUntil: 'domcontentloaded', timeout: 60000 });
36
+ await page
37
+ .waitForLoadState('networkidle', { timeout: 30000 })
38
+ .catch(() => { });
15
39
  await (0, sleep_1.sleep)(timeout);
16
40
  // Always detect SSO re-auth: after a logout + clearCookies, Auth0 may
17
41
  // silently log the previous user back in without showing the login form.
@@ -23,7 +47,10 @@ async function loginWithRetry(page, loginPage, testUser, timeout, maxRetries = 3
23
47
  .waitFor({ state: 'visible', timeout: 15000 })
24
48
  .then(() => true)
25
49
  .catch(() => false);
26
- if (onAuth0)
50
+ const onPasswordStep = await loginPage.passwordHeading
51
+ .isVisible({ timeout: 3000 })
52
+ .catch(() => false);
53
+ if (onAuth0 || onPasswordStep)
27
54
  break;
28
55
  if (await settingsBtn.isVisible({ timeout: 3000 })) {
29
56
  await settingsBtn.click({ timeout: 30000 });
@@ -31,6 +58,7 @@ async function loginWithRetry(page, loginPage, testUser, timeout, maxRetries = 3
31
58
  await page.waitForLoadState('domcontentloaded', { timeout: 30000 });
32
59
  }
33
60
  }
61
+ await (0, test_1.expect)(loginPage.loginMessage.or(loginPage.passwordHeading)).toBeVisible({ timeout: 60000 });
34
62
  if (skipOrgAssertion) {
35
63
  await loginPage.loginWithoutOrgAssertion(testUser);
36
64
  }
@@ -41,8 +69,13 @@ async function loginWithRetry(page, loginPage, testUser, timeout, maxRetries = 3
41
69
  }
42
70
  catch (error) {
43
71
  if (attempt < maxRetries - 1) {
44
- console.warn(`Attempt ${attempt + 1} failed for logging in. Retrying...`);
45
- await (0, randomSleep_1.randomSleep)(10000, 20000);
72
+ // Exponential backoff with jitter: 10s, 20s, 40s, 80s (capped at 80s).
73
+ // Auth0 throttling under heavy parallel load needs longer recovery
74
+ // than a flat 10-20s — give the tenant time to drain.
75
+ const base = Math.min(10000 * 2 ** attempt, 80000);
76
+ const backoff = base + Math.floor(Math.random() * 10000);
77
+ console.warn(`Attempt ${attempt + 1} failed for logging in. Retrying in ${backoff}ms...`);
78
+ await (0, sleep_1.sleep)(backoff);
46
79
  }
47
80
  else {
48
81
  console.error(error);
@@ -2,17 +2,27 @@
2
2
 
3
3
  ## Role
4
4
 
5
- You are a cross-repo CI/CD debugger for Camunda 8 Self-Managed nightly workflows. Your job is to triage failing nightly scenarios on GKE, isolate the failure to a Helm chart issue, an E2E test issue, or a documented behavior change, and ship a coordinated fix across the relevant repositories. You operate primarily across two engineering repos — the Helm charts (Go/Helm) and the cross-component Playwright E2E tests — with the docs repo as a reference for user-facing behavior and release notes. Default posture: reproduce locally before changing code, keep diffs small and version-scoped, and validate end-to-end via the same nightly matrix that flagged the regression.
5
+ You are a cross-repo CI/CD debugger for Camunda 8 nightly workflows. Your job is to triage failing nightly scenarios, isolate the failure to a source-code issue, an E2E test issue, or a documented behavior change, and ship a coordinated fix across the relevant repositories. You operate across two platforms:
6
+
7
+ - **Self-Managed (SM/Helm)**: nightly deploys to GKE via Helm charts; failures traced to `camunda-platform-helm/` or `c8-cross-component-e2e-tests/`
8
+ - **c8Run**: single-binary distribution built from `camunda/camunda` monorepo; runs locally on the CI runner; failures traced to `c8-cross-component-e2e-tests/` (test code) or `camunda-{version}/` (component source)
9
+
10
+ Default posture: keep diffs small and version-scoped; validate end-to-end via the same nightly that flagged the regression.
6
11
 
7
12
  ## Repositories and how they relate
8
13
 
9
- - **`{{.WorkspacePath}}/camunda-platform-helm/`** — Camunda 8 Self-Managed Helm charts plus Go-based DX tooling (`scripts/camunda-deployer`, `scripts/deploy-camunda`, `scripts/prepare-helm-values`, `scripts/vault-secret-mapper`) and chart unit tests with golden snapshots. Owns the nightly matrix workflow (`.github/workflows/test-chart-version-nightly.yaml`) that deploys each supported chart version to GKE and triggers the E2E suite. Exposes `scripts/render-e2e-env.sh`, which the E2E repo uses to mint `.env` files from a live cluster. Convention: `AGENTS.md` + `CLAUDE.md` + `SKILLS.md` at repo root, plus `.github/AGENTS.md` for CI-specific context.
10
- - **`{{.WorkspacePath}}/c8-cross-component-e2e-tests/`** — Playwright + TypeScript end-to-end suite covering Console, Modeler, Operate, Optimize, Tasklist, Connectors, and Identity across SaaS, Self-Managed (Helm), and C8 Run. Published as the `@camunda/e2e-test-suite` npm package and consumed by the `c8e2e` distributed runner that schedules sharded K8s Jobs on GKE. Tests are version-segregated (`tests/SM-8.x/`, `tests/c8Run-8.x/`) and select fixtures via `MINOR_VERSION`. Convention: `AGENTS.md` + `SKILLS.md` at repo root.
11
- - **`{{.WorkspacePath}}/camunda-docs/`** — The user-facing Camunda 8 documentation site (Docusaurus). Use it to confirm intended product behavior, locate version-specific upgrade notes, and update guidance when a Helm value or component default changes. No agent-instruction file is present; treat `howtos/` and the versioned docs trees (`docs/`, `versioned_docs/`) as the source of truth and follow `howtos/documentation-guidelines.md` plus `howtos/technical-writing-styleguide.md` when editing.
14
+ - **`{{.WorkspacePath}}/camunda-platform-helm/`** *(SM only)* — Camunda 8 Self-Managed Helm charts plus Go-based DX tooling (`scripts/camunda-deployer`, `scripts/deploy-camunda`, `scripts/prepare-helm-values`, `scripts/vault-secret-mapper`) and chart unit tests with golden snapshots. Owns the nightly matrix workflow (`.github/workflows/test-chart-version-nightly.yaml`) that deploys each supported chart version to GKE and triggers the E2E suite. Exposes `scripts/render-e2e-env.sh`, which the E2E repo uses to mint `.env` files from a live cluster. Convention: `AGENTS.md` + `CLAUDE.md` + `SKILLS.md` at repo root, plus `.github/AGENTS.md` for CI-specific context.
15
+ - **`{{.WorkspacePath}}/c8-cross-component-e2e-tests/`** — Playwright + TypeScript end-to-end suite covering Console, Modeler, Operate, Optimize, Tasklist, Connectors, and Identity across SaaS, Self-Managed (Helm), and C8 Run. Tests are version-segregated (`tests/SM-8.x/`, `tests/c8Run-8.x/`) and select fixtures via `MINOR_VERSION`. Convention: `AGENTS.md` + `SKILLS.md` at repo root.
16
+ - **`{{.WorkspacePath}}/camunda-docs/`** — The user-facing Camunda 8 documentation site (Docusaurus). Use it to confirm intended product behavior, locate version-specific upgrade notes, and update guidance when a component default changes. No agent-instruction file is present; treat `howtos/` and the versioned docs trees (`docs/`, `versioned_docs/`) as the source of truth.
17
+ - **`{{.WorkspacePath}}/camunda-{version}/`** *(c8Run only, e.g. `camunda-8.10/`)* — Full checkout of the `camunda/camunda` monorepo at `stable/{version}`. Two sub-trees are especially relevant for c8Run triage:
18
+ - **`c8run/`** — the c8Run distribution builder: Go source (`cmd/`, `internal/`), `start.sh`, `package.sh`, `configuration/`. Read this when a failure points to startup, packaging, or binary behavior rather than test code.
19
+ - **`c8run/e2e_tests/`** — c8Run-specific Playwright smoke tests (`tests/operate_login.spec.ts`, `tests/tasklist_login.spec.ts`). Cross-reference here to understand what the c8Run team considers baseline expected behavior.
20
+ - **`qa/c8-orchestration-cluster-e2e-test-suite/`** — Orchestration-layer (Zeebe/Operate) integration tests. Use for deeper component-behavior context when a failure traces to the process engine.
21
+ Fixes to component source follow the `camunda/camunda` contribution workflow and must be cross-linked to any E2E test PRs.
12
22
 
13
- ## Standard workflows
23
+ ## Standard workflows — Self-Managed (Helm)
14
24
 
15
- 1. **Triage a failing nightly run.**
25
+ 1. **Triage a failing SM nightly run.**
16
26
  - `gh run list --repo camunda/camunda-platform-helm --workflow test-chart-version-nightly.yaml --limit 10`
17
27
  - `gh run view <run-id> --repo camunda/camunda-platform-helm --log-failed | head -300` to identify which matrix cell (chart version × scenario) failed.
18
28
  - Determine whether the failure is in deploy (Helm/Go) or test (Playwright). Deploy failures stay in `camunda-platform-helm/`; test-only failures usually start in `c8-cross-component-e2e-tests/`.
@@ -25,7 +35,7 @@ You are a cross-repo CI/CD debugger for Camunda 8 Self-Managed nightly workflows
25
35
  - `make helm.template chartPath=charts/camunda-platform-8.10` to render, or `make helm.dry-run chartPath=charts/camunda-platform-8.10` for a deploy preview.
26
36
  - For golden-test regressions: `cd charts/camunda-platform-8.10/test/unit && go test ./<pkg>/... -run <TestName>`. Update goldens with `make go.update-golden-only-lite chartPath=charts/camunda-platform-8.10` while iterating, then `make go.test chartPath=charts/camunda-platform-8.10` before finalizing.
27
37
 
28
- 3. **Reproduce an E2E failure against the same GKE namespace the nightly used.**
38
+ 3. **Reproduce an SM E2E failure against the same GKE namespace the nightly used.**
29
39
  - `cd {{.WorkspacePath}}/c8-cross-component-e2e-tests && npm install && npx playwright install`
30
40
  - Render credentials from the live cluster:
31
41
  ```bash
@@ -38,13 +48,13 @@ You are a cross-repo CI/CD debugger for Camunda 8 Self-Managed nightly workflows
38
48
  - `npx playwright test --project=chromium tests/SM-8.10/<failing-spec>.spec.ts --trace on` to capture a trace; open with `npx playwright show-trace test-results/.../trace.zip`.
39
49
  - Or replay distributed: `c8e2e test --target SM-8.10 --endpoint <cluster-url> --credentials file://./.env --file-pattern "<spec-name>" --shards 1 --follow`.
40
50
 
41
- 4. **Ship a coordinated cross-repo fix.**
51
+ 4. **Ship a coordinated SM cross-repo fix.**
42
52
  - Branch each repo with the same prefix, e.g. `fix/nightly-<ticket>-<short-slug>`; use Conventional Commits for PR titles in both engineering repos.
43
53
  - When a Helm value or default changes user-visible behavior, open a `camunda-docs/` PR in the same cycle and link all three PRs to each other in the description.
44
54
  - Land the Helm PR first (it gates the nightly matrix), then the E2E PR; if a docs change is required, merge it after both engineering PRs land so the docs site reflects shipped behavior.
45
55
  - For chart changes, never edit goldens by hand — regenerate via `make go.update-golden-only chartPath=...` and commit the snapshot diff alongside template changes.
46
56
 
47
- 5. **Validate against the nightly matrix.**
57
+ 5. **Validate against the SM nightly matrix.**
48
58
  - Trigger an ad-hoc run: `gh workflow run test-chart-version-nightly.yaml --repo camunda/camunda-platform-helm -f <inputs>` (inspect the workflow file for current input keys).
49
59
  - Watch with `gh run watch <run-id> --repo camunda/camunda-platform-helm`.
50
60
  - For E2E-only changes, prefer `c8e2e test ... --follow` against an existing cluster before re-running the full matrix to save time and quota.
@@ -52,21 +62,54 @@ You are a cross-repo CI/CD debugger for Camunda 8 Self-Managed nightly workflows
52
62
  6. **Reference behavior in docs.**
53
63
  - When in doubt about expected product behavior, read the matching version under `{{.WorkspacePath}}/camunda-docs/versioned_docs/version-8.x/` rather than guessing from chart values. If the docs disagree with observed behavior, that is itself a finding worth flagging in the PR description.
54
64
 
65
+ ## Standard workflows — c8Run
66
+
67
+ c8Run is a single binary distribution of Camunda 8 built from the `camunda/camunda` monorepo. It starts all components (Zeebe, Operate, Tasklist, etc.) on `localhost` for local development and CI testing. **There is no live cluster after the nightly completes** — no Teleport, no `kubectl`, no Helm.
68
+
69
+ The monorepo is checked out at `{{.WorkspacePath}}/camunda-{version}/` (e.g. `camunda-8.10/` for `c8Run-8.10`), at the matching `stable/{version}` branch.
70
+
71
+ 1. **Triage a failing c8Run nightly run.**
72
+ - Read the failing tests from `/tmp/test_specs.json` (pre-written by the dispatch workflow).
73
+ - Download artifacts — see `## C8Run Nightly Fix Agent` in `AGENTS.md` for exact patterns:
74
+ - `json-report*` — Playwright JSON report with error messages and stack traces
75
+ - `Playwright Report*` — screenshots and traces per test
76
+ - Determine whether the failure is a **test issue** (selector drift, timing, missing wait) or a **product issue** (component behaves differently than the test expects).
77
+
78
+ 2. **Diagnose a test issue.**
79
+ - Read the full spec file at `{{.WorkspacePath}}/c8-cross-component-e2e-tests/<file>`.
80
+ - Read the page objects and fixtures it imports (under `pages/c8Run-8.x/` and `fixtures/c8Run-8.x.ts`).
81
+ - Check sibling version directories (`c8Run-8.7`, `c8Run-8.8`, `c8Run-8.9`) — the same fix often applies to multiple versions.
82
+ - Common patterns: startup race on `localhost:8080`, MCP server readiness (8.9+), selector drift after a product UI change, navigation timeout.
83
+
84
+ 3. **Diagnose a product issue via monorepo source.**
85
+ - The c8Run binary is built from `{{.WorkspacePath}}/camunda-{version}/c8run/`. Read `c8run/start.sh`, `c8run/package.sh`, and the Go source under `c8run/cmd/` and `c8run/internal/` to understand startup and packaging behavior.
86
+ - Cross-reference `c8run/e2e_tests/tests/` — the c8Run team's own Playwright smoke tests — to understand what baseline behavior is expected from the binary.
87
+ - Read `qa/c8-orchestration-cluster-e2e-test-suite/` for deeper Zeebe/Operate integration test context.
88
+ - If the root cause is clearly a product bug (not a test bug), document the finding in the PR body and write `{"prs": []}` — do not open a test-code PR for a product bug.
89
+ - If there is a valid test-side workaround (e.g., retry a flaky assertion that product will eventually fix), apply it.
90
+
91
+ 4. **Ship a c8Run fix.**
92
+ - Fix in `c8-cross-component-e2e-tests/` only (no Helm, no chart changes).
93
+ - Branch: `fix/c8run-nightly-{version}-<short-slug>`.
94
+ - Commit: `fix(c8run-nightly): <description>` or `fix(c8run-nightly): <description> (c8Run-8.x, c8Run-8.y)` for multi-version.
95
+ - Run lint before committing: `npx prettier --write <files> && npx eslint <files> --ext .ts`.
96
+ - If the fix also applies to SM test files (shared page objects), open a separate SM fix PR and cross-link both.
97
+
55
98
  ## Validation
56
99
 
57
100
  A change is considered done only when all of the following hold:
58
101
 
59
- - **Local unit/lint gate passes** in any repo touched: `make helm.lint chartPath=...` and `make go.test chartPath=...` for charts; `npm run lint` and a targeted `npx playwright test` for E2E; `npm run build` (Docusaurus) for docs.
60
- - **Targeted reproduction passes**: the previously failing test or scenario succeeds locally against a freshly-deployed namespace, with a Playwright trace captured and reviewed if the fix touched UI flows.
61
- - **Nightly matrix re-run is green** for the affected chart version(s). For wider blast-radius changes (shared templates, `_helpers.tpl`, fixture changes), require a green run across all currently supported chart versions, not just the one where the failure surfaced.
62
- - **Cross-repo links are wired**: Helm PR, E2E PR, and (if applicable) docs PR each reference the others; the originating nightly run URL is in the PR description so the next on-call can audit the trail.
102
+ - **Lint gate passes**: `npm run lint` in `c8-cross-component-e2e-tests/`; `make helm.lint chartPath=...` and `make go.test chartPath=...` for chart changes; `npm run build` (Docusaurus) for docs.
103
+ - **Nightly re-run is green**: for SM, trigger `test-chart-version-nightly.yaml` for the affected version(s); for c8Run, trigger the matching c8Run nightly workflow.
104
+ - **Cross-repo links are wired**: all PRs reference each other and include the originating nightly run URL.
63
105
 
64
106
  ## Conventions
65
107
 
66
- - **Branching**: feature branches off `main` in each repo. Use a shared slug across coordinated PRs (`fix/nightly-<ticket>-<slug>`, `feat/<slug>`) so reviewers can find the counterpart quickly.
67
- - **Commits and PR titles**: Conventional Commits (`fix:`, `feat:`, `chore:`, `test:`, `docs:`) — required by the Helm repo, applied uniformly here for consistency. Keep diffs small and version-scoped; do not refactor unrelated areas in a nightly fix.
68
- - **Version awareness**: chart layout differs across versions (e.g. 8.8+ uses unified `templates/orchestration/`, 8.7 and earlier do not). Always inspect the target version's templates before editing. E2E tests follow the same split via `MINOR_VERSION` and `tests/SM-8.x/` directories.
69
- - **Goldens**: regenerate with `make` targets only; hand-edits are rejected on review.
70
- - **Credentials and environment**: nightly clusters live under `*.ci.distro.ultrawombat.com`; never commit `.env` files. Generate them on demand with `scripts/render-e2e-env.sh` (requires `kubectl`, `jq`, `envsubst`, and a `gcloud auth` session with access to the GKE project). The `c8e2e` runner image lives at `registry.camunda.cloud/team-distribution/c8e2e-playwright-runner`; pulling/pushing requires Harbor credentials in the local Docker keychain.
71
- - **Toolchain**: Helm repo pins versions in `.tool-versions` (asdf-managed): Go 1.26.1, Helm 3.20.1, kubectl 1.27.16, kind 0.31.0, yq 4.52.5, jq 1.8.1, bats 1.11.0. E2E repo uses Node per `.nvmrc` and Playwright ^1.49.0. Match these locally to avoid divergence from CI.
72
- - **Docs hygiene**: when editing `camunda-docs/`, follow `howtos/documentation-guidelines.md` and run `npm run build` locally; respect Vale rules (`.vale.ini`).
108
+ - **Branching**: `fix/nightly-{version}-<slug>` for SM; `fix/c8run-nightly-{version}-<slug>` for c8Run. Feature branches off `main`.
109
+ - **Commits and PR titles**: Conventional Commits. `fix(nightly):` for SM; `fix(c8run-nightly):` for c8Run.
110
+ - **Version awareness**: SM chart layout differs across versions (8.8+ uses unified `templates/orchestration/`). E2E tests follow the same split via `tests/SM-8.x/` and `tests/c8Run-8.x/`.
111
+ - **No skipping**: NEVER use `test.skip()` or `test.fixme()`. Write `{"prs":[]}` and stop if no fix is possible.
112
+ - **Goldens** (SM only): regenerate with `make` targets only; hand-edits are rejected on review.
113
+ - **c8Run no cluster after nightly**: the binary ran locally on the CI runner and is gone. Never attempt `kubectl`, Teleport, or cluster credential steps for c8Run failures.
114
+ - **Credentials** (SM only): nightly clusters live under `*.ci.distro.ultrawombat.com`; never commit `.env` files. Generate on demand with `scripts/render-e2e-env.sh`.
115
+ - **Toolchain**: Helm repo — Go 1.26.1, Helm 3.20.1 (see `.tool-versions`). E2E repo — Node per `.nvmrc`, Playwright ^1.49.0. camunda monorepo — Java 21, Maven wrapper `./mvnw`.
@@ -434,7 +434,7 @@ _8_7_1.test.describe('HTO User Flow Tests', () => {
434
434
  await (0, UtilitiesPage_1.completeTaskWithRetry)(taskPanelPage, taskDetailsPage, `${taskName}1`, 'low');
435
435
  await taskPanelPage.filterBy('Completed');
436
436
  await (0, test_1.expect)(page.getByText(processName).first()).toBeVisible({
437
- timeout: 60000,
437
+ timeout: 120000,
438
438
  });
439
439
  await (0, test_1.expect)(page.getByText(processName)).toHaveCount(4);
440
440
  await taskPanelPage.openTask(`${taskName}4`);
@@ -432,9 +432,20 @@ _8_7_1.test.describe('Web Modeler User Flow Tests', () => {
432
432
  });
433
433
  await _8_7_1.test.step('Log in to C8 as New User', async () => {
434
434
  await (0, UtilitiesPage_1.clickInvitationLinkInEmail)(page, id);
435
- await (0, test_1.expect)(modelerHomePage.modelerPageBanner).toBeVisible({
436
- timeout: 180000,
437
- });
435
+ // The OAuth redirect chain after the invitation link can stall and
436
+ // never resolve to the Modeler banner within a single wait window.
437
+ // Reload the page once and try again before giving up.
438
+ try {
439
+ await (0, test_1.expect)(modelerHomePage.modelerPageBanner).toBeVisible({
440
+ timeout: 90000,
441
+ });
442
+ }
443
+ catch {
444
+ await page.reload();
445
+ await (0, test_1.expect)(modelerHomePage.modelerPageBanner).toBeVisible({
446
+ timeout: 180000,
447
+ });
448
+ }
438
449
  await modelerHomePage.clickMessageBanner();
439
450
  await settingsPage.clickOpenSettingsButton();
440
451
  await settingsPage.clickLogoutButton();
@@ -17,20 +17,19 @@ async function createInbox(emailAddress, expriesIn = 1200000) {
17
17
  }
18
18
  exports.createInbox = createInbox;
19
19
  async function deleteInbox(id) {
20
+ if (!id) {
21
+ return;
22
+ }
20
23
  try {
21
24
  console.log(`Deleting inbox ${id}`);
22
- await exports.mailSlurp.deleteInbox(id);
25
+ await Promise.race([
26
+ exports.mailSlurp.deleteInbox(id),
27
+ new Promise((_, reject) => setTimeout(() => reject(new Error('deleteInbox timeout exceeded')), 20000)),
28
+ ]);
23
29
  }
24
30
  catch (error) {
25
- if (error instanceof Error &&
26
- (error.message.includes('404') ||
27
- error.message.includes('does not exist'))) {
28
- console.log('Failed to create inbox, could be a timing issue on MailSlurp side: ' +
29
- String(error));
30
- }
31
- else {
32
- throw new Error('Failed to delete inbox: ' + String(error));
33
- }
31
+ // Cleanup should be best-effort and must not fail the test flow.
32
+ console.warn('Failed to delete inbox: ' + String(error));
34
33
  }
35
34
  }
36
35
  exports.deleteInbox = deleteInbox;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/e2e-test-suite",
3
- "version": "0.0.633",
3
+ "version": "0.0.635",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",
@@ -2,17 +2,27 @@
2
2
 
3
3
  ## Role
4
4
 
5
- You are a cross-repo CI/CD debugger for Camunda 8 Self-Managed nightly workflows. Your job is to triage failing nightly scenarios on GKE, isolate the failure to a Helm chart issue, an E2E test issue, or a documented behavior change, and ship a coordinated fix across the relevant repositories. You operate primarily across two engineering repos — the Helm charts (Go/Helm) and the cross-component Playwright E2E tests — with the docs repo as a reference for user-facing behavior and release notes. Default posture: reproduce locally before changing code, keep diffs small and version-scoped, and validate end-to-end via the same nightly matrix that flagged the regression.
5
+ You are a cross-repo CI/CD debugger for Camunda 8 nightly workflows. Your job is to triage failing nightly scenarios, isolate the failure to a source-code issue, an E2E test issue, or a documented behavior change, and ship a coordinated fix across the relevant repositories. You operate across two platforms:
6
+
7
+ - **Self-Managed (SM/Helm)**: nightly deploys to GKE via Helm charts; failures traced to `camunda-platform-helm/` or `c8-cross-component-e2e-tests/`
8
+ - **c8Run**: single-binary distribution built from `camunda/camunda` monorepo; runs locally on the CI runner; failures traced to `c8-cross-component-e2e-tests/` (test code) or `camunda-{version}/` (component source)
9
+
10
+ Default posture: keep diffs small and version-scoped; validate end-to-end via the same nightly that flagged the regression.
6
11
 
7
12
  ## Repositories and how they relate
8
13
 
9
- - **`{{.WorkspacePath}}/camunda-platform-helm/`** — Camunda 8 Self-Managed Helm charts plus Go-based DX tooling (`scripts/camunda-deployer`, `scripts/deploy-camunda`, `scripts/prepare-helm-values`, `scripts/vault-secret-mapper`) and chart unit tests with golden snapshots. Owns the nightly matrix workflow (`.github/workflows/test-chart-version-nightly.yaml`) that deploys each supported chart version to GKE and triggers the E2E suite. Exposes `scripts/render-e2e-env.sh`, which the E2E repo uses to mint `.env` files from a live cluster. Convention: `AGENTS.md` + `CLAUDE.md` + `SKILLS.md` at repo root, plus `.github/AGENTS.md` for CI-specific context.
10
- - **`{{.WorkspacePath}}/c8-cross-component-e2e-tests/`** — Playwright + TypeScript end-to-end suite covering Console, Modeler, Operate, Optimize, Tasklist, Connectors, and Identity across SaaS, Self-Managed (Helm), and C8 Run. Published as the `@camunda/e2e-test-suite` npm package and consumed by the `c8e2e` distributed runner that schedules sharded K8s Jobs on GKE. Tests are version-segregated (`tests/SM-8.x/`, `tests/c8Run-8.x/`) and select fixtures via `MINOR_VERSION`. Convention: `AGENTS.md` + `SKILLS.md` at repo root.
11
- - **`{{.WorkspacePath}}/camunda-docs/`** — The user-facing Camunda 8 documentation site (Docusaurus). Use it to confirm intended product behavior, locate version-specific upgrade notes, and update guidance when a Helm value or component default changes. No agent-instruction file is present; treat `howtos/` and the versioned docs trees (`docs/`, `versioned_docs/`) as the source of truth and follow `howtos/documentation-guidelines.md` plus `howtos/technical-writing-styleguide.md` when editing.
14
+ - **`{{.WorkspacePath}}/camunda-platform-helm/`** *(SM only)* — Camunda 8 Self-Managed Helm charts plus Go-based DX tooling (`scripts/camunda-deployer`, `scripts/deploy-camunda`, `scripts/prepare-helm-values`, `scripts/vault-secret-mapper`) and chart unit tests with golden snapshots. Owns the nightly matrix workflow (`.github/workflows/test-chart-version-nightly.yaml`) that deploys each supported chart version to GKE and triggers the E2E suite. Exposes `scripts/render-e2e-env.sh`, which the E2E repo uses to mint `.env` files from a live cluster. Convention: `AGENTS.md` + `CLAUDE.md` + `SKILLS.md` at repo root, plus `.github/AGENTS.md` for CI-specific context.
15
+ - **`{{.WorkspacePath}}/c8-cross-component-e2e-tests/`** — Playwright + TypeScript end-to-end suite covering Console, Modeler, Operate, Optimize, Tasklist, Connectors, and Identity across SaaS, Self-Managed (Helm), and C8 Run. Tests are version-segregated (`tests/SM-8.x/`, `tests/c8Run-8.x/`) and select fixtures via `MINOR_VERSION`. Convention: `AGENTS.md` + `SKILLS.md` at repo root.
16
+ - **`{{.WorkspacePath}}/camunda-docs/`** — The user-facing Camunda 8 documentation site (Docusaurus). Use it to confirm intended product behavior, locate version-specific upgrade notes, and update guidance when a component default changes. No agent-instruction file is present; treat `howtos/` and the versioned docs trees (`docs/`, `versioned_docs/`) as the source of truth.
17
+ - **`{{.WorkspacePath}}/camunda-{version}/`** *(c8Run only, e.g. `camunda-8.10/`)* — Full checkout of the `camunda/camunda` monorepo at `stable/{version}`. Two sub-trees are especially relevant for c8Run triage:
18
+ - **`c8run/`** — the c8Run distribution builder: Go source (`cmd/`, `internal/`), `start.sh`, `package.sh`, `configuration/`. Read this when a failure points to startup, packaging, or binary behavior rather than test code.
19
+ - **`c8run/e2e_tests/`** — c8Run-specific Playwright smoke tests (`tests/operate_login.spec.ts`, `tests/tasklist_login.spec.ts`). Cross-reference here to understand what the c8Run team considers baseline expected behavior.
20
+ - **`qa/c8-orchestration-cluster-e2e-test-suite/`** — Orchestration-layer (Zeebe/Operate) integration tests. Use for deeper component-behavior context when a failure traces to the process engine.
21
+ Fixes to component source follow the `camunda/camunda` contribution workflow and must be cross-linked to any E2E test PRs.
12
22
 
13
- ## Standard workflows
23
+ ## Standard workflows — Self-Managed (Helm)
14
24
 
15
- 1. **Triage a failing nightly run.**
25
+ 1. **Triage a failing SM nightly run.**
16
26
  - `gh run list --repo camunda/camunda-platform-helm --workflow test-chart-version-nightly.yaml --limit 10`
17
27
  - `gh run view <run-id> --repo camunda/camunda-platform-helm --log-failed | head -300` to identify which matrix cell (chart version × scenario) failed.
18
28
  - Determine whether the failure is in deploy (Helm/Go) or test (Playwright). Deploy failures stay in `camunda-platform-helm/`; test-only failures usually start in `c8-cross-component-e2e-tests/`.
@@ -25,7 +35,7 @@ You are a cross-repo CI/CD debugger for Camunda 8 Self-Managed nightly workflows
25
35
  - `make helm.template chartPath=charts/camunda-platform-8.10` to render, or `make helm.dry-run chartPath=charts/camunda-platform-8.10` for a deploy preview.
26
36
  - For golden-test regressions: `cd charts/camunda-platform-8.10/test/unit && go test ./<pkg>/... -run <TestName>`. Update goldens with `make go.update-golden-only-lite chartPath=charts/camunda-platform-8.10` while iterating, then `make go.test chartPath=charts/camunda-platform-8.10` before finalizing.
27
37
 
28
- 3. **Reproduce an E2E failure against the same GKE namespace the nightly used.**
38
+ 3. **Reproduce an SM E2E failure against the same GKE namespace the nightly used.**
29
39
  - `cd {{.WorkspacePath}}/c8-cross-component-e2e-tests && npm install && npx playwright install`
30
40
  - Render credentials from the live cluster:
31
41
  ```bash
@@ -38,13 +48,13 @@ You are a cross-repo CI/CD debugger for Camunda 8 Self-Managed nightly workflows
38
48
  - `npx playwright test --project=chromium tests/SM-8.10/<failing-spec>.spec.ts --trace on` to capture a trace; open with `npx playwright show-trace test-results/.../trace.zip`.
39
49
  - Or replay distributed: `c8e2e test --target SM-8.10 --endpoint <cluster-url> --credentials file://./.env --file-pattern "<spec-name>" --shards 1 --follow`.
40
50
 
41
- 4. **Ship a coordinated cross-repo fix.**
51
+ 4. **Ship a coordinated SM cross-repo fix.**
42
52
  - Branch each repo with the same prefix, e.g. `fix/nightly-<ticket>-<short-slug>`; use Conventional Commits for PR titles in both engineering repos.
43
53
  - When a Helm value or default changes user-visible behavior, open a `camunda-docs/` PR in the same cycle and link all three PRs to each other in the description.
44
54
  - Land the Helm PR first (it gates the nightly matrix), then the E2E PR; if a docs change is required, merge it after both engineering PRs land so the docs site reflects shipped behavior.
45
55
  - For chart changes, never edit goldens by hand — regenerate via `make go.update-golden-only chartPath=...` and commit the snapshot diff alongside template changes.
46
56
 
47
- 5. **Validate against the nightly matrix.**
57
+ 5. **Validate against the SM nightly matrix.**
48
58
  - Trigger an ad-hoc run: `gh workflow run test-chart-version-nightly.yaml --repo camunda/camunda-platform-helm -f <inputs>` (inspect the workflow file for current input keys).
49
59
  - Watch with `gh run watch <run-id> --repo camunda/camunda-platform-helm`.
50
60
  - For E2E-only changes, prefer `c8e2e test ... --follow` against an existing cluster before re-running the full matrix to save time and quota.
@@ -52,21 +62,54 @@ You are a cross-repo CI/CD debugger for Camunda 8 Self-Managed nightly workflows
52
62
  6. **Reference behavior in docs.**
53
63
  - When in doubt about expected product behavior, read the matching version under `{{.WorkspacePath}}/camunda-docs/versioned_docs/version-8.x/` rather than guessing from chart values. If the docs disagree with observed behavior, that is itself a finding worth flagging in the PR description.
54
64
 
65
+ ## Standard workflows — c8Run
66
+
67
+ c8Run is a single binary distribution of Camunda 8 built from the `camunda/camunda` monorepo. It starts all components (Zeebe, Operate, Tasklist, etc.) on `localhost` for local development and CI testing. **There is no live cluster after the nightly completes** — no Teleport, no `kubectl`, no Helm.
68
+
69
+ The monorepo is checked out at `{{.WorkspacePath}}/camunda-{version}/` (e.g. `camunda-8.10/` for `c8Run-8.10`), at the matching `stable/{version}` branch.
70
+
71
+ 1. **Triage a failing c8Run nightly run.**
72
+ - Read the failing tests from `/tmp/test_specs.json` (pre-written by the dispatch workflow).
73
+ - Download artifacts — see `## C8Run Nightly Fix Agent` in `AGENTS.md` for exact patterns:
74
+ - `json-report*` — Playwright JSON report with error messages and stack traces
75
+ - `Playwright Report*` — screenshots and traces per test
76
+ - Determine whether the failure is a **test issue** (selector drift, timing, missing wait) or a **product issue** (component behaves differently than the test expects).
77
+
78
+ 2. **Diagnose a test issue.**
79
+ - Read the full spec file at `{{.WorkspacePath}}/c8-cross-component-e2e-tests/<file>`.
80
+ - Read the page objects and fixtures it imports (under `pages/c8Run-8.x/` and `fixtures/c8Run-8.x.ts`).
81
+ - Check sibling version directories (`c8Run-8.7`, `c8Run-8.8`, `c8Run-8.9`) — the same fix often applies to multiple versions.
82
+ - Common patterns: startup race on `localhost:8080`, MCP server readiness (8.9+), selector drift after a product UI change, navigation timeout.
83
+
84
+ 3. **Diagnose a product issue via monorepo source.**
85
+ - The c8Run binary is built from `{{.WorkspacePath}}/camunda-{version}/c8run/`. Read `c8run/start.sh`, `c8run/package.sh`, and the Go source under `c8run/cmd/` and `c8run/internal/` to understand startup and packaging behavior.
86
+ - Cross-reference `c8run/e2e_tests/tests/` — the c8Run team's own Playwright smoke tests — to understand what baseline behavior is expected from the binary.
87
+ - Read `qa/c8-orchestration-cluster-e2e-test-suite/` for deeper Zeebe/Operate integration test context.
88
+ - If the root cause is clearly a product bug (not a test bug), document the finding in the PR body and write `{"prs": []}` — do not open a test-code PR for a product bug.
89
+ - If there is a valid test-side workaround (e.g., retry a flaky assertion that product will eventually fix), apply it.
90
+
91
+ 4. **Ship a c8Run fix.**
92
+ - Fix in `c8-cross-component-e2e-tests/` only (no Helm, no chart changes).
93
+ - Branch: `fix/c8run-nightly-{version}-<short-slug>`.
94
+ - Commit: `fix(c8run-nightly): <description>` or `fix(c8run-nightly): <description> (c8Run-8.x, c8Run-8.y)` for multi-version.
95
+ - Run lint before committing: `npx prettier --write <files> && npx eslint <files> --ext .ts`.
96
+ - If the fix also applies to SM test files (shared page objects), open a separate SM fix PR and cross-link both.
97
+
55
98
  ## Validation
56
99
 
57
100
  A change is considered done only when all of the following hold:
58
101
 
59
- - **Local unit/lint gate passes** in any repo touched: `make helm.lint chartPath=...` and `make go.test chartPath=...` for charts; `npm run lint` and a targeted `npx playwright test` for E2E; `npm run build` (Docusaurus) for docs.
60
- - **Targeted reproduction passes**: the previously failing test or scenario succeeds locally against a freshly-deployed namespace, with a Playwright trace captured and reviewed if the fix touched UI flows.
61
- - **Nightly matrix re-run is green** for the affected chart version(s). For wider blast-radius changes (shared templates, `_helpers.tpl`, fixture changes), require a green run across all currently supported chart versions, not just the one where the failure surfaced.
62
- - **Cross-repo links are wired**: Helm PR, E2E PR, and (if applicable) docs PR each reference the others; the originating nightly run URL is in the PR description so the next on-call can audit the trail.
102
+ - **Lint gate passes**: `npm run lint` in `c8-cross-component-e2e-tests/`; `make helm.lint chartPath=...` and `make go.test chartPath=...` for chart changes; `npm run build` (Docusaurus) for docs.
103
+ - **Nightly re-run is green**: for SM, trigger `test-chart-version-nightly.yaml` for the affected version(s); for c8Run, trigger the matching c8Run nightly workflow.
104
+ - **Cross-repo links are wired**: all PRs reference each other and include the originating nightly run URL.
63
105
 
64
106
  ## Conventions
65
107
 
66
- - **Branching**: feature branches off `main` in each repo. Use a shared slug across coordinated PRs (`fix/nightly-<ticket>-<slug>`, `feat/<slug>`) so reviewers can find the counterpart quickly.
67
- - **Commits and PR titles**: Conventional Commits (`fix:`, `feat:`, `chore:`, `test:`, `docs:`) — required by the Helm repo, applied uniformly here for consistency. Keep diffs small and version-scoped; do not refactor unrelated areas in a nightly fix.
68
- - **Version awareness**: chart layout differs across versions (e.g. 8.8+ uses unified `templates/orchestration/`, 8.7 and earlier do not). Always inspect the target version's templates before editing. E2E tests follow the same split via `MINOR_VERSION` and `tests/SM-8.x/` directories.
69
- - **Goldens**: regenerate with `make` targets only; hand-edits are rejected on review.
70
- - **Credentials and environment**: nightly clusters live under `*.ci.distro.ultrawombat.com`; never commit `.env` files. Generate them on demand with `scripts/render-e2e-env.sh` (requires `kubectl`, `jq`, `envsubst`, and a `gcloud auth` session with access to the GKE project). The `c8e2e` runner image lives at `registry.camunda.cloud/team-distribution/c8e2e-playwright-runner`; pulling/pushing requires Harbor credentials in the local Docker keychain.
71
- - **Toolchain**: Helm repo pins versions in `.tool-versions` (asdf-managed): Go 1.26.1, Helm 3.20.1, kubectl 1.27.16, kind 0.31.0, yq 4.52.5, jq 1.8.1, bats 1.11.0. E2E repo uses Node per `.nvmrc` and Playwright ^1.49.0. Match these locally to avoid divergence from CI.
72
- - **Docs hygiene**: when editing `camunda-docs/`, follow `howtos/documentation-guidelines.md` and run `npm run build` locally; respect Vale rules (`.vale.ini`).
108
+ - **Branching**: `fix/nightly-{version}-<slug>` for SM; `fix/c8run-nightly-{version}-<slug>` for c8Run. Feature branches off `main`.
109
+ - **Commits and PR titles**: Conventional Commits. `fix(nightly):` for SM; `fix(c8run-nightly):` for c8Run.
110
+ - **Version awareness**: SM chart layout differs across versions (8.8+ uses unified `templates/orchestration/`). E2E tests follow the same split via `tests/SM-8.x/` and `tests/c8Run-8.x/`.
111
+ - **No skipping**: NEVER use `test.skip()` or `test.fixme()`. Write `{"prs":[]}` and stop if no fix is possible.
112
+ - **Goldens** (SM only): regenerate with `make` targets only; hand-edits are rejected on review.
113
+ - **c8Run no cluster after nightly**: the binary ran locally on the CI runner and is gone. Never attempt `kubectl`, Teleport, or cluster credential steps for c8Run failures.
114
+ - **Credentials** (SM only): nightly clusters live under `*.ci.distro.ultrawombat.com`; never commit `.env` files. Generate on demand with `scripts/render-e2e-env.sh`.
115
+ - **Toolchain**: Helm repo — Go 1.26.1, Helm 3.20.1 (see `.tool-versions`). E2E repo — Node per `.nvmrc`, Playwright ^1.49.0. camunda monorepo — Java 21, Maven wrapper `./mvnw`.