Change mockimplementation on specific functions within a manual mocked service - testing

I have a service.
export const PostService = jest.fn().mockReturnValue({
findPost: jest.fn().mockResolvedValue(false),
updatePosts: jest.fn().mockResolvedValue(false),
});
I import the service into my (nestjs) test module and mock it.
import { PostService } from '../post.service';
jest.mock('../post.service')
const module: TestingModule = await Test.createTestingModule({
controllers: [PostController],
providers: [PostService]
}).compile();
postService = module.get<PostService>(PostService);
I want to change the implementation of functions inside the mocked postService for different tests.
test('findPost should return false', () => {
postController.getPost() // This calls postService.findPost(), which returns false
})
test('findPost should return true', () => {
// I'm trying to change the implementation here, and then calling the controller
postService.findPost.mockImplementation(() => true) // Error: mockImplementation is not a function
postController.getPost() // This should call postService.findPost() and return true
})
How can I change the implementation of any of the functions inside the mocked service depending on the test cases? For example, if I want to test a service method that throws an error depending on the parameters.
Been testing for two weeks, reading the jest docs, trying jest.doMock, messing around with the factory parameter, and importing the service per test and mocking it per test case. All the examples I could find of changing the mockImplementation per test case is for a single mocked function, not a jest function returning an object that contains multiple functions.

