-
Notifications
You must be signed in to change notification settings - Fork 0
Creating Models Using Test Driven Development
Karen Coombs edited this page Jul 10, 2018
·
1 revision
- Open package.json
- Add line to scripts section to run tests
"test": "mocha"
- Create a directory within
testscalledmocks- Add the following files to
mockscontaining the linked code
- Add the following files to
- In tests directory create a file named illRequest.test.js to test your ILLRequest Class
- Open illRequest.test.js and add constants for classes you want to use (WSKey and Access Token)
const expect = require('chai').expect;
const moxios = require('moxios');
const fs = require('fs');
const ILLRequest = require('../src/ILLRequest');
const ill_request_response = fs.readFileSync(require('path').resolve(__dirname, './mocks/illRequestResponse.json')).toString();
- Write for Test creating an ILL Request
- Create a new ILLRequest object a. load API response
- Test that it is an instance of a ILLRequest object
describe('Create ILL Request test', () => {
let my_request;
before(() => {
my_request = new ILLRequest(JSON.parse(ill_request_response));
});
it('Creates an ILL Request object', () => {
expect(my_request).to.be.an.instanceof(ILLRequest);
});
});
-
Make the test pass by creating ILLRequest class and constructor
- In the src directory create a file named ILLRequest.js to represent the ILLRequest Class
- Open ILLRequest.js, declare ILLRequest class and add use constants for classes you want to use
const serviceUrl = '.share.worldcat.org/ILL/request/data'; const ILLRequestError = require('../src/ILLRequestError'); module.exports = class ILLRequest { // the constructor and other methods }- Create a constructor for the ILLRequest class
constructor(doc) { this.doc = doc; } -
Run tests
npm test- Write a test for making sure a doc property is set
- Make sure "Creates an ILLRequest object" passes
- Test that it is an instance of a JSON object
it('Sets the ILL Request properties', () => {
expect(my_request.doc).to.be.an("object");
});
- Run tests
npm test- Write a test to ensure "getter" functions are returning values
- Make sure "Sets the ILLRequest properties" passes
- Test each "getter" method returns appropriate value.
it('Has functioning getters', () => {
expect(my_request.getID()).to.equal(166917929);
expect(my_request.getStatus()).to.equal('CREATED');
expect(my_request.dateNeededBy()).to.equal('2018-06-30T20:00:00.000-04:00');
expect(my_request.getItemTitle()).to.equal('Simon\'s Cat');
expect(my_request.getItemAuthor()).to.equal('Tofield, Simon');
expect(my_request.getItemOCLCNumber()).to.equal(780941515);
expect(my_request.getUserID()).to.equal('jkdjfldjfdlj');
});
});
-
Write function to get the ID in ILLRequest class
getID(){ return this.doc.requestId; } -
Run tests
npm test-
Write function to get a Status in ILLRequest class
getStatus(){ return this.doc.requestStatus; } -
Run tests
npm test- Write function to get the NeededBy in the ILLRequest class
dateNeededBy(){
return this.doc.needed;
}
- Run tests
npm test- Write function to get the ItemTitle in ILLRequest class
getItemTitle(){
return this.doc.item.title;
}
- Run tests
npm test- Write function to get the ItemAuthor in the ILLRequest Class
getItemAuthor(){
return this.doc.item.author
}
- Run tests
npm test- Write function to get the ItemOCLCNumber in the ILLRequest Class
getItemOCLCNumber(){
return this.doc.item.oclcNumber;
}
- Run tests
npm test- Write function to get the UserID in the ILLRequest Class
getUserID(){
return this.doc.patron.ppid;
}
- Run tests
npm test- Tell tests what file to use for mocks
describe('Add ILL Request tests', () => {
beforeEach(() => {
moxios.install();
});
afterEach(() => {
moxios.uninstall();
});
it('Post ILL Request by Access Token', () => {
moxios.stubOnce('POST', 'https://128807.share.worldcat.org/ILL/request/data', {
status: 200,
responseText: ill_request_response
});
// Test expects go here
});
});
- Add ILL Request
- Test that object returned is an instance of a ILLRequest
let fields = {
"needed": "2018-06-30T20:00:00.000-04:00",
"userID": "jkdjfldjfdlj",
"ItemOCLCNumber": "780941515",
"ItemTitle": "Simon's Cat",
"ItemAuthor": "Tofield, Simon",
"ItemMediaType": "BOOK"
};
return ILLRequest.add(128807, 'tk_12345', fields)
.then(response => {
//expect an ILLRequest object back
expect(response).to.be.an.instanceof(ILLRequest);
});
});
- Make test pass by creating a static "add" function for the ILLRequest
- Make function take to variables
- institution
- access token
- fields
- Create a url for the request
- Create an HTTP client
- Create a set of headers
- Authorization
- User-Agent
- Content-Type
- Accept
- Create a JSON document of the fields to pass as the request body
- try to make the HTTP request
- If successful
- Pass response to create a new ILLRequest
- If fails
- Pass response off to ILLRequestError to handle
- If successful
- Make function take to variables
static add(institution, accessToken, fields) {
var config = {
headers: {
'Authorization': 'Bearer ' + accessToken,
'User-Agent': 'node.js KAC client',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
};
let url = 'https://' + institution + serviceUrl;
// create the necessary JSON
let data = {
"needed": fields['needed'],
"patron":{
"ppid" : fields['user_id']
},
"item":{
"title": fields['title'],
"author": ['author'],
"mediaType":{
"definedValue": ['mediaType']
},
"oclcNumber": ['oclcnumber']
}
}
return new Promise(function (resolve, reject) {
axios.post(url, data, config)
.then(response => {
// parse out the ILL Request
resolve(new ILLRequest(response.data));
})
.catch (error => {
reject(new ILLRequestError(error));
});
});
}
- Run tests
npm test- Test that getID method returns a value of 166917929
- Test that getStatus method returns a value of CREATED
- Test that dateNeededBy method returns a value of 2018-06-30T20:00:00.000-04:00
- Test that getItemTitle method returns a value of Simon's Cat
- Test that getItemAuthor method returns a value of Tofield, Simon
- Test that getItemOCLCNumber method returns a value of 780941515
- Test that getUserID method returns a value of jkdjfldjfdlj
expect(response.getID()).to.equal(166917929);
expect(response.getStatus()).to.equal('CREATED');
expect(response.dateNeededBy()).to.equal('2018-06-30T20:00:00.000-04:00');
expect(response.getItemTitle()).to.equal('Simon\'s Cat');
expect(response.getItemAuthor()).to.equal('Tofield, Simon');
expect(response.getItemOCLCNumber()).to.equal(780941515);
expect(response.getUserID()).to.equal('jkdjfldjfdlj');
- Run tests
npm test- In tests directory create a file named ill_request_error.test.js to test your ILLRequestError Class
- Open ill_request_error.test.js and add constants for classes you want to use (WSKey and Access Token)
const expect = require('chai').expect;
const nock = require('nock');
const moxios = require('moxios');
const fs = require('fs');
const yaml = require('js-yaml');
const get_config = require("../src/config.js");
global.config = yaml.load(get_config("test"));
const ILLRequestError = require('../src/ILLRequestError');
const error_response = fs.readFileSync(require('path').resolve(__dirname, './mocks/errorResponse.json')).toString();
const ILLRequest = require('../src/ILLRequest');
const error_mock = require('./mocks/errorMock');
- Write for Test creating a ILLRequestError
- Create a new ILLRequestError object
- Test that it is an instance of a ILLRequestError object
describe('Create Error test', () => {
var error;
before(() => {
error = new ILLRequestError(error_mock);
});
it('Creates an Error object', () => {
expect(error).to.be.an.instanceof(ILLRequestError);
});
});
-
Make the test pass by creating ILLRequestError class and constructor
- In the src directory create a file named ILLRequestError.js to represent the ILLRequestError Class
- Open ILLRequestError.js and declare ILLRequestError class
module.exports = class ILLRequestError { }- Create a constructor for the ILLRequestError class
constructor(error) { this.error = error; if (this.error.response) { // The request was made and the server responded with a status code // that falls out of the range of 2xx if (this.error.response.status) { this.code = this.error.response.status; } else { this.code = this.error.response.statusCode; } this.request = this.error.request; if (this.error.response.data){ if (typeof this.error.response.data === 'string') { this.doc = JSON.parse(this.error.response.data); } else { this.doc = this.error.response.data; } if (this.doc.message){ this.message = this.doc.message; this.detail = this.doc.details; } else { this.message = this.doc.detail; this.detail = null; } } else { if (typeof this.error.response.body === 'string') { this.doc = JSON.parse(this.error.response.body); } else { this.doc = this.error.response.body; } this.message = this.doc.message; if (this.doc.detail) { this.detail = this.doc.detail; } else { this.detail = this.doc.details; } } } else if (this.error.request) { // The request was made but no response was received this.request = this.error.request; this.code = null; this.message = null; this.detail = null; } else { // Something happened in setting up the request that triggered an Error this.code = null; this.message = this.error.message; this.detail = null; } } -
Run tests
npm test- Write code to ensure error properties are set
it('Sets the Error properties', () => {
expect(error.error).to.be.an.instanceof(Error);
expect(error.code).to.equal(401)
expect(error.message).to.equal('WSKey \'test\' is invalid');
expect(error.detail).to.equal('Authorization header: http://www.worldcat.org/wskey/v2/hmac/v1 clientId=\"test\", timestamp=\"1525205192\", nonce=\"2f33d4fb3c483f99\", signature=\"k7svWPSwMA1qTmwnePoRIlpvcCQNUf8S5/FWTjVbT38=\", principalID=\"8eaggf92-3951-431c-975a-d7rf26b8d131\", principalIDNS=\"urn:oclc:wms:da\"')
});
- Run tests
npm test- Write a test to ensure "getter" functions are returning values
it('Has functioning getters', () => {
expect(error.getRequestError()).to.be.an.instanceof(Error);
expect(error.getCode()).to.equal(401)
expect(error.getMessage()).to.equal('WSKey \'test\' is invalid');
expect(error.getDetail()).to.equal('Authorization header: http://www.worldcat.org/wskey/v2/hmac/v1 clientId=\"test\", timestamp=\"1525205192\", nonce=\"2f33d4fb3c483f99\", signature=\"k7svWPSwMA1qTmwnePoRIlpvcCQNUf8S5/FWTjVbT38=\", principalID=\"8eaggf92-3951-431c-975a-d7rf26b8d131\", principalIDNS=\"urn:oclc:wms:da\"')
});
- Write code for getting a request error
getRequestError()
{
return this.requestError;
}
- Run tests
npm test- Create function to retrieve error code
getCode(){ return this.code; } - Run tests
npm test- Create function to retrieve error message
getMessage(){ return this.message } - Run tests
npm test- Create function to retrieve error detail
getDetail(){ return this.detail; } - Run tests
npm test- Add mock for Access token error
const accesstoken_error_mock = require('./mocks/accessTokenErrorMock')
- Pass the ILLRequstError class the Access Token error mock
- Check the object is instantiated
- Test the properties are set
- Test the getters work
describe('Create Error from Access Token Error test', () => {
var error;
before(() => {
error = new ILLRequestError(accesstoken_error_mock);
});
it('Creates an Error object', () => {
expect(error).to.be.an.instanceof(ILLRequestError);
});
it('Sets the Error properties', () => {
expect(error.error).to.be.an.instanceof(Error);
expect(error.code).to.equal(401)
expect(error.message).to.equal('WSKey \'test\' is invalid')
expect(error.detail).to.equal('Authorization header: http://www.worldcat.org/wskey/v2/hmac/v1 clientId="test", timestamp="1524513365", nonce="a2b79385", signature="yS+aKqSbJ2PjL9S5AuA5zqo+t2QfWLl8W9wWbACnFMk=", principalID="id", principalIDNS="namespace"')
});
it('Has functioning getters', () => {
expect(error.getRequestError()).to.be.an.instanceof(Error);
expect(error.getCode()).to.equal(401)
expect(error.getMessage()).to.equal("WSKey 'test' is invalid")
expect(error.getDetail()).to.equal('Authorization header: http://www.worldcat.org/wskey/v2/hmac/v1 clientId="test", timestamp="1524513365", nonce="a2b79385", signature="yS+aKqSbJ2PjL9S5AuA5zqo+t2QfWLl8W9wWbACnFMk=", principalID="id", principalIDNS="namespace"')
});
});
- Run tests
npm test- Create tests for parsing API errors
- Tell tests what file to use for mocks
- Call ILLRequest.add in a failed fashion
- Test error is an instance of ILLRequestError
- Test the getCode() method returns 401
- Test the getMessage() method returns Authentication failure. Missing or invalid authorization token.
describe('API Error tests', () => {
beforeEach(() => {
moxios.install();
});
afterEach(() => {
moxios.uninstall();
});
it('Returns a 401 Error from an HTTP request', () => {
moxios.stubOnce('POST', 'https://128807.share.worldcat.org/ILL/request/data', {
status: 401,
responseText: error_response
});
// set the fields
let fields = {
"needed": "2018-06-30T20:00:00.000-04:00",
"userID": "jkdjfldjfdlj",
"ItemOCLCNumber": "780941515",
"ItemTitle": "Simon's Cat",
"ItemAuthor": "Tofield, Simon",
"ItemMediaType": "BOOK"
};
return ILLRequest.add(128807, 'tk_12345', fields)
.catch(error => {
//expect an Error object back
expect(error).to.be.an.instanceof(ILLRequestError);
expect(error.getRequestError()).to.be.an.instanceof(Error);
expect(error.getCode()).to.equal(401);
expect(error.getMessage()).to.equal('Authentication failure. Missing or invalid authorization token.')
});
});
- Run tests
npm test- Create tests for parsing Access Token request errors
- Tell tests what file to use for mocks
- Call wskey.getAccessTokenWithAuthCode in a failed fashion
- Test error is an instance of ILLRequestError
- Test the getCode() method returns 401
- Test the getMessage() method returns WSKey 'test' is invalid
- Test the getDetail() method returns Authorization header: http://www.worldcat.org/wskey/v2/hmac/v1 clientId="test", timestamp="1524513365", nonce="a2b79385", signature="yS+aKqSbJ2PjL9S5AuA5zqo+t2QfWLl8W9wWbACnFMk=", principalID="id", principalIDNS="namespace"
it('Returns a 401 Error from an Access Token request', () => {
nock('https://authn.sd00.worldcat.org/oauth2')
.post('/accessToken?grant_type=code&code=auth_12345&authenticatingInstitutionId=128807&contextInstitutionId=128807&redirect_uri=http://localhost:8000/request')
.replyWithFile(401, __dirname + '/mocks/access_token_error.json', { 'Content-Type': 'application/json' });
const nodeauth = require("nodeauth");
const options = {
services: ["tipasa"],
redirectUri: "http://localhost:8000/request"
};
const user = new nodeauth.User(config['institution'], config['principalID'], config['principalIDNS']);
const wskey = new nodeauth.Wskey(config['wskey'], config['secret'], options);
return wskey.getAccessTokenWithAuthCode("auth_12345", config['institution'], config['institution'])
.catch(error => {
//expect an Error object back
let atError = new ILLRequestError(error);
expect(atError).to.be.an.instanceof(ILLRequestError);
expect(atError.getRequestError()).to.be.an.instanceof(Error);
expect(atError.getCode()).to.equal(401);
expect(atError.getMessage()).to.equal("WSKey 'test' is invalid")
expect(atError.getDetail()).to.equal('Authorization header: http://www.worldcat.org/wskey/v2/hmac/v1 clientId="test", timestamp="1524513365", nonce="a2b79385", signature="yS+aKqSbJ2PjL9S5AuA5zqo+t2QfWLl8W9wWbACnFMk=", principalID="id", principalIDNS="namespace"')
});
});