Skip to content

Commit

Permalink
Added tests for critters and lookups paths
Browse files Browse the repository at this point in the history
  • Loading branch information
GrahamS-Quartech committed Aug 29, 2023
1 parent 118d022 commit 6660d97
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 8 deletions.
62 changes: 62 additions & 0 deletions api/src/paths/critter-data/critters/post.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import Ajv from 'ajv';
import chai, { expect } from 'chai';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';
import { CritterbaseService, IBulkCreate } from '../../../services/critterbase-service';
import { getRequestHandlerMocks } from '../../../__mocks__/db';
import * as createCritter from './post';

chai.use(sinonChai);

describe('paths/critter-data/critters/post', () => {
const ajv = new Ajv();

it('is valid openapi v3 schema', () => {
expect(ajv.validateSchema((createCritter.POST.apiDoc as unknown) as object)).to.be.true;
});

const payload: IBulkCreate = {
critters: [],
captures: [],
mortality: [],
locations: [],
markings: [],
measurement_quantitative: [],
measurement_qualitative: [],
family: []
};

describe('createCritter', () => {
afterEach(() => {
sinon.restore();
});
it('should succeed', async () => {
const mockCreateCritter = sinon.stub(CritterbaseService.prototype, 'createCritter').resolves({ count: 0 });
const { mockReq, mockRes, mockNext } = getRequestHandlerMocks();
mockReq.body = payload;
const requestHandler = createCritter.createCritter();

await requestHandler(mockReq, mockRes, mockNext);

expect(mockCreateCritter.calledOnce).to.be.true;
expect(mockCreateCritter).calledWith(payload);
expect(mockRes.statusValue).to.equal(200);
expect(mockRes.json.calledWith({ count: 0 })).to.be.true;
});
it('should fail', async () => {
const mockError = new Error('mock error');
const mockCreateCritter = sinon.stub(CritterbaseService.prototype, 'createCritter').rejects(mockError);

const { mockReq, mockRes, mockNext } = getRequestHandlerMocks();
const requestHandler = createCritter.createCritter();

try {
await requestHandler(mockReq, mockRes, mockNext);
expect.fail();
} catch (actualError) {
expect(actualError).to.equal(mockError);
expect(mockCreateCritter.calledOnce).to.be.true;
}
});
});
});
12 changes: 9 additions & 3 deletions api/src/paths/critter-data/critters/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import { Operation } from 'express-openapi';
import { PROJECT_PERMISSION, SYSTEM_ROLE } from '../../../constants/roles';
import { authorizeRequestHandler } from '../../../request-handlers/security/authorization';
import { CritterbaseService, ICritterbaseUser } from '../../../services/critterbase-service';
import { getLogger } from '../../../utils/logger';

// TODO: Put this all into an existing endpoint

