Tapable.plugin is deprecated. Use new API on `.hooks` instead - javascript

A am trying to build a webpack resolver and the .plugin method code below seems to be deprecated and I can't find the analogous method call using .hooks.
module.exports = class Resolver {
apply(compiler) {
compiler.plugin('module', function (init, callback) {
console.log(init);
return callback();
});
}
}

I believe I found it, this works:
module.exports = class Resolver {
apply(compiler) {
compiler.hooks.module.tapPromise('module', async (init) => {
console.log(JSON.stringify(init));
return init;
});
}
}

Related

Custom webpack resolver plugin change #meow to ./meow.js

I am trying to create a webpack resolver that will convert the import for #meow to the import of ./meow.js. I have some basic code below that shows main imports #meow and the resolver should be converting all require statements to be ./meow.js.
meow.js
module.export = 'meow';
main.js
import meow from '#meow';
console.log(meow);
Resolver.js
module.exports = class Resolver {
apply(compiler) {
compiler.hooks.module.tapPromise('Resolver', async (init, resolveContext) => {
return compiler.doResolve(compiler.hooks.module, init, './meow.js', resolveContext, () => {});
});
}
}
Here's an example I got working with webpack 4.
class Example {
constructor() {
this.name = 'Example';
}
apply(compiler) {
compiler.hooks.resolve.tapPromise(this.name, async (init, context) => {
const callback = () => {};
if (init.request.match('#')) {
init.request = './meow.js'
return compiler.doResolve(compiler.hooks.resolve, init, null, context, callback)
} else {
return callback()
}
})
}
}
module.exports = Example;
I think that it is better to utilize NormalModuleReplacementPlugin to replace all the imports that are matched to some rule.
module.exports = function(env) {
return {
plugins: [
new webpack.NormalModuleReplacementPlugin(/(.*)#meow(\.*)/, function(resource) {
// do what ever mapping
resource.request = resource.request.replace(/#meow/, `meow.js`);
})
]
};
};

Node.js unittest Stubbing Own function

Apologies if this was asked before. Here is the module that I'd like to unittest inside file getStuff.js. I'm having difficulty stubbing theresolveThing module used here.
getStuff.js
const resolveThing = require('./resolveThing.js');
module.exports = async function getStuff(target, stuff) {
const { element, test, other } = resolveThing(target);
try {
return element;
} catch (error) {
throw new Error('Did not work.');
}
};
And here is my attempt at the unittest with stubbing using sinon. However when I try to run this it errors out with TypeError: Cannot stub non-existent own property resolveType. Anyone know how I can get this test to work?
const getStuff = require('../com/getStuff');
const resolveThing = require('../com/resolveThing');
const mochaccino = require('mochaccino');
const { expect } = mochaccino;
const sinon = require('sinon');
describe('com.resolveThing', function() {
beforeEach(function () {
sinon.stub(resolveThing, 'resolveThing').returns({element:'a',test:'b',other:'c'});
});
afterEach(function () {
resolveThing.restore();
});
it('Standard message', function() {
const answer = getAttribute('a','b');
expect(answer).toEqual('a');
});
});
sinon.stub(resolveThing, 'resolveThing').returns({element:'a',test:'b',other:'c'});
resolveThing must be an object and 'resolveThing' must be a function in the object, an exception is thrown if the property is not already a function.
I think this is what's hapning in your case.

Stubing a class call from another function

