view doesn't load when I mock backend

All we need is an easy explanation of the problem, so here it is.

I’m trying to test one particular element of user interface. To do so I need particular request to my backend to respond with predefined data, but all other requests should pass through. Here’s how I do it (coffee for more readability):

describe 'select2 combobox widget', ()->
  httpBackendMock = () ->
     angular.module 'httpBackendMock', ['ngMockE2E', 'fmAppApp']
        .run ($httpBackend)->
            dummyCategories = [
               {id: 1, name: 'foo', icon: '', user_id: 5},
               {id: 2, name: 'bar', icon: '', user_id: 5},
               {id: 3, name: 'baz', icon: '', user_id: 5},
               {id: 4, name: 'quax', icon: '', user_id: 5}
            ]

            $httpBackend.whenGET '/api/categories'
                .respond ()->
                    [200, dummyCategories]
            $httpBackend.whenGET /.*/
                .passThrough()
            $httpBackend.whenGET /^\/views\//
                .passThrough()
            $httpBackend.whenGET /^\/scripts\/.*/
                .passThrough()
            $httpBackend.whenGET /^\/scripts\//
                .passThrough()
            $httpBackend.whenGET /^\/bower_components\//
                .passThrough()
            $httpBackend.whenGET(/\.html$/).passThrough()

  browser
     .addMockModule 'httpBackendMock', httpBackendMock

so basically what I do here is create new module on top of my application module fmAppApp and angular ngMockE2E and tell Protractor about it.

And for the sake of completeness I’ll show here one simple statement inside this describe block:

it 'should allow user to type in anything', ()->
    browser.get 'http://localhost:9000/#/'
    element By.model 'category.selected'
        .click()
    input = element By.css '.ui-select-search'
    input.sendKeys 'newtestcategory'
    expect input.getAttribute('value')
        .toBe 'newtestcategory'

when I run grunt protractor it opens browser, navigates to specified url (http://localhost:9000/#/) as it should and then I see blank page and spec failures with this error:
NoSuchElementError: No element found using locator: by.model("category.selected")

Unfortunately this message is all I have since I can’t open firebug and see what went wrong for obvious reasons. I guess I could redirect logging from browser console somehow and see what is root of evil here but I don’t know how. Maybe someone encountered that as well and knows what it might be?
Update:
I did as Cétia below suggested and I got this message in logs:

message: 'http://localhost:9000/bower_components/angular/angular.js 11607:24 Error: Unexpected request: POST /api/login

Now why is that? Should I add ‘api/login’ to passThrough() ?

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

To be sure that your mock is loaded, you can add console.log inside, and, in your protractor test add :

browser.manage().logs().get('browser').then(function(browserLog) {
    console.log('log: ' + require('util').inspect(browserLog));
});

In order to output browser logs in your protractor console (after your browser.get).

Method 2

It seems I didn’t provide sufficient information. I left out some code that I thought was irrelevant with intent to not overwhelm you, but as it turned out it was a stumbling block.

browser.get 'http://localhost:9000/#/'
element By.model 'email'
  .sendKeys '[email protected]'
element By.model 'password'
  .sendKeys '123456'
element By.cssContainingText 'form[name=login] button', 'Войти'
  .click()

This code is responsible for logging user in, I need it here because unauthorized users aren’t allowed to see the view I wanted to test.
I thought I made sure all requests make it through, but of course I forgot that my login request is a POST request. So problem was solved simply by adding

$httpBackend.whenPOST /.*/
      .passThrough()

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply