angular2 testing using jasmine for subscribe method - unit-testing

I have a spec code to test like this
it('login test', () => {
const fixture = TestBed.createComponent(component);
fixture.detectChanges();
let authService = fixture.debugElement.injector.get(Auth);
spyOn(authService, 'login').and.returnValue('');
const elements = fixture.nativeElement;
fixture.componentInstance.login();
expect(authService.login).toHaveBeenCalled();
});
and the implementation code like this
login() {
this.auth.login(this.username, this.password).subscribe(() => {
}
});
}
it gives error:
this.auth.login(...).subscribe is not a function
Why does this error happen?

You need to return something with a subscribe method, as the component calls subscribe directly from login. A string does not. You could just return an object with a subscribe function and it should work
and.returnValue({ subscribe: () => {} });
Or if you want to pass a real observable, you could
and.returnValue(Observable.of('some value'));
You might need to import rxjs/add/observable/of

On rxjs v6 you should use of instead of Observable.of or Observable.from e.g
const loginService: any = {
getUser: () => of(['Adam West']),
};
and import
import { of } from 'rxjs';

Change your spy for the 'login' method on your authService to return an observable instead of a value. You'll need to import:
import 'rxjs/add/observable/from';
import {Observable} from 'rxjs/Observable';
Setup your spy:
const loginResult = '';
const spy = spyOn(authService, 'login').and.callFake(() => {
return Observable.from([loginResult]);
})
Call login:
fixture.componentInstance.login();
Assert:
expect(spy).toHaveBeenCalled();

Related

React Testing, using axios-mock-adapter

I need to switch out my backend in-memory DB for testing due to memory issues. Below is my code
import { fireEvent, render, screen, waitFor } from "#testing-library/react";
import userEvent from "#testing-library/user-event";
import App from "App";
import axios from "axios";
import MockAdapter from "axios-mock-adapter";
import { AccessLevel, ResponseApi, SystemUserApi } from "types";
let mock: MockAdapter;
beforeAll(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.reset();
});
beforeEach(() => {
jest.resetModules();
});
describe("<App />", () => {
test("login", async () => {
mock.onPost('/Hello').reply(200, getPost);
const result = render(<App />);
const user = userEvent.setup();
const btnLogin = screen.getByText(/Login/i) as HTMLButtonElement;
await userEvent.click(btnLogin);
let btnOk = screen.queryByText(/OK/i) as HTMLButtonElement;
expect(btnOk.disabled).toBe(true);
let btnCancel = screen.getByText(/Cancel/i) as HTMLButtonElement;
expect(btnCancel.disabled).toBe(false);
fireEvent.change(screen.getByLabelText(/Access Code/i) as HTMLInputElement, { target: { value: 'USER' } });
expect(btnOk.disabled).toBe(false);
await userEvent.click(btnOk);
//At this point I was expecting the onPost to be clicked
});
});
function getPost(config: any): any {
console.log(config);
debugger;
return {
data: {
access_code: 'USER'.toUpperCase(),
access_level: AccessLevel.USER ,
lock_level:true
} as SystemUserApi,
error: false,
} as ResponseApi
}
Deep down in the is a call axios post to /Hello but my function within the test is not called. I do not know if it has to do with the actual call being axios.request vs axios.post. I have tried switching to mock.onAny, but that did not seem to work. Not sure what to do here.

How to jest.spyOn mock implementation only for the first call then use default implementation?

I would like to use jest.spyOn to mock the implementation of a method only for the first call. On 2nd 3rd ...nth call want to call it's actual previous implementation.
I tried the below in ts and it is not working:
import handler from '../src/handler';
import * as cRedis from '../src/redis';
jest.spyOn(cRedis, 'rGetAsync');
describe('handle cart quantity validation', () => {
test('test 1 blabla', async () => {
(cRedis.rGetAsync as jest.Mock).mockImplementationOnce(
() =>
new Promise(resolve =>
setTimeout(() => {
resolve('{}');
}, 1000),
),
);
const response = await handler();
});
});
the handler function calls the method rGetAsync of cRedis two times.
just for illustrative example:
handler.ts
import { rGetAsync } from './redis';
export default function () {
const a = await rGetAsync('a');
const b = await rGetAsync('b');
console.log(a, b);
}
My problem is that the mockedImplementation is used in both calls!
So mockImplementationOnce is not really mocking it once.
I expect that for first call to use the mock implementation and second one the real one.
How can I achieve this with jest?
I have used your code and the following test:
import * as cRedis from '../redis';
import handler from '../handler';
describe('handle cart quantity validation', () => {
it('test 1 blabla', async () => {
const spy = jest.spyOn(cRedis, 'rGetAsync');
spy.mockResolvedValueOnce('Not Original')
await handler();
});
});
My redis looks like this:
export const rGetAsync = async () => Promise.resolve('Original implementation');
And my output is:
console.log
Not Original Original implementation
So it works properly.
You can check my post about clear/reset/restore of spies and mocks.

Vue.js unit:test : Is there any way to mock a Vee-Validate validator plugin?

