fix(ui): match the "Save and launch scan" footer in the provider E2E flows (#13133)

This commit is contained in:
Alejandro Bailo authored and GitHub committed 2026-10-26 12:53:36 +01:00
1 parent 75f81cc751
commit 7ecb6aaefd
3 files changed
+37 -37

No files matched your search

+9
View File
@@ -39,6 +39,9 @@ jobs:
github.repository == 'prowler-cloud/prowler' &&
(github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false) &&
(needs.impact-analysis.outputs.has-ui-e2e == 'true' || needs.impact-analysis.outputs.run-all == 'true')
# ubuntu-latest is moving to 26.04 (rollout began October 19, 2026; completion
# targeted for November 19, 2026), where `playwright install` refuses to install
# Chromium for the pinned Playwright. Stay on 24.04 until the suite upgrades.
runs-on: ubuntu-24.04
env:
AUTH_SECRET: "fallback-ci-secret-for-testing"
@@ -391,6 +394,12 @@ jobs:
working-directory: ./ui
run: pnpm run test:e2e:registry
# A worker that crashes on import or a connection test that never resolves
# only shows up here; Playwright just reports a missing footer button.
- name: Dump API service logs
if: failure()
run: docker compose logs --no-color --tail=300 api worker worker-beat || true
- name: Upload test reports
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
if: failure()
+3
View File
@@ -21,6 +21,9 @@ permissions: {}
jobs:
ui-tests:
# ubuntu-latest is moving to 26.04 (rollout began October 19, 2026; completion
# targeted for November 19, 2026), where `playwright install` refuses to install
# Chromium for the pinned Playwright. Stay on 24.04 until the suite upgrades.
runs-on: ubuntu-24.04
timeout-minutes: 20
permissions:
+25 -37
View File
@@ -267,6 +267,11 @@ export interface VercelProviderCredential {
apiToken: string;
}
// The wizard's final action. Setup pre-ticks "launch an initial scan", so the
// schedule step reads "Save and launch scan" ("Save" once unticked); manual-only
// accounts get "Launch scan" instead. Anchored so "Save" never matches a longer label.
const LAUNCH_STEP_ACTION_NAME = /^(Save|Save and launch scan|Launch scan)$/;
// Providers page
export class ProvidersPage extends BasePage {
readonly wizardModal: Locator;
@@ -934,6 +939,10 @@ export class ProvidersPage extends BasePage {
}
}
private get launchStepAction(): Locator {
return this.page.getByRole("button", { name: LAUNCH_STEP_ACTION_NAME });
}
async clickNext(): Promise<void> {
await this.verifyWizardModalOpen();
@@ -943,6 +952,7 @@ export class ProvidersPage extends BasePage {
"Connect account",
"Next",
"Save",
"Save and launch scan",
"Check connection",
"Launch scan",
] as const;
@@ -957,9 +967,8 @@ export class ProvidersPage extends BasePage {
if (actionName === "Check connection") {
await this.handleCheckConnectionCompletion();
}
// "Save" is the wizard's final action (saves the scan schedule) and
// "Launch scan" its legacy/manual counterpart; both close the modal.
if (actionName === "Launch scan" || actionName === "Save") {
// The launch step's action (see LAUNCH_STEP_ACTION_NAME) closes the modal.
if (LAUNCH_STEP_ACTION_NAME.test(actionName)) {
await this.handleLaunchScanCompletion();
}
return;
@@ -972,24 +981,16 @@ export class ProvidersPage extends BasePage {
}
private async handleCheckConnectionCompletion(): Promise<void> {
// A successful connection advances to the schedule step ("Save"); older
// flows surfaced a "Launch scan" action instead.
const saveScheduleButton = this.page.getByRole("button", {
name: "Save",
exact: true,
});
const launchScanButton = this.page.getByRole("button", {
name: "Launch scan",
exact: true,
});
// A successful connection advances to the launch step; update flows may
// close the modal instead.
const launchAction = this.launchStepAction;
const connectionError = this.page.locator(
"div.border-border-error p.text-text-error-primary",
);
try {
await Promise.race([
saveScheduleButton.waitFor({ state: "visible", timeout: 30000 }),
launchScanButton.waitFor({ state: "visible", timeout: 30000 }),
launchAction.waitFor({ state: "visible", timeout: 30000 }),
this.wizardModal.waitFor({ state: "hidden", timeout: 30000 }),
connectionError.waitFor({ state: "visible", timeout: 30000 }),
]);
@@ -1004,19 +1005,14 @@ export class ProvidersPage extends BasePage {
);
}
if (await saveScheduleButton.isVisible().catch(() => false)) {
await saveScheduleButton.click();
await this.handleLaunchScanCompletion();
} else if (await launchScanButton.isVisible().catch(() => false)) {
await launchScanButton.click();
if (await launchAction.isVisible().catch(() => false)) {
await launchAction.click();
await this.handleLaunchScanCompletion();
}
}
private async waitForProviderLaunchChoice(): Promise<void> {
const launchAction = this.page
.getByRole("button", { name: "Save", exact: true })
.or(this.page.getByRole("button", { name: "Launch scan", exact: true }));
const launchAction = this.launchStepAction;
const connectionError = this.page.locator(
"div.border-border-error p.text-text-error-primary",
);
@@ -1049,9 +1045,7 @@ export class ProvidersPage extends BasePage {
name: "Check connection",
exact: true,
});
const launchAction = this.page
.getByRole("button", { name: "Save", exact: true })
.or(this.page.getByRole("button", { name: "Launch scan", exact: true }));
const launchAction = this.launchStepAction;
const connectionError = this.page.locator(
"div.border-border-error p.text-text-error-primary",
);
@@ -1664,17 +1658,11 @@ export class ProvidersPage extends BasePage {
await this.verifyPageHasProwlerTitle();
await this.verifyWizardModalOpen();
// The final step saves the scan schedule ("Save"); manual-only accounts
// show "Launch scan" and some providers show "Check connection" first.
const launchAction = this.page
.getByRole("button", { name: "Save", exact: true })
.or(this.page.getByRole("button", { name: "Launch scan", exact: true }))
.or(
this.page.getByRole("button", {
name: "Check connection",
exact: true,
}),
);
// The launch step's action, or "Check connection" for providers that
// still have to test the connection first.
const launchAction = this.launchStepAction.or(
this.page.getByRole("button", { name: "Check connection", exact: true }),
);
await expect(launchAction).toBeVisible();
}