How can I make a POST request from a Protractor test?
Asked Answered
E

4

14

I would like to make a POST request (with JSON payload) to a database server prior to running a Protractor test, in order to inject test data. How can I do this, if at all possible?

Echolalia answered 10/2, 2014 at 22:18 Comment(2)
See #21056460Upon
@AndresD Is there no other way? I wouldn't mind using the Node http module, but can't figure out how to make async calls from Jasmine tests.Echolalia
E
5

I found a way to do it, with the help of Andres D. The gist of it is to run a script in the browser via browser.executeAsyncScript and inject the $http service in there. The $http service is then told to make a POST request. Here's example CoffeeScript of how it's done:

browser.get('http://your-angular-app.com')
browser.executeAsyncScript((callback) ->
  $http = angular.injector(["ng"]).get("$http")
  $http(
    url: "http://yourservice.com"
    method: "post"
    data: yourData
    dataType: "json"
  )
  .success(->
    callback([true])
  ).error((data, status) ->
    callback([false, data, status])
  )
)
.then((data) ->
  [success, response] = data
  if success
    console.log("Browser async finished without errors")
  else
    console.log("Browser async finished with errors", response)
)
Echolalia answered 15/2, 2014 at 22:9 Comment(2)
where does this angular at 3rd line come from?. I got undefined angular.Carbo
@Carbo I don't have the code in front of me, but it's part of Angular's global API. IIRC that function is executed within the context of the loaded page (e.g., http://your-angular-app.com), which must have loaded Angular.Echolalia
G
6

You can just use another library to run the POST request if you just want to populate your database.

For example, you can use superagent in your beforeEach like so:

var request = require( "superagent" );

describe( "Something", function() {

  beforeEach( function( done ) {
    request
      .post( "http://localhost/api/foo" )
      .send( {data : "something"} )
      .end( done );
  } );

} );
Gore answered 20/5, 2014 at 10:37 Comment(0)
E
5

I found a way to do it, with the help of Andres D. The gist of it is to run a script in the browser via browser.executeAsyncScript and inject the $http service in there. The $http service is then told to make a POST request. Here's example CoffeeScript of how it's done:

browser.get('http://your-angular-app.com')
browser.executeAsyncScript((callback) ->
  $http = angular.injector(["ng"]).get("$http")
  $http(
    url: "http://yourservice.com"
    method: "post"
    data: yourData
    dataType: "json"
  )
  .success(->
    callback([true])
  ).error((data, status) ->
    callback([false, data, status])
  )
)
.then((data) ->
  [success, response] = data
  if success
    console.log("Browser async finished without errors")
  else
    console.log("Browser async finished with errors", response)
)
Echolalia answered 15/2, 2014 at 22:9 Comment(2)
where does this angular at 3rd line come from?. I got undefined angular.Carbo
@Carbo I don't have the code in front of me, but it's part of Angular's global API. IIRC that function is executed within the context of the loaded page (e.g., http://your-angular-app.com), which must have loaded Angular.Echolalia
G
3

It is possible to run some async setup code in your onPrepare function of your protractor config. You need to explicitly tell protractor to wait for your request to finish. This can be done with flow.await() which plays nice with promises.

onPrepare: function() {

  flow = protractor.promise.controlFlow()

  flow.await(setup_data({data: 'test'})).then( function(result) {
    console.log(result);
  })

}

** As of protractor 1.1.0 on prepare can return a promise, so the use of flow to explictly wait for the promise to resolve is unnecessary.

See: https://github.com/angular/protractor/blob/master/CHANGELOG.md

Goda answered 11/2, 2014 at 16:51 Comment(5)
Not familiar with onPrepare, but would this be run once for the whole suite? I would really need per-test setup/teardown methods.Echolalia
Yes, it is run once, before any tests are run. It doesn't sound like onPrepare would do what you want.Goda
flow.await seems to work in an it or beforeEach function also; I don't think there's a restriction to onPrepare.Var
Forgive me if I'm missing something, but doesn't await expect a promise? Protractor allows you to return a promise from an onPrepare function, so you could just do return setup_data({data: 'test'});.Classics
This was written prior to Protractor 1.1.0, before onPrepare allowed you to return a promise. It could indeed be simplified.Goda
L
1

Another way of doing POST request from protractor is using "http"

const http = require('http');

   const data = yourData; 
   const options = {
        port: portnumber,
        hostname: hostname,  // without http
        path: '/api/path/',
        method: 'POST',
        headers: {
            "content-type": "application/json"                
        }
    };

    const request = http.request(options, function (result) {
        var body = '';

        result.on("data", function (chunk) {
            body = body + chunk;
        });

        result.on("end", function () {
          console.log(body);
        });
    });

    request.write(JSON.stringify(data));
    request.end(); 
Lambaste answered 11/7, 2018 at 15:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.