| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- 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(() => {
- console.log('TestComponent useEffect called, action:', action, 'item:', item, 'isLoading:', cart.isLoading)
- // 等待购物车加载完成后再添加商品
- if (!cart.isLoading && action === 'add' && item) {
- console.log('Calling addToCart with item:', item)
- cart.addToCart(item)
- }
- }, [action, item, cart.isLoading])
- console.log('TestComponent rendering, cart items:', cart.cart.items, 'isLoading:', cart.isLoading)
- 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>
- {/* spec字段已移除 */}
- <span data-testid={`item-${index}-quantity`}>{item.quantity}</span>
- <span data-testid={`item-${index}-stock`} style={{ display: 'none' }}>{item.stock}</span>
- </div>
- ))}
- </div>
- )
- }
- describe('CartContext - 规格支持', () => {
- beforeEach(() => {
- mockGetStorageSync.mockReturnValue(null)
- mockSetStorageSync.mockClear()
- mockShowToast.mockClear()
- })
- it('应该支持添加父商品到购物车', () => {
- const parentGoods: CartItem = {
- id: 1001,
- parentGoodsId: 0, // 父商品,无父商品
- 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
- parentGoodsId: 2000, // 父商品ID
- name: '红色/M', // 规格名称
- price: 109.9,
- image: 'child.jpg',
- stock: 5,
- quantity: 1,
- }
- 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(mockSetStorageSync).toHaveBeenCalled()
- })
- it('应该支持添加同一子商品多次(数量累加)', () => {
- const childGoods1: CartItem = {
- id: 3001,
- parentGoodsId: 3000, // 父商品ID
- name: '蓝色/L', // 规格名称
- price: 89.9,
- image: 'goods.jpg',
- stock: 10,
- quantity: 1,
- }
- const childGoods2: CartItem = {
- id: 3001, // 同一子商品ID
- parentGoodsId: 3000, // 父商品ID
- name: '蓝色/L', // 规格名称
- price: 89.9,
- image: 'goods.jpg',
- stock: 10,
- quantity: 3,
- }
- const { getByTestId, rerender } = render(
- <CartProvider>
- <TestComponent action="add" item={childGoods1} />
- </CartProvider>
- )
- expect(getByTestId('items-count').textContent).toBe('1')
- console.log('Item 0 id:', getByTestId('item-0-id').textContent)
- console.log('Item 0 name:', getByTestId('item-0-name').textContent)
- const quantityElement = getByTestId('item-0-quantity')
- console.log('Quantity element text:', quantityElement.textContent)
- // 修复:检查数量是否正确,应该是1而不是库存值10
- expect(parseInt(quantityElement.textContent || '0')).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,
- parentGoodsId: 4000, // 父商品ID
- 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,
- parentGoodsId: 0, // 父商品,无父商品
- name: '测试父商品',
- price: 199.9,
- image: 'parent.jpg',
- stock: 20,
- quantity: 1,
- }
- const childGoods1: CartItem = {
- id: 5002, // 子商品ID1
- parentGoodsId: 5001, // 父商品ID
- name: '测试父商品 - 规格A',
- price: 219.9,
- image: 'child1.jpg',
- stock: 5,
- quantity: 2,
- spec: '规格A',
- }
- const childGoods2: CartItem = {
- id: 5003, // 子商品ID2
- parentGoodsId: 5001, // 父商品ID
- 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')
- })
- it('应该支持切换购物车项规格', () => {
- // 首先添加一个子商品到购物车
- const childGoods: CartItem = {
- id: 6001,
- parentGoodsId: 6000, // 父商品ID
- name: '测试父商品 - 规格A',
- price: 99.9,
- image: 'child1.jpg',
- stock: 10,
- quantity: 2,
- spec: '规格A',
- }
- // 创建一个新的测试组件来测试switchSpec
- const TestSwitchSpecComponent = ({ cartItemId, newChildGoods }: {
- cartItemId?: number,
- newChildGoods?: { id: number; name: string; price: number; stock: number; image?: string; spec?: string }
- }) => {
- const cart = useCart()
- React.useEffect(() => {
- if (!cart.isLoading && cartItemId && newChildGoods) {
- cart.switchSpec(cartItemId, newChildGoods)
- }
- }, [cart.isLoading, cartItemId, newChildGoods])
- return (
- <div>
- <div data-testid="items-count">{cart.cart.items.length}</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>
- {/* spec字段已移除 */}
- <span data-testid={`item-${index}-quantity`}>{item.quantity}</span>
- <span data-testid={`item-${index}-price`}>{item.price}</span>
- </div>
- ))}
- </div>
- )
- }
- const { getByTestId, rerender } = render(
- <CartProvider>
- <TestComponent action="add" item={childGoods} />
- </CartProvider>
- )
- expect(getByTestId('items-count').textContent).toBe('1')
- expect(getByTestId('item-0-id').textContent).toBe('6001')
- expect(getByTestId('item-0-name').textContent).toBe('测试父商品 - 规格A')
- // 切换到新规格
- const newChildGoods = {
- id: 6002,
- name: '规格B', // 规格名称
- price: 119.9,
- stock: 5,
- image: 'child2.jpg',
- }
- rerender(
- <CartProvider>
- <TestSwitchSpecComponent cartItemId={6001} newChildGoods={newChildGoods} />
- </CartProvider>
- )
- // 验证规格已切换
- expect(getByTestId('items-count').textContent).toBe('1')
- expect(getByTestId('item-0-id').textContent).toBe('6002') // ID已更新
- expect(getByTestId('item-0-name').textContent).toBe('规格B') // 规格名称
- expect(getByTestId('item-0-price').textContent).toBe('119.9')
- expect(getByTestId('item-0-quantity').textContent).toBe('2') // 数量保持不变
- })
- it('切换规格时应该验证库存', () => {
- const childGoods: CartItem = {
- id: 7001,
- parentGoodsId: 7000,
- name: '测试商品 - 规格A',
- price: 50,
- image: 'test.jpg',
- stock: 10,
- quantity: 8, // 当前数量8
- spec: '规格A',
- }
- const TestSwitchSpecComponent = ({ cartItemId, newChildGoods }: {
- cartItemId?: number,
- newChildGoods?: { id: number; name: string; price: number; stock: number; image?: string; spec?: string }
- }) => {
- const cart = useCart()
- React.useEffect(() => {
- if (!cart.isLoading && cartItemId && newChildGoods) {
- cart.switchSpec(cartItemId, newChildGoods)
- }
- }, [cart.isLoading, cartItemId, newChildGoods])
- return <div data-testid="toast-called">{mockShowToast.mock.calls.length}</div>
- }
- // 添加商品到购物车
- const { getByTestId, rerender } = render(
- <CartProvider>
- <TestComponent action="add" item={childGoods} />
- </CartProvider>
- )
- // 尝试切换到库存不足的规格(库存只有5,但当前数量是8)
- const newChildGoods = {
- id: 7002,
- name: '测试商品 - 规格B',
- price: 60,
- stock: 5, // 库存不足
- image: 'test2.jpg',
- spec: '规格B'
- }
- rerender(
- <CartProvider>
- <TestSwitchSpecComponent cartItemId={7001} newChildGoods={newChildGoods} />
- </CartProvider>
- )
- // 应该显示库存不足提示
- expect(mockShowToast).toHaveBeenCalledWith(
- expect.objectContaining({ title: expect.stringContaining('库存不足') })
- )
- })
- it('单规格商品不应该支持切换规格', () => {
- const singleSpecGoods: CartItem = {
- id: 8001,
- parentGoodsId: 0, // 单规格商品
- name: '单规格商品',
- price: 30,
- image: 'single.jpg',
- stock: 10,
- quantity: 1,
- }
- const TestSwitchSpecComponent = ({ cartItemId, newChildGoods }: {
- cartItemId?: number,
- newChildGoods?: { id: number; name: string; price: number; stock: number; image?: string; spec?: string }
- }) => {
- const cart = useCart()
- React.useEffect(() => {
- if (!cart.isLoading && cartItemId && newChildGoods) {
- cart.switchSpec(cartItemId, newChildGoods)
- }
- }, [cart.isLoading, cartItemId, newChildGoods])
- return <div>Test</div>
- }
- // 添加单规格商品
- const { rerender } = render(
- <CartProvider>
- <TestComponent action="add" item={singleSpecGoods} />
- </CartProvider>
- )
- const newChildGoods = {
- id: 8002,
- name: '新规格',
- price: 40,
- stock: 5,
- spec: '新规格'
- }
- rerender(
- <CartProvider>
- <TestSwitchSpecComponent cartItemId={8001} newChildGoods={newChildGoods} />
- </CartProvider>
- )
- // 应该显示不支持切换的提示
- expect(mockShowToast).toHaveBeenCalledWith(
- expect.objectContaining({ title: '该商品不支持切换规格' })
- )
- })
- })
|