Jeroen
Jeroen

Reputation: 63729

How to do an Ajax call in beforeAll for Angular 2+ Protractor e2e tests?

I want to do a POST to my API in the beforeAll of Angular 6 e2e tests. I've tried various approaches, none seem to work. Here's a repro of my scenario.

Start with ng new foobar (Angular 6 CLI) and go into that folder. Open the app.e2e-spec.ts and add the following code inside the describe lambda:

let id: string;

beforeAll((done) => {
  fetch('https://example.org/my-api', { method: 'POST' })
    .then(r => r.json())
    .then(r => {
      id = r;
      done();
    })
    .catch(err => done(err));
});

The reason I want to do the above is because I want to insert an test subject in the database via my API so that I can then use the ID that's returned in later e2e tests.

This unfortunately gives an error:

Failed: fetch is not defined

I've tried some other options as well. First, I tried doing a native xhr, but then I get an error:

Failed: XMLHttpRequest is not defined

Second, I tried doing import { http } from 'https'; and then calling the http.request(...) function but that fails expectedly because VSCode already complained that

[ts] Module '"https"' has no exported member 'http'.

Finally, I've also tried wrapping the fetch in a browser.executeAsyncScript(...) call block, but then I seem unable to capture the result from my POST call outside the browser scope, to be used in the tests.

So, I'm at a loss. What is a good way to do an Ajax POST to my API in the beforeAll of an Angular 6 protractor end to end test?

Upvotes: 1

Views: 454

Answers (1)

Jeroen
Jeroen

Reputation: 63729

After some good 'ole rubber duck debugging I found a solution:

beforeAll((done) => {
  const request = require('request');

  const options = {
    url: 'https://example.org/my-api',
    method: 'POST',
    headers: { 'Content-Type': 'application/json', },
    json: true,
    body: { key: 'dummy value' },
  };

  const callback = (error, response, body) => {
    if (!error && response.statusCode > 200 && response.statusCode < 300) {
      id = body;
      done();
    } else {
      done(error);
    }
  };

  request(options, callback);
});

The key takeaway is that this code is executed in a Node.js context, and that the way to get to a Node.js library for executing Ajax calls is const request = require('request'); (or something similar with http).

The done(...) calls (and the fact that you require it as an argument in your lambda) make Jasmine and Protractor wait for the callback to happen.

Note that at first this approach didn't seem to work, but then I found that the callback was called but that my request was incorrect leading to a 400 status code. I recommend using this VSCode e2e debugging setup to verify if things are working as expected if you still have troubles.

Upvotes: 1

Related Questions