const defaultLog = getLogger('paths/critter-data/critters')
export const POST: Operation = [
authorizeRequestHandler((req) => {
return {
Expand Down Expand Up @@ -150,7 +151,12 @@ export function createCritter(): RequestHandler {
};

const cb = new CritterbaseService(user);
const result = await cb.createCritter(req.body);
return res.status(200).json(result);
try {
const result = await cb.createCritter(req.body);
return res.status(200).json(result);
} catch (error) {
defaultLog.error({ label: 'createCritter', message: 'error', error });
throw error;
}
};
}
68 changes: 68 additions & 0 deletions api/src/paths/critter-data/critters/{critterId}.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import Ajv from 'ajv';
import chai, { expect } from 'chai';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';
import { CritterbaseService } from '../../../services/critterbase-service';
import { getRequestHandlerMocks } from '../../../__mocks__/db';
import * as critter from './{critterId}';

chai.use(sinonChai);

describe('paths/critter-data/critters/{critterId}', () => {
const ajv = new Ajv();

it('is valid openapi v3 schema', () => {
expect(ajv.validateSchema((critter.GET.apiDoc as unknown) as object)).to.be.true;
});

const mockCritter = {
critter_id: 'asdf',
wlh_id: '17-10748',
animal_id: '6',
sex: 'Female',
taxon: 'Caribou',
collection_units: [
{
category_name: 'Population Unit',
unit_name: 'Itcha-Ilgachuz',
collection_unit_id: '0284c4ca-a279-4135-b6ef-d8f4f8c3d1e6',
collection_category_id: '9dcf05a8-9bfe-421b-b487-ce65299441ca'
}
],
mortality_timestamp: new Date()
};

describe('getCritter', async () => {
afterEach(() => {
sinon.restore();
});
it('should succeed', async () => {
const mockGetCritter = sinon.stub(CritterbaseService.prototype, 'getCritter').resolves(mockCritter);
const { mockReq, mockRes, mockNext } = getRequestHandlerMocks();
mockReq.params = { critterId: 'asdf' };
const requestHandler = critter.getCritter();

await requestHandler(mockReq, mockRes, mockNext);

expect(mockGetCritter.calledOnce).to.be.true;
expect(mockGetCritter).calledWith('asdf');
expect(mockRes.statusValue).to.equal(200);
expect(mockRes.json.calledWith(mockCritter)).to.be.true;
});
it('should fail', async () => {
const mockError = new Error('mock error');
const mockGetCritter = sinon.stub(CritterbaseService.prototype, 'getCritter').rejects(mockError);

const { mockReq, mockRes, mockNext } = getRequestHandlerMocks();
const requestHandler = critter.getCritter();

try {
await requestHandler(mockReq, mockRes, mockNext);
expect.fail();
} catch (actualError) {
expect(actualError).to.equal(mockError);
expect(mockGetCritter.calledOnce).to.be.true;
}
});
});
});
11 changes: 9 additions & 2 deletions api/src/paths/critter-data/critters/{critterId}.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import { Operation } from 'express-openapi';
import { PROJECT_PERMISSION, SYSTEM_ROLE } from '../../../constants/roles';
import { authorizeRequestHandler } from '../../../request-handlers/security/authorization';
import { CritterbaseService, ICritterbaseUser } from '../../../services/critterbase-service';
import { getLogger } from '../../../utils/logger';

// TODO: Put this all into an existing endpoint
const defaultLog = getLogger('paths/critter-data/critters');

export const GET: Operation = [
authorizeRequestHandler((req) => {
Expand Down Expand Up @@ -81,7 +83,12 @@ export function getCritter(): RequestHandler {
};

const cb = new CritterbaseService(user);
const result = await cb.getCritter(req.params.critterId);
return res.status(200).json(result);
try {
const result = await cb.getCritter(req.params.critterId);
return res.status(200).json(result);
} catch (error) {
defaultLog.error({ label: 'getCritter', message: 'error', error });
throw error;
}
};
}
53 changes: 53 additions & 0 deletions api/src/paths/critter-data/lookups/{key}.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import Ajv from 'ajv';
import chai, { expect } from 'chai';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';
import { CritterbaseService } from '../../../services/critterbase-service';
import { getRequestHandlerMocks } from '../../../__mocks__/db';
import * as key from './{key}';

chai.use(sinonChai);

describe('paths/critter-data/lookups/{key}', () => {
const ajv = new Ajv();

it('is valid openapi v3 schema', () => {
expect(ajv.validateSchema((key.GET.apiDoc as unknown) as object)).to.be.true;
});

const mockSelectOptions = [{ key: 'a', value: 'a', id: 'a' }];

describe('getSelectOptions', () => {
afterEach(() => {
sinon.restore();
});
it('should succeed', async () => {
const mockGetLookupValues = sinon
.stub(CritterbaseService.prototype, 'getLookupValues')
.resolves(mockSelectOptions);
const { mockReq, mockRes, mockNext } = getRequestHandlerMocks();
const requestHandler = key.getLookupValues();

await requestHandler(mockReq, mockRes, mockNext);

expect(mockGetLookupValues.calledOnce).to.be.true;
expect(mockRes.statusValue).to.equal(200);
expect(mockRes.json.calledWith(mockSelectOptions)).to.be.true;
});
it('should fail', async () => {
const mockError = new Error('mock error');
const mockGetLookupValues = sinon.stub(CritterbaseService.prototype, 'getLookupValues').rejects(mockError);

const { mockReq, mockRes, mockNext } = getRequestHandlerMocks();
const requestHandler = key.getLookupValues();

try {
await requestHandler(mockReq, mockRes, mockNext);
expect.fail();
} catch (actualError) {
expect(actualError).to.equal(mockError);
expect(mockGetLookupValues.calledOnce).to.be.true;
}
});
});
});
12 changes: 9 additions & 3 deletions api/src/paths/critter-data/lookups/{key}.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import { Operation } from 'express-openapi';
import { PROJECT_PERMISSION, SYSTEM_ROLE } from '../../../constants/roles';
import { authorizeRequestHandler } from '../../../request-handlers/security/authorization';
import { CritterbaseService, ICbRouteKey, ICritterbaseUser } from '../../../services/critterbase-service';
import { getLogger } from '../../../utils/logger';

// TODO: Put this all into an existing endpoint

const defaultLog = getLogger('paths/lookups');
export const GET: Operation = [
authorizeRequestHandler((req) => {
return {
Expand Down Expand Up @@ -118,7 +119,12 @@ export function getLookupValues(): RequestHandler {
for (const [a, b] of Object.entries(req.query)) {
params.push({ key: String(a), value: String(b) });
}
const result = await cb.getLookupValues(key, params);
return res.status(200).json(result);
try {
const result = await cb.getLookupValues(key, params);
return res.status(200).json(result);
} catch (error) {
defaultLog.error({ label: 'lookups', message: 'error', error });
throw error;
}
};
}

0 comments on commit 6660d97

Please sign in to comment.