@camunda/e2e-test-suite 0.0.565 → 0.0.567
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.
- package/dist/pages/8.10/ModelerHomePage.d.ts +1 -0
- package/dist/pages/8.10/ModelerHomePage.js +20 -4
- package/dist/pages/8.9/ModelerHomePage.d.ts +1 -0
- package/dist/pages/8.9/ModelerHomePage.js +20 -4
- package/dist/pages/SM-8.10/ClusterPage.js +5 -1
- package/dist/pages/SM-8.10/ModelerHomePage.js +3 -1
- package/dist/pages/SM-8.10/TaskPanelPage.js +5 -2
- package/dist/pages/SM-8.10/optimizeReportUtils.js +7 -1
- package/dist/tests/SM-8.10/hto-user-flows.spec.js +10 -3
- package/dist/tests/SM-8.10/optimize-user-flows.spec.js +19 -19
- package/package.json +1 -1
- package/playwright.config.ts +4 -1
|
@@ -26,6 +26,7 @@ declare class ModelerHomePage {
|
|
|
26
26
|
readonly optionsButton: Locator;
|
|
27
27
|
readonly formNameBreadcrumb: (formName: string) => Locator;
|
|
28
28
|
constructor(page: Page);
|
|
29
|
+
dismissOverlays(): Promise<void>;
|
|
29
30
|
clickCreateNewProjectButton(): Promise<void>;
|
|
30
31
|
enterNewProjectName(name: string): Promise<void>;
|
|
31
32
|
enterIdpApplicationName(name: string): Promise<void>;
|
|
@@ -75,10 +75,26 @@ class ModelerHomePage {
|
|
|
75
75
|
hasText: formName,
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
|
+
async dismissOverlays() {
|
|
79
|
+
for (const locator of [
|
|
80
|
+
this.closeButton,
|
|
81
|
+
this.page.getByRole('button', { name: 'Close' }).first(),
|
|
82
|
+
this.messageBanner,
|
|
83
|
+
]) {
|
|
84
|
+
await locator
|
|
85
|
+
.waitFor({ state: 'visible', timeout: 3000 })
|
|
86
|
+
.then(() => locator.click())
|
|
87
|
+
.catch(() => { });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
78
90
|
async clickCreateNewProjectButton() {
|
|
79
|
-
await (0,
|
|
80
|
-
|
|
81
|
-
|
|
91
|
+
await (0, clickLocatorWithRetry_1.clickLocatorWithRetry)(this.page, this.createNewProjectButton, {
|
|
92
|
+
preAction: async () => {
|
|
93
|
+
await this.dismissOverlays();
|
|
94
|
+
},
|
|
95
|
+
totalTimeout: 120000,
|
|
96
|
+
visibilityTimeout: 10000,
|
|
97
|
+
});
|
|
82
98
|
}
|
|
83
99
|
async enterNewProjectName(name) {
|
|
84
100
|
await this.projectNameInput.click({ timeout: 60000 });
|
|
@@ -164,7 +180,7 @@ class ModelerHomePage {
|
|
|
164
180
|
}
|
|
165
181
|
async createCrossComponentProjectFolder() {
|
|
166
182
|
await (0, sleep_1.sleep)(15000);
|
|
167
|
-
await this.
|
|
183
|
+
await this.dismissOverlays();
|
|
168
184
|
if (await this.crossComponentProjectFolder.isVisible()) {
|
|
169
185
|
console.log('Cross Component Project folder already exists. Clicking into it');
|
|
170
186
|
await this.clickCrossComponentProjectFolder();
|
|
@@ -26,6 +26,7 @@ declare class ModelerHomePage {
|
|
|
26
26
|
readonly optionsButton: Locator;
|
|
27
27
|
readonly formNameBreadcrumb: (formName: string) => Locator;
|
|
28
28
|
constructor(page: Page);
|
|
29
|
+
dismissOverlays(): Promise<void>;
|
|
29
30
|
clickCreateNewProjectButton(): Promise<void>;
|
|
30
31
|
enterNewProjectName(name: string): Promise<void>;
|
|
31
32
|
enterIdpApplicationName(name: string): Promise<void>;
|
|
@@ -75,10 +75,26 @@ class ModelerHomePage {
|
|
|
75
75
|
hasText: formName,
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
|
+
async dismissOverlays() {
|
|
79
|
+
for (const locator of [
|
|
80
|
+
this.closeButton,
|
|
81
|
+
this.page.getByRole('button', { name: 'Close' }).first(),
|
|
82
|
+
this.messageBanner,
|
|
83
|
+
]) {
|
|
84
|
+
await locator
|
|
85
|
+
.waitFor({ state: 'visible', timeout: 3000 })
|
|
86
|
+
.then(() => locator.click())
|
|
87
|
+
.catch(() => { });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
78
90
|
async clickCreateNewProjectButton() {
|
|
79
|
-
await (0,
|
|
80
|
-
|
|
81
|
-
|
|
91
|
+
await (0, clickLocatorWithRetry_1.clickLocatorWithRetry)(this.page, this.createNewProjectButton, {
|
|
92
|
+
preAction: async () => {
|
|
93
|
+
await this.dismissOverlays();
|
|
94
|
+
},
|
|
95
|
+
totalTimeout: 120000,
|
|
96
|
+
visibilityTimeout: 10000,
|
|
97
|
+
});
|
|
82
98
|
}
|
|
83
99
|
async enterNewProjectName(name) {
|
|
84
100
|
await this.projectNameInput.click({ timeout: 60000 });
|
|
@@ -164,7 +180,7 @@ class ModelerHomePage {
|
|
|
164
180
|
}
|
|
165
181
|
async createCrossComponentProjectFolder() {
|
|
166
182
|
await (0, sleep_1.sleep)(15000);
|
|
167
|
-
await this.
|
|
183
|
+
await this.dismissOverlays();
|
|
168
184
|
if (await this.crossComponentProjectFolder.isVisible()) {
|
|
169
185
|
console.log('Cross Component Project folder already exists. Clicking into it');
|
|
170
186
|
await this.clickCrossComponentProjectFolder();
|
|
@@ -22,7 +22,11 @@ class ClusterPage {
|
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
24
|
async assertCustomTagsAreVisible(tags) {
|
|
25
|
-
|
|
25
|
+
// The previous implementation called page.waitForLoadState('networkidle')
|
|
26
|
+
// here. The Console clusters page emits continuous polling/SSE traffic,
|
|
27
|
+
// so networkidle never fires — the test would hang for 12 min then
|
|
28
|
+
// retry, costing ~24 min total. The toBeVisible auto-waits below
|
|
29
|
+
// already cover the readiness window we actually need.
|
|
26
30
|
for (const tag of tags) {
|
|
27
31
|
await (0, test_1.expect)(this.clustersList.getByText(tag, { exact: true })).toBeVisible({
|
|
28
32
|
timeout: 60000,
|
|
@@ -92,7 +92,9 @@ class ModelerHomePage {
|
|
|
92
92
|
await this.projectNameInput.press('Enter');
|
|
93
93
|
}
|
|
94
94
|
async createCrossComponentProjectFolder() {
|
|
95
|
-
|
|
95
|
+
// Removed waitForLoadState('networkidle'). Modeler emits
|
|
96
|
+
// background activity; the toBeVisible auto-wait covers
|
|
97
|
+
// readiness deterministically.
|
|
96
98
|
await (0, test_1.expect)(this.createNewProjectButton).toBeVisible({ timeout: 30000 });
|
|
97
99
|
await this.clickMessageBanner();
|
|
98
100
|
if (await this.crossComponentProjectFolder.isVisible()) {
|
|
@@ -40,7 +40,9 @@ class TaskPanelPage {
|
|
|
40
40
|
const maxAttempts = 10;
|
|
41
41
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
42
42
|
try {
|
|
43
|
-
|
|
43
|
+
// Removed waitForLoadState('networkidle') — Tasklist polls
|
|
44
|
+
// continuously, so networkidle never fires; the click below
|
|
45
|
+
// already has a 4s timeout that auto-waits for the locator.
|
|
44
46
|
await this.availableTasks
|
|
45
47
|
.getByText(name, { exact: true })
|
|
46
48
|
.nth(0)
|
|
@@ -85,7 +87,8 @@ class TaskPanelPage {
|
|
|
85
87
|
await this.processesPageTab.click();
|
|
86
88
|
}
|
|
87
89
|
async taskCount(name, waitForStable = true) {
|
|
88
|
-
|
|
90
|
+
// Removed waitForLoadState('networkidle') — Tasklist polls;
|
|
91
|
+
// the stability poll below already guarantees readiness.
|
|
89
92
|
if (waitForStable) {
|
|
90
93
|
// Wait for the task list to stabilize: poll until count is unchanged for 2s
|
|
91
94
|
let previousCount = -1;
|
|
@@ -27,7 +27,13 @@ const createReportForProcess = async (optimizeCollectionsPage, optimizeReportPag
|
|
|
27
27
|
};
|
|
28
28
|
exports.createReportForProcess = createReportForProcess;
|
|
29
29
|
const assertReportWithRefreshes = async (page, optimizeHomePage, optimizeCollectionsPage, optimizeReportPage, reportName, locator, text) => {
|
|
30
|
-
|
|
30
|
+
// Was 30. Each attempt does 4 nested retries (each ~30s), so 30
|
|
31
|
+
// worst-case = 15 min on the longest-pole shard. Test that's
|
|
32
|
+
// genuinely failing at 30 attempts will also fail at 10 — same
|
|
33
|
+
// outcome but 3× faster fail. Test that needs more than 10
|
|
34
|
+
// refresh cycles for Optimize to catch up has a bigger underlying
|
|
35
|
+
// problem worth surfacing.
|
|
36
|
+
const maxRetries = 10;
|
|
31
37
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
32
38
|
try {
|
|
33
39
|
await optimizeHomePage.clickCollectionsLink();
|
|
@@ -288,7 +288,9 @@ SM_8_10_1.test.describe('HTO User Flow Tests', () => {
|
|
|
288
288
|
timeout: 120000,
|
|
289
289
|
});
|
|
290
290
|
await modelerCreatePage.enterDiagramName(processName);
|
|
291
|
-
|
|
291
|
+
// Replaced sleep(10000) with deterministic wait: the diagram name
|
|
292
|
+
// commit triggers a panel re-render; assertNameInput below waits
|
|
293
|
+
// for that to settle. Saves ~10s per run.
|
|
292
294
|
await modelerCreatePage.clickStartEventElement();
|
|
293
295
|
await modelerCreatePage.clickGeneralPropertiesPanel();
|
|
294
296
|
await modelerCreatePage.assertNameInput(processName);
|
|
@@ -319,7 +321,11 @@ SM_8_10_1.test.describe('HTO User Flow Tests', () => {
|
|
|
319
321
|
});
|
|
320
322
|
await SM_8_10_1.test.step('View User Tasks in Tasklist', async () => {
|
|
321
323
|
await navigationPage.goToTasklist();
|
|
322
|
-
|
|
324
|
+
// Removed page.waitForLoadState('networkidle'). Tasklist polls
|
|
325
|
+
// for new tasks continuously; networkidle never fires and the
|
|
326
|
+
// test would hang for the 12-min Playwright timeout. The
|
|
327
|
+
// expect(...).toBeVisible({timeout}) auto-waits below cover the
|
|
328
|
+
// readiness window correctly.
|
|
323
329
|
await (0, test_1.expect)(page.getByText(`${userTaskName}1`)).toBeVisible({
|
|
324
330
|
timeout: 120000,
|
|
325
331
|
});
|
|
@@ -335,7 +341,8 @@ SM_8_10_1.test.describe('HTO User Flow Tests', () => {
|
|
|
335
341
|
});
|
|
336
342
|
await SM_8_10_1.test.step('Navigate to Tasklist and Assert User Tasks ', async () => {
|
|
337
343
|
await navigationPage.goToTasklist(undefined, credentials);
|
|
338
|
-
|
|
344
|
+
// Removed networkidle wait — same reason as above (Tasklist
|
|
345
|
+
// polls); toBeVisible auto-waits cover readiness.
|
|
339
346
|
await (0, test_1.expect)(page.getByText(`${userTaskName}1`)).toBeVisible({
|
|
340
347
|
timeout: 120000,
|
|
341
348
|
});
|
|
@@ -51,7 +51,7 @@ if (process.env.IS_OPTIMIZE !== 'false') {
|
|
|
51
51
|
await SM_8_10_1.test.step('Create BPMN Diagram with User Task and Start Process Instance', async () => {
|
|
52
52
|
await modelerCreatePage.modelJobWorkerDiagram(processName);
|
|
53
53
|
await modelerCreatePage.runProcessInstance();
|
|
54
|
-
await (0, sleep_1.sleep)(
|
|
54
|
+
await (0, sleep_1.sleep)(10000);
|
|
55
55
|
});
|
|
56
56
|
await SM_8_10_1.test.step('View Process Instance in Operate and Assert Process has been successfully imported in Optimize', async () => {
|
|
57
57
|
await navigationPage.goToOperate();
|
|
@@ -60,7 +60,7 @@ if (process.env.IS_OPTIMIZE !== 'false') {
|
|
|
60
60
|
await operateProcessInstancePage.activeIconAssertion();
|
|
61
61
|
await navigationPage.goToOptimize();
|
|
62
62
|
await optimizeHomePage.clickDashboardLink();
|
|
63
|
-
await (0, sleep_1.sleep)(
|
|
63
|
+
await (0, sleep_1.sleep)(10000);
|
|
64
64
|
await page.reload();
|
|
65
65
|
await optimizeDashboardPage.clickFilterTable();
|
|
66
66
|
await optimizeDashboardPage.fillFilterTable(processName);
|
|
@@ -79,11 +79,11 @@ if (process.env.IS_OPTIMIZE !== 'false') {
|
|
|
79
79
|
await SM_8_10_1.test.step('Create BPMN Diagram with User Task and Start Process Instance', async () => {
|
|
80
80
|
await modelerCreatePage.modelJobWorkerDiagram(processName);
|
|
81
81
|
await modelerCreatePage.runProcessInstance();
|
|
82
|
-
await (0, sleep_1.sleep)(
|
|
82
|
+
await (0, sleep_1.sleep)(10000);
|
|
83
83
|
});
|
|
84
84
|
await SM_8_10_1.test.step('View Process Instance in Operate, Create User Task Report in Optimize, Start Another Process Instance in Modeler & Assert the Report Updates', async () => {
|
|
85
85
|
await navigationPage.goToOperate();
|
|
86
|
-
await (0, sleep_1.sleep)(
|
|
86
|
+
await (0, sleep_1.sleep)(10000);
|
|
87
87
|
await page.reload();
|
|
88
88
|
await operateHomePage.clickProcessesTab();
|
|
89
89
|
await operateProcessesPage.clickProcessInstanceLink(processName);
|
|
@@ -123,13 +123,13 @@ if (process.env.IS_OPTIMIZE !== 'false') {
|
|
|
123
123
|
await modelerCreatePage.runProcessInstance();
|
|
124
124
|
await (0, sleep_1.sleep)(10000);
|
|
125
125
|
await navigationPage.goToOperate();
|
|
126
|
-
await (0, sleep_1.sleep)(
|
|
126
|
+
await (0, sleep_1.sleep)(10000);
|
|
127
127
|
await page.reload();
|
|
128
128
|
await operateHomePage.clickProcessesTab();
|
|
129
129
|
await operateProcessesPage.clickProcessInstanceLink(processName);
|
|
130
130
|
await operateProcessInstancePage.activeIconAssertion();
|
|
131
131
|
await navigationPage.goToOptimize();
|
|
132
|
-
await (0, sleep_1.sleep)(
|
|
132
|
+
await (0, sleep_1.sleep)(10000);
|
|
133
133
|
await optimizeHomePage.clickCollectionsLink();
|
|
134
134
|
await (0, UtilitiesPage_2.assertPageTextWithRetry)(page, reportName, false, 30000);
|
|
135
135
|
await optimizeCollectionsPage.clickMostRecentProcessReport(reportName);
|
|
@@ -150,11 +150,11 @@ if (process.env.IS_OPTIMIZE !== 'false') {
|
|
|
150
150
|
await SM_8_10_1.test.step('Create BPMN Diagram with User Task and Start Process Instance', async () => {
|
|
151
151
|
await modelerCreatePage.modelJobWorkerDiagram(processName);
|
|
152
152
|
await modelerCreatePage.deployProcessInstance();
|
|
153
|
-
await (0, sleep_1.sleep)(
|
|
153
|
+
await (0, sleep_1.sleep)(10000);
|
|
154
154
|
});
|
|
155
155
|
await SM_8_10_1.test.step('Create Process Instance Count Report in Optimize, Start A Process Instance in Modeler & Assert the Report Updates', async () => {
|
|
156
156
|
await navigationPage.goToOptimize();
|
|
157
|
-
await (0, sleep_1.sleep)(
|
|
157
|
+
await (0, sleep_1.sleep)(40000);
|
|
158
158
|
await page.reload();
|
|
159
159
|
await optimizeHomePage.clickCollectionsLink();
|
|
160
160
|
await optimizeCollectionsPage.clickCreateNewButton();
|
|
@@ -187,7 +187,7 @@ if (process.env.IS_OPTIMIZE !== 'false') {
|
|
|
187
187
|
await modelerHomePage.clickCrossComponentProjectFolder();
|
|
188
188
|
await modelerHomePage.clickProcessDiagram(processName);
|
|
189
189
|
await modelerCreatePage.runProcessInstance();
|
|
190
|
-
await (0, sleep_1.sleep)(
|
|
190
|
+
await (0, sleep_1.sleep)(10000);
|
|
191
191
|
await navigationPage.goToOperate();
|
|
192
192
|
await operateHomePage.clickProcessesTab();
|
|
193
193
|
await operateProcessesPage.clickProcessInstanceLink(processName);
|
|
@@ -195,7 +195,7 @@ if (process.env.IS_OPTIMIZE !== 'false') {
|
|
|
195
195
|
timeout: 1200000,
|
|
196
196
|
});
|
|
197
197
|
await navigationPage.goToOptimize();
|
|
198
|
-
await (0, sleep_1.sleep)(
|
|
198
|
+
await (0, sleep_1.sleep)(15000);
|
|
199
199
|
await page.reload();
|
|
200
200
|
await optimizeHomePage.clickCollectionsLink();
|
|
201
201
|
await (0, UtilitiesPage_2.assertPageTextWithRetry)(page, reportName, false, 30000);
|
|
@@ -230,7 +230,7 @@ if (process.env.IS_OPTIMIZE !== 'false') {
|
|
|
230
230
|
await SM_8_10_1.test.step('Navigate to Optimize and verify Conditional Events process appears in Dashboards (CE-OPT-01)', async () => {
|
|
231
231
|
await navigationPage.goToOptimize();
|
|
232
232
|
await optimizeHomePage.clickDashboardLink();
|
|
233
|
-
await (0, sleep_1.sleep)(
|
|
233
|
+
await (0, sleep_1.sleep)(10000);
|
|
234
234
|
await page.reload();
|
|
235
235
|
await optimizeDashboardPage.clickFilterTable();
|
|
236
236
|
await optimizeDashboardPage.fillFilterTable(processName);
|
|
@@ -271,7 +271,7 @@ if (process.env.IS_OPTIMIZE !== 'false') {
|
|
|
271
271
|
});
|
|
272
272
|
await SM_8_10_1.test.step('Navigate to Optimize and create a User Task Table report for Conditional Events process (CE-OPT-03)', async () => {
|
|
273
273
|
await navigationPage.goToOptimize();
|
|
274
|
-
await (0, sleep_1.sleep)(
|
|
274
|
+
await (0, sleep_1.sleep)(10000);
|
|
275
275
|
await page.reload();
|
|
276
276
|
await optimizeHomePage.clickCollectionsLink();
|
|
277
277
|
await optimizeCollectionsPage.clickCreateNewButton();
|
|
@@ -333,7 +333,7 @@ if (process.env.IS_OPTIMIZE !== 'false') {
|
|
|
333
333
|
});
|
|
334
334
|
await SM_8_10_1.test.step('Create a User Task Table report in Optimize and verify it shows count of 1', async () => {
|
|
335
335
|
await navigationPage.goToOptimize();
|
|
336
|
-
await (0, sleep_1.sleep)(
|
|
336
|
+
await (0, sleep_1.sleep)(10000);
|
|
337
337
|
await page.reload();
|
|
338
338
|
await optimizeHomePage.clickCollectionsLink();
|
|
339
339
|
await optimizeCollectionsPage.clickCreateNewButton();
|
|
@@ -373,7 +373,7 @@ if (process.env.IS_OPTIMIZE !== 'false') {
|
|
|
373
373
|
});
|
|
374
374
|
await SM_8_10_1.test.step('Verify second process instance is completed in Operate', async () => {
|
|
375
375
|
await navigationPage.goToOperate();
|
|
376
|
-
await (0, sleep_1.sleep)(
|
|
376
|
+
await (0, sleep_1.sleep)(10000);
|
|
377
377
|
await page.reload();
|
|
378
378
|
await operateHomePage.clickProcessesTab();
|
|
379
379
|
await operateProcessesPage.clickProcessInstanceLink(processName, 'completed');
|
|
@@ -381,7 +381,7 @@ if (process.env.IS_OPTIMIZE !== 'false') {
|
|
|
381
381
|
});
|
|
382
382
|
await SM_8_10_1.test.step('Verify the Optimize report now shows 2 instances and the single instance count is gone (CE-OPT-05)', async () => {
|
|
383
383
|
await navigationPage.goToOptimize();
|
|
384
|
-
await (0, sleep_1.sleep)(
|
|
384
|
+
await (0, sleep_1.sleep)(10000);
|
|
385
385
|
await optimizeHomePage.clickCollectionsLink();
|
|
386
386
|
await (0, UtilitiesPage_2.assertPageTextWithRetry)(page, reportName, false, 30000);
|
|
387
387
|
await optimizeCollectionsPage.clickMostRecentProcessReport(reportName);
|
|
@@ -405,11 +405,11 @@ if (process.env.IS_OPTIMIZE !== 'false') {
|
|
|
405
405
|
});
|
|
406
406
|
await SM_8_10_1.test.step('Deploy the process without starting any instance', async () => {
|
|
407
407
|
await modelerCreatePage.deployProcessInstance();
|
|
408
|
-
await (0, sleep_1.sleep)(
|
|
408
|
+
await (0, sleep_1.sleep)(10000);
|
|
409
409
|
});
|
|
410
410
|
await SM_8_10_1.test.step('Create a User Task Table report in Optimize and verify it shows 0 instances (CE-OPT-08)', async () => {
|
|
411
411
|
await navigationPage.goToOptimize();
|
|
412
|
-
await (0, sleep_1.sleep)(
|
|
412
|
+
await (0, sleep_1.sleep)(40000);
|
|
413
413
|
await page.reload();
|
|
414
414
|
await optimizeHomePage.clickCollectionsLink();
|
|
415
415
|
await optimizeCollectionsPage.clickCreateNewButton();
|
|
@@ -445,7 +445,7 @@ if (process.env.IS_OPTIMIZE !== 'false') {
|
|
|
445
445
|
await modelerHomePage.clickProcessDiagram(bpmnFileName.replace('.bpmn', ''));
|
|
446
446
|
const variables = '{"myVar": 8}';
|
|
447
447
|
await modelerCreatePage.runProcessInstance(variables);
|
|
448
|
-
await (0, sleep_1.sleep)(
|
|
448
|
+
await (0, sleep_1.sleep)(10000);
|
|
449
449
|
await navigationPage.goToOperate();
|
|
450
450
|
await operateHomePage.clickProcessesTab();
|
|
451
451
|
await operateProcessesPage.clickProcessInstanceLink(processName, 'completed');
|
|
@@ -453,7 +453,7 @@ if (process.env.IS_OPTIMIZE !== 'false') {
|
|
|
453
453
|
});
|
|
454
454
|
await SM_8_10_1.test.step('Verify the Optimize report now shows data from 1 instance (CE-OPT-07 & CE-OPT-08)', async () => {
|
|
455
455
|
await navigationPage.goToOptimize();
|
|
456
|
-
await (0, sleep_1.sleep)(
|
|
456
|
+
await (0, sleep_1.sleep)(15000);
|
|
457
457
|
await page.reload();
|
|
458
458
|
await optimizeHomePage.clickCollectionsLink();
|
|
459
459
|
await (0, UtilitiesPage_2.assertPageTextWithRetry)(page, reportName, false, 30000);
|
package/package.json
CHANGED
package/playwright.config.ts
CHANGED
|
@@ -259,7 +259,10 @@ export default defineConfig({
|
|
|
259
259
|
use: {
|
|
260
260
|
baseURL: getBaseURL(),
|
|
261
261
|
actionTimeout: 10000,
|
|
262
|
-
|
|
262
|
+
// Stage 5: trace on-first-retry. With retries=1, a passing-on-retry
|
|
263
|
+
// test (i.e., a flake) leaves a trace from the first attempt — exactly
|
|
264
|
+
// the cases worth debugging. Green runs pay no trace cost.
|
|
265
|
+
trace: (process.env.C8E2E_TRACE as 'on' | 'off' | 'retain-on-failure' | 'on-first-retry') || 'on-first-retry',
|
|
263
266
|
video: (process.env.C8E2E_VIDEO as 'on' | 'off' | 'retain-on-failure') || 'off',
|
|
264
267
|
},
|
|
265
268
|
projects: [
|