printmaker
Version:
Generate PDF documents and from JavaScript objects
173 lines (137 loc) • 6.2 kB
text/typescript
import { beforeEach, describe, expect, it, jest } from '@jest/globals';
import { embedFonts, parseFonts, selectFont } from '../src/fonts.js';
import { fakeFont } from './test-utils.js';
describe('fonts', () => {
describe('parseFonts', () => {
it('returns an empty array for missing fonts definition', () => {
const fonts = parseFonts(undefined);
expect(fonts).toEqual([]);
});
it('returns fonts array', () => {
const fontsDef = {
Test: [
{ data: mkData('Test_Sans_Normal') },
{ data: mkData('Test_Sans_Italic'), italic: true },
{ data: mkData('Test_Sans_Bold'), bold: true },
{ data: mkData('Test_Sans_BoldItalic'), italic: true, bold: true },
],
Other: [{ data: mkData('Other_Normal') }],
};
const fonts = parseFonts(fontsDef);
expect(fonts).toEqual([
{ name: 'Test', data: mkData('Test_Sans_Normal') },
{ name: 'Test', data: mkData('Test_Sans_Italic'), italic: true },
{ name: 'Test', data: mkData('Test_Sans_Bold'), bold: true },
{ name: 'Test', data: mkData('Test_Sans_BoldItalic'), italic: true, bold: true },
{ name: 'Other', data: mkData('Other_Normal') },
]);
});
it('throws on invalid type', () => {
expect(() => parseFonts(23)).toThrowError('Invalid value for "fonts":');
});
it('throws on invalid italic value', () => {
const fn = () => parseFonts({ Test: [{ data: 'data', italic: 23 }] });
expect(fn).toThrowError('Invalid value for "fonts[\'Test\'][0].italic":');
});
it('throws on invalid bold value', () => {
const fn = () => parseFonts({ Test: [{ data: 'data', bold: 23 }] });
expect(fn).toThrowError('Invalid value for "fonts[\'Test\'][0].bold":');
});
it('throws on missing data', () => {
const fn = () => parseFonts({ Test: [{ italic: true }] });
expect(fn).toThrowError('Missing value for "data"');
});
it('removes redundant false values for italic and bold', () => {
const data = mkData('data');
const fontsDef = { Test: [{ data, italic: false, bold: false }] };
const fonts = parseFonts(fontsDef);
expect(fonts).toEqual([{ name: 'Test', data }]);
});
});
describe('embedFont', () => {
it('returns an empty array for empty fonts definition', async () => {
const fonts = await embedFonts([], {} as any);
expect(fonts).toEqual([]);
});
it('embeds fonts in PDF document and returns fonts array', async () => {
const embedFont = jest.fn().mockImplementation((font) => Promise.resolve(`PDF_${font}`));
const doc = { embedFont } as any;
const fontsDef = [
{ name: 'Test', data: 'Test_Sans_Normal' },
{ name: 'Test', data: 'Test_Sans_Italic', italic: true },
{ name: 'Test', data: 'Test_Sans_Bold', bold: true },
{ name: 'Test', data: 'Test_Sans_BoldItalic', italic: true, bold: true },
{ name: 'Other', data: 'Other_Normal' },
];
const fonts = await embedFonts(fontsDef, doc);
expect(fonts).toEqual([
{ name: 'Test', pdfFont: 'PDF_Test_Sans_Normal' },
{ name: 'Test', pdfFont: 'PDF_Test_Sans_Italic', italic: true },
{ name: 'Test', pdfFont: 'PDF_Test_Sans_Bold', bold: true },
{ name: 'Test', pdfFont: 'PDF_Test_Sans_BoldItalic', italic: true, bold: true },
{ name: 'Other', pdfFont: 'PDF_Other_Normal' },
]);
});
it('throws when embedding fails', async () => {
const embedFont = (data) =>
data === 'Bad_Data' ? Promise.reject('Bad font') : Promise.resolve(data);
const doc = { embedFont } as any;
const fontsDef = [
{ name: 'Good', data: 'Good_Data' },
{ name: 'Bad', data: 'Bad_Data' },
];
const promise = embedFonts(fontsDef, doc);
await expect(promise).rejects.toThrowError('Could not embed font "Bad": Bad font');
});
});
describe('selectFont', () => {
let fonts, normalFont, italicFont, boldFont, italicBoldFont, otherFont;
beforeEach(() => {
fonts = [
fakeFont('Test'),
fakeFont('Test', { italic: true }),
fakeFont('Test', { bold: true }),
fakeFont('Test', { italic: true, bold: true }),
fakeFont('Other'),
];
[normalFont, italicFont, boldFont, italicBoldFont, otherFont] = fonts.map((f) => f.pdfFont);
});
it('selects different font variants', () => {
const fontFamily = 'Test';
expect(selectFont(fonts, { fontFamily })).toEqual(normalFont);
expect(selectFont(fonts, { fontFamily, bold: true })).toEqual(boldFont);
expect(selectFont(fonts, { fontFamily, italic: true })).toEqual(italicFont);
expect(selectFont(fonts, { fontFamily, italic: true, bold: true })).toEqual(italicBoldFont);
});
it('selects first matching font if no family specified', () => {
expect(selectFont(fonts, {})).toEqual(normalFont);
expect(selectFont(fonts, { bold: true })).toEqual(boldFont);
expect(selectFont(fonts, { italic: true })).toEqual(italicFont);
expect(selectFont(fonts, { italic: true, bold: true })).toEqual(italicBoldFont);
});
it('selects font with matching font family', () => {
expect(selectFont(fonts, { fontFamily: 'Other' })).toEqual(otherFont);
});
it('throws when no matching font can be found', () => {
const fontFamily = 'Other';
expect(() => selectFont(fonts, { fontFamily, italic: true })).toThrowError(
'No font found for "Other italic"'
);
expect(() => selectFont(fonts, { fontFamily, bold: true })).toThrowError(
'No font found for "Other bold"'
);
expect(() => selectFont(fonts, { fontFamily, italic: true, bold: true })).toThrowError(
'No font found for "Other bold italic"'
);
});
it('throws when font family can be found', () => {
const fontFamily = 'Foo';
expect(() => selectFont(fonts, { fontFamily })).toThrowError(
'No font found for "Foo normal"'
);
});
});
});
function mkData(value: string) {
return new Uint8Array(value.split('').map((c) => c.charCodeAt(0)));
}