刘光辉
4 小时以前 cf11e63b659afcc9792ab3e395f1b45d844431a8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { flushPromises, mount } from '@vue/test-utils';
 
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
 
import { defaultPosition, defaultWatermark } from '../model';
import PaperPreview from '../PaperPreview.vue';
 
const mocks = vi.hoisted(() => ({ preview: vi.fn() }));
vi.mock('#/api/x/dms/watermark', () => ({ getWatermarkPreview: mocks.preview }));
 
beforeEach(() => {
  vi.clearAllMocks();
  vi.stubGlobal(
    'Image',
    class {
      listeners = new Map<string, () => void>();
      get src() {
        return 'blob:preview';
      }
      set src(_: string) {
        queueMicrotask(() => this.listeners.get('load')?.());
      }
      addEventListener(event: string, listener: () => void) {
        this.listeners.set(event, listener);
      }
    },
  );
  vi.spyOn(URL, 'createObjectURL').mockReturnValue('blob:preview');
  vi.spyOn(URL, 'revokeObjectURL').mockImplementation(() => {});
  mocks.preview.mockResolvedValue(new Blob(['preview'], { type: 'image/png' }));
});
afterEach(() => {
  vi.restoreAllMocks();
  vi.unstubAllGlobals();
});
 
describe('server-rendered watermark preview', () => {
  it.each([
    ['portrait', 210, 297, 420, 594],
    ['landscape', 297, 210, 594, 420],
  ] as const)('uses the export renderer and configured font in %s', async (orientation, width, height, canvasWidth, canvasHeight) => {
    const context = { clearRect: vi.fn(), drawImage: vi.fn() };
    vi.spyOn(HTMLCanvasElement.prototype, 'getContext').mockReturnValue(context as unknown as CanvasRenderingContext2D);
    const config = {
      ...defaultWatermark(),
      contentTemplate: '用户:{/CUN}',
      fontFamily: 'Directory Font',
      horizontalAlign: 'RIGHT' as const,
      verticalAlign: 'BOTTOM' as const,
    };
    const position = defaultPosition();
    const wrapper = mount(PaperPreview, { props: { config, position, orientation } });
    await flushPromises();
    expect(mocks.preview).toHaveBeenCalledWith(
      width,
      height,
      expect.objectContaining({
        fontFamily: 'Directory Font',
        horizontalAlign: 'RIGHT',
        verticalAlign: 'BOTTOM',
        positions: [position],
      }),
      '用户:张三',
    );
    expect(context.drawImage).toHaveBeenCalledWith(expect.anything(), 0, 0, canvasWidth, canvasHeight);
    expect(URL.revokeObjectURL).toHaveBeenCalledWith('blob:preview');
    expect(wrapper.find('.render-error').exists()).toBe(false);
    wrapper.unmount();
  });
 
  it('displays font errors from the renderer instead of substituting a browser font', async () => {
    const context = { clearRect: vi.fn(), drawImage: vi.fn() };
    vi.spyOn(HTMLCanvasElement.prototype, 'getContext').mockReturnValue(context as unknown as CanvasRenderingContext2D);
    mocks.preview.mockResolvedValue(new Blob([JSON.stringify({ msg: '配置字体目录中不存在字体:SimHei' })], { type: 'application/json' }));
    const wrapper = mount(PaperPreview, { props: { config: defaultWatermark(), position: defaultPosition(), orientation: 'portrait' } });
    await flushPromises();
    expect(wrapper.get('.render-error').text()).toContain('配置字体目录中不存在字体');
    expect(context.drawImage).not.toHaveBeenCalled();
    wrapper.unmount();
  });
 
  it('does not draw a request that finishes after the preview is closed', async () => {
    const context = { clearRect: vi.fn(), drawImage: vi.fn() };
    vi.spyOn(HTMLCanvasElement.prototype, 'getContext').mockReturnValue(context as unknown as CanvasRenderingContext2D);
    let finish!: (blob: Blob) => void;
    mocks.preview.mockReturnValue(
      new Promise<Blob>((resolve) => {
        finish = resolve;
      }),
    );
    const wrapper = mount(PaperPreview, { props: { config: defaultWatermark(), position: defaultPosition(), orientation: 'portrait' } });
    wrapper.unmount();
    finish(new Blob(['preview'], { type: 'image/png' }));
    await flushPromises();
    expect(context.drawImage).not.toHaveBeenCalled();
    expect(URL.createObjectURL).not.toHaveBeenCalled();
  });
});