rewiremock
Advanced tools
Comparing version 2.1.3 to 3.0.0
@@ -24,2 +24,6 @@ 'use strict'; | ||
var _asyncModules = require('./asyncModules'); | ||
var _asyncModules2 = _interopRequireDefault(_asyncModules); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -96,2 +100,12 @@ | ||
function asyncTest() { | ||
var asyncModulesLeft = _asyncModules2.default.hasAsyncModules(); | ||
if (asyncModulesLeft) { | ||
console.error('Rewiremock: listed async modules should finish loading first. Use async API of rewiremock.', asyncModulesLeft.map(function (module) { | ||
return module.creator.toString(); | ||
})); | ||
throw new Error('Rewiremock: listed async modules should finish loading first. Use async API of rewiremock.'); | ||
} | ||
} | ||
function mockLoader(request, parent, isMain) { | ||
@@ -103,2 +117,4 @@ var _getScope2 = (0, _globals2.default)(), | ||
asyncTest(); | ||
var baseRequest = _module2.default._resolveFilename(request, parent); | ||
@@ -105,0 +121,0 @@ var shortRequest = monkeyPatchPath((0, _path.relative)((0, _module.getModuleName)(parent), request)); |
@@ -30,2 +30,7 @@ 'use strict'; | ||
_createClass(ModuleMock, [{ | ||
key: 'nonStrict', | ||
value: function nonStrict() { | ||
return this; | ||
} | ||
}, { | ||
key: 'from', | ||
@@ -32,0 +37,0 @@ value: function from(source) { |
@@ -50,3 +50,3 @@ 'use strict'; | ||
* @name rewiremock | ||
* @param {String} module name | ||
* @param {String|Function} module name | ||
* @return {ModuleMock} | ||
@@ -56,5 +56,9 @@ */ | ||
scope(); | ||
var name = (0, _plugins.convertName)(moduleName, parentModule); | ||
(0, _mocks.resetMock)(name); | ||
return (0, _plugins.onMockCreate)(new _mock2.default((0, _mocks.getMock)(name))); | ||
if (typeof moduleName === 'function') { | ||
return (0, _plugins.onMockCreate)(new _mock2.default((0, _mocks.getAsyncMock)(moduleName))); | ||
} else { | ||
var name = (0, _plugins.convertName)(moduleName, parentModule); | ||
(0, _mocks.resetMock)(name); | ||
return (0, _plugins.onMockCreate)(new _mock2.default((0, _mocks.getMock)(name))); | ||
} | ||
} | ||
@@ -215,2 +219,4 @@ | ||
}).then(function () { | ||
return _module2.default.probeAsyncModules(); | ||
}).then(function () { | ||
return Promise.resolve(loader()).then(function (mockedResult) { | ||
@@ -217,0 +223,0 @@ restore(); |
@@ -6,3 +6,3 @@ 'use strict'; | ||
}); | ||
exports.resetMock = exports.getAllMocks = exports.getMock = undefined; | ||
exports.resetMock = exports.getAllMocks = exports.getAllAsyncMocks = exports.getAsyncMock = exports.getMock = exports.insertMock = undefined; | ||
@@ -30,4 +30,7 @@ var _path = require('path'); | ||
var insertMock = function insertMock(name, mock) { | ||
return (0, _globals2.default)().mocks[name] = mock; | ||
}; | ||
var resetMock = function resetMock(name) { | ||
return (0, _globals2.default)().mocks[name] = genMock(name); | ||
return insertMock(name, genMock(name)); | ||
}; | ||
@@ -60,4 +63,16 @@ | ||
var getAllMocks = function getAllMocks() { | ||
var result = {}; | ||
var getAsyncMock = function getAsyncMock(creator) { | ||
var scope = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : (0, _globals2.default)(); | ||
var signature = creator.toString(); | ||
var mock = resetMock(signature); | ||
scope.asyncMocks.push({ | ||
mock: mock, | ||
creator: creator, | ||
loaded: false | ||
}); | ||
return mock; | ||
}; | ||
var collectMocks = function collectMocks(result, selector) { | ||
var collect = function collect(scope) { | ||
@@ -67,4 +82,4 @@ if (scope.parentScope) { | ||
} | ||
var mocks = scope.mocks; | ||
Object.keys(scope.mocks).forEach(function (key) { | ||
var mocks = selector(scope); | ||
Object.keys(mocks).forEach(function (key) { | ||
return result[key] = mocks[key]; | ||
@@ -77,4 +92,23 @@ }); | ||
var getAllMocks = function getAllMocks() { | ||
return collectMocks({}, function (scope) { | ||
return scope.mocks; | ||
}); | ||
}; | ||
var getAllAsyncMocks = function getAllAsyncMocks() { | ||
return collectMocks([], function (scope) { | ||
return scope.asyncMocks.filter(function (mock) { | ||
return !mock.loaded; | ||
}); | ||
}).filter(function (mock) { | ||
return !!mock; | ||
}); | ||
}; | ||
exports.insertMock = insertMock; | ||
exports.getMock = getMock; | ||
exports.getAsyncMock = getAsyncMock; | ||
exports.getAllAsyncMocks = getAllAsyncMocks; | ||
exports.getAllMocks = getAllMocks; | ||
exports.resetMock = resetMock; |
@@ -14,2 +14,6 @@ 'use strict'; | ||
var _asyncModules = require('./asyncModules'); | ||
var _asyncModules2 = _interopRequireDefault(_asyncModules); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -29,2 +33,9 @@ | ||
}, | ||
probeAsyncModules: function probeAsyncModules() { | ||
var load = Module._load; | ||
Module._load = _asyncModules2.default.load(this); | ||
return _asyncModules2.default.execute().then(function () { | ||
Module._load = load; | ||
}); | ||
}, | ||
_resolveFilename: function _resolveFilename(fileName, module) { | ||
@@ -31,0 +42,0 @@ return Module._resolveFilename(fileName, module); |
@@ -13,2 +13,3 @@ "use strict"; | ||
mocks: {}, | ||
asyncMocks: [], | ||
@@ -15,0 +16,0 @@ passBy: [], |
{ | ||
"name": "rewiremock", | ||
"version": "2.1.3", | ||
"version": "3.0.0", | ||
"description": "Easy and es6 compatible dependency mocking tool.", | ||
"main": "lib/index.js", | ||
"module": "src/index.js", | ||
"jsnext:main": "es/index.js", | ||
"module": "es/index.js", | ||
"types": "rewiremock.d.ts", | ||
"scripts": { | ||
"test": "npm run test:pick -- '_tests/**/*spec.js'", | ||
"test:pick": "BABEL_ENV=test mocha --compilers js:babel-core/register", | ||
"test:pick": "BABEL_ENV=cjs mocha --compilers js:babel-core/register", | ||
"test:karma": "node ./node_modules/karma/bin/karma start --single-run --browsers PhantomJS", | ||
"test:browser": "node ./node_modules/karma/bin/karma start --browsers Chrome", | ||
"build": "babel src -d lib", | ||
"build": "npm run build5 && npm run build6", | ||
"build5": "BABEL_ENV=cjs babel src -d lib & cp src/index.js.flow lib/index.js.flow", | ||
"build6": "BABEL_ENV=ejs babel src -d es & cp src/index.js.flow es/index.js.flow", | ||
"prepublish": "npm run build", | ||
@@ -20,2 +23,3 @@ "lint": "eslint src tests", | ||
"lib", | ||
"es", | ||
"webpack", | ||
@@ -54,3 +58,3 @@ "rewiremock.d.ts" | ||
"babel-plugin-transform-object-rest-spread": "^6.23.0", | ||
"babel-preset-latest": "^6.16.0", | ||
"babel-preset-env": "1.6.1", | ||
"babel-register": "6.18.0", | ||
@@ -60,2 +64,3 @@ "chai": "^3.5.0", | ||
"eslint-plugin-mocha": "^4.9.0", | ||
"flow-bin": "false0.59.0", | ||
"karma": "^1.7.0", | ||
@@ -62,0 +67,0 @@ "karma-chrome-launcher": "^2.2.0", |
@@ -27,4 +27,4 @@ # rewiremock [![Build Status](https://secure.travis-ci.org/theKashey/rewiremock.svg)](http://travis-ci.org/theKashey/rewiremock) | ||
# Goal: | ||
- give ability to mock everything | ||
- give ability to do correctly. | ||
- give ability to mock everything - CommonJS, ES6, Webpack, anything. | ||
- give ability to do correctly - isolation, typechecks, powerfull API | ||
@@ -37,9 +37,9 @@ I have wrote some articles about these ideas - https://medium.com/tag/rewiremock/latest | ||
- rewiremock.enable() - wipes cache and enables interceptor. | ||
- rewiremock.disable() - wipes cache and disables interceptor. | ||
- rewiremock.inScope(callback) - place callback inside a sandbox. | ||
- rewiremock.around(loader, creator) - loads a module in an asynchronous sandbox. | ||
- rewiremock.proxy(file, stubs) - _proxyquire_ like mocking api, where file is file name, and stubs are an object or a function. | ||
- rewiremock.module(loader, stubs) - async version of proxy, where loader is a function. | ||
- rewiremock.disable() - wipes cache and disables interceptor. | ||
- rewiremock.around(loader, creator):Promise< T > - loads a module in an **asynchronous** sandbox. | ||
- rewiremock.proxy(file, stubs):T - _proxyquire_ like mocking api, where file is file name, and stubs are an object or a function. | ||
- rewiremock.module(loader, stubs):Promise< T > - async version of proxy, where loader is a function. | ||
## mocking API | ||
- rewiremock(moduleName: string) - set name of overloading module | ||
- rewiremock(moduleName: string) - fabric for a moduleNames's mock | ||
- rewiremock(moduleImport: loader) - async fabric for a module import function. | ||
- .enable/disable() - to enable or disable mock (enabled by default). | ||
@@ -57,2 +57,4 @@ - .with(stubs: function | Object) - overloads module with a value | ||
- rewiremock.passBy(pattern or function) - enables some modules to pass thought isolation. | ||
## sandboxing | ||
- rewiremock.inScope(callback) - place synchronous callback inside a sandbox. | ||
@@ -63,11 +65,12 @@ # Which one? | ||
Which one to choose? Any! It just depends: | ||
- If everything is simply - use __proxy__. | ||
- If you have issues with name resolve - use __module__ and resolve names by yourself. | ||
- If you need scope isolation - use __around__. inScope is just creating a scope and can be used in all cases. | ||
- If everything is simply - use __rewiremock.proxy__. | ||
- If you have issues with name resolve - use __rewiremock.module__ and resolve names by yourself. | ||
- If you need scope isolation - use __rewiremock.around__, or inScope. | ||
- If you advanced syntax and type checking - use __rewiremock.around__. | ||
- If you need full control - you will always have it. | ||
- As long all internal API will call __.enable/.disable__ - I would not recommend using them directly. | ||
- You always can just use __.enable/.disable__. | ||
#Usage | ||
```js | ||
// 1. proxy will load a file by it's own ( name resolution is a hard thing) | ||
// 1. proxy will load a file by it's own ( keep in mind - name resolution is a complex thing) | ||
const mock = rewiremock.proxy('somemodule', (r) => ({ | ||
@@ -85,2 +88,3 @@ 'dep1': { name: 'override' }, | ||
// 3. or use es6 import (not for node.js mjs `real` es6 modules) | ||
// PS: module is an async version of proxy, so you can use imports | ||
const mock = await rewiremock.module(() => import('somemodule'), { | ||
@@ -103,2 +107,45 @@ 'dep1': { name: 'override' }, | ||
# Type safety | ||
Rewiremock is able to provide a type-safe mocks. To enable type-safety follow these steps: | ||
1. Use TypeScript or Flow. | ||
2. Use dynamic import syntax. | ||
3. Use rewiremock.around or rewiremock.module to perform a mock. | ||
4. Use async form of rewiremock mock declaration. | ||
```js | ||
// @flow | ||
import rewiremock from 'rewiremock'; | ||
rewiremock.around( | ||
() => import('./a.js'), | ||
mock => { | ||
mock(() => import('./b.js')) | ||
.withDefault(() => "4") | ||
.with({testB: () => 10}) | ||
.nonStrict() // turn off type system | ||
.with({ absolutely: "anything" }) | ||
} | ||
); | ||
``` | ||
If default export is not exists on module 'b', or there is no named export testB, or types do not match - type system will throw. | ||
If you will declare an async mock, you it will not be resolved by the time of execution - Rewiremock will throw on Error. | ||
If you have async imports inside mocked file, follow this syntax | ||
```js | ||
rewiremock.around( | ||
() => import('./a.js'), | ||
mock => { | ||
// just before loader function rewiremock enabled itself | ||
mock(() => import('./b.js').then(mock=>mock)) // mocks `live` one `tick` more | ||
// just after loader function resolved rewiremock disables itself | ||
mock => { | ||
.... | ||
} | ||
} | ||
); | ||
``` | ||
# Setup | ||
@@ -105,0 +152,0 @@ |
@@ -1,132 +0,181 @@ | ||
interface OverloadedModule { | ||
name: String, | ||
fileName: String, | ||
parent: Object, | ||
original: Object, | ||
requireActual: Function | ||
} | ||
declare module 'rewiremock' { | ||
interface ModuleMock { | ||
/** | ||
* Enabled call thought original module | ||
*/ | ||
callThrough(): ModuleMock, | ||
type Plugin = any; | ||
type PluginNames = 'childOnly' | 'nodejs' | 'protectNodeModules' | 'relative' | 'webpackAlias' | 'toBeUsed' | 'disabledByDefault' | 'usedByDefault' | 'directChild'; | ||
type Plugins = { | ||
[Key in PluginNames]: any | ||
}; | ||
/** | ||
* Setting es6 bahavior for a module | ||
*/ | ||
es6(): ModuleMock, | ||
interface OverloadedModule { | ||
name: String, | ||
fileName: String, | ||
parent: Object, | ||
original: Object, | ||
requireActual: Function | ||
} | ||
/** | ||
* Setting es6 behavior for a current module and overriding default export | ||
*/ | ||
withDefault(stubs: any): ModuleMock, | ||
interface BaseMock { | ||
/** | ||
* Enabled call thought original module | ||
*/ | ||
callThrough(): this, | ||
/** | ||
* Overriding export of a module | ||
*/ | ||
with(stubs: any): ModuleMock, | ||
/** | ||
* Setting es6 bahavior for a module | ||
*/ | ||
es6(): this, | ||
/** | ||
* Overriding export of one module by another | ||
*/ | ||
by(module: string): ModuleMock, | ||
/** | ||
* Overriding export of one module by something generated by a function | ||
*/ | ||
by(module: (module: OverloadedModule) => Object): ModuleMock, | ||
/** | ||
* Overriding export of one module by another | ||
*/ | ||
by(module: string): BaseMock, | ||
enable(): ModuleMock, | ||
disable(): ModuleMock, | ||
/** | ||
* Overriding export of one module by something generated by a function | ||
*/ | ||
by(module: (module: OverloadedModule) => Object): BaseMock, | ||
/** | ||
* mocks only first direct children. | ||
*/ | ||
directChildOnly(): ModuleMock; | ||
atAnyPlace(): ModuleMock; | ||
enable(): this, | ||
/** | ||
* mocks only if parent were mocked | ||
*/ | ||
calledFromMock(): ModuleMock; | ||
calledFromAnywhere(): ModuleMock; | ||
/** | ||
* Force mock to be used, or throw an error otherwise | ||
*/ | ||
toBeUsed(): ModuleMock, | ||
disable(): this, | ||
noToBeUsed(): ModuleMock | ||
} | ||
/** | ||
* mocks only first direct children. | ||
*/ | ||
directChildOnly(): this; | ||
type ProxyFunction = (r: ModuleMock) => Object; | ||
type RequireFunction<T>= () => T; | ||
type ImportFunction<T> = () => Promise<T>; | ||
type AnyImportFunction<T> = RequireFunction<T> | ImportFunction<T>; | ||
/** | ||
* @name rewiremock | ||
* @class | ||
* Proxies imports/require in order to allow overriding dependencies during testing. | ||
*/ | ||
interface rewiremock { | ||
(module: string): ModuleMock; | ||
atAnyPlace(): this; | ||
enable(): rewiremock; | ||
disable(): rewiremock; | ||
/** | ||
* mocks only if parent were mocked | ||
*/ | ||
calledFromMock(): this; | ||
/** | ||
* executes module in a sanbox | ||
* @param {Function} loader - loader of target module. You can use import or require. May return a Promise | ||
* @param {Function} [creator] - mock creator. You may add any mocks inside. | ||
*/ | ||
around<T>(loader: AnyImportFunction<T>, creator?: Function): Promise<T>; | ||
inScope(callback: Function): rewiremock; | ||
calledFromAnywhere(): this; | ||
/** | ||
* Loads a file and hooks deps in a `proxyquire` way | ||
* @param {String|Function} fileName | ||
* @param {Object|Function} overrides, with key==filename, and value==data | ||
*/ | ||
proxy<T>(fileName: String | RequireFunction<T>, overrides?: Object | ProxyFunction): T; | ||
/** | ||
* Loads a file and hooks deps in a `proxyquire` way | ||
* @param {Function} fileLoader. Require or Import desired module | ||
* @param {Object} overrides, with key==filename, and value==data | ||
*/ | ||
module<T>(fileLoader: ImportFunction<T>, overrides?: Object | ProxyFunction): Promise<T>; | ||
/** | ||
* Force mock to be used, or throw an error otherwise | ||
*/ | ||
toBeUsed(): this, | ||
flush(): void; | ||
clear(): void; | ||
/** | ||
* converts module name | ||
* @param module | ||
*/ | ||
resolve(module: string): string, | ||
noToBeUsed(): this | ||
} | ||
/** | ||
* Activates module isolation | ||
* @param {Boolean} [options.noAutoPassBy] auto-includes mocked modules passBy list. | ||
*/ | ||
isolation(options?: Object): rewiremock; | ||
interface NamedModuleMock<T> extends BaseMock { | ||
/** | ||
* Overriding export of a module | ||
*/ | ||
with(keys: {[P in keyof T]?: T[P]}): this; | ||
/** | ||
* Deactivates isolation | ||
*/ | ||
withoutIsolation(): rewiremock; | ||
/** | ||
* Washes away the types | ||
*/ | ||
nonStrict(): AnyModuleMock; | ||
} | ||
/** | ||
* Adding new isolationpassby record | ||
*/ | ||
passBy(pattern: any): rewiremock; | ||
interface HasDefault { | ||
default: any | ||
} | ||
interface DefaultModuleMock<T extends HasDefault> extends NamedModuleMock<T> { | ||
/** | ||
* Setting es6 behavior for a current module and overriding default export | ||
*/ | ||
withDefault<Ts extends {[K in keyof Ts]: Ts[K]} & T>(fn: Ts['default']): this; | ||
} | ||
interface AnyModuleMock { | ||
/** | ||
* Setting es6 behavior for a current module and overriding default export | ||
*/ | ||
withDefault(stubs: any): this; | ||
/** | ||
* Overriding export of a module | ||
*/ | ||
with(stubs: any): this; | ||
} | ||
type ModuleMock = AnyModuleMock; | ||
type ProxyFunction = (r: ModuleMock) => Object; | ||
type RequireFunction<T> = () => T; | ||
type ImportFunction<T> = () => Promise<T>; | ||
type AnyImportFunction<T> = RequireFunction<T> | ImportFunction<T>; | ||
/** | ||
* Adds a plugin | ||
* @name rewiremock | ||
* @class | ||
* Proxies imports/require in order to allow overriding dependencies during testing. | ||
*/ | ||
addPlugin(plugin: any): rewiremock; | ||
} | ||
interface rewiremock { | ||
(module: string): ModuleMock; | ||
declare module 'rewiremock' { | ||
<T extends HasDefault>(module: ImportFunction<T>): DefaultModuleMock<T> | ||
<T>(module: ImportFunction<T>): NamedModuleMock<T> | ||
enable(): rewiremock; | ||
disable(): rewiremock; | ||
/** | ||
* executes module in a sanbox | ||
* @param {Function} loader - loader of target module. You can use import or require. May return a Promise | ||
* @param {Function} [creator] - mock creator. You may add any mocks inside. | ||
*/ | ||
around<T>(loader: AnyImportFunction<T>, creator?: (r: rewiremock) => any): Promise<T>; | ||
inScope(callback: Function): rewiremock; | ||
/** | ||
* Loads a file and hooks deps in a `proxyquire` way | ||
* @param {String|Function} fileName | ||
* @param {Object|Function} overrides, with key==filename, and value==data | ||
*/ | ||
proxy<T>(fileName: String | RequireFunction<T>, overrides?: Object | ProxyFunction): T; | ||
/** | ||
* Loads a file and hooks deps in a `proxyquire` way | ||
* @param {Function} fileLoader. Require or Import desired module | ||
* @param {Object} overrides, with key==filename, and value==data | ||
*/ | ||
module<T>(fileLoader: ImportFunction<T>, overrides?: Object | ProxyFunction): Promise<T>; | ||
flush(): void; | ||
clear(): void; | ||
/** | ||
* converts module name | ||
* @param module | ||
*/ | ||
resolve(module: string): string, | ||
/** | ||
* Activates module isolation | ||
* @param {Boolean} [options.noAutoPassBy] auto-includes mocked modules passBy list. | ||
*/ | ||
isolation(options?: Object): rewiremock; | ||
/** | ||
* Deactivates isolation | ||
*/ | ||
withoutIsolation(): rewiremock; | ||
/** | ||
* Adding new isolationpassby record | ||
*/ | ||
passBy(pattern: any): rewiremock; | ||
/** | ||
* Adds a plugin | ||
*/ | ||
addPlugin(plugin: any): rewiremock; | ||
} | ||
var rewiremockdefault: rewiremock; | ||
} | ||
export default rewiremockdefault; | ||
export default rewiremockdefault; | ||
export function addPlugin(plugin:Plugin):void; | ||
export function removePlugins(plugin:Plugin):void; | ||
export var plugins: Plugins; | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
136207
64
3028
459
23
19