|
|
@@ -0,0 +1,213 @@
|
|
|
+import React from 'react'
|
|
|
+import { render } from '@testing-library/react'
|
|
|
+import { CartProvider, useCart, CartItem } from '@/contexts/CartContext'
|
|
|
+import { mockShowToast, mockGetStorageSync, mockSetStorageSync } from '~/__mocks__/taroMock'
|
|
|
+
|
|
|
+// Mock Taro API
|
|
|
+jest.mock('@tarojs/taro', () => jest.requireActual('~/__mocks__/taroMock'))
|
|
|
+
|
|
|
+// 测试组件用于访问购物车hook
|
|
|
+const TestComponent = ({ action, item }: { action: string; item?: CartItem }) => {
|
|
|
+ const cart = useCart()
|
|
|
+
|
|
|
+ React.useEffect(() => {
|
|
|
+ if (action === 'add' && item) {
|
|
|
+ cart.addToCart(item)
|
|
|
+ }
|
|
|
+ }, [action, item, cart])
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ <div data-testid="items-count">{cart.cart.items.length}</div>
|
|
|
+ <div data-testid="total-count">{cart.cart.totalCount}</div>
|
|
|
+ <div data-testid="total-amount">{cart.cart.totalAmount}</div>
|
|
|
+ {cart.cart.items.map((item, index) => (
|
|
|
+ <div key={index} data-testid={`item-${index}`}>
|
|
|
+ <span data-testid={`item-${index}-id`}>{item.id}</span>
|
|
|
+ <span data-testid={`item-${index}-name`}>{item.name}</span>
|
|
|
+ <span data-testid={`item-${index}-spec`}>{item.spec || ''}</span>
|
|
|
+ <span data-testid={`item-${index}-quantity`}>{item.quantity}</span>
|
|
|
+ </div>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+describe('CartContext - 规格支持', () => {
|
|
|
+ beforeEach(() => {
|
|
|
+ mockGetStorageSync.mockReturnValue(null)
|
|
|
+ mockSetStorageSync.mockClear()
|
|
|
+ mockShowToast.mockClear()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('应该支持添加父商品到购物车', () => {
|
|
|
+ const parentGoods: CartItem = {
|
|
|
+ id: 1001,
|
|
|
+ name: '测试父商品',
|
|
|
+ price: 99.9,
|
|
|
+ image: 'parent.jpg',
|
|
|
+ stock: 10,
|
|
|
+ quantity: 2,
|
|
|
+ }
|
|
|
+
|
|
|
+ const { getByTestId } = render(
|
|
|
+ <CartProvider>
|
|
|
+ <TestComponent action="add" item={parentGoods} />
|
|
|
+ </CartProvider>
|
|
|
+ )
|
|
|
+
|
|
|
+ expect(getByTestId('items-count').textContent).toBe('1')
|
|
|
+ expect(getByTestId('item-0-id').textContent).toBe('1001')
|
|
|
+ expect(getByTestId('item-0-name').textContent).toBe('测试父商品')
|
|
|
+ expect(mockSetStorageSync).toHaveBeenCalled()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('应该支持添加子商品(带规格)到购物车', () => {
|
|
|
+ const childGoods: CartItem = {
|
|
|
+ id: 2001, // 子商品ID
|
|
|
+ name: '测试父商品 - 红色/M', // 包含规格信息的完整名称
|
|
|
+ price: 109.9,
|
|
|
+ image: 'child.jpg',
|
|
|
+ stock: 5,
|
|
|
+ quantity: 1,
|
|
|
+ spec: '红色/M', // 规格信息
|
|
|
+ }
|
|
|
+
|
|
|
+ const { getByTestId } = render(
|
|
|
+ <CartProvider>
|
|
|
+ <TestComponent action="add" item={childGoods} />
|
|
|
+ </CartProvider>
|
|
|
+ )
|
|
|
+
|
|
|
+ expect(getByTestId('items-count').textContent).toBe('1')
|
|
|
+ expect(getByTestId('item-0-id').textContent).toBe('2001')
|
|
|
+ expect(getByTestId('item-0-name').textContent).toBe('测试父商品 - 红色/M')
|
|
|
+ expect(getByTestId('item-0-spec').textContent).toBe('红色/M')
|
|
|
+ expect(mockSetStorageSync).toHaveBeenCalled()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('应该支持添加同一子商品多次(数量累加)', () => {
|
|
|
+ const childGoods1: CartItem = {
|
|
|
+ id: 3001,
|
|
|
+ name: '测试商品 - 蓝色/L',
|
|
|
+ price: 89.9,
|
|
|
+ image: 'goods.jpg',
|
|
|
+ stock: 10,
|
|
|
+ quantity: 1,
|
|
|
+ spec: '蓝色/L',
|
|
|
+ }
|
|
|
+
|
|
|
+ const childGoods2: CartItem = {
|
|
|
+ id: 3001, // 同一子商品ID
|
|
|
+ name: '测试商品 - 蓝色/L',
|
|
|
+ price: 89.9,
|
|
|
+ image: 'goods.jpg',
|
|
|
+ stock: 10,
|
|
|
+ quantity: 3,
|
|
|
+ spec: '蓝色/L',
|
|
|
+ }
|
|
|
+
|
|
|
+ const { getByTestId, rerender } = render(
|
|
|
+ <CartProvider>
|
|
|
+ <TestComponent action="add" item={childGoods1} />
|
|
|
+ </CartProvider>
|
|
|
+ )
|
|
|
+
|
|
|
+ expect(getByTestId('items-count').textContent).toBe('1')
|
|
|
+ expect(getByTestId('item-0-quantity').textContent).toBe('1')
|
|
|
+
|
|
|
+ // 重新渲染添加更多数量
|
|
|
+ rerender(
|
|
|
+ <CartProvider>
|
|
|
+ <TestComponent action="add" item={childGoods2} />
|
|
|
+ </CartProvider>
|
|
|
+ )
|
|
|
+
|
|
|
+ expect(getByTestId('item-0-quantity').textContent).toBe('4') // 1 + 3
|
|
|
+ })
|
|
|
+
|
|
|
+ it('应该限制数量不超过库存', () => {
|
|
|
+ const childGoods: CartItem = {
|
|
|
+ id: 4001,
|
|
|
+ name: '测试商品 - 黑色/XL',
|
|
|
+ price: 129.9,
|
|
|
+ image: 'goods.jpg',
|
|
|
+ stock: 2, // 库存只有2
|
|
|
+ quantity: 3, // 尝试购买3个
|
|
|
+ spec: '黑色/XL',
|
|
|
+ }
|
|
|
+
|
|
|
+ const { getByTestId } = render(
|
|
|
+ <CartProvider>
|
|
|
+ <TestComponent action="add" item={childGoods} />
|
|
|
+ </CartProvider>
|
|
|
+ )
|
|
|
+
|
|
|
+ // 应该显示库存不足提示
|
|
|
+ expect(mockShowToast).toHaveBeenCalledWith(
|
|
|
+ expect.objectContaining({ title: '库存不足' })
|
|
|
+ )
|
|
|
+ // 商品不应被添加
|
|
|
+ expect(getByTestId('items-count').textContent).toBe('0')
|
|
|
+ })
|
|
|
+
|
|
|
+ it('应该支持同时添加父商品和不同子商品', () => {
|
|
|
+ const parentGoods: CartItem = {
|
|
|
+ id: 5001,
|
|
|
+ name: '测试父商品',
|
|
|
+ price: 199.9,
|
|
|
+ image: 'parent.jpg',
|
|
|
+ stock: 20,
|
|
|
+ quantity: 1,
|
|
|
+ }
|
|
|
+
|
|
|
+ const childGoods1: CartItem = {
|
|
|
+ id: 5002, // 子商品ID1
|
|
|
+ name: '测试父商品 - 规格A',
|
|
|
+ price: 219.9,
|
|
|
+ image: 'child1.jpg',
|
|
|
+ stock: 5,
|
|
|
+ quantity: 2,
|
|
|
+ spec: '规格A',
|
|
|
+ }
|
|
|
+
|
|
|
+ const childGoods2: CartItem = {
|
|
|
+ id: 5003, // 子商品ID2
|
|
|
+ name: '测试父商品 - 规格B',
|
|
|
+ price: 229.9,
|
|
|
+ image: 'child2.jpg',
|
|
|
+ stock: 3,
|
|
|
+ quantity: 1,
|
|
|
+ spec: '规格B',
|
|
|
+ }
|
|
|
+
|
|
|
+ const { getByTestId, rerender } = render(
|
|
|
+ <CartProvider>
|
|
|
+ <TestComponent action="add" item={parentGoods} />
|
|
|
+ </CartProvider>
|
|
|
+ )
|
|
|
+
|
|
|
+ expect(getByTestId('items-count').textContent).toBe('1')
|
|
|
+
|
|
|
+ // 添加第一个子商品
|
|
|
+ rerender(
|
|
|
+ <CartProvider>
|
|
|
+ <TestComponent action="add" item={childGoods1} />
|
|
|
+ </CartProvider>
|
|
|
+ )
|
|
|
+
|
|
|
+ expect(getByTestId('items-count').textContent).toBe('2')
|
|
|
+
|
|
|
+ // 添加第二个子商品
|
|
|
+ rerender(
|
|
|
+ <CartProvider>
|
|
|
+ <TestComponent action="add" item={childGoods2} />
|
|
|
+ </CartProvider>
|
|
|
+ )
|
|
|
+
|
|
|
+ expect(getByTestId('items-count').textContent).toBe('3')
|
|
|
+ expect(getByTestId('item-0-id').textContent).toBe('5001')
|
|
|
+ expect(getByTestId('item-1-id').textContent).toBe('5002')
|
|
|
+ expect(getByTestId('item-2-id').textContent).toBe('5003')
|
|
|
+ })
|
|
|
+})
|