Fixes API controller tests

The tests mock the mogoose User model and the express Response model
which isn't good. We should find a solution that makes use of
the actual model object.
This commit is contained in:
Andrew Nicolaou 2019-05-14 16:49:57 +02:00 committed by Cassie Tarakajian
parent 7bfacf08d0
commit 69d5a87861
2 changed files with 89 additions and 30 deletions

View File

@ -1,13 +1,18 @@
/* @jest-environment node */ /* @jest-environment node */
import last from 'lodash/last';
import { createApiKey, removeApiKey } from '../../user.controller/apiKey'; import { createApiKey, removeApiKey } from '../../user.controller/apiKey';
jest.mock('../../../models/user'); jest.mock('../../../models/user');
const createResponseMock = function (done) { /*
Create a mock object representing an express Response
*/
const createResponseMock = function createResponseMock(done) {
const json = jest.fn(() => { const json = jest.fn(() => {
if (done) { done(); } if (done) { done(); }
}); });
const status = jest.fn(() => ({ json })); const status = jest.fn(() => ({ json }));
return { return {
@ -16,6 +21,41 @@ const createResponseMock = function (done) {
}; };
}; };
/*
Create a mock of the mongoose User model
*/
const createUserMock = function createUserMock() {
const apiKeys = [];
let nextId = 0;
apiKeys.push = ({ label, hashedKey }) => {
const id = nextId;
nextId += 1;
const publicFields = { id, label };
const allFields = { ...publicFields, hashedKey };
Object.defineProperty(allFields, 'publicFields', {
value: publicFields,
enumerable: false
});
return Array.prototype.push.call(apiKeys, allFields);
};
apiKeys.pull = ({ _id }) => {
const index = apiKeys.findIndex(({ id }) => id === _id);
return apiKeys.splice(index, 1);
};
return {
apiKeys,
get publicApiKeys() {
return apiKeys.map(k => k.publicFields)
},
save: jest.fn(callback => callback())
};
};
const User = require('../../../models/user').default; const User = require('../../../models/user').default;
describe('user.controller', () => { describe('user.controller', () => {
@ -38,9 +78,8 @@ describe('user.controller', () => {
}); });
it('returns an error if label not provided', () => { it('returns an error if label not provided', () => {
User.__setFindById(undefined, { User.__setFindById(undefined, createUserMock());
apiKeys: []
});
const request = { user: { id: '1234' }, body: {} }; const request = { user: { id: '1234' }, body: {} };
const response = createResponseMock(); const response = createResponseMock();
@ -60,17 +99,18 @@ describe('user.controller', () => {
body: { label: 'my key' } body: { label: 'my key' }
}; };
const foundUser = { const user = createUserMock();
apiKeys: [],
save: jest.fn(callback => callback())
};
const checkExpecations = () => { const checkExpecations = () => {
expect(foundUser.apiKeys[0].label).toBe('my key'); const lastKey = last(user.apiKeys);
expect(typeof foundUser.apiKeys[0].hashedKey).toBe('string');
expect(lastKey.label).toBe('my key');
expect(typeof lastKey.hashedKey).toBe('string');
expect(response.json).toHaveBeenCalledWith({ expect(response.json).toHaveBeenCalledWith({
token: foundUser.apiKeys[0].hashedKey apiKeys: [
{ id: 0, label: 'my key', token: lastKey.hashedKey }
]
}); });
done(); done();
@ -78,7 +118,7 @@ describe('user.controller', () => {
response = createResponseMock(checkExpecations); response = createResponseMock(checkExpecations);
User.__setFindById(undefined, foundUser); User.__setFindById(undefined, user);
createApiKey(request, response); createApiKey(request, response);
}); });
@ -105,11 +145,8 @@ describe('user.controller', () => {
}; };
const response = createResponseMock(); const response = createResponseMock();
const foundUser = { const user = createUserMock();
apiKeys: [], User.__setFindById(undefined, user);
save: jest.fn(callback => callback())
};
User.__setFindById(undefined, foundUser);
removeApiKey(request, response); removeApiKey(request, response);
@ -119,24 +156,27 @@ describe('user.controller', () => {
}); });
}); });
it.skip('removes key if it exists', () => { it('removes key if it exists', () => {
const request = { const request = {
user: { id: '1234' }, user: { id: '1234' },
params: { keyId: 'the-key' } params: { keyId: 0 }
}; };
const response = createResponseMock(); const response = createResponseMock();
const foundUser = { const user = createUserMock();
apiKeys: [{ label: 'the-label', id: 'the-key' }],
save: jest.fn(callback => callback()) user.apiKeys.push({ label: 'first key' }); // id 0
}; user.apiKeys.push({ label: 'second key' }); // id 1
User.__setFindById(undefined, foundUser);
User.__setFindById(undefined, user);
removeApiKey(request, response); removeApiKey(request, response);
expect(response.status).toHaveBeenCalledWith(404); expect(response.status).toHaveBeenCalledWith(200);
expect(response.json).toHaveBeenCalledWith({ expect(response.json).toHaveBeenCalledWith({
error: 'Key does not exist for user' apiKeys: [
{ id: 1, label: 'second key' }
]
}); });
}); });
}); });

View File

@ -30,9 +30,9 @@ export function createApiKey(req, res) {
return; return;
} }
const hashedKey = await generateApiKey(); const keyToBeHashed = await generateApiKey();
user.apiKeys.push({ label: req.body.label, hashedKey }); const addedApiKeyIndex = user.apiKeys.push({ label: req.body.label, hashedKey: keyToBeHashed });
user.save((saveErr) => { user.save((saveErr) => {
if (saveErr) { if (saveErr) {
@ -40,7 +40,17 @@ export function createApiKey(req, res) {
return; return;
} }
res.json({ token: hashedKey }); const apiKeys = user.apiKeys
.map((apiKey, index) => {
const fields = apiKey.publicFields;
const shouldIncludeToken = index === addedApiKeyIndex - 1;
return shouldIncludeToken ?
{ ...fields, token: keyToBeHashed } :
fields;
});
res.json({ apiKeys });
}); });
}); });
} }
@ -60,7 +70,16 @@ export function removeApiKey(req, res) {
res.status(404).json({ error: 'Key does not exist for user' }); res.status(404).json({ error: 'Key does not exist for user' });
return; return;
} }
user.apiKeys.pull({ _id: req.params.keyId }); user.apiKeys.pull({ _id: req.params.keyId });
saveUser(res, user);
user.save((saveErr) => {
if (saveErr) {
res.status(500).json({ error: saveErr });
return;
}
res.status(200).json({ apiKeys: user.publicApiKeys });
});
}); });
} }