vue-source-loading-hook.spec.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import { describe, expect, it, vi } from 'vitest'
  2. import { ref } from 'vue'
  3. import {
  4. FILE_VIEWER_PREVIEW_MESSAGES,
  5. createFileViewerLoadStartState,
  6. createFileViewerRenderCompleteState,
  7. createFileViewerRequestController
  8. } from '../packages/core/src'
  9. import { useViewerSourceLoading } from '../packages/components/vue3/src/package/components/FileViewer/hooks/useViewerSourceLoading'
  10. import type { FileViewerLifecycleContext } from '../packages/components/vue3/src/package/common/type'
  11. describe('Vue FileViewer source loading hook', () => {
  12. it('keeps local file loading state and lifecycle events aligned with the legacy component flow', async () => {
  13. const file = new File(['hello file viewer'], 'hello.txt', { type: 'text/plain' })
  14. const filename = ref('')
  15. const currentFile = ref<File | null>(null)
  16. const currentBuffer = ref<ArrayBuffer | null>(null)
  17. const currentSourceUrl = ref<string | null>(null)
  18. const renderedReady = ref(false)
  19. const progressiveReady = ref(true)
  20. const lifecycleEvents: FileViewerLifecycleContext[] = []
  21. const renderSession = { destroy: vi.fn() }
  22. const clearRenderedContent = vi.fn()
  23. const mountRenderedContent = vi.fn(async () => renderSession)
  24. const setActiveRenderSession = vi.fn()
  25. const startLoading = vi.fn()
  26. const stopLoading = vi.fn()
  27. const startedAt = new Map<number, number>()
  28. const sourceLoading = useViewerSourceLoading({
  29. getFile: () => file,
  30. getUrl: () => undefined,
  31. getOptions: () => undefined,
  32. filename,
  33. currentFile,
  34. currentBuffer,
  35. currentSourceUrl,
  36. renderedReady,
  37. progressiveReady,
  38. requestController: createFileViewerRequestController(),
  39. clearRenderedContent,
  40. mountRenderedContent,
  41. destroyRenderSession: vi.fn(),
  42. setActiveRenderSession,
  43. buildLoadStartState: input => createFileViewerLoadStartState({
  44. ...input,
  45. filename: filename.value,
  46. bufferSize: currentBuffer.value?.byteLength,
  47. loadingMessage: input.source === 'url'
  48. ? FILE_VIEWER_PREVIEW_MESSAGES.downloading
  49. : FILE_VIEWER_PREVIEW_MESSAGES.reading
  50. }),
  51. buildRenderCompleteState: input => createFileViewerRenderCompleteState({
  52. ...input,
  53. filename: filename.value,
  54. bufferSize: currentBuffer.value?.byteLength,
  55. startedAt: startedAt.get(input.version)
  56. }),
  57. notifyLifecycle: context => {
  58. lifecycleEvents.push(context)
  59. },
  60. setActiveDocumentContext: vi.fn(),
  61. markLoadStarted: version => {
  62. startedAt.set(version, Date.now())
  63. },
  64. clearLoadStarted: version => {
  65. startedAt.delete(version)
  66. },
  67. startLoading,
  68. setLoadingMessage: vi.fn(),
  69. stopLoading,
  70. showError: vi.fn(),
  71. clearError: vi.fn(),
  72. resetLoading: vi.fn(),
  73. formatErrorMessage: (prefix, nextError) => `${prefix}: ${String(nextError)}`
  74. })
  75. await sourceLoading.refreshPreview()
  76. expect(clearRenderedContent).toHaveBeenCalledWith('replace')
  77. expect(startLoading).toHaveBeenCalledWith(FILE_VIEWER_PREVIEW_MESSAGES.reading)
  78. expect(stopLoading).toHaveBeenCalledTimes(1)
  79. expect(filename.value).toBe('hello.txt')
  80. expect(currentFile.value).toBe(file)
  81. expect(currentSourceUrl.value).toBeNull()
  82. expect(currentBuffer.value?.byteLength).toBe(file.size)
  83. expect(renderedReady.value).toBe(true)
  84. expect(progressiveReady.value).toBe(false)
  85. expect(mountRenderedContent).toHaveBeenCalledWith(
  86. currentBuffer.value,
  87. file,
  88. 1,
  89. undefined
  90. )
  91. expect(setActiveRenderSession).toHaveBeenCalledWith(renderSession)
  92. expect(lifecycleEvents.map(item => item.phase)).toEqual(['load-start', 'load-complete'])
  93. expect(lifecycleEvents[1]).toMatchObject({
  94. filename: 'hello.txt',
  95. source: 'file',
  96. size: file.size
  97. })
  98. })
  99. it('delegates local preview load errors to the core reporting helper', async () => {
  100. const file = new File(['broken file viewer'], 'broken.txt', { type: 'text/plain' })
  101. const filename = ref('')
  102. const currentFile = ref<File | null>(null)
  103. const currentBuffer = ref<ArrayBuffer | null>(null)
  104. const currentSourceUrl = ref<string | null>(null)
  105. const renderedReady = ref(false)
  106. const progressiveReady = ref(false)
  107. const renderError = new Error('render failed')
  108. const showError = vi.fn()
  109. const consoleError = vi.spyOn(console, 'error').mockImplementation(() => undefined)
  110. const sourceLoading = useViewerSourceLoading({
  111. getFile: () => file,
  112. getUrl: () => undefined,
  113. getOptions: () => undefined,
  114. filename,
  115. currentFile,
  116. currentBuffer,
  117. currentSourceUrl,
  118. renderedReady,
  119. progressiveReady,
  120. requestController: createFileViewerRequestController(),
  121. clearRenderedContent: vi.fn(),
  122. mountRenderedContent: vi.fn(async () => {
  123. throw renderError
  124. }),
  125. destroyRenderSession: vi.fn(),
  126. setActiveRenderSession: vi.fn(),
  127. buildLoadStartState: input => createFileViewerLoadStartState({
  128. ...input,
  129. filename: filename.value,
  130. loadingMessage: FILE_VIEWER_PREVIEW_MESSAGES.reading
  131. }),
  132. buildRenderCompleteState: input => createFileViewerRenderCompleteState({
  133. ...input,
  134. filename: filename.value
  135. }),
  136. notifyLifecycle: vi.fn(),
  137. setActiveDocumentContext: vi.fn(),
  138. markLoadStarted: vi.fn(),
  139. clearLoadStarted: vi.fn(),
  140. startLoading: vi.fn(),
  141. setLoadingMessage: vi.fn(),
  142. stopLoading: vi.fn(),
  143. showError,
  144. clearError: vi.fn(),
  145. resetLoading: vi.fn(),
  146. formatErrorMessage: (prefix, nextError) => `${prefix}: ${nextError instanceof Error ? nextError.message : String(nextError)}`
  147. })
  148. try {
  149. await sourceLoading.refreshPreview()
  150. expect(consoleError).toHaveBeenCalledWith(renderError)
  151. expect(showError).toHaveBeenCalledWith('读取文件异常: render failed')
  152. } finally {
  153. consoleError.mockRestore()
  154. }
  155. })
  156. })