From 3feb1249bbbb8e4dd6bf6e9a8c8b4c7fd1ace7ba Mon Sep 17 00:00:00 2001 From: Amy Chisholm Date: Thu, 6 Nov 2025 15:43:07 -0800 Subject: [PATCH 1/2] Conditional export tests --- .../lib/node_modules/pkg-3/lib/foo.cjs | 8 ++ .../lib/node_modules/pkg-3/lib/foo.js | 8 ++ .../lib/node_modules/pkg-3/package.json | 14 ++ test/hook.test.mjs | 130 ++++++++++++++---- 4 files changed, 132 insertions(+), 28 deletions(-) create mode 100644 test/example-deps/lib/node_modules/pkg-3/lib/foo.cjs create mode 100644 test/example-deps/lib/node_modules/pkg-3/lib/foo.js create mode 100644 test/example-deps/lib/node_modules/pkg-3/package.json diff --git a/test/example-deps/lib/node_modules/pkg-3/lib/foo.cjs b/test/example-deps/lib/node_modules/pkg-3/lib/foo.cjs new file mode 100644 index 0000000..32dce8e --- /dev/null +++ b/test/example-deps/lib/node_modules/pkg-3/lib/foo.cjs @@ -0,0 +1,8 @@ +class Foo { + constructor() {} + bar() { + return 'baz!' + } +} + +module.exports = Foo \ No newline at end of file diff --git a/test/example-deps/lib/node_modules/pkg-3/lib/foo.js b/test/example-deps/lib/node_modules/pkg-3/lib/foo.js new file mode 100644 index 0000000..fd7338a --- /dev/null +++ b/test/example-deps/lib/node_modules/pkg-3/lib/foo.js @@ -0,0 +1,8 @@ +class Foo { + constructor() {} + bar() { + return 'baz!' + } +} + +export default Foo \ No newline at end of file diff --git a/test/example-deps/lib/node_modules/pkg-3/package.json b/test/example-deps/lib/node_modules/pkg-3/package.json new file mode 100644 index 0000000..c11d3e5 --- /dev/null +++ b/test/example-deps/lib/node_modules/pkg-3/package.json @@ -0,0 +1,14 @@ +{ + "name": "custom-pkg-3-name", + "version": "1.0.0", + "exports": { + "./foo": { + "require": { + "default": "./lib/foo.cjs" + }, + "import": { + "default": "./lib/foo.js" + } + } + } +} \ No newline at end of file diff --git a/test/hook.test.mjs b/test/hook.test.mjs index c0a42fc..4a4e71e 100644 --- a/test/hook.test.mjs +++ b/test/hook.test.mjs @@ -9,25 +9,25 @@ test.beforeEach(async (t) => { const esmLoaderRewriter = await import('../hook.mjs') esmLoaderRewriter.initialize({ instrumentations: [ - { - channelName: 'unitTestEsm', - module: { name: 'esm-pkg', versionRange: '>=1', filePath: 'foo.js' }, - functionQuery: { - className: 'Foo', - methodName: 'doStuff', - kind: 'Async' - } - }, - { - channelName: 'unitTestCjs', - module: { name: 'pkg-1', versionRange: '>=1', filePath: 'foo.js' }, - functionQuery: { - className: 'Foo', - methodName: 'doStuff', - kind: 'Async' - } + { + channelName: 'unitTestEsm', + module: { name: 'esm-pkg', versionRange: '>=1', filePath: 'foo.js' }, + functionQuery: { + className: 'Foo', + methodName: 'doStuff', + kind: 'Async' } - ] + }, + { + channelName: 'unitTestCjs', + module: { name: 'pkg-1', versionRange: '>=1', filePath: 'foo.js' }, + functionQuery: { + className: 'Foo', + methodName: 'doStuff', + kind: 'Async' + } + } + ] }) const snap = Snap(`${import.meta.url}/${t.name}`) @@ -61,7 +61,7 @@ test('should rewrite code if it matches a subscriber and esm module', async (t) }) test('should not rewrite code if it does not match a subscriber and a esm module', async (t) => { - const { esmLoaderRewriter, snap } = t.ctx + const { esmLoaderRewriter, snap } = t.ctx const esmPath = path.join(import.meta.dirname, './example-deps/lib/node_modules/esm-pkg-2/index.js') async function resolveFn() { return { url: `file://${esmPath}` } @@ -152,16 +152,16 @@ test('should not rewrite code if a function query does not exist in file', async const { esmLoaderRewriter, snap } = t.ctx esmLoaderRewriter.initialize({ instrumentations: [ - { - channelName: 'unitTestEsm', - module: { name: 'esm-pkg', versionRange: '>=1', filePath: 'foo.js' }, - functionQuery: { - className: 'Foo', - methodName: 'nonExistentMethod', - kind: 'Async' - } + { + channelName: 'unitTestEsm', + module: { name: 'esm-pkg', versionRange: '>=1', filePath: 'foo.js' }, + functionQuery: { + className: 'Foo', + methodName: 'nonExistentMethod', + kind: 'Async' } - ] + } + ] }) const esmPath = path.join(import.meta.dirname, './example-deps/lib/node_modules/esm-pkg/foo.js') async function resolveFn() { @@ -203,3 +203,77 @@ test('should default initialization to not crash if not defined', async (t) => { const snapshot = await snap(result.source) assert.deepEqual(result.source, snapshot) }) + +test('should rewrite code with conditional exports, cjs', async (t) => { + const { esmLoaderRewriter, snap } = t.ctx + // Re-initialize with pkg-3 instrumentation + esmLoaderRewriter.initialize({ + instrumentations: [ + { + channelName: 'unitTestConditional', + module: { name: 'pkg-3', versionRange: '>=1', filePath: 'lib/foo.cjs' }, + functionQuery: { + className: 'Foo', + methodName: 'bar', + kind: 'Sync' + } + } + ] + }) + + const cjsPath = path.join(import.meta.dirname, './example-deps/lib/node_modules/pkg-3/lib/foo.cjs') + async function resolveFn() { + return { url: `file://${cjsPath}` } + } + async function nextLoad(url, context) { + const data = readFileSync(cjsPath, 'utf8') + return { + format: 'commonjs', + source: data + } + } + + const url = await esmLoaderRewriter.resolve('pkg-3/foo', {}, resolveFn) + const result = await esmLoaderRewriter.load(url.url, {}, nextLoad) + assert.equal(result.format, 'commonjs') + assert.equal(result.shortCircuit, true) + const snapshot = await snap(result.source) + assert.deepEqual(result.source, snapshot) +}) + +test('should rewrite code with conditional exports, esm', async (t) => { + const { esmLoaderRewriter, snap } = t.ctx + // Re-initialize with pkg-3 instrumentation + esmLoaderRewriter.initialize({ + instrumentations: [ + { + channelName: 'unitTestConditional', + module: { name: 'pkg-3', versionRange: '>=1', filePath: 'lib/foo.js' }, + functionQuery: { + className: 'Foo', + methodName: 'bar', + kind: 'Sync' + } + } + ] + }) + + const esmPath = path.join(import.meta.dirname, './example-deps/lib/node_modules/pkg-3/lib/foo.js') + async function resolveFn() { + return { url: `file://${esmPath}` } + } + async function nextLoad(url, context) { + const data = readFileSync(esmPath, 'utf8') + return { + format: 'module', + source: data + } + } + + const url = await esmLoaderRewriter.resolve('pkg-3/foo', {}, resolveFn) + const result = await esmLoaderRewriter.load(url.url, {}, nextLoad) + assert.equal(result.format, 'module') + assert.equal(result.shortCircuit, true) + const snapshot = await snap(result.source) + assert.deepEqual(result.source, snapshot) +}) \ No newline at end of file From a3fe2ba257a8d638055b765f419a03de5baae921 Mon Sep 17 00:00:00 2001 From: Amy Chisholm Date: Mon, 10 Nov 2025 14:31:14 -0800 Subject: [PATCH 2/2] Fix up cjs test to use actual require --- .gitignore | 1 + test/hook.test.mjs | 21 +++++++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index ba2a97b..280d31c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules coverage +.snapshots \ No newline at end of file diff --git a/test/hook.test.mjs b/test/hook.test.mjs index 4a4e71e..aeca709 100644 --- a/test/hook.test.mjs +++ b/test/hook.test.mjs @@ -3,6 +3,7 @@ import test from 'node:test' import assert from 'node:assert' import path from 'node:path' import { readFileSync } from 'node:fs' +import { createRequire } from 'node:module' import Snap from '@matteo.collina/snap' test.beforeEach(async (t) => { @@ -206,7 +207,7 @@ test('should default initialization to not crash if not defined', async (t) => { test('should rewrite code with conditional exports, cjs', async (t) => { const { esmLoaderRewriter, snap } = t.ctx - // Re-initialize with pkg-3 instrumentation + esmLoaderRewriter.initialize({ instrumentations: [ { @@ -221,12 +222,20 @@ test('should rewrite code with conditional exports, cjs', async (t) => { ] }) - const cjsPath = path.join(import.meta.dirname, './example-deps/lib/node_modules/pkg-3/lib/foo.cjs') - async function resolveFn() { - return { url: `file://${cjsPath}` } + const pkgDir = path.join(import.meta.dirname, './example-deps/lib/node_modules') + const require = createRequire(path.join(pkgDir, 'pkg-3', 'package.json')) + + async function resolveFn(specifier, context) { + try { + const resolved = require.resolve(specifier) + return { url: `file://${resolved}` } + } catch (err) { + throw new Error(`Cannot resolve ${specifier}: ${err.message}`) + } } async function nextLoad(url, context) { - const data = readFileSync(cjsPath, 'utf8') + const filePath = url.startsWith('file://') ? fileURLToPath(url) : url + const data = readFileSync(filePath, 'utf8') return { format: 'commonjs', source: data @@ -243,7 +252,7 @@ test('should rewrite code with conditional exports, cjs', async (t) => { test('should rewrite code with conditional exports, esm', async (t) => { const { esmLoaderRewriter, snap } = t.ctx - // Re-initialize with pkg-3 instrumentation + esmLoaderRewriter.initialize({ instrumentations: [ {