Show seven cards on the four method decks and open each as a routing overlay of its parts, so groups write from empty fields with Generate draft, search the full deck, and see unselected scope chips with enough contrast.
This commit is contained in:
1 parent
dea7dd7fbd
commit
46656f52d3
28 files changed
+1349
-318
No files matched your search
@@ -155,6 +155,66 @@ describe("CardStack Component", () => {
|
||||
expect(screen.getAllByText("SELECTED").length).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
|
||||
test("compact single-stack shows seven recommended cards and hides the tag", () => {
|
||||
const cards = Array.from({ length: 8 }, (_, index) => ({
|
||||
id: String(index),
|
||||
label: `Card ${index}`,
|
||||
supportText: `Desc ${index}`,
|
||||
recommended: true,
|
||||
}));
|
||||
render(
|
||||
<CardStack cards={cards} layout="singleStack" expanded={false} />,
|
||||
);
|
||||
|
||||
expect(
|
||||
screen.getAllByRole("button", { name: /Card \d: Desc \d/ }),
|
||||
).toHaveLength(7);
|
||||
expect(screen.queryByText("RECOMMENDED")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("See all search filters the expanded single-stack", () => {
|
||||
render(
|
||||
<CardStack
|
||||
cards={SAMPLE_CARDS}
|
||||
layout="singleStack"
|
||||
expanded={true}
|
||||
searchPlaceholder="Search this deck"
|
||||
/>,
|
||||
);
|
||||
|
||||
const search = screen.getByRole("searchbox", { name: "Search this deck" });
|
||||
fireEvent.change(search, { target: { value: "Option B" } });
|
||||
expect(
|
||||
screen.getByRole("button", { name: "Option B: Description B" }),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByRole("button", { name: "Option A: Description A" }),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("compact alternative row opens the named card", () => {
|
||||
const onAlternativeSelect = vi.fn();
|
||||
render(
|
||||
<CardStack
|
||||
cards={[
|
||||
{
|
||||
id: "1",
|
||||
label: "Option A",
|
||||
supportText: "Description A",
|
||||
recommended: true,
|
||||
alternative: { id: "2", label: "Option B" },
|
||||
},
|
||||
]}
|
||||
layout="singleStack"
|
||||
alternativePrefix="Another way communities do this:"
|
||||
onAlternativeSelect={onAlternativeSelect}
|
||||
/>,
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "Option B" }));
|
||||
expect(onAlternativeSelect).toHaveBeenCalledWith("2");
|
||||
});
|
||||
|
||||
test("calls onCardSelect when re-clicking an already selected card", () => {
|
||||
const onCardSelect = vi.fn();
|
||||
render(
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
selectedKeyResourceLabelsFromCheckedIds,
|
||||
stringArraysEqual,
|
||||
syncDecisionApproachKeyResourceDetails,
|
||||
decisionApproachDefaultScopeChips,
|
||||
withDecisionApproachKeyResourceScopes,
|
||||
} from "../../lib/create/decisionApproachKeyResources";
|
||||
import type { DecisionApproachDetailEntry } from "../../app/(app)/create/types";
|
||||
@@ -158,10 +159,20 @@ describe("decisionApproachKeyResources", () => {
|
||||
expect(decisionApproachKeyResourceLabels()).toHaveLength(7);
|
||||
});
|
||||
|
||||
it("unions key-resource labels onto an existing scope list", () => {
|
||||
it("unions signed-off default chips then key-resource labels onto an existing scope list", () => {
|
||||
expect(decisionApproachDefaultScopeChips()).toEqual([
|
||||
"Changing the Rule",
|
||||
"Money",
|
||||
"Projects",
|
||||
"Asking someone to leave",
|
||||
]);
|
||||
expect(
|
||||
withDecisionApproachKeyResourceScopes(["Daily Operations"]),
|
||||
).toEqual([
|
||||
"Changing the Rule",
|
||||
"Money",
|
||||
"Projects",
|
||||
"Asking someone to leave",
|
||||
"Daily Operations",
|
||||
"Everyday decisions",
|
||||
"Big decisions",
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { formatRecommendationWhyLine } from "../../lib/create/formatRecommendationWhyLine";
|
||||
import type { GroupAnswers } from "../../lib/create/deckTypes";
|
||||
import messages from "../../messages/en/index";
|
||||
|
||||
const copy = messages.create.customRule.recommendations;
|
||||
const emptyAnswers: GroupAnswers = {
|
||||
size: null,
|
||||
mainKind: null,
|
||||
otherKinds: [],
|
||||
scale: [],
|
||||
stage: null,
|
||||
traits: {},
|
||||
};
|
||||
|
||||
describe("formatRecommendationWhyLine", () => {
|
||||
it("builds a fit line from kind and size", () => {
|
||||
expect(
|
||||
formatRecommendationWhyLine(
|
||||
{ kind: "fit", matched: ["kind"] },
|
||||
{ ...emptyAnswers, mainKind: "workersCoop", size: "sixToTwelve" },
|
||||
copy,
|
||||
),
|
||||
).toBe("Fits a worker co-op of 6 to 12 people");
|
||||
});
|
||||
|
||||
it("builds an added line from the setup answer", () => {
|
||||
expect(
|
||||
formatRecommendationWhyLine(
|
||||
{ kind: "added", answer: "employer" },
|
||||
emptyAnswers,
|
||||
copy,
|
||||
),
|
||||
).toBe("Added because you said you pay some people to do your work");
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user