How to mock a #Header request for NestJS unit testing - 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()
});
});
})

Related

VueComponent.mounted : TypeError: Cannot read property 'get' of undefined in mounted hook

I am using jest for unit testing in nuxt js
I have mounted hook like this
async mounted(){
try{
var response = await this.$axios.get("api_url here");
this.result = response.data;
} catch(e){
console.log("Exception: ",e)
}
}
when i do unit test for it my code is . utnit.spec.js
jest.mock("axios", () => ({
get: () => Promise.resolve({ data: [{ val: 1 }] })
}));
import { mount } from '#vue/test-utils';
import file from '../filefile';
import axios from "axios";
describe('file', () => {
test('check comp. working correctly', () => {
var wrapper = mount(file);
afterEach(() => {
wrapper.destroy()
})
})
})
I am getting this warn there and there is no data in the results
Exception: TypeError: Cannot read property 'get' of undefined
at VueComponent.mounted
how do I know what is the problem here, is this I can not access axios in the unit file Is there any specific way to test Axios in mounted hook
The error means that it's this.$axios.get that is not available, not axios.get. The component relies on Axios plugin that is commonly installed in Vue application entry point or Nuxt configuration.
It can be installed for localVue Vue instance in tests, or be supplied directly to the component:
var wrapper = mount(file, { mocks: { $axios: axios } });
Also, the mock will fail if Axios is used as axios() somewhere because default import is expected to be a function:
jest.mock("axios", () => Object.assign(
jest.fn(),
{ get: jest.fn() }
));
axios.get is Jest spy, the implementation is mocked per test depending on the use and isn't limited to hard-coded Promise.resolve({ data: ... }) supplied in the mock.

Angular 2 Test verify API was called

I am creating a service in Angular 2 which should call an API url to retrieve its data.
For unit testing I would like to verify that the service actually calls the API. To do this TDD, the service getPicture method is currently empty:
#Injectable()
export class ImageService {
getPicture(id: string) {
//To be implemented later
}
}
My test is as follows:
describe('ImageService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpModule],
providers: [
ImageService,
{ provide: XHRBackend, useClass: MockBackend }
]
});
});
afterEach(inject([XHRBackend], (mockBackend) => mockBackend.verifyNoPendingRequests()));
describe('getPicture', () => {
it('should call picture API', inject([ImageService, XHRBackend], (service: ImageService, mockBackend) => {
mockBackend.connections.subscribe((connection) => {
expect(connection.request.url).toBe('localhost/some/url/picture');
});
service.getPicture('id');
}));
});
});
Wherever I look, I see code to deal with any incoming requests. However, I can't find anything that will cause a failed test when no request is made.
I could set some variable (request received) to false, set it true in the subscribe block but this feels clumsy and something that should have a proper implementation already.
How can I verify that the/any http request was made?

How to test Angular2's router.navigate?

