|
|
@@ -481,4 +481,265 @@ describe('GoodsDetailPage集成测试', () => {
|
|
|
duration: 1500
|
|
|
})
|
|
|
})
|
|
|
+
|
|
|
+ it('商品详情API加载失败时按钮应禁用', async () => {
|
|
|
+ // Mock商品详情API失败
|
|
|
+ ;(goodsClient[':id'].$get as jest.Mock).mockRejectedValue(new Error('网络错误'))
|
|
|
+ // Mock子商品API正常返回空列表
|
|
|
+ ;(goodsClient[':id'].children.$get as jest.Mock).mockResolvedValue({
|
|
|
+ status: 200,
|
|
|
+ json: async () => ({ data: [], total: 0, page: 1, pageSize: 100, totalPages: 0 })
|
|
|
+ })
|
|
|
+
|
|
|
+ render(
|
|
|
+ <TestWrapper>
|
|
|
+ <GoodsDetailPage />
|
|
|
+ </TestWrapper>
|
|
|
+ )
|
|
|
+
|
|
|
+ // 等待组件渲染完成(可能显示加载或错误状态)
|
|
|
+ await waitFor(() => {
|
|
|
+ // 验证页面显示商品不存在提示
|
|
|
+ expect(screen.getByText('商品不存在')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+
|
|
|
+ // 验证按钮不存在(因为goods为null,按钮不会渲染)
|
|
|
+ expect(screen.queryByText('加入购物车')).not.toBeInTheDocument()
|
|
|
+ expect(screen.queryByText('立即购买')).not.toBeInTheDocument()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('子商品列表API加载失败时按钮状态正确', async () => {
|
|
|
+ // Mock商品详情API成功
|
|
|
+ const mockGoodsResponse = {
|
|
|
+ status: 200,
|
|
|
+ json: async () => mockGoods
|
|
|
+ }
|
|
|
+ ;(goodsClient[':id'].$get as jest.Mock).mockResolvedValue(mockGoodsResponse)
|
|
|
+ // Mock子商品API失败
|
|
|
+ ;(goodsClient[':id'].children.$get as jest.Mock).mockRejectedValue(new Error('获取子商品列表失败'))
|
|
|
+
|
|
|
+ render(
|
|
|
+ <TestWrapper>
|
|
|
+ <GoodsDetailPage />
|
|
|
+ </TestWrapper>
|
|
|
+ )
|
|
|
+
|
|
|
+ // 等待商品加载完成
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(screen.getByText('测试商品', { selector: '.goods-title' })).toBeInTheDocument()
|
|
|
+ })
|
|
|
+
|
|
|
+ // 验证按钮存在且不禁用(因为商品库存>0,且hasSpecOptions为false)
|
|
|
+ const addToCartButton = screen.getByText('加入购物车')
|
|
|
+ const buyNowButton = screen.getByText('立即购买')
|
|
|
+ expect(addToCartButton).toBeInTheDocument()
|
|
|
+ expect(buyNowButton).toBeInTheDocument()
|
|
|
+ expect(addToCartButton).not.toBeDisabled()
|
|
|
+ expect(buyNowButton).not.toBeDisabled()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('有规格选项但库存为0时按钮应禁用', async () => {
|
|
|
+ // 创建库存为0的子商品数据
|
|
|
+ const zeroStockChildren = {
|
|
|
+ data: [
|
|
|
+ { id: 103, name: '黑色款', price: 299, stock: 0, imageFile: null }
|
|
|
+ ],
|
|
|
+ total: 1,
|
|
|
+ page: 1,
|
|
|
+ pageSize: 100,
|
|
|
+ totalPages: 1
|
|
|
+ }
|
|
|
+
|
|
|
+ // Mock商品详情API成功
|
|
|
+ const mockGoodsResponse = {
|
|
|
+ status: 200,
|
|
|
+ json: async () => mockGoods
|
|
|
+ }
|
|
|
+ ;(goodsClient[':id'].$get as jest.Mock).mockResolvedValue(mockGoodsResponse)
|
|
|
+ // Mock子商品API返回库存为0的子商品
|
|
|
+ ;(goodsClient[':id'].children.$get as jest.Mock).mockResolvedValue({
|
|
|
+ status: 200,
|
|
|
+ json: async () => zeroStockChildren
|
|
|
+ })
|
|
|
+
|
|
|
+ render(
|
|
|
+ <TestWrapper>
|
|
|
+ <GoodsDetailPage />
|
|
|
+ </TestWrapper>
|
|
|
+ )
|
|
|
+
|
|
|
+ // 等待商品加载完成
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(screen.getByText('测试商品', { selector: '.goods-title' })).toBeInTheDocument()
|
|
|
+ })
|
|
|
+
|
|
|
+ // 打开规格选择弹窗
|
|
|
+ const specButton = screen.getByText('选择规格', { selector: '.spec-select-btn' })
|
|
|
+ fireEvent.click(specButton)
|
|
|
+
|
|
|
+ // 等待规格弹窗加载
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(screen.getByText('黑色款')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+
|
|
|
+ // 选择库存为0的规格
|
|
|
+ const blackSpec = screen.getByText('黑色款')
|
|
|
+ fireEvent.click(blackSpec)
|
|
|
+
|
|
|
+ // 点击确认按钮
|
|
|
+ const confirmButton = screen.getByText(/确定/)
|
|
|
+ fireEvent.click(confirmButton)
|
|
|
+
|
|
|
+ // 等待规格弹窗关闭,页面更新
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(screen.getByText('黑色款')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+
|
|
|
+ // 验证按钮禁用(因为选择的规格库存为0)
|
|
|
+ const addToCartButton = screen.getByText('加入购物车')
|
|
|
+ const buyNowButton = screen.getByText('立即购买')
|
|
|
+ expect(addToCartButton).toBeDisabled()
|
|
|
+ expect(buyNowButton).toBeDisabled()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('无规格选项且商品库存为0时按钮应禁用', async () => {
|
|
|
+ // 创建库存为0的商品
|
|
|
+ const zeroStockGoods = {
|
|
|
+ ...mockGoods,
|
|
|
+ stock: 0
|
|
|
+ }
|
|
|
+
|
|
|
+ // Mock商品详情API成功
|
|
|
+ const mockGoodsResponse = {
|
|
|
+ status: 200,
|
|
|
+ json: async () => zeroStockGoods
|
|
|
+ }
|
|
|
+ ;(goodsClient[':id'].$get as jest.Mock).mockResolvedValue(mockGoodsResponse)
|
|
|
+ // Mock子商品API返回空列表
|
|
|
+ ;(goodsClient[':id'].children.$get as jest.Mock).mockResolvedValue({
|
|
|
+ status: 200,
|
|
|
+ json: async () => ({ data: [], total: 0, page: 1, pageSize: 100, totalPages: 0 })
|
|
|
+ })
|
|
|
+
|
|
|
+ render(
|
|
|
+ <TestWrapper>
|
|
|
+ <GoodsDetailPage />
|
|
|
+ </TestWrapper>
|
|
|
+ )
|
|
|
+
|
|
|
+ // 等待商品加载完成
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(screen.getByText('测试商品', { selector: '.goods-title' })).toBeInTheDocument()
|
|
|
+ })
|
|
|
+
|
|
|
+ // 验证按钮禁用(因为商品库存为0)
|
|
|
+ const addToCartButton = screen.getByText('加入购物车')
|
|
|
+ const buyNowButton = screen.getByText('立即购买')
|
|
|
+ expect(addToCartButton).toBeDisabled()
|
|
|
+ expect(buyNowButton).toBeDisabled()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('数量输入最小值边界', async () => {
|
|
|
+ // Mock商品详情API成功
|
|
|
+ const mockGoodsResponse = {
|
|
|
+ status: 200,
|
|
|
+ json: async () => mockGoods
|
|
|
+ }
|
|
|
+ ;(goodsClient[':id'].$get as jest.Mock).mockResolvedValue(mockGoodsResponse)
|
|
|
+ // Mock子商品API返回空列表(无规格)
|
|
|
+ ;(goodsClient[':id'].children.$get as jest.Mock).mockResolvedValue({
|
|
|
+ status: 200,
|
|
|
+ json: async () => ({ data: [], total: 0, page: 1, pageSize: 100, totalPages: 0 })
|
|
|
+ })
|
|
|
+
|
|
|
+ render(
|
|
|
+ <TestWrapper>
|
|
|
+ <GoodsDetailPage />
|
|
|
+ </TestWrapper>
|
|
|
+ )
|
|
|
+
|
|
|
+ // 等待商品加载完成
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(screen.getByText('测试商品', { selector: '.goods-title' })).toBeInTheDocument()
|
|
|
+ })
|
|
|
+
|
|
|
+ // 获取数量输入框
|
|
|
+ const quantityInput = screen.getByDisplayValue('1')
|
|
|
+
|
|
|
+ // 尝试输入0
|
|
|
+ fireEvent.change(quantityInput, { target: { value: '0' } })
|
|
|
+ fireEvent.blur(quantityInput)
|
|
|
+
|
|
|
+ // 验证数量自动纠正为1
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(quantityInput).toHaveValue(1)
|
|
|
+ })
|
|
|
+
|
|
|
+ // 尝试输入负数(负号会被移除,变为5)
|
|
|
+ fireEvent.change(quantityInput, { target: { value: '-5' } })
|
|
|
+ fireEvent.blur(quantityInput)
|
|
|
+
|
|
|
+ // 验证负号被移除,值变为5
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(quantityInput).toHaveValue(5)
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ it('规格选择弹窗取消操作', async () => {
|
|
|
+ // Mock商品详情API成功
|
|
|
+ const mockGoodsResponse = {
|
|
|
+ status: 200,
|
|
|
+ json: async () => mockGoods
|
|
|
+ }
|
|
|
+ ;(goodsClient[':id'].$get as jest.Mock).mockResolvedValue(mockGoodsResponse)
|
|
|
+ ;(goodsClient[':id'].children.$get as jest.Mock).mockResolvedValue({
|
|
|
+ status: 200,
|
|
|
+ json: async () => mockChildren
|
|
|
+ })
|
|
|
+
|
|
|
+ render(
|
|
|
+ <TestWrapper>
|
|
|
+ <GoodsDetailPage />
|
|
|
+ </TestWrapper>
|
|
|
+ )
|
|
|
+
|
|
|
+ // 等待商品加载完成
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(screen.getByText('测试商品', { selector: '.goods-title' })).toBeInTheDocument()
|
|
|
+ })
|
|
|
+
|
|
|
+ // 打开规格选择弹窗
|
|
|
+ const specButton = screen.getByText('选择规格', { selector: '.spec-select-btn' })
|
|
|
+ fireEvent.click(specButton)
|
|
|
+
|
|
|
+ // 等待规格弹窗加载
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(screen.getByText('红色款')).toBeInTheDocument()
|
|
|
+ })
|
|
|
+
|
|
|
+ // 不选择规格,直接关闭弹窗(点击弹窗外部或关闭按钮)
|
|
|
+ // 查找关闭按钮(通过class或文本)
|
|
|
+ const closeButton = screen.getByText('选择规格', { selector: '.spec-modal-title' }).closest('.spec-modal-content')?.querySelector('.spec-modal-close')
|
|
|
+ if (closeButton) {
|
|
|
+ fireEvent.click(closeButton)
|
|
|
+ } else {
|
|
|
+ // 如果没有关闭按钮,直接模拟关闭操作
|
|
|
+ // 点击弹窗外部(通过点击页面其他区域)
|
|
|
+ fireEvent.click(document.body)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 等待弹窗关闭
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(screen.queryByText('红色款')).not.toBeInTheDocument()
|
|
|
+ })
|
|
|
+
|
|
|
+ // 验证页面没有选择规格
|
|
|
+ expect(screen.queryByText('红色款', { selector: '.spec-price' })).not.toBeInTheDocument()
|
|
|
+
|
|
|
+ // 验证按钮禁用(因为未选择规格但有规格选项)
|
|
|
+ const addToCartButton = screen.getByText('加入购物车')
|
|
|
+ const buyNowButton = screen.getByText('立即购买')
|
|
|
+ expect(addToCartButton).toBeDisabled()
|
|
|
+ expect(buyNowButton).toBeDisabled()
|
|
|
+ })
|
|
|
})
|