diff --git a/src/utils/pdf/__tests__/create-document.test.js b/src/utils/pdf/__tests__/create-document.test.js index f2c656d5..8a09b984 100644 --- a/src/utils/pdf/__tests__/create-document.test.js +++ b/src/utils/pdf/__tests__/create-document.test.js @@ -52,4 +52,16 @@ describe('createDocument', () => { ).rejects.toThrow('boom'); expect(onError).toHaveBeenCalled(); }); + + it('calls onError and rejects when the browser download fails', async () => { + const { pdfMake } = createFakePdfMake(); + const onError = jest.fn(); + global.URL.createObjectURL = jest.fn(() => { + throw new Error('no blob url'); + }); + jest.spyOn(console, 'error').mockImplementation(() => {}); + const api = await createDocument({ pdfMake, template: () => ({ content: [] }), data: {}, onError }); + await expect(api.download('receipt.pdf')).rejects.toThrow('no blob url'); + expect(onError).toHaveBeenCalledWith(expect.objectContaining({ message: 'no blob url' })); + }); }); diff --git a/src/utils/pdf/__tests__/download-blob.test.js b/src/utils/pdf/__tests__/download-blob.test.js index 313c4212..1fda36c1 100644 --- a/src/utils/pdf/__tests__/download-blob.test.js +++ b/src/utils/pdf/__tests__/download-blob.test.js @@ -39,4 +39,12 @@ describe('downloadBlob', () => { downloadBlob(new Blob(['%PDF']), 'file.pdf'); expect(document.body.contains(anchor)).toBe(true); }); + + it('rethrows when the browser cannot start the download', () => { + global.URL.createObjectURL = jest.fn(() => { + throw new Error('no blob url'); + }); + jest.spyOn(console, 'error').mockImplementation(() => {}); + expect(() => downloadBlob(new Blob(['%PDF']), 'file.pdf')).toThrow('no blob url'); + }); }); diff --git a/src/utils/pdf/__tests__/resolve-font.test.js b/src/utils/pdf/__tests__/resolve-font.test.js index 52296213..41354b1c 100644 --- a/src/utils/pdf/__tests__/resolve-font.test.js +++ b/src/utils/pdf/__tests__/resolve-font.test.js @@ -25,6 +25,14 @@ describe('resolveFont', () => { expect(pdfMake.addFontContainer).toHaveBeenCalledWith({ vfs: font.vfs, fonts: font.fonts }); }); + it('falls back to Helvetica when a pre-baked container does not define its family', async () => { + jest.spyOn(console, 'warn').mockImplementation(() => {}); + const pdfMake = fakePdfMake(); + const font = { family: 'Brand', vfs: { 'BrandSans-normal.ttf': 'QUFB' }, fonts: { BrandSans: { normal: 'BrandSans-normal.ttf' } } }; + await expect(resolveFont(pdfMake, font)).resolves.toBe('Helvetica'); + expect(pdfMake.addFontContainer).not.toHaveBeenCalled(); + }); + it('fetches + base64s a URL font and registers a container', async () => { global.fetch = jest.fn(() => Promise.resolve({ ok: true, arrayBuffer: () => Promise.resolve(new Uint8Array([65, 66, 67]).buffer) })); const pdfMake = fakePdfMake(); diff --git a/src/utils/pdf/download-blob.js b/src/utils/pdf/download-blob.js index 91fb4086..09a44d0d 100644 --- a/src/utils/pdf/download-blob.js +++ b/src/utils/pdf/download-blob.js @@ -30,6 +30,7 @@ export const downloadBlob = (blob, filename) => { } catch (err) { // eslint-disable-next-line no-console console.error('[pdf] download failed', err); + throw err; } }; diff --git a/src/utils/pdf/resolve-font.js b/src/utils/pdf/resolve-font.js index df72be72..4390a1b3 100644 --- a/src/utils/pdf/resolve-font.js +++ b/src/utils/pdf/resolve-font.js @@ -57,6 +57,11 @@ export const resolveFont = async (pdfMake, font) => { // Imported / pre-baked container — no fetch. if (font.family && font.vfs && font.fonts) { + if (!font.fonts[font.family]) { + // eslint-disable-next-line no-console + console.warn('[pdf] font container lacks family, using Helvetica:', font.family); + return HELVETICA; + } pdfMake.addFontContainer({ vfs: font.vfs, fonts: font.fonts }); return font.family; }