Files
prowler/ui/lib/organizations.test.ts
T

143 lines
5.2 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
NODE_KIND,
NodeKind,
ORGANIZATION_TYPE,
OrganizationType,
} from "@/types/organizations";
import {
getCandidateNoun,
organizationNameFallbackHint,
getNodeLabel,
toNodeKind,
} from "./organizations";
describe("getNodeLabel", () => {
it("labels a node by its kind, regardless of organization type", () => {
expect(
getNodeLabel(ORGANIZATION_TYPE.AWS, NODE_KIND.ORGANIZATIONAL_UNIT),
).toBe("Organizational Unit");
expect(getNodeLabel(ORGANIZATION_TYPE.GCP, NODE_KIND.FOLDER)).toBe(
"Folder",
);
expect(
getNodeLabel(ORGANIZATION_TYPE.AZURE, NODE_KIND.MANAGEMENT_GROUP),
).toBe("Management Group");
});
it("falls back to the organization type's container label when kind is absent", () => {
// Nodes served before the canonical `kind` attribute exists, or organization
// rows that have no kind at all.
expect(getNodeLabel(ORGANIZATION_TYPE.AWS)).toBe("Organizational Unit");
expect(getNodeLabel(ORGANIZATION_TYPE.GCP)).toBe("Folder");
expect(getNodeLabel(ORGANIZATION_TYPE.AZURE)).toBe("Management Group");
});
it("falls back to neutral wording for an organization type this build predates", () => {
// The enum mirrors a server-side one: an unknown value must render neutrally
// instead of crashing the cell or claiming AWS.
expect(getNodeLabel("oci" as OrganizationType)).toBe("Group");
expect(organizationNameFallbackHint("oci" as OrganizationType)).toBe(
"If left blank, Prowler will use the organization identifier.",
);
});
it("falls back to the container label for a node kind this build predates", () => {
// `kind` is typed but unvalidated: node rows pass the wire attribute
// straight through, so a backend-added kind must resolve to the
// organization's own container label. Returning `undefined` would crash
// callers that lowercase the result (the deletion dialog). Every kind this
// build knows now has a label, so the case needs a kind it does not.
const unknownKind = "compartment" as NodeKind;
expect(getNodeLabel(ORGANIZATION_TYPE.AWS, unknownKind)).toBe(
"Organizational Unit",
);
expect(getNodeLabel(ORGANIZATION_TYPE.GCP, unknownKind)).toBe("Folder");
expect(getNodeLabel(ORGANIZATION_TYPE.AZURE, unknownKind)).toBe(
"Management Group",
);
expect(getNodeLabel("oci" as OrganizationType, unknownKind)).toBe("Group");
});
it("falls back for wire values that collide with Object.prototype keys", () => {
// The lookup tables are object literals, so indexing them with an inherited
// key returns a truthy non-string — a function, or the prototype itself.
// That defeats a `??` fallback and hands the callers something they then
// call `.toLowerCase()` on. Every label getter must survive it.
for (const key of [
"constructor",
"toString",
"valueOf",
"hasOwnProperty",
"__proto__",
]) {
expect(getNodeLabel(ORGANIZATION_TYPE.AWS, key as NodeKind)).toBe(
"Organizational Unit",
);
expect(getNodeLabel(key as OrganizationType, "folder" as NodeKind)).toBe(
"Folder",
);
expect(getNodeLabel(key as OrganizationType)).toBe("Group");
expect(organizationNameFallbackHint(key as OrganizationType)).toBe(
"If left blank, Prowler will use the organization identifier.",
);
expect(getCandidateNoun(key as OrganizationType)).toEqual({
singular: "account",
plural: "accounts",
});
}
});
});
describe("organizationNameFallbackHint", () => {
it("names the identifier the organization falls back to, per type", () => {
// Never a provider-side name: the organization exists before discovery runs.
expect(organizationNameFallbackHint(ORGANIZATION_TYPE.AWS)).toBe(
"If left blank, Prowler will use the AWS organization ID.",
);
expect(organizationNameFallbackHint(ORGANIZATION_TYPE.GCP)).toBe(
"If left blank, Prowler will use the organization ID.",
);
expect(organizationNameFallbackHint(ORGANIZATION_TYPE.AZURE)).toBe(
"If left blank, Prowler will use the tenant ID.",
);
});
});
describe("getCandidateNoun", () => {
it("names what a discovered candidate is, per organization type", () => {
expect(getCandidateNoun(ORGANIZATION_TYPE.AWS)).toEqual({
singular: "account",
plural: "accounts",
});
expect(getCandidateNoun(ORGANIZATION_TYPE.GCP)).toEqual({
singular: "project",
plural: "projects",
});
expect(getCandidateNoun(ORGANIZATION_TYPE.AZURE)).toEqual({
singular: "subscription",
plural: "subscriptions",
});
});
});
describe("toNodeKind", () => {
it("narrows canonical kind values", () => {
expect(toNodeKind("organizational-unit")).toBe(
NODE_KIND.ORGANIZATIONAL_UNIT,
);
expect(toNodeKind("folder")).toBe(NODE_KIND.FOLDER);
expect(toNodeKind("management-group")).toBe(NODE_KIND.MANAGEMENT_GROUP);
});
it("returns undefined for absent or unknown kinds", () => {
expect(toNodeKind(undefined)).toBeUndefined();
expect(toNodeKind("")).toBeUndefined();
expect(toNodeKind("organizational_unit")).toBeUndefined();
expect(toNodeKind("management_group")).toBeUndefined();
});
});