api.ts 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /**
  2. * API Mock 工具
  3. * 用于单元测试中模拟 API 响应
  4. */
  5. import { vi } from 'vitest'
  6. import * as fixtures from '../fixtures'
  7. // Mock request 模块的类型
  8. type MockedRequest = {
  9. get: ReturnType<typeof vi.fn>
  10. post: ReturnType<typeof vi.fn>
  11. put: ReturnType<typeof vi.fn>
  12. del: ReturnType<typeof vi.fn>
  13. }
  14. /**
  15. * 创建 API mock
  16. */
  17. export function createApiMock() {
  18. return {
  19. get: vi.fn(),
  20. post: vi.fn(),
  21. put: vi.fn(),
  22. del: vi.fn()
  23. }
  24. }
  25. /**
  26. * 设置登录 API mock
  27. */
  28. export function mockLoginApi(request: MockedRequest) {
  29. // login
  30. request.post.mockImplementation((url: string, data?: any) => {
  31. if (url === '/admin/auth/login') {
  32. if (data?.username === 'admin' && data?.password === 'admin123') {
  33. return Promise.resolve(fixtures.wrapResponse(fixtures.mockLoginResponse))
  34. }
  35. return Promise.resolve(fixtures.wrapErrorResponse('用户名或密码错误', 401))
  36. }
  37. if (url === '/admin/auth/logout') {
  38. return Promise.resolve(fixtures.wrapResponse(null))
  39. }
  40. if (url === '/admin/auth/password') {
  41. if (data?.oldPassword === 'admin123') {
  42. return Promise.resolve(fixtures.wrapResponse(null, 200, '密码修改成功'))
  43. }
  44. return Promise.resolve(fixtures.wrapErrorResponse('原密码错误', 400))
  45. }
  46. return Promise.resolve(fixtures.wrapErrorResponse('Not Found', 404))
  47. })
  48. // getInfo
  49. request.get.mockImplementation((url: string) => {
  50. if (url === '/admin/auth/info') {
  51. return Promise.resolve(fixtures.wrapResponse(fixtures.mockAdminInfo))
  52. }
  53. return Promise.resolve(fixtures.wrapErrorResponse('Not Found', 404))
  54. })
  55. }
  56. /**
  57. * 设置机器 API mock
  58. */
  59. export function mockMachineApi(request: MockedRequest) {
  60. request.get.mockImplementation((url: string, params?: any) => {
  61. if (url === '/admin/machines/list') {
  62. return Promise.resolve(fixtures.wrapResponse(fixtures.mockMachines))
  63. }
  64. if (url === '/admin/machines/detail') {
  65. const machine = fixtures.mockMachines.find((m) => m.id === params?.id)
  66. if (machine) {
  67. return Promise.resolve(fixtures.wrapResponse(machine))
  68. }
  69. return Promise.resolve(fixtures.wrapErrorResponse('机器不存在', 404))
  70. }
  71. return Promise.resolve(fixtures.wrapErrorResponse('Not Found', 404))
  72. })
  73. request.post.mockImplementation((url: string, data?: any, config?: any) => {
  74. if (url === '/admin/machines/add') {
  75. const newMachine: typeof fixtures.mockMachines[0] = {
  76. id: fixtures.mockMachines.length + 1,
  77. machineId: data.machineId,
  78. name: data.name,
  79. location: data.location || '',
  80. description: data.description || '',
  81. enabled: true,
  82. cameraCount: 0,
  83. createdAt: new Date().toISOString(),
  84. updatedAt: new Date().toISOString()
  85. }
  86. return Promise.resolve(fixtures.wrapResponse(newMachine))
  87. }
  88. if (url === '/admin/machines/update') {
  89. const machine = fixtures.mockMachines.find((m) => m.id === data?.id)
  90. if (machine) {
  91. return Promise.resolve(fixtures.wrapResponse({ ...machine, ...data }))
  92. }
  93. return Promise.resolve(fixtures.wrapErrorResponse('机器不存在', 404))
  94. }
  95. if (url === '/admin/machines/delete') {
  96. const id = config?.params?.id
  97. const machine = fixtures.mockMachines.find((m) => m.id === id)
  98. if (machine) {
  99. if (machine.cameraCount > 0) {
  100. return Promise.resolve(fixtures.wrapErrorResponse('该机器下存在摄像头,无法删除', 400))
  101. }
  102. return Promise.resolve(fixtures.wrapResponse(null))
  103. }
  104. return Promise.resolve(fixtures.wrapErrorResponse('机器不存在', 404))
  105. }
  106. return Promise.resolve(fixtures.wrapErrorResponse('Not Found', 404))
  107. })
  108. }
  109. /**
  110. * 设置摄像头 API mock
  111. */
  112. export function mockCameraApi(request: MockedRequest) {
  113. request.get.mockImplementation((url: string, params?: any) => {
  114. if (url === '/admin/cameras/list') {
  115. let cameras = fixtures.mockCameras
  116. if (params?.machineId) {
  117. cameras = cameras.filter((c) => c.machineId === params.machineId)
  118. }
  119. return Promise.resolve(fixtures.wrapResponse(cameras))
  120. }
  121. if (url === '/admin/cameras/detail') {
  122. const camera = fixtures.mockCameras.find((c) => c.id === params?.id)
  123. if (camera) {
  124. return Promise.resolve(fixtures.wrapResponse(camera))
  125. }
  126. return Promise.resolve(fixtures.wrapErrorResponse('摄像头不存在', 404))
  127. }
  128. if (url === '/camera/list') {
  129. return Promise.resolve(fixtures.wrapResponse(fixtures.mockCameras))
  130. }
  131. if (url.startsWith('/camera/') && !url.includes('/ptz')) {
  132. const cameraId = url.split('/')[2]
  133. const camera = fixtures.mockCameras.find((c) => c.cameraId === cameraId)
  134. if (camera) {
  135. return Promise.resolve(fixtures.wrapResponse(camera))
  136. }
  137. }
  138. if (url === '/camera/current') {
  139. return Promise.resolve(fixtures.wrapResponse(fixtures.mockChannels[0]))
  140. }
  141. return Promise.resolve(fixtures.wrapErrorResponse('Not Found', 404))
  142. })
  143. request.post.mockImplementation((url: string, data?: any, config?: any) => {
  144. if (url === '/admin/cameras/add') {
  145. const newCamera = {
  146. id: fixtures.mockCameras.length + 1,
  147. ...data,
  148. status: 'OFFLINE',
  149. channels: [],
  150. createdAt: new Date().toISOString(),
  151. updatedAt: new Date().toISOString()
  152. }
  153. return Promise.resolve(fixtures.wrapResponse(newCamera))
  154. }
  155. if (url === '/admin/cameras/update') {
  156. const camera = fixtures.mockCameras.find((c) => c.id === data?.id)
  157. if (camera) {
  158. return Promise.resolve(fixtures.wrapResponse({ ...camera, ...data }))
  159. }
  160. return Promise.resolve(fixtures.wrapErrorResponse('摄像头不存在', 404))
  161. }
  162. if (url === '/admin/cameras/delete') {
  163. return Promise.resolve(fixtures.wrapResponse(null))
  164. }
  165. if (url === '/admin/cameras/check') {
  166. return Promise.resolve(fixtures.wrapResponse(true))
  167. }
  168. if (url === '/camera/switch') {
  169. const channel = fixtures.mockChannels.find((c) => c.channelId === data?.channelId)
  170. if (channel) {
  171. return Promise.resolve(fixtures.wrapResponse(channel))
  172. }
  173. return Promise.resolve(fixtures.wrapErrorResponse('通道不存在', 404))
  174. }
  175. if (url.includes('/ptz/start')) {
  176. return Promise.resolve(fixtures.wrapResponse(null))
  177. }
  178. if (url.includes('/ptz/stop')) {
  179. return Promise.resolve(fixtures.wrapResponse(null))
  180. }
  181. return Promise.resolve(fixtures.wrapErrorResponse('Not Found', 404))
  182. })
  183. }
  184. /**
  185. * 设置统计 API mock
  186. */
  187. export function mockStatsApi(request: MockedRequest) {
  188. request.get.mockImplementation((url: string) => {
  189. if (url === '/admin/stats/dashboard') {
  190. return Promise.resolve(fixtures.wrapResponse(fixtures.mockDashboardStats))
  191. }
  192. return Promise.resolve(fixtures.wrapErrorResponse('Not Found', 404))
  193. })
  194. }
  195. /**
  196. * 设置所有 API mock
  197. */
  198. export function mockAllApis(request: MockedRequest) {
  199. const originalGet = request.get.getMockImplementation?.() || (() => {})
  200. const originalPost = request.post.getMockImplementation?.() || (() => {})
  201. request.get.mockImplementation((url: string, params?: any) => {
  202. // Auth
  203. if (url === '/admin/auth/info') {
  204. return Promise.resolve(fixtures.wrapResponse(fixtures.mockAdminInfo))
  205. }
  206. // Machines
  207. if (url === '/admin/machines/list') {
  208. return Promise.resolve(fixtures.wrapResponse(fixtures.mockMachines))
  209. }
  210. if (url === '/admin/machines/detail') {
  211. const machine = fixtures.mockMachines.find((m) => m.id === params?.id)
  212. return Promise.resolve(fixtures.wrapResponse(machine))
  213. }
  214. // Cameras
  215. if (url === '/admin/cameras/list') {
  216. return Promise.resolve(fixtures.wrapResponse(fixtures.mockCameras))
  217. }
  218. if (url === '/camera/list') {
  219. return Promise.resolve(fixtures.wrapResponse(fixtures.mockCameras))
  220. }
  221. // Stats
  222. if (url === '/admin/stats/dashboard') {
  223. return Promise.resolve(fixtures.wrapResponse(fixtures.mockDashboardStats))
  224. }
  225. return Promise.resolve(fixtures.wrapErrorResponse('Not Found', 404))
  226. })
  227. request.post.mockImplementation((url: string, data?: any) => {
  228. if (url === '/admin/auth/login') {
  229. if (data?.username === 'admin' && data?.password === 'admin123') {
  230. return Promise.resolve(fixtures.wrapResponse(fixtures.mockLoginResponse))
  231. }
  232. return Promise.resolve(fixtures.wrapErrorResponse('用户名或密码错误', 401))
  233. }
  234. if (url === '/admin/auth/logout') {
  235. return Promise.resolve(fixtures.wrapResponse(null))
  236. }
  237. return Promise.resolve(fixtures.wrapResponse(null))
  238. })
  239. }