Skip to content

Commit 4fa9501

Browse files
committed
fix radios
1 parent 8d57573 commit 4fa9501

2 files changed

Lines changed: 125 additions & 1 deletion

File tree

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import {
2+
ApolloClient,
3+
ApolloLink,
4+
ApolloProvider,
5+
InMemoryCache,
6+
Observable,
7+
} from "@apollo/client";
8+
import type { Meta, StoryObj } from "@storybook/react-vite";
9+
import { type ReactNode, useState } from "react";
10+
import { expect, within } from "storybook/test";
11+
12+
import DryRunItemsList from "./DryRunItemsList";
13+
14+
const zones = [
15+
{ id: "U2hpcHBpbmdab25lOjE=", name: "Europe" },
16+
{ id: "U2hpcHBpbmdab25lOjI=", name: "North America" },
17+
{ id: "U2hpcHBpbmdab25lOjM=", name: "Rest of the world" },
18+
];
19+
20+
/**
21+
* The list picks its own query out of `DocumentMap` and `useQuery` injects every permission
22+
* flag into the variables, so matching a mock by document+variables is brittle. A link that
23+
* answers with the same payload regardless of the operation keeps the story about the rows.
24+
*/
25+
const mockedApollo = (data: Record<string, unknown>, { loading = false } = {}) =>
26+
new ApolloClient({
27+
cache: new InMemoryCache(),
28+
defaultOptions: { watchQuery: { fetchPolicy: "no-cache" } },
29+
link: new ApolloLink(
30+
() =>
31+
new Observable(observer =>
32+
loading ? undefined : (observer.next({ data }), observer.complete()),
33+
),
34+
),
35+
});
36+
37+
const zonesData = {
38+
shippingZones: {
39+
__typename: "ShippingZoneCountableConnection",
40+
edges: zones.map(node => ({
41+
__typename: "ShippingZoneCountableEdge",
42+
node: {
43+
__typename: "ShippingZone",
44+
...node,
45+
description: "",
46+
countries: [],
47+
priceRange: null,
48+
metadata: [],
49+
privateMetadata: [],
50+
},
51+
})),
52+
pageInfo: {
53+
__typename: "PageInfo",
54+
endCursor: null,
55+
hasNextPage: false,
56+
hasPreviousPage: false,
57+
startCursor: null,
58+
},
59+
},
60+
};
61+
62+
const Wrapper = ({ client, children }: { client: ApolloClient<object>; children: ReactNode }) => (
63+
<ApolloProvider client={client}>{children}</ApolloProvider>
64+
);
65+
66+
const DryRunItemsListStory = ({
67+
initialObjectId = "",
68+
loading = false,
69+
}: {
70+
initialObjectId?: string;
71+
loading?: boolean;
72+
}) => {
73+
const [objectId, setObjectId] = useState(initialObjectId);
74+
75+
return (
76+
<Wrapper client={mockedApollo(zonesData, { loading })}>
77+
<DryRunItemsList object="SHIPPING_PRICE" objectId={objectId} setObjectId={setObjectId} />
78+
</Wrapper>
79+
);
80+
};
81+
82+
const meta: Meta<typeof DryRunItemsListStory> = {
83+
title: "Components/DryRunItemsList",
84+
component: DryRunItemsListStory,
85+
};
86+
87+
export default meta;
88+
type Story = StoryObj<typeof DryRunItemsListStory>;
89+
90+
export const Loading: Story = {
91+
args: { loading: true },
92+
};
93+
94+
export const Default: Story = {};
95+
96+
export const WithSelection: Story = {
97+
args: { initialObjectId: zones[1].id },
98+
};
99+
100+
export const PickingRowSelectsIt: Story = {
101+
play: async ({ canvasElement }: { canvasElement: HTMLElement }) => {
102+
const canvas = within(canvasElement);
103+
104+
// Arrange
105+
const row = await canvas.findByText(zones[2].name);
106+
107+
for (const radio of await canvas.findAllByRole("radio")) {
108+
await expect(radio).not.toBeChecked();
109+
}
110+
111+
// Act — the row owns the selection, the radio only displays it
112+
await row.click();
113+
114+
// Assert
115+
await expect((await canvas.findAllByRole("radio"))[2]).toBeChecked();
116+
},
117+
};

src/components/Radio/Radio.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,14 @@ export const Radio = ({
2424
onChange,
2525
"data-test-id": dataTestId,
2626
}: RadioProps) => (
27-
<RadioGroup value={checked ? value : ""} onValueChange={onChange}>
27+
// Legacy macaw's list cells set `box-sizing: content-box`, which the global
28+
// `* { box-sizing: inherit }` reset passes down and inflates the radio by its border,
29+
// pushing the inner dot off centre. Re-anchor it for any legacy container.
30+
<RadioGroup
31+
value={checked ? value : ""}
32+
onValueChange={onChange}
33+
style={{ boxSizing: "border-box" }}
34+
>
2835
<RadioGroup.Item
2936
id={value}
3037
value={value}

0 commit comments

Comments
 (0)