From c85601f59f28add859fa00306172430b01aede9a Mon Sep 17 00:00:00 2001 From: Meruert Date: Tue, 17 Jun 2025 21:57:38 +0500 Subject: [PATCH] test: ECOM-83 add cart item view, empty cart, quantity control tests --- app/pages/cart/CartItem/CartItemView.test.tsx | 77 +++++++++++++++++++ .../cart/CartItem/QuantityControl.test.tsx | 36 +++++++++ app/pages/cart/CartItem/QuantityControl.tsx | 8 +- app/pages/cart/index.test.tsx | 48 ++++++++++++ package.json | 1 + pnpm-lock.yaml | 14 ++++ 6 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 app/pages/cart/CartItem/CartItemView.test.tsx create mode 100644 app/pages/cart/CartItem/QuantityControl.test.tsx create mode 100644 app/pages/cart/index.test.tsx diff --git a/app/pages/cart/CartItem/CartItemView.test.tsx b/app/pages/cart/CartItem/CartItemView.test.tsx new file mode 100644 index 0000000..e430839 --- /dev/null +++ b/app/pages/cart/CartItem/CartItemView.test.tsx @@ -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( + {}} + 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() + }) +}) diff --git a/app/pages/cart/CartItem/QuantityControl.test.tsx b/app/pages/cart/CartItem/QuantityControl.test.tsx new file mode 100644 index 0000000..f67f1e9 --- /dev/null +++ b/app/pages/cart/CartItem/QuantityControl.test.tsx @@ -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( {}} />) + expect(screen.getByText(QUANTITY)).toBeInTheDocument() + }) + + it('increase cart item quantity', async () => { + const QUANTITY = 1 + const handleChange = vi.fn() + const user = userEvent.setup() + + renderWithProviders() + 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() + const decreaseButton = screen.getByLabelText('decrease-button') + + await user.click(decreaseButton) + expect(handleChange).toHaveBeenCalledWith(1) + }) +}) diff --git a/app/pages/cart/CartItem/QuantityControl.tsx b/app/pages/cart/CartItem/QuantityControl.tsx index 103c7a0..6d885ff 100644 --- a/app/pages/cart/CartItem/QuantityControl.tsx +++ b/app/pages/cart/CartItem/QuantityControl.tsx @@ -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" >
{quantity}
- diff --git a/app/pages/cart/index.test.tsx b/app/pages/cart/index.test.tsx new file mode 100644 index 0000000..ba0de4f --- /dev/null +++ b/app/pages/cart/index.test.tsx @@ -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(, emptyCartState) + + await waitFor(() => { + expect(screen.getByText('Your cart is empty.')).toBeInTheDocument() + }) + }) +}) diff --git a/package.json b/package.json index f783bc9..c4f02df 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 74854ff..abefda9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -134,6 +134,9 @@ importers: '@testing-library/react': specifier: 16.3.0 version: 16.3.0(@testing-library/dom@10.4.0)(@types/react-dom@19.1.5(@types/react@19.1.4))(@types/react@19.1.4)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@testing-library/user-event': + specifier: 14.6.1 + version: 14.6.1(@testing-library/dom@10.4.0) '@types/node': specifier: 22.15.18 version: 22.15.18 @@ -1775,6 +1778,13 @@ packages: '@types/react-dom': optional: true + '@testing-library/user-event@14.6.1': + resolution: + { integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw== } + engines: { node: '>=12', npm: '>=6' } + peerDependencies: + '@testing-library/dom': '>=7.21.4' + '@tybys/wasm-util@0.9.0': resolution: { integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw== } @@ -6878,6 +6888,10 @@ snapshots: '@types/react': 19.1.4 '@types/react-dom': 19.1.5(@types/react@19.1.4) + '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.0)': + dependencies: + '@testing-library/dom': 10.4.0 + '@tybys/wasm-util@0.9.0': dependencies: tslib: 2.8.1