From 7cc14630a91c3656df819a6a409406f630080bbb Mon Sep 17 00:00:00 2001 From: Aaron Po Date: Fri, 28 Aug 2026 15:06:27 -0400 Subject: [PATCH] Add Storybook stories for the new brewery detail page components --- web/frontend/.storybook/main.ts | 12 +++ web/frontend/stories/BeerListCard.stories.tsx | 47 +++++++++++ .../BeerStyleBreakdownCard.stories.tsx | 46 +++++++++++ .../stories/BreweryDetailsCard.stories.tsx | 37 +++++++++ .../stories/BreweryHeaderCard.stories.tsx | 77 +++++++++++++++++++ .../stories/BreweryLocationMap.stories.tsx | 28 +++++++ web/frontend/stories/CommentItem.stories.tsx | 56 ++++++++++++++ web/frontend/stories/CommentsCard.stories.tsx | 59 ++++++++++++++ .../stories/CommunityStatsCard.stories.tsx | 37 +++++++++ web/frontend/stories/LocationCard.stories.tsx | 64 +++++++++++++++ web/frontend/stories/SidebarCard.stories.tsx | 34 ++++++++ web/frontend/stories/StarRating.stories.tsx | 49 ++++++++++++ .../stories/YourRatingCard.stories.tsx | 45 +++++++++++ 13 files changed, 591 insertions(+) create mode 100644 web/frontend/stories/BeerListCard.stories.tsx create mode 100644 web/frontend/stories/BeerStyleBreakdownCard.stories.tsx create mode 100644 web/frontend/stories/BreweryDetailsCard.stories.tsx create mode 100644 web/frontend/stories/BreweryHeaderCard.stories.tsx create mode 100644 web/frontend/stories/BreweryLocationMap.stories.tsx create mode 100644 web/frontend/stories/CommentItem.stories.tsx create mode 100644 web/frontend/stories/CommentsCard.stories.tsx create mode 100644 web/frontend/stories/CommunityStatsCard.stories.tsx create mode 100644 web/frontend/stories/LocationCard.stories.tsx create mode 100644 web/frontend/stories/SidebarCard.stories.tsx create mode 100644 web/frontend/stories/StarRating.stories.tsx create mode 100644 web/frontend/stories/YourRatingCard.stories.tsx diff --git a/web/frontend/.storybook/main.ts b/web/frontend/.storybook/main.ts index eb9037c9..0ccf3437 100644 --- a/web/frontend/.storybook/main.ts +++ b/web/frontend/.storybook/main.ts @@ -19,6 +19,18 @@ const config: StorybookConfig = { '../stories/BreweryMap.stories.tsx', '../stories/NearbyBreweryMap.stories.tsx', '../stories/Themes.stories.tsx', + '../stories/StarRating.stories.tsx', + '../stories/SidebarCard.stories.tsx', + '../stories/BreweryDetailsCard.stories.tsx', + '../stories/BeerStyleBreakdownCard.stories.tsx', + '../stories/CommunityStatsCard.stories.tsx', + '../stories/BreweryLocationMap.stories.tsx', + '../stories/LocationCard.stories.tsx', + '../stories/BreweryHeaderCard.stories.tsx', + '../stories/YourRatingCard.stories.tsx', + '../stories/BeerListCard.stories.tsx', + '../stories/CommentItem.stories.tsx', + '../stories/CommentsCard.stories.tsx', ], addons: [ '@chromatic-com/storybook', diff --git a/web/frontend/stories/BeerListCard.stories.tsx b/web/frontend/stories/BeerListCard.stories.tsx new file mode 100644 index 00000000..1358afeb --- /dev/null +++ b/web/frontend/stories/BeerListCard.stories.tsx @@ -0,0 +1,47 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { expect, within } from 'storybook/test'; +import BeerListCard from '../app/features/breweries/components/BeerListCard'; +import { FILLER_BEERS } from '../app/features/breweries/utils/filler-brewery-detail'; + +const beerListCardDescription = `A brewery's beer list on the detail page: name/description, style badge, ABV, and star rating per row. Currently filler pending a beers-by-brewery endpoint — see BREWERY_DETAIL_HANDOFF.md.`; + +const meta = { + title: 'Breweries/BeerListCard', + component: BeerListCard, + tags: ['autodocs'], + args: { + beers: FILLER_BEERS, + }, + parameters: { + layout: 'padded', + docs: { + description: { + component: beerListCardDescription, + }, + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await expect(canvas.getByRole('heading', { name: 'Beers (9)' })).toBeInTheDocument(); + await expect(canvas.getByRole('link', { name: /view all beers/i })).toHaveAttribute( + 'href', + '/beers', + ); + await expect(canvas.getByText('Switchyard IPA')).toBeInTheDocument(); + await expect(canvas.getByText('6.8% ABV')).toBeInTheDocument(); + }, +}; + +export const SingleBeer: Story = { + args: { beers: FILLER_BEERS.slice(0, 1) }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await expect(canvas.getByRole('heading', { name: 'Beers (1)' })).toBeInTheDocument(); + }, +}; diff --git a/web/frontend/stories/BeerStyleBreakdownCard.stories.tsx b/web/frontend/stories/BeerStyleBreakdownCard.stories.tsx new file mode 100644 index 00000000..e21fa35d --- /dev/null +++ b/web/frontend/stories/BeerStyleBreakdownCard.stories.tsx @@ -0,0 +1,46 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { expect, within } from 'storybook/test'; +import BeerStyleBreakdownCard from '../app/features/breweries/components/BeerStyleBreakdownCard'; +import { FILLER_BEERS } from '../app/features/breweries/utils/filler-brewery-detail'; + +const beerStyleBreakdownCardDescription = `Sidebar "Beer styles" card: per-style progress bars, sorted by count descending, derived client-side from a brewery's beer list.`; + +const meta = { + title: 'Breweries/BeerStyleBreakdownCard', + component: BeerStyleBreakdownCard, + tags: ['autodocs'], + args: { + beers: FILLER_BEERS, + }, + parameters: { + layout: 'padded', + docs: { + description: { + component: beerStyleBreakdownCardDescription, + }, + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await expect(canvas.getByText('Beer styles')).toBeInTheDocument(); + await expect(canvas.getByText('IPA')).toBeInTheDocument(); + await expect(canvas.getByText('Sour')).toBeInTheDocument(); + }, +}; + +export const SingleStyle: Story = { + args: { + beers: FILLER_BEERS.filter((beer) => beer.style === 'IPA'), + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await expect(canvas.getByText('IPA')).toBeInTheDocument(); + await expect(canvas.queryByText('Sour')).not.toBeInTheDocument(); + }, +}; diff --git a/web/frontend/stories/BreweryDetailsCard.stories.tsx b/web/frontend/stories/BreweryDetailsCard.stories.tsx new file mode 100644 index 00000000..b3bca892 --- /dev/null +++ b/web/frontend/stories/BreweryDetailsCard.stories.tsx @@ -0,0 +1,37 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { expect, within } from 'storybook/test'; +import BreweryDetailsCard from '../app/features/breweries/components/BreweryDetailsCard'; + +const breweryDetailsCardDescription = `Sidebar "Details" card on the brewery detail page: founded year, brewery type, and beer count. Founded year and type are currently filler pending backend support — see BREWERY_DETAIL_HANDOFF.md.`; + +const meta = { + title: 'Breweries/BreweryDetailsCard', + component: BreweryDetailsCard, + tags: ['autodocs'], + args: { + foundedYear: 2014, + type: 'Microbrewery', + beerCount: 9, + }, + parameters: { + layout: 'padded', + docs: { + description: { + component: breweryDetailsCardDescription, + }, + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await expect(canvas.getByText('Founded')).toBeInTheDocument(); + await expect(canvas.getByText('2014')).toBeInTheDocument(); + await expect(canvas.getByText('Microbrewery')).toBeInTheDocument(); + await expect(canvas.getByText('9')).toBeInTheDocument(); + }, +}; diff --git a/web/frontend/stories/BreweryHeaderCard.stories.tsx b/web/frontend/stories/BreweryHeaderCard.stories.tsx new file mode 100644 index 00000000..a77bdd88 --- /dev/null +++ b/web/frontend/stories/BreweryHeaderCard.stories.tsx @@ -0,0 +1,77 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { expect, fn, userEvent, within } from 'storybook/test'; +import BreweryHeaderCard from '../app/features/breweries/components/BreweryHeaderCard'; +import type { Brewery, BreweryLocation } from '../app/features/breweries/breweries.server'; + +const breweryHeaderCardDescription = `Top card on the brewery detail page: eyebrow + "Est." badge, name, address, like button, average rating, and description. Founded year and average rating are currently filler pending backend support — see BREWERY_DETAIL_HANDOFF.md.`; + +const portlandLocation: BreweryLocation = { + breweryPostLocationId: 'loc-1', + breweryPostId: 'brewery-1', + cityId: 'city-1', + cityName: 'Portland', + stateProvinceName: 'Oregon', + stateProvinceCode: 'OR', + countryName: 'United States', + countryCode: 'US', + addressLine1: '123 Hop Street', + addressLine2: null, + postalCode: '97201', + coordinates: { latitude: 45.5152, longitude: -122.6784 }, +}; + +const brewery: Brewery = { + breweryPostId: 'brewery-1', + postedById: 'user-1', + breweryName: 'Cascade Hollow Brewing', + description: + 'A small-batch brewery known for hazy IPAs and barrel-aged sours, tucked into an old warehouse district.', + createdAt: '2024-03-01T12:00:00.000Z', + updatedAt: null, + location: portlandLocation, +}; + +const meta = { + title: 'Breweries/BreweryHeaderCard', + component: BreweryHeaderCard, + tags: ['autodocs'], + args: { + brewery, + foundedYear: 2014, + avgRating: 4, + ratingsCount: 76, + onToggleLike: fn(), + }, + parameters: { + layout: 'padded', + docs: { + description: { + component: breweryHeaderCardDescription, + }, + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Unliked: Story = { + args: { liked: false, likeCount: 127 }, + play: async ({ args, canvasElement }) => { + const canvas = within(canvasElement); + await expect( + canvas.getByRole('heading', { name: 'Cascade Hollow Brewing', level: 1 }), + ).toBeInTheDocument(); + const likeButton = canvas.getByRole('button', { name: /like · 127/i }); + await userEvent.click(likeButton); + await expect(args.onToggleLike).toHaveBeenCalledOnce(); + }, +}; + +export const Liked: Story = { + args: { liked: true, likeCount: 128 }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await expect(canvas.getByRole('button', { name: /liked · 128/i })).toBeInTheDocument(); + }, +}; diff --git a/web/frontend/stories/BreweryLocationMap.stories.tsx b/web/frontend/stories/BreweryLocationMap.stories.tsx new file mode 100644 index 00000000..1c4270c0 --- /dev/null +++ b/web/frontend/stories/BreweryLocationMap.stories.tsx @@ -0,0 +1,28 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; +import BreweryLocationMap from '../app/features/breweries/components/BreweryLocationMap'; + +const breweryLocationMapDescription = `Small fixed single-pin Leaflet map used by the brewery detail page's Location sidebar card. Smoke-render only - this hits the real OpenStreetMap tile server in the browser test run.`; + +const meta = { + title: 'Breweries/BreweryLocationMap', + component: BreweryLocationMap, + parameters: { + layout: 'padded', + docs: { + description: { + component: breweryLocationMapDescription, + }, + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + latitude: 45.5152, + longitude: -122.6784, + label: 'Cascade Hollow Brewing — 123 Hop Street', + }, +}; diff --git a/web/frontend/stories/CommentItem.stories.tsx b/web/frontend/stories/CommentItem.stories.tsx new file mode 100644 index 00000000..afb8e4e5 --- /dev/null +++ b/web/frontend/stories/CommentItem.stories.tsx @@ -0,0 +1,56 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { expect, fn, userEvent, within } from 'storybook/test'; +import CommentItem from '../app/features/breweries/components/CommentItem'; +import type { FillerComment } from '../app/features/breweries/utils/filler-brewery-detail'; + +const commentItemDescription = `A single comment row on the brewery detail page: avatar initials, username/star/timestamp, body, and a per-comment like toggle.`; + +const comment: FillerComment = { + id: '1', + user: 'malt_kettle', + initials: 'MK', + rating: 5, + time: '2 days ago', + text: 'The barrel-aged flanders red is worth the trip alone.', + likes: 12, + liked: false, +}; + +const meta = { + title: 'Breweries/CommentItem', + component: CommentItem, + tags: ['autodocs'], + args: { + onToggleLike: fn(), + }, + parameters: { + layout: 'padded', + docs: { + description: { + component: commentItemDescription, + }, + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Unliked: Story = { + args: { comment }, + play: async ({ args, canvasElement }) => { + const canvas = within(canvasElement); + await expect(canvas.getByText('malt_kettle')).toBeInTheDocument(); + const likeButton = canvas.getByRole('button', { name: /12 likes/i }); + await userEvent.click(likeButton); + await expect(args.onToggleLike).toHaveBeenCalledWith('1'); + }, +}; + +export const Liked: Story = { + args: { comment: { ...comment, liked: true } }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await expect(canvas.getByRole('button', { name: /13 likes/i })).toBeInTheDocument(); + }, +}; diff --git a/web/frontend/stories/CommentsCard.stories.tsx b/web/frontend/stories/CommentsCard.stories.tsx new file mode 100644 index 00000000..62f18445 --- /dev/null +++ b/web/frontend/stories/CommentsCard.stories.tsx @@ -0,0 +1,59 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { expect, fn, userEvent, within } from 'storybook/test'; +import CommentsCard from '../app/features/breweries/components/CommentsCard'; +import { FILLER_COMMENTS } from '../app/features/breweries/utils/filler-brewery-detail'; + +const commentsCardDescription = `Comments section on the brewery detail page: a post form (logged in) or a sign-in alert (logged out), followed by the comment list. Posting is disabled until the textarea has non-whitespace content.`; + +const meta = { + title: 'Breweries/CommentsCard', + component: CommentsCard, + tags: ['autodocs'], + args: { + comments: FILLER_COMMENTS, + currentUserInitials: 'JD', + onAddComment: fn(), + onToggleCommentLike: fn(), + }, + parameters: { + layout: 'padded', + docs: { + description: { + component: commentsCardDescription, + }, + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const LoggedIn: Story = { + args: { loggedIn: true }, + play: async ({ args, canvasElement }) => { + const canvas = within(canvasElement); + const postButton = canvas.getByRole('button', { name: /post comment/i }); + await expect(postButton).toBeDisabled(); + + await userEvent.type( + canvas.getByPlaceholderText('Share your thoughts on this brewery'), + 'Great taproom!', + ); + await expect(postButton).toBeEnabled(); + await userEvent.click(postButton); + await expect(args.onAddComment).toHaveBeenCalledWith('Great taproom!'); + }, +}; + +export const LoggedOut: Story = { + args: { loggedIn: false }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await expect( + canvas.getByText('Sign in to like, rate, and comment on breweries.'), + ).toBeInTheDocument(); + await expect( + canvas.queryByPlaceholderText('Share your thoughts on this brewery'), + ).not.toBeInTheDocument(); + }, +}; diff --git a/web/frontend/stories/CommunityStatsCard.stories.tsx b/web/frontend/stories/CommunityStatsCard.stories.tsx new file mode 100644 index 00000000..eafbf61c --- /dev/null +++ b/web/frontend/stories/CommunityStatsCard.stories.tsx @@ -0,0 +1,37 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { expect, within } from 'storybook/test'; +import CommunityStatsCard from '../app/features/breweries/components/CommunityStatsCard'; + +const communityStatsCardDescription = `Sidebar "Community" card: live likes/ratings/comments counts, kept in sync with the header, your-rating, and comments cards on the brewery detail page.`; + +const meta = { + title: 'Breweries/CommunityStatsCard', + component: CommunityStatsCard, + tags: ['autodocs'], + args: { + likeCount: 127, + ratingsCount: 76, + commentCount: 3, + }, + parameters: { + layout: 'padded', + docs: { + description: { + component: communityStatsCardDescription, + }, + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await expect(canvas.getByText('Likes')).toBeInTheDocument(); + await expect(canvas.getByText('127')).toBeInTheDocument(); + await expect(canvas.getByText('76')).toBeInTheDocument(); + await expect(canvas.getByText('3')).toBeInTheDocument(); + }, +}; diff --git a/web/frontend/stories/LocationCard.stories.tsx b/web/frontend/stories/LocationCard.stories.tsx new file mode 100644 index 00000000..fbd15224 --- /dev/null +++ b/web/frontend/stories/LocationCard.stories.tsx @@ -0,0 +1,64 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { expect, within } from 'storybook/test'; +import LocationCard from '../app/features/breweries/components/LocationCard'; +import type { BreweryLocation } from '../app/features/breweries/breweries.server'; + +const locationCardDescription = `Sidebar "Location" card: an interactive single-pin map (when coordinates are available), address, and website link. Smoke-render only for the map portion - this hits the real OpenStreetMap tile server in the browser test run.`; + +const portlandLocation: BreweryLocation = { + breweryPostLocationId: 'loc-1', + breweryPostId: 'brewery-1', + cityId: 'city-1', + cityName: 'Portland', + stateProvinceName: 'Oregon', + stateProvinceCode: 'OR', + countryName: 'United States', + countryCode: 'US', + addressLine1: '123 Hop Street', + addressLine2: null, + postalCode: '97201', + coordinates: { latitude: 45.5152, longitude: -122.6784 }, +}; + +const meta = { + title: 'Breweries/LocationCard', + component: LocationCard, + tags: ['autodocs'], + args: { + breweryName: 'Cascade Hollow Brewing', + website: 'cascadehollow.example', + }, + parameters: { + layout: 'padded', + docs: { + description: { + component: locationCardDescription, + }, + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const WithCoordinates: Story = { + args: { location: portlandLocation }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await expect(canvas.getByText('Location')).toBeInTheDocument(); + await expect(canvas.getByRole('link', { name: 'cascadehollow.example' })).toHaveAttribute( + 'href', + 'https://cascadehollow.example', + ); + }, +}; + +export const WithoutCoordinates: Story = { + args: { location: { ...portlandLocation, coordinates: null } }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await expect( + canvas.getByText('123 Hop Street, Portland, OR 97201, United States'), + ).toBeInTheDocument(); + }, +}; diff --git a/web/frontend/stories/SidebarCard.stories.tsx b/web/frontend/stories/SidebarCard.stories.tsx new file mode 100644 index 00000000..4a81e940 --- /dev/null +++ b/web/frontend/stories/SidebarCard.stories.tsx @@ -0,0 +1,34 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { expect, within } from 'storybook/test'; +import SidebarCard from '../app/features/breweries/components/SidebarCard'; + +const sidebarCardDescription = `Shared card shell used by the brewery detail page's sidebar sections (Location, Details, Beer styles, Community) — an uppercase eyebrow label over arbitrary content.`; + +const meta = { + title: 'Breweries/SidebarCard', + component: SidebarCard, + tags: ['autodocs'], + parameters: { + layout: 'padded', + docs: { + description: { + component: sidebarCardDescription, + }, + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + title: 'Details', + children:

Founded 2014

, + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await expect(canvas.getByText('Details')).toBeInTheDocument(); + await expect(canvas.getByText('Founded 2014')).toBeInTheDocument(); + }, +}; diff --git a/web/frontend/stories/StarRating.stories.tsx b/web/frontend/stories/StarRating.stories.tsx new file mode 100644 index 00000000..04296296 --- /dev/null +++ b/web/frontend/stories/StarRating.stories.tsx @@ -0,0 +1,49 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { expect, fn, userEvent, within } from 'storybook/test'; +import StarRating from '../app/features/breweries/components/StarRating'; + +const starRatingDescription = `Dual-purpose star control built on daisyUI's \`rating\` component. Read-only (no \`onChange\`) when used for an average or a display rating; interactive otherwise — clicking the currently-selected star clears the rating, since daisyUI radios can't do that natively.`; + +const meta = { + title: 'Breweries/StarRating', + component: StarRating, + tags: ['autodocs'], + parameters: { + layout: 'centered', + docs: { + description: { + component: starRatingDescription, + }, + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const ReadOnly: Story = { + args: { value: 4, size: 'sm' }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await expect(canvas.queryByRole('radio')).not.toBeInTheDocument(); + await expect(canvas.getByLabelText('4 out of 5 stars')).toBeInTheDocument(); + }, +}; + +export const Interactive: Story = { + args: { value: 0, size: 'lg', onChange: fn() }, + play: async ({ args, canvasElement }) => { + const canvas = within(canvasElement); + await userEvent.click(canvas.getByRole('radio', { name: 'Rate 3 of 5' })); + await expect(args.onChange).toHaveBeenCalledWith(3); + }, +}; + +export const InteractiveClearsOnRepeatClick: Story = { + args: { value: 3, size: 'lg', onChange: fn() }, + play: async ({ args, canvasElement }) => { + const canvas = within(canvasElement); + await userEvent.click(canvas.getByRole('radio', { name: 'Rate 3 of 5' })); + await expect(args.onChange).toHaveBeenCalledWith(0); + }, +}; diff --git a/web/frontend/stories/YourRatingCard.stories.tsx b/web/frontend/stories/YourRatingCard.stories.tsx new file mode 100644 index 00000000..d6c5ec8e --- /dev/null +++ b/web/frontend/stories/YourRatingCard.stories.tsx @@ -0,0 +1,45 @@ +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { expect, fn, userEvent, within } from 'storybook/test'; +import YourRatingCard from '../app/features/breweries/components/YourRatingCard'; + +const yourRatingCardDescription = `Interactive 1-5 star rating control on the brewery detail page. The hint text switches once a rating is set, and clicking the selected star again clears it.`; + +const meta = { + title: 'Breweries/YourRatingCard', + component: YourRatingCard, + tags: ['autodocs'], + args: { + onChange: fn(), + }, + parameters: { + layout: 'padded', + docs: { + description: { + component: yourRatingCardDescription, + }, + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Unrated: Story = { + args: { value: 0 }, + play: async ({ args, canvasElement }) => { + const canvas = within(canvasElement); + await expect(canvas.getByText('Tap a star to rate this brewery.')).toBeInTheDocument(); + await userEvent.click(canvas.getByRole('radio', { name: 'Rate 4 of 5' })); + await expect(args.onChange).toHaveBeenCalledWith(4); + }, +}; + +export const Rated: Story = { + args: { value: 4 }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await expect( + canvas.getByText('You rated this 4 of 5. Tap the same star to clear.'), + ).toBeInTheDocument(); + }, +};