Files
dashboard/utils/__tests__/pdfExport.test.ts
T

91 lines
2.9 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest';
import { choosePdfSliceHeight, pdfBlockBreakOffsets } from '../pdfExport.ts';
const mocks = vi.hoisted(() => ({
addImage: vi.fn(),
save: vi.fn(),
jsPDF: vi.fn(),
html2canvas: vi.fn(),
}));
vi.mock('jspdf', () => ({
jsPDF: mocks.jsPDF,
}));
vi.mock('html2canvas', () => ({
default: mocks.html2canvas,
}));
describe('exportCardToPdf compression', () => {
beforeEach(() => {
mocks.addImage.mockReset();
mocks.save.mockReset();
mocks.jsPDF.mockReset();
mocks.html2canvas.mockReset();
mocks.jsPDF.mockImplementation(function JsPDF() {
return {
internal: { pageSize: { getWidth: () => 210, getHeight: () => 297 } },
addPage: vi.fn(),
addImage: mocks.addImage,
save: mocks.save,
};
});
mocks.html2canvas.mockImplementation(async () => {
const canvas = document.createElement('canvas');
canvas.width = 800;
canvas.height = 400;
return canvas;
});
});
it('embeds JPEG pages in a compressed jsPDF document', async () => {
vi.spyOn(HTMLCanvasElement.prototype, 'getContext').mockReturnValue({
fillStyle: '',
fillRect: vi.fn(),
drawImage: vi.fn(),
} as unknown as CanvasRenderingContext2D);
const toDataURL = vi
.spyOn(HTMLCanvasElement.prototype, 'toDataURL')
.mockReturnValue('data:image/jpeg;base64,xx');
const { exportCardToPdf } = await import('../pdfExport.ts');
await exportCardToPdf(document.createElement('div'), 'Laporan.pdf');
expect(mocks.jsPDF).toHaveBeenCalledWith(expect.objectContaining({ compress: true }));
expect(toDataURL).toHaveBeenCalledWith('image/jpeg', expect.any(Number));
const quality = toDataURL.mock.calls.find((call) => call[0] === 'image/jpeg')?.[1] as number;
expect(quality).toBeGreaterThan(0);
expect(quality).toBeLessThan(1);
expect(mocks.addImage).toHaveBeenCalledWith(
expect.any(String),
'JPEG',
expect.any(Number),
expect.any(Number),
expect.any(Number),
expect.any(Number)
);
expect(mocks.save).toHaveBeenCalledWith('Laporan.pdf');
toDataURL.mockRestore();
vi.restoreAllMocks();
});
});
describe('pdf page breaks', () => {
it('does not defer an oversized table past the header', () => {
const usableHeight = 1200;
const breaks = pdfBlockBreakOffsets([{ top: 80, bottom: 5000 }], usableHeight);
expect(breaks).not.toContain(80);
expect(breaks).toContain(5000);
expect(choosePdfSliceHeight(0, 5000, usableHeight, breaks)).toBe(usableHeight);
});
it('keeps a small chart whole by breaking before it when it no longer fits', () => {
const usableHeight = 400;
const breaks = pdfBlockBreakOffsets([{ top: 350, bottom: 500 }], usableHeight);
expect(breaks).toEqual(expect.arrayContaining([350, 500]));
expect(choosePdfSliceHeight(0, 900, usableHeight, breaks)).toBe(350);
});
});