@camunda/e2e-test-suite 0.0.642 → 0.0.644
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/SM-8.10/ConnectorMarketplacePage.d.ts +1 -0
- package/dist/pages/SM-8.10/ConnectorMarketplacePage.js +7 -3
- package/dist/pages/SM-8.10/ModelerCreatePage.js +51 -0
- package/dist/pages/SM-8.10/OperateProcessesPage.js +21 -2
- package/dist/pages/SM-8.10/PlayPage.d.ts +1 -0
- package/dist/pages/SM-8.10/PlayPage.js +9 -1
- package/dist/pages/SM-8.10/UtilitiesPage.js +7 -0
- package/dist/resources/test-api-v2-complete.sh +11 -7
- package/dist/tests/SM-8.10/play.spec.js +16 -9
- package/package.json +1 -1
- package/resources/test-api-v2-complete.sh +11 -7
|
@@ -6,6 +6,7 @@ declare class ConnectorMarketplacePage {
|
|
|
6
6
|
readonly replaceResourceButton: Locator;
|
|
7
7
|
readonly cancelButton: Locator;
|
|
8
8
|
readonly marketplaceErrorMessage: Locator;
|
|
9
|
+
readonly noResultsMessage: Locator;
|
|
9
10
|
constructor(page: Page);
|
|
10
11
|
clickSearchForConnectorTextbox(): Promise<void>;
|
|
11
12
|
fillSearchForConnectorTextbox(connectorName: string): Promise<void>;
|
|
@@ -10,6 +10,7 @@ class ConnectorMarketplacePage {
|
|
|
10
10
|
replaceResourceButton;
|
|
11
11
|
cancelButton;
|
|
12
12
|
marketplaceErrorMessage;
|
|
13
|
+
noResultsMessage;
|
|
13
14
|
constructor(page) {
|
|
14
15
|
this.page = page;
|
|
15
16
|
this.searchForConnectorTextbox = page.getByPlaceholder('Search for a connector');
|
|
@@ -21,6 +22,7 @@ class ConnectorMarketplacePage {
|
|
|
21
22
|
name: 'Replace resource',
|
|
22
23
|
});
|
|
23
24
|
this.marketplaceErrorMessage = page.getByText('an error occurred, please try again later');
|
|
25
|
+
this.noResultsMessage = page.getByText('find a match for your search phrase');
|
|
24
26
|
}
|
|
25
27
|
async clickSearchForConnectorTextbox() {
|
|
26
28
|
await this.searchForConnectorTextbox.click({ timeout: 60000 });
|
|
@@ -42,11 +44,13 @@ class ConnectorMarketplacePage {
|
|
|
42
44
|
async waitForConnectorSearchResults() {
|
|
43
45
|
const MAX_RETRIES = 3;
|
|
44
46
|
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
|
45
|
-
await (0, test_1.expect)(this.downloadToProjectButton
|
|
47
|
+
await (0, test_1.expect)(this.downloadToProjectButton
|
|
48
|
+
.or(this.marketplaceErrorMessage)
|
|
49
|
+
.or(this.noResultsMessage)).toBeVisible({ timeout: 60000 });
|
|
46
50
|
if (await this.downloadToProjectButton.isVisible()) {
|
|
47
51
|
return;
|
|
48
52
|
}
|
|
49
|
-
console.log(`Marketplace search attempt ${attempt} of ${MAX_RETRIES} returned an error. Retrying search...`);
|
|
53
|
+
console.log(`Marketplace search attempt ${attempt} of ${MAX_RETRIES} returned an error or no results. Retrying search...`);
|
|
50
54
|
if (attempt < MAX_RETRIES) {
|
|
51
55
|
const searchText = await this.searchForConnectorTextbox.inputValue();
|
|
52
56
|
await this.searchForConnectorTextbox.clear();
|
|
@@ -55,7 +59,7 @@ class ConnectorMarketplacePage {
|
|
|
55
59
|
await (0, sleep_1.sleep)(2000);
|
|
56
60
|
}
|
|
57
61
|
}
|
|
58
|
-
throw new Error('Marketplace connector search failed after retries due to persistent error');
|
|
62
|
+
throw new Error('Marketplace connector search failed after retries due to persistent error or no matching results');
|
|
59
63
|
}
|
|
60
64
|
async downloadConnectorToProject() {
|
|
61
65
|
await this.clickDownloadToProjectButton();
|
|
@@ -710,6 +710,57 @@ class ModelerCreatePage {
|
|
|
710
710
|
}
|
|
711
711
|
async completePlayConfiguration() {
|
|
712
712
|
const timeout = 30000;
|
|
713
|
+
// New flow (8.10+): "Setup environment" panel with three steps:
|
|
714
|
+
// 1. Connect cluster → "Configure environment" modal → select cluster → Save
|
|
715
|
+
// 2. Deploy process → wait for success banner
|
|
716
|
+
// 3. Configure scenario
|
|
717
|
+
const setupDeployButton = this.page
|
|
718
|
+
.getByText('Deploy process')
|
|
719
|
+
.locator('..')
|
|
720
|
+
.getByRole('button', { name: 'Deploy' });
|
|
721
|
+
const configureScenarioButton = this.page.getByRole('button', {
|
|
722
|
+
name: 'Configure scenario',
|
|
723
|
+
});
|
|
724
|
+
// Wait up to 15s for EITHER the new-flow setup panel OR the legacy Continue
|
|
725
|
+
// button to appear. Using .or() avoids separate sequential timeouts that would
|
|
726
|
+
// both expire before the page finishes loading on a slow cluster.
|
|
727
|
+
const setupOrContinue = setupDeployButton.or(this.continueToPlayButton);
|
|
728
|
+
const panelAppeared = await setupOrContinue
|
|
729
|
+
.first()
|
|
730
|
+
.isVisible({ timeout: 15000 })
|
|
731
|
+
.catch(() => false);
|
|
732
|
+
if (!panelAppeared) {
|
|
733
|
+
// Neither appeared — Play is already configured and ready.
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
const isNewFlow = await setupDeployButton.isVisible().catch(() => false);
|
|
737
|
+
if (isNewFlow) {
|
|
738
|
+
// Step 1: connect cluster if not yet connected (modal with cluster dropdown)
|
|
739
|
+
const connectClusterButton = this.page.getByRole('button', {
|
|
740
|
+
name: 'Connect cluster',
|
|
741
|
+
});
|
|
742
|
+
const needsConnect = await connectClusterButton
|
|
743
|
+
.isVisible({ timeout: 3000 })
|
|
744
|
+
.catch(() => false);
|
|
745
|
+
if (needsConnect) {
|
|
746
|
+
await connectClusterButton.click({ timeout });
|
|
747
|
+
const configureEnvDialog = this.page
|
|
748
|
+
.getByRole('dialog')
|
|
749
|
+
.filter({ hasText: 'Configure environment' });
|
|
750
|
+
await configureEnvDialog.getByRole('combobox').click({ timeout });
|
|
751
|
+
await this.page.getByRole('option').first().click({ timeout });
|
|
752
|
+
await configureEnvDialog
|
|
753
|
+
.getByRole('button', { name: 'Save' })
|
|
754
|
+
.click({ timeout });
|
|
755
|
+
}
|
|
756
|
+
// Step 2: deploy
|
|
757
|
+
await setupDeployButton.click({ timeout });
|
|
758
|
+
await (0, test_1.expect)(this.page.getByText('Process has been successfully deployed')).toBeVisible({ timeout: 90000 });
|
|
759
|
+
// Step 3: configure scenario
|
|
760
|
+
await configureScenarioButton.click({ timeout });
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
// Legacy flow: "Continue" button → "Play environment is ready" confirmation.
|
|
713
764
|
let attempts = 0;
|
|
714
765
|
const maxRetries = 2;
|
|
715
766
|
while (attempts < maxRetries) {
|
|
@@ -49,7 +49,18 @@ class OperateProcessesPage {
|
|
|
49
49
|
async checkCheckbox(checkbox) {
|
|
50
50
|
await checkbox.waitFor({ state: 'attached', timeout: constants_1._1_SECOND_IN_MS * 10 });
|
|
51
51
|
if (!(await checkbox.isChecked())) {
|
|
52
|
-
|
|
52
|
+
// Carbon DS checkboxes are hidden inputs — click the label to trigger React's
|
|
53
|
+
// synthetic event instead of force-checking the hidden input directly, which
|
|
54
|
+
// would be overridden by React's controlled state on the next render.
|
|
55
|
+
const checkboxId = await checkbox.getAttribute('id');
|
|
56
|
+
if (checkboxId) {
|
|
57
|
+
await this.page
|
|
58
|
+
.locator(`label[for="${checkboxId}"]`)
|
|
59
|
+
.click({ timeout: constants_1._1_SECOND_IN_MS * 30 });
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
await checkbox.check({ force: true, timeout: constants_1._1_SECOND_IN_MS * 30 });
|
|
63
|
+
}
|
|
53
64
|
await (0, test_1.expect)(checkbox).toBeChecked({
|
|
54
65
|
checked: true,
|
|
55
66
|
timeout: constants_1._1_SECOND_IN_MS * 30,
|
|
@@ -59,7 +70,15 @@ class OperateProcessesPage {
|
|
|
59
70
|
async uncheckCheckbox(checkbox) {
|
|
60
71
|
await checkbox.waitFor({ state: 'attached', timeout: constants_1._1_SECOND_IN_MS * 10 });
|
|
61
72
|
if (await checkbox.isChecked()) {
|
|
62
|
-
await checkbox.
|
|
73
|
+
const checkboxId = await checkbox.getAttribute('id');
|
|
74
|
+
if (checkboxId) {
|
|
75
|
+
await this.page
|
|
76
|
+
.locator(`label[for="${checkboxId}"]`)
|
|
77
|
+
.click({ timeout: constants_1._1_SECOND_IN_MS * 30 });
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
await checkbox.uncheck({ force: true, timeout: constants_1._1_SECOND_IN_MS * 30 });
|
|
81
|
+
}
|
|
63
82
|
await (0, test_1.expect)(checkbox).toBeChecked({
|
|
64
83
|
checked: false,
|
|
65
84
|
timeout: constants_1._1_SECOND_IN_MS * 30,
|
|
@@ -21,6 +21,7 @@ declare class PlayPage {
|
|
|
21
21
|
readonly loadingInstanceDetailsText: Locator;
|
|
22
22
|
readonly retryButton: Locator;
|
|
23
23
|
readonly dialog: Locator;
|
|
24
|
+
readonly inputPanelStartButton: Locator;
|
|
24
25
|
constructor(page: Page);
|
|
25
26
|
waitForCompleteJobButtonToBeAvailable(): Promise<void>;
|
|
26
27
|
clickCompleteJobButton(): Promise<void>;
|
|
@@ -28,6 +28,7 @@ class PlayPage {
|
|
|
28
28
|
loadingInstanceDetailsText;
|
|
29
29
|
retryButton;
|
|
30
30
|
dialog;
|
|
31
|
+
inputPanelStartButton;
|
|
31
32
|
constructor(page) {
|
|
32
33
|
this.page = page;
|
|
33
34
|
this.dialog = page.getByRole('dialog');
|
|
@@ -63,6 +64,11 @@ class PlayPage {
|
|
|
63
64
|
this.saveScenarioModal = page.getByTestId('save-scenario-modal');
|
|
64
65
|
this.loadingInstanceDetailsText = this.page.getByText('Loading instance details...');
|
|
65
66
|
this.retryButton = this.page.getByRole('button', { name: 'Retry' });
|
|
67
|
+
// New Play UI (8.10+): "Configure scenario" opens an input panel with a plain "Start" button.
|
|
68
|
+
this.inputPanelStartButton = page.getByRole('button', {
|
|
69
|
+
name: 'Start',
|
|
70
|
+
exact: true,
|
|
71
|
+
});
|
|
66
72
|
}
|
|
67
73
|
async waitForCompleteJobButtonToBeAvailable() {
|
|
68
74
|
await (0, test_1.expect)(this.completeJobButton).toBeVisible({
|
|
@@ -75,6 +81,7 @@ class PlayPage {
|
|
|
75
81
|
}
|
|
76
82
|
async clickStartInstanceButton() {
|
|
77
83
|
const startTrigger = this.configureTestPanelStartButton
|
|
84
|
+
.or(this.inputPanelStartButton)
|
|
78
85
|
.or(this.startInstanceButton)
|
|
79
86
|
.or(this.startInstanceWithCachedButton)
|
|
80
87
|
.first();
|
|
@@ -108,7 +115,8 @@ class PlayPage {
|
|
|
108
115
|
await this.page.waitForLoadState('load');
|
|
109
116
|
}
|
|
110
117
|
}
|
|
111
|
-
|
|
118
|
+
// No modal present — new Play UI skips the modal entirely (Configure scenario
|
|
119
|
+
// opens the input panel directly without a modal step).
|
|
112
120
|
}
|
|
113
121
|
async clickStartInstanceWithCachedButton() {
|
|
114
122
|
await this.diagram.waitFor({ state: 'visible', timeout: 30000 });
|
|
@@ -174,6 +174,13 @@ async function modelRestConnector(modelerCreatePage, connectorSettingsPage, conn
|
|
|
174
174
|
await connectorMarketplacePage.fillSearchForConnectorTextbox('REST Connector');
|
|
175
175
|
await connectorMarketplacePage.waitForConnectorSearchResults();
|
|
176
176
|
await connectorMarketplacePage.downloadConnectorToProject();
|
|
177
|
+
// Marketplace modal closes the change-type dropdown. The task may remain in
|
|
178
|
+
// a selected state (class includes "djs-selected") which breaks the exact
|
|
179
|
+
// class-attribute match used by secondElement. Click the canvas background
|
|
180
|
+
// first to deselect, then re-select the task and reopen the dropdown.
|
|
181
|
+
await modelerCreatePage.clickCanvas();
|
|
182
|
+
await modelerCreatePage.secondElement.click({ timeout: 30000 });
|
|
183
|
+
await modelerCreatePage.clickChangeTypeButton();
|
|
177
184
|
}
|
|
178
185
|
await modelerCreatePage.clickRestConnectorOption(recoverSession);
|
|
179
186
|
await connectorSettingsPage.clickAuthenticationTab();
|
|
@@ -10799,15 +10799,19 @@ BPMN_EOF
|
|
|
10799
10799
|
|
|
10800
10800
|
if [[ "$J2_RESTORE_SUCCESS" == "true" ]]; then
|
|
10801
10801
|
# Wait for authorization change to propagate
|
|
10802
|
-
sleep
|
|
10802
|
+
sleep 5
|
|
10803
10803
|
TEST_CLIENT_TOKEN="$(get_client_token "$TEST_CLIENT_ID" "$TEST_CLIENT_SECRET")"
|
|
10804
|
-
|
|
10804
|
+
|
|
10805
10805
|
# Step 6: HAPPY PATH - Create document as $CLIENT_ID client (should succeed)
|
|
10806
10806
|
echo -e "\n${BLUE}Step 6: HAPPY PATH - Creating document as '$CLIENT_ID' client (expecting 201)${NC}"
|
|
10807
|
-
|
|
10808
|
-
# Retry up to 5 times with
|
|
10807
|
+
|
|
10808
|
+
# Retry up to 5 times with increasing delay; refresh token on each retry to
|
|
10809
|
+
# handle auth-cache propagation delays (permission store may lag behind token).
|
|
10809
10810
|
happy_doc_status=""
|
|
10810
10811
|
for retry in 1 2 3 4 5; do
|
|
10812
|
+
# Refresh token on each attempt — the permission change may not be reflected
|
|
10813
|
+
# in the Keycloak token cache until a new token is issued.
|
|
10814
|
+
TEST_CLIENT_TOKEN="$(get_client_token "$TEST_CLIENT_ID" "$TEST_CLIENT_SECRET")"
|
|
10811
10815
|
DOC_TEST_CONTENT2="Authorization test document - with permission - $(date)"
|
|
10812
10816
|
DOC_TEST_FILENAME2="auth-test-doc-happy-$(date +%s)-retry$retry.txt"
|
|
10813
10817
|
DOC_TEST_TEMPFILE2="/tmp/$DOC_TEST_FILENAME2"
|
|
@@ -10864,12 +10868,12 @@ BPMN_EOF
|
|
|
10864
10868
|
break
|
|
10865
10869
|
else
|
|
10866
10870
|
if [[ $retry -lt 5 ]]; then
|
|
10867
|
-
echo " Retrying after
|
|
10868
|
-
sleep
|
|
10871
|
+
echo " Retrying after 3 seconds..."
|
|
10872
|
+
sleep 3
|
|
10869
10873
|
fi
|
|
10870
10874
|
fi
|
|
10871
10875
|
done
|
|
10872
|
-
|
|
10876
|
+
|
|
10873
10877
|
# If all retries failed
|
|
10874
10878
|
if [[ "$happy_doc_status" != "201" && "$happy_doc_status" != "200" ]]; then
|
|
10875
10879
|
echo -e "${RED}✗ UNEXPECTED: Document creation failed after 5 retries with permission restored${NC}"
|
|
@@ -92,6 +92,18 @@ SM_8_10_1.test.describe('Deploy and run a process in Play', () => {
|
|
|
92
92
|
timeout: 30000,
|
|
93
93
|
});
|
|
94
94
|
await modelerCreatePage.clickFirstPlacedGateway();
|
|
95
|
+
// On slow clusters clickFirstPlacedGateway() may trigger page.reload();
|
|
96
|
+
// the canvas needs settling before the context-pad JavaScript handler
|
|
97
|
+
// attaches. Wait up to 20 s for the context pad, then re-click the
|
|
98
|
+
// gateway directly (canvas is settled by then) if it still isn't open.
|
|
99
|
+
if (!(await modelerCreatePage.appendElementButton
|
|
100
|
+
.isVisible({ timeout: 20000 })
|
|
101
|
+
.catch(() => false))) {
|
|
102
|
+
await modelerCreatePage.firstPlacedGateway.click({ timeout: 10000 });
|
|
103
|
+
}
|
|
104
|
+
await (0, test_1.expect)(modelerCreatePage.appendElementButton).toBeVisible({
|
|
105
|
+
timeout: 15000,
|
|
106
|
+
});
|
|
95
107
|
await modelerCreatePage.clickAppendElementButton();
|
|
96
108
|
await modelerCreatePage.clickAppendTaskButton();
|
|
97
109
|
await modelerCreatePage.clickConnectToOtherElementButton();
|
|
@@ -102,15 +114,10 @@ SM_8_10_1.test.describe('Deploy and run a process in Play', () => {
|
|
|
102
114
|
// Wait for modeler background auto-save to complete
|
|
103
115
|
await (0, sleep_1.sleep)(2000);
|
|
104
116
|
await modelerCreatePage.switchToPlay();
|
|
105
|
-
// After diagram modification, Play
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
await modelerCreatePage.clickContinueToPlay();
|
|
110
|
-
}
|
|
111
|
-
catch {
|
|
112
|
-
// Continue button not present; Play loaded directly
|
|
113
|
-
}
|
|
117
|
+
// After diagram modification, Play shows the setup panel again (new flow)
|
|
118
|
+
// or a Continue button (legacy flow), or loads directly.
|
|
119
|
+
await modelerCreatePage.completePlayConfiguration();
|
|
120
|
+
await playPage.dismissStartModal();
|
|
114
121
|
await playPage.clickStartInstanceButton();
|
|
115
122
|
await playPage.waitForNextElementToBeActive('zeebe-user-task' + randomString + '1');
|
|
116
123
|
await playPage.waitForCompleteJobButtonToBeAvailable();
|
package/package.json
CHANGED
|
@@ -10799,15 +10799,19 @@ BPMN_EOF
|
|
|
10799
10799
|
|
|
10800
10800
|
if [[ "$J2_RESTORE_SUCCESS" == "true" ]]; then
|
|
10801
10801
|
# Wait for authorization change to propagate
|
|
10802
|
-
sleep
|
|
10802
|
+
sleep 5
|
|
10803
10803
|
TEST_CLIENT_TOKEN="$(get_client_token "$TEST_CLIENT_ID" "$TEST_CLIENT_SECRET")"
|
|
10804
|
-
|
|
10804
|
+
|
|
10805
10805
|
# Step 6: HAPPY PATH - Create document as $CLIENT_ID client (should succeed)
|
|
10806
10806
|
echo -e "\n${BLUE}Step 6: HAPPY PATH - Creating document as '$CLIENT_ID' client (expecting 201)${NC}"
|
|
10807
|
-
|
|
10808
|
-
# Retry up to 5 times with
|
|
10807
|
+
|
|
10808
|
+
# Retry up to 5 times with increasing delay; refresh token on each retry to
|
|
10809
|
+
# handle auth-cache propagation delays (permission store may lag behind token).
|
|
10809
10810
|
happy_doc_status=""
|
|
10810
10811
|
for retry in 1 2 3 4 5; do
|
|
10812
|
+
# Refresh token on each attempt — the permission change may not be reflected
|
|
10813
|
+
# in the Keycloak token cache until a new token is issued.
|
|
10814
|
+
TEST_CLIENT_TOKEN="$(get_client_token "$TEST_CLIENT_ID" "$TEST_CLIENT_SECRET")"
|
|
10811
10815
|
DOC_TEST_CONTENT2="Authorization test document - with permission - $(date)"
|
|
10812
10816
|
DOC_TEST_FILENAME2="auth-test-doc-happy-$(date +%s)-retry$retry.txt"
|
|
10813
10817
|
DOC_TEST_TEMPFILE2="/tmp/$DOC_TEST_FILENAME2"
|
|
@@ -10864,12 +10868,12 @@ BPMN_EOF
|
|
|
10864
10868
|
break
|
|
10865
10869
|
else
|
|
10866
10870
|
if [[ $retry -lt 5 ]]; then
|
|
10867
|
-
echo " Retrying after
|
|
10868
|
-
sleep
|
|
10871
|
+
echo " Retrying after 3 seconds..."
|
|
10872
|
+
sleep 3
|
|
10869
10873
|
fi
|
|
10870
10874
|
fi
|
|
10871
10875
|
done
|
|
10872
|
-
|
|
10876
|
+
|
|
10873
10877
|
# If all retries failed
|
|
10874
10878
|
if [[ "$happy_doc_status" != "201" && "$happy_doc_status" != "200" ]]; then
|
|
10875
10879
|
echo -e "${RED}✗ UNEXPECTED: Document creation failed after 5 retries with permission restored${NC}"
|