Angular Protractor e2e Testing

前端 未结 4 1682
半阙折子戏
半阙折子戏 2021-01-02 01:42

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

4条回答
  •  萌比男神i
    2021-01-02 02:20

    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:

    • Use Jasmine directly to run our API integration tests. (There is a jasmine npm package you can install.) That way, we maintain the familiar 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
    • Use request-promise npm package to generate HTTP requests.

    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.

提交回复
热议问题