Skip to content

Commit

Permalink
📦 Upgrade to vitest 3, adjust tests
Browse files Browse the repository at this point in the history
Vitest 3 checks more properties when comparing errors via `toEqual` or
`toThrow`. This commit adjusts all tests to use `toThrow(newError(...))`
as this checks the error type, the _complete_ error message, and
optionally also the cause.
  • Loading branch information
ralfstx committed Jan 19, 2025
1 parent 2d4ad75 commit 012dffe
Show file tree
Hide file tree
Showing 19 changed files with 434 additions and 796 deletions.
793 changes: 189 additions & 604 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
},
"devDependencies": {
"@types/node": "^22.10.7",
"@vitest/coverage-v8": "^2.1.8",
"@vitest/coverage-v8": "^3.0.2",
"esbuild": "^0.24.2",
"eslint": "^9.18.0",
"eslint-config-prettier": "^10.0.1",
Expand All @@ -45,6 +45,6 @@
"prettier": "^3.4.2",
"typescript": "^5.7.3",
"typescript-eslint": "^8.20.0",
"vitest": "^2.1.8"
"vitest": "^3.0.2"
}
}
5 changes: 2 additions & 3 deletions src/api/PdfMaker.test.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
import { before } from 'node:test';

import { describe, expect, it, vi } from 'vitest';
import { beforeEach, describe, expect, it, vi } from 'vitest';

import { image, text } from './layout.ts';
import { PdfMaker } from './PdfMaker.ts';

