Skip to content

Commit 55e0239

Browse files
committed
v3 Add Async modules and type checking
1 parent 4245f22 commit 55e0239

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+2381
-202
lines changed

.babelrc

+36-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,38 @@
11
{
2-
"presets": ["latest"],
3-
"plugins": [
4-
["transform-object-rest-spread", { "useBuiltIns": true }],
5-
"dynamic-import-node"
6-
]
2+
"presets": [],
3+
"env": {
4+
"cjs": {
5+
"presets": [
6+
"env"
7+
],
8+
"plugins": [
9+
[
10+
"transform-object-rest-spread",
11+
{
12+
"useBuiltIns": true
13+
}
14+
],
15+
"dynamic-import-node"
16+
]
17+
},
18+
"ejs": {
19+
"presets": [
20+
[
21+
"env",
22+
{
23+
"modules": false
24+
}
25+
]
26+
],
27+
"plugins": [
28+
[
29+
"transform-object-rest-spread",
30+
{
31+
"useBuiltIns": true
32+
}
33+
],
34+
"dynamic-import-node"
35+
]
36+
}
37+
}
738
}

.flowconfig

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[ignore]
2+
3+
[include]
4+
5+
[libs]
6+
7+
[lints]
8+
9+
[options]
10+
11+
[strict]

README.md