I have 2 files controller.js and entity.js which interact with each other. I am testing controller.js, and it creates an instance of entity.js (class) and use one of its functions. How can I stub/mock/spy the call and the return of that method?
controller.js
const controller= async (req, res) => {
try {
...
const entity = new Entity({
...
});
const validation = await entity.validate();
...
return res.send()
}
} catch (error) {
return res.send(error)
}
};
Entity.js
class Entity{
constructor() {
...
}
...
async validate() {
...
return response;
}
}
Any idea how to test controller.js using supertest, sinon and chai?
Sinon will happily stub the function. Since it's a class method you just need to be sure to stub the function on the prototype:
const controller = async (req, res) => {
const entity = new Entity();
const validation = await entity.validate();
console.log(validation)
};
class Entity{
constructor() {}
async validate() {
return "real function";
}
}
// stub it
let stub = sinon.stub(Entity.prototype, 'validate')
stub.returns('stubbed function')
controller()
<script src="https://cdnjs.cloudflare.com/ajax/libs/sinon.js/7.1.1/sinon.min.js"></script>
This solution uses Ava (but you should be able to adapt to Mocha easily). However I'm more familiar with testdouble. If you have no success with sinon (I'm sure you will), here's an alternative that you may want to consider.
So if we have burrito.js:
module.exports = class {
eat() {
return '🌯';
}
};
And lunch.js:
var Burrito = require('./burrito');
module.exports = () => (new Burrito()).eat();
Then in your test:
const td = require('testdouble');
const test = require('ava');
test('swap burrito', t => {
td.replace('./burrito', class FakeBurrito {
eat() {
return '🌮';
}
});
const lunch = require('./lunch');
t.is(lunch(), '🌮'); // PASS
t.is(lunch(), '🌯'); // FAIL
});
The key is to require your dependency (a burrito) before your subject under test (your lunch) requires it, so that you have time to fake it.

js jest mock classes and static methods

I wrote mock for my class and everything works, when I test creating instance, but not, when I test static method. How to fix this?
Here is my testing class:
class Order {
async add(items) {
const order = new OrderModel({items});
await order.save();
//...
}
async find(items) {
const query = OrderModel.find({
//condition
});
//...
}
}
My OrderModel mock:
const mockOrderModel = {
save: jest.fn(),
find: jest.fn(),
exec: jest.fn()
};
jest.mock('../order/order.model', () => {
return jest.fn().mockImplementation(() => {
return {
save: mockOrderModel.save,
find: mockOrderModel.find,
exec: mockOrderModel.exec
};
});
});
And tests for both methods:
//WORKS
it('add()', async () => {
await order.add(['']);
expect(OrderModel).toHaveBeenCalledTimes(1);
expect(mockOrderModel.save).toHaveBeenCalledTimes(1);
});
//NOT WORKS
it('find()', async () => {
await order.find(['']);
expect(mockOrderModel.find).toHaveBeenCalledTImes(1);
});
OrderModel.find() method is not called
That's because find on mockOrderModel is defined as a property of an object and not a static method. So basically you're creating a mock object for Order with find property that must be called on an instance. Static method of Order is not mocked. To do so you can try:
Order.find = jest.fn()

Jest.js Mocking a method within a module

I'm testing a generator function with Jest.js but my question is generally about mocking functions within modules.
Foo.js has:-
const Foo = {
callMe() {
return true;
},
callMe2() {
return true;
}
};
export default Foo;
In my Jest test I want Foo.callMe to throw an error but I can't get it to work with Jest mock.
import Foo from '../Foo';
it('fails my generator function', () => {
const gen = myGenFunction();
expect(gen.next().value).toEqual(call(Foo.callMe));
});
The generator function looks something like this:
export function* myGenFunction(action) {
try {
const response = yield call(Foo.callMe);
console.log('Success');
} catch(err) {
console.log('Error!!!');
} finally {
// do something else
}
}
How can I make Foo.callMe throw an error? I've tried a few things, but nothing worked so far.
I have managed to achieve what I wanted by using redux-saga's throw method.
it('fails my generator function', () => {
const error = { message: 'Look see here, an error' };
const gen = myGenFunction();
...
expect(gen.throw(error).value).toEqual(
put(actions.setIsLoading(false)), // action that happens on fail
'gen should yield an Effect put(actions.setIsLoading(false))'
);
});
It's nicely documented here: https://redux-saga.js.org/docs/basics/ErrorHandling.html

Categories