I want to be able to assert whether my 'SIGN_IN' action works as intended.
My action looks like this (not the cleanest implementation but it's what I have to work with for now):
// actions.js
import {
SIGN_IN, SIGN_OUT, SET_AUTH_TOKEN, CLEAR_AUTH_TOKEN, USER_AUTHORISED,
} from '@/store/types';
import AuthService from '../../../authService';
export default {
async [SIGN_IN]({ commit, rootState }) {
const authService = new AuthService(rootState.clientSettings);
let response;
try {
response = await authService.getToken();
} catch (e) {
console.log('User not authorised to use application.');
}
if (response) {
commit(SET_AUTH_TOKEN, response);
} else {
commit(USER_AUTHORISED, false);
}
},
...
};
authService.getToken();
is what I want to mock the response of.
I want this to be able to resolve to a mock response in my test.
The class for AuthService looks like this:
// authService.js
import { PublicClientApplication } from '@azure/msal-browser';
class AuthService {
constructor(clientSettings) {
this.config = {
auth: {
clientId: clientSettings.clientId,
authority: `https://login.microsoftonline.com/${clientSettings.tenantId}`,
},
cache: {
cacheLocation: 'sessionStorage',
storeAuthStateInCookie: false,
},
};
this.scopes = [
clientSettings.appScope,
];
this.msal = new PublicClientApplication(this.config);
this.clientSettings = clientSettings;
}
...
async getToken() {
const { scopes } = this;
try {
const response = await this.msal.acquireTokenSilent({ scopes });
return response;
} catch (err) {
const response = await this.msal.acquireTokenPopup({ scopes });
return response;
}
}
...
}
export default AuthService;
This is what I tried in my test:
// actions.spec.js
import sinon, { mock } from 'sinon';
import actions from '@/store/modules/auth/actions';
import { SIGN_IN, SIGN_OUT } from '@/store/types';
import { PublicClientApplication } from '@azure/msal-browser';
import AuthService from '../../../../../src/authService';
import templateRootState from '../../../../helpers/rootState.json';
describe('Auth', () => {
describe('Actions', () => {
let state;
beforeEach(() => {
state = JSON.parse(JSON.stringify(templateRootState));
});
afterEach(() => {
sinon.reset();
});
describe('SIGN_IN', () => {
it.only('returns a token from the AuthService & sets it in the store', async () => {
const commit = sinon.spy();
const mockResponse = {
token: 'bobbins'
};
sinon.stub(AuthService, 'getToken').resolves(mockResponse);
const requestParams = { commit, rootState: state };
await actions[SIGN_IN](requestParams);
expect(commit.calledOnce).toEqual(true);
expect(commit.args.length).toEqual(1);
expect(commit.args[0][0]).toEqual('SET_AUTH_TOKEN');
expect(commit.args[0][1]).toEqual(mockResponse);
});
});
});
});
While debugging, I am unable to get getToken
to be a stubbed response. It still calls the actual userService
class instance created in my action: new AuthService(rootState.clientSettings);
.
Hopefully you can see what I'm trying to achieve with my test. I just want to assert that SET_AUTH_TOKEN
is triggered and nothing else. How can I stub out this AuthService
class entirely so that my action uses that one instead? I don't really want to be passing an instance of AuthService
into the action itself, there must be a neater way of doing it?
What you need is to stub prototype method.
sinon.stub(AuthService.prototype, 'getToken').resolves(mockResponse);
Reference: how to mock es6 class