10

I've searched around quite a bit on this problem, but can't find a solution.

I'm trying to mock my backend, which is well tested so I can completely isolate my frontend. I've tried using protractor-http-mock and also various efforts with angular-mocks.

Having settled on the angular-mocks method with HttpBackend, I'm getting this error when firing up my protractor tests:

MBP:test-site admin$ protractor protractor.conf.js
Using ChromeDriver directly...
[launcher] Running 1 instances of WebDriver
[launcher] Error: ReferenceError: window is not defined
    at Object.<anonymous> (/Users/Ed/Sites/F4F/web/node_modules/angular/angular.js:30426:4)
    at Module._compile (module.js:413:34)
    at Object.Module._extensions..js (module.js:422:10)
    at Module.load (module.js:357:32)
    at Function.Module._load (module.js:314:12)
    at Module.require (module.js:367:17)
    at require (internal/module.js:16:19)
    at Object.<anonymous> (/Users/Ed/Sites/F4F/web/node_modules/angular/index.js:1:1)
    at Module._compile (module.js:413:34)
    at Object.Module._extensions..js (module.js:422:10)
[launcher] Process exited with error code 100

This is my protractor.conf.js

exports.config = {

    directConnect: true,

    // Capabilities to be passed to the webdriver instance.
    capabilities: {
        'browserName': 'chrome'
    },

    chromeOnly: true,
    chromeDriver: './node_modules/protractor/selenium/chromedriver',

    // Framework to use. Jasmine 2 is recommended.
    framework: 'jasmine2',

    baseUrl: 'http://localhost:5000/',
    seleniumAddress: 'http://127.0.0.1:4444/wd/hub',

    // Spec patterns are relative to the current working directly when
    // protractor is called.
    specs: ['./tests/**/*.js'],

    // Options to be passed to Jasmine.
    jasmineNodeOpts: {
        showColors: true,
        defaultTimeoutInterval: 30000
    }

};

And this is my test:

'use strict'

var angular         = require('angular');
var angular_mock    = require('angular-mocks');
var HttpBackend     = require('httpbackend');
var backend         = null;

describe("Footer", function () {

    beforeEach(function() {
        backend = new HttpBackend(browser);
    });

    afterEach(function() {
        backend.clear();
    });

    describe("Display Values", function () {

        it("should show correct contact details", function () {

            backend.whenGET(/app/).respond({
                "name": "ExampleApp",
                "company": {
                    "code": "EXA",
                    "name": "ExampleApp",
                    "brand_name": "ExampleApp",
                    "head_office_id": 3,
                    "display_email": "sales@example.com",
                    "display_tel": "+44 (0) 1234 56789"
                }
            });

            browser.get('/');

            var tel_li      = $('#footer .top li:first-child');
            var email_li    = $('#footer .top li:last-child');

            expect(tel_li.getText()).toEqual('+44 (0) 1234 56789');
            expect(email_li.getText()).toEqual('sales@example.com');

        });
    });
});

Can anybody help please?

--- Responding to @alecxe's comment

Revising the test to look like this:

'use strict'

describe("Footer", function () {

    describe("Display Values", function () {

        it("should show correct contact details", function () {

            browser.get('/');

        });
    });
});

Gives the following result:

MBP:test-site admin$ protractor protractor.conf.js
Using ChromeDriver directly...
[launcher] Running 1 instances of WebDriver
Started
.


