printConfigManagement.integration.test.tsx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. import { describe, it, expect, vi, beforeEach } from 'vitest';
  2. import { render, screen, fireEvent, waitFor } from '@testing-library/react';
  3. import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
  4. import { PrintConfigManagement } from '../../src/components/PrintConfigManagement';
  5. import { createFeiePrinterClient } from '../../src/api/feiePrinterClient';
  6. import { ConfigKey, ConfigType } from '../../src/types/feiePrinter';
  7. // Mock API client
  8. vi.mock('../../src/api/feiePrinterClient', () => {
  9. const mockClient = {
  10. getPrintConfigs: vi.fn(),
  11. updatePrintConfig: vi.fn(),
  12. setAuthToken: vi.fn(),
  13. setTenantId: vi.fn(),
  14. };
  15. return {
  16. createFeiePrinterClient: vi.fn(() => mockClient),
  17. };
  18. });
  19. // Mock toast
  20. vi.mock('sonner', () => ({
  21. toast: {
  22. success: vi.fn(() => {}),
  23. error: vi.fn(() => {}),
  24. info: vi.fn(() => {}),
  25. },
  26. }));
  27. const createTestQueryClient = () =>
  28. new QueryClient({
  29. defaultOptions: {
  30. queries: {
  31. retry: false,
  32. },
  33. },
  34. });
  35. const renderWithProviders = (component: React.ReactElement) => {
  36. const queryClient = createTestQueryClient();
  37. return render(
  38. <QueryClientProvider client={queryClient}>
  39. {component as any}
  40. </QueryClientProvider>
  41. );
  42. };
  43. describe('打印配置管理组件集成测试', () => {
  44. let mockClient: any;
  45. beforeEach(() => {
  46. vi.clearAllMocks();
  47. mockClient = (createFeiePrinterClient as any)();
  48. });
  49. it('应该渲染组件并加载配置数据', async () => {
  50. const mockConfigsData = {
  51. data: [
  52. {
  53. id: 1,
  54. configKey: ConfigKey.ANTI_REFUND_DELAY,
  55. configValue: '120',
  56. configType: ConfigType.NUMBER,
  57. description: '防退款延迟时间(秒)',
  58. isEnabled: 1,
  59. createdAt: '2024-01-01T00:00:00Z',
  60. updatedAt: '2024-01-01T00:00:00Z',
  61. },
  62. ],
  63. pagination: {
  64. total: 1,
  65. page: 1,
  66. pageSize: 20,
  67. totalPages: 1,
  68. },
  69. };
  70. // Mock initial configs data
  71. mockClient.getPrintConfigs.mockResolvedValue(mockConfigsData);
  72. renderWithProviders(
  73. <PrintConfigManagement
  74. baseURL="/api/v1/feie"
  75. tenantId={123}
  76. authToken="test-token"
  77. />
  78. );
  79. // 验证API被调用
  80. await waitFor(() => {
  81. expect(mockClient.getPrintConfigs).toHaveBeenCalled();
  82. });
  83. // 验证组件标题渲染
  84. expect(screen.getByText('打印配置管理')).toBeInTheDocument();
  85. expect(screen.getByText('管理飞鹅打印的配置项,包括基础配置、打印策略和模板配置')).toBeInTheDocument();
  86. // 验证刷新按钮存在
  87. expect(screen.getByRole('button', { name: /刷新/i })).toBeInTheDocument();
  88. });
  89. it('应该处理获取配置列表API错误', async () => {
  90. // Mock API error
  91. mockClient.getPrintConfigs.mockRejectedValue(new Error('获取配置列表失败'));
  92. renderWithProviders(
  93. <PrintConfigManagement
  94. baseURL="/api/v1/feie"
  95. tenantId={123}
  96. authToken="test-token"
  97. />
  98. );
  99. // 检查错误UI是否显示
  100. await waitFor(() => {
  101. expect(screen.getByText('加载配置失败')).toBeInTheDocument();
  102. expect(screen.getByRole('button', { name: /重试/i })).toBeInTheDocument();
  103. });
  104. });
  105. it('应该处理更新配置API错误', async () => {
  106. const { toast } = await import('sonner');
  107. const mockConfigsData = {
  108. data: [
  109. {
  110. id: 1,
  111. configKey: ConfigKey.ANTI_REFUND_DELAY,
  112. configValue: '120',
  113. configType: ConfigType.NUMBER,
  114. description: '防退款延迟时间(秒)',
  115. isEnabled: 1,
  116. createdAt: '2024-01-01T00:00:00Z',
  117. updatedAt: '2024-01-01T00:00:00Z',
  118. },
  119. ],
  120. pagination: {
  121. total: 1,
  122. page: 1,
  123. pageSize: 20,
  124. totalPages: 1,
  125. },
  126. };
  127. mockClient.getPrintConfigs.mockResolvedValue(mockConfigsData);
  128. mockClient.updatePrintConfig.mockRejectedValue(new Error('更新配置失败'));
  129. renderWithProviders(
  130. <PrintConfigManagement
  131. baseURL="/api/v1/feie"
  132. tenantId={123}
  133. authToken="test-token"
  134. />
  135. );
  136. // 等待初始数据加载
  137. await waitFor(() => {
  138. expect(mockClient.getPrintConfigs).toHaveBeenCalled();
  139. });
  140. // 等待配置项渲染
  141. await waitFor(() => {
  142. expect(screen.getByText('防退款延迟时间(秒)')).toBeInTheDocument();
  143. });
  144. // 找到配置值输入框(根据组件行为,可能是spinbutton或textbox)
  145. // 注意:实际组件可能使用不同的输入方式,这里需要根据实际组件调整
  146. let configInputs = screen.queryAllByRole('spinbutton');
  147. if (configInputs.length === 0) {
  148. configInputs = screen.queryAllByRole('textbox');
  149. }
  150. expect(configInputs.length).toBeGreaterThan(0);
  151. // 修改配置值
  152. fireEvent.change(configInputs[0], { target: { value: '180' } });
  153. // 找到批量保存按钮
  154. const saveButtons = screen.getAllByRole('button', { name: /批量保存/i });
  155. expect(saveButtons.length).toBeGreaterThan(0);
  156. // 点击批量保存按钮
  157. fireEvent.click(saveButtons[0]);
  158. await waitFor(() => {
  159. expect(toast.error).toHaveBeenCalledWith('批量保存失败: 更新配置失败');
  160. });
  161. });
  162. it('应该支持多租户场景', async () => {
  163. const mockConfigsData = {
  164. data: [
  165. {
  166. id: 1,
  167. configKey: ConfigKey.ANTI_REFUND_DELAY,
  168. configValue: '150',
  169. configType: ConfigType.NUMBER,
  170. description: '防退款延迟时间(秒)',
  171. isEnabled: 1,
  172. createdAt: '2024-01-01T00:00:00Z',
  173. updatedAt: '2024-01-01T00:00:00Z',
  174. },
  175. ],
  176. pagination: {
  177. total: 1,
  178. page: 1,
  179. pageSize: 20,
  180. totalPages: 1,
  181. },
  182. };
  183. mockClient.getPrintConfigs.mockResolvedValue(mockConfigsData);
  184. renderWithProviders(
  185. <PrintConfigManagement
  186. baseURL="/api/v1/feie"
  187. tenantId={456}
  188. authToken="test-token"
  189. />
  190. );
  191. await waitFor(() => {
  192. expect(mockClient.getPrintConfigs).toHaveBeenCalled();
  193. });
  194. // 验证租户ID设置
  195. expect(mockClient.setTenantId).toHaveBeenCalledWith(456);
  196. expect(mockClient.setAuthToken).toHaveBeenCalledWith('test-token');
  197. // 等待数据加载
  198. await waitFor(() => {
  199. expect(screen.getByText('防退款延迟时间(秒)')).toBeInTheDocument();
  200. });
  201. // 配置值在输入框中,检查输入框存在
  202. const configInputs = screen.queryAllByRole('spinbutton');
  203. const textInputs = screen.queryAllByRole('textbox');
  204. expect(configInputs.length + textInputs.length).toBeGreaterThan(0);
  205. // 检查租户ID设置是否正确
  206. expect(mockClient.setTenantId).toHaveBeenCalledWith(456);
  207. expect(mockClient.setAuthToken).toHaveBeenCalledWith('test-token');
  208. });
  209. it('应该处理配置项启用/禁用状态', async () => {
  210. const mockConfigsData = {
  211. data: [
  212. {
  213. id: 1,
  214. configKey: ConfigKey.ANTI_REFUND_DELAY,
  215. configValue: '120',
  216. configType: ConfigType.NUMBER,
  217. description: '防退款延迟时间(秒)',
  218. isEnabled: 1,
  219. createdAt: '2024-01-01T00:00:00Z',
  220. updatedAt: '2024-01-01T00:00:00Z',
  221. },
  222. {
  223. id: 2,
  224. configKey: ConfigKey.RECEIPT_TEMPLATE,
  225. configValue: '订单号: {orderNo}',
  226. configType: ConfigType.STRING,
  227. description: '小票模板',
  228. isEnabled: 0, // 禁用状态
  229. createdAt: '2024-01-01T00:00:00Z',
  230. updatedAt: '2024-01-01T00:00Z',
  231. },
  232. ],
  233. pagination: {
  234. total: 2,
  235. page: 1,
  236. pageSize: 20,
  237. totalPages: 1,
  238. },
  239. };
  240. mockClient.getPrintConfigs.mockResolvedValue(mockConfigsData);
  241. renderWithProviders(
  242. <PrintConfigManagement
  243. baseURL="/api/v1/feie"
  244. tenantId={123}
  245. authToken="test-token"
  246. />
  247. );
  248. // 等待数据加载 - 至少检查一个配置项存在
  249. await waitFor(() => {
  250. expect(screen.getByText('防退款延迟时间(秒)')).toBeInTheDocument();
  251. });
  252. // 检查组件基本渲染
  253. expect(screen.getByText('打印配置管理')).toBeInTheDocument();
  254. expect(screen.getByRole('button', { name: /刷新/i })).toBeInTheDocument();
  255. });
  256. it('应该处理不同配置类型的显示', async () => {
  257. const mockConfigsData = {
  258. data: [
  259. {
  260. id: 1,
  261. configKey: ConfigKey.ANTI_REFUND_DELAY,
  262. configValue: '120',
  263. configType: ConfigType.NUMBER,
  264. description: '防退款延迟时间(秒)',
  265. isEnabled: 1,
  266. createdAt: '2024-01-01T00:00:00Z',
  267. updatedAt: '2024-01-01T00:00:00Z',
  268. },
  269. {
  270. id: 2,
  271. configKey: ConfigKey.RECEIPT_TEMPLATE,
  272. configValue: '订单号: {orderNo}',
  273. configType: ConfigType.STRING,
  274. description: '小票模板',
  275. isEnabled: 1,
  276. createdAt: '2024-01-01T00:00:00Z',
  277. updatedAt: '2024-01-01T00:00:00Z',
  278. },
  279. {
  280. id: 3,
  281. configKey: ConfigKey.SHIPPING_TEMPLATE,
  282. configValue: '发货单\n订单号: {orderNo}',
  283. configType: ConfigType.STRING,
  284. description: '发货单模板',
  285. isEnabled: 1,
  286. createdAt: '2024-01-01T00:00:00Z',
  287. updatedAt: '2024-01-01T00:00:00Z',
  288. },
  289. ],
  290. pagination: {
  291. total: 3,
  292. page: 1,
  293. pageSize: 20,
  294. totalPages: 1,
  295. },
  296. };
  297. mockClient.getPrintConfigs.mockResolvedValue(mockConfigsData);
  298. renderWithProviders(
  299. <PrintConfigManagement
  300. baseURL="/api/v1/feie"
  301. tenantId={123}
  302. authToken="test-token"
  303. />
  304. );
  305. // 等待数据加载 - 至少检查一个配置项存在
  306. await waitFor(() => {
  307. expect(screen.getByText('防退款延迟时间(秒)')).toBeInTheDocument();
  308. });
  309. // 检查组件基本渲染和输入框存在
  310. expect(screen.getByText('打印配置管理')).toBeInTheDocument();
  311. // 检查是否有输入框(配置值在输入框中)
  312. const configInputs = screen.queryAllByRole('spinbutton');
  313. const textInputs = screen.queryAllByRole('textbox');
  314. expect(configInputs.length + textInputs.length).toBeGreaterThan(0);
  315. });
  316. });