Skip to content

Commit d578ab3

Browse files
committed
chore: fix tests
1 parent e5d6457 commit d578ab3

4 files changed

Lines changed: 38 additions & 48 deletions

File tree

lib/parser.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,17 @@ const config = {
7575
*
7676
* @param {string} data
7777
* @param {string=} from
78-
* @param {number=} maxEntityCount Maximum number of XML entities the parser may
79-
* expand, forwarded to sax as its XXE protection limit. When omitted, sax
80-
* falls back to its own default (512 in sax >= 1.6.0).
78+
* @param {number=} maxEntityCount Maximum number of XML entities the parser is
79+
* allowed to expand before throwing. When omitted, the underlying parser
80+
* falls back to its own default (512 in recent versions).
8181
* @returns {import('./types.js').XastRoot}
8282
*/
8383
export const parseSvg = (data, from, maxEntityCount) => {
84+
// Build a fresh options object per call: sax mutates the options it receives
85+
// (e.g. it stamps a default `maxEntityCount`), so the shared `config` must
86+
// not be passed directly.
8487
const parserConfig =
85-
maxEntityCount == null ? config : { ...config, maxEntityCount };
88+
maxEntityCount == null ? { ...config } : { ...config, maxEntityCount };
8689
const sax = SAX.parser(parserConfig.strict, parserConfig);
8790
/** @type {import('./types.js').XastRoot} */
8891
const root = { type: 'root', children: [] };

lib/parser.test.js

Lines changed: 28 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { jest } from '@jest/globals';
2+
import SAX from 'sax';
23
import { parseSvg } from './parser.js';
34
import { stringifySvg } from './stringifier.js';
45

@@ -33,53 +34,39 @@ test('a text preserved', () => {
3334
});
3435

3536
describe('maxEntityCount', () => {
36-
/**
37-
* Re-import parseSvg with a mocked sax that records the options it receives.
38-
*
39-
* @returns {Promise<{ parseSvg: typeof parseSvg, getOpt: () => any }>}
40-
*/
41-
const importWithSaxSpy = async () => {
42-
/** @type {any} */
43-
let receivedOpt;
44-
jest.resetModules();
45-
jest.unstable_mockModule('sax', () => ({
46-
default: {
47-
/**
48-
* @param {boolean} _strict
49-
* @param {any} opt
50-
*/
51-
parser: (_strict, opt) => {
52-
receivedOpt = opt;
53-
return {
54-
ENTITIES: {},
55-
write() {
56-
return this;
57-
},
58-
close() {
59-
return this;
60-
},
61-
};
37+
// sax mutates the options object it receives (it stamps a default
38+
// `maxEntityCount`), so snapshot the options at call time, before sax runs.
39+
/** @type {any} */
40+
let receivedOpt;
41+
42+
beforeEach(() => {
43+
jest.spyOn(SAX, 'parser').mockImplementation((_strict, opt) => {
44+
receivedOpt = { ...opt };
45+
// Minimal stub: parseSvg only assigns handlers then calls write().close().
46+
return /** @type {any} */ ({
47+
ENTITIES: {},
48+
write() {
49+
return this;
50+
},
51+
close() {
52+
return this;
6253
},
63-
},
64-
}));
65-
const mod = await import('./parser.js');
66-
return { parseSvg: mod.parseSvg, getOpt: () => receivedOpt };
67-
};
54+
});
55+
});
56+
});
6857

6958
afterEach(() => {
70-
jest.dontMock('sax');
71-
jest.resetModules();
59+
jest.restoreAllMocks();
60+
receivedOpt = undefined;
7261
});
7362

74-
test('forwards a provided maxEntityCount to the sax parser', async () => {
75-
const { parseSvg: parse, getOpt } = await importWithSaxSpy();
76-
parse('<svg xmlns="http://www.w3.org/2000/svg"/>', undefined, 1234);
77-
expect(getOpt().maxEntityCount).toBe(1234);
63+
test('forwards a provided maxEntityCount to the parser options', () => {
64+
parseSvg('<svg xmlns="http://www.w3.org/2000/svg"/>', undefined, 1234);
65+
expect(receivedOpt.maxEntityCount).toBe(1234);
7866
});
7967

80-
test('does not pass maxEntityCount when it is omitted', async () => {
81-
const { parseSvg: parse, getOpt } = await importWithSaxSpy();
82-
parse('<svg xmlns="http://www.w3.org/2000/svg"/>');
83-
expect(getOpt().maxEntityCount).toBeUndefined();
68+
test('does not set maxEntityCount when it is omitted', () => {
69+
parseSvg('<svg xmlns="http://www.w3.org/2000/svg"/>');
70+
expect(receivedOpt.maxEntityCount).toBeUndefined();
8471
});
8572
});

lib/svgo/coa.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export default function makeProgram(program) {
4949
)
5050
.option(
5151
'--max-entity-count <INTEGER>',
52-
'Maximum number of XML entities the parser may expand (sax XXE protection limit)',
52+
'Maximum number of XML entities the parser may expand before throwing',
5353
)
5454
.option(
5555
'--config <CONFIG>',

lib/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -345,8 +345,8 @@ export type Config = {
345345
floatPrecision?: number;
346346
/**
347347
* Maximum number of XML entities the parser is allowed to expand before
348-
* throwing, forwarded to sax as its XXE protection limit. Defaults to sax's
349-
* own default (512 in sax >= 1.6.0) when omitted.
348+
* throwing. When omitted, the underlying parser falls back to its own
349+
* default (512 in recent versions).
350350
*/
351351
maxEntityCount?: number;
352352
/**

0 commit comments

Comments
 (0)