I've run into missing <router-outlet> messages in other unit tests, but just to have a nice isolated example, I created an AuthGuard that checks if a user is logged in for certain actions.
This is the code:
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
if (!this.authService.isLoggedIn()) {
this.router.navigate(['/login']);
return false;
}
return true;
}
Now I want to write a unit test for this.
This is how I start my test:
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule.withRoutes([
{
path: 'login',
component: DummyComponent
}
])
],
declarations: [
DummyComponent
],
providers: [
AuthGuardService,
{
provide: AuthService,
useClass: MockAuthService
}
]
});
});
I created a DummyComponent that does nothing.
Now my test. Pretend that the service returns false and that it triggers this.router.navigate(['/login']):
it('should not let users pass when not logged in', (): void => {
expect(authGuardService.canActivate(<any>{}, <any>{})).toBe(false);
});
This will throw an exception with "Cannot find primary outlet to load".
Obviously I can use toThrow() instead of toBe(false), but that doesn't seem like a very sensible solution. Since I'm testing a service here, there is no template where I can put the <router-outlet> tag. I could mock the router and make my own navigate function, but then what's the point of RouterTestingModule? Perhaps you even want to check that navigation worked.
I could mock the router and make my own navigate function, but then what's the point of RouterTestingModule? Perhaps you even want to check that navigation worked.
There's no real point. If his is just a unit test for the auth guard, then just mock and spy on the mock to check that it's navigate method was called with the login argument
let router = {
navigate: jasmine.createSpy('navigate')
}
{ provide: Router, useValue: router }
expect(authGuardService.canActivate(<any>{}, <any>{})).toBe(false);
expect(router.navigate).toHaveBeenCalledWith(['/login']);
This is how unit tests should normally be written. To try to test any actual real navigation, that would probably fall under the umbrella of end-to-end testing.
If you want to test the router without mocking it you can just inject it into your test and then spy directly on the navigate method there. The .and.stub() will make it so the call doesn't do anything.
describe('something that navigates', () => {
it('should navigate', inject([Router], (router: Router) => {
spyOn(router, 'navigate').and.stub();
expect(authGuardService.canActivate(<any>{}, <any>{})).toBe(false);
expect(router.navigate).toHaveBeenCalledWith(['/login']);
}));
});
this worked for me
describe('navigateExample', () => {
it('navigate Example', () => {
const routerstub: Router = TestBed.get(Router);
spyOn(routerstub, 'navigate');
component.navigateExample();
});
});
it(`editTemplate() should navigate to template build module with query params`, inject(
[Router],
(router: Router) => {
let id = 25;
spyOn(router, "navigate").and.stub();
router.navigate(["/template-builder"], {
queryParams: { templateId: id }
});
expect(router.navigate).toHaveBeenCalledWith(["/template-builder"], {
queryParams: { templateId: id }
});
}
));
I came up with something like that:
describe('TestComponent', () => {
let component: TestComponent;
let router: Router;
let fixture: ComponentFixture<TestComponent>;
const routerSpy = jasmine.createSpyObj('Router', ['navigate']); // create a router spy
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule
],
declarations: [TestComponent],
providers: [
{ provide: Router, useValue: routerSpy } // use routerSpy against Router
],
}).compileComponents();
}));
beforeEach(() => {
router = TestBed.inject(Router); // get instance of router
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it(`should navigate to 'home' page`, () => {
component.navigateToHome(); // call router.navigate
const spy = router.navigate as jasmine.Spy; // create the navigate spy
const navArgs = spy.calls.first().args[0]; // get the spy values
expect(navArgs[0]).toBe('/home');
});
});
Inspired with angular docs: https://angular.io/guide/testing-components-scenarios#routing-component
I am new to unit testing angular/javascript apps. I needed a way to mock (or spy) for my unit test. The following line is borrowed from Experimenter and helped me TREMENDOUSLY!
const routerSpy = jasmine.createSpyObj('Router', ['navigate']); // create a router spy
I would like to say that I had no idea I could do that with Jasmine. Using that line above, allowed me to then create a spy on that object and verify it was called with the correct route value.
This is a great way to do unit testing without the need to have the testbed and all the ceremony around getting the testing module setup. Its also great because it still allows me to have a fake router object with out the need to stub in all of the parameters, methods, etc etc etc.

Unit testing interceptor (axios)

I use axios for the api calls in my react redux app. I added this interceptor to intercept the response for all the api calls and redirect user to login if the status code is 401.
axios.interceptors.response.use((response) => {
if (response.status === 401) {
browserHistory.push('/login');
}
return response;
});
I am unit testing this and asserting on browserHistory spy to get called but I am not sure why my test keeps failing. I'm kind of stuck after loads of tries and am not able to sort out the issue. I am using moxios for mocking response.
Test
let sandbox;
beforeEach(() => {
moxios.install();
sandbox = sinon.sandbox.create();
});
afterEach(() => {
moxios.uninstall();
sandbox.restore();
});
describe('interceptors', () => {
it('should redirect to login if response status code is 401', (done) => {
moxios.withMock(() => {
sandbox.spy(browserHistory, 'push');
axios.get('/test');
moxios.wait(() => {
const request = moxios.requests.mostRecent();
request.respondWith({
status: 401,
response: {}
}).then(() => {
expect(browserHistory.push).to.have.been.called; // Fails
done();
}).catch(done);
});
});
});
});
Any sort of resources or guide would be really appreciated. I am pretty sure I am missing something here.

State not changing when unit testing VueJS and VueResource

I'm trying to test a service that I've created that makes an API call with vue-resource. The service should make the call and update the component with the new data, however in my tests it doesn't register the updated value. I'm using the same setup as the vue-cli webpack example and have based my auth service off this repo (which unfortunately doesn't have any tests)
my service:
export default {
login(context, creds){
context.$http.post(LOGIN_URL, creds)
.then((response) => {
//do something else here
}, (response) => {
context.error = response.data.error
}
}
}
my test:
import Vue from 'vue'
import VueResource from 'vue-resource'
Vue.use(VueResource)
import Auth from 'src/auth'
describe('Auth', () => {
it('should throw an error on unsuccessful login', (done) => {
//intercept the api call and force an invalid response
Vue.http.interceptors.unshift((request, next) => {
next(request.respondWidth({error: 'some error'}, {status: 401}));
});
const vm = new Vue({
data: {
error: ''
}
}).$mount()
Auth.login(vm, {email: 'test#test.com', pass: 'test'} )
//this always fails
expect(vm.error).to.equal('some error')
//ive also tried:
vm.$nextTick(() => {
expect(vm.error).to.equal('some error')
//done()
});
//undo our interceptor
Vue.http.interceptors.shift()
}
}
When I run the test it fails because it's expecting '' to equal 'some error'.
My suspicions are around the fact that vue-resource is using promises.
After reading through some of the Vue.js tests I found my answer. Instead of using vm.$nextTick I did the following:
setTimeout(function(){
expect(vm.error).to.equal('something')
done()
}, 0)