1 spec, 0 failures
Finished in 0.749 seconds
[launcher] 0 instance(s) of WebDriver still running
[launcher] chrome #1 passed
Ed Stephenson
  • 686
  • 1
  • 6
  • 25
  • Sounds like a problem with the app itself: what if you go to `http://localhost:5000/` - do you see the app loaded and no errors on the console? – alecxe Feb 17 '16 at 14:24
  • Yep! Outside of the testing the app runs fine. This http call is resolved perfectly via UI-Router. I can use the app as normal. I've pretty much developed it and I'm now coming back to write tests before deployment. I know that's naughty, but... – Ed Stephenson Feb 17 '16 at 16:01
  • I've also searched the whole app for loose variables named 'window' on the off chance, but nothing comes up. – Ed Stephenson Feb 17 '16 at 16:03
  • Okay, what if you remove all of the requires and mocks from the test and leave `browser.get()` only - is it passing now with no errors? Thanks! – alecxe Feb 17 '16 at 16:08
  • @alecxe I'll put the revised test below the last paragraph above. – Ed Stephenson Feb 17 '16 at 16:12
  • The problems arise as soon as I start including angular-mocks. If I run the tests to match the data in the backend, everything works fine. When including angular-mocks start mocking responses from the backend, the "ReferenceError: window is not defined" error appears. – Ed Stephenson Feb 17 '16 at 16:16
  • I have the same problem with mocha framework, do you resolve it? – Emna Ayadi Apr 13 '16 at 09:10
  • I still haven't solved this problem. – Ed Stephenson Jul 13 '16 at 08:19
  • In case anyone else stumbled upon this problem and is running Angular 2, look no further - mock modules is not supported in Angular 2. None of the answers provided here works on Angular 2. Took me a while to figured this out. https://stackoverflow.com/questions/36354233/protractor-mocking-backend-with-angular2-on-api-request – HaC Oct 27 '17 at 21:26

2 Answers2

1

Don't import angular-mocks and angular at all, httpbackend don't need them to be imported:

'use strict'

var HttpBackend     = require('httpbackend');
var backend         = null;

describe("Footer", function () {

    beforeEach(function() {
        backend = new HttpBackend(browser);
    });

    afterEach(function() {
        backend.clear();
    });

    describe("Display Values", function () {

        it("should show correct contact details", function () {

            backend.whenGET(/app/).respond({
                "name": "ExampleApp",
                "company": {
                    "code": "EXA",
                    "name": "ExampleApp",
                    "brand_name": "ExampleApp",
                    "head_office_id": 3,
                    "display_email": "sales@example.com",
                    "display_tel": "+44 (0) 1234 56789"
                }
            });

            browser.get('/');

            var tel_li      = $('#footer .top li:first-child');
            var email_li    = $('#footer .top li:last-child');

            expect(tel_li.getText()).toEqual('+44 (0) 1234 56789');
            expect(email_li.getText()).toEqual('sales@example.com');

        });
    });
});
alecxe
  • 414,977
  • 106
  • 935
  • 1,083
  • I copied and pasted your code to be sure, but it's still throwing exactly the same error as first mentioned.. – Ed Stephenson Feb 17 '16 at 17:09
  • If I remove the require("angular"), the error changes from `"Error: ReferenceError: window is not defined"` to `"Error: [$injector:nomod] Module 'ngMockE2E' is not available!"` which surely implies that we need to include anuglar-mocks? – Ed Stephenson Feb 17 '16 at 17:12
  • @EdStephenson I think it's your application under test that should have `angular-mocks` loaded, not your test itself. And, you don't need to import angular in the test too. – alecxe Feb 17 '16 at 17:23
  • 1
    Including 'ngMockE2E' causes the whole app to fail both in the tests and when running normally. When running normally, every $http call errors with `"Error: Unexpected request: GET"`. The tests fail with "ReferenceError: window is not defined" again. I also tried mocking the module in the beforeEach part of the test with the 'ngMockE2E' included, and this failed with and "Unexpected ." error. Presumably from the "angular.module(" element, although it didn't give a clear picture of where the unexpected dot was. I'm struggling to understand how this is so hard to get going...! – Ed Stephenson Feb 17 '16 at 21:03
1

I had your exact issue, and ended up solving it by importing angular-mocks as a raw string and injecting it via browser.addMockModule:

const fs = require('fs');
const ngMock = fs.readFileSync(__dirname + '/../../node_modules/angular-mocks/angular-mocks.js', 'utf-8');

browser.addMockModule('ngMockE2E', ngMock);
browser.addMockModule('e2e', function e2e() {
  angular.module('e2e', ['ngMockE2E'])
    .run(['$httpBackend', function($httpBackend) {
      // Your mocked calls here
    }])
});

This will force the driver to compile the script during runtime, where window is available. However, this breaks if you have browser.ignoreSynchronization = true; however.

csvan
  • 7,796
  • 8
  • 40
  • 81