Giter Site home page Giter Site logo

Comments (20)

juliemr avatar juliemr commented on May 5, 2024

It'd help to get a better idea of what you're hoping to test. Protractor is intended for end to end tests, so the primary use case is when you have an actual backend hooked up. It sounds like you're looking to test just your UI via your static files, without any real $http requests hitting backends?

Protractor provides a way to override modules, so it would certainly be possible to have a helper file that would make setting up your $http mocks easier. You still need some way to serve your static files, though.

from protractor.

appleton avatar appleton commented on May 5, 2024

My exact case is that I have a rails app serving an API and the static files which make up my Angular app. I'd like to test the Angular app but stop at the AJAX requests and keep the rails app out of it.

I have a lightweight connect server which serves the Angular app for integration testing and currently it just returns canned responses to the AJAX API requests. I'd like to be able to make assertions against those requests and set them to return different responses in different tests.

I didn't realise that I could override modules from protractor - that sounds like exactly what I need! I take it I can just use the mock $httpBackend like I do in Karma unit tests? Is there an example somewhere of how to go about this with Protractor?

from protractor.

davemo avatar davemo commented on May 5, 2024

Hey @mrappleton, we do something similar with a Rails app that acts as only API in dev and also serves static assets in production. We use Lineman to manage our static assets in dev mode and run a small apiProxy configuration that talks to the Rails API transparently. Lineman has a built in fake-server that sounds similar to what you are using connect for. Once we are ready to move to prod we execute lineman build which bundles up all our static assets that we just dump into the Rails public directory.

If you need the flexibility of defining the API responses in each test you may want to check out a small gem that we made @testdouble called servme. It gives you a small DSL that allows you to stub responses for particular requests, here's an example:

before(:each) do
  on({
    :url => "/api/login",
    :method => :post,
    :params => {
      :login => "todd",
      :password => "scotch"
    }
  }).respond_with(:token => "1234567890")
end

In general I agree with @juliemr that Protractor is the ideal tool for writing tests that hit your actual backend or an actual fake backend as opposed to $httpBackend; I feel the latter is most appropriate for unit tests.

from protractor.

appleton avatar appleton commented on May 5, 2024

Hey @davemo serveme looks very cool, however what I'm really after though is to avoid Rails entirely with these tests and just isolate the Angular app as a system. I think having access to the mock $httpBackend would do the job for me, @juliemr do you have any pointers on getting this set up? Will I be able to access the mocked object from within my specs?

from protractor.

juliemr avatar juliemr commented on May 5, 2024

@mrappleton - unfortunately, the javascript running in your application is separated from the javascript running in your specs, so you won't be able to access the mocked object from your specs. The only way that code is sent to the browser under test is via webdriver.executeScript, which can only return a primitive or an element. That means you won't be able to use the unit testing $httpBackend. Here's an example of a very simple way to override a module:

    // This function will be executed in the context of the application under test, so it may not refer to any local variables.
    var mockModuleA = function() {
      var newModule = angular.module('moduleA', []);
      newModule.factory('$http', function() {
        mockHttp = function() { return 'foo!' };
        return mockHttp;
      });
    };

    it('should override services via mock modules', function() {
      ptor.addMockModule('moduleA', mockModuleA);\
      ptor.get('app/index.html');
      // your test here
    });

from protractor.

appleton avatar appleton commented on May 5, 2024

Thanks for the explanation @juliemr, makes perfect sense. What I've decided to do is change my API mocking to be a little smarter so it can more closely simulate POSTing and saving data - that way I can just do a POST then reload a page and assert that the data is shown.

from protractor.

ozanturksever avatar ozanturksever commented on May 5, 2024

i use ngMockE2E as mock, works perfect.

var mock_code = function () {
    angular.module('httpBackendMock', ['ngMockE2E'])
        .run(function ($httpBackend) {
            $httpBackend.whenGET('/api/login').respond({status:'loggedin'});
            $httpBackend.whenGET(/.*/).passThrough();
        });
};

it('should override services via mock modules', function() {
      ptor.addMockModule('httpBackendMock', mock_code);
      ptor.get('app/index.html');
      // your test here
});

from protractor.

benlesh avatar benlesh commented on May 5, 2024

@ozanturksever How are you getting the ngMockE2E module? Do you have it referenced in your test or on the browser already? The code that you have won't work unless the angular-mock.js file is referenced somewhere.

from protractor.

ozanturksever avatar ozanturksever commented on May 5, 2024

i have grunt tasks that generates reference for it, so for tests it is referenced after angular.js. I also made a little change in angular-mocks.js. It is not queuing responses anymore, responds immediately.

$ diff angular-mocks-protractor.js angular-mocks.js
911c911
<           setTimeout(resp,0);
---
>           responses.push(resp);

from protractor.

benlesh avatar benlesh commented on May 5, 2024

Very clever, @ozanturksever, thanks for the insight.

from protractor.

mcalthrop avatar mcalthrop commented on May 5, 2024

@juliemr: with reference to your suggested solution... thank you. My setup is slightly different, and I'm having trouble adapting your solution to my requirements.

The code for the service (ie, the service that I want to mock) looks something like this:

