CancelReasonDialog.test.tsx 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. import { render, fireEvent, waitFor } from '@testing-library/react'
  2. import { mockShowToast } from '~/__mocks__/taroMock'
  3. import CancelReasonDialog from '@/components/common/CancelReasonDialog'
  4. describe('CancelReasonDialog', () => {
  5. const defaultProps = {
  6. open: true,
  7. onOpenChange: jest.fn(),
  8. onConfirm: jest.fn(),
  9. loading: false
  10. }
  11. beforeEach(() => {
  12. jest.clearAllMocks()
  13. })
  14. it('应该渲染对话框当可见时为true', () => {
  15. const { getByText, getAllByText } = render(<CancelReasonDialog {...defaultProps} />)
  16. expect(getByText('取消订单')).toBeTruthy()
  17. expect(getByText('请选择或填写取消原因,这将帮助我们改进服务')).toBeTruthy()
  18. expect(getByText('我不想买了')).toBeTruthy()
  19. expect(getByText('信息填写错误,重新下单')).toBeTruthy()
  20. expect(getByText('商家缺货')).toBeTruthy()
  21. expect(getByText('价格不合适')).toBeTruthy()
  22. // 有多个"其他原因"文本,使用getAllByText
  23. expect(getAllByText('其他原因').length).toBeGreaterThan(0)
  24. })
  25. it('不应该渲染对话框当open为false时', () => {
  26. const { queryByText } = render(
  27. <CancelReasonDialog {...defaultProps} open={false} />
  28. )
  29. expect(queryByText('取消订单')).toBeNull()
  30. })
  31. it.each([
  32. '我不想买了',
  33. '信息填写错误,重新下单',
  34. '商家缺货',
  35. '价格不合适',
  36. '其他原因'
  37. ])('应该选择预定义原因 %s 当点击时', async (reason) => {
  38. const { getByTestId } = render(<CancelReasonDialog {...defaultProps} />)
  39. const reasonOption = getByTestId(`cancel-reason-${reason}`)
  40. fireEvent.click(reasonOption)
  41. // 等待状态更新完成
  42. await waitFor(() => {
  43. expect(reasonOption).toHaveClass('border-primary')
  44. })
  45. const confirmButton = getByTestId('confirm-cancel-button')
  46. fireEvent.click(confirmButton)
  47. expect(defaultProps.onConfirm).toHaveBeenCalledWith(reason)
  48. })
  49. it('应该显示选中状态当点击预定义原因时', async () => {
  50. const { getByTestId } = render(<CancelReasonDialog {...defaultProps} />)
  51. // 点击第一个原因
  52. const firstReason = getByTestId('cancel-reason-我不想买了')
  53. fireEvent.click(firstReason)
  54. // 等待状态更新完成
  55. await waitFor(() => {
  56. // 验证选中状态样式
  57. expect(firstReason).toHaveClass('border-primary')
  58. expect(firstReason).toHaveClass('bg-primary/10')
  59. })
  60. // 点击第二个原因,第一个应该取消选中
  61. const secondReason = getByTestId('cancel-reason-信息填写错误,重新下单')
  62. fireEvent.click(secondReason)
  63. // 等待状态更新完成
  64. await waitFor(() => {
  65. // 第一个原因应该不再有选中状态
  66. expect(firstReason).not.toHaveClass('border-primary')
  67. expect(firstReason).not.toHaveClass('bg-primary/10')
  68. // 第二个原因应该有选中状态
  69. expect(secondReason).toHaveClass('border-primary')
  70. expect(secondReason).toHaveClass('bg-primary/10')
  71. })
  72. })
  73. it('应该清除预定义原因选中状态当输入自定义原因时', async () => {
  74. const { getByTestId, getByPlaceholderText } = render(<CancelReasonDialog {...defaultProps} />)
  75. // 先点击一个预定义原因
  76. const reasonOption = getByTestId('cancel-reason-我不想买了')
  77. fireEvent.click(reasonOption)
  78. // 等待选中状态更新
  79. await waitFor(() => {
  80. // 验证有选中状态
  81. expect(reasonOption).toHaveClass('border-primary')
  82. expect(reasonOption).toHaveClass('bg-primary/10')
  83. })
  84. // 输入自定义原因
  85. const input = getByPlaceholderText('请输入其他取消原因...')
  86. fireEvent.input(input, { target: { value: '自定义取消原因' } })
  87. // 等待选中状态清除
  88. await waitFor(() => {
  89. // 预定义原因的选中状态应该被清除
  90. expect(reasonOption).not.toHaveClass('border-primary')
  91. expect(reasonOption).not.toHaveClass('bg-primary/10')
  92. })
  93. })
  94. it('应该模拟用户实际点击流程', async () => {
  95. const { getByTestId } = render(<CancelReasonDialog {...defaultProps} />)
  96. // 点击一个原因
  97. const reasonOption = getByTestId('cancel-reason-商家缺货')
  98. fireEvent.click(reasonOption)
  99. // 等待选中状态
  100. await waitFor(() => {
  101. expect(reasonOption).toHaveClass('border-primary')
  102. expect(reasonOption).toHaveClass('bg-primary/10')
  103. })
  104. // 立即点击确认按钮
  105. const confirmButton = getByTestId('confirm-cancel-button')
  106. fireEvent.click(confirmButton)
  107. // 应该成功调用onConfirm
  108. expect(defaultProps.onConfirm).toHaveBeenCalledWith('商家缺货')
  109. })
  110. it('应该调用onConfirm当确认按钮被点击时', () => {
  111. const { getByTestId } = render(<CancelReasonDialog {...defaultProps} />)
  112. const reasonOption = getByTestId('cancel-reason-我不想买了')
  113. fireEvent.click(reasonOption)
  114. const confirmButton = getByTestId('confirm-cancel-button')
  115. fireEvent.click(confirmButton)
  116. expect(defaultProps.onConfirm).toHaveBeenCalledWith('我不想买了')
  117. })
  118. it('应该调用onOpenChange当取消按钮被点击时', () => {
  119. const { getByText } = render(<CancelReasonDialog {...defaultProps} />)
  120. const cancelButton = getByText('取消')
  121. fireEvent.click(cancelButton)
  122. expect(defaultProps.onOpenChange).toHaveBeenCalledWith(false)
  123. })
  124. it('应该显示错误当确认空原因时', () => {
  125. const { getByTestId, getByText } = render(<CancelReasonDialog {...defaultProps} />)
  126. const confirmButton = getByTestId('confirm-cancel-button')
  127. fireEvent.click(confirmButton)
  128. // 使用更精确的查询方式查找错误消息
  129. const errorMessage = getByText('请输入取消原因')
  130. expect(errorMessage).toBeTruthy()
  131. expect(defaultProps.onConfirm).not.toHaveBeenCalled()
  132. })
  133. it('应该显示错误当原因超过200字符时', () => {
  134. const { getByPlaceholderText, getByTestId, getByText } = render(
  135. <CancelReasonDialog {...defaultProps} />
  136. )
  137. const input = getByPlaceholderText('请输入其他取消原因...')
  138. fireEvent.input(input, { target: { value: 'a'.repeat(201) } })
  139. const confirmButton = getByTestId('confirm-cancel-button')
  140. fireEvent.click(confirmButton)
  141. const errorMessage = getByText('取消原因不能超过200个字符')
  142. expect(errorMessage).toBeTruthy()
  143. expect(defaultProps.onConfirm).not.toHaveBeenCalled()
  144. })
  145. it('应该处理自定义原因输入', () => {
  146. const { getByPlaceholderText, getByTestId } = render(
  147. <CancelReasonDialog {...defaultProps} />
  148. )
  149. const input = getByPlaceholderText('请输入其他取消原因...')
  150. fireEvent.input(input, { target: { value: '自定义取消原因' } })
  151. const confirmButton = getByTestId('confirm-cancel-button')
  152. fireEvent.click(confirmButton)
  153. expect(defaultProps.onConfirm).toHaveBeenCalledWith('自定义取消原因')
  154. })
  155. it('应该显示加载状态当loading为true时', () => {
  156. const { getByTestId } = render(
  157. <CancelReasonDialog {...defaultProps} loading={true} />
  158. )
  159. const confirmButton = getByTestId('confirm-cancel-button')
  160. expect(confirmButton).toHaveTextContent('提交中...')
  161. })
  162. it('应该禁用按钮当loading为true时', () => {
  163. const { getByText, getByTestId } = render(
  164. <CancelReasonDialog {...defaultProps} loading={true} />
  165. )
  166. const cancelButton = getByText('取消')
  167. const confirmButton = getByTestId('confirm-cancel-button')
  168. // 检查按钮是否被禁用
  169. expect(cancelButton).toBeTruthy()
  170. expect(confirmButton).toBeTruthy()
  171. })
  172. it('应该重置状态当对话框关闭时', () => {
  173. const { getByTestId, getByText, rerender } = render(
  174. <CancelReasonDialog {...defaultProps} />
  175. )
  176. const reasonOption = getByTestId('cancel-reason-我不想买了')
  177. fireEvent.click(reasonOption)
  178. // 重新渲染关闭的对话框
  179. rerender(<CancelReasonDialog {...defaultProps} open={false} />)
  180. // 重新渲染打开的对话框
  181. rerender(<CancelReasonDialog {...defaultProps} open={true} />)
  182. // 检查状态是否重置 - 直接点击确认按钮应该显示错误
  183. const confirmButton = getByTestId('confirm-cancel-button')
  184. fireEvent.click(confirmButton)
  185. const errorMessage = getByText('请输入取消原因')
  186. expect(errorMessage).toBeTruthy()
  187. })
  188. })