I would to understand how can i test my "auth/refresh" action in the "beforeCreate" hook with jest like below :
// main.vue
async beforeCreate() {
let authTokenRefreshIntervalId;
await this.$store.dispatch('auth/initialize');
authTokenRefreshIntervalId = setInterval(() => {
this.$store.dispatch('auth/refresh').catch(() => {
this.$store.dispatch('auth/logout');
clearInterval(authTokenRefreshIntervalId);
});
}, 30 * 1000);
}
// main.spec.js
import Vue from 'vue';
import Vuex from 'vuex';
import { shallow, createLocalVue, mount } from '#vue/test-utils';
import Main from '#/main';
const localVue = createLocalVue();
jest.useFakeTimers();
describe('store-auth', () => {
let store;
let actions;
let getters;
beforeEach(() => {
actions = {
initialize: jest.fn(),
refresh: jest.fn(),
logout: jest.fn(),
};
getters = {
isAuthenticated: jest.fn(),
};
store = new Vuex.Store({
modules: {
auth: {
namespaced: true,
actions,
getters,
},
},
});
});
it('dispatch initialize on beforeCreate hook', () => {
const wrapper = shallow(Main, { store, localVue });
expect(actions.initialize).toHaveBeenCalled();
});
it('dispatch refresh on beforeCreate hook every 30s', () => {
const wrapper = shallow(Main, { store, localVue });
jest.runTimersToTime(30 * 1000);
expect(actions.refresh).toHaveBeenCalled();
});
});
Jest say that the mocked function is not called.
I tried with expect(setInterval).toHaveBeenCalled() and it pass the test.
Where i'm wrong plz ?
Try using async/await in your test also.
it('dispatch refresh on beforeCreate hook every 30s', async () => {
const wrapper = shallow(Main, { store, localVue });
jest.runTimersToTime(30 * 1000);
await expect(actions.refresh).toHaveBeenCalled();
});
Related
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.
I'm having trouble unit testing a prisma.service.ts file:
import { INestApplication, Injectable } from '#nestjs/common';
import { PrismaClient } from '#prisma/client';
#Injectable()
export class PrismaService extends PrismaClient {
async enableShutdownHooks(app: INestApplication) {
this.$on('beforeExit', async () => {
await app.close();
});
}
}
The prisma.service.spec.ts I have currently looks like this:
import { INestApplication } from '#nestjs/common';
import { NestFastifyApplication } from '#nestjs/platform-fastify';
import { Test, TestingModule } from '#nestjs/testing';
import { PrismaService } from './prisma.service';
const MockApp = jest.fn<Partial<INestApplication>, []>(() => ({
close: jest.fn(),
}));
describe('PrismaService', () => {
let service: PrismaService;
let app: NestFastifyApplication;
beforeEach(async () => {
app = MockApp() as NestFastifyApplication;
const module: TestingModule = await Test.createTestingModule({
providers: [PrismaService],
}).compile();
service = module.get<PrismaService>(PrismaService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
describe('enableShutdownHooks', () => {
it('should call $on and successfully close the app', async () => {
const spy = jest.spyOn(PrismaService.prototype, '$on')
.mockImplementation(async () => {
await app.close();
});
await service.enableShutdownHooks(app);
expect(spy).toBeCalledTimes(1);
expect(app.close).toBeCalledTimes(1);
spy.mockRestore();
});
});
});
However, this does not test line 8 of prisma.service.ts:
await app.close();
because I am mocking the implementation of this.$on('beforeExit', callback), with a copy of its original implementation.
Even if I don't mock it, app.close() never gets called.
Is there a way to test this line?
Could you try using a callback:
jest
.spyOn(service, '$on')
.mockImplementation(async (eventType, cb) => cb(() => Promise.resolve()))
await service.enableShutdownHooks(app);
expect(service.$on).toBeCalledTimes(1);
That allows you to use the callback to invoke the function where await app.close() is located.
i have this bootstrap vue component:
<b-form-input
v-model="currentUser.name"
placeholder="Name *"
name="name"
#input="checkSubmitStatus()"
></b-form-input>
checkSubmitStatus in the methods goes to call updateSubmitDisabled which I have in the mutations inside another file:
methods: {
...mapMutations({
updateSubmitDisabled: "updateSubmitDisabled"
}),
checkSubmitStatus() {
const isDisabled = this.currentUser.name.length === 0;
this.updateSubmitDisabled(isDisabled);
}
}
this is the .spec.js file:
import { createLocalVue, mount } from "#vue/test-utils";
import Vue from "vue";
import Vuex from 'vuex';
import UserForm from "#/components/event-created/UserForm.vue";
import { BootstrapVue, BootstrapVueIcons } from "bootstrap-vue";
const localVue = createLocalVue();
localVue.use(BootstrapVue);
localVue.use(BootstrapVueIcons);
localVue.use(Vuex);
describe("UserForm.vue", () => {
let mutations;
let store;
beforeEach(() => {
mutations = {
updateSubmitDisabled: jest.fn()
};
store = new Vuex.Store({
state: {
currentUser: {
name: 'pippo',
}
},
mutations
});
})
it("should call the updateSubmitDisabled mutation", async () => {
const wrapper = mount(UserForm, { localVue, store });
const input = wrapper.get('input[name="name"]');
await Vue.nextTick();
input.element.value = 'Test';
await input.trigger('input');
await Vue.nextTick();
expect(mutations.updateSubmitDisabled).toHaveBeenCalled();
});
});
for now I just want to test if "updateSubmitDisabled" is called on "name" but as a result the test says:
Expected number of calls:> = 1
Received number of calls: 0
I finally settled with:
it("should call the updateSubmitDisabled mutation", () => {
const wrapper = mount(UserForm, { localVue, store });
const input = wrapper.get('input[name="name"]');
input.element.dispatchEvent(new Event('input'));
expect(mutations.updateSubmitDisabled).toHaveBeenCalled();
});
I need help adding unit test to the function below in NestJs.
I have a class with a createOrder function as shown below. the constructor of the class injects an Entity Manager. How can I test for the createOrder function in jest.
import { Injectable } from '#nestjs/common';
import * as shortId from 'shortid';
import { EntityManager, Repository } from 'typeorm';
import { HttpException, HttpStatus } from '#nestjs/common';
import { Service } from 'models/service.model';
#Injectable()
export class OrderService {
private readonly orderRepository: Repository<Service>;
constructor(private readonly entityManager: EntityManager) {
this.orderRepository = entityManager.getRepository(Service);
}
async createOrder(data) {
const orderService = new Service();
orderService.id = shortId.generate(); // just to generate a string for id
const orderServiceData = Object.assign(orderService, data);
try {
await this.orderRepository.save(orderServiceData);
return { success: true };
} catch (err) {
throw new HttpException('Post not found', HttpStatus.NOT_FOUND);
}
}
}
This is what I have tried so far. Yet it fails to call the save function
import { Test, TestingModule } from '#nestjs/testing';
import { OrderService } from './order_service.service';
import { Service } from '../../models/service.model';
import { Repository, EntityManager, getRepository } from 'typeorm';
import { getRepositoryToken } from '#nestjs/typeorm';
describe('Order Service', () => {
let orderService: OrderServiceService;
let orderRepository: Repository<Service>;
const mockOrderRepository = () => ({
save: jest.fn(),
});
const mockEntityManager = () => ({
getRepository: jest.fn(),
});
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
OrderService,
{
provide: EntityManager,
useFactory: mockEntityManager,
},
{
provide: getRepositoryToken(Service),
useFactory: mockOrderRepository,
},
],
}).compile();
orderService = await module.get<OrderService>(
OrderService,
);
orderRepository = await module.get(getRepositoryToken(Service));
});
it('should check that order service is defined', () => {
expect(orderService).toBeDefined();
});
describe('Create order service', () => {
it('should create an order service', () => {
expect(orderRepository.save).not.toHaveBeenCalled();
const data = {
name: 'Gucci Cloths',
type: 'Cloths',
};
orderService.createOrder(data);
expect(orderRepository.save).toHaveBeenCalled();
});
});
});
What you can do is mocking the save function of the orderRepository:
const mockRepository = {
save: jest.fn(),
}
const mockEntityManager = () => ({
getRepository: () => mockRepository,
});
This way you can test the function and also check that the save function has been called with the right parameters.
I'm testing a Single file component that uses vue router to watch $route. The problem is that I can't get the test to both change the route and trigger the watcher's function.
The test file:
import { createLocalVue, shallow } from 'vue-test-utils';
import Vue from 'vue';
import Vuex from 'vuex';
const localVue = createLocalVue();
localVue.use(Vuex);
const $route = {
path: '/my/path',
query: { uuid: 'abc' },
}
wrapper = shallow({
localVue,
store,
mocks: {
$route,
}
});
it('should call action when route changes', () => {
// ensure jest has a clean state for this mocked func
expect(actions['myVuexAction']).not.toHaveBeenCalled();
vm.$set($route.query, 'uuid', 'def');
//vm.$router.replace(/my/path?uuid=def') // tried when installing actual router
//vm.$route.query.uuid = 'def'; // tried
//vm.$route = { query: { uuid: 'def'} }; // tried
expect(actions['myVuexAction']).toHaveBeenLastCalledWith({ key: true });
});
My watch method in the SFC:
watch: {
$route() {
this.myVuexAction({ key: true });
},
},
How do you mock router in such a way that you can watch it and test the watch method is working as you expect?
This is how I'm testing a watch on route change that adds the current route name as a css class to my app component:
import VueRouter from 'vue-router'
import { shallowMount, createLocalVue } from '#vue/test-utils'
import MyApp from './MyApp'
describe('MyApp', () => {
it('adds current route name to css classes on route change', () => {
// arrange
const localVue = createLocalVue()
localVue.use(VueRouter)
const router = new VueRouter({ routes: [{path: '/my-new-route', name: 'my-new-route'}] })
const wrapper = shallowMount(MyApp, { localVue, router })
// act
router.push({ name: 'my-new-route' })
// assert
expect(wrapper.find('.my-app').classes()).toContain('my-new-route')
})
})
Tested with vue#2.6.11 and vue-router#3.1.3.
I checked how VueRouter initializes $route and $router and replicated this in my test. The following works without using VueRouter directly:
const localVue = createLocalVue();
// Mock $route
const $routeWrapper = {
$route: null,
};
localVue.util.defineReactive($routeWrapper, '$route', {
params: {
step,
},
});
Object.defineProperty(localVue.prototype, '$route', {
get() { return $routeWrapper.$route; },
});
// Mock $router
const $routerPushStub = sinon.stub();
localVue.prototype.$router = { push: $routerPushStub };
const wrapper = shallowMount(TestComponent, {
localVue,
});
Updating $route should always be done by replacing the whole object, that is the only way it works without using a deep watcher on $route and is also the way VueRouter behaves:
$routeWrapper.$route = { params: { step: 1 } };
await vm.wrapper.$nextTick();
Source: install.js
Its working for me
let $route = {
name: 'any-route',
};
We defined a $route and we called like
wrapper = mount(YourComponent, {
mocks: {
$route,
},
});
and my componente is like this
#Watch('$route', { deep: true, immediate: true, })
async onRouteChange(val: Route) {
if (val.name === 'my-route') {
await this.getDocumentByUrl();
await this.allDocuments();
}
};
pd: I use typescript, but this work with the another format
and finally my test
it('my test', ()=>{
const getDocumentByUrl = jest.spyOn(wrapper.vm, 'getDocumentByUrl');
const allDocuments = jest.spyOn(wrapper.vm, 'allDocuments');
wrapper.vm.$route.name = 'my-route';
await flushPromises();
expect(getDocumentByUrl).toHaveBeenCalled();
expect(allDocuments).toHaveBeenCalled();
})
The way to do this actually is to use vue-test-utils wrapper method, setData.
wrapper.setData({ $route: { query: { uuid: 'def'} } });