I am writing an end-to-end test using Protractor for my Angular application. I can mock httpBackend for unit test but I want to actually call the server and get the JSON re
We do this type of "hit the API directly and test the data in the response" integration testing in addition to our Protractor e2e testing. For the API-side testing, you don't need Protractor, because there's no need to fire up a browser just to send HTTP requests to a server.
Here's what we do:
describe()/it()/expect()
grammar from our Protractor environment (which is based on Jasmine). So rather than running protractor to run tests, you run jasmine, a la: jasmine --config=jasmine.json path/to/tests/*spec.js
Our spec files look something like this:
describe('API Tests written in Jasmine', function() {
beforeAll(() => authAsAdmin());
it('Should get a proposal object as auth\'d user', function() {
const httpOptions = {
uri: `/proposals/100`,
};
return requestWithAuth(httpOptions)
.then(res => {
const proposal = res.body.proposal;
// console.log(`Proposal ${proposal.id} title: ${proposal.title}`);
expect(proposal.id).toEqual(100);
expect(res.statusCode).toEqual(200);
expect(res.statusMessage).toBe('OK');
});
});
Our spec files depend on some global helper methods that we set up in a Jasmine helper file (part of the standard mechanics of how Jasmine works), like below:
const rp = require('request-promise');
...
// Declare our helper methods globally so they can be accessed anywhere in tests
global.requestWithAuth = requestWithAuth;
global.authAs = authAs;
global.authAsAdmin = () => authAs(ADMIN_USER);
global.catchErrorInLocation = (error, location) => {
throw new Error(`Error in ${location}\n ${error}`);
};
global.catchErrorInBeforeAll = (error) => catchErrorInLocation(error, 'beforeAll()');
function authAs(user) {
...
}
/**
* Combines a given set of options with the DEFAULT_HTTP_OPTIONS plus a session token
* and initiates an http request, returning a promise for the response.
* @param {Object} options properties matching request-promise API
* @param {string} token, optional session token. sessionToken used by default.
* @returns {Promise} request-promise response
*/
function requestWithAuth(options, token = sessionToken) {
Object.assign(options, { ...DEFAULT_HTTP_OPTIONS, ...options }); // Merge custom options with default options
options.headers['x-token'] = token; // Merge current session token into options
options.uri = `${BASE_URL}${options.uri}`; // Update the URI to include the correct base path
return rp(options);
}
I hope this helps.