Test Jest and NestJs - unit-testing

I have a service (in Nestjs) and I want test the function exception whit Jest.
My service:
class MyService{
public throwError(ms: string) {
throw new UnprocessableEntityException(ms);
}
}
And I want test it, but I don't know how to do it.

I feel like jest's docs point this out pretty well, but as a quick example, for the above code you'd just need something simple like
describe('MyuService', () => {
describe('throwError', () => {
it('should throw an UnprocessableEntityException', () => {
const myService = new MyService();
expect(
() => myService.throwError('some string')
).toThrow(new UnprocessableEntityException('some string'));
})
})
})
For even more examples, there's a git repo here with a lot of different samples from rxjs to typeorm to graphql, sync and async

Related

How to mock a #Header request for NestJS unit testing

I am attempting to implement unit testing in NestJS. However, I am new to both NestJS and unit testing in general.
So, what I need to do is to pass a test that gets all projects from a gitlab profile.
#Get()
getProjects(#Headers() headers: any): Observable<Project[]> {
if (!headers.token) {
throw new HttpException('Missing User Token', HttpStatus.BAD_REQUEST);
}
return this.projectsService.listProjects(headers.token);
}
This is the code in the project.controller.ts file. It works well, and returns an observable with the list of projects. However, it requires a header to be sent through the HTTP request(Which is received using the #Headers decorator), as the gitlab is locked behind an authentication that requires a token to be passed through the header of the request.
I have attempted to mock the header to no success, and I was wondering if anyone has any idea how to proceed with the unit testing for that get request.
You don't need anything special here. In your unit test, you just need to pass an object with a token property to your method call.
describe('SomeController', () => {
let controller: SomeController;
let service: jest.Mocked<SomeService>;
beforeAll(async () => {
const modRef = await Test.createTestingModule({
controllers: [SomeController],
providers: [{
provide: SomeService,
useValue: {
method: jest.fn(() => of('value'))
}
}]
}).compile();
controller = modRef.get(SomeController)
service = modRef.get<jest.Mocked<SomeService>>(SomeService)
});
it('getProjects', (done) => {
controller.getProejcts({ token: 'hey look! a token'}).subscribe({
next: (val) => expect(val).toBe('value'),
error: (err) => { throw err; }
complete: () => done()
});
});
})

How to run jest test inside other test block?

For example I have 2 test, how can I test one depend on another one?
Sometimes, we want to have some E2E test, which could reproduce same test steps.
What I think right now is using separate function for testing, but if there is a quick way to run other test with one statement which would be great.
test('test1', () => {
})
test('test2', () => {
// run test1 here
})
What I understand from your comment on another answer is: You want to share part of a test just for some specific tests.
To do this you can use the beforeEach and beforeAll functions inside a describe block.
See my example:
describe('some module', () => {
it('should test something awesome', () => {
// My test 1
})
it('should test something awesome', () => {
// My test 2
})
describe('something specific or tests that are related to each other', () => {
beforeEach(() => {
// code that runs for each tests within this describe block
})
it('should test something awesome', () => {
// My test 3
})
it('should test something awesome', () => {
// My test 4
})
})
})
I don't know if I understood your question very well.
What I understood was that you have some steps that we need to write to all tests right?
I think that you can use the beforeEach or beforeAll function to not repeat this code. But is always good that your test to transmit everything that do you need to create the senary.
Tests should work as a document as well!

Mocking BsModalRef for Unit Testing

I am using the BsModalRef for showing modals and sending data using the content property. So we have some like this :
this.followerService.getFollowers(this.bsModalRef.content.channelId).subscribe((followers) => {
this.followerList = followers;
this.followerList.forEach((follower) => {
follower.avatarLink = this.setUserImage(follower.userId);
this.followerEmails.push(follower.email);
});
});
We are setting the channelId in content of bsModalRef (this.bsModalRef.content.channelId). It is working fine. Now i am writing a unit test for this. Problem is i am not able to mock it. I have tried overriding, spy etc but nothing seems to work. I am using the approach mentioned in this link. One alternative is to use TestBed but i am not much aware of its use. Can anyone please help me finding any approach by which this can be achieved ?
I recently had to do something similar and Mocking the method call worked. The tricky part is injecting the BsModalService in both the test suite and the component.
describe('MyFollowerService', () => {
configureTestSuite(() => {
TestBed.configureTestingModule({
imports: [...],
declarations: [...],
providers: [...]
}).compileComponents();
});
// inject the service
beforeEach(() => {
bsModalService = getTestBed().get(BsModalService);
}
it('test', () => {
// Mock the method call
bsModalService.show = (): BsModalRef => {
return {hide: null, content: {channelId: 123}, setClass: null};
};
// Do the test that calls the modal
});
});
As long as you're calling bsModal as follows this approach will work
let bsModalRef = this.modalService.show(MyChannelModalComponent));
Finally, here are some links that have more indepth coverage about setting up the tests with TestBed.
https://chariotsolutions.com/blog/post/testing-angular-2-0-x-services-http-jasmine-karma/
http://angulartestingquickstart.com/
https://angular.io/guide/testing

React Native: Jest mocking Platform

When writing unit tests for a React Native project I want to be able to test different snapshots based on different platforms.
I first tried jest.mock to mock Platform but seems to be async. This approach does work when I have two separate files, but I'd prefer to keep everything in one file if possible.
I tried jest.doMock because of this snippet from the documentation:
When using babel-jest, calls to mock will automatically be hoisted to the top of the code block. Use this method if you want to explicitly avoid this behavior.
https://facebook.github.io/jest/docs/en/jest-object.html#jestdomockmodulename-factory-options
However I'm still seeing undesirable results. When I console.log in the android test I see that Platform.OS is whatever I set the first doMock to be.
I also tried wrapping the mock in a beforeEach in a describe becasue I thought that might help with scoping
http://facebook.github.io/jest/docs/en/setup-teardown.html#scoping
describe('ios test', () => {
it('renders ui correctly', () => {
jest.doMock('Platform', () => {
const Platform = require.requireActual('Platform');
Platform.OS = 'ios';
return Platform;
});
const wrapper = shallow(<SomeComponent />);
const tree = renderer.create(wrapper).toJSON();
expect(tree).toMatchSnapshot();
});
});
describe('android test', () => {
it('renders ui correctly', () => {
jest.doMock('Platform', () => {
const Platform = require.requireActual('Platform');
Platform.OS = 'android';
return Platform;
});
const wrapper = shallow(<SomeComponent />);
const tree = renderer.create(wrapper).toJSON();
expect(tree).toMatchSnapshot();
});
});
Any ideas on how I can change the mock Platform for tests in the same file?
There are a lot of suggestions on how to solve this problem in another question, but none of them worked for me either, given the same requirements you have (tests for different OSs in the same suite file and in one test run).
I eventually worked around it with a somewhat clunky trivial helper function that can be mocked as expected in tests – something like:
export function getOS() {
return Platform.OS;
}
Use it instead of Platform.OS in your code, and then simply mock it in your tests, e.g.
it('does something on Android', () => {
helpers.getOS = jest.fn().mockImplementationOnce(() => 'android');
// ...
}
That did the trick; credit for the idea is due to this guy.

How to unit test API calls with mocked fetch() in react-native with Jest

In React Native I use fetch to perform network requests, however fetch is not an explicitly required module, so it is seemingly impossible to mock in Jest.
Even trying to call a method which uses fetch in a test will result in:
ReferenceError: fetch is not defined
Is there a way to test such API requests in react native with Jest?
Inside your test case you can mock any function you want by using Jest's mocks:
fetch = jest.fn(() => Promise.resolve());
This approach works only for the promise-based test cases (see pit in the Jest docs).
As far as fetch is an async function, you need to run all your tests using pit (read more about async tests here).
Another approach where you mock the global fetch object:
const mockSuccesfulResponse = (
status = 200,
method = RequestType.GET,
returnBody?: object
) => {
global.fetch = jest.fn().mockImplementationOnce(() => {
return new Promise((resolve, reject) => {
resolve({
ok: true,
status,
json: () => {
return returnBody ? returnBody : {};
},
});
});
});
};
The above helper method can be modified any way you want :-) Hope it helps someone
Rather than rolling your own mock, you can use the jest-fetch-mock npm package to override the global fetch object. That package allows you to set up fake responses and verify sent requests. See that link for extensive usage examples.
I solved this by adding isomorphic-fetch.
$ npm install --save isomorphic-fetch
and using it like
import fetch from 'isomorphic-fetch';
...
fetch('http://foo.com');
whatwg-fetch might work as well
Suppose you want to test resolve and reject cases, for this first you mock the fetch behaviour and then use Jest's rejects and resolves methods with with assertion block
function fetchTodos() {
return fetch(`${window.location.origin}/todos.json`)
.then(response => response.json())
.catch(error => console.log(error))
}
describe('fetchTodos', () => {
it('returns promise resolving to parsed response', () => {
global.fetch = jest.fn(() => Promise.resolve({ json: () => ''}))
expect(fetchTodos()).resolves.toBe('');
})
it('returns promise handling the error', async () => {
global.fetch = jest.fn(() => Promise.reject(''))
expect(fetchTodos()).rejects.toBe('')
})
})
As #ArthurDenture recommended, you can use fetch-mock, but there are some additional packages you will need to install to make it work with React Native and Jest:
$ npm install --save-dev fetch-mock
$ npm install --save-dev babel-plugin-transform-runtime
$ npm install --save-dev babel-preset-env
You can then mock fetch requests in your tests. Here is an example:
// __tests__/App.test.js
import React from 'react';
import App from '../App';
import fetchMock from 'fetch-mock';
import renderer from 'react-test-renderer';
it('renders without crashing', () => {
fetchMock.mock('*', 'Hello World!');
const rendered = renderer.create(<App />).toJSON();
expect(rendered).toBeTruthy();
});
Due to problems using fetch-mock with jest, I've release fetch-mock-jest. It basically gives the full fetch-mock api, but with a few jest-specific helpers, and works out of the box with jest, without needing to do any tricky wiring yourself
As shown in the react-testing-library documentation, you can use the jest.spyOn() function, which will mock the fetch function only for the next time it is called.
const fakeUserResponse = {token: 'fake_user_token'}
jest.spyOn(window, 'fetch').mockImplementationOnce(() => {
return Promise.resolve({
json: () => Promise.resolve(fakeUserResponse),
})
})
react-testing-library