test(ui): drop organization unit tests restated by integration (#12382)

This commit is contained in:
Pablo Fernandez Guerra (PFE)
2026-08-11 15:41:34 +02:00
committed by GitHub
parent 3074f02a63
commit 931612443a
3 changed files with 4 additions and 303 deletions
@@ -7,6 +7,8 @@ import { CLOUD_UPGRADE_FEATURE } from "@/types/cloud-upgrade";
import { GcpMethodSelector } from "./gcp-method-selector";
// OSS gating only: `CloudUpgradeModal` mounts outside the providers page, so the
// harness cannot see the upsell open. The Cloud case is restated by integration.
describe("GcpMethodSelector", () => {
afterEach(() => {
vi.unstubAllEnvs();
@@ -40,29 +42,4 @@ describe("GcpMethodSelector", () => {
CLOUD_UPGRADE_FEATURE.GCP_ORGANIZATIONS,
);
});
it("enters the GCP org flow in Cloud", async () => {
// Given
vi.stubEnv("UI_CLOUD_ENABLED", "true");
const user = userEvent.setup();
const onSelectOrganizations = vi.fn();
// When
render(
<GcpMethodSelector
onSelectSingle={vi.fn()}
onSelectOrganizations={onSelectOrganizations}
/>,
);
// Then
await user.click(
screen.getByRole("radio", {
name: /add multiple projects with gcp organization/i,
}),
);
expect(onSelectOrganizations).toHaveBeenCalledTimes(1);
expect(useCloudUpgradeStore.getState().activeFeature).toBeNull();
});
});
@@ -1,10 +1,8 @@
import { act, renderHook } from "@testing-library/react";
import { createElement, type PropsWithChildren, StrictMode } from "react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { useOrgSetupStore } from "@/store/organizations/store";
import {
APPLY_STATUS,
DISCOVERY_STATUS,
ORG_SECRET_TYPE,
ORGANIZATION_TYPE,
@@ -80,10 +78,6 @@ vi.mock(
() => organizationsActionsMock,
);
function StrictModeWrapper({ children }: PropsWithChildren) {
return createElement(StrictMode, null, children);
}
/** Mocks the chain up to (and including) triggering discovery, all succeeding. */
function mockChainThroughDiscoveryTrigger() {
organizationsActionsMock.listOrganizationsByExternalId.mockResolvedValue({
@@ -123,116 +117,6 @@ describe("useOrgSetupSubmission", () => {
}
});
it("completes the setup chain and stores selectable candidates", async () => {
// Given
const onNext = vi.fn();
// `true` = the form owns the field and rendered the error on it.
const setFieldError = vi.fn(() => true);
const discoveryResult = {
roots: [
{ id: "r-root", arn: "arn:root", name: "Root", policy_types: [] },
],
organizational_units: [],
accounts: [
{
id: "111111111111",
name: "Account One",
arn: "arn:aws:organizations::111111111111:account/o-123/111111111111",
email: "one@example.com",
status: "ACTIVE",
joined_method: "CREATED",
joined_timestamp: "2024-01-01T00:00:00Z",
parent_id: "r-root",
registration: {
provider_exists: false,
provider_id: null,
organization_relation: "link_required",
organization_node_relation: "not_applicable",
provider_secret_state: "will_create",
apply_status: APPLY_STATUS.READY,
blocked_reasons: [],
},
},
{
id: "222222222222",
name: "Account Two",
arn: "arn:aws:organizations::222222222222:account/o-123/222222222222",
email: "two@example.com",
status: "ACTIVE",
joined_method: "CREATED",
joined_timestamp: "2024-01-01T00:00:00Z",
parent_id: "r-root",
registration: {
provider_exists: false,
provider_id: null,
organization_relation: "link_required",
organization_node_relation: "not_applicable",
provider_secret_state: "will_create",
apply_status: APPLY_STATUS.BLOCKED,
blocked_reasons: ["Already linked"],
},
},
],
};
organizationsActionsMock.listOrganizationsByExternalId.mockResolvedValue({
data: [],
});
organizationsActionsMock.createOrganization.mockResolvedValue({
data: { id: "org-1" },
});
organizationsActionsMock.listOrganizationSecretsByOrganizationId.mockResolvedValue(
{
data: [],
},
);
organizationsActionsMock.createOrganizationSecret.mockResolvedValue({
data: { id: "secret-1" },
});
organizationsActionsMock.triggerDiscovery.mockResolvedValue({
data: { id: "discovery-1" },
});
organizationsActionsMock.getDiscovery.mockResolvedValue({
data: {
attributes: {
status: DISCOVERY_STATUS.SUCCEEDED,
result: discoveryResult,
},
},
});
const { result } = renderHook(
() =>
useOrgSetupSubmission({
stackSetExternalId: "tenant-external-id",
onNext,
setFieldError,
}),
{ wrapper: StrictModeWrapper },
);
// When
await act(async () => {
await result.current.submitOrganizationSetup({
orgType: ORGANIZATION_TYPE.AWS,
organizationName: "Acme",
awsOrgId: "o-abc123def4",
roleArn: "arn:aws:iam::123456789012:role/ProwlerOrgRole",
});
});
// Then
expect(onNext).toHaveBeenCalledTimes(1);
expect(setFieldError).not.toHaveBeenCalled();
const state = useOrgSetupStore.getState();
expect(state.organizationId).toBe("org-1");
expect(state.organizationExternalId).toBe("o-abc123def4");
expect(state.discoveryId).toBe("discovery-1");
expect(state.selectedCandidateIds).toEqual(["111111111111"]);
expect(state.selectableCandidateIds).toEqual(["111111111111"]);
});
it("times out then resumes the same discovery via keep waiting", async () => {
// Given — a discovery that stays running until the client budget is spent.
vi.useFakeTimers();
@@ -292,6 +176,8 @@ describe("useOrgSetupSubmission", () => {
vi.useRealTimers();
});
// The MSW handler answers every trigger with the same static discovery, so
// integration can only count POSTs — not the retry clearing the failure.
it("retry triggers a fresh discovery after a failed one", async () => {
// Given — a discovery that completes as failed.
const onNext = vi.fn();
@@ -1,5 +1,4 @@
import { act, render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import type { ComponentProps } from "react";
import { beforeEach, describe, expect, it, vi } from "vitest";
@@ -138,47 +137,6 @@ describe("OrgLaunchScan", () => {
).toBe(`/scans?tab=${SCAN_JOBS_TAB.SCHEDULED}`);
});
it("should launch the complete organization after a partial schedule save", async () => {
// Given
const user = userEvent.setup();
const onFooterChange = vi.fn();
updateSchedulesBulkMock.mockResolvedValue({
data: {
updated: ["provider-2"],
failed: [{ id: "provider-1", error: "Denied" }],
},
});
render(
<OrgLaunchScan
onClose={vi.fn()}
onBack={vi.fn()}
onFooterChange={onFooterChange}
capability={SCAN_SCHEDULE_CAPABILITY.ADVANCED}
/>,
);
// When
await user.click(
await screen.findByRole("checkbox", {
name: /launch an initial scan now/i,
}),
);
await act(async () => {
lastFooterConfig(onFooterChange)?.onAction?.();
});
// Then
await waitFor(() =>
expect(launchOrganizationScansMock).toHaveBeenCalledTimes(1),
);
expect(launchOrganizationScansMock).toHaveBeenCalledWith("org-1");
expect(scheduleOrganizationDailyScansMock).not.toHaveBeenCalled();
expect(
toastMock.mock.calls[0]?.[0].action.props.children.props.href,
).toBe(`/scans?tab=${SCAN_JOBS_TAB.ACTIVE}`);
});
it("should disable launch actions while schedule capability is loading", async () => {
// Given
const onFooterChange = vi.fn();
@@ -246,126 +204,6 @@ describe("OrgLaunchScan", () => {
expect(pushMock).not.toHaveBeenCalled();
expect(onClose).not.toHaveBeenCalled();
});
it("should treat a fully-failed bulk response as an error without navigating away", async () => {
// Given
const onClose = vi.fn();
const onFooterChange = vi.fn();
updateSchedulesBulkMock.mockResolvedValue({
data: {
updated: [],
failed: [
{ id: "provider-1", error: "Denied" },
{ id: "provider-2", error: "Denied" },
],
},
});
render(
<OrgLaunchScan
onClose={onClose}
onBack={vi.fn()}
onFooterChange={onFooterChange}
capability={SCAN_SCHEDULE_CAPABILITY.ADVANCED}
/>,
);
// When
await screen.findByText("Scan Schedule");
await act(async () => {
lastFooterConfig(onFooterChange)?.onAction?.();
});
// Then
await waitFor(() =>
expect(toastMock).toHaveBeenCalledWith(
expect.objectContaining({
variant: "destructive",
title: "Unable to save scan schedules",
description:
"The scan schedule could not be saved for 2 accounts: Denied.",
}),
),
);
expect(launchOrganizationScansMock).not.toHaveBeenCalled();
expect(pushMock).not.toHaveBeenCalled();
expect(onClose).not.toHaveBeenCalled();
});
it("should describe partial failures in the success toast", async () => {
// Given
const onFooterChange = vi.fn();
updateSchedulesBulkMock.mockResolvedValue({
data: {
updated: ["provider-2"],
failed: [{ id: "provider-1", error: "Denied" }],
},
});
render(
<OrgLaunchScan
onClose={vi.fn()}
onBack={vi.fn()}
onFooterChange={onFooterChange}
capability={SCAN_SCHEDULE_CAPABILITY.ADVANCED}
/>,
);
// When
await screen.findByText("Scan Schedule");
await act(async () => {
lastFooterConfig(onFooterChange)?.onAction?.();
});
// Then
await waitFor(() => expect(toastMock).toHaveBeenCalled());
expect(toastMock).toHaveBeenCalledWith(
expect.objectContaining({
title: "Scan schedules saved",
description:
"The schedule was saved for 1 account, but 1 account could not be updated: Denied.",
}),
);
});
it("should proceed when the response carries no result lists", async () => {
// Given — an empty 200/204 body. The endpoint commits each schedule before
// answering, so this is not a failure.
const user = userEvent.setup();
const onFooterChange = vi.fn();
updateSchedulesBulkMock.mockResolvedValue({ success: true });
render(
<OrgLaunchScan
onClose={vi.fn()}
onBack={vi.fn()}
onFooterChange={onFooterChange}
capability={SCAN_SCHEDULE_CAPABILITY.ADVANCED}
/>,
);
// When
await user.click(
await screen.findByRole("checkbox", {
name: /launch an initial scan now/i,
}),
);
await act(async () => {
lastFooterConfig(onFooterChange)?.onAction?.();
});
// Then — every created provider is treated as saved and scanned.
await waitFor(() =>
expect(launchOrganizationScansMock).toHaveBeenCalledWith("org-1"),
);
expect(toastMock).toHaveBeenCalledWith(
expect.objectContaining({
title: "Scan schedules saved and initial scans launched",
description: "The scan schedule was saved for 2 accounts.",
}),
);
expect(pushMock).toHaveBeenCalledWith("/providers");
});
});
describe("when capability is DAILY_LEGACY", () => {