It turns out the solution is simple, all I needed was:
jest.spyOn("service, "method").mockImplementation(() => { implementation... })
This can change the implementation of any mock function in any test cases.

I am usually do it like this
const serviceMock = jest.fn(() => ({
methodMock(): () => { ... }
})
Then, in beforeEach function add this service as a provider
const module: TestingModule = await Test.createTestingModule({
controllers: [MyController],
providers: [
{
provide: MyService,
useValue: serviceMock,
},
],
}).compile();
controller = module.get<MyController>(MyController);
And if i want to do this only for some of the test cases, i just add this code to testcase. If i need to use it in a bunch of test cases, i wrap it in a function

Related

testing method calls in `mounted` lifecycle hook in vue test utils now that `methods` is deprecated and will be removed in next major version

I have the following lifecycle hook in my component:
async mounted () {
await this.fetchTabData()
},
said method calls a decoupled method as the data it requests can be refreshed based on user activity at runtime (ie. switching between "tabs" that each call async data)
In order to get test coverage for the above I wrote the following:
describe('mounted', () => {
test('test', async () => {
const fetchTabData = jest.fn()
wrapper = await shallowMount(Overview, {
store: new Vuex.Store({ ... }),
...
methods: { fetchTabData }
})
expect(fetchTabData).toHaveBeenCalled()
})
})
VTU tells me
[vue-test-utils]: overwriting methods via the methods property is deprecated and will be removed in the next major version. There is no clear migration path for the methods property - Vue does not support arbitrarily replacement of methods, nor should VTU. To stub a complex method extract it from the component and test it in isolation. Otherwise, the suggestion is to rethink those tests.
what is the proposed solution therefore (if there is one/are any), when the given complex method is itself a lifecycle hook?
the below passes my test and the warning no longer appears
[Edit: to clarify, Overview is the component to be tested]
describe('mounted', () => {
test('test', async () => {
const fetchTabData = jest.fn()
Overview.methods.fetchTabData = fetchTabData
wrapper = await shallowMount(Overview, {
store: new Vuex.Store({ ... }),
...
})
expect(fetchTabData).toHaveBeenCalled()
})
})
the same approach should, in theory, work for other instances where the lifecycle hook is calling methods.

Unit Testing the NestJS Routes are defined

I found this question about determine the routes. While the first answer is exactly what I need, and it works
import { Controller, Get, Request } from "#nestjs/common";
import { Request as ExpressRequest, Router } from "express";
#Get()
root(#Request() req: ExpressRequest) {
const router = req.app._router as Router;
return {
routes: router.stack
.map(layer => {
if(layer.route) {
const path = layer.route?.path;
const method = layer.route?.stack[0].method;
return `${method.toUpperCase()} ${path}`
}
})
.filter(item => item !== undefined)
}
}
I want to be able to unit test this.
My end to end test works fine
it('/api (GET) test expected routes', async done => {
const ResponseData = await request(app.getHttpServer())
.get('/api')
.set('Accept', 'application/json');
expect(ResponseData.status).toBe(200);
expect(ResponseData.headers['content-type']).toContain('json');
expect(ResponseData.body.routes.length).toBeGreaterThan(2);
done(); // Call this to finish the test
});
The problem I am having, is how to create and pass the Request part that is needed for the root() call for a unit test. The ExpressRequest is not a class or anything to simply create, and then assign values. It is currently a large definition. I assume there must be an easy way to create one, but I have not found it yet.
You can make use of the #golevelup/ts-jest package to help create mocks of objects. It can take an interface as a generic and return an entire jest mock that is compatible with the type.

How Test with Jest a function in the method "mounted" VueJS

I would to try call a function already mocked. I use vueJS for the frond and Jest as unit test. Below a example of my code. My purpose is to test the call of « anotherFunction". The first test is succeed , not the second.Thanks for help or suggestion
code vueJS:
mounted() {
this.myfunction();
}
methods: {
myfunction() {
this.anotherFunction();
}
}
Jest code:
describe('Home.vue', () => {
let wrapper = null;
const options = {
mocks: {
$t: () => 'some specific text',
},
methods: {
myFunction: jest.fn(),
},
};
it('Should renders Home Component', () => {
// Given
wrapper = shallowMount(Home, options);
// Then
expect(wrapper).toBeTruthy();
});
it('Should call anotherFunction', async (done) => {
// Given
wrapper.vm.anotherFunction = jest.fn().mockResolvedValue([]);
// When
await wrapper.vm.myFunction();
// THIS THE PROBLEM, myFunction is mocked and I can't call the function 'anotherFunction' inside...
// Then
// expect(wrapper.vm.anotherFunction).toHaveBeenCalled();
});
});
I was finding a good way to help you if this test case. So, I thought in something like the chuck code below:
import { mount } from '#vue/test-utils';
describe('Home', () => {
it('method calls test case', () => {
const anotherMethodMock = jest.fn();
wrapper = mount(Home, {
methods: {
anotherMethod: anotherMethodMock
}
});
expect(anotherMethodMock).toHaveBeenCalled();
});
});
But, the Jest threw the following exception:
[vue-test-utils]: overwriting methods via the methods property is deprecated and will be removed in the next major version. There is no clear migration path for themethods property - Vue does not support arbitrarily replacement of methods, nor should VTU. To stub a complex m ethod extract it from the component and test it in isolation. Otherwise, the suggestion is to rethink those tests.
I had the following insight, maybe, in this case, should be better to test the side effect of this anotherMethod calling. What does it change? Is something being shown to the user?
I believe that here we have started from the wrong concept.
I hope that this tip could be useful :)
As suggested by #Vinícius Alonso, We should avoid using methods and setMethods in our test cases because of it's deprecation. But you can still test the mounted lifecycle by mocking the functions that are being called during mount. So you can do something similar to below snippet.
describe('Mounted Lifecycle', () => {
const mockMethodOne = jest.spyOn(MyComponent.methods, 'methodOne');
const mockMethodTwo = jest.spyOn(MyComponent.methods, 'methodTwo');
it('Validate data and function call during mount', () => {
const wrapper = shallowMount(MyComponent);
expect(mockMethodOne).toHaveBeenCalled();
expect(mockMethodTwo).toHaveBeenCalled();
})
})
Do mount/shallowMount inside it only rather putting it outside of it as it was not working in my case. You can checkout more details on it if you want.

Testing a function called on an object with Jest in React Native

EDIT
Current example,
it('CALLED THE canOpenURL FUNCTION', () => {
const wrapper = mount(<ResourceCardComponent {...mockProps} />);
const canOpenURLSpy = jest.spyOn(Linking, 'canOpenURL');
wrapper.find('TouchableOpacity').simulate('click');
expect(canOpenURLSpy).toHaveBeenCalled();
canOpenURLSpy.mockReset();
canOpenURLSpy.mockRestore();
});
Error
expect(jest.fn()).toHaveBeenCalled() Expected mock function to have
been called.
Problem
I am using Jest & Enzyme to test a class made with React Native. This class has a function inside of it that when fired off uses the Linking library to call canOpenUrl and openUrl. I can simulate the click event on the mounted component but I am having trouble knowing how much of this I can actually test.
My goal is to check if Linking.canOpenUrl ever fires off.
Exmaple
The function inside the component looks like this,
onPressLink() {
console.log('HEY THIS FUNCTION FIRED WOOT WOOT');
Linking.canOpenURL(this.props.url).then((supported) => {
if (supported) {
Linking.openURL(this.props.url);
}
});
}
I can simulate this firing off like this,
describe('onPressLink has been called!', () => {
it('It clicks the mock function onPressLink!', (done) => {
const wrapper = mount(<MyComponent {...mockProps} />);
const onPressLink = jest.fn();
const a = new onPressLink();
wrapper.find('TouchableOpacity').first().simulate('click');
expect(onPressLink).toHaveBeenCalled();
done();
});
});
Now that does work, but my goal is to use something like this,
expect(Linking.canOpenUrl).toHaveBeenCalled();
But I keep getting this error,
TypeError: Cannot read property '_isMockFunction' of undefined
Current code that is trying to check if this function is ever fired off. Which is inside the parent function that is clicked with the simulate method,
it('calls canOpenURL', () => {
const wrapper = mount(<MyComponent {...mockProps} />);
const canOpenURL = jest.spyOn(wrapper.instance, 'onPressLink');
wrapper.find('TouchableOpacity').simulate('click');
expect('Linking.canOpenUrl').toHaveBeenCalled();
});
Question
What is the proper way to check to see if Linking.canOpenURL is fired when its parent function is executed?
(Since Jest 19.0.0+)
You can spy on the Linking module methods using jest.spyOn().
(1) Tell jest to spy on the module method:
const spy = jest.spyOn(Linking, 'canOpenURL');
(2) After doing everything you need to test it, check the spy:
expect(spy).toHaveBeenCalled();
(3) Clean up and stop spying on the module method
spy.mockReset();
spy.mockRestore();
If you don't want the tests to use the actual implementation of the methods, you can fake them like this:
jest.spyOn(Linking, 'canOpenURL').mockImplementation(() => Promise.resolve());
Where the function passed to mockImplementation will be whatever you want the method to do when called.
Ref https://facebook.github.io/jest/docs/en/jest-object.html#jestspyonobject-methodname
When using the actual implementation of your module method, which is asynchronous, the promise might not have been resolved by the time you tested it. You need to make sure any promise is resolved in your method implementation before making any assertions on it.
One way to deal with this is using async/await, like so:
it('...', async () => {
// Wait for promise to resolve before moving on
await wrapper.instance().onPressLink();
// make your assertions
expect(...);
});
Another option is using expect().resolves, available since Jest 20.0.0, where you wait for some promise in the argument to expect() to resolve with a value before making an assertion on that value.
expect(somePromiseThatEventuallyResolvesWithValue).resolves.toBe(Value);
I've done in simplest way:
Steps to spy:
Make spy object for original function using jest
Call original function with / without argument(s)
Assert the function which should be called with valid argument(s)
Reset mock
Restore mock
Here is the sample example
DefaultBrowser.ts which is actual class.
import { Linking } from 'react-native';
export const openDefaultBrowser = async url => {
if (await Linking.canOpenURL(url)) {
Linking.openURL(url);
}
};
DefaultBrowser.test.ts which is test case class.
import { openDefaultBrowser } from '../DefaultBrowser';
import { Linking } from 'react-native';
describe('openDefaultBrowser with validate and open url', () => {
it('validate url', async () => {
const spy = jest.spyOn(Linking, 'canOpenURL');
openDefaultBrowser('https://www.google.com');
expect(spy).toBeCalledWith('https://www.google.com');
spy.mockReset();
spy.mockRestore();
});
it('open url', async () => {
const spy = jest.spyOn(Linking, 'openURL');
openDefaultBrowser('https://www.google.com');
expect(spy).toBeCalledWith('https://www.google.com');
spy.mockReset();
spy.mockRestore();
});
});
Hope this helps you.
it('open url', async () => {
jest.spyOn(Linking, 'canOpenURL')
const spy = jest.spyOn(Linking, 'openURL')
openURL(sitePath)
await waitFor(() => {
expect(spy).toHaveBeenCalledWith(sitePath)
})
spy.mockReset()
spy.mockRestore()
})

Test that a value is correctly set before calling an asynchronous service in a component

I'm writing unit tests for an Angular2 app in which a component is calling an asynchronous service when it is initialized in order to load its data. Before loading data, it should set a loading flag to true in order to show a spinner, and then the loading flag is set back to falseonce the data has been retrieved.
ngOnInit() {
this.reloadEmployees(this.filter);
}
reloadEmployees(filter: string) {
this.loading = true;
this.employeeService.getEmployees(filter).subscribe((results: Employee[]) => {
this.employees = results;
this.loading = false;
});
}
Here is how I wrote my test:
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [EmployeeComponent],
imports: [FormsModule, SpinnerModule, ModalModule, TranslateModule.forRoot()],
providers: [
{ provide: EmployeeService, useValue: employeeServiceStub },
]
});
fixture = TestBed.createComponent(EmployeeComponent);
component = fixture.componentInstance;
let employeeService = fixture.debugElement.injector.get(EmployeeService);
spy = spyOn(employeeService, 'getEmployees').and.returnValue(Observable.of(testEmployees));
});
it('should start loading employees when the component is initialized', fakeAsync(() => {
fixture.detectChanges();
expect(component.loading).toEqual(true);
}));
I was expecting the callback from the service to be run only if I call tick() in my test but apparently it is called anyway because component.loadingis already back to false when I check its value. Note that if I comment out the line that sets loading back to false in the callback of the component, the test passes.
Any idea how I should test that?
Rx.Observable.of seems to be synchronous (GitHub issue). That's why fakeAsync wrapper doesn't work with it.
Instead you can use e.g. Observable.fromPromise(Promise.resolve(...)).
In your case:
spy = spyOn(employeeService, 'getEmployees').and.returnValue(
Observable.fromPromise(Promise.resolve(testEmployees)));
Alternatively you can use async scheduler:
import { Scheduler } from 'rxjs/Rx';
...
spy = spyOn(employeeService, 'getEmployees').and.returnValue(
Observable.of(testEmployees, Scheduler.async));
I have prepared a working test sample on Plunkr