describe('makePdf', () => {
let pdfMaker: PdfMaker;

before(async () => {
beforeEach(async () => {
pdfMaker = new PdfMaker();
pdfMaker.setResourceRoot(join(__dirname, '../test/resources'));
const fontData = await readFile(
Expand Down
14 changes: 8 additions & 6 deletions src/base64.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,21 @@ describe('decodeBase64', () => {
expect(decodeBase64(base64(array3))).toEqual(array3);
});

it('fails if string is not a multiple of 4', () => {
it('throws if string is not a multiple of 4', () => {
expect(() => decodeBase64('A')).toThrow(
'Invalid base64 string: length must be a multiple of 4',
new Error('Invalid base64 string: length must be a multiple of 4'),
);
expect(() => decodeBase64('AA')).toThrow(
'Invalid base64 string: length must be a multiple of 4',
new Error('Invalid base64 string: length must be a multiple of 4'),
);
expect(() => decodeBase64('AAA')).toThrow(
'Invalid base64 string: length must be a multiple of 4',
new Error('Invalid base64 string: length must be a multiple of 4'),
);
});

it('fails if string contains invalid characters', () => {
expect(() => decodeBase64('ABØ=')).toThrow("Invalid Base64 character 'Ø' at position 2");
it('throws if string contains invalid characters', () => {
expect(() => decodeBase64('ABØ=')).toThrow(
new Error("Invalid Base64 character 'Ø' at position 2"),
);
});
});
12 changes: 6 additions & 6 deletions src/binary-data.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@ describe('parseBinaryData', () => {
});

it('throws for arrays', () => {
expect(() => parseBinaryData([1, 2, 3])).toThrowError(
'Expected Uint8Array, ArrayBuffer, or base64-encoded string, got: [1, 2, 3]',
expect(() => parseBinaryData([1, 2, 3])).toThrow(
new TypeError('Expected Uint8Array, ArrayBuffer, or base64-encoded string, got: [1, 2, 3]'),
);
});

it('throws for other types', () => {
expect(() => parseBinaryData(23)).toThrowError(
'Expected Uint8Array, ArrayBuffer, or base64-encoded string, got: 23',
expect(() => parseBinaryData(23)).toThrow(
new TypeError('Expected Uint8Array, ArrayBuffer, or base64-encoded string, got: 23'),
);
expect(() => parseBinaryData(null)).toThrowError(
'Expected Uint8Array, ArrayBuffer, or base64-encoded string, got: null',
expect(() => parseBinaryData(null)).toThrow(
new TypeError('Expected Uint8Array, ArrayBuffer, or base64-encoded string, got: null'),
);
});
});
56 changes: 36 additions & 20 deletions src/box.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,22 +74,26 @@ describe('parseEdges', () => {
});

it('throws on invalid lengths', () => {
expect(() => parseEdges('')).toThrowError("Expected number or length string, got: ''");
expect(() => parseEdges(Infinity)).toThrowError(
'Expected number or length string, got: Infinity',
expect(() => parseEdges('')).toThrow(
new TypeError("Expected number or length string, got: ''"),
);
expect(() => parseEdges(Infinity)).toThrow(
new TypeError('Expected number or length string, got: Infinity'),
);
});

it('throws on invalid types', () => {
expect(() => parseEdges('')).toThrowError("Expected number or length string, got: ''");
expect(() => parseEdges(null)).toThrowError(
'Expected number, length string, or object, got: null',
expect(() => parseEdges('')).toThrow(
new TypeError("Expected number or length string, got: ''"),
);
expect(() => parseEdges(null)).toThrow(
new TypeError('Expected number, length string, or object, got: null'),
);
expect(() => parseEdges(true)).toThrowError(
'Expected number, length string, or object, got: true',
expect(() => parseEdges(true)).toThrow(
new TypeError('Expected number, length string, or object, got: true'),
);
expect(() => parseEdges(() => 23)).toThrowError(
'Expected number, length string, or object, got: anonymous function',
expect(() => parseEdges(() => 23)).toThrow(
new TypeError('Expected number, length string, or object, got: anonymous function'),
);
});
});
Expand Down Expand Up @@ -125,23 +129,35 @@ describe('parseLength', () => {
});

it('throws on invalid strings', () => {
expect(() => parseLength('')).toThrowError("Expected number or length string, got: ''");
expect(() => parseLength('1')).toThrowError("Expected number or length string, got: '1'");
expect(() => parseLength('1xy')).toThrowError("Expected number or length string, got: '1xy'");
expect(() => parseLength('')).toThrow(
new TypeError("Expected number or length string, got: ''"),
);
expect(() => parseLength('1')).toThrow(
new TypeError("Expected number or length string, got: '1'"),
);
expect(() => parseLength('1xy')).toThrow(
new TypeError("Expected number or length string, got: '1xy'"),
);
});

it('throws on invalid numbers', () => {
expect(() => parseLength(Infinity)).toThrowError(
'Expected number or length string, got: Infinity',
expect(() => parseLength(Infinity)).toThrow(
new TypeError('Expected number or length string, got: Infinity'),
);
expect(() => parseLength(NaN)).toThrow(
new TypeError('Expected number or length string, got: NaN'),
);
expect(() => parseLength(NaN)).toThrowError('Expected number or length string, got: NaN');
});

it('throws on invalid types', () => {
expect(() => parseLength(null)).toThrowError('Expected number or length string, got: null');
expect(() => parseLength(true)).toThrowError('Expected number or length string, got: true');
expect(() => parseLength(() => 23)).toThrowError(
'Expected number or length string, got: anonymous function',
expect(() => parseLength(null)).toThrow(
new TypeError('Expected number or length string, got: null'),
);
expect(() => parseLength(true)).toThrow(
new TypeError('Expected number or length string, got: true'),
);
expect(() => parseLength(() => 23)).toThrow(
new TypeError('Expected number or length string, got: anonymous function'),
);
});
});
12 changes: 6 additions & 6 deletions src/data-loader.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ describe('createDataLoader', () => {
const loader = createDataLoader();

it('throws for invalid URLs', async () => {
await expect(loader('')).rejects.toThrow("Invalid URL: ''");
await expect(loader('http://')).rejects.toThrow("Invalid URL: 'http://'");
await expect(loader('')).rejects.toThrow(new Error("Invalid URL: ''"));
await expect(loader('http://')).rejects.toThrow(new Error("Invalid URL: 'http://'"));
});

it('throws for unsupported URL scheme', async () => {
await expect(loader('foo:bar')).rejects.toThrow("URL not supported: 'foo:bar'");
await expect(loader('foo:bar')).rejects.toThrow(new Error("URL not supported: 'foo:bar'"));
});

describe('http:', () => {
Expand Down Expand Up @@ -49,7 +49,7 @@ describe('createDataLoader', () => {

it('throws if 404 received', async () => {
await expect(loader('https://example.com/not-there')).rejects.toThrow(
'Received 404 Not Found',
new Error('Received 404 Not Found'),
);
});
});
Expand All @@ -62,12 +62,12 @@ describe('createDataLoader', () => {
});

it('throws for invalid data: URLs', async () => {
await expect(loader('data:foo')).rejects.toThrow("Invalid data URL: 'data:foo'");
await expect(loader('data:foo')).rejects.toThrow(new Error("Invalid data URL: 'data:foo'"));
});

it('throws for unsupported encoding in data: URLs', async () => {
await expect(loader('data:foo,bar')).rejects.toThrow(
"Unsupported encoding in data URL: 'data:foo,bar'",
new Error("Unsupported encoding in data URL: 'data:foo,bar'"),
);
});
});
Expand Down
12 changes: 4 additions & 8 deletions src/font-store.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,17 +76,15 @@ describe('FontStore', () => {
const store = new FontStore();

await expect(store.selectFont({ fontFamily: 'Foo' })).rejects.toThrow(
expect.objectContaining({
message: "Could not load font for 'Foo', style=normal, weight=normal",
new Error("Could not load font for 'Foo', style=normal, weight=normal", {
cause: new Error('No fonts defined'),
}),
);
});

it('rejects for unknown font name', async () => {
await expect(store.selectFont({ fontFamily: 'Unknown' })).rejects.toThrow(
expect.objectContaining({
message: "Could not load font for 'Unknown', style=normal, weight=normal",
new Error("Could not load font for 'Unknown', style=normal, weight=normal", {
cause: new Error(
"No matching font found for family 'Unknown'. Registered families are: 'Test', 'Other'.",
),
Expand All @@ -98,8 +96,7 @@ describe('FontStore', () => {
store = new FontStore([normalFont, boldFont]);

await expect(store.selectFont({ fontFamily: 'Test', fontStyle: 'italic' })).rejects.toThrow(
expect.objectContaining({
message: "Could not load font for 'Test', style=italic, weight=normal",
new Error("Could not load font for 'Test', style=italic, weight=normal", {
cause: new Error("No matching font found for 'Test', style=italic"),
}),
);
Expand Down Expand Up @@ -170,8 +167,7 @@ describe('FontStore', () => {

it('rejects if font could not be loaded', async () => {
await expect(store.selectFont({ fontFamily: 'foo' })).rejects.toThrow(
expect.objectContaining({
message: "Could not load font for 'foo', style=normal, weight=normal",
new Error("Could not load font for 'foo', style=normal, weight=normal", {
cause: new Error(
"No matching font found for family 'foo'. Registered families are: 'Test', 'Other'.",
),
Expand Down
20 changes: 11 additions & 9 deletions src/fonts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,31 @@ describe('readFonts', () => {
});

it('throws on missing input', () => {
expect(() => readFonts(undefined)).toThrowError('Expected object, got: undefined');
expect(() => readFonts(undefined)).toThrow(new TypeError('Expected object, got: undefined'));
});

it('throws on invalid type', () => {
expect(() => readFonts(23)).toThrowError('Expected object, got: 23');
expect(() => readFonts(23)).toThrow(new TypeError('Expected object, got: 23'));
});

it('throws on invalid italic value', () => {
const fn = () => readFonts({ Test: [{ data: 'data', italic: 23 }] });

expect(fn).toThrowError('Invalid value for "Test/0/italic":');
expect(fn).toThrow(
new TypeError('Invalid value for "Test/0/italic": Expected boolean, got: 23'),
);
});

it('throws on invalid bold value', () => {
const fn = () => readFonts({ Test: [{ data: 'data', bold: 23 }] });

expect(fn).toThrowError('Invalid value for "Test/0/bold":');
expect(fn).toThrow(new TypeError('Invalid value for "Test/0/bold": Expected boolean, got: 23'));
});

it('throws on missing data', () => {
const fn = () => readFonts({ Test: [{ italic: true }] });

expect(fn).toThrowError('Missing value for "data"');
expect(fn).toThrow(new TypeError('Invalid value for "Test/0": Missing value for "data"'));
});
});

Expand All @@ -63,13 +65,13 @@ describe('weightToNumber', () => {
});

it('throws for invalid types', () => {
expect(() => weightToNumber('foo' as any)).toThrowError("Invalid font weight: 'foo'");
expect(() => weightToNumber(null as any)).toThrowError('Invalid font weight: null');
expect(() => weightToNumber('foo' as any)).toThrow(new Error("Invalid font weight: 'foo'"));
expect(() => weightToNumber(null as any)).toThrow(new Error('Invalid font weight: null'));
});

it('throws for invalid numbers', () => {
expect(() => weightToNumber(NaN)).toThrowError('Invalid font weight: NaN');
expect(() => weightToNumber(0.1)).toThrowError('Invalid font weight: 0.1');
expect(() => weightToNumber(NaN)).toThrow(new Error('Invalid font weight: NaN'));
expect(() => weightToNumber(0.1)).toThrow(new Error('Invalid font weight: 0.1'));
});
});

Expand Down
2 changes: 1 addition & 1 deletion src/image-store.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ describe('ImageStore', () => {
});

it('rejects if image could not be loaded', async () => {
await expect(store.selectImage('foo')).rejects.toThrow("Could not load image 'foo'");
await expect(store.selectImage('foo')).rejects.toThrow(new Error("Could not load image 'foo'"));
});

it('loads registered images (deprecated)', async () => {
Expand Down
10 changes: 7 additions & 3 deletions src/images.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,23 @@ describe('readImages', () => {
it('throws on invalid type', () => {
const fn = () => readImages(23);

expect(fn).toThrowError('Expected object, got: 23');
expect(fn).toThrow(new TypeError('Expected object, got: 23'));
});

it('throws on invalid image definition', () => {
const fn = () => readImages({ foo: 23 });

expect(fn).toThrowError('Invalid value for "foo": Expected object, got: 23');
expect(fn).toThrow(new TypeError('Invalid value for "foo": Expected object, got: 23'));
});

it('throws on invalid image data', () => {
const fn = () => readImages({ foo: { data: 23 } });

expect(fn).toThrowError('Invalid value for "foo/data":');
expect(fn).toThrow(
new TypeError(
'Invalid value for "foo/data": Expected Uint8Array, ArrayBuffer, or base64-encoded string, got: 23',
),
);
});
});

Expand Down
6 changes: 3 additions & 3 deletions src/images/png.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,21 @@ describe('readPngInfo', () => {
const data = new Uint8Array(40);
data.set([0x49, 0x48, 0x44, 0x52], 12); // IHDR chunk

expect(() => readPngInfo(data)).toThrow('Invalid PNG data');
expect(() => readPngInfo(data)).toThrow(new Error('Invalid PNG data'));
});

it('throws if IHDR chunk is missing', () => {
const data = new Uint8Array(40);
data.set([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]); // PNG signature

expect(() => readPngInfo(data)).toThrow('Invalid PNG data');
expect(() => readPngInfo(data)).toThrow(new Error('Invalid PNG data'));
});

it('throws if too short', () => {
const data = new Uint8Array(32);
data.set([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]); // PNG signature
data.set([0x49, 0x48, 0x44, 0x52], 12); // IHDR chunk

expect(() => readPngInfo(data)).toThrow('Invalid PNG data');
expect(() => readPngInfo(data)).toThrow(new Error('Invalid PNG data'));
});
});
Loading

0 comments on commit 012dffe

Please sign in to comment.