-
Notifications
You must be signed in to change notification settings - Fork 31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use with "esm" and .mjs files does not work #24
Comments
It will be interesting to solve. |
Node 10 introduced loader hooks - https://nodejs.org/api/esm.html#esm_loader_hooks |
Sorry a "delay". Would not work
Would workIt would work every time you use
index = (await rewiremock.module(() => import('./index'), (r) => ({
'./foo': r.withDefault(() => 'fake-foo'),
}))).default; It's the same as
rewiremock(() => import('./foo')).withDefault(() => 'fake-foo');
// or, it does not matter
rewiremock('./foo').withDefault(() => 'fake-foo');
rewiremock.enable();
index = (await import('./index')).default; |
@theKashey today I tried updating a package and some dependency-packages from "transpiled" to "native es6". A perfect blend of cjs/mjs incompatibilities prevent my success. The final problem of getting ava and rewiremock to work with these packages is blocked it seems. AVA doesn't support es modules but can transpile only test files with esm and rewiremock does not support ".mjs" files. When importing rewiremock from an .mjs test file there is an error Unfortunately, I don't have a solution and am just describing my experience. Setting up packages that nicely provide both commonjs and es modules is complex. The best-working combination I found so far is to identify an ".mjs" file as the "main" file, so that node handles the file correctly when it is imported and doesn't require one to declare type "module" in the package.json (nodejs restricts how "module" type packages can be used and it seems better not to declare that) I do not remember all of the subtle cjs/esm restrictions and problems to list them here... I wish rewiremock supported .mjs files. Anyway thank you @theKashey for rewiremock it is a great package :) |
@theKashey I'm un-familiar with module-loading details, but if you have a plan for adding esm module support to rewiremock, I might be interested in trying to implement that plan. The discussion here seems related https://gist.github.com/guybedford/e6687e77d60739f27d1b5449a2872bf4 -- edit
|
I have tried using variations of the 'import' strategy as below await rewiremock.module( () => import( '../../src/file.js' ), r => ({
'./localfile.js': { abcd: true },
'@org/package': r.withDefault({ abcd: true })
}); I control the sources at '@org/package' and no matter the changes I make at @org/package or to the rewiremock call, localfile is always mocked succesfully and @org/package is never mocked succesfully. In some combinations, the imported src/file.js script gets an undefined default for the mocked '@org/package' package. If rewiremock is able to mock the localfile this indicates it may also somehow be able to mock the package... @theKashey do you have any ideas for me? What can I do so that '@org/package' will be mocked here? |
https://gist.github.com/guybedford/e6687e77d60739f27d1b5449a2872bf4 has an interesting, but not documented moment
Right now the main problem with "esm mocking" is not the actual "mocking", but clearing the cache later - ESM was designed to be immutable, so dependency level mocking was(?) not possible by design. |
So. Let's clarify one moment - anything which goes not through "old" module system is invisible to rewiremock. That is why You can try to use the same "name resolution hack"(aka "import") to double check this moment. await rewiremock.module( () => import( '../../src/file.js' ), r => ({
'./localfile.js': { abcd: true },
// lets resolve a fill name
require.resolve('@org/package'): r.withDefault({ abcd: true })
}); or await rewiremock.around( () => import( '../../src/file.js' ), () => {
rewiremock('./localfile.js').with({ abcd: true }),
rewiremock(() => import('@org/package').withDefault({ abcd: true });
}); |
@theKashey thanks for your assistance. I'll try it out later on at the end of the day :) |
@theKashey these lines from my test use the first pattern you gave... const post = stub().resolves();
const { doHealthPush } = await rewiremock.module( () => import( '../../src/health/health.js' ), r => ({
'../utils/errors.js': errorsExports,
[require.resolve( '@platform/template-js-http-request' )]: r.withDefault({ post })
})); inside "health.js" the package resolves to import request from '@platform/template-js-http-request';
console.log({ request }); // { request: undefined } |
@theKashey I made a small little package to test your setup pattern... it worked. I'll investigate to find what causes the issue in the original package. edit I'm trying to make a little sample that replicates the issue by loading the module again elsewhere in a dependency hierarchy outside the target file. but so far am unable to reproduce. In the bigger original package not-importing certain files that import "@platform/template-js-http-request" allows the mocked definition to remain... using console.log to log imported "@platform/template-js-http-request" definitions like this... import request from '@platform/template-js-http-request';
console.log({ request }); the shell process shows these definitions... { request: { post: [Function: functionStub] } }
{ request: undefined } if I remove the rewiremock definition for the file, the full un-mocked definition appears in both console.log calls (there is no |
Sounds like mocking is working, but there is a problem with providing mocked value. import * as request from '@platform/template-js-http-request';
console.log({ request });
|
@theKashey a little demonstration is here: https://github.com/iambumblehead/rewiremock-discuss |
That's awesome way to tackle the problem. How I will all issues will be as easily reproducible as this one. |
@theKashey thank you :) I am glad if I am helpful and thankful for your assistance |
@theKashey I wanted to give you a little update... I tried updating the sources here but things are complicated by the way node's module system works. I made this package, but is slow to process really demanding test loads (fast enough for moderate loads) https://github.com/iambumblehead/esmock A few anecdotal things I found... if 'mjs' files can, in fact, be mocked. Inside module._load, load a blank/dummy.mjs file, write the mock definitions to that and return it. A problem I was unable to solve is (big problem)... removing an 'es-module' from module._cache causes that modules' definition to revert to the un-mocked definition at runtime inside files that have already imported that definition. The 'solution' at esmock is to use a semaphor to load each mock definition completely before processing the next one. If I were able to solve that last problem I would maybe try optimizing esmock for general use. |
I google-searched this subject again this morning and found this package which uses the new node.js module loader. I haven't tried it yet, but the source code consists of a few amazingly small files |
Yep, here are a few details on how it works - https://dev.to/giltayar/mock-all-you-want-supporting-es-modules-in-the-testdouble-js-mocking-library-3gh1 And I don't want to implement the same hacky and smelly solutions for rewiremock. My opinion is not changing for the last years - mjs/esm are not ready to be used and should be avoided. Especially for tests, which never were considered as an important use case for ESM (immutable cache) |
@theKashey thanks for your response. I agree with you and am not a fan of the ESM format :/ |
Ideal solution here would be developing a "module cache" polyfill, probably based on quibble approach, to abstract the missing API and let other solutions to integrate to not yet friendly ecosystem with less friction. |
Hello, I'm unsure how to use this mocking together with
mocha
,esm
and a.mjs
file.I built a reproducible test repo here: https://github.com/onlywei/rewiremock-esm-repro
I've also tried turning on esm's cjs-interop flag and got a different error.
Would like advice.
The text was updated successfully, but these errors were encountered: