Files
wehub-resource-sync b3a7f98e5a
CI / E2E Cloudflare (4/8) (push) Failing after 0s
CI / E2E Cloudflare (8/8) (push) Failing after 1s
CI / Lint (push) Failing after 1s
Auto Extract / Extract (push) Failing after 4s
CI / Version Check (push) Failing after 9s
CI / Integration Tests (push) Failing after 1s
CI / E2E tests (1/8) (push) Failing after 1s
CI / E2E tests (2/8) (push) Failing after 2s
CI / E2E tests (3/8) (push) Failing after 2s
CI / Browser Tests (push) Failing after 1s
CI / E2E tests (5/8) (push) Failing after 1s
CI / E2E Cloudflare (2/8) (push) Failing after 2s
CI / Typecheck (push) Failing after 1s
CI / Changeset Validation (push) Failing after 2s
CI / E2E Cloudflare (5/8) (push) Failing after 1s
CI / E2E Cloudflare (6/8) (push) Failing after 1s
CI / E2E Cloudflare (7/8) (push) Failing after 1s
CodeQL / Analyze (javascript-typescript) (push) Failing after 1s
Format / Format (push) Failing after 0s
CodeQL / Analyze (actions) (push) Failing after 4s
CI / E2E tests (4/8) (push) Failing after 1s
CI / E2E tests (6/8) (push) Failing after 1s
CI / E2E tests (7/8) (push) Failing after 2s
CI / E2E tests (8/8) (push) Failing after 1s
CI / E2E Cloudflare (1/8) (push) Failing after 1s
CI / E2E Cloudflare (3/8) (push) Failing after 2s
Preview Releases / Publish Preview (push) Failing after 0s
zizmor / Run zizmor (push) Failing after 1s
Release / Release (push) Failing after 2s
CI / Smoke Tests (push) Failing after 5m36s
CI / Tests (push) Failing after 6m36s
Release / Sync Templates (push) Has been skipped
CI / E2E Tests (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:23:53 +08:00

257 lines
6.7 KiB
TypeScript

import * as React from "react";
import { describe, it, expect, vi, beforeEach } from "vitest";
import { CapabilityConsentDialog } from "../../src/components/CapabilityConsentDialog";
import { render } from "../utils/render.tsx";
describe("CapabilityConsentDialog", () => {
let onConfirm: ReturnType<typeof vi.fn>;
let onCancel: ReturnType<typeof vi.fn>;
beforeEach(() => {
onConfirm = vi.fn();
onCancel = vi.fn();
});
it("renders dialog with plugin name and capabilities", async () => {
const screen = await render(
<CapabilityConsentDialog
pluginName="SEO Helper"
capabilities={["read:content", "write:content"]}
onConfirm={onConfirm}
onCancel={onCancel}
/>,
);
await expect
.element(screen.getByText("SEO Helper requires the following permissions:"))
.toBeInTheDocument();
await expect.element(screen.getByText("Read your content")).toBeInTheDocument();
await expect
.element(screen.getByText("Create, update, and delete content"))
.toBeInTheDocument();
});
it("shows 'Plugin Permissions' title for fresh install", async () => {
const screen = await render(
<CapabilityConsentDialog
pluginName="Test"
capabilities={["read:content"]}
onConfirm={onConfirm}
onCancel={onCancel}
/>,
);
await expect.element(screen.getByText("Plugin Permissions")).toBeInTheDocument();
});
it("shows 'Review New Permissions' title for update with new capabilities", async () => {
const screen = await render(
<CapabilityConsentDialog
pluginName="Test"
capabilities={["read:content", "write:content"]}
newCapabilities={["write:content"]}
onConfirm={onConfirm}
onCancel={onCancel}
/>,
);
await expect.element(screen.getByText("Review New Permissions")).toBeInTheDocument();
await expect
.element(screen.getByText("Test is requesting additional permissions:"))
.toBeInTheDocument();
});
it("marks new capabilities with NEW badge", async () => {
const screen = await render(
<CapabilityConsentDialog
pluginName="Test"
capabilities={["read:content", "write:content", "network:fetch"]}
newCapabilities={["network:fetch"]}
onConfirm={onConfirm}
onCancel={onCancel}
/>,
);
// The NEW badge should appear for network:fetch (exact match to avoid matching "New" in header)
const newBadges = screen.getByText("NEW", { exact: true }).all();
expect(newBadges.length).toBeGreaterThanOrEqual(1);
});
it("shows 'Accept & Install' button for fresh install", async () => {
const screen = await render(
<CapabilityConsentDialog
pluginName="Test"
capabilities={["read:content"]}
onConfirm={onConfirm}
onCancel={onCancel}
/>,
);
await expect.element(screen.getByText("Accept & Install")).toBeInTheDocument();
});
it("shows 'Accept & Update' button for update", async () => {
const screen = await render(
<CapabilityConsentDialog
pluginName="Test"
capabilities={["read:content"]}
newCapabilities={["read:content"]}
onConfirm={onConfirm}
onCancel={onCancel}
/>,
);
await expect.element(screen.getByText("Accept & Update")).toBeInTheDocument();
});
it("calls onConfirm when confirm button is clicked", async () => {
const screen = await render(
<CapabilityConsentDialog
pluginName="Test"
capabilities={["read:content"]}
onConfirm={onConfirm}
onCancel={onCancel}
/>,
);
await screen.getByText("Accept & Install").click();
expect(onConfirm).toHaveBeenCalledOnce();
});
it("calls onCancel when cancel button is clicked", async () => {
const screen = await render(
<CapabilityConsentDialog
pluginName="Test"
capabilities={["read:content"]}
onConfirm={onConfirm}
onCancel={onCancel}
/>,
);
await screen.getByText("Cancel").click();
expect(onCancel).toHaveBeenCalledOnce();
});
it("shows warning banner for 'warn' audit verdict", async () => {
const screen = await render(
<CapabilityConsentDialog
pluginName="Test"
capabilities={["read:content"]}
auditVerdict="warn"
onConfirm={onConfirm}
onCancel={onCancel}
/>,
);
await expect
.element(screen.getByText("Security audit flagged potential concerns with this plugin."))
.toBeInTheDocument();
});
it("shows danger banner for 'fail' audit verdict", async () => {
const screen = await render(
<CapabilityConsentDialog
pluginName="Test"
capabilities={["read:content"]}
auditVerdict="fail"
onConfirm={onConfirm}
onCancel={onCancel}
/>,
);
await expect
.element(screen.getByText("Security audit flagged this plugin as potentially unsafe."))
.toBeInTheDocument();
});
it("shows no audit banner for 'pass' verdict", async () => {
const screen = await render(
<CapabilityConsentDialog
pluginName="Test"
capabilities={["read:content"]}
auditVerdict="pass"
onConfirm={onConfirm}
onCancel={onCancel}
/>,
);
const warnText = screen.getByText(
"Security audit flagged potential concerns with this plugin.",
);
await expect.element(warnText).not.toBeInTheDocument();
});
it("shows pending state during install", async () => {
const screen = await render(
<CapabilityConsentDialog
pluginName="Test"
capabilities={["read:content"]}
isPending={true}
onConfirm={onConfirm}
onCancel={onCancel}
/>,
);
await expect.element(screen.getByText("Installing...")).toBeInTheDocument();
});
it("shows pending state during update", async () => {
const screen = await render(
<CapabilityConsentDialog
pluginName="Test"
capabilities={["read:content"]}
newCapabilities={["read:content"]}
isPending={true}
onConfirm={onConfirm}
onCancel={onCancel}
/>,
);
await expect.element(screen.getByText("Updating...")).toBeInTheDocument();
});
it("appends allowed hosts for network:fetch", async () => {
const screen = await render(
<CapabilityConsentDialog
pluginName="Test"
capabilities={["network:fetch"]}
allowedHosts={["api.example.com"]}
onConfirm={onConfirm}
onCancel={onCancel}
/>,
);
await expect
.element(screen.getByText("Make network requests to: api.example.com"))
.toBeInTheDocument();
});
it("renders raw capability string for unknown capabilities", async () => {
const screen = await render(
<CapabilityConsentDialog
pluginName="Test"
capabilities={["custom:magic"]}
onConfirm={onConfirm}
onCancel={onCancel}
/>,
);
await expect.element(screen.getByText("custom:magic")).toBeInTheDocument();
});
it("has correct dialog role and aria attributes", async () => {
const screen = await render(
<CapabilityConsentDialog
pluginName="Test"
capabilities={["read:content"]}
onConfirm={onConfirm}
onCancel={onCancel}
/>,
);
const dialog = screen.getByRole("dialog");
await expect.element(dialog).toBeInTheDocument();
});
});