angular.module('XServiceModule', ['ngResource']).factory(
    'XService',
    function ($resource) {
        return $resource(
            'path/to/service'
        );
    }
);

That service is called as a POST from the controller like this:

XService.save(
    {},
    JSON.stringify(YModel),
    function (value, getResponseHeaders) {
        // everybody is happy; do something
    },
    function (httpResponse) {
        // error handling here
    }
);

From an e2e testing pov (I'm using Protractor), what I want to do is to specify exactly the JSON object that is returned when that service is called – but I'm stuck!

Can you help out? Am sure I am close... :-)

many thanks

Matt

from protractor.

mcalthrop avatar mcalthrop commented on May 5, 2024

I think I might have found a solution:

// this mock service will return success
var mockXServiceModuleSuccess = function () {
    angular.module('XServiceModule', []).factory(
        'XService',
        function () {
            return {
                save: function (params, postData, onSuccess, onError) {
                    var value = {},         // set as necessary
                        getResponseHeaders = function () {
                            return {};      // set as necessary
                        };
                    onSuccess(value, getResponseHeaders);
                }
            };
        }
    );
};
// and this one will fail
var mockXServiceModuleError = function () {
    angular.module('XServiceModule', []).factory(
        'XService',
        function () {
            return {
                save: function (params, postData, onSuccess, onError) {
                    var httpResponse = {};  // set as necessary
                    onError(httpResponse);
                }
            };
        }
    );
};

And then, at the relevant parts in the testing code, add the mocked module:

browser.addMockModule('XServiceModule', mockXServiceModuleSuccess);

or:

browser.addMockModule('XServiceModule', mockXServiceModuleError);

I have given that a go, and it seems to be working.

Does it look right to you? Is there something I have missed?

cheers

Matt

from protractor.

mcalthrop avatar mcalthrop commented on May 5, 2024

The only thing I think I might have missed is to return a promise from the mocked save() method, which I guess would look like this:

return $q.defer().deferred.promise;

Does that look right?
And how would I inject $q?

from protractor.

mcalthrop avatar mcalthrop commented on May 5, 2024

Bump.

I have found that using mockXServiceModuleSuccess() (in my sample code, above) works, but using mockXServiceModuleError() does not work: the onError() parameter is never called.

So I'm guessing that I am not correctly mocking the behaviour of the Promise that would normally be returned by $http.

Could someone point me in the right direction?

Spent quite a bit of time on this already.

cheers

Matt

from protractor.

lucassus avatar lucassus commented on May 5, 2024

ngMockE2E does the job for simple specs but what about with complex multi-stage scenarios?
For example:

  1. go to the list of products (mock GET /api/products.json), assets that we have 3 rows
  2. click delete product (mock 'DELETE /api/products/1.json)
  3. products list will be reloaded (mock GET /api/products.json again, this time return a list with 2 rows)
  4. assert that the list contains 2 rows

Can we somehow redefine $httpBackend stubs several times in the flow (for examples for GET /api/products.json request)?

from protractor.

russmatney avatar russmatney commented on May 5, 2024

@lucassus i've been dealing with a complicated mock situation for the last week or so - have just made a breakthrough - you can use clearMockModules() in tandem with addMockModule to hand in a different set of mocks for any test.

For now, i've added a before and after to all my tests

beforeEach ->
  ptor.addMockModule 'MockedBackend', MockedBackend

afterEach ->
  ptor.clearMockModules()

it 'should blah blah blah', -> etc

You should be able to remove that beforeEach and add a custom mockedBackend per describe or per test.

from protractor.

dineshmani avatar dineshmani commented on May 5, 2024

@ozanturksever .Yes I followed similar to your thinking and I am new to protractor. can you please instruct for the correct solution. I have created mock module thats replace the main module during bootstrap process, and the httpBacked intercepts the desired calls and returns the dummy data. Since my app not interact with real backend.

But In my case I want to test the case with server exception, The same url we need to test for both positive case and negative case.

from protractor.

unDemian avatar unDemian commented on May 5, 2024

Hey guys,
I created a little mock module to help me handle success and error scenarios, maybe it will help you better organize mocking.

https://github.com/unDemian/protractor-mock

from protractor.

npmlady avatar npmlady commented on May 5, 2024

i was following exact same example with addMockmodule for ssome reason it was not mocking my backend resource calls

var mock_code = function () {
angular.module('httpBackendMock', ['ngMockE2E'])
.run(function ($httpBackend) {
console.log($httpBackend);
$httpBackend.whenGET('someurl').respond('json');
$httpBackend.whenGET('someurl').respond('json1');
$httpBackend.whenGET(/.*/).passThrough();
});
};
console.log(mock_code);
ptor.addMockModule('myapp', mock_code);
ptor.addMockModule('myapp', mock_code);
ptor.addMockModule('httpBackendMock', mock_code);

        browser.addMockModule('myapp', mock_code);
        browser.addMockModule('myapp', mock_code);
        browser.addMockModule('httpBackendMock', mock_code);
        ptor.driver.get('appurl');

and this is inside my protractor specs and it just not complaining any issue and not mocking my resource calls

from protractor.

AQadeer avatar AQadeer commented on May 5, 2024

This is be the good solution. Which i am using right now.
http://stackoverflow.com/a/34610987/3840665

from protractor.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.