+60-13
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,22 @@ and magic of [proxyquire-webpack-alias](https://github.com/theKashey/proxyquire-
2424
- be fast, to be faster.
2525

2626
# Goal:
27-
- give ability to mock everything
28-
- give ability to do correctly.
27+
- give ability to mock everything - CommonJS, ES6, Webpack, anything.
28+
- give ability to do correctly - isolation, typechecks, powerfull API
2929

3030
I have wrote some articles about these ideas - https://medium.com/tag/rewiremock/latest
3131

3232
# API
3333

3434
## main API
3535
- rewiremock.enable() - wipes cache and enables interceptor.
36-
- rewiremock.disable() - wipes cache and disables interceptor.
37-
- rewiremock.inScope(callback) - place callback inside a sandbox.
38-
- rewiremock.around(loader, creator) - loads a module in an asynchronous sandbox.
39-
- rewiremock.proxy(file, stubs) - _proxyquire_ like mocking api, where file is file name, and stubs are an object or a function.
40-
- rewiremock.module(loader, stubs) - async version of proxy, where loader is a function.
36+
- rewiremock.disable() - wipes cache and disables interceptor.
37+
- rewiremock.around(loader, creator):Promise< T > - loads a module in an **asynchronous** sandbox.
38+
- rewiremock.proxy(file, stubs):T - _proxyquire_ like mocking api, where file is file name, and stubs are an object or a function.
39+
- rewiremock.module(loader, stubs):Promise< T > - async version of proxy, where loader is a function.
4140
## mocking API
42-
- rewiremock(moduleName: string) - set name of overloading module
41+
- rewiremock(moduleName: string) - fabric for a moduleNames's mock
42+
- rewiremock(moduleImport: loader) - async fabric for a module import function.
4343
- .enable/disable() - to enable or disable mock (enabled by default).
4444
- .with(stubs: function | Object) - overloads module with a value
4545
- .withDefault(stub: function | Object) - overload `default` es6 export
@@ -52,20 +52,23 @@ I have wrote some articles about these ideas - https://medium.com/tag/rewiremock
5252
- rewiremock.isolation() - enables isolation
5353
- rewiremock.withoutIsolation() - disables isolation
5454
- rewiremock.passBy(pattern or function) - enables some modules to pass thought isolation.
55+
## sandboxing
56+
- rewiremock.inScope(callback) - place synchronous callback inside a sandbox.
5557

5658
# Which one?
5759
Yep - there is 4 top level ways to activate a mock - inScope, around, proxy or just enable.
5860

5961
Which one to choose? Any! It just depends:
60-
- If everything is simply - use __proxy__.
61-
- If you have issues with name resolve - use __module__ and resolve names by yourself.
62-
- If you need scope isolation - use __around__. inScope is just creating a scope and can be used in all cases.
62+
- If everything is simply - use __rewiremock.proxy__.
63+
- If you have issues with name resolve - use __rewiremock.module__ and resolve names by yourself.
64+
- If you need scope isolation - use __rewiremock.around__, or inScope.
65+
- If you advanced syntax and type checking - use __rewiremock.around__.
6366
- If you need full control - you will always have it.
64-
- As long all internal API will call __.enable/.disable__ - I would not recommend using them directly.
67+
- You always can just use __.enable/.disable__.
6568

6669
#Usage
6770
```js
68-
// 1. proxy will load a file by it's own ( name resolution is a hard thing)
71+
// 1. proxy will load a file by it's own ( keep in mind - name resolution is a complex thing)
6972
const mock = rewiremock.proxy('somemodule', (r) => ({
7073
'dep1': { name: 'override' },
7174
'dep2': r.with({name: 'override' }).toBeUsed().directChildOnly() // use all `mocking API`
@@ -78,6 +81,7 @@ const mock = rewiremock.proxy(() => require('somemodule'), {
7881
}));
7982

8083
// 3. or use es6 import (not for node.js mjs `real` es6 modules)
84+
// PS: module is an async version of proxy, so you can use imports
8185
const mock = await rewiremock.module(() => import('somemodule'), {
8286
'dep1': { name: 'override' },
8387
'dep2': { onlyDump: 'stubs' }
@@ -95,6 +99,49 @@ const mock = await rewiremock.around(() => import('somemodule'), () => {
9599
rewiremock.disable();
96100
```
97101

102+
# Type safety
103+
Rewiremock is able to provide a type-safe mocks. To enable type-safety follow these steps:
104+
1. Use TypeScript or Flow.
105+
2. Use dynamic import syntax.
106+
3. Use rewiremock.around or rewiremock.module to perform a mock.
107+
4. Use async form of rewiremock mock declaration.
108+
109+
```js
110+
// @flow
111+
112+
import rewiremock from 'rewiremock';
113+
114+
rewiremock.around(
115+
() => import('./a.js'),
116+
mock => {
117+
mock(() => import('./b.js'))
118+
.withDefault(() => "4")
119+
.with({testB: () => 10})
120+
.nonStrict() // turn off type system
121+
.with({ absolutely: "anything" })
122+
}
123+
);
124+
```
125+
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.
126+
127+
If you will declare an async mock, you it will not be resolved by the time of execution - Rewiremock will throw on Error.
128+
129+
If you have async imports inside mocked file, follow this syntax
130+
```js
131+
rewiremock.around(
132+
() => import('./a.js'),
133+
mock => {
134+
// just before loader function rewiremock enabled itself
135+
mock(() => import('./b.js').then(mock=>mock)) // mocks `live` one `tick` more
136+
// just after loader function resolved rewiremock disables itself
137+
mock => {
138+
....
139+
}
140+
}
141+
);
142+
```
143+
144+
98145
# Setup
99146

100147
## To run with node.js

_tests/lib/typed/a-delayed.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// @flow
2+
let a=42;
3+
4+
import('./b.js').then(t => a=t.default());
5+
6+
export default () => a;

_tests/lib/typed/a.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// @flow
2+
3+
import test from './b.js';
4+
5+
export default () => test();

_tests/lib/typed/b.js

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// @flow
2+
export default () => 10;

_tests/typedImport.spec.js

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// @flow
2+
3+
import { expect } from 'chai';
4+
import rewiremock from '../src/index';
5+
6+
describe('typed import ', () => {
7+
it('should throw: ', () => {
8+
rewiremock.inScope(() => {
9+
rewiremock(() => import('./lib/typed/b.js')).with(() => 42);
10+
rewiremock.enable();
11+
try {
12+
require('./lib/typed/a.js');
13+
expect("should throw").to.be.false();
14+
} catch (e) {
15+
expect(true).to.be.equal(true);
16+
}
17+
rewiremock.disable();
18+
});
19+
});
20+
21+
it('import as a mock name: ', () => {
22+
const unmockedBaz = require('./lib/typed/a.js');
23+
expect(unmockedBaz.default()).to.be.equal(10);
24+
25+
const mockedBazLoad = rewiremock.around(
26+
() => import('./lib/typed/a.js'),
27+
mock => {
28+
mock(() => import('./lib/typed/b.js')).with(() => 42).toBeUsed();
29+
});
30+
31+
return mockedBazLoad.then(mockedBaz => {
32+
expect(mockedBaz.default()).to.be.equal(42)
33+
})
34+
});
35+
36+
describe('import delayed: ', () => {
37+
it('import after: ', () => {
38+
const mockedBazLoad = rewiremock.around(
39+
() => import('./lib/typed/a-delayed.js'),
40+
mock => {
41+
mock(() => import('./lib/typed/b.js')).with(() => 0);
42+
});
43+
44+
return mockedBazLoad.then(mockedBaz => {
45+
expect(mockedBaz.default()).not.to.be.equal('aa')
46+
})
47+
});
48+
49+
it('import before: ', () => {
50+
return rewiremock.around(
51+
() =>
52+
import('./lib/typed/a-delayed.js')
53+
.then(module => module) // emulate time tick
54+
.then(mockedBaz => {
55+
expect(mockedBaz.default()).to.be.equal(5)
56+
}),
57+
mock => {
58+
mock(() => import('./lib/typed/b.js')).with(() => 5);
59+
});
60+
});
61+
});
62+
});

es/_common.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
var extensions = ['', '.js', '.jsx'];
2+
3+
var magicProps = ['__esModule'];
4+
5+
export { extensions, magicProps };

es/asyncModules.js

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { getAllAsyncMocks, insertMock } from "./mocks";
2+
3+
var currentModule = void 0;
4+
5+
var loadInRoll = function loadInRoll(mocks) {
6+
if (mocks.length) {
7+
currentModule = mocks[0];
8+
return Promise.resolve().then(currentModule.creator).then(function () {
9+
return loadInRoll(mocks.slice(1));
10+
});
11+
} else {
12+
return Promise.resolve();
13+
}
14+
};
15+
16+
var probeAsyncModules = {
17+
hasAsyncModules: function hasAsyncModules() {
18+
var mocks = getAllAsyncMocks();
19+
return mocks.length ? mocks : false;
20+
},
21+
22+
23+
load: function load(Module) {
24+
return function (request, parent) {
25+
currentModule.loaded = true;
26+
var baseRequest = Module._resolveFilename(request, parent);
27+
currentModule.mock.name = baseRequest;
28+
insertMock(baseRequest, currentModule.mock);
29+
};
30+
},
31+
32+
execute: function execute() {
33+
var mocks = getAllAsyncMocks();
34+
return loadInRoll(mocks);
35+
}
36+
};
37+
38+
export default probeAsyncModules;

0 commit comments

Comments
 (0)