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";
|
||||
|
||||
|
||||
@@ -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", () => {
|
||||
|
||||
+3
-3
@@ -31,10 +31,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,
|
||||
@@ -43,7 +43,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 LoginTrigger() {
|
||||
const { openLogin, closeLogin } = useAuthModal();
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
} from "../utils/test-utils";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { describe, test, expect, afterEach } from "vitest";
|
||||
import { CommunicationMethodsScreen } from "../../app/create/screens/card/CommunicationMethodsScreen";
|
||||
import { CommunicationMethodsScreen } from "../../app/(app)/create/screens/card/CommunicationMethodsScreen";
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
} from "../utils/test-utils";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { describe, test, expect, afterEach } from "vitest";
|
||||
import { DecisionApproachesScreen } from "../../app/create/screens/right-rail/DecisionApproachesScreen";
|
||||
import { DecisionApproachesScreen } from "../../app/(app)/create/screens/right-rail/DecisionApproachesScreen";
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
|
||||
@@ -24,6 +24,7 @@ const mockPost = {
|
||||
},
|
||||
};
|
||||
|
||||
// Pure presentational; no provider context needed.
|
||||
describe("ContentContainer", () => {
|
||||
it("renders with default props", () => {
|
||||
render(<ContentContainer post={mockPost} />);
|
||||
|
||||
@@ -35,6 +35,7 @@ const mockPost = {
|
||||
},
|
||||
};
|
||||
|
||||
// Pure presentational; no provider context needed.
|
||||
describe("ContentThumbnailTemplate", () => {
|
||||
describe("Vertical Variant", () => {
|
||||
it("should render vertical variant with responsive dimensions", () => {
|
||||
|
||||
+37
-19
@@ -1,5 +1,7 @@
|
||||
import { describe, test, expect, vi } from "vitest";
|
||||
import RootLayout from "../../app/layout";
|
||||
import MarketingLayout from "../../app/(marketing)/layout";
|
||||
import AppLayout from "../../app/(app)/layout";
|
||||
|
||||
// Mock the font imports since they're Next.js specific
|
||||
vi.mock("next/font/google", () => ({
|
||||
@@ -70,30 +72,46 @@ describe("RootLayout", () => {
|
||||
expect(container).toBeTruthy();
|
||||
});
|
||||
|
||||
test("renders main content area", () => {
|
||||
const testContent = "Test content";
|
||||
const tree = RootLayout({ children: <div>{testContent}</div> });
|
||||
const main = findDescendant(
|
||||
tree,
|
||||
(n) => n.type === "main" && n.props?.className?.includes("flex-1"),
|
||||
);
|
||||
expect(main).toBeTruthy();
|
||||
|
||||
const childText = findDescendant(
|
||||
main,
|
||||
(n) => typeof n === "string" && n.includes(testContent),
|
||||
);
|
||||
expect(childText).toBeTruthy();
|
||||
});
|
||||
|
||||
test("renders children content correctly", () => {
|
||||
test("renders children directly inside the flex container (no <main> at root)", () => {
|
||||
const testContent = "This is test content";
|
||||
const tree = RootLayout({ children: <div>{testContent}</div> });
|
||||
const main = findDescendant(tree, (n) => n.type === "main");
|
||||
|
||||
expect(findDescendant(tree, (n) => n?.type === "main")).toBeNull();
|
||||
|
||||
const childText = findDescendant(
|
||||
main,
|
||||
tree,
|
||||
(n) => typeof n === "string" && n.includes(testContent),
|
||||
);
|
||||
expect(childText).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Group layouts (chrome composition)", () => {
|
||||
test("MarketingLayout wraps children in <main flex-1> and appends Footer", () => {
|
||||
const tree = MarketingLayout({ children: <div>marketing-child</div> });
|
||||
const main = findDescendant(
|
||||
tree,
|
||||
(n) => n?.type === "main" && n.props?.className?.includes("flex-1"),
|
||||
);
|
||||
expect(main).toBeTruthy();
|
||||
expect(
|
||||
findDescendant(main, (n) => typeof n === "string" && n.includes("marketing-child")),
|
||||
).toBeTruthy();
|
||||
|
||||
// Footer is loaded via next/dynamic — it appears as a render prop component
|
||||
// sibling to <main>. Verify the layout returns more than just <main>.
|
||||
const childrenArr = Array.isArray(tree.props.children)
|
||||
? tree.props.children
|
||||
: [tree.props.children];
|
||||
expect(childrenArr.length).toBeGreaterThan(1);
|
||||
});
|
||||
|
||||
test("AppLayout wraps children in <main flex-1> with no footer", () => {
|
||||
const tree = AppLayout({ children: <div>app-child</div> });
|
||||
expect(tree.type).toBe("main");
|
||||
expect(tree.props.className).toContain("flex-1");
|
||||
expect(
|
||||
findDescendant(tree, (n) => typeof n === "string" && n.includes("app-child")),
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
// Pure presentational; no provider context needed.
|
||||
describe("LogoWall Component", () => {
|
||||
test("renders with default logos", () => {
|
||||
render(<LogoWall />);
|
||||
|
||||
@@ -2,6 +2,7 @@ import { render, screen } from "@testing-library/react";
|
||||
import { describe, it, expect } from "vitest";
|
||||
import NumberCard from "../../app/components/cards/NumberCard";
|
||||
|
||||
// Pure presentational; no provider context needed.
|
||||
describe("NumberCard Component", () => {
|
||||
const defaultProps = {
|
||||
number: 1,
|
||||
@@ -200,7 +201,7 @@ describe("NumberCard Component", () => {
|
||||
});
|
||||
|
||||
it("applies Small size variant correctly", () => {
|
||||
render(<NumberCard {...defaultProps} size="Small" />);
|
||||
render(<NumberCard {...defaultProps} size="small" />);
|
||||
|
||||
// For Small size, text is directly in card div (no wrapper), so use closest("div")
|
||||
const card = screen.getByText("Test Card Text").closest("div");
|
||||
@@ -219,7 +220,7 @@ describe("NumberCard Component", () => {
|
||||
});
|
||||
|
||||
it("applies Medium size variant correctly", () => {
|
||||
render(<NumberCard {...defaultProps} size="Medium" />);
|
||||
render(<NumberCard {...defaultProps} size="medium" />);
|
||||
|
||||
const card = screen
|
||||
.getByText("Test Card Text")
|
||||
@@ -237,7 +238,7 @@ describe("NumberCard Component", () => {
|
||||
});
|
||||
|
||||
it("applies Large size variant correctly", () => {
|
||||
render(<NumberCard {...defaultProps} size="Large" />);
|
||||
render(<NumberCard {...defaultProps} size="large" />);
|
||||
|
||||
const card = screen
|
||||
.getByText("Test Card Text")
|
||||
@@ -257,7 +258,7 @@ describe("NumberCard Component", () => {
|
||||
});
|
||||
|
||||
it("applies XLarge size variant correctly", () => {
|
||||
render(<NumberCard {...defaultProps} size="XLarge" />);
|
||||
render(<NumberCard {...defaultProps} size="xlarge" />);
|
||||
|
||||
const card = screen
|
||||
.getByText("Test Card Text")
|
||||
|
||||
@@ -159,7 +159,7 @@ describe("RuleCard Component", () => {
|
||||
{
|
||||
name: "Values",
|
||||
chipOptions: [
|
||||
{ id: "v1", label: "Consciousness", state: "Unselected" },
|
||||
{ id: "v1", label: "Consciousness", state: "unselected" },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
parseDocumentSectionsForDisplay,
|
||||
parseSectionsFromCreateFlowState,
|
||||
} from "../../lib/create/buildPublishPayload";
|
||||
import type { CreateFlowState } from "../../app/create/types";
|
||||
import type { CreateFlowState } from "../../app/(app)/create/types";
|
||||
|
||||
describe("buildPublishPayload", () => {
|
||||
it("returns error when title missing", () => {
|
||||
@@ -97,8 +97,8 @@ describe("buildPublishPayload", () => {
|
||||
title: "T",
|
||||
selectedCoreValueIds: ["1", "2"],
|
||||
coreValuesChipsSnapshot: [
|
||||
{ id: "1", label: "Alpha", state: "Selected" },
|
||||
{ id: "2", label: "Beta", state: "Selected" },
|
||||
{ id: "1", label: "Alpha", state: "selected" },
|
||||
{ id: "2", label: "Beta", state: "selected" },
|
||||
],
|
||||
coreValueDetailsByChipId: {
|
||||
"1": { meaning: "m1", signals: "s1" },
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS,
|
||||
CREATE_FLOW_MD_UP_GRID_CELL_CLASS,
|
||||
CREATE_FLOW_TWO_COLUMN_MAX_WIDTH_CLASS,
|
||||
} from "../../app/create/components/createFlowLayoutTokens";
|
||||
} from "../../app/(app)/create/components/createFlowLayoutTokens";
|
||||
|
||||
describe("createFlowLayoutTokens", () => {
|
||||
it("exports create-flow column and two-column max class strings", () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { getProportionBarProgressForCreateFlowStep } from "../../app/create/utils/createFlowProportionProgress";
|
||||
import { getProportionBarProgressForCreateFlowStep } from "../../app/(app)/create/utils/createFlowProportionProgress";
|
||||
|
||||
describe("getProportionBarProgressForCreateFlowStep", () => {
|
||||
it("uses 1-2 on community-structure (third Create Community step)", () => {
|
||||
|
||||
@@ -83,8 +83,8 @@ describe("createFlowStateSchema", () => {
|
||||
const r = createFlowStateSchema.safeParse({
|
||||
communityStructureChipSnapshots: {
|
||||
organizationTypes: [
|
||||
{ id: "1", label: "Co-op", state: "Selected" },
|
||||
{ id: "custom-uuid", label: "My type", state: "Selected" },
|
||||
{ id: "1", label: "Co-op", state: "selected" },
|
||||
{ id: "custom-uuid", label: "My type", state: "selected" },
|
||||
],
|
||||
scale: [{ id: "1", label: "Local" }],
|
||||
maturity: [],
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
getPreviousStep,
|
||||
isValidStep,
|
||||
getStepIndex,
|
||||
} from "../../app/create/utils/flowSteps";
|
||||
} from "../../app/(app)/create/utils/flowSteps";
|
||||
|
||||
describe("flowSteps", () => {
|
||||
it("places confirm-stakeholders immediately before final-review", () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { hasCreateFlowUserInput } from "../../app/create/utils/hasCreateFlowUserInput";
|
||||
import { hasCreateFlowUserInput } from "../../app/(app)/create/utils/hasCreateFlowUserInput";
|
||||
|
||||
describe("hasCreateFlowUserInput", () => {
|
||||
it("returns false for empty state", () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
||||
import { saveDraftToServer } from "../../lib/create/api";
|
||||
import type { CreateFlowState } from "../../app/create/types";
|
||||
import type { CreateFlowState } from "../../app/(app)/create/types";
|
||||
|
||||
const minimalState: CreateFlowState = {};
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { type ReactElement } from "react";
|
||||
import { render, type RenderOptions } from "@testing-library/react";
|
||||
import { AuthModalProvider } from "../../app/contexts/AuthModalContext";
|
||||
import { MessagesProvider } from "../../app/contexts/MessagesContext";
|
||||
import { CreateFlowProvider } from "../../app/create/context/CreateFlowContext";
|
||||
import { CreateFlowProvider } from "../../app/(app)/create/context/CreateFlowContext";
|
||||
import messages from "../../messages/en/index";
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user