mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-11-08 20:33:41 +00:00
329 lines
11 KiB
TypeScript
329 lines
11 KiB
TypeScript
import { expect, type Locator, type Page, test } from "@playwright/test";
|
|
|
|
import { BasePage } from "../base-page";
|
|
|
|
export class RegistryPage extends BasePage {
|
|
async captureEvidence(name: string): Promise<void> {
|
|
const path = test.info().outputPath(`${name}.png`);
|
|
await this.page.screenshot({
|
|
path,
|
|
fullPage: true,
|
|
animations: "disabled",
|
|
});
|
|
await test.info().attach(name, { path, contentType: "image/png" });
|
|
}
|
|
readonly connectButton: Locator;
|
|
readonly connectDialog: Locator;
|
|
readonly exploreTab: Locator;
|
|
readonly myArtifactsTab: Locator;
|
|
readonly registryKeyInput: Locator;
|
|
readonly registryLink: Locator;
|
|
readonly searchInput: Locator;
|
|
readonly refreshButton: Locator;
|
|
|
|
constructor(page: Page) {
|
|
super(page);
|
|
this.connectButton = page.getByRole("button", {
|
|
name: "Connect API key",
|
|
});
|
|
this.connectDialog = page.getByRole("dialog", {
|
|
name: "Connect Registry",
|
|
});
|
|
this.exploreTab = page.getByRole("tab", { name: /All/ });
|
|
this.myArtifactsTab = page.getByRole("tab", { name: /My artifacts/ });
|
|
this.registryKeyInput = page.getByLabel("Registry key");
|
|
this.registryLink = page.getByRole("link", { name: "Registry" });
|
|
this.searchInput = page.getByLabel("Search artifacts");
|
|
this.refreshButton = page.getByRole("button", { name: "Refresh Registry" });
|
|
}
|
|
|
|
async goto(): Promise<void> {
|
|
await super.goto("/registry");
|
|
await this.dismissWelcomeDialog();
|
|
}
|
|
|
|
artifactCardFor(name: string): Locator {
|
|
return this.page
|
|
.getByRole("listitem")
|
|
.filter({ has: this.page.getByText(name, { exact: true }) });
|
|
}
|
|
|
|
addButtonFor(name: string): Locator {
|
|
return this.page.getByRole("button", { name: `Add ${name}` });
|
|
}
|
|
|
|
updateButtonFor(name: string, version: string): Locator {
|
|
return this.page.getByRole("button", {
|
|
name: `Update ${name} to ${version}`,
|
|
});
|
|
}
|
|
|
|
removeButtonFor(name: string): Locator {
|
|
return this.page.getByRole("button", { name: `Remove ${name}` });
|
|
}
|
|
|
|
async verifyDirectRouteDenied(): Promise<void> {
|
|
await this.dismissWelcomeDialog();
|
|
await expect(this.page).not.toHaveURL(/\/registry(?:\?|$)/);
|
|
await expect(
|
|
this.page.getByRole("heading", { name: "Profile" }),
|
|
).toBeVisible();
|
|
}
|
|
|
|
async verifyRegistryNavigationVisible(): Promise<void> {
|
|
await this.dismissWelcomeDialog();
|
|
await expect(this.registryLink).toBeVisible();
|
|
}
|
|
|
|
async verifyRegistryNavigationHidden(): Promise<void> {
|
|
await expect(this.registryLink).toBeHidden();
|
|
}
|
|
|
|
async verifyProviderSelectorWithoutRegistry(): Promise<void> {
|
|
await this.page.goto("/providers");
|
|
await this.dismissWelcomeDialog();
|
|
await this.page.getByRole("button", { name: /Add (a )?Provider/i }).click();
|
|
await expect(
|
|
this.page.getByRole("option", {
|
|
name: "Amazon Web Services",
|
|
exact: true,
|
|
}),
|
|
).toBeVisible();
|
|
await expect(
|
|
this.page.getByRole("tab", { name: "Registry", exact: true }),
|
|
).toBeHidden();
|
|
await expect(
|
|
this.page.getByRole("tab", { name: "All providers", exact: true }),
|
|
).toBeHidden();
|
|
}
|
|
|
|
async verifyOnboarding(): Promise<void> {
|
|
await expect(this.connectButton).toBeVisible();
|
|
await expect(
|
|
this.page.getByRole("link", {
|
|
name: "Explore Prowler Registry (opens in a new tab)",
|
|
}),
|
|
).toBeVisible();
|
|
}
|
|
|
|
async verifyMarketplaceReady(): Promise<void> {
|
|
await expect(this.exploreTab).toBeVisible();
|
|
await expect(
|
|
this.page.getByRole("button", { name: "Manage access" }),
|
|
).toBeVisible();
|
|
}
|
|
|
|
async verifySearchPreserved(search: string): Promise<void> {
|
|
await expect(this.searchInput).toHaveValue(search);
|
|
expect(new URL(this.page.url()).searchParams.get("filter[search]")).toBe(
|
|
search,
|
|
);
|
|
}
|
|
|
|
async submitRegistryKey(key: string): Promise<void> {
|
|
await this.connectButton.click();
|
|
await expect(this.connectDialog).toBeVisible();
|
|
await expect(this.registryKeyInput).toBeFocused();
|
|
await this.registryKeyInput.fill(key);
|
|
await this.page
|
|
.getByRole("button", { name: "Connect", exact: true })
|
|
.click();
|
|
}
|
|
|
|
async connectFixtureRegistry(): Promise<void> {
|
|
await this.dismissWelcomeDialog();
|
|
await this.verifyOnboarding();
|
|
await this.submitRegistryKey("fixture-registry-key-not-a-secret");
|
|
await this.verifyMarketplaceReady();
|
|
}
|
|
|
|
async verifyCompleteCatalogSearchAndFilters(): Promise<void> {
|
|
const sharedPolicyCard = this.page.getByText("Fixture shared policy", {
|
|
exact: true,
|
|
});
|
|
const networkAuditCard = this.page.getByText("Fixture network audit", {
|
|
exact: true,
|
|
});
|
|
await this.searchInput.fill("shared");
|
|
await expect(sharedPolicyCard).toBeVisible();
|
|
|
|
await this.page
|
|
.getByRole("combobox", { name: "Filter by provider" })
|
|
.press("Enter");
|
|
await this.page.getByRole("option", { name: "AWS", exact: true }).click();
|
|
await expect(this.page).toHaveURL(/filter%5Bprovider%5D=aws/);
|
|
await this.page.keyboard.press("Escape");
|
|
await expect(sharedPolicyCard).toBeVisible();
|
|
|
|
// The multi-provider artifact stays reachable through every provider it serves.
|
|
await this.page
|
|
.getByRole("combobox", { name: "Filter by provider" })
|
|
.press("Enter");
|
|
await this.page
|
|
.getByRole("option", { name: "Google Cloud", exact: true })
|
|
.click();
|
|
await this.page.keyboard.press("Escape");
|
|
await expect(sharedPolicyCard).toBeVisible();
|
|
await expect(networkAuditCard).toBeHidden();
|
|
|
|
await this.page
|
|
.getByRole("button", { name: "Clear filters", exact: true })
|
|
.click();
|
|
await expect(networkAuditCard).toBeVisible();
|
|
}
|
|
|
|
async verifyOwnerRows(): Promise<void> {
|
|
// Logo-backed owner renders its image; the logo-less owner falls back to
|
|
// an initial avatar, so only its name is asserted.
|
|
await expect(this.page.getByText("Prowler Fixtures")).toBeVisible();
|
|
await expect(
|
|
this.page.locator('img[src$="/fixture-owner.svg"]'),
|
|
).toBeVisible();
|
|
await expect(this.page.getByText("Community Fixtures")).toBeVisible();
|
|
}
|
|
|
|
async verifyBuiltInArtifactHasNoAdd(name: string): Promise<void> {
|
|
const card = this.artifactCardFor(name);
|
|
|
|
await expect(card.getByRole("status", { name: "Built in" })).toBeVisible();
|
|
await expect(
|
|
card.getByRole("button", { name: `Add ${name}` }),
|
|
).toBeHidden();
|
|
}
|
|
|
|
async addLatest(name: string): Promise<void> {
|
|
await this.addButtonFor(name).click();
|
|
await expect(
|
|
this.artifactCardFor(name).getByText("Added", { exact: true }),
|
|
).toBeVisible();
|
|
}
|
|
|
|
async verifyAddedInMyArtifacts(name: string): Promise<void> {
|
|
await this.myArtifactsTab.click();
|
|
await expect(this.removeButtonFor(name)).toBeVisible();
|
|
}
|
|
|
|
async removeArtifact(name: string): Promise<void> {
|
|
await this.removeButtonFor(name).click();
|
|
await expect(
|
|
this.page.getByRole("button", { name: "Cancel" }),
|
|
).toBeFocused();
|
|
await this.page.getByRole("button", { name: "Confirm Remove" }).click();
|
|
await expect(
|
|
this.page.getByText("Artifact removed", { exact: true }),
|
|
).toBeVisible();
|
|
}
|
|
|
|
async dismissWelcomeDialog(): Promise<void> {
|
|
for (const name of ["Got it", "Skip for now"]) {
|
|
const dismiss = this.page.getByRole("button", { name, exact: true });
|
|
if (
|
|
await dismiss
|
|
.waitFor({ state: "visible", timeout: 1500 })
|
|
.then(() => true)
|
|
.catch(() => false)
|
|
)
|
|
await dismiss.click({ timeout: 2000 }).catch(async () => {
|
|
// A route transition can unmount the welcome popover while it animates.
|
|
await expect(dismiss).toBeHidden();
|
|
});
|
|
}
|
|
}
|
|
|
|
async verifyKeyIsNotDisclosed(
|
|
key: string,
|
|
requestUrls: string[],
|
|
): Promise<void> {
|
|
const literalKey = new RegExp(
|
|
key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"),
|
|
"u",
|
|
);
|
|
await expect(this.page).not.toHaveURL(literalKey);
|
|
await expect(this.page.locator("body")).not.toContainText(key);
|
|
for (const requestUrl of requestUrls) {
|
|
expect(requestUrl).not.toContain(key);
|
|
}
|
|
|
|
const storedValues = await this.page.evaluate(() => [
|
|
...Object.values(localStorage),
|
|
...Object.values(sessionStorage),
|
|
]);
|
|
for (const storedValue of storedValues) {
|
|
expect(storedValue).not.toContain(key);
|
|
}
|
|
}
|
|
async connectInstalledProviderAndScan(): Promise<void> {
|
|
await this.page.getByRole("link", { name: "Go to Providers" }).click();
|
|
await expect(this.page).toHaveURL(/\/providers$/);
|
|
await this.dismissWelcomeDialog();
|
|
await this.page.getByRole("button", { name: /Add (a )?Provider/i }).click();
|
|
const allTab = this.page.getByRole("tab", {
|
|
name: "All providers",
|
|
exact: true,
|
|
});
|
|
const registryTab = this.page.getByRole("tab", {
|
|
name: "Registry",
|
|
exact: true,
|
|
});
|
|
const nativeProvider = this.page.getByRole("option", {
|
|
name: "Amazon Web Services",
|
|
exact: true,
|
|
});
|
|
await expect(allTab).toHaveAttribute("aria-selected", "true");
|
|
await expect(nativeProvider).toBeVisible();
|
|
await registryTab.click();
|
|
await expect(nativeProvider).toBeHidden();
|
|
await expect(
|
|
this.page.getByRole("option", { name: "Fixture Cloud Registry" }),
|
|
).toBeVisible();
|
|
await this.page
|
|
.getByRole("option", { name: "Fixture Cloud Registry" })
|
|
.scrollIntoViewIfNeeded();
|
|
await this.captureEvidence("registry-provider-selector");
|
|
await this.page
|
|
.getByRole("option", { name: "Fixture Cloud Registry" })
|
|
.click();
|
|
await this.page
|
|
.getByLabel("Provider UID", { exact: true })
|
|
.fill("fixture-account");
|
|
await this.page
|
|
.getByLabel("Provider alias (optional)")
|
|
.fill("Registry test account");
|
|
await this.page.getByRole("button", { name: "Next", exact: true }).click();
|
|
const token = this.page.getByLabel("API token", { exact: false });
|
|
await expect(token).toBeVisible();
|
|
await expect(token).toHaveAttribute("type", "password");
|
|
await this.captureEvidence("registry-provider-credentials");
|
|
await token.fill("fixture-provider-token-not-a-secret");
|
|
await this.page
|
|
.getByRole("button", { name: "Authenticate", exact: true })
|
|
.click();
|
|
await this.page
|
|
.getByRole("button", { name: "Check connection", exact: true })
|
|
.click();
|
|
await this.page
|
|
.getByRole("radio", { name: "Run now", exact: true })
|
|
.click();
|
|
await this.page
|
|
.getByRole("button", { name: "Launch scan", exact: true })
|
|
.click();
|
|
await expect(
|
|
this.page.getByText("Scan launched", { exact: true }),
|
|
).toBeVisible();
|
|
await this.page.goto("/scans?tab=completed");
|
|
const completedScan = this.page
|
|
.getByRole("tabpanel", { name: "Completed", exact: true })
|
|
.getByRole("row")
|
|
.filter({
|
|
has: this.page.getByText("Fixture Registry scan", { exact: true }),
|
|
});
|
|
await expect(
|
|
completedScan.getByText("Fixture Registry scan", { exact: true }),
|
|
).toBeVisible();
|
|
await expect(
|
|
completedScan.getByText("Registry test account", { exact: true }),
|
|
).toBeVisible();
|
|
await this.captureEvidence("registry-provider-scan-completed");
|
|
}
|
|
}
|