diff --git a/.gitignore b/.gitignore index b30921b1..92ebc14a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules README.html -.tern-port \ No newline at end of file +.tern-port +package-lock.json \ No newline at end of file diff --git a/README.md b/README.md index c0e2d63b..1589ed62 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,8 @@ test('should mock "await import()" using esmock.p', async t => { changelog
+ * 1.6.0 _Dec.02.2021_ + * reduce file url length (improve readability of stacktrace) * 1.5.0 _Dec.01.2021_ * resolve bug around error '--loader=esmock' detection * 1.4.0 _Nov.30.2021_ diff --git a/package.json b/package.json index d74f4d63..c5e3cd11 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "esmock", - "version": "1.5.0", + "version": "1.6.0", "license": "MIT", "readmeFilename": "README.md", "description": "provides native ESM import mocking for unit tests", diff --git a/spec/esmock.spec.js b/spec/esmock.spec.js index 46d0b672..7f96457a 100644 --- a/spec/esmock.spec.js +++ b/spec/esmock.spec.js @@ -283,7 +283,7 @@ test('mocks inline `async import("name")`', async t => { filePath : 'filePath' })); - const [ , key ] = writeJSConfigFile.esmockKey.match(/esmockKey=(\d*)/); + const [ , key ] = writeJSConfigFile.esmockKey.match(/esmk=(\d*)/); const keyRe = new RegExp(`esmockKey=${key}[^d]`); const moduleKeys = Object.keys(esmock.esmockCache.mockDefs) @@ -293,3 +293,15 @@ test('mocks inline `async import("name")`', async t => { esmock.purge(writeJSConfigFile); t.true(moduleKeys.every(mkey => esmock.esmockCache.mockDefs[mkey] === null)); }); + +test('should have small querystring in stacktrace filename', async t => { + const { causeRuntimeError } = await esmock('./local/mainUtil.js'); + + try { + causeRuntimeError(); + } catch (e) { + t.true(/\?esmk=\d/.test(e.stack.split('\n')[1])); + } + + t.pass(); +}); diff --git a/src/esmockCache.js b/src/esmockCache.js index 5a377e63..96129b3a 100644 --- a/src/esmockCache.js +++ b/src/esmockCache.js @@ -6,6 +6,12 @@ const esmockCache = { mockDefs : {} }; +const esmockKeySet = (key, keylong) => ( + global.mockKeys[String(key)] = keylong); + +const esmockKeyGet = key => ( + global.mockKeys[String(key)]); + const esmockCacheSet = (key, mockDef) => ( esmockCache.mockDefs[key] = mockDef); @@ -18,12 +24,18 @@ const esmockCacheResolvedPathIsESMGet = mockPathFull => ( const esmockCacheResolvedPathIsESMSet = (mockPathFull, isesm) => ( esmockCache.isESM[mockPathFull] = isesm); -Object.assign(global, { esmockCacheGet }); +Object.assign(global, { + esmockCacheGet, + esmockKeyGet, + mockKeys : {} +}); export { esmockCache, esmockCacheSet, esmockCacheGet, + esmockKeySet, + esmockKeyGet, esmockCacheResolvedPathIsESMGet, esmockCacheResolvedPathIsESMSet }; diff --git a/src/esmockLoader.mjs b/src/esmockLoader.mjs index bbd8b314..ee098ada 100644 --- a/src/esmockLoader.mjs +++ b/src/esmockLoader.mjs @@ -12,9 +12,15 @@ const urlDummy = 'file:///' + path .replace(/^\//, ''); const resolve = async (specifier, context, defaultResolve) => { - const [ esmockKeyParam ] = (context.parentURL - && context.parentURL.match(/esmockKey=\d*/) || []); - + const { parentURL } = context; + const [ esmockKeyParamSmall ] = + (parentURL && parentURL.match(/\?esmk=\d*/)) || []; + const esmockKeyLong = esmockKeyParamSmall + ? global.esmockKeyGet(esmockKeyParamSmall.split('=')[1]) + : parentURL; + const [ esmockKeyParam ] = + (esmockKeyLong && esmockKeyLong.match(/esmockKey=\d*/) || []); + if (!esmockKeyParam) return defaultResolve(specifier, context, defaultResolve); @@ -22,7 +28,7 @@ const resolve = async (specifier, context, defaultResolve) => { const moduleKeyRe = new RegExp( '.*(' + resolved.url + '\\?' + esmockKeyParam + '[^#]*).*'); - const moduleURLSplitKeys = context.parentURL.split('#esmockModuleKeys='); + const moduleURLSplitKeys = esmockKeyLong.split('#esmockModuleKeys='); // eslint-disable-next-line prefer-destructuring const moduleGlobals = moduleURLSplitKeys[0].split('?esmockGlobals=')[1]; const moduleKeyChild = moduleKeyRe.test(moduleURLSplitKeys[1]) diff --git a/src/esmockModule.js b/src/esmockModule.js index 1b30d0af..3c7029eb 100644 --- a/src/esmockModule.js +++ b/src/esmockModule.js @@ -3,6 +3,8 @@ import path from 'path'; import resolvewith from 'resolvewithplus'; import { + esmockKeySet, + esmockKeyGet, esmockCacheSet, esmockCacheResolvedPathIsESMGet, esmockCacheResolvedPathIsESMSet @@ -68,7 +70,7 @@ const esmockModuleIsESM = (mockPathFull, isesm) => { // does not need to lookup default as in "esmockedValue.default" const esmockModuleImportedSanitize = (importedModule, esmockKey) => { const importedDefault = 'default' in importedModule && importedModule.default; - + if (!/boolean|string|number/.test(typeof importedDefault)) { // an example of [object Module]: import * as mod from 'fs'; export mod; return Object.prototype.toString.call(importedDefault) === '[object Module]' @@ -81,7 +83,8 @@ const esmockModuleImportedSanitize = (importedModule, esmockKey) => { const esmockModuleImportedPurge = modulePathKey => { const purgeKey = key => key === 'null' || esmockCacheSet(key, null); - const [ url, keys ] = modulePathKey.split('#esmockModuleKeys='); + const longKey = esmockKeyGet(modulePathKey.split('esmk=')[1]); + const [ url, keys ] = longKey.split('#esmockModuleKeys='); String(keys).split('#').forEach(purgeKey); String(url.split('esmockGlobals=')[1]).split('#').forEach(purgeKey); @@ -148,11 +151,15 @@ const esmockModuleMock = async (calleePath, modulePath, defs, gdefs, opt) => { if (pathModuleFull === null) throw new Error(`modulePath not found: "${modulePath}"`); - return pathAddProtocol(pathModuleFull, 'file:///') + '?' + const esmockKeyLong = pathAddProtocol(pathModuleFull, 'file:///') + '?' + 'key=:esmockKey?esmockGlobals=:esmockGlobals#esmockModuleKeys=:moduleKeys' .replace(/:esmockKey/, esmockKey) .replace(/:esmockGlobals/, esmockGlobalKeys.join('#') || 'null') .replace(/:moduleKeys/, esmockModuleKeys.join('#')); + + esmockKeySet(String(esmockKey), esmockKeyLong); + + return pathAddProtocol(pathModuleFull, 'file:///') + `?esmk=${esmockKey}`; }; export {