mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-30 07:14:20 +00:00
fix(ui): match the "Save and launch scan" footer in the provider E2E flows (#13133)
This commit is contained in:
1 parent
75f81cc751
commit
7ecb6aaefd
3 files changed
+37
-37
No files matched your search
@@ -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()
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user