@camunda/e2e-test-suite 0.0.1156 → 0.0.1158

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.
@@ -4,6 +4,12 @@ exports.PlayPage = void 0;
4
4
  const test_1 = require("@playwright/test");
5
5
  const clickLocatorWithRetry_1 = require("../../utils/assertionHelpers/clickLocatorWithRetry");
6
6
  const maxWaitTimeSeconds = 180000;
7
+ // The instance-details wait gets its own, larger budget: the old code spent
8
+ // two separate 180s assertions with a page reload between them, so shrinking
9
+ // the total to one 180s pass would have cut the time the step is allowed to
10
+ // take. Keep the generous end-to-end budget (the test is test.slow(), i.e. 36
11
+ // minutes) while polling inside it.
12
+ const instanceDetailsTimeout = 300000;
7
13
  class PlayPage {
8
14
  page;
9
15
  diagram;
@@ -122,44 +128,72 @@ class PlayPage {
122
128
  }
123
129
  }
124
130
  async waitForInstanceDetailsToBeLoaded() {
125
- const maxRetries = 2;
126
- let attempts = 0;
127
- while (attempts < maxRetries) {
128
- try {
129
- await (0, test_1.expect)(this.page.getByText(/process instance key|instance key/i).first()).toBeVisible({ timeout: maxWaitTimeSeconds });
130
- await (0, test_1.expect)(this.page
131
- .getByText(/This process instance has no variables|No variables/i)
132
- .first()).toBeVisible({ timeout: maxWaitTimeSeconds });
133
- return;
134
- }
135
- catch (error) {
136
- if (attempts >= maxRetries - 1)
137
- throw error;
138
- await this.page.reload();
139
- // A reload drops the Modeler back on the Implement tab (the same
140
- // trap clickStartInstanceButton's catch block already handles), so
141
- // the retry would otherwise wait out its whole 180s budget against
142
- // DOM that can never hold the instance details -- which is why the
143
- // nightly still failed on "process instance key" despite this loop.
144
- // Re-open Play first.
145
- if (await this.playTab.isVisible({ timeout: 30000 }).catch(() => false)) {
146
- await this.playTab.click();
147
- }
148
- // The details panel only renders once an instance exists. The one way
149
- // it never rendered is that the start click resolved against a
150
- // re-laid-out (briefly detached) overlay and was silently lost --
151
- // clickLocatorWithRetry only retries a click that *throws*. Re-issue
152
- // the start so the retry has an instance to show; if one is already
153
- // running the assertions below simply pass on it.
154
- const startTrigger = this.configureTestPanelStartButton
155
- .or(this.startInstanceOverlayButton)
156
- .first();
157
- if (await startTrigger.isVisible({ timeout: 30000 }).catch(() => false)) {
158
- await this.clickStartInstanceButton();
131
+ const instanceKeyHeader = this.page
132
+ .getByText(/process instance key|instance key/i)
133
+ .first();
134
+ const noVariablesMessage = this.page
135
+ .getByText(/This process instance has no variables|No variables/i)
136
+ .first();
137
+ // A Start trigger that is STILL on screen is positive proof that no
138
+ // instance was ever created: camunda-hub test-studio's ConfigureTestCaseStep
139
+ // returns null as soon as `processInstanceKey !== undefined`, while
140
+ // InstanceHeader returns null for as long as it is undefined -- the panel
141
+ // and the header are mutually exclusive. So the recovery here is to
142
+ // re-issue the start click, not to reload: `clickLocatorWithRetry` only
143
+ // retries a click that *throws*, so a click that resolved against a
144
+ // re-laid-out overlay is lost silently and the sole symptom is this
145
+ // locator timing out with "element(s) not found" -- exactly the nightly
146
+ // failure. Re-clicking cannot pile up requests because the product
147
+ // disables the button while a start is in flight (`isStartingInstance`).
148
+ //
149
+ // The previous recovery called `page.reload()` first, which is the very
150
+ // trap the surrounding comments document: a reload resets test-mode state
151
+ // and drops the Modeler back on the Implement tab, so the configure panel
152
+ // needs the whole setup chain (checkExistingDeployment -> deploy step ->
153
+ // configure step) to re-run before a Start button exists again. The 30s
154
+ // probe that followed regularly expired before that, no start was
155
+ // re-issued, and the second attempt then waited out its full budget
156
+ // against DOM that could never hold the instance details.
157
+ const startTrigger = this.configureTestPanelStartButton
158
+ .or(this.startInstanceOverlayButton)
159
+ .first();
160
+ // A start the backend rejects raises a notification instead of creating an
161
+ // instance (camunda-hub test-studio `useStartInstance` -> `notify.error`
162
+ // with REQUEST_FAILURE / MISSING_PERMISSIONS). Name it in the failure
163
+ // message so the next occurrence is diagnosable from the report alone
164
+ // instead of reporting a bare "element(s) not found".
165
+ const startErrorNotification = this.page
166
+ .getByText(/Unable to process request|Missing permissions/i)
167
+ .first();
168
+ // Grace period before the first re-click, so we never fire a second start
169
+ // during the brief window where the first one is already in flight but the
170
+ // panel has not unmounted yet.
171
+ const recoveryGraceMs = 30000;
172
+ const startedAt = Date.now();
173
+ await (0, test_1.expect)(async () => {
174
+ const hasInstance = await instanceKeyHeader
175
+ .isVisible()
176
+ .catch(() => false);
177
+ if (!hasInstance && Date.now() - startedAt > recoveryGraceMs) {
178
+ const canRestart = (await startTrigger.isVisible().catch(() => false)) &&
179
+ (await startTrigger.isEnabled().catch(() => false));
180
+ if (canRestart) {
181
+ await startTrigger.click({ timeout: 30000 });
159
182
  }
160
- attempts++;
161
183
  }
162
- }
184
+ const reportedError = (await startErrorNotification
185
+ .isVisible()
186
+ .catch(() => false))
187
+ ? await startErrorNotification.innerText()
188
+ : undefined;
189
+ await (0, test_1.expect)(instanceKeyHeader, reportedError === undefined
190
+ ? 'Play never rendered the process instance header'
191
+ : `Play reported: ${reportedError}`).toBeVisible({ timeout: 15000 });
192
+ await (0, test_1.expect)(noVariablesMessage).toBeVisible({ timeout: 15000 });
193
+ }).toPass({
194
+ timeout: instanceDetailsTimeout,
195
+ intervals: [2000, 5000, 10000],
196
+ });
163
197
  }
164
198
  async waitForNextElementToBeActive(historyItem) {
165
199
  // Same lost-click hazard waitForProcessToBeCompleted documents for the
@@ -56,10 +56,15 @@ class NavigationPage {
56
56
  // deleted -- the logo is its own anchor (aria-label="Camunda logo", with
57
57
  // an aria-hidden svg) and "Tasklist" moved into the breadcrumb nav, so
58
58
  // the legacy shell's combined "Camunda logo Tasklist" name no longer
59
- // exists. Match either shell so the banner resolves on both.
59
+ // exists. Match either shell so the banner resolves on both, and scope
60
+ // the generic logo-link fallback to Tasklist's orchestration href so it
61
+ // stays aligned with overridden context paths too.
60
62
  this.tasklistPageBanner = page
61
63
  .getByRole('navigation', { name: 'Camunda context' })
62
64
  .getByRole('link', { name: 'Tasklist', exact: true })
65
+ .or(page
66
+ .getByRole('link', { name: 'Camunda logo', exact: true })
67
+ .and(page.locator(`[href$="${NORMALIZED_ORCHESTRATION_CONTEXT_PATH}/tasklist"]`)))
63
68
  .or(page.getByRole('link', { name: 'Camunda logo Tasklist' }))
64
69
  .first();
65
70
  this.optimizePageBanner = page.getByRole('link', {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/e2e-test-suite",
3
- "version": "0.0.1156",
3
+ "version": "0.0.1158",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",