Create Community stage implemented
This commit is contained in:
@@ -57,7 +57,7 @@ function LoginTrigger() {
|
||||
onClick={() =>
|
||||
openLogin({
|
||||
variant: "saveProgress",
|
||||
nextPath: "/create/community-size?syncDraft=1",
|
||||
nextPath: "/create/community-structure?syncDraft=1",
|
||||
})
|
||||
}
|
||||
>
|
||||
@@ -143,7 +143,7 @@ describe("AuthModalProvider (header overlay)", () => {
|
||||
await waitFor(() => {
|
||||
expect(requestMagicLink).toHaveBeenCalledWith(
|
||||
"guest@example.com",
|
||||
"/create/community-size?syncDraft=1",
|
||||
"/create/community-structure?syncDraft=1",
|
||||
);
|
||||
});
|
||||
expect(setTransferPendingFlag).toHaveBeenCalled();
|
||||
|
||||
@@ -48,6 +48,22 @@ describe("CreateFlowFooter (behavioral tests)", () => {
|
||||
name: "Create Flow Footer",
|
||||
});
|
||||
expect(footer).toBeInTheDocument();
|
||||
const bar = screen.getByRole("progressbar");
|
||||
expect(bar).toHaveAttribute("aria-valuenow", String(1 / 6));
|
||||
});
|
||||
|
||||
it("passes proportionBarProgress to the progress bar", () => {
|
||||
render(
|
||||
<CreateFlowFooter
|
||||
progressBar={true}
|
||||
proportionBarProgress="1-1"
|
||||
proportionBarVariant="segmented"
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByRole("progressbar")).toHaveAttribute(
|
||||
"aria-valuenow",
|
||||
String(2 / 6),
|
||||
);
|
||||
});
|
||||
|
||||
it("does not render progress bar when progressBar is false", () => {
|
||||
|
||||
@@ -49,6 +49,22 @@ describe("HeaderLockup (behavioral tests)", () => {
|
||||
expect(screen.getByText("Test description")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders ReactNode description (rich inline)", () => {
|
||||
render(
|
||||
<HeaderLockup
|
||||
title="Test Title"
|
||||
description={
|
||||
<>
|
||||
Before <span className="underline">link</span> after
|
||||
</>
|
||||
}
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByText(/Before/)).toBeInTheDocument();
|
||||
expect(screen.getByText("link")).toBeInTheDocument();
|
||||
expect(screen.getByText(/after/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("does not render description when not provided", () => {
|
||||
const { container } = render(<HeaderLockup title="Test Title" />);
|
||||
const description = container.querySelector("p");
|
||||
|
||||
@@ -22,6 +22,13 @@ describe("InformationalScreen", () => {
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders workshop as a link (URL TBD) with underline per Figma", () => {
|
||||
render(<InformationalScreen />);
|
||||
const workshop = screen.getByRole("link", { name: "workshop" });
|
||||
expect(workshop).toHaveAttribute("href", "#");
|
||||
expect(workshop.className).toMatch(/underline/);
|
||||
});
|
||||
|
||||
it("renders first numbered list item title", () => {
|
||||
render(<InformationalScreen />);
|
||||
expect(
|
||||
|
||||
@@ -119,7 +119,7 @@ describe("LoginForm", () => {
|
||||
<Suspense fallback={null}>
|
||||
<LoginForm
|
||||
variant="saveProgress"
|
||||
magicLinkNextPath="/create/community-size?syncDraft=1"
|
||||
magicLinkNextPath="/create/community-structure?syncDraft=1"
|
||||
/>
|
||||
</Suspense>,
|
||||
);
|
||||
@@ -133,7 +133,7 @@ describe("LoginForm", () => {
|
||||
await waitFor(() => {
|
||||
expect(requestMagicLink).toHaveBeenCalledWith(
|
||||
"save@example.com",
|
||||
"/create/community-size?syncDraft=1",
|
||||
"/create/community-structure?syncDraft=1",
|
||||
);
|
||||
});
|
||||
expect(setTransferPendingFlag).toHaveBeenCalled();
|
||||
|
||||
@@ -22,6 +22,7 @@ const config: ComponentTestSuiteConfig<ProportionBarProps> = {
|
||||
optionalProps: {
|
||||
progress: "3-2",
|
||||
className: "custom-class",
|
||||
variant: "segmented",
|
||||
},
|
||||
primaryRole: "progressbar",
|
||||
testCases: {
|
||||
|
||||
@@ -8,22 +8,14 @@ describe("CommunitySizeSelectScreen", () => {
|
||||
render(<CommunitySizeSelectScreen />);
|
||||
expect(
|
||||
screen.getByRole("heading", {
|
||||
name: "How large is your community?",
|
||||
name: "How many people will be in your community in the near term?",
|
||||
}),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders MultiSelect add control", () => {
|
||||
render(<CommunitySizeSelectScreen />);
|
||||
const addButtons = screen.getAllByRole("button", {
|
||||
name: "Add organization type",
|
||||
});
|
||||
expect(addButtons.length).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
|
||||
it("renders preset chip labels", () => {
|
||||
it("renders preset size chips", () => {
|
||||
render(<CommunitySizeSelectScreen />);
|
||||
expect(screen.getByText("1 member")).toBeInTheDocument();
|
||||
expect(screen.getByText("2-10 members")).toBeInTheDocument();
|
||||
expect(screen.getByText("2-5 members")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -31,7 +31,7 @@ describe("CreateFlowTextFieldScreen (community name)", () => {
|
||||
screen.getByText("This will be the name of your community"),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByPlaceholderText("Enter your community name"),
|
||||
screen.getByPlaceholderText("Enter community name"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,6 +20,7 @@ componentTestSuite<UploadProps>({
|
||||
label: "Upload",
|
||||
active: true,
|
||||
showHelpIcon: true,
|
||||
hintText: "Add image from your device",
|
||||
},
|
||||
primaryRole: "button",
|
||||
testCases: {
|
||||
@@ -81,14 +82,14 @@ describe("Upload (behavioral tests)", () => {
|
||||
it("displays description text", () => {
|
||||
render(<Upload label="Upload" />);
|
||||
expect(
|
||||
screen.getByText(/Add images, PDFs, and other files to the policy/i),
|
||||
screen.getByText(/Add image from your device/i),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("applies active state styles correctly", () => {
|
||||
render(<Upload label="Upload" active={true} />);
|
||||
const descriptionText = screen.getByText(
|
||||
/Add images, PDFs, and other files to the policy/i,
|
||||
/Add image from your device/i,
|
||||
);
|
||||
const descriptionContainer = descriptionText.parentElement;
|
||||
expect(descriptionContainer).toHaveClass(
|
||||
@@ -99,7 +100,7 @@ describe("Upload (behavioral tests)", () => {
|
||||
it("applies inactive state styles correctly", () => {
|
||||
render(<Upload label="Upload" active={false} />);
|
||||
const descriptionText = screen.getByText(
|
||||
/Add images, PDFs, and other files to the policy/i,
|
||||
/Add image from your device/i,
|
||||
);
|
||||
const descriptionContainer = descriptionText.parentElement;
|
||||
expect(descriptionContainer).toHaveClass(
|
||||
|
||||
@@ -8,7 +8,7 @@ describe("CommunityUploadScreen", () => {
|
||||
render(<CommunityUploadScreen />);
|
||||
expect(
|
||||
screen.getByRole("heading", {
|
||||
name: "How should conflicts be resolved?",
|
||||
name: "Add a photo to identify your group",
|
||||
}),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
@@ -17,7 +17,9 @@ describe("CommunityUploadScreen", () => {
|
||||
render(<CommunityUploadScreen />);
|
||||
expect(screen.getByRole("button", { name: "Upload" })).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(/Add images, PDFs, and other files to the policy/i),
|
||||
screen.getByText(
|
||||
/This photo be used as a profile picture for your group/i,
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
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";
|
||||
|
||||
describe("createFlowLayoutTokens", () => {
|
||||
it("exports create-flow column and two-column max class strings", () => {
|
||||
expect(CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS).toBe(
|
||||
"w-full min-w-0 md:max-w-[640px]",
|
||||
);
|
||||
expect(CREATE_FLOW_MD_UP_GRID_CELL_CLASS).toBe(
|
||||
"w-full min-w-0 md:mx-auto md:max-w-[640px]",
|
||||
);
|
||||
expect(CREATE_FLOW_TWO_COLUMN_MAX_WIDTH_CLASS).toBe("md:max-w-[1328px]");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { getProportionBarProgressForCreateFlowStep } from "../../app/create/utils/createFlowProportionProgress";
|
||||
|
||||
describe("getProportionBarProgressForCreateFlowStep", () => {
|
||||
it("uses 1-2 on community-structure (third Create Community step)", () => {
|
||||
expect(getProportionBarProgressForCreateFlowStep("community-structure")).toBe(
|
||||
"1-2",
|
||||
);
|
||||
});
|
||||
|
||||
it("advances proportion after structure for context and size", () => {
|
||||
expect(getProportionBarProgressForCreateFlowStep("community-context")).toBe(
|
||||
"1-3",
|
||||
);
|
||||
expect(getProportionBarProgressForCreateFlowStep("community-size")).toBe(
|
||||
"1-4",
|
||||
);
|
||||
});
|
||||
|
||||
it("uses 2-0 on community-save and review (end of Create Community segment)", () => {
|
||||
expect(getProportionBarProgressForCreateFlowStep("community-save")).toBe(
|
||||
"2-0",
|
||||
);
|
||||
expect(getProportionBarProgressForCreateFlowStep("review")).toBe("2-0");
|
||||
});
|
||||
});
|
||||
@@ -71,6 +71,13 @@ describe("createFlowStateSchema", () => {
|
||||
const r = createFlowStateSchema.safeParse({ title: "x".repeat(600) });
|
||||
expect(r.success).toBe(false);
|
||||
});
|
||||
|
||||
it("rejects communitySaveEmail longer than 320 chars", () => {
|
||||
const r = createFlowStateSchema.safeParse({
|
||||
communitySaveEmail: "x".repeat(321),
|
||||
});
|
||||
expect(r.success).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("putDraftBodySchema", () => {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import messages from "../../messages/en/index";
|
||||
|
||||
describe("create footer messages", () => {
|
||||
it("exposes confirmName for the community-name footer CTA", () => {
|
||||
expect(messages.create.footer.confirmName).toBe("Confirm name");
|
||||
});
|
||||
|
||||
it("exposes confirmDetails for the community-structure footer CTA", () => {
|
||||
expect(messages.create.footer.confirmDetails).toBe("Confirm details");
|
||||
});
|
||||
|
||||
it("exposes confirmDescription for the community-context footer CTA", () => {
|
||||
expect(messages.create.footer.confirmDescription).toBe(
|
||||
"Confirm description",
|
||||
);
|
||||
});
|
||||
|
||||
it("exposes confirmMembers for the community-size footer CTA", () => {
|
||||
expect(messages.create.footer.confirmMembers).toBe("Confirm members");
|
||||
});
|
||||
});
|
||||
@@ -8,6 +8,8 @@ describe("createFlowStateHasKeys", () => {
|
||||
|
||||
it("returns true when any key is present", () => {
|
||||
expect(createFlowStateHasKeys({ title: "x" })).toBe(true);
|
||||
expect(createFlowStateHasKeys({ currentStep: "text" })).toBe(true);
|
||||
expect(createFlowStateHasKeys({ currentStep: "community-name" })).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -46,4 +46,13 @@ describe("flowSteps", () => {
|
||||
// @ts-expect-error — invalid step id
|
||||
expect(getStepIndex("bogus")).toBe(-1);
|
||||
});
|
||||
|
||||
it("places community-structure before community-context and community-size (Figma order)", () => {
|
||||
expect(getStepIndex("community-structure")).toBe(2);
|
||||
expect(getStepIndex("community-context")).toBe(3);
|
||||
expect(getStepIndex("community-size")).toBe(4);
|
||||
expect(getNextStep("community-name")).toBe("community-structure");
|
||||
expect(getNextStep("community-structure")).toBe("community-context");
|
||||
expect(getNextStep("community-context")).toBe("community-size");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { migrateLegacyCreateFlowState } from "../../lib/create/migrateLegacyCreateFlowState";
|
||||
|
||||
describe("migrateLegacyCreateFlowState", () => {
|
||||
it("maps communityReflection to communitySaveEmail when save email empty", () => {
|
||||
const out = migrateLegacyCreateFlowState({
|
||||
title: "T",
|
||||
communityReflection: "old@example.com",
|
||||
});
|
||||
expect(out.communitySaveEmail).toBe("old@example.com");
|
||||
expect("communityReflection" in out).toBe(false);
|
||||
});
|
||||
|
||||
it("does not overwrite existing communitySaveEmail", () => {
|
||||
const out = migrateLegacyCreateFlowState({
|
||||
communityReflection: "old@example.com",
|
||||
communitySaveEmail: "kept@example.com",
|
||||
});
|
||||
expect(out.communitySaveEmail).toBe("kept@example.com");
|
||||
});
|
||||
|
||||
it("rewrites currentStep slug", () => {
|
||||
const out = migrateLegacyCreateFlowState({
|
||||
currentStep: "community-reflection",
|
||||
});
|
||||
expect(out.currentStep).toBe("community-save");
|
||||
});
|
||||
|
||||
it("returns empty object for nullish input", () => {
|
||||
expect(migrateLegacyCreateFlowState(null)).toEqual({});
|
||||
expect(migrateLegacyCreateFlowState(undefined)).toEqual({});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user