I am testing a form component, all fields are validated with vee-validate
Currently I a injecting in my wrapper mount a validator
import VeeValidate from "vee-validate";
Vue.use(VeeValidate, { errorBagName: "errors" });
describe("ContactForm.vue", () => {
const v = new VeeValidate.Validator();
beforeEach(() => {
options = {
sync: false,
provide: () => ({
$validator: v
})
};
wrapper = shallowMount(ContactForm, options);
});
the $validator has some functions like : init(), localize(), validateAll() , reset(), ... that I could bypass in some of my tests
Is there anyway to mock such validator with Jest functions ?
thanks for feedback
Have you tried to use stubs of your functions using sinon ? They mentioned that on vue test utils with setMethods.
It could look like:
import { mount } from '#vue/test-utils'
import sinon from 'sinon'
import ContactForm from './ContactForm.vue'
const wrapper = mount(ContactForm)
const submit = wrapper.find('button')
const validateStub = sinon.stub()
allInputs.setMethods({ validateAll: validateStub })
submit.trigger('click')
expect(validateStub.called).toBe(true)
So you would be able to know if the validateAll method is called when you submit the form for example. Or you could try asking on github/VeeValidate

Is it possible to use TypeScript with 'aws-sdk-mock'

I'm writing unit tests for a serverless application in TypeScript, and I'd like to mock the AWS SDK.
Unfortunately I have not found many existing type definitions for popular AWS mocking projects. In particular I'd like to use the aws-sdk-mock library, but without its type definitions I can't.
Theoretically I'd like to be able to do something like:
import 'jest';
import * as sinon from 'sinon';
import * as _ from 'lodash';
import { handler } from '../lib/lambda';
import AWSMock from 'aws-sdk-mock';
import { PutItemInput } from 'aws-sdk/clients/dynamodb';
const mockData: DataType = {
// ...some fields
};
describe('create data lambda tests', () => {
afterEach(() => {
sinon.restore();
AWSMock.restore();
});
it('returns a success response on creation', () => {
AWSMock.mock('DynamoDB.DocumentClient', 'put', (params: PutItemInput, callback: any) => {
return callback(null, 'Successful creation');
});
const mockGatewayEvent: any = {
headers: {
Authorization: // some JWT
},
body: _.clone(mockData)
};
handler(mockGatewayEvent).then((createdData: DataType) => {
expect(createdData.id).toBeDefined();
expect(createdData.id.length).toBeGreaterThan(0);
}, () => {
fail('The create request should not have failed');
});
});
});
Here's how we got it working with jest. This tests a lambda function that makes calls to Dynamo using the DynamoDB.DocumentClient.
The warnings about importing the aws-sdk-mock ts definitions go away for me if the file is called *.test.ts or *.spec.ts.
// stubbed.test.ts
// this line needs to come first due to my project's config
jest.mock("aws-sdk");
import * as AWS from "aws-sdk-mock";
import { handler } from "../index";
// these next two are just test data
import { mockDynamoData } from "../__data__/dynamo.data";
import { mockIndexData } from "../__data__/index.data";
describe("Stubbed tests", () => {
it("should return correct result when Dynamo returns one slice", async () => {
expect.assertions(2);
const mockQuery = jest.fn((params: any, cb: any) =>
cb(null, mockDynamoData.queryOneSlice)
);
AWS.mock("DynamoDB.DocumentClient", "query", mockQuery);
// now all calls to DynamoDB.DocumentClient.query() will return mockDynamoData.queryOneSlice
const response = await handler(mockIndexData.handlerEvent, null, null);
expect(mockQuery).toHaveBeenCalled();
expect(response).toEqual(mockIndexData.successResponseOneSlice);
AWS.restore("DynamoDB.DocumentClient");
});
});

vue-test-utils: mocking vue-router and vuex in the same test

I'm trying to mount a component that uses Vuex and requires $route.query to be mocked
import { mount, shallow, createLocalVue } from 'vue-test-utils'
import Vue from 'vue'
import expect from 'expect'
import Vuex from 'vuex'
import VueRouter from 'vue-router'
import Post from '../../components/Post.vue'
const localVue = createLocalVue()
localVue.use(Vuex);
localVue.use(VueRouter);
describe('Lead list', () => {
let wrapper;
let getters;
let store;
beforeEach(() => {
getters = {
post: () => { return {} }
}
store = new Vuex.Store({
getters
});
});
it('should just be true', () => {
const $route = {
path: '/some/path',
query: {}
}
wrapper = shallow(Post, {
localVue,
mocks: {
$route
}, store
});
expect(true).toBe(true);
});
});
And I'm getting back this error
TypeError: Cannot set property $route of #<VueComponent> which has only a getter
I've found the closed issue https://github.com/vuejs/vue-test-utils/issues/142 that has similar error. But my case is a little different. If I remove store or mocks from the options it works fine, but it does't work when you have both. Is this an issue or I'm doing something wrong?
Thanks
You're getting this error because you have installed VueRouter on the Vue constructor, by calling localVue.use(VueRouter). This adds $route as a read only property on the localVue constructor.
You're then trying to overwrite $router using mocks. mocks is unable to overwrite $route because it's been added as a read only property by Vue Router.
To fix your problem, you could create another localVue, install Vuex, and then use mocks to pass in $route:
it('should just be true', () => {
const freshLocalVue = createLocalVue()
freshLocalVue.use(Vuex)
const $route = {
path: '/some/path',
query: {}
}
wrapper = shallow(Post, {
localVue,
mocks: {
$route
},
store
})
expect(true).toBe(true)
})