App reorganization
This commit is contained in:
@@ -3,7 +3,7 @@ import { describe, it, expect, vi } from "vitest";
|
||||
import { screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import "@testing-library/jest-dom/vitest";
|
||||
import ApplicableScopeField from "../../app/create/components/ApplicableScopeField";
|
||||
import ApplicableScopeField from "../../app/(app)/create/components/ApplicableScopeField";
|
||||
import { componentTestSuite } from "../utils/componentTestSuite";
|
||||
import { renderWithProviders } from "../utils/test-utils";
|
||||
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
import { Suspense } from "react";
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { screen, waitFor } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import "@testing-library/jest-dom/vitest";
|
||||
import { renderWithProviders } from "../utils/test-utils";
|
||||
import { useAuthModal } from "../../app/contexts/AuthModalContext";
|
||||
|
||||
const { navMock } = vi.hoisted(() => ({
|
||||
navMock: {
|
||||
pathname: "/",
|
||||
searchParams: new URLSearchParams(),
|
||||
replace: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("next/navigation", () => ({
|
||||
useRouter: () => ({
|
||||
replace: navMock.replace,
|
||||
push: vi.fn(),
|
||||
prefetch: vi.fn(),
|
||||
refresh: vi.fn(),
|
||||
back: vi.fn(),
|
||||
forward: vi.fn(),
|
||||
}),
|
||||
usePathname: () => navMock.pathname,
|
||||
useSearchParams: () => navMock.searchParams,
|
||||
}));
|
||||
|
||||
vi.mock("../../lib/create/api", () => ({
|
||||
requestMagicLink: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("../../app/create/utils/anonymousDraftStorage", async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<
|
||||
typeof import("../../app/create/utils/anonymousDraftStorage")
|
||||
>();
|
||||
return {
|
||||
...actual,
|
||||
setTransferPendingFlag: vi.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
import { requestMagicLink } from "../../lib/create/api";
|
||||
import { setTransferPendingFlag } from "../../app/create/utils/anonymousDraftStorage";
|
||||
|
||||
function LoginTrigger() {
|
||||
const { openLogin, closeLogin } = useAuthModal();
|
||||
return (
|
||||
<div>
|
||||
<button type="button" onClick={() => openLogin()}>
|
||||
Open login modal
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
openLogin({
|
||||
variant: "saveProgress",
|
||||
nextPath: "/create/community-structure?syncDraft=1",
|
||||
})
|
||||
}
|
||||
>
|
||||
Open save progress
|
||||
</button>
|
||||
<button type="button" onClick={() => closeLogin()}>
|
||||
Close from outside
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
describe("AuthModalProvider (header overlay)", () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(requestMagicLink).mockReset();
|
||||
vi.mocked(setTransferPendingFlag).mockReset();
|
||||
navMock.replace.mockReset();
|
||||
navMock.pathname = "/";
|
||||
navMock.searchParams = new URLSearchParams();
|
||||
});
|
||||
|
||||
it("opens blurred overlay with LoginForm when openLogin is called", async () => {
|
||||
const user = userEvent.setup();
|
||||
renderWithProviders(
|
||||
<Suspense fallback={null}>
|
||||
<LoginTrigger />
|
||||
</Suspense>,
|
||||
);
|
||||
await user.click(screen.getByRole("button", { name: /open login modal/i }));
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole("dialog")).toBeInTheDocument();
|
||||
});
|
||||
const backdrop = screen.getByRole("dialog").parentElement;
|
||||
expect(backdrop).toHaveClass("backdrop-blur-md");
|
||||
expect(
|
||||
screen.getByRole("heading", { name: /log in to communityrule/i }),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole("link", { name: /back to home/i }),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("closes overlay when closeLogin is called", async () => {
|
||||
const user = userEvent.setup();
|
||||
renderWithProviders(
|
||||
<Suspense fallback={null}>
|
||||
<LoginTrigger />
|
||||
</Suspense>,
|
||||
);
|
||||
await user.click(screen.getByRole("button", { name: /open login modal/i }));
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole("dialog")).toBeInTheDocument();
|
||||
});
|
||||
await user.click(
|
||||
screen.getByRole("button", { name: /close from outside/i }),
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it("saveProgress openLogin wires magicLinkNextPath and transfer flag on success", async () => {
|
||||
const user = userEvent.setup();
|
||||
vi.mocked(requestMagicLink).mockResolvedValue({ ok: true });
|
||||
renderWithProviders(
|
||||
<Suspense fallback={null}>
|
||||
<LoginTrigger />
|
||||
</Suspense>,
|
||||
);
|
||||
await user.click(
|
||||
screen.getByRole("button", { name: /open save progress/i }),
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole("dialog")).toBeInTheDocument();
|
||||
});
|
||||
await user.type(
|
||||
screen.getByRole("textbox", { name: /email address/i }),
|
||||
"guest@example.com",
|
||||
);
|
||||
await user.click(
|
||||
screen.getByRole("button", { name: /send me a magic link/i }),
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(requestMagicLink).toHaveBeenCalledWith(
|
||||
"guest@example.com",
|
||||
"/create/community-structure?syncDraft=1",
|
||||
);
|
||||
});
|
||||
expect(setTransferPendingFlag).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -39,6 +39,7 @@ const config: ComponentTestSuiteConfig<ButtonProps> = {
|
||||
|
||||
componentTestSuite<ButtonProps>(config);
|
||||
|
||||
// Pure presentational; no provider context needed.
|
||||
describe("Button (behavioral tests)", () => {
|
||||
it("calls onClick when clicked", async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { describe } from "vitest";
|
||||
import {
|
||||
componentTestSuite,
|
||||
type ComponentTestSuiteConfig,
|
||||
} from "../utils/componentTestSuite";
|
||||
import Chip from "../../app/components/controls/Chip";
|
||||
|
||||
type Props = React.ComponentProps<typeof Chip>;
|
||||
|
||||
const config: ComponentTestSuiteConfig<Props> = {
|
||||
component: Chip,
|
||||
name: "Chip",
|
||||
props: {
|
||||
label: "Worker cooperative",
|
||||
state: "unselected",
|
||||
palette: "default",
|
||||
size: "m",
|
||||
} as Props,
|
||||
primaryRole: "button",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
keyboardNavigation: true,
|
||||
disabledState: true,
|
||||
},
|
||||
states: {
|
||||
disabledProps: { disabled: true, state: "disabled" },
|
||||
},
|
||||
};
|
||||
|
||||
describe("Chip", () => {
|
||||
componentTestSuite<Props>(config);
|
||||
});
|
||||
@@ -0,0 +1,37 @@
|
||||
import { describe } from "vitest";
|
||||
import {
|
||||
componentTestSuite,
|
||||
type ComponentTestSuiteConfig,
|
||||
} from "../utils/componentTestSuite";
|
||||
import CommunityRuleDocument from "../../app/components/sections/CommunityRuleDocument";
|
||||
|
||||
type Props = React.ComponentProps<typeof CommunityRuleDocument>;
|
||||
|
||||
const sampleSections = [
|
||||
{
|
||||
categoryName: "Decision making",
|
||||
entries: [
|
||||
{
|
||||
title: "How proposals pass",
|
||||
body: "Important decisions require unanimous agreement.",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const config: ComponentTestSuiteConfig<Props> = {
|
||||
component: CommunityRuleDocument,
|
||||
name: "CommunityRuleDocument",
|
||||
props: {
|
||||
sections: sampleSections,
|
||||
} as Props,
|
||||
requiredProps: ["sections"],
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
},
|
||||
};
|
||||
|
||||
describe("CommunityRuleDocument", () => {
|
||||
componentTestSuite<Props>(config);
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { renderWithProviders as render, screen } from "../utils/test-utils";
|
||||
import "@testing-library/jest-dom/vitest";
|
||||
import { CompletedScreen } from "../../app/create/screens/completed/CompletedScreen";
|
||||
import { CompletedScreen } from "../../app/(app)/create/screens/completed/CompletedScreen";
|
||||
|
||||
describe("CompletedScreen", () => {
|
||||
it("renders without crashing", () => {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { describe, it, expect } from "vitest";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { renderWithProviders as render, screen } from "../utils/test-utils";
|
||||
import "@testing-library/jest-dom/vitest";
|
||||
import { ConfirmStakeholdersScreen } from "../../app/create/screens/select/ConfirmStakeholdersScreen";
|
||||
import { ConfirmStakeholdersScreen } from "../../app/(app)/create/screens/select/ConfirmStakeholdersScreen";
|
||||
|
||||
describe("ConfirmStakeholdersScreen", () => {
|
||||
it("renders title and description", () => {
|
||||
|
||||
@@ -43,6 +43,7 @@ const mockPost: BlogPost = {
|
||||
lastModified: new Date("2025-04-15"),
|
||||
};
|
||||
|
||||
// Pure presentational; no provider context needed.
|
||||
describe("ContentBanner", () => {
|
||||
it("renders without crashing", () => {
|
||||
render(<ContentBanner post={mockPost} />);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
import ContextMenu from "../../app/components/ContextMenu/ContextMenu";
|
||||
import ContextMenuItem from "../../app/components/ContextMenu/ContextMenuItem";
|
||||
import ContextMenu from "../../app/components/modals/ContextMenu/ContextMenu";
|
||||
import ContextMenuItem from "../../app/components/modals/ContextMenuItem";
|
||||
import { componentTestSuite } from "../utils/componentTestSuite";
|
||||
|
||||
type ContextMenuProps = React.ComponentProps<typeof ContextMenu>;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import ContextMenuItem from "../../app/components/ContextMenu/ContextMenuItem";
|
||||
import ContextMenuItem from "../../app/components/modals/ContextMenuItem";
|
||||
import { componentTestSuite } from "../utils/componentTestSuite";
|
||||
|
||||
type ContextMenuItemProps = React.ComponentProps<typeof ContextMenuItem>;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { screen, fireEvent, waitFor, within } from "@testing-library/react";
|
||||
import "@testing-library/jest-dom/vitest";
|
||||
import { renderWithProviders } from "../utils/test-utils";
|
||||
import { CoreValuesSelectScreen } from "../../app/create/screens/select/CoreValuesSelectScreen";
|
||||
import { CoreValuesSelectScreen } from "../../app/(app)/create/screens/select/CoreValuesSelectScreen";
|
||||
|
||||
describe("CoreValuesSelectScreen", () => {
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -35,6 +35,7 @@ const config: ComponentTestSuiteConfig<CreateFlowFooterProps> = {
|
||||
|
||||
componentTestSuite<CreateFlowFooterProps>(config);
|
||||
|
||||
// Pure presentational; no provider context needed (no useMessages/useAuthModal/useCreateFlow consumers).
|
||||
describe("CreateFlowFooter (behavioral tests)", () => {
|
||||
it("renders Back button", () => {
|
||||
render(<CreateFlowFooter />);
|
||||
|
||||
@@ -6,8 +6,8 @@ import {
|
||||
waitFor,
|
||||
} from "../utils/test-utils";
|
||||
import "@testing-library/jest-dom/vitest";
|
||||
import { FinalReviewScreen } from "../../app/create/screens/review/FinalReviewScreen";
|
||||
import { useCreateFlow } from "../../app/create/context/CreateFlowContext";
|
||||
import { FinalReviewScreen } from "../../app/(app)/create/screens/review/FinalReviewScreen";
|
||||
import { useCreateFlow } from "../../app/(app)/create/context/CreateFlowContext";
|
||||
|
||||
const FALLBACK_CARD_TITLE = "Your community";
|
||||
const FALLBACK_CARD_DESCRIPTION_SNIPPET =
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { describe, vi } from "vitest";
|
||||
import {
|
||||
componentTestSuite,
|
||||
type ComponentTestSuiteConfig,
|
||||
} from "../utils/componentTestSuite";
|
||||
import { GovernanceTemplateGrid } from "../../app/components/sections/GovernanceTemplateGrid";
|
||||
import { GOVERNANCE_TEMPLATE_CATALOG } from "../../lib/templates/governanceTemplateCatalog";
|
||||
|
||||
type Props = React.ComponentProps<typeof GovernanceTemplateGrid>;
|
||||
|
||||
const config: ComponentTestSuiteConfig<Props> = {
|
||||
component: GovernanceTemplateGrid,
|
||||
name: "GovernanceTemplateGrid",
|
||||
props: {
|
||||
entries: GOVERNANCE_TEMPLATE_CATALOG.slice(0, 2),
|
||||
onTemplateClick: vi.fn(),
|
||||
} as Props,
|
||||
requiredProps: ["entries", "onTemplateClick"],
|
||||
primaryRole: "button",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
},
|
||||
};
|
||||
|
||||
describe("GovernanceTemplateGrid", () => {
|
||||
componentTestSuite<Props>(config);
|
||||
});
|
||||
@@ -36,6 +36,7 @@ const config: ComponentTestSuiteConfig<HeaderLockupProps> = {
|
||||
|
||||
componentTestSuite<HeaderLockupProps>(config);
|
||||
|
||||
// Pure presentational; no provider context needed.
|
||||
describe("HeaderLockup (behavioral tests)", () => {
|
||||
it("renders title", () => {
|
||||
render(<HeaderLockup title="Test Title" />);
|
||||
@@ -84,8 +85,8 @@ describe("HeaderLockup (behavioral tests)", () => {
|
||||
expect(screen.getByRole("heading", { level: 1 })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("accepts PascalCase props", () => {
|
||||
render(<HeaderLockup title="Test Title" justification="Left" size="L" />);
|
||||
it("accepts justification and size props", () => {
|
||||
render(<HeaderLockup title="Test Title" justification="left" size="L" />);
|
||||
expect(screen.getByRole("heading", { level: 1 })).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { describe } from "vitest";
|
||||
import {
|
||||
componentTestSuite,
|
||||
type ComponentTestSuiteConfig,
|
||||
} from "../utils/componentTestSuite";
|
||||
import { Icon } from "../../app/components/asset";
|
||||
|
||||
type Props = React.ComponentProps<typeof Icon>;
|
||||
|
||||
const config: ComponentTestSuiteConfig<Props> = {
|
||||
component: Icon,
|
||||
name: "Icon",
|
||||
props: {
|
||||
name: "exclamation",
|
||||
size: 24,
|
||||
} as Props,
|
||||
requiredProps: ["name"],
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
},
|
||||
};
|
||||
|
||||
describe("Icon", () => {
|
||||
componentTestSuite<Props>(config);
|
||||
});
|
||||
@@ -38,6 +38,7 @@ const config: ComponentTestSuiteConfig<IconCardProps> = {
|
||||
|
||||
componentTestSuite<IconCardProps>(config);
|
||||
|
||||
// Pure presentational; no provider context needed.
|
||||
describe("IconCard (behavioral tests)", () => {
|
||||
it("calls onClick when clicked", () => {
|
||||
const handleClick = vi.fn();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { renderWithProviders as render, screen } from "../utils/test-utils";
|
||||
import "@testing-library/jest-dom/vitest";
|
||||
import { InformationalScreen } from "../../app/create/screens/informational/InformationalScreen";
|
||||
import { InformationalScreen } from "../../app/(app)/create/screens/informational/InformationalScreen";
|
||||
|
||||
describe("InformationalScreen", () => {
|
||||
it("renders without crashing", () => {
|
||||
|
||||
@@ -17,16 +17,16 @@ const config: ComponentTestSuiteConfig<Props> = {
|
||||
helpIcon: false,
|
||||
asterisk: false,
|
||||
helperText: false,
|
||||
size: "S",
|
||||
palette: "Default",
|
||||
size: "s",
|
||||
palette: "default",
|
||||
} as Props,
|
||||
requiredProps: ["label"],
|
||||
optionalProps: {
|
||||
helpIcon: true,
|
||||
asterisk: true,
|
||||
helperText: true,
|
||||
size: "M",
|
||||
palette: "Inverse",
|
||||
size: "m",
|
||||
palette: "inverse",
|
||||
},
|
||||
primaryRole: undefined, // InputLabel is not directly interactive
|
||||
testCases: {
|
||||
@@ -67,28 +67,28 @@ describe("InputLabel – behaviour specifics", () => {
|
||||
expect(screen.getByText("Custom helper")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("applies size S styling", () => {
|
||||
render(<InputLabel label="Test Label" size="S" />);
|
||||
it("applies size s styling", () => {
|
||||
render(<InputLabel label="Test Label" size="s" />);
|
||||
const label = screen.getByText("Test Label");
|
||||
expect(label).toHaveClass("text-[length:var(--sizing-350,14px)]");
|
||||
});
|
||||
|
||||
it("applies size M styling", () => {
|
||||
render(<InputLabel label="Test Label" size="M" />);
|
||||
it("applies size m styling", () => {
|
||||
render(<InputLabel label="Test Label" size="m" />);
|
||||
const label = screen.getByText("Test Label");
|
||||
expect(label).toHaveClass("text-[length:var(--sizing-400,16px)]");
|
||||
});
|
||||
|
||||
it("applies Default palette styling", () => {
|
||||
render(<InputLabel label="Test Label" palette="Default" />);
|
||||
it("applies default palette styling", () => {
|
||||
render(<InputLabel label="Test Label" palette="default" />);
|
||||
const label = screen.getByText("Test Label");
|
||||
expect(label).toHaveClass(
|
||||
"text-[color:var(--color-content-default-secondary,#d2d2d2)]",
|
||||
);
|
||||
});
|
||||
|
||||
it("applies Inverse palette styling", () => {
|
||||
render(<InputLabel label="Test Label" palette="Inverse" />);
|
||||
it("applies inverse palette styling", () => {
|
||||
render(<InputLabel label="Test Label" palette="inverse" />);
|
||||
const label = screen.getByText("Test Label");
|
||||
expect(label).toHaveClass(
|
||||
"text-[color:var(--color-content-inverse-secondary,#1f1f1f)]",
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { describe, vi } from "vitest";
|
||||
import {
|
||||
componentTestSuite,
|
||||
type ComponentTestSuiteConfig,
|
||||
} from "../utils/componentTestSuite";
|
||||
import InputWithCounter from "../../app/components/controls/InputWithCounter";
|
||||
|
||||
type Props = React.ComponentProps<typeof InputWithCounter>;
|
||||
|
||||
const config: ComponentTestSuiteConfig<Props> = {
|
||||
component: InputWithCounter,
|
||||
name: "InputWithCounter",
|
||||
props: {
|
||||
label: "Community name",
|
||||
placeholder: "Enter a name",
|
||||
value: "",
|
||||
onChange: vi.fn(),
|
||||
maxLength: 50,
|
||||
showHelpIcon: false,
|
||||
} as Props,
|
||||
requiredProps: ["value", "onChange", "maxLength"],
|
||||
primaryRole: "textbox",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
},
|
||||
};
|
||||
|
||||
describe("InputWithCounter", () => {
|
||||
componentTestSuite<Props>(config);
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { describe } from "vitest";
|
||||
import {
|
||||
componentTestSuite,
|
||||
type ComponentTestSuiteConfig,
|
||||
} from "../utils/componentTestSuite";
|
||||
import LanguageSwitcher from "../../app/components/localization/LanguageSwitcher";
|
||||
|
||||
type Props = React.ComponentProps<typeof LanguageSwitcher>;
|
||||
|
||||
const config: ComponentTestSuiteConfig<Props> = {
|
||||
component: LanguageSwitcher,
|
||||
name: "LanguageSwitcher",
|
||||
props: {} as Props,
|
||||
primaryRole: "combobox",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
},
|
||||
};
|
||||
|
||||
describe("LanguageSwitcher", () => {
|
||||
componentTestSuite<Props>(config);
|
||||
});
|
||||
@@ -32,10 +32,10 @@ vi.mock("../../lib/create/api", () => ({
|
||||
requestMagicLink: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("../../app/create/utils/anonymousDraftStorage", async (importOriginal) => {
|
||||
vi.mock("../../app/(app)/create/utils/anonymousDraftStorage", async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<
|
||||
typeof import("../../app/create/utils/anonymousDraftStorage")
|
||||
typeof import("../../app/(app)/create/utils/anonymousDraftStorage")
|
||||
>();
|
||||
return {
|
||||
...actual,
|
||||
@@ -44,7 +44,7 @@ vi.mock("../../app/create/utils/anonymousDraftStorage", async (importOriginal) =
|
||||
});
|
||||
|
||||
import { requestMagicLink } from "../../lib/create/api";
|
||||
import { setTransferPendingFlag } from "../../app/create/utils/anonymousDraftStorage";
|
||||
import { setTransferPendingFlag } from "../../app/(app)/create/utils/anonymousDraftStorage";
|
||||
|
||||
function renderLoginForm() {
|
||||
return renderWithProviders(
|
||||
|
||||
@@ -27,6 +27,7 @@ const config: ComponentTestSuiteConfig<LogoProps> = {
|
||||
|
||||
componentTestSuite<LogoProps>(config);
|
||||
|
||||
// Pure presentational; no provider context needed.
|
||||
describe("Logo (behavioral tests)", () => {
|
||||
it("renders as a link to home", () => {
|
||||
render(<Logo />);
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { describe, vi } from "vitest";
|
||||
import {
|
||||
componentTestSuite,
|
||||
type ComponentTestSuiteConfig,
|
||||
} from "../utils/componentTestSuite";
|
||||
import ModalFooter from "../../app/components/utility/ModalFooter";
|
||||
|
||||
type Props = React.ComponentProps<typeof ModalFooter>;
|
||||
|
||||
const config: ComponentTestSuiteConfig<Props> = {
|
||||
component: ModalFooter,
|
||||
name: "ModalFooter",
|
||||
props: {
|
||||
showBackButton: true,
|
||||
showNextButton: true,
|
||||
onBack: vi.fn(),
|
||||
onNext: vi.fn(),
|
||||
currentStep: 2,
|
||||
totalSteps: 4,
|
||||
} as Props,
|
||||
primaryRole: "button",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
},
|
||||
};
|
||||
|
||||
describe("ModalFooter", () => {
|
||||
componentTestSuite<Props>(config);
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
import { describe, vi } from "vitest";
|
||||
import {
|
||||
componentTestSuite,
|
||||
type ComponentTestSuiteConfig,
|
||||
} from "../utils/componentTestSuite";
|
||||
import ModalHeader from "../../app/components/utility/ModalHeader";
|
||||
|
||||
type Props = React.ComponentProps<typeof ModalHeader>;
|
||||
|
||||
const config: ComponentTestSuiteConfig<Props> = {
|
||||
component: ModalHeader,
|
||||
name: "ModalHeader",
|
||||
props: {
|
||||
showCloseButton: true,
|
||||
showMoreOptionsButton: true,
|
||||
onClose: vi.fn(),
|
||||
onMoreOptions: vi.fn(),
|
||||
} as Props,
|
||||
primaryRole: "button",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
},
|
||||
};
|
||||
|
||||
describe("ModalHeader", () => {
|
||||
componentTestSuite<Props>(config);
|
||||
});
|
||||
@@ -3,7 +3,7 @@ import { describe, it, expect, vi } from "vitest";
|
||||
import { screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import "@testing-library/jest-dom/vitest";
|
||||
import ModalTextAreaField from "../../app/create/components/ModalTextAreaField";
|
||||
import ModalTextAreaField from "../../app/(app)/create/components/ModalTextAreaField";
|
||||
import { componentTestSuite } from "../utils/componentTestSuite";
|
||||
import { renderWithProviders } from "../utils/test-utils";
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ import {
|
||||
type Props = React.ComponentProps<typeof MultiSelect>;
|
||||
|
||||
const defaultChipOptions = [
|
||||
{ id: "1", label: "Option 1", state: "Unselected" as const },
|
||||
{ id: "2", label: "Option 2", state: "Selected" as const },
|
||||
{ id: "1", label: "Option 1", state: "unselected" as const },
|
||||
{ id: "2", label: "Option 2", state: "selected" as const },
|
||||
];
|
||||
|
||||
const config: ComponentTestSuiteConfig<Props> = {
|
||||
@@ -21,8 +21,8 @@ const config: ComponentTestSuiteConfig<Props> = {
|
||||
props: {
|
||||
label: "Test Label",
|
||||
showHelpIcon: false,
|
||||
size: "S",
|
||||
palette: "Default",
|
||||
size: "s",
|
||||
palette: "default",
|
||||
options: defaultChipOptions,
|
||||
addButton: true,
|
||||
addButtonText: "",
|
||||
@@ -31,8 +31,8 @@ const config: ComponentTestSuiteConfig<Props> = {
|
||||
optionalProps: {
|
||||
label: "Optional Label",
|
||||
showHelpIcon: true,
|
||||
size: "M",
|
||||
palette: "Inverse",
|
||||
size: "m",
|
||||
palette: "inverse",
|
||||
onChipClick: vi.fn(),
|
||||
onAddClick: vi.fn(),
|
||||
addButton: false,
|
||||
@@ -144,7 +144,7 @@ describe("MultiSelect – behaviour specifics", () => {
|
||||
it("handles custom chip confirm", async () => {
|
||||
const handleConfirm = vi.fn();
|
||||
const customOptions = [
|
||||
{ id: "custom-1", label: "", state: "Custom" as const },
|
||||
{ id: "custom-1", label: "", state: "custom" as const },
|
||||
];
|
||||
render(
|
||||
<MultiSelect
|
||||
@@ -169,7 +169,7 @@ describe("MultiSelect – behaviour specifics", () => {
|
||||
it("handles custom chip close", async () => {
|
||||
const handleClose = vi.fn();
|
||||
const customOptions = [
|
||||
{ id: "custom-1", label: "", state: "Custom" as const },
|
||||
{ id: "custom-1", label: "", state: "custom" as const },
|
||||
];
|
||||
render(
|
||||
<MultiSelect options={customOptions} onCustomChipClose={handleClose} />,
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { describe } from "vitest";
|
||||
import {
|
||||
componentTestSuite,
|
||||
type ComponentTestSuiteConfig,
|
||||
} from "../utils/componentTestSuite";
|
||||
import NavigationItem from "../../app/components/navigation/NavigationItem";
|
||||
|
||||
type Props = React.ComponentProps<typeof NavigationItem>;
|
||||
|
||||
const config: ComponentTestSuiteConfig<Props> = {
|
||||
component: NavigationItem,
|
||||
name: "NavigationItem",
|
||||
props: {
|
||||
children: "Templates",
|
||||
href: "#",
|
||||
variant: "default",
|
||||
size: "default",
|
||||
} as Props,
|
||||
primaryRole: "link",
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
keyboardNavigation: true,
|
||||
},
|
||||
};
|
||||
|
||||
describe("NavigationItem", () => {
|
||||
componentTestSuite<Props>(config);
|
||||
});
|
||||
@@ -49,6 +49,7 @@ const config: ComponentTestSuiteConfig<NumberedListProps> = {
|
||||
|
||||
componentTestSuite<NumberedListProps>(config);
|
||||
|
||||
// Pure presentational; no provider context needed.
|
||||
describe("NumberedList (behavioral tests)", () => {
|
||||
it("renders all items", () => {
|
||||
render(<NumberedList items={mockItems} />);
|
||||
|
||||
@@ -36,6 +36,7 @@ const config: ComponentTestSuiteConfig<ProportionBarProps> = {
|
||||
|
||||
componentTestSuite<ProportionBarProps>(config);
|
||||
|
||||
// Pure presentational; no provider context needed.
|
||||
describe("ProportionBar (behavioral tests)", () => {
|
||||
it("renders proportion bar with correct progress value", () => {
|
||||
render(<ProportionBar progress="2-1" />);
|
||||
|
||||
@@ -63,6 +63,7 @@ const mockPosts: BlogPost[] = [
|
||||
},
|
||||
];
|
||||
|
||||
// Pure presentational; no provider context needed (mocked thumbnail + useIsMobile).
|
||||
describe("RelatedArticles", () => {
|
||||
it("renders without crashing", () => {
|
||||
render(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { renderWithProviders as render, screen } from "../utils/test-utils";
|
||||
import "@testing-library/jest-dom/vitest";
|
||||
import { CommunityReviewScreen } from "../../app/create/screens/review/CommunityReviewScreen";
|
||||
import { CommunityReviewScreen } from "../../app/(app)/create/screens/review/CommunityReviewScreen";
|
||||
|
||||
describe("CommunityReviewScreen", () => {
|
||||
it("renders without crashing", () => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { renderWithProviders as render, screen } from "../utils/test-utils";
|
||||
import "@testing-library/jest-dom/vitest";
|
||||
import { CommunitySizeSelectScreen } from "../../app/create/screens/select/CommunitySizeSelectScreen";
|
||||
import { CommunitySizeSelectScreen } from "../../app/(app)/create/screens/select/CommunitySizeSelectScreen";
|
||||
|
||||
describe("CommunitySizeSelectScreen", () => {
|
||||
it("renders HeaderLockup title", () => {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { describe } from "vitest";
|
||||
import {
|
||||
componentTestSuite,
|
||||
type ComponentTestSuiteConfig,
|
||||
} from "../utils/componentTestSuite";
|
||||
import Separator from "../../app/components/utility/Separator";
|
||||
|
||||
type Props = React.ComponentProps<typeof Separator>;
|
||||
|
||||
const config: ComponentTestSuiteConfig<Props> = {
|
||||
component: Separator,
|
||||
name: "Separator",
|
||||
props: {} as Props,
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
},
|
||||
};
|
||||
|
||||
describe("Separator", () => {
|
||||
componentTestSuite<Props>(config);
|
||||
});
|
||||
@@ -37,6 +37,7 @@ const config: ComponentTestSuiteConfig<StepperProps> = {
|
||||
|
||||
componentTestSuite<StepperProps>(config);
|
||||
|
||||
// Pure presentational; no provider context needed.
|
||||
describe("Stepper (behavioral tests)", () => {
|
||||
it("renders with correct number of steps", () => {
|
||||
render(<Stepper active={3} totalSteps={5} />);
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import { describe } from "vitest";
|
||||
import {
|
||||
componentTestSuite,
|
||||
type ComponentTestSuiteConfig,
|
||||
} from "../utils/componentTestSuite";
|
||||
import { TemplateReviewCard } from "../../app/components/cards/TemplateReviewCard";
|
||||
|
||||
type Props = React.ComponentProps<typeof TemplateReviewCard>;
|
||||
|
||||
const sampleTemplate = {
|
||||
id: "tmpl-1",
|
||||
slug: "consensus",
|
||||
title: "Consensus",
|
||||
category: null,
|
||||
description:
|
||||
"Important decisions require unanimous agreement. Proposals pass only if no serious objections remain.",
|
||||
body: {
|
||||
sections: [
|
||||
{
|
||||
categoryName: "Decision making",
|
||||
entries: [
|
||||
{
|
||||
title: "How proposals pass",
|
||||
body: "Unanimous agreement is required.",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
sortOrder: 1,
|
||||
featured: true,
|
||||
};
|
||||
|
||||
const config: ComponentTestSuiteConfig<Props> = {
|
||||
component: TemplateReviewCard,
|
||||
name: "TemplateReviewCard",
|
||||
props: {
|
||||
template: sampleTemplate,
|
||||
size: "L",
|
||||
} as Props,
|
||||
primaryRole: "button",
|
||||
testCases: {
|
||||
renders: true,
|
||||
// RuleCard contains nested interactive elements (chips inside a clickable card)
|
||||
// which trigger axe's "nested-interactive" rule. Tracked by RuleCard itself.
|
||||
accessibility: false,
|
||||
},
|
||||
};
|
||||
|
||||
describe("TemplateReviewCard", () => {
|
||||
componentTestSuite<Props>(config);
|
||||
});
|
||||
@@ -32,6 +32,7 @@ componentTestSuite<TextInputProps>({
|
||||
},
|
||||
});
|
||||
|
||||
// Pure presentational; no provider context needed.
|
||||
describe("TextInput (size tests)", () => {
|
||||
it("renders with medium size by default", () => {
|
||||
const { container } = render(<TextInput label="Test" inputSize="medium" />);
|
||||
@@ -45,9 +46,4 @@ describe("TextInput (size tests)", () => {
|
||||
expect(input).toHaveClass("h-[32px]");
|
||||
});
|
||||
|
||||
it("accepts PascalCase size prop", () => {
|
||||
const { container } = render(<TextInput label="Test" inputSize="Small" />);
|
||||
const input = container.querySelector("input");
|
||||
expect(input).toHaveClass("h-[32px]");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { renderWithProviders as render, screen } from "../utils/test-utils";
|
||||
import "@testing-library/jest-dom/vitest";
|
||||
import { CreateFlowTextFieldScreen } from "../../app/create/screens/text/CreateFlowTextFieldScreen";
|
||||
import { CreateFlowTextFieldScreen } from "../../app/(app)/create/screens/text/CreateFlowTextFieldScreen";
|
||||
|
||||
describe("CreateFlowTextFieldScreen (community name)", () => {
|
||||
it("renders main heading", () => {
|
||||
|
||||
@@ -30,6 +30,7 @@ componentTestSuite<TooltipProps>({
|
||||
},
|
||||
});
|
||||
|
||||
// Pure presentational; no provider context needed.
|
||||
describe("Tooltip (behavioral tests)", () => {
|
||||
it("shows tooltip on hover", async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
@@ -30,6 +30,7 @@ componentTestSuite<UploadProps>({
|
||||
},
|
||||
});
|
||||
|
||||
// Pure presentational; no provider context needed.
|
||||
describe("Upload (behavioral tests)", () => {
|
||||
it("renders with active state by default", () => {
|
||||
render(<Upload label="Upload" />);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { renderWithProviders as render, screen } from "../utils/test-utils";
|
||||
import "@testing-library/jest-dom/vitest";
|
||||
import { CommunityUploadScreen } from "../../app/create/screens/upload/CommunityUploadScreen";
|
||||
import { CommunityUploadScreen } from "../../app/(app)/create/screens/upload/CommunityUploadScreen";
|
||||
|
||||
describe("CommunityUploadScreen", () => {
|
||||
it("renders HeaderLockup", () => {
|
||||
|
||||
Reference in New Issue
Block a user