@camunda/e2e-test-suite 0.0.1379 → 0.0.1380
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.
|
@@ -24,6 +24,7 @@ declare class ClusterPage {
|
|
|
24
24
|
readonly clusterVersionOption: Locator;
|
|
25
25
|
readonly generationSearchInput: Locator;
|
|
26
26
|
readonly g3DevClusterType: Locator;
|
|
27
|
+
readonly clusterRegion: (clusterName: string, regionText: string) => Locator;
|
|
27
28
|
readonly alphaTab: Locator;
|
|
28
29
|
readonly devTab: Locator;
|
|
29
30
|
readonly stableTab: Locator;
|
|
@@ -49,7 +50,7 @@ declare class ClusterPage {
|
|
|
49
50
|
fillClusterNameInput(name: string): Promise<void>;
|
|
50
51
|
private extractClusterIdFromUrl;
|
|
51
52
|
private logClusterCreationInfo;
|
|
52
|
-
createCluster(name: string, region?: string, tasklistV1Api?: boolean): Promise<void>;
|
|
53
|
+
createCluster(name: string, region?: string, tasklistV1Api?: boolean, subRegion?: string): Promise<void>;
|
|
53
54
|
determineTasklistAPI(tasklistV1Api?: boolean): Promise<void>;
|
|
54
55
|
clickClusterType(): Promise<void>;
|
|
55
56
|
clickCreateClusterButton(): Promise<void>;
|
|
@@ -89,7 +90,7 @@ declare class ClusterPage {
|
|
|
89
90
|
clickDevTab(): Promise<void>;
|
|
90
91
|
clickStableTab(): Promise<void>;
|
|
91
92
|
clickQAGenerationsTab(): Promise<void>;
|
|
92
|
-
selectSubRegion(region: string): Promise<void>;
|
|
93
|
+
selectSubRegion(region: string, subRegion?: string): Promise<void>;
|
|
93
94
|
clickGCPRegion(): Promise<void>;
|
|
94
95
|
clickTasklistV1Api(): Promise<void>;
|
|
95
96
|
}
|
|
@@ -29,6 +29,7 @@ class ClusterPage {
|
|
|
29
29
|
clusterVersionOption;
|
|
30
30
|
generationSearchInput;
|
|
31
31
|
g3DevClusterType;
|
|
32
|
+
clusterRegion;
|
|
32
33
|
alphaTab;
|
|
33
34
|
devTab;
|
|
34
35
|
stableTab;
|
|
@@ -141,6 +142,7 @@ class ClusterPage {
|
|
|
141
142
|
});
|
|
142
143
|
this.dialog = page.getByRole('dialog');
|
|
143
144
|
this.clusterVersion = (clusterName, versionText) => this.clusterRow(clusterName).getByText(versionText, { exact: false });
|
|
145
|
+
this.clusterRegion = (clusterName, regionText) => this.clusterRow(clusterName).getByText(regionText, { exact: false });
|
|
144
146
|
}
|
|
145
147
|
async clickClusterBanner() {
|
|
146
148
|
// Camunda Hub has no `banner` landmark; "Clusters" instead lives in its
|
|
@@ -273,7 +275,7 @@ class ClusterPage {
|
|
|
273
275
|
console.warn(`⚠️ Could not extract cluster info for "${clusterName}": ${error}`);
|
|
274
276
|
}
|
|
275
277
|
}
|
|
276
|
-
async createCluster(name, region = 'GCP', tasklistV1Api) {
|
|
278
|
+
async createCluster(name, region = 'GCP', tasklistV1Api, subRegion) {
|
|
277
279
|
await this.clickClusterTab();
|
|
278
280
|
await this.deleteCluster(name);
|
|
279
281
|
await this.clickCreateNewClusterButton();
|
|
@@ -288,7 +290,7 @@ class ClusterPage {
|
|
|
288
290
|
.getByRole('tab', { name: region })
|
|
289
291
|
.or(this.page.getByRole('radio', { name: region, exact: true }))
|
|
290
292
|
.click();
|
|
291
|
-
await this.selectSubRegion(region);
|
|
293
|
+
await this.selectSubRegion(region, subRegion);
|
|
292
294
|
await this.clickClusterOption();
|
|
293
295
|
await this.determineTasklistAPI(tasklistV1Api);
|
|
294
296
|
await this.clickCreateClusterButton();
|
|
@@ -616,7 +618,29 @@ class ClusterPage {
|
|
|
616
618
|
async clickQAGenerationsTab() {
|
|
617
619
|
await this.qaGenerationsTab.click();
|
|
618
620
|
}
|
|
619
|
-
async selectSubRegion(region) {
|
|
621
|
+
async selectSubRegion(region, subRegion) {
|
|
622
|
+
// An explicit sub-region makes the choice reproducible. The default below
|
|
623
|
+
// picks at random, which is right for a test that only needs *a* cluster
|
|
624
|
+
// but wrong for one that has to know which region the cluster is in --
|
|
625
|
+
// console-cluster-duplication asserts that an overridden region beat the
|
|
626
|
+
// carried-over one, and a random source region can collide with the
|
|
627
|
+
// override and make that assertion vacuous.
|
|
628
|
+
if (subRegion) {
|
|
629
|
+
const known = {
|
|
630
|
+
Belgium: this.belgiumRegion,
|
|
631
|
+
Finland: this.finlandRegion,
|
|
632
|
+
London: this.londonRegion,
|
|
633
|
+
Ohio: this.ohioRegion,
|
|
634
|
+
};
|
|
635
|
+
const locator = known[subRegion];
|
|
636
|
+
if (!locator) {
|
|
637
|
+
throw new Error(`Unknown sub-region "${subRegion}". Known: ${Object.keys(known).join(', ')}`);
|
|
638
|
+
}
|
|
639
|
+
console.log(`Selected region: ${subRegion}`);
|
|
640
|
+
await (0, test_1.expect)(locator).toBeVisible({ timeout: 20000 });
|
|
641
|
+
await locator.click();
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
620
644
|
if (region === 'GCP') {
|
|
621
645
|
if (process.env.IS_PROD == 'true') {
|
|
622
646
|
await (0, test_1.expect)(this.londonRegion).toBeVisible({ timeout: 20000 });
|
|
@@ -10,6 +10,16 @@ const users_1 = require("../../utils/users");
|
|
|
10
10
|
// reads C8_USERNAME_TEST, which is not a member of the run's org (and is not
|
|
11
11
|
// exported at all in the nightly test job, so fill() received undefined).
|
|
12
12
|
const testUser = (0, users_1.getTestUser)('mainUser');
|
|
13
|
+
// The two GCP sub-regions a non-prod org can create in. DUP-02 pins the source
|
|
14
|
+
// to one and overrides to the other: left to its default selectSubRegion()
|
|
15
|
+
// picks at random, and a source that lands on the override's region makes
|
|
16
|
+
// "the override won" indistinguishable from "the source value carried over".
|
|
17
|
+
// The strings are the rendered tile labels, not display names -- see the
|
|
18
|
+
// belgiumRegion/finlandRegion locators in pages/8.10/ClusterPage.ts.
|
|
19
|
+
const SOURCE_SUB_REGION = 'Belgium';
|
|
20
|
+
const OVERRIDE_SUB_REGION = 'Finland';
|
|
21
|
+
const SOURCE_REGION_LABEL = 'Chaos, Belgium, Europe (europe-west1)';
|
|
22
|
+
const OVERRIDE_REGION_LABEL = 'Finland, Europe (europe-north1)';
|
|
13
23
|
/**
|
|
14
24
|
* Epic: camunda/product-hub#3824 - Console cluster duplication.
|
|
15
25
|
*
|
|
@@ -136,4 +146,95 @@ _8_10_1.test.describe('Console cluster duplication', () => {
|
|
|
136
146
|
await clusterDetailsPage.assertComponentsHealth();
|
|
137
147
|
});
|
|
138
148
|
});
|
|
149
|
+
// Scoped to name and region. The epic's case also lists plan type, channel
|
|
150
|
+
// and generation, but neither is overridable through today's page object:
|
|
151
|
+
// ClusterPage models exactly one cluster type (defaultClusterType =
|
|
152
|
+
// 'G3-Dev'), and createCluster() already drives the source through the same
|
|
153
|
+
// clickClusterOption() the duplicate would use, so both land on the same
|
|
154
|
+
// generation and an "override" assertion would pass without overriding
|
|
155
|
+
// anything. Asserting a value the test never set is what the first draft of
|
|
156
|
+
// this case did. Covering them needs page-object work first.
|
|
157
|
+
(0, _8_10_1.test)('DUP-02: a name and region overridden on the duplication form win over the carried-over ones', async ({ page, homePage, clusterPage, clusterDetailsPage, clusterSecretsPage, }) => {
|
|
158
|
+
// Two cluster creations plus health polling - this case is long by nature.
|
|
159
|
+
_8_10_1.test.setTimeout(60 * 60 * 1000);
|
|
160
|
+
const randomSuffix = await (0, _setup_1.generateRandomStringAsync)(6);
|
|
161
|
+
const sourceClusterName = `dup-src-ovr-${randomSuffix}`;
|
|
162
|
+
const duplicateClusterName = `dup-ovr-${randomSuffix}`;
|
|
163
|
+
await _8_10_1.test.step('given a healthy source cluster in a known region with its settings populated', async () => {
|
|
164
|
+
await clusterPage.clickClusterTab();
|
|
165
|
+
createdClusterNames.push(sourceClusterName);
|
|
166
|
+
// Pin the source region explicitly: the override below must differ from
|
|
167
|
+
// it, otherwise "the override won" is indistinguishable from "carried
|
|
168
|
+
// over". The second argument is the cloud provider, the fourth the
|
|
169
|
+
// sub-region -- passing a region label as the provider matches no tab.
|
|
170
|
+
await clusterPage.createCluster(sourceClusterName, 'GCP', undefined, SOURCE_SUB_REGION);
|
|
171
|
+
await clusterPage.assertClusterHealthyStatusWithRetry(sourceClusterName);
|
|
172
|
+
// A populated source - against an empty one this case would pass by
|
|
173
|
+
// copying nothing at all.
|
|
174
|
+
await clusterSecretsPage.createNewSecret(`DUP_SECRET_${randomSuffix}`, `dup-secret-value-${randomSuffix}`, sourceClusterName);
|
|
175
|
+
});
|
|
176
|
+
await _8_10_1.test.step('when I override the name and the region before submitting', async () => {
|
|
177
|
+
await homePage.clickClusters();
|
|
178
|
+
await clusterPage.clickClusterLink(sourceClusterName);
|
|
179
|
+
await clusterDetailsPage.dismissOopsIfPresent();
|
|
180
|
+
await (0, UtilitiesPage_1.waitForLoadingToFinish)(page);
|
|
181
|
+
await page.getByRole('button', { name: 'cluster operations' }).click();
|
|
182
|
+
const duplicateAction = page
|
|
183
|
+
.getByRole('menuitem', { name: /duplicate/i })
|
|
184
|
+
.or(page.getByRole('button', { name: /duplicate/i }));
|
|
185
|
+
await (0, test_1.expect)(duplicateAction).toBeVisible({ timeout: 30000 });
|
|
186
|
+
await duplicateAction.click();
|
|
187
|
+
// Every editable field of the duplication form, changed away from the
|
|
188
|
+
// value the form carried over from the source cluster.
|
|
189
|
+
await clusterPage.clickClusterNameInput();
|
|
190
|
+
await clusterPage.fillClusterNameInput(duplicateClusterName);
|
|
191
|
+
// clickGCPRegion only acts when REGION_SELECTION is set, so the tile
|
|
192
|
+
// click below is what actually moves the region either way.
|
|
193
|
+
await clusterPage.clickGCPRegion();
|
|
194
|
+
await clusterPage.selectSubRegion('GCP', OVERRIDE_SUB_REGION);
|
|
195
|
+
createdClusterNames.push(duplicateClusterName);
|
|
196
|
+
const submitDuplicate = page.getByRole('button', {
|
|
197
|
+
name: 'Duplicate cluster',
|
|
198
|
+
exact: true,
|
|
199
|
+
});
|
|
200
|
+
await (0, test_1.expect)(submitDuplicate).toBeEnabled({ timeout: 30000 });
|
|
201
|
+
// Same as DUP-01: hold the page until the duplicate POST has answered,
|
|
202
|
+
// otherwise navigating away aborts the in-flight request.
|
|
203
|
+
const duplicateResponse = page.waitForResponse((response) => response.request().method() === 'POST' &&
|
|
204
|
+
/\/clusters\/[^/]+\/duplicate$/.test(new URL(response.url()).pathname), { timeout: 60000 });
|
|
205
|
+
await submitDuplicate.click();
|
|
206
|
+
const duplicate = await duplicateResponse;
|
|
207
|
+
(0, test_1.expect)(duplicate.ok()).toBe(true);
|
|
208
|
+
const { clusterId } = await duplicate.json();
|
|
209
|
+
await page.waitForURL(new RegExp(`/cluster/${clusterId}`), {
|
|
210
|
+
timeout: 60000,
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
await _8_10_1.test.step('then the created duplicate carries the overridden values, not the source ones, and is healthy', async () => {
|
|
214
|
+
await homePage.clickClusters();
|
|
215
|
+
await (0, UtilitiesPage_1.waitForLoadingToFinish)(page);
|
|
216
|
+
// The overridden name is what the cluster was actually created with.
|
|
217
|
+
await (0, test_1.expect)(clusterPage.clusterLink(duplicateClusterName)).toBeVisible({
|
|
218
|
+
timeout: 60000,
|
|
219
|
+
});
|
|
220
|
+
await (0, test_1.expect)(clusterPage.clusterLink(sourceClusterName)).toBeVisible();
|
|
221
|
+
// The result, not the form state: the row of the cluster that was really
|
|
222
|
+
// created carries the overridden region. Scoped to that row rather than
|
|
223
|
+
// read off a page-wide getByText -- the source cluster is still listed
|
|
224
|
+
// on this same page and carries the region the override had to beat.
|
|
225
|
+
await (0, test_1.expect)(clusterPage.clusterRegion(duplicateClusterName, OVERRIDE_REGION_LABEL)).toBeVisible({ timeout: 60000 });
|
|
226
|
+
// ...and not the one it would have inherited from the source. Asserted
|
|
227
|
+
// after the positive check above, so an empty row cannot pass it.
|
|
228
|
+
await (0, test_1.expect)(clusterPage.clusterRegion(duplicateClusterName, SOURCE_REGION_LABEL)).toHaveCount(0);
|
|
229
|
+
// The source kept its own region, which is what makes the two labels
|
|
230
|
+
// above a real comparison rather than two reads of the same cluster.
|
|
231
|
+
await (0, test_1.expect)(clusterPage.clusterRegion(sourceClusterName, SOURCE_REGION_LABEL)).toBeVisible();
|
|
232
|
+
// Completion rule: a duplicate that is created but never healthy is the
|
|
233
|
+
// failure this epic exists to prevent.
|
|
234
|
+
await clusterPage.assertClusterHealthyStatusWithRetry(duplicateClusterName);
|
|
235
|
+
await clusterPage.clickClusterLink(duplicateClusterName);
|
|
236
|
+
await clusterDetailsPage.dismissOopsIfPresent();
|
|
237
|
+
await clusterDetailsPage.assertComponentsHealth();
|
|
238
|
+
});
|
|
239
|
+
});
|
|
139
240
|
});
|