Skip to content
This repository was archived by the owner on Jul 3, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions app/pages/cart/CartItem/CartItemView.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import type { LineItem } from '@commercetools/platform-sdk'
import { renderWithProviders } from '~/utils/test'
import { CartItemView } from './CartItemView'
import { screen } from '@testing-library/react'
import { formatProductItemPrice } from '~/utils/formatPrice'

const mockCartItem: LineItem = {
id: '3a334a02-1663-4aa0-b9ca-6d95e0be07b',
productId: 'e37dbed7-9a2d-4e78-bd77-3c1c0d02e12e',
name: {
'en-US': 'Home coffee table – White'
},
productType: {
id: '251d23e8-5488-480c-8293-60e589124072',
typeId: 'product-type'
},
variant: {
id: 1,
images: [
{
url: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z/C/HgAGgwJ/lK3Q6wAAAABJRU5ErkJggg==',
dimensions: {
w: 500,
h: 500
}
}
]
},
price: {
id: '7da4c77b-cf10-4f54-a499-196c32aed7b2',
value: {
centAmount: 19_999,
currencyCode: 'USD',
fractionDigits: 2,
type: 'centPrecision'
}
},
quantity: 1,
totalPrice: {
centAmount: 16_999,
currencyCode: 'USD',
fractionDigits: 2,
type: 'centPrecision'
},
discountedPricePerQuantity: [],
taxedPricePortions: [],
state: [],
perMethodTaxRate: [],
priceMode: 'Platform',
lineItemMode: 'Standard'
}

describe('CartItemView', () => {
it('renders cart item: name, quantity, price, totalPrice, image', () => {
const { name, quantity, price, totalPrice, variant } = mockCartItem
const LOCALE = 'en-US'

renderWithProviders(
<CartItemView
name={name[LOCALE]}
imageUrl={variant.images?.[0].url}
price={price}
quantity={quantity}
totalPrice={totalPrice.centAmount}
onQuantityChange={() => {}}
onDelete={() => {}}
/>
)
const image = screen.getByRole('img')
expect(screen.getByText(name[LOCALE])).toBeInTheDocument()
expect(image).toHaveAttribute('src', variant.images?.[0].url)
expect(image).toHaveAttribute('alt', name[LOCALE])
expect(screen.getByText(quantity.toString())).toBeInTheDocument()
expect(screen.getByText(formatProductItemPrice(+price.value.centAmount))).toBeInTheDocument()
expect(screen.getByText(`Total: ${formatProductItemPrice(+totalPrice.centAmount)}`)).toBeInTheDocument()
})
})
36 changes: 36 additions & 0 deletions app/pages/cart/CartItem/QuantityControl.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { QuantityControl } from './QuantityControl'
import { renderWithProviders } from '~/utils/test'
import { screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'

describe('QuantityControl', () => {
it('display cart item quantity', () => {
const QUANTITY = 1
renderWithProviders(<QuantityControl quantity={QUANTITY} onQuantityChange={() => {}} />)
expect(screen.getByText(QUANTITY)).toBeInTheDocument()
})

it('increase cart item quantity', async () => {
const QUANTITY = 1
const handleChange = vi.fn()
const user = userEvent.setup()

renderWithProviders(<QuantityControl quantity={QUANTITY} onQuantityChange={handleChange} />)
const increaseButton = screen.getByLabelText('increase-button')

await user.click(increaseButton)
expect(handleChange).toHaveBeenCalledWith(2)
})

it('display and decrease cart item quantity', async () => {
const QUANTITY = 2
const handleChange = vi.fn()
const user = userEvent.setup()

renderWithProviders(<QuantityControl quantity={QUANTITY} onQuantityChange={handleChange} />)
const decreaseButton = screen.getByLabelText('decrease-button')

await user.click(decreaseButton)
expect(handleChange).toHaveBeenCalledWith(1)
})
})
8 changes: 7 additions & 1 deletion app/pages/cart/CartItem/QuantityControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,17 @@ export function QuantityControl({ quantity, onQuantityChange }: QuantityControlP
className="w-6 h-6 rounded-sm cursor-pointer"
onClick={handleDecrease}
disabled={quantity === 1}
aria-label="decrease-button"
>
<Minus />
</Button>
<div className="w-6 h-6 flex justify-center items-center">{quantity}</div>
<Button variant="gray" className="w-6 h-6 rounded-sm cursor-pointer" onClick={handleIncrease}>
<Button
variant="gray"
className="w-6 h-6 rounded-sm cursor-pointer"
onClick={handleIncrease}
aria-label="increase-button"
>
<Plus />
</Button>
</div>
Expand Down
48 changes: 48 additions & 0 deletions app/pages/cart/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { CART_TABLE_STATUS } from '~/store/cart/types'
import { renderWithProviders } from '~/utils/test'
import { screen, waitFor } from '@testing-library/react'
import Cart from '.'
import { makeStore } from '~/store'

const emptyCartState = makeStore({
cart: {
cart: {
lineItems: [],
id: '123',
version: 0,
customLineItems: [],
totalPrice: {
centAmount: 16_999,
currencyCode: 'USD',
fractionDigits: 2,
type: 'centPrecision'
},
taxMode: '',
taxRoundingMode: '',
taxCalculationMode: '',
inventoryMode: '',
cartState: '',
shippingMode: '',
shipping: [],
itemShippingAddresses: [],
discountCodes: [],
directDiscounts: [],
refusedGifts: [],
origin: '',
createdAt: '',
lastModifiedAt: ''
},
status: CART_TABLE_STATUS.READY,
errorMessage: ''
}
})

describe('Empty cart', () => {
it('display empty cart message when cart is empty', async () => {
renderWithProviders(<Cart />, emptyCartState)

await waitFor(() => {
expect(screen.getByText('Your cart is empty.')).toBeInTheDocument()
})
})
})
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"@tailwindcss/vite": "4.1.7",
"@testing-library/jest-dom": "6.6.3",
"@testing-library/react": "16.3.0",
"@testing-library/user-event": "14.6.1",
"@types/node": "22.15.18",
"@types/react": "19.1.4",
"@types/react-dom": "19.1.5",
Expand Down
14 changes: 14 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.