From f3ffd68f4ef21b0d370cff9b3710089f31d20577 Mon Sep 17 00:00:00 2001 From: chris Date: Mon, 18 Sep 2023 12:20:00 -0700 Subject: [PATCH 1/8] add import json tests --- src/esmockCache.js | 12 +++++++++++- src/esmockLoader.js | 20 +++++++++++++++++-- src/esmockModule.js | 15 ++++++++++++-- tests/local/example.json | 1 + tests/local/importsJSONfile.js | 5 +++++ tests/tests-node/esmock.node.test.js | 29 ++++++++++++++++++++++++++++ 6 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 tests/local/example.json create mode 100644 tests/local/importsJSONfile.js diff --git a/src/esmockCache.js b/src/esmockCache.js index 1bb2fd72..5c1d6f9b 100644 --- a/src/esmockCache.js +++ b/src/esmockCache.js @@ -8,6 +8,13 @@ const esmockCache = { mockDefs: {} } +const esmockModuleIdSourceSet = (keysource, source) => ( + esmockPostMessage({ keysource, source }), + global.mockKeysSource[String(keysource)] = source) + +const esmockModuleIdSourceGet = keysource => ( + global.mockKeysSource[String(keysource)]) + const esmockTreeIdSet = (key, keylong) => ( esmockPostMessage({ key, keylong }), global.mockKeys[String(key)] = keylong) @@ -31,7 +38,8 @@ Object.assign(global, { esmockCache, esmockCacheGet, esmockTreeIdGet, - mockKeys: global.mockKeys || {} + mockKeys: global.mockKeys || {}, + mockKeysSource: global.mockKeysSource || {} }) export { @@ -40,6 +48,8 @@ export { esmockCacheGet, esmockTreeIdSet, esmockTreeIdGet, + esmockModuleIdSourceSet, + esmockModuleIdSourceGet, esmockCacheResolvedPathIsESMGet, esmockCacheResolvedPathIsESMSet } diff --git a/src/esmockLoader.js b/src/esmockLoader.js index 7c707c01..ffe1f071 100644 --- a/src/esmockLoader.js +++ b/src/esmockLoader.js @@ -20,6 +20,7 @@ const esmkModuleIdRe = /esmkModuleId=([^&]*)/ const esmkIdRe = /\?esmk=\d*/ const exportNamesRe = /.*exportNames=(.*)/ const withHashRe = /.*#-#/ +const isJSONExtnRe = /\.json$/i const isesmRe = /isesm=true/ const isnotfoundRe = /isfound=false/ const iscommonjsmoduleRe = /^(commonjs|module)$/ @@ -31,11 +32,14 @@ const moduleIdReCreate = (moduleid, treeid) => new RegExp( // node v12.0-v18.x, global const mockKeys = global.mockKeys = (global.mockKeys || {}) +const mockKeysSource = global.mockKeysSource = (global.mockKeysSource || {}) // node v20.0-v20.6 const globalPreload = !module.register && (({ port }) => ( port.addEventListener('message', ev => ( - mockKeys[ev.data.key] = ev.data.keylong)), + ev.data.keysource + ? mockKeysSource[ev.data.keysource] = ev.data.source + : mockKeys[ev.data.key] = ev.data.keylong)), port.unref(), 'global.postMessageEsmk = d => port.postMessage(d)' )) @@ -44,7 +48,9 @@ const globalPreload = !module.register && (({ port }) => ( const initialize = module.register && (data => { if (data && data.port) { data.port.on('message', msg => { - mockKeys[msg.key] = msg.keylong + msg.keysource + ? mockKeysSource[msg.keysource] = msg.source + : mockKeys[msg.key] = msg.keylong }) } }) @@ -198,6 +204,16 @@ const load = async (url, context, nextLoad) => { .split(',') if (exportedNames && exportedNames[0]) { + if (mockKeysSource[url]) { + return { + // ...await nextLoad(url, context), + format: 'json', + shortCircuit: true, + responseURL: encodeURI(url), + source: mockKeysSource[url] + } + } + return { format: 'module', shortCircuit: true, diff --git a/src/esmockModule.js b/src/esmockModule.js index db4ba243..214b0afd 100644 --- a/src/esmockModule.js +++ b/src/esmockModule.js @@ -1,4 +1,5 @@ import fs from 'fs' +import url from 'url' import resolvewith from 'resolvewithplus' import esmockErr from './esmockErr.js' import esmockIsESMRe from './esmockIsESMRe.js' @@ -7,6 +8,7 @@ import { esmockTreeIdSet, esmockTreeIdGet, esmockCacheSet, + esmockModuleIdSourceSet, esmockCacheResolvedPathIsESMGet, esmockCacheResolvedPathIsESMSet } from './esmockCache.js' @@ -18,6 +20,7 @@ const nextId = ((id = 0) => () => ++id)() const objProto = Object.getPrototypeOf({}) const isPlainObj = o => Object.getPrototypeOf(o) === objProto const iscoremodule = resolvewith.iscoremodule +const isJSONExtnRe = /\.json$/i // assigning the object to its own prototypal inheritor can error, eg // 'Cannot assign to read only property \'F_OK\' of object \'#\'' @@ -36,7 +39,7 @@ const esmockModuleMergeDefault = (defLive, def) => const esmockModuleApply = (defLive, def, fileURL) => { // no fileURL here indicates 'import' mock, 'default' not needed - if (fileURL === null) + if (fileURL === null || isJSONExtnRe.test(fileURL)) return Object.assign({}, defLive || {}, def) if (Array.isArray(def)) @@ -95,9 +98,13 @@ const esmockModuleImportedPurge = treeid => { String(url.split('esmkgdefs=')[1]).split('#-#').forEach(purgeKey) } +const esmockImport = async fileURL => isJSONExtnRe.test(fileURL) + ? JSON.parse(fs.readFileSync(new url.URL(fileURL), 'utf-8')) + : import(fileURL) + const esmockModuleCreate = async (treeid, def, id, fileURL, opt) => { def = esmockModuleApply( - opt.strict || !fileURL || await import(fileURL), def, fileURL) + opt.strict || !fileURL || await esmockImport(fileURL), def, fileURL) const mockModuleKey = (fileURL || 'file:///' + id) + '?' + [ 'esmkTreeId=' + treeid, @@ -107,6 +114,10 @@ const esmockModuleCreate = async (treeid, def, id, fileURL, opt) => { 'exportNames=' + Object.keys(def).sort().join() ].join('&') + if (isJSONExtnRe.test(fileURL)) { + esmockModuleIdSourceSet(mockModuleKey, JSON.stringify(def)) + } + esmockCacheSet(mockModuleKey, def) return mockModuleKey diff --git a/tests/local/example.json b/tests/local/example.json new file mode 100644 index 00000000..4fa8f886 --- /dev/null +++ b/tests/local/example.json @@ -0,0 +1 @@ +{ "example": "json" } diff --git a/tests/local/importsJSONfile.js b/tests/local/importsJSONfile.js new file mode 100644 index 00000000..f1a3c8b2 --- /dev/null +++ b/tests/local/importsJSONfile.js @@ -0,0 +1,5 @@ +import JSONobj from './example.json' assert { type: 'json' }; + +export { + JSONobj +} diff --git a/tests/tests-node/esmock.node.test.js b/tests/tests-node/esmock.node.test.js index c2f3582c..43753c26 100644 --- a/tests/tests-node/esmock.node.test.js +++ b/tests/tests-node/esmock.node.test.js @@ -548,3 +548,32 @@ test('should mock an exported array', async () => { assert.deepStrictEqual(importsArray(), ['mocked']) }) + +test('should mock imported json', async () => { + const importsJSON = await esmock( + '../local/importsJSONfile.js', { + '../local/example.json': { + 'test-example': 'test-json' + } + }) + + assert.strictEqual( + Object.keys(importsJSON.JSONobj).sort().join(), 'example,test-example') + assert.strictEqual(importsJSON.JSONobj['test-example'], 'test-json') + assert.strictEqual(importsJSON.JSONobj['example'], 'json') +}) +/* +test('should mock imported json (strict)', async () => { + const importsJSON = await esmock.strict( + '../local/importsJSONfile.js', { + '../local/example.json': { + 'test-example': 'test-json' + } + }) + + assert.strictEqual( + Object.keys(importsJSON.JSONobj).sort().join(), 'test-example') + assert.strictEqual(importsJSON.JSONobj['test-example'], 'test-json') +}) +*/ + From 2898d5b0fa667e56df8e24889f1b069e143d76fb Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 19 Sep 2023 13:05:30 -0700 Subject: [PATCH 2/8] remove unused import --- src/esmockLoader.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/esmockLoader.js b/src/esmockLoader.js index ffe1f071..2c049230 100644 --- a/src/esmockLoader.js +++ b/src/esmockLoader.js @@ -20,7 +20,6 @@ const esmkModuleIdRe = /esmkModuleId=([^&]*)/ const esmkIdRe = /\?esmk=\d*/ const exportNamesRe = /.*exportNames=(.*)/ const withHashRe = /.*#-#/ -const isJSONExtnRe = /\.json$/i const isesmRe = /isesm=true/ const isnotfoundRe = /isfound=false/ const iscommonjsmoduleRe = /^(commonjs|module)$/ From 014d3cc571f0171f40cc88754869aa04a3350070 Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 19 Sep 2023 13:15:50 -0700 Subject: [PATCH 3/8] eslint ignore json-importing file --- .eslintrc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index dfd41062..841989b6 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,6 +1,6 @@ { "plugins": [], - "ignorePatterns": ["dist"], + "ignorePatterns": ["importsJSONfile.js"], "extends": [ "eslint:recommended", "plugin:markdown/recommended" From 57edc34ad56b90803b6ba51febc15b981000dfe4 Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 17 Oct 2023 11:22:28 -0700 Subject: [PATCH 4/8] update JSON test --- tests/tests-node/esmock.node.test.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/tests-node/esmock.node.test.js b/tests/tests-node/esmock.node.test.js index 43753c26..ac067664 100644 --- a/tests/tests-node/esmock.node.test.js +++ b/tests/tests-node/esmock.node.test.js @@ -553,27 +553,25 @@ test('should mock imported json', async () => { const importsJSON = await esmock( '../local/importsJSONfile.js', { '../local/example.json': { - 'test-example': 'test-json' + 'test-example': 'test-json-a' } }) assert.strictEqual( Object.keys(importsJSON.JSONobj).sort().join(), 'example,test-example') - assert.strictEqual(importsJSON.JSONobj['test-example'], 'test-json') + assert.strictEqual(importsJSON.JSONobj['test-example'], 'test-json-a') assert.strictEqual(importsJSON.JSONobj['example'], 'json') }) -/* + test('should mock imported json (strict)', async () => { const importsJSON = await esmock.strict( '../local/importsJSONfile.js', { '../local/example.json': { - 'test-example': 'test-json' + 'test-example': 'test-json-b' } }) assert.strictEqual( Object.keys(importsJSON.JSONobj).sort().join(), 'test-example') - assert.strictEqual(importsJSON.JSONobj['test-example'], 'test-json') + assert.strictEqual(importsJSON.JSONobj['test-example'], 'test-json-b') }) -*/ - From a85afcc73192a1bd4a453ddf2c6e609a94b5a1c9 Mon Sep 17 00:00:00 2001 From: chris Date: Tue, 17 Oct 2023 11:54:45 -0700 Subject: [PATCH 5/8] do not test json mock if node version 18 or 20 --- tests/tests-node/esmock.node.test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/tests-node/esmock.node.test.js b/tests/tests-node/esmock.node.test.js index ac067664..8b02f1fc 100644 --- a/tests/tests-node/esmock.node.test.js +++ b/tests/tests-node/esmock.node.test.js @@ -557,6 +557,9 @@ test('should mock imported json', async () => { } }) + if (/^(18|20)$/.test(process.versions.node.split('.')[0])) + return assert.ok(true) + assert.strictEqual( Object.keys(importsJSON.JSONobj).sort().join(), 'example,test-example') assert.strictEqual(importsJSON.JSONobj['test-example'], 'test-json-a') @@ -571,6 +574,9 @@ test('should mock imported json (strict)', async () => { } }) + if (/^(18|20)$/.test(process.versions.node.split('.')[0])) + return assert.ok(true) + assert.strictEqual( Object.keys(importsJSON.JSONobj).sort().join(), 'test-example') assert.strictEqual(importsJSON.JSONobj['test-example'], 'test-json-b') From 19cb4914225a6197e53e5c4953b7726180bb4606 Mon Sep 17 00:00:00 2001 From: chris Date: Thu, 2 Nov 2023 23:33:01 -0700 Subject: [PATCH 6/8] try running json-mockng tests in latest node 18 and 20, to see if upstream issue is resolved those --- tests/tests-node/esmock.node.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/tests-node/esmock.node.test.js b/tests/tests-node/esmock.node.test.js index 8b02f1fc..8e022fe2 100644 --- a/tests/tests-node/esmock.node.test.js +++ b/tests/tests-node/esmock.node.test.js @@ -557,8 +557,8 @@ test('should mock imported json', async () => { } }) - if (/^(18|20)$/.test(process.versions.node.split('.')[0])) - return assert.ok(true) + //if (/^(18|20)$/.test(process.versions.node.split('.')[0])) + // return assert.ok(true) assert.strictEqual( Object.keys(importsJSON.JSONobj).sort().join(), 'example,test-example') @@ -574,8 +574,8 @@ test('should mock imported json (strict)', async () => { } }) - if (/^(18|20)$/.test(process.versions.node.split('.')[0])) - return assert.ok(true) + //if (/^(18|20)$/.test(process.versions.node.split('.')[0])) + // return assert.ok(true) assert.strictEqual( Object.keys(importsJSON.JSONobj).sort().join(), 'test-example') From 9b94cff9fa47ed57fa09839933ff6eb806667fca Mon Sep 17 00:00:00 2001 From: chris Date: Thu, 2 Nov 2023 23:36:00 -0700 Subject: [PATCH 7/8] do not test json mock if node version 18 or 20 --- tests/tests-node/esmock.node.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/tests-node/esmock.node.test.js b/tests/tests-node/esmock.node.test.js index 8e022fe2..8b02f1fc 100644 --- a/tests/tests-node/esmock.node.test.js +++ b/tests/tests-node/esmock.node.test.js @@ -557,8 +557,8 @@ test('should mock imported json', async () => { } }) - //if (/^(18|20)$/.test(process.versions.node.split('.')[0])) - // return assert.ok(true) + if (/^(18|20)$/.test(process.versions.node.split('.')[0])) + return assert.ok(true) assert.strictEqual( Object.keys(importsJSON.JSONobj).sort().join(), 'example,test-example') @@ -574,8 +574,8 @@ test('should mock imported json (strict)', async () => { } }) - //if (/^(18|20)$/.test(process.versions.node.split('.')[0])) - // return assert.ok(true) + if (/^(18|20)$/.test(process.versions.node.split('.')[0])) + return assert.ok(true) assert.strictEqual( Object.keys(importsJSON.JSONobj).sort().join(), 'test-example') From 97993ad77e6d2a4ad196453670ca7c58293a74f9 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 3 Nov 2023 19:15:52 -0700 Subject: [PATCH 8/8] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9a7eb15..0b7dc82f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ * 2.5.9 _Nov.11.2023_ * [mock Array-type default export,](https://github.com/iambumblehead/esmock/pull/266) thanks @altearius + * [support json import mocking,](https://github.com/iambumblehead/esmock/pull/247) only working at node v21, see [node#49724](https://github.com/nodejs/node/issues/49724) * 2.5.8 _Oct.23.2023_ * [catch yarn PnP exceptions](https://github.com/iambumblehead/esmock/pull/262) @koshic * 2.5.7 _Oct.20.2023_