@camunda/e2e-test-suite 0.0.727 → 0.0.729
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.
|
@@ -2,11 +2,8 @@ import { Page, Locator } from '@playwright/test';
|
|
|
2
2
|
declare class PlayPage {
|
|
3
3
|
private page;
|
|
4
4
|
readonly completeJobButton: Locator;
|
|
5
|
-
readonly saveScenarioButton: Locator;
|
|
6
5
|
readonly viewScenarioButton: Locator;
|
|
7
6
|
readonly runAllScenariosButton: Locator;
|
|
8
|
-
readonly confirmSaveScenarioButton: Locator;
|
|
9
|
-
readonly enterScenarioNameInput: Locator;
|
|
10
7
|
readonly confirmDeleteScenarioButton: Locator;
|
|
11
8
|
readonly viewAllScenariosButton: Locator;
|
|
12
9
|
readonly getScenarioRowByName: (scenarioName: string) => Locator;
|
|
@@ -17,7 +14,9 @@ declare class PlayPage {
|
|
|
17
14
|
readonly configureTestPanel: Locator;
|
|
18
15
|
readonly configureTestPanelStartButton: Locator;
|
|
19
16
|
readonly notifications: Locator;
|
|
20
|
-
readonly
|
|
17
|
+
readonly scenarioSavedToast: Locator;
|
|
18
|
+
readonly scenarioDetailNameInput: Locator;
|
|
19
|
+
readonly scenarioDetailSaveButton: Locator;
|
|
21
20
|
readonly loadingInstanceDetailsText: Locator;
|
|
22
21
|
readonly retryButton: Locator;
|
|
23
22
|
readonly dialog: Locator;
|
|
@@ -31,12 +30,13 @@ declare class PlayPage {
|
|
|
31
30
|
waitForInstanceDetailsToBeLoaded(): Promise<void>;
|
|
32
31
|
waitForNextElementToBeActive(historyItem: string): Promise<void>;
|
|
33
32
|
waitForProcessToBeCompleted(): Promise<void>;
|
|
34
|
-
|
|
33
|
+
waitForScenarioRecordPanelReady(): Promise<void>;
|
|
35
34
|
clickViewScenarioButton(): Promise<void>;
|
|
36
35
|
enterScenarioName(scenarioName: string): Promise<void>;
|
|
37
36
|
updateScenarioName(newScenarioName: string): Promise<void>;
|
|
38
37
|
clickViewAllScenariosButton(): Promise<void>;
|
|
39
38
|
confirmSaveScenario(): Promise<void>;
|
|
39
|
+
assertSavedScenarioNameInPanel(scenarioName: string): Promise<void>;
|
|
40
40
|
getDeleteIconForScenario(scenarioName: string): Promise<Locator>;
|
|
41
41
|
deleteScenario(scenarioName: string): Promise<void>;
|
|
42
42
|
confirmDeleteScenario(): Promise<void>;
|
|
@@ -2,18 +2,14 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PlayPage = void 0;
|
|
4
4
|
const test_1 = require("@playwright/test");
|
|
5
|
-
const sleep_1 = require("../../utils/sleep");
|
|
6
5
|
const expectLocatorWithRetry_1 = require("../../utils/assertionHelpers/expectLocatorWithRetry");
|
|
7
6
|
const clickLocatorWithRetry_1 = require("../../utils/assertionHelpers/clickLocatorWithRetry");
|
|
8
7
|
const maxWaitTimeSeconds = 180000;
|
|
9
8
|
class PlayPage {
|
|
10
9
|
page;
|
|
11
10
|
completeJobButton;
|
|
12
|
-
saveScenarioButton;
|
|
13
11
|
viewScenarioButton;
|
|
14
12
|
runAllScenariosButton;
|
|
15
|
-
confirmSaveScenarioButton;
|
|
16
|
-
enterScenarioNameInput;
|
|
17
13
|
confirmDeleteScenarioButton;
|
|
18
14
|
viewAllScenariosButton;
|
|
19
15
|
getScenarioRowByName;
|
|
@@ -24,7 +20,9 @@ class PlayPage {
|
|
|
24
20
|
configureTestPanel;
|
|
25
21
|
configureTestPanelStartButton;
|
|
26
22
|
notifications;
|
|
27
|
-
|
|
23
|
+
scenarioSavedToast;
|
|
24
|
+
scenarioDetailNameInput;
|
|
25
|
+
scenarioDetailSaveButton;
|
|
28
26
|
loadingInstanceDetailsText;
|
|
29
27
|
retryButton;
|
|
30
28
|
dialog;
|
|
@@ -35,22 +33,23 @@ class PlayPage {
|
|
|
35
33
|
this.completeJobButton = page
|
|
36
34
|
.getByTestId('diagram')
|
|
37
35
|
.getByLabel('Complete job');
|
|
38
|
-
this.saveScenarioButton = page.getByRole('button', { name: 'Save scenario' });
|
|
39
36
|
this.viewScenarioButton = page.getByRole('button', { name: 'View scenario' });
|
|
40
37
|
this.runAllScenariosButton = page.getByRole('button', {
|
|
41
38
|
name: 'Run all scenarios',
|
|
42
39
|
});
|
|
43
|
-
this.confirmSaveScenarioButton = page
|
|
44
|
-
.getByTestId('save-scenario-modal')
|
|
45
|
-
.getByRole('button', { name: 'Save' });
|
|
46
|
-
this.enterScenarioNameInput = page
|
|
47
|
-
.getByTestId('save-scenario-modal')
|
|
48
|
-
.locator('input#scenario-name')
|
|
49
|
-
.first();
|
|
50
40
|
this.confirmDeleteScenarioButton = page
|
|
51
41
|
.getByRole('dialog', { name: 'Delete scenario' })
|
|
52
42
|
.getByRole('button', { name: 'Delete', exact: true });
|
|
53
|
-
|
|
43
|
+
// After saving a scenario, the Scenarios panel is in detail-view mode.
|
|
44
|
+
// To get back to the list (where "Run all scenarios" lives in
|
|
45
|
+
// ScenarioTopBar), click the "Back to scenarios" ghost button at the
|
|
46
|
+
// top of the detail panel — see ScenarioDetail/index.tsx Header.
|
|
47
|
+
// This replaces the legacy bottom-bar `(View all)` link that used to
|
|
48
|
+
// close the saved-scenario view.
|
|
49
|
+
this.viewAllScenariosButton = page.getByRole('button', {
|
|
50
|
+
name: 'Back to scenarios',
|
|
51
|
+
exact: true,
|
|
52
|
+
});
|
|
54
53
|
this.getScenarioRowByName = (scenarioName) => page.locator('tr', { hasText: scenarioName });
|
|
55
54
|
this.getScenarioRow = (scenarioName) => page.locator('tr', { hasText: scenarioName });
|
|
56
55
|
this.diagram = page.getByTestId('diagram');
|
|
@@ -61,7 +60,24 @@ class PlayPage {
|
|
|
61
60
|
this.configureTestPanel = page.getByTestId('configure-test-panel');
|
|
62
61
|
this.configureTestPanelStartButton = this.configureTestPanel.getByRole('button', { name: /^Start( with .*)?$/, exact: false });
|
|
63
62
|
this.notifications = page.locator('.cds--toast-notification');
|
|
64
|
-
|
|
63
|
+
// Hub PR #25327 (2026-06-22) removed the standalone "Save scenario" modal
|
|
64
|
+
// and moved recording into the Scenarios side panel's detail view. The
|
|
65
|
+
// detail view renders a TextInput with id="scenario-name" and a primary
|
|
66
|
+
// "Save scenario" button. A success toast with title "Scenario saved"
|
|
67
|
+
// is emitted via @camunda/c4-notifications — see
|
|
68
|
+
// ScenarioDetail/useScenarioEditor.ts.
|
|
69
|
+
this.scenarioDetailNameInput = page.locator('input#scenario-name');
|
|
70
|
+
this.scenarioDetailSaveButton = page.getByRole('button', {
|
|
71
|
+
name: 'Save scenario',
|
|
72
|
+
exact: true,
|
|
73
|
+
});
|
|
74
|
+
// c4-notifications wraps Carbon ToastNotification with role="alert" for
|
|
75
|
+
// non-actionable toasts (see Notification.tsx in @camunda/c4-notifications).
|
|
76
|
+
// Anchor on the accessible role instead of the Carbon CSS class so the
|
|
77
|
+
// locator is resilient to Carbon version bumps.
|
|
78
|
+
this.scenarioSavedToast = page
|
|
79
|
+
.getByRole('alert')
|
|
80
|
+
.filter({ hasText: 'Scenario saved' });
|
|
65
81
|
this.loadingInstanceDetailsText = this.page.getByText('Loading instance details...');
|
|
66
82
|
this.retryButton = this.page.getByRole('button', { name: 'Retry' });
|
|
67
83
|
// New Play UI (8.10+): "Configure scenario" opens an input panel with a plain "Start" button.
|
|
@@ -145,49 +161,67 @@ class PlayPage {
|
|
|
145
161
|
timeout: maxWaitTimeSeconds,
|
|
146
162
|
});
|
|
147
163
|
}
|
|
148
|
-
async
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
await (0, test_1.expect)(this.saveScenarioButton).toBeEnabled({ timeout: 30000 });
|
|
160
|
-
await this.saveScenarioButton.click({ force: true, timeout: 30000 });
|
|
161
|
-
}
|
|
164
|
+
async waitForScenarioRecordPanelReady() {
|
|
165
|
+
// Hub PR #25327 (2026-06-22) removed the standalone "Save scenario" modal.
|
|
166
|
+
// Starting a Play run now auto-opens the Scenarios side panel in "record"
|
|
167
|
+
// mode with the scenario-name input + a primary "Save scenario" button.
|
|
168
|
+
// This method waits for that record-mode panel to be ready for input.
|
|
169
|
+
//
|
|
170
|
+
// `state: 'hidden'` already resolves immediately when the notification is
|
|
171
|
+
// absent, so no try/catch is needed — letting a real timeout surface is
|
|
172
|
+
// intentional (it signals a stuck stale toast blocking subsequent input).
|
|
173
|
+
await this.notifications.first().waitFor({ state: 'hidden', timeout: 60000 });
|
|
174
|
+
await (0, test_1.expect)(this.scenarioDetailNameInput).toBeVisible({ timeout: 30000 });
|
|
162
175
|
}
|
|
163
176
|
async clickViewScenarioButton() {
|
|
164
177
|
await this.viewScenarioButton.waitFor({ state: 'visible', timeout: 30000 });
|
|
165
178
|
await this.viewScenarioButton.click();
|
|
166
179
|
}
|
|
167
180
|
async enterScenarioName(scenarioName) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
181
|
+
// New flow: the name input lives directly inside the auto-opened record
|
|
182
|
+
// panel — no modal to click open first. Fill and blur so the validation
|
|
183
|
+
// (canSave = isDirty && !isNameEmpty && !isNameDuplicate) commits before
|
|
184
|
+
// the Save scenario button is clicked.
|
|
185
|
+
await this.scenarioDetailNameInput.waitFor({
|
|
186
|
+
state: 'visible',
|
|
187
|
+
timeout: 30000,
|
|
172
188
|
});
|
|
173
|
-
|
|
174
|
-
await
|
|
175
|
-
await
|
|
176
|
-
await input.fill(scenarioName);
|
|
189
|
+
await this.scenarioDetailNameInput.clear();
|
|
190
|
+
await this.scenarioDetailNameInput.fill(scenarioName);
|
|
191
|
+
await this.scenarioDetailNameInput.press('Tab');
|
|
177
192
|
}
|
|
178
193
|
async updateScenarioName(newScenarioName) {
|
|
179
|
-
|
|
194
|
+
// Mirror enterScenarioName's blur step so canSave validation commits
|
|
195
|
+
// before any subsequent Save click.
|
|
196
|
+
await this.scenarioDetailNameInput.fill(newScenarioName);
|
|
197
|
+
await this.scenarioDetailNameInput.press('Tab');
|
|
180
198
|
}
|
|
181
199
|
async clickViewAllScenariosButton() {
|
|
182
200
|
await (0, expectLocatorWithRetry_1.expectLocatorWithRetry)(this.page, this.viewAllScenariosButton);
|
|
183
201
|
await this.viewAllScenariosButton.click();
|
|
184
202
|
}
|
|
185
203
|
async confirmSaveScenario() {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
await this.
|
|
204
|
+
// Click the in-panel "Save scenario" primary button. It is gated by the
|
|
205
|
+
// canSave predicate in useScenarioEditor.ts — a non-empty, non-duplicate
|
|
206
|
+
// name and a completed instance are both required. enterScenarioName()
|
|
207
|
+
// and waitForProcessToBeCompleted() satisfy those before this is called.
|
|
208
|
+
await (0, test_1.expect)(this.scenarioDetailSaveButton).toBeVisible({ timeout: 30000 });
|
|
209
|
+
await (0, test_1.expect)(this.scenarioDetailSaveButton).toBeEnabled({ timeout: 30000 });
|
|
210
|
+
await this.scenarioDetailSaveButton.click({ timeout: 30000 });
|
|
211
|
+
// Saving fires a c4-notifications toast with title "Scenario saved".
|
|
212
|
+
// Wait for it as the success signal that replaces the legacy
|
|
213
|
+
// modal-hidden assertion.
|
|
214
|
+
await (0, test_1.expect)(this.scenarioSavedToast).toBeVisible({ timeout: 30000 });
|
|
215
|
+
}
|
|
216
|
+
async assertSavedScenarioNameInPanel(scenarioName) {
|
|
217
|
+
// After save, useScenarioEditor.saveTest() calls
|
|
218
|
+
// scenariosStore.stopRecording() + setSelectedScenario(newScenario) and
|
|
219
|
+
// processInstanceStore.reset(). The Scenarios side panel stays open in
|
|
220
|
+
// 'view' mode for the just-saved scenario, rendering the name as the
|
|
221
|
+
// TestName h4 (see ScenarioDetail/styled.tsx and index.tsx). The legacy
|
|
222
|
+
// instance-header scenarioName slot is cleared by the reset and is no
|
|
223
|
+
// longer the source of truth for the saved name.
|
|
224
|
+
await (0, test_1.expect)(this.page.getByRole('heading', { name: scenarioName, exact: true })).toBeVisible({ timeout: 30000 });
|
|
191
225
|
}
|
|
192
226
|
async getDeleteIconForScenario(scenarioName) {
|
|
193
227
|
const scenarioRow = this.page
|
|
@@ -81,10 +81,9 @@ SM_8_10_1.test.describe('Deploy and run a process in Play', () => {
|
|
|
81
81
|
await playPage.waitForCompleteJobButtonToBeAvailable();
|
|
82
82
|
await playPage.clickCompleteJobButton();
|
|
83
83
|
await playPage.waitForProcessToBeCompleted();
|
|
84
|
-
await playPage.
|
|
84
|
+
await playPage.waitForScenarioRecordPanelReady();
|
|
85
85
|
await playPage.enterScenarioName(scenarioName);
|
|
86
86
|
await playPage.confirmSaveScenario();
|
|
87
|
-
await (0, test_1.expect)(playPage.saveScenarioModal).toBeHidden({ timeout: 10000 });
|
|
88
87
|
});
|
|
89
88
|
await SM_8_10_1.test.step('Update the saved scenario', async () => {
|
|
90
89
|
await modelerCreatePage.switchToImplementTab();
|
|
@@ -123,10 +122,10 @@ SM_8_10_1.test.describe('Deploy and run a process in Play', () => {
|
|
|
123
122
|
await playPage.waitForCompleteJobButtonToBeAvailable();
|
|
124
123
|
await playPage.clickCompleteJobButton();
|
|
125
124
|
await playPage.waitForProcessToBeCompleted();
|
|
126
|
-
await playPage.
|
|
125
|
+
await playPage.waitForScenarioRecordPanelReady();
|
|
127
126
|
await playPage.enterScenarioName(updatedScenarioName);
|
|
128
127
|
await playPage.confirmSaveScenario();
|
|
129
|
-
await
|
|
128
|
+
await playPage.assertSavedScenarioNameInPanel(updatedScenarioName);
|
|
130
129
|
});
|
|
131
130
|
await SM_8_10_1.test.step('Run all scenarios', async () => {
|
|
132
131
|
await playPage.clickViewAllScenariosButton();
|