@camunda/e2e-test-suite 0.0.615 → 0.0.617

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.
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LoginPage = void 0;
4
- const test_1 = require("@playwright/test");
5
4
  class LoginPage {
6
5
  page;
7
6
  usernameInput;
@@ -17,18 +16,31 @@ class LoginPage {
17
16
  this.page = page;
18
17
  this.usernameInput = page.getByLabel('Username or email');
19
18
  this.passwordInput = page.getByLabel('Password');
20
- this.loginButton = page.getByRole('button', { name: 'Log in' });
19
+ this.loginButton = page.getByRole('button', { name: /log in|sign in/i });
21
20
  this.coreUsernameInput = page.getByPlaceholder('Username');
22
21
  this.corePasswordInput = page.getByPlaceholder('Password');
23
22
  this.coreLoginButton = page.getByRole('button', { name: 'Login' });
24
23
  this.keycloakBanner = page.locator('body#keycloak-bg[data-page-id="login-login"]');
25
24
  }
26
25
  async detectLoginForm() {
27
- const anyForm = this.usernameInput
28
- .or(this.coreUsernameInput)
29
- .or(this.keycloakBanner);
30
- await anyForm.waitFor({ state: 'visible', timeout: 15000 });
31
- if (await this.coreUsernameInput.isVisible()) {
26
+ // If we're on an app page that's about to redirect to KC, wait for
27
+ // the navigation to complete before looking for login form elements.
28
+ const url = this.page.url();
29
+ if (!url.includes('/auth/') && !url.includes('/login-callback')) {
30
+ await this.page
31
+ .waitForURL((u) => u.pathname.includes('/auth/'), {
32
+ timeout: 30000,
33
+ waitUntil: 'domcontentloaded',
34
+ })
35
+ .catch(() => { });
36
+ }
37
+ const kcUsername = this.page.locator('#username');
38
+ const anyForm = kcUsername
39
+ .or(this.coreLoginButton)
40
+ .or(this.keycloakBanner)
41
+ .first();
42
+ await anyForm.waitFor({ state: 'visible', timeout: 30000 });
43
+ if (await this.coreLoginButton.isVisible()) {
32
44
  this.useCore = true;
33
45
  }
34
46
  else if (await this.keycloakBanner.isVisible()) {
@@ -78,17 +90,6 @@ class LoginPage {
78
90
  async login(username, password) {
79
91
  try {
80
92
  await this.detectLoginForm();
81
- if (await this.page
82
- .locator('body#keycloak-bg[data-page-id="login-login"]')
83
- .isVisible()) {
84
- await (0, test_1.expect)(this.keycloakBanner).toBeVisible({ timeout: 15000 });
85
- }
86
- else {
87
- const activeLoginButton = this.useCore
88
- ? this.coreLoginButton
89
- : this.loginButton;
90
- await (0, test_1.expect)(activeLoginButton).toBeVisible({ timeout: 15000 });
91
- }
92
93
  }
93
94
  catch (error) {
94
95
  return;
@@ -77,7 +77,13 @@ class NavigationPage {
77
77
  .first();
78
78
  await (0, test_1.expect)(loginEntryPoint).toBeVisible({ timeout: 60000 });
79
79
  const isBannerVisible = await banner.isVisible().catch(() => false);
80
- if (isBannerVisible) {
80
+ // Guard against the Modeler SPA rendering its header on the login
81
+ // page before the OAuth redirect fires. If the banner is visible
82
+ // but the URL is still a login/auth path, the user is NOT actually
83
+ // authenticated — wait for the real login form to appear.
84
+ const currentUrl = this.page.url();
85
+ const onLoginPath = currentUrl.includes('/login') || currentUrl.includes('/auth/');
86
+ if (isBannerVisible && !onLoginPath) {
81
87
  const loginVisible = await loginPage.usernameInput.isVisible();
82
88
  if (loginVisible) {
83
89
  await loginPage.login(username, password);
@@ -21,6 +21,7 @@ declare class OperateProcessInstancePage {
21
21
  assertEitherIncidentOrCompletedIconVisible(): Promise<string>;
22
22
  assertProcessCompleteStatusWithRetry(timeout?: number, maxRetries?: number): Promise<void>;
23
23
  assertProcessVariableContainsText(variableName: string, text: string): Promise<void>;
24
+ private captureVariableJsonValue;
24
25
  assertResultVariableVisibleWithRetry(variableName: string): Promise<void>;
25
26
  assertActiveTokenIsPresent(): Promise<void>;
26
27
  assertVariablesListVisible(timeout?: number): Promise<void>;
@@ -162,8 +162,21 @@ class OperateProcessInstancePage {
162
162
  await (0, test_1.expect)(this.page.getByTestId(`variable-${variableName}`)).toContainText(text, { timeout: 8000 });
163
163
  return;
164
164
  }
165
- catch (error) {
166
- console.log(`assertProcessVariableContainsText attempt ${attempt + 1}/${maxRetries} failed: ${error}`);
165
+ catch (uiError) {
166
+ // Document-typed variables render as a compact summary
167
+ // (e.g. "3 documents" or "<docId> <size>") that omits metadata
168
+ // such as filename, storeId, and contentType. Fall back to the
169
+ // raw JSON value from the variables API response.
170
+ try {
171
+ const value = await this.captureVariableJsonValue(variableName);
172
+ if (value != null && value.includes(text)) {
173
+ return;
174
+ }
175
+ }
176
+ catch (apiError) {
177
+ console.log(`captureVariableJsonValue for ${variableName} attempt ${attempt + 1}/${maxRetries} failed: ${apiError}`);
178
+ }
179
+ console.log(`assertProcessVariableContainsText attempt ${attempt + 1}/${maxRetries} failed: ${uiError}`);
167
180
  if (attempt < maxRetries - 1) {
168
181
  await this.page.reload({ timeout: 10000 }).catch(() => { });
169
182
  await this.page.waitForLoadState('domcontentloaded').catch(() => { });
@@ -172,6 +185,34 @@ class OperateProcessInstancePage {
172
185
  }
173
186
  throw new Error(`Failed to assert variable ${variableName} contains "${text}" after ${maxRetries} attempts.`);
174
187
  }
188
+ async captureVariableJsonValue(variableName) {
189
+ let capturedValue = null;
190
+ const responsePromise = this.page
191
+ .waitForResponse(async (resp) => {
192
+ if (!resp.url().includes('/v2/variables/search') ||
193
+ resp.status() !== 200) {
194
+ return false;
195
+ }
196
+ try {
197
+ const body = await resp.text();
198
+ const data = JSON.parse(body);
199
+ const item = data?.items?.find((i) => i.name === variableName);
200
+ if (item?.value != null) {
201
+ capturedValue = String(item.value);
202
+ return true;
203
+ }
204
+ return false;
205
+ }
206
+ catch {
207
+ return false;
208
+ }
209
+ }, { timeout: 15000 })
210
+ .catch(() => null);
211
+ await this.page.reload({ timeout: 10000 }).catch(() => { });
212
+ await this.page.waitForLoadState('domcontentloaded').catch(() => { });
213
+ await responsePromise;
214
+ return capturedValue;
215
+ }
175
216
  async assertResultVariableVisibleWithRetry(variableName) {
176
217
  const maxRetries = 3;
177
218
  for (let attempt = 0; attempt < maxRetries; attempt++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/e2e-test-suite",
3
- "version": "0.0.615",
3
+ "version": "0.0.617",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",