Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,9 @@
"lint": "biome check ./src && node tools/check-color-literals.mjs && node tools/check-doc-links.mjs",
"lint:fix": "biome check --write ./src",
"format": "biome format --write .",
"test": "node --loader=./tools/svg-loader.mjs --import=./tools/__mocks__/sprite-init.mjs --experimental-test-snapshots --require ./tools/test-setup.cjs --test --test-concurrency=4 --no-warnings src/**/*.test.{js,mjs}",
"test:watch": "node --watch --loader=./tools/svg-loader.mjs --import=./tools/__mocks__/sprite-init.mjs --experimental-test-snapshots --require ./tools/test-setup.cjs --test --test-concurrency=4 --no-warnings src/**/*.test.{js,mjs}",
"test:updateSnapshots": "node --loader=./tools/svg-loader.mjs --import=./tools/__mocks__/sprite-init.mjs --experimental-test-snapshots --test-update-snapshots --require ./tools/test-setup.cjs --test --test-concurrency=4 --no-warnings src/**/*.test.{js,mjs}",
"test": "node --import=./tools/register-test-hooks.mjs --import=./tools/__mocks__/sprite-init.mjs --experimental-test-snapshots --require ./tools/test-setup.cjs --test --test-reporter=spec --test-concurrency=4 --no-warnings \"src/**/*.test.{js,mjs}\"",
"test:watch": "node --watch --import=./tools/register-test-hooks.mjs --import=./tools/__mocks__/sprite-init.mjs --experimental-test-snapshots --require ./tools/test-setup.cjs --test --test-reporter=spec --test-concurrency=4 --no-warnings \"src/**/*.test.{js,mjs}\"",
"test:updateSnapshots": "node --import=./tools/register-test-hooks.mjs --import=./tools/__mocks__/sprite-init.mjs --experimental-test-snapshots --test-update-snapshots --require ./tools/test-setup.cjs --test --test-reporter=spec --test-concurrency=4 --no-warnings \"src/**/*.test.{js,mjs}\"",
"test:ci": "npm test --coverage",
"test:dist": "node --test --no-warnings tools/dist.test.mjs",
"test:types": "tsc -p src/types/tsconfig.json",
Expand Down
16 changes: 16 additions & 0 deletions tools/register-test-hooks.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import module from 'node:module'
import { load } from './svg-loader.mjs'

/**
* Registers the test module hooks. Loaded with `--import` before any test code.
*
* `module.registerHooks()` (Node >= 22.15 / 23.5) runs the hooks in-thread and synchronously,
* so they also apply to `require()` of ES modules. The older `--loader` flag ran async hooks
* off-thread and crashed on Node 22 with "ERR_METHOD_NOT_IMPLEMENTED: The resolveSync() method
* is not implemented" as soon as a CommonJS module required an ES module.
*/
if (typeof module.registerHooks === 'function') {
module.registerHooks({ load })
} else {
module.register('./svg-loader.mjs', import.meta.url)
}
40 changes: 15 additions & 25 deletions tools/svg-loader.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,27 @@ import { readFileSync } from 'node:fs'
import { fileURLToPath } from 'node:url'

/**
* Custom loader to handle SVG imports with ?raw suffix in tests
* This loader is needed because Node.js doesn't natively support importing .svg files
* Module load hook that handles SVG imports (with or without the ?raw suffix) in tests,
* because Node.js doesn't natively support importing .svg files.
*
* The hook is synchronous so it can be used with `module.registerHooks()`, which also covers
* `require()` of ES modules. It works unchanged as an async `module.register()` hook.
*/

export async function resolve(specifier, context, nextResolve) {
// Let the default resolver handle the path resolution first
return nextResolve(specifier, context)
}

export async function load(url, context, nextLoad) {
// Check if this is an SVG file (with or without ?raw query parameter)
export function load(url, context, nextLoad) {
const urlWithoutQuery = url.split('?')[0]

if (urlWithoutQuery.endsWith('.svg')) {
let content = ''
try {
const filePath = fileURLToPath(urlWithoutQuery)
const content = readFileSync(filePath, 'utf-8')

// Return as an ES module with a default export
return {
format: 'module',
source: `export default ${JSON.stringify(content)}`,
shortCircuit: true,
}
content = readFileSync(fileURLToPath(urlWithoutQuery), 'utf-8')
} catch {
// If file doesn't exist or can't be read, return empty string
return {
format: 'module',
source: 'export default ""',
shortCircuit: true,
}
// If the file doesn't exist or can't be read, export an empty string
}

return {
format: 'module',
source: `export default ${JSON.stringify(content)}`,
shortCircuit: true,
}
}

Expand Down
Loading