boblauer / mock-require Goto Github PK
View Code? Open in Web Editor NEWSimple, intuitive mocking of Node.js modules.
License: MIT License
Simple, intuitive mocking of Node.js modules.
License: MIT License
Hi,
I'm aware that mocking via object key replacement doesn't necessarily work, i.e
const module = require('...')
const { feature } = module;
and
exports = function () { }
Don't work with sinon and similar libraries. This led me to mock-require.
I've been playing with it using before() and after() in mocha and individual unit tests complete successfully, however since tests are not sandbox there is module mock creep and others fail. Resolving this has been surprisingly difficult. I have concluded that reRequire() in before/after suffers the same flaw as the others because mocha enumerates all the describe() functions before running the if functions, so unless all tests have their requires inside the before and after they will be loaded immediately.
I have a solution, but it is yet to work and I believe this is a bug with mock--require.
mock.reRequire('./payment'); // just in case
mock.reRequire('../../../../common/daoFactory'); // just in case
const getOneByQuery = () => Promise.resolve(null);
mock('../../../../common/daoFactory', () => {
return {
getOneByQuery
};
});
const payment = require('./payment'); // immediately requires and calls daoFactory.
mock.stopAll();
mock.reRequire('./payment');
mock.reRequire('../../../../common/daoFactory');
Here two modules are removed from node cache (just in case). The mock is inserted and the main unit loaded. It references the mock. I don't think mock.stopAll() is necessary unless it's firing event emitters as reRequire() should do the same thing. Unlike using after() subsequent spec files loaded by mocha will reference the require module. Mocks are changed by modifying the function in this case.
Alas it doesn't work as expected, the daoFactory still references the require module. Is mock() async in any way? I can't see what else it could be.
I am trying to mock a dependency in a route module in an express js server but cannot get it to work.
I tried everything with the route module loaded in the main server/index.js file so I thought ok just remount the route on another root path so to have two paths to the routes with different prefixes like when you version an end point but this one will be for testing with the mocked service/business layer module which is called ecourier.controller in my sample. See below but even then on the new /apitest route path it still does not mock the Module.... AWWWWWW..
Please what am I doing wrong...
import chai from 'chai';
import server from '..';
var mock = require('mock-require');
chai.use(require('chai-http'));
var expect = chai.expect;
var route = '/apitest/shipmentDispatched';
var mockreq = null;
var winstoncls = {
stream: {
write: (msg) => { console.log(msg); }
}
}
const emptycls = { name: 'Dummy class' };
mock('../controllers/ecourier.controller', {
updateDispatch: function(res,req,config) {
res.json({ status: 'OK' });
}
});
mock.reRequire('../controllers/ecourier.controller');
import routes from '../routes';
server.use('/apitest', routes({ emptycls, emptycls, emptycls, winstoncls }));
We hit an issue of subsequencing tests keep loading previously mocked dependency.
It stops only if we add reRequire(moduleInQuestion)
after previous test finished running to clear out cache:
testA.js
afterEach(() => {
mock.stopAll()
mock.reRequire('../dep')
})
Hi,
I'm using Jasmine to test a helper module that contains a few requires. I have tried to use the reRequire
method, but it does not seem to do the trick:
beforeEach(function () {
mock('mime', { lookup: function () {
return 'application/sadsda'
}})
helper = mock.reRequire('./helper')}
When I test a method in the helper module, I can see that the actual modules are being used, rather than the mocks. Am I doing something wrong?
Thank you.
So I'm using https://www.npmjs.com/package/decache and require
instead. That actually works, so, perhaps you can just swap out the implementation with that.
It seems that getFullPath
returns the path to mock-require
, instead of to the correct module.
The method getFullPath() does not take into consideration Win32 environments with mixed Posix style require strings.
For instance:
mockRequire(process.cwd() + "/" + path, obj);
In Posix environment the backslash remains, but in Win32 environment, the backslash becomes a forward slash "".
To overcome, wrap the result of getFullPath() with a call to normalize(), exposed by the path module.
Hi and thanks for this package, it seems really useful. Specially since there are some packages that cannot be mocked easily otherwise.
I am trying an example very similar to the one stated in the documentation:
var mock = require('mock-require');
mock('pkg-dir', { sync: function () {
console.log('pkg.sync() called');
}});
const pkg = require('pkg-dir');
console.log(pkg.sync());
When I try it with Node.js with node plugins/index.test.js
(in my case) it works flawlessly printing pkg.sync() called
. However, with Jest (with slight modifications since at least one test is required) it does not seem to work:
var mock = require('mock-require');
mock('pkg-dir', { sync: function () {
console.log('pkg.sync() called');
}});
it('is synced', () => {
const pkg = require('pkg-dir');
console.log(pkg.sync());
});
It prints the directory where the package.json
is hosted, as the pkg-dir
library specifies (so it runs the original code). I have no idea how to even debug this since it seems like it's an issue with Jest + mock-require. I do not know the differences at runtime of Node.js and Jest, I thought Jest just loaded a couple of functions like it()
and expect()
but otherwise used a stock Node.js runtime.
Hi,
I am currently having the issue where I want to mock a HTML-file. Unfortunately, I cannot do this because if the second argument of mock()
is a string, it assumes that it is a path to look for a module to return. But I simply want mock('../templates/template.html', 'dummytemplate')
to return 'dummytemplate'
.
Maybe this is already possible somehow...?
I'm trying to use this library, but so far it doesn't seem to work.
I've created a test repo for this
If you run the code, the original function is still executed.
Any help would be appreciated!
I believe this issue is similar to #34 , but unfortunately when I tried the suggested solution by @boblauer it did not work. I've tried to include slightly more specific code in case I misunderstood issue #34 and my situation is in fact different.
server file (subject)
const express = require('express')
const app = express()
// import route
const router = require('./route')
app.use('/', router)
const startServer = () => {
app.listen(PORT, () => logger.info('Listening on port 3000'))
}
startServer()
module.exports = app
router file (dep)
const express = require('express')
const router = express.Router()
// Import function
const { getTwilio } = require('./utils')
const twilioClient = getTwilio()
const routeFunction(req, res) {
twilioClient.messages.create({
body: 'xxxx,
messagingServiceSid: 'xxxx',
from: 'xxxx',
to: 'xxxx',
})
}
router.post('/', routeFunction)
utils function dependency
function getTwilio () {
return require('twilio')(process.env.ACCOUNT_SID, process.env.AUTH_TOKEN)
}
module.exports = {
getTwilio,
}
test file
const chai = require('chai')
const chaiHttp = require('chai-http')
chai.use(chaiHttp)
const sinon = require('sinon')
const mock = require('mock-require')
// Mock twilio client
const twilioStub = sinon.stub()
const twilioStub = () => ({
messages: {
create: twilioStub,
},
})
mock('./utils', { getTwilio: twilioStub })
// Import server
const server = require('./index')
async function tests () {
describe('tests', () => {
mock.reRequire('./route')
server = mock.reRequire('./index')
const res = await chai
.request(server)
.post('/')
.send()
const resBody = JSON.parse(res.text)
})
}
As it stands, if I do not use:
mock.reRequire('./route')
server = mock.reRequire('./index')
the dependency is not mocked and the actual dependency is used instead, even though the mock was created before I imported the server file. Anyone has any idea why this is happening?
I'm mocking some libraries using mock-require
in my unit tests. I'm using Mocha 3.1.2 and Node 4.7.0. I have my tests in the folder test
in separate files. Running mocha test/foo.js
works perfectly, but running npm test
(which in turn runs mocha --reporter spec test/*.js
) makes the same tests in test/foo.js
fail! To be exact, the require
statements sometimes still return the real libraries, not the mocked ones.
I inserted some debugging statements in mock-require, especially in the overridden Module._load
function, and it seems like that function is not being called for all require statements. For example: if the file test/foo.js
requires src/bar.js
(using the correct path of course) and that file requires src/libAsdf.js
, then the overridden Module._load
is correctly called when requiring src/bar.js
but NOT when requiring src/libAsdf.js
. This is always the pattern: mock-require
works for the first link in a require
chain, but not after that.
NOTE: This only happens when running mocha on all my tests. Running individual test files, mock-require
is correctly used for all files in the dependency tree.
I couldn't spot any obvious answer to this problem, I suppose it's some magic that Mocha does. Any tips?
I'm using this module with node version 0.12.17 and got the error:
ModuleNotFoundError: Module not found: Error: Cannot resolve module 'module' in node_modules/mock-require
Any ideas of what could be wrong?
It's not easy to learn what new features or fixes landed with given version updates, or even more importantly what were breaking changes with given major (is it safe for me to upgrade or not?)
There seems to be no changelog, no release notes, and when one wants to look into code of specific version it's impossible on Github due to lack corresponding tags
The module which I'm trying to mock refers to global variables which do no exist in my node environment. I'd like that module to be not loaded at all, but simply mocking it with mock('myModule', {}); still makes it (and its imports as well) to be loaded. Is there a way to just not load that module?
Thanks for the great work, API seems super simple. I wonder - are there any advantages for using this instead of full-blown test double library like Sinon?
When trying to reRequire
a file named index
that is in the local path, reRequire
will instead return what mock-require
exports, specifically the startMocking
function.
Example code:
index.js:
const fs = require('fs')
// ...
module.exports = { fs }
test.js:
const mock = require('mock-require')
mock('fs', {})
const index = mock.reRequire('./index')
console.log(index)
Expected output:
{ fs: {} }
Actual output:
function startMocking(path, mockExport) {
const calledFrom = getCallerFile();
if (typeof mockExport === 'string') {
mockExport = getFullPathNormalized(mockExport, calledFrom);
}
pendingMockExports[getFullPathNormalized(path, calledFrom)] = mockExport;
}
Based on looking at the code (and specifically at getFullPath
and isInNodePath
, it looks like any file that can be resolved from the mock-require package will cause it to return that file rather than the actual local file.
I noticed that mock-require
doesn't align with Node in its Module._load
overwrite in that it requires parent
(even though parent
may be null
or undefined
). See the Node version for more. This caused an error with a combo of nyc
, mock-require
, and @std/esm
packages.
Hi @boblauer,
I have the following project structure:
gtm.js:
var setEnvironment = require('./setEnvironment');
module.exports = function() {
setEnvironment();
}
gtm.spec.js:
// ....
var gtm = require('../../lib/gtm');
var setEnvironment = jasmine.createSpy();
mock('./setEnvironment', setEnvironment);
gtm();
mock.stopAll();
// ....
The problem is that when I run the code above, mock-require doesn't mock ./setEnvironment
path. I went deeper and debug it a little bit. When mock('./setEnvironment', setEnvironment);
is run:
startMocking
called with ./setEnvironment
, Function
argumentsgetFullPath
called with ./setEnvironment
, /vagrant/spec/unit/gtm.spec.js
argumentsresolvedPath = require.resolve(path);
throws Error: Cannot find module './setEnvironment'
Please confirm is that bug or not? If not, could you please let me know about any possible workaround?
It would be nice if there was a possibility to stop mocking all modules with a single call:
mock.stopAll();
or similar.
The rationale behind my request is that I often have multiple mocks in dozens of test cases and it's annoyingly repetitive to add the afterEach
in every single test case with all the mocks I have created. Instead, it would be much cleaner to just create a single afterEach
call after every test in the entire test suite (Jasmine allows this), reducing greatly the amount of boilerplate code:
var mock = require("mock-require");
afterEach(function() {
mock.stopAll();
});
I can provide a pull request if needed.
Travis Ci does not seem to work with mock requires the same as what I have locally, is there anything that could cause mock require not to work in their environment?
This probably isn't really an issue with mock require but I figured it would be best to open one in case others run into the same problem
First of all, thanks for a great module!
I'm trying to use mock-require
with execa
, but unfortunately the mock doesn't run.
Here is the gist of my test:
const mock = require('mock-require');
const execa = require('execa');
mock('analyze-deps', './analyze-deps-mock');
it('should ...', () => {
return expect(execa('./bin/deps'))
.to.eventually.have.property('stdout').equal('something');
});
where ./bin/deps
is simply:
#!/usr/bin/env node
require('../index');
With this setup, ./analyze-deps-mock
is not run.
If I replace execa('./bin/deps')
with require('../index')
, then ./analyze-deps-mock
is run as expected.
I assume the problem is that execa
spawns a new process, but not sure how to workaround this.
Any ideas?
To reproduce:
git clone [email protected]:moroshko/analyze-deps-cli.git
cd analyze-deps-cli
git checkout 93251ff
npm install
npm test
My reproduction code is here.
Here is a screencast of me debugging the issue. I hope you enjoy it rather than swear at me for it.
So am I using it wrong or what?
This is one module which can mock React modules, resolve paths, don't launch original dependencies, etc. Thanks!
Hi,
I'm trying to mock-require the js-ubersmithclient module, however it uses a constructor, like this:
const Ubersmith = require('js-ubersmithclient')
let ubersmithClient = new Ubersmith(url, username, password)
And then you can actually use the various functions that the API provides, e.g.:
ubersmith.uber.check_login({login: username, pass: password})
.then(...)
(where uber.check_login
is just what the API provides, and not part of the module itself).
Is there any way that mock-require
can mock that sort of constructor and the subsequent API calls?
Thank you.
Consider this test:
subject:
const dep = require('./dep');
module.exports = () => {
return dep();
}
dep:
const uuid = require('uuid/v4');
module.exports = () => {
return uuid();
}
test:
const t = require('tap');
const mock = require('mock-require');
let subject = require('./subject');
t.test('should return uuid', t => {
mock('uuid/v4', () => '12345');
subject = mock.reRequire('./subject');
const result = subject();
t.equal(result, '12345');
t.end();
});
This test fails because the nested uuid/v4
dependency is not actually mocked. Why is that and how can I make it work? What am I missing here?
This module is exactly what I'm looking for, but when I imported it and ran it, I got this runtime error. Any ideas what's happening here? I'm running on Node v8.
/workspace/node_modules/caller-id/lib/caller-id.js:12
typeName: caller.getTypeName(),
^
TypeError: caller.getTypeName is not a function
at Object.getData (/workspace/node_modules/caller-id/lib/caller-id.js:12:26)
at startMocking (/workspace/node_modules/mock-require/index.js:27:29)
at Object.<anonymous> (/workspace/tests/test.js:3:1)
at Module._compile (module.js:624:30)
at Object.Module._extensions..js (module.js:635:10)
at Module.load (module.js:545:32)
at tryModuleLoad (module.js:508:12)
at Function.Module._load (module.js:500:3)
at Module.require (module.js:568:17)
at require (internal/module.js:11:18)
at /Users/mcphandr/.nvm/versions/node/v8.6.0/lib/node_modules/mocha/lib/mocha.js:231:27
at Array.forEach (<anonymous>)
at Mocha.loadFiles (/Users/mcphandr/.nvm/versions/node/v8.6.0/lib/node_modules/mocha/lib/mocha.js:228:14)
at Mocha.run (/Users/mcphandr/.nvm/versions/node/v8.6.0/lib/node_modules/mocha/lib/mocha.js:514:10)
at Object.<anonymous> (/Users/mcphandr/.nvm/versions/node/v8.6.0/lib/node_modules/mocha/bin/_mocha:480:18)
at Module._compile (module.js:624:30)
at Object.Module._extensions..js (module.js:635:10)
at Module.load (module.js:545:32)
at tryModuleLoad (module.js:508:12)
at Function.Module._load (module.js:500:3)
at Function.Module.runMain (module.js:665:10)
at startup (bootstrap_node.js:187:16)
at bootstrap_node.js:607:3
Hello,
I'm having trouble mocking nested dependencies in my Jasmine tests. Here is the code:
mockSpec.js
'use strict';
const mock = require('mock-require');
describe('mock', function() {
mock('./test', 'MOCKED');
var testSubject = require('./subfolder');
it("should be mocked", function() {
expect(testSubject.test).toBe("MOCKED");
})
mock.stopAll();
})
subfolder/index.js
'use strict';
module.exports = {
test: require('./test')
}
subfolder/test.js
'use strict';
module.exports = 'ORIGINAL';
I would expect this test to pass but instead it fails:
Failures:
1) mock should be mocked
Message:
Expected 'ORIGINAL' to be 'MOCKED'.
I also tried using mock.reRequire()
as well as making the require paths relative to the spec file without success.
Is there a way to use unix wildcards?
Something like so: mock('*.scss');
. I think this would be useful if you want to mock CSS modules for unit testing.
It may be a stupid suggestion, but I thought it was worth sharing it.
My use case requires me to support two behaviors, one for one a module exists and one if it's, missing. I tried to use this module to write the test suite for both scenarios but this:
mock({
'./hello.json': { foo: 'bar' }
})
require('./hello.json')
yields
Error: Cannot find module './hello.json'
at Function.Module._load (node_modules/mock-require/index.js:24:22)
at require (internal/module.js:20:19)
at Context.it.only (index.test.js:32:5)
Is this a missing feature or I am missing something?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.