Nowadays, it’s not a good practice inlining webpack loaders inside our js
file. Good one is to configure the loader
inside the project’s webpack.config
. However, I have a scenario lately where I’m using a webpack loader ( worker-plugin ) that crashes the build
when configured inside webpack.config
. So to be able to use the loader while waiting for a fix, my only option in my case is to inline it. And it works as I expected if
done this way. Inside my made-up startWorker.js
file, I inlined the loader like this.
import workerUrl from 'worker-plugin/loader!./worker';
const startWorker = () => {
if (!window.SharedWorker) {
return;
}
const worker = new window.SharedWorker(workerUrl);
// more code ....
};
export default startWorker;
startWorker.js
is then referenced inside a React component MyComponent.jsx
…
import React from 'react';
import startWorker from './startWorker';
import ChildComponent from './ChildComponent';
class MyComponent extends React.Component {
componentDidMount() {
// more code ....
startWorker();
}
render () {
return (
<ChildComponent
// more props....
/>
);
// more code ...
}
}
export default MyComponent;
And the component’s unit test…
import React from 'react';
import test from 'tape';
import { shallow } from 'enzyme';
import MyComponent from './MyComponent';
import ChildComponent from './ChildComponent';
const wrapper = shallow(<MyComponent
// props here ...
/>);
test('MyComponent render child test', (t) => {
const actual = wrapper.find(ChildComponent).length;
const expected = 1;
t.deepEqual(actual, expected, 'it should render child');
t.end();
});
// more code ...
Obviously, unit test will fail when run due to the inline webpack loader. Noticed in my unit test, I’m only
interested if the ChildComponent
is rendered or not. Test doesn’t care about what’s going on inside startWorker.js
.
Consequently, I can make my test pass again by mocking startWorker.js
dependency inside MyComponent.jsx
. Using proxyquire, I can cleanly mock
this dependency.
First step is to install proxyquire inside the project.
npm install proxyquire --save-dev
Next is to start mocking the dependency by modifying how MyComponent.jsx
is referenced inside unit test. It should look like this.
import proxyquire from 'proxyquire';
import React from 'react';
import test from 'tape';
import { shallow } from 'enzyme';
import ChildComponent from './ChildComponent';
proxyquire.noCallThru();
const { WrappedComponent: MyComponent } = proxyquire('./MyComponent', { './startWorker': () => {} }).default;
const wrapper = shallow(<MyComponent
// props here ...
/>);
test('MyComponent render child test', (t) => {
const actual = wrapper.find(ChildComponent).length;
const expected = 1;
t.deepEqual(actual, expected, 'it should render child');
t.end();
});
// more code ...
Noticed that I’m not directly referencing MyComponent.jsx
inside the unit test file. I’m passing it as a parameter inside proxyquire.
Also I’m directing proxyquire to mock the dependency startWorker.js
inside MyComponent.jsx
file as an empty/noop function.
Running unit test this time will pass as expected. However, webpack
build may fail depending on your setup. In my case,
it did failed. Mainly because of this known issue, https://github.com/thlorenz/proxyquire/issues/62. To work around, we need to able to configure webpack to exclude all references (import) with proxyquire
. With that said, I added an ignore plugin on my webpack.config
.
plugins: [
// more plugins......
new webpack.IgnorePlugin({ resourceRegExp: /proxyquire$/ }),
]
Webpack build should go through without a problem this time. If you have another solution to this issue, please let me know. Thank you for reading.