Creating Models Using Test Driven Development - OCLC-Developer-Network/devconnect2018-idm GitHub Wiki
Test Setup
- Open package.json
- Add line to scripts section to run tests
"test": "mocha"
- Create a directory within
tests
calledmocks
- Add the following files to
mocks
containing the linked code
- Add the following files to
Write your first test
- In tests directory create a file named user.test.js to test your User Class
- Open user.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 User = require('../src/User');
const user_response = fs.readFileSync(require('path').resolve(__dirname, './mocks/userResponse.json')).toString();
- Write for Test creating a User
- Create a new User object a. load API response as JSON
- Test that it is an instance of a User object
describe('Create user test', () => {
let my_user;
before(() => {
my_user = new User(JSON.parse(user_response));
});
it('Creates an User object', () => {
expect(my_user).to.be.an.instanceof(User);
});
});
-
Make the test pass by creating User class and constructor
- In the src directory create a file named User.js to represent the User Class
- Open User.js, declare User class and add use constants for classes you want to use
const axios = require("axios"); const serviceUrl = '.share.worldcat.org/idaas/scim/v2'; const UserError = require('../src/UserError'); module.exports = class User {
- Create a constructor for the User 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 User object" passes
- Test that it is an instance of a JSON object
it('Sets the User properties', () => {
expect(my_user.doc).to.be.an.instanceof(object);
});
- Run tests
npm test
Getters
- Write a test to ensure "getter" functions are returning values
- Make sure "Sets the User properties" passes
- Test each "getter" method returns appropriate value.
it('Has functioning getters', () => {
expect(my_user.getFamilyName()).to.equal('Coombs');
expect(my_user.getGivenName()).to.equal('Karen');
expect(my_user.getMiddleName()).to.equal('');
expect(my_user.getEmail()).to.equal("[email protected]");
expect(my_user.getOclcPPID()).to.equal("412d947b-144e-4ea4-97f5-fd6593315f17");
expect(my_user.getInstitutionId()).to.equal("128807");
expect(my_user.getOclcNamespace()).to.equal("urn:oclc:platform:127950");
});
-
Write function to get the FamilyName in User class
getFamilyName() { return this.doc.name.familyName; }
-
Run tests
npm test
-
Write function to get a GivenName in User class
getGivenName() { return this.doc.name.givenName; }
-
Run tests
npm test
- Write function to get the MiddleName in the User class
getMiddleName() {
return this.doc.name.middleName;
}
- Run tests
npm test
- Write function to get the Email in User class
getEmail() {
return this.doc.email;
}
- Run tests
npm test
- Write function to get the OclcPPID in the User Class
getOclcPPID() {
return this.doc.oclcPPID;
}
- Run tests
npm test
- Write function to get the InstitutionId in the User Class
getInstitutionId() {
return this.doc.institutionId;
}
- Run tests
npm test
- Write function to get the OclcNamespace in the User Class
getOclcNamespace() {
return this.doc.oclcNamespace;
}
- Run tests
npm test
Getting a User from the API
- Tell tests what file to use for mocks
describe('Get self user tests', () => {
beforeEach(() => {
moxios.install();
});
afterEach(() => {
moxios.uninstall();
});
it('Get user by Access Token', () => {
moxios.stubRequest('https://128807.share.worldcat.org/idaas/scim/v2/Me', {
status: 200,
responseText: user_response
});
// Test expects go here
});
});
- Get Self
- Test that object returned is an instance of a User
return User.self(128807, 'tk_12345')
.then(response => {
//expect an user object back
expect(response).to.be.an.instanceof(User);
});
- Make test pass by creating a static "self" function for the User
- Make function take to variables
- institution
- access token
- Create a url for the request
- Create an HTTP client
- Create a set of headers
- try to make the HTTP request
- If successful
- Pass response to create a new User
- If fails
- Pass response off to UserError to handle
- If successful
- Make function take to variables
static self(institution, accessToken) {
var config = {
headers: {
'Authorization': 'Bearer ' + accessToken,
'User-Agent': 'node.js KAC client'
}
};
let url = 'https://' + institution + serviceUrl + '/Me';
return new Promise(function (resolve, reject) {
axios.get(url, config)
.then(response => {
// parse out the User
resolve(new User(response.data));
})
.catch (error => {
reject(new UserError(error));
});
});
}
- Run tests
npm test
Write test for getting data from User
- Test that getFamilyName method returns a value of Coombs
- Test that getGivenName method returns a value of Karen
- Test that getMiddleName method returns a value of ""
- Test that getEmail method returns a value of [email protected]
- Test that getOclcPPID method returns a value of 412d947b-144e-4ea4-97f5-fd6593315f17
- Test that getInstitutionId method returns a value of 128807
- Test that getOclcNamespace method returns a value of urn:oclc:platform:127950
expect(response.getFamilyName()).to.equal('Coombs');
expect(response.getGivenName()).to.equal('Karen');
expect(response.getMiddleName()).to.equal('');
expect(response.getEmail()).to.equal("[email protected]");
expect(response.getOclcPPID()).to.equal("412d947b-144e-4ea4-97f5-fd6593315f17");
expect(response.getInstitutionId()).to.equal("128807");
expect(response.getOclcNamespace()).to.equal("urn:oclc:platform:127950");
- Run tests
npm test
Write the first test for the UserError Class
- In tests directory create a file named user_error.test.js to test your UserError Class
- Open user_error.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 UserError = require('../src/UserError');
const error_response = fs.readFileSync(require('path').resolve(__dirname, './mocks/errorResponse.json')).toString();
const User = require('../src/User');
const error_mock = require('./mocks/errorMock');
- Write for Test creating a UserError
- Create a new UserError object
- Test that it is an instance of a UserError object
describe('Create Error test', () => {
var error;
before(() => {
error = new UserError(error_mock);
});
it('Creates an Error object', () => {
expect(error).to.be.an.instanceof(UserError);
});
});
-
Make the test pass by creating UserError class and constructor
- In the src directory create a file named UserError.js to represent the UserError Class
- Open UserError.js and declare UserError class
module.exports = class UserError { }
- Create a constructor for the UserError 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 this.code = this.error.response.status; this.request = this.error.request; this.doc = this.error.response.data; this.message = this.doc.detail; } else if (this.error.request) { // The request was made but no response was received this.request = this.error.request; } else { // Something happened in setting up the request that triggered an Error this.message = this.error.message; } }
-
Run tests
npm test
Properties set
- 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('Authentication failure. Missing or invalid authorization token.')
});
- Run tests
npm test
Getters
- 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('Authentication failure. Missing or invalid authorization token.')
});
- 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
Test that Access Token error can be properly parsed
- Add mock for Access token error
const accesstoken_error_mock = require('./mocks/accessTokenErrorMock')
- Pass the UserError 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 UserError(accesstoken_error_mock);
});
it('Creates an Error object', () => {
expect(error).to.be.an.instanceof(UserError);
});
it('Sets the Error properties', () => {
expect(error.error).to.be.an.instanceof(Error);
expect(error.code).to.equal(401)
expect(error.message).to.equal('Authentication failure. Missing or invalid authorization token.')
});
it('Has functioning getters', () => {
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.')
});
});
Alter UserError Class to handle Access Token errors
- Change UserError Class constructor
this.code = this.error.response.status;
this.request = this.error.request;
this.doc = this.error.response.data;
this.message = this.doc.detail;
to
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){
this.doc = this.error.response.data;
this.message = this.doc.detail;
this.detail = null;
} else {
this.doc = JSON.parse(this.error.response.body);
this.message = this.doc.message;
this.detail = this.doc.detail;
}
- Run tests
npm test
Test that an API error can be properly parsed
- Create tests for parsing API errors
- Tell tests what file to use for mocks
- Call User::self in a failed fashion
- Test error is an instance of UserError
- 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.stubRequest('https://128807.share.worldcat.org/idaas/scim/v2/Me', {
status: 401,
responseText: error_response
});
return User.self(128807, 'tk_12345')
.catch(error => {
//expect an Error object back
expect(error).to.be.an.instanceof(UserError);
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