pdf-text.client.spec.ts 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  1. // @vitest-environment jsdom
  2. /** Text overlay resources follow page ownership; resize only aligns selection with the existing canvas. */
  3. import type { PageViewport, PDFPageProxy } from 'pdfjs-dist'
  4. import { afterEach, expect, it, vi } from 'vitest'
  5. const api = vi.hoisted(() => ({ render: vi.fn(), cancel: vi.fn(), create: vi.fn() }))
  6. vi.mock('pdfjs-dist', () => ({}))
  7. vi.mock('pdfjs-dist/web/pdf_viewer.mjs', () => ({
  8. TextLayerBuilder: class {
  9. div = document.createElement('div')
  10. constructor(options: unknown) { api.create(options) }
  11. render = api.render
  12. cancel = api.cancel
  13. },
  14. }))
  15. import { pdfTextRenderer } from '../src/client/pdf/text.ts'
  16. afterEach(() => { vi.unstubAllGlobals(); vi.restoreAllMocks() })
  17. it('aligns selectable text to the displayed width and removes its observer and DOM on cancellation', async () => {
  18. let resize: ResizeObserverCallback | undefined
  19. const observe = vi.fn()
  20. const disconnect = vi.fn()
  21. vi.stubGlobal('ResizeObserver', class {
  22. constructor(callback: ResizeObserverCallback) { resize = callback }
  23. observe = observe
  24. disconnect = disconnect
  25. })
  26. api.render.mockResolvedValue(undefined)
  27. const host = document.createElement('div')
  28. let width = 200
  29. vi.spyOn(host, 'getBoundingClientRect').mockImplementation(() => ({ width }) as DOMRect)
  30. const viewport = { width: 400, scale: 4 / 3, userUnit: 1 } as PageViewport
  31. const text = new ReadableStream()
  32. const page = { streamTextContent: () => text } as PDFPageProxy
  33. const task = pdfTextRenderer(host)(page, viewport)
  34. await task.promise
  35. expect(api.create).toHaveBeenCalledWith({ pdfPage: page })
  36. expect(api.render).toHaveBeenCalledWith({ viewport })
  37. expect(observe).toHaveBeenCalledWith(host)
  38. expect((host.firstElementChild as HTMLElement).style.scale).toBe('0.5')
  39. width = 100
  40. resize!([], {} as ResizeObserver)
  41. expect((host.firstElementChild as HTMLElement).style.scale).toBe('0.25')
  42. task.cancel()
  43. expect(disconnect).toHaveBeenCalledOnce()
  44. expect(api.cancel).toHaveBeenCalledOnce()
  45. expect(host.childElementCount).toBe(0)
  46. })