I have trouble for Mocking my ActionContext in my unit test. Actually, I have Mock my ActionContext in this way :
testUtilities.ts
import { ActionContext, Dispatch, Commit } from 'vuex';
import { IRootState } from './../src/store/store';
import { expect } from 'chai';
import { DispatchAccessorNoPayload } from 'vuex-typescript';
export interface ContextTest {
state: any;
rootState: IRootState;
getters: any;
rootGetters: any;
}
type TestActionTypes = (action: DispatchAccessorNoPayload<any, IRootState, any>,
{
state,
rootState,
getters,
rootGetters,
}: ContextTest,
expectedMutations: any,
done: Mocha.Done) => void;
export const testAction: TestActionTypes = (
action,
{
state,
rootState,
getters,
rootGetters,
},
expectedMutations,
done
) => {
let countDispatch = 0;
let countCommit = 0;
// mock dispatch
const dispatch: Dispatch = (type: string) => {
return new Promise((resolve, reject) => {
const mutation = expectedMutations[countDispatch];
try {
expect(mutation.type).to.equal(type);
} catch (error) {
done(error);
reject(error);
}
countDispatch++;
if (countDispatch >= expectedMutations.length) {
done();
resolve();
}
});
};
// mock commit
const commit: Commit = (type: string) => {
const mutation = expectedMutations[countCommit];
try {
expect(mutation.type).to.equal(type);
} catch (error) {
done(error);
}
countCommit++;
if (countCommit >= expectedMutations.length) {
done();
}
};
const context: ActionContext<any, IRootState> = {
state,
rootState,
rootGetters,
commit,
dispatch,
getters,
};
// call the action with mocked store and arguments
action(context);
// check if no mutations should have been dispatched
if (expectedMutations.length === 0) {
expect(countCommit).to.equal(0);
expect(countDispatch).to.equal(0);
done();
}
};
I use this helper from the documentation of Vuex : https://vuex.vuejs.org/guide/testing.html#testing-actions
customer.module.ts
import { IRootState } from "./../store";
import { ICustomer } from "./../../models/customer.model";
import { ActionContext } from "vuex";
import { getStoreAccessors } from "vuex-typescript";
import { CustomerService } from './../../services/entities/customer.service';
export interface ICustomersState {
customers: ICustomer[];
}
const initialState: ICustomersState = {
customers: []
};
type CustomersContext = ActionContext<ICustomersState, IRootState>;
export const mutations = {
FETCH_CUSTOMERS(state: ICustomersState, customers: ICustomer[]) {
state.customers = customers;
}
};
export const actions = {
GETALL_CUSTOMERS(context: CustomersContext) {
let customerService = new CustomerService();
return customerService.getAll().then(customers => {
context.commit("FETCH_CUSTOMERS", customers);
});
},
}
export const customer = {
namespaced: true,
state: { ...initialState },
mutations,
actions
};
const { read, commit, dispatch } = getStoreAccessors<ICustomersState, IRootState>("customers");
export const getAllCustomersDispatch = dispatch(customer.actions.GETALL_CUSTOMERS);
customer.actions.spec.ts
import { getAllCustomersDispatch } from './../../../../src/store/modules/customer';
import { testAction, ContextTest } from "./../../../../tests/testUtilities";
describe("Customer Actions", () => {
it("GETALL_CUSTOMERS", (done) => {
const context: ContextTest = {
state: [],
getters: {},
rootGetters: {},
rootState: {
customers: {
customers: []
}
}
}
testAction(getAllCustomersDispatch, context, [{
type: 'customers/FETCH_CUSTOMERS'
}], done)
});
});
Expected Result
I would like my unit test verify if the action GETALL_CUSTOMERS
well call my commit FETCH_CUSTOMERS
.
Test OUTPUT
+ expected - actual
-"customers/FETCH_CUSTOMERS"
+"customers/GETALL_CUSTOMERS"
I put a breakpoint inside commit
constant in my testAction
function, but my treatment doesn't go through this one.
I solved my problem, I used sinon.js
for mock my API call and mock my commit
.
I get the expected result well.
customer.actions.spec.ts
import { actions } from "./../../../../src/store/modules/customer";
import { spy, createSandbox } from "sinon";
import { expect } from "chai";
import Axios from "axios";
import Sinon = require("sinon");
import { ICustomer } from "src/models/customer.model";
describe("Customer Actions", () => {
let sandbox: Sinon.SinonSandbox;
beforeEach(() => (sandbox = createSandbox()));
afterEach(() => sandbox.restore());
it("GETALL_CUSTOMERS", async () => {
// Assign
let data: ICustomer[] = [
{
id: 1,
address: "",
company: "",
firstName: "",
lastName: "",
zipcode: "",
siret: "",
tel: "",
projects: []
}
];
const resolved = new Promise<any>(r => r({ data }));
sandbox.stub(Axios, "get").returns(resolved);
let commit = spy();
let state = {
customers: []
};
const getters: {} = {};
let rootGetters: {} = {};
let rootState: {
customers: {
customers: [];
};
} = {
customers: {
customers: []
}
};
// Act
await actions.GETALL_CUSTOMERS({
commit,
state,
dispatch: () => Promise.resolve(),
getters,
rootGetters,
rootState
});
// Assert
expect(commit.args).to.deep.equal([
["FETCH_CUSTOMERS_REQUEST"],
["FETCH_CUSTOMERS_SUCCESS", data]
]);
})
customer.module.ts
import { IRootState } from "./../store";
import { ICustomer } from "./../../models/customer.model";
import { ActionContext } from "vuex";
import { getStoreAccessors } from "vuex-typescript";
import { CustomerService } from './../../services/entities/customer.service';
export interface ICustomersState {
customers: ICustomer[];
}
const initialState: ICustomersState = {
customers: []
};
type CustomersContext = ActionContext<ICustomersState, IRootState>;
export const mutations = {
FETCH_CUSTOMERS(state: ICustomersState, customers: ICustomer[]) {
state.customers = customers;
}
};
export const actions = {
async GETALL_CUSTOMERS(context: CustomersContext) {
let customerService = new CustomerService();
context.commit("FETCH_CUSTOMERS_REQUEST", customers);
await customerService.getAll().then(customers => {
context.commit("FETCH_CUSTOMERS_SUCCESS", customers);
}).catch(err => context.commit("FETCH_CUSTOMERS_ERROR", err));
},
}
export const customer = {
namespaced: true,
state: { ...initialState },
mutations,
actions
};
const { read, commit, dispatch } = getStoreAccessors<ICustomersState, IRootState>("customers");
export const getAllCustomersDispatch = dispatch(customer.actions.GETALL_CUSTOMERS);
I deleted the file testUtilities.ts because I didn't need it anymore.