yevhenpavliuk / ng-mock-e2e

Fake HTTP back end in Protractor end-to-end tests similarly to how it's done in AngularJS unit tests.
MIT License
15 stars 1 forks source link

ngMockE2E is not available #1

Open ghost opened 8 years ago

ghost commented 8 years ago

Hello, first of all thanks a lot for this library, it's working great. However I noticed a random issue when I run E2E test. Sometimes the module is not available and I guess it's because the embedScript is running in parallel of the addMockModule, and probably, sometimes, the script is not injected into the browser when try to add the module. I think you should wait until the bower dependency has been loaded into the page first and the start using the module.

beforeEach(function () {
  ngMockE2E.addMockModule();
  ngMockE2E.addAsDependencyForModule('myApp');
  ngMockE2E.embedScript('/bower_components/angular-mocks/angular-mocks.js'); // This should be the cause of the problem
});

This is my random error:

yevhenpavliuk commented 8 years ago

@azornada-resilient Hello Andrea, Sorry I didn't reply earlier - I just saw the issue and there was no email sent to me regarding that. I'll take a look at it this weekend. Thanks for your feedback!

yevhenpavliuk commented 8 years ago

Didn't get to it this weekend. I'll try again in a week.

andreasonny83 commented 8 years ago

no worry, just let me know if you need more information when you're ready

yevhenpavliuk commented 8 years ago

@andreasonny83

script is not injected into the browser when try to add the module

That's exactly the reason.

I felt wrong when I added embedScript to the library. This method is out of scope of the library's responsibilities.

I think it should be deprecated. Instead, adding angular-mocks.js should be handled outside the library. For instance, it can be added by client code based on a query string parameter:

<script>
if (/(?:\?|&)protractor(?:&|$)/.test(location.search)) {
  document.write('<script src="https://code.angularjs.org/1.5.5/angular-mocks.js"></' + 'script>');
}
</script>

Or maybe there's a library that allows including scripts so that Protractor waits until they load. In this case just use such a library.

andreasonny83 commented 8 years ago

I agree it shouldn't be a library responsibility and it shouldn't force to include the angular mock because your library doesn't know which version of Angular and angular-mock the user want to use on his/her project. Instead, what you can do in order to optimise your library, could be to verify if the angular-mock has been included in the project and, if not, disable the library and report a warning to the user.

yevhenpavliuk commented 8 years ago

@andreasonny83 Sounds reasonable. Thanks! I'll reserve some time to work on this during the week (I have vacation now). I'll keep you updated.

bladyk1 commented 7 years ago

Hi, I have exactly same error mentioned in 1st post, I'm testing UI and I would like to mock https request the way is described in second post here https://github.com/angular/protractor/issues/125 I have the mocked-backend.js including code:

var ngMockE2E = require('ng-mock-e2e');

exports.httpBackendMock = function() {
    angular.module('httpBackendMock', ['app', 'ngMockE2E'])
        .run(function ($httpBackend) {
            $httpBackend.whenGET('..config.json')
                .respond([
                    {
                        ...
                    }
                ]);
        });
};

then in onPrepare hook I have:

    var mockModule = require('./mocked-backend');
    browser.addMockModule('httpBackendMock', mockModule.httpBackendMock);

and angular-mocks is added as a dependency to package.json

    "angular-mocks": "1.6.5"

Can anyone help me with this please? Do I have to modify website code to make it work ?

yevhenpavliuk commented 7 years ago

Hi @bladyk1,

Let me look into the issue.

Sorry, I've been neglecting it for a long time, but I hope I've gained some enthusiasm to finally start working on it.

I'll try to do what I can and write you back here soon.

bladyk1 commented 7 years ago

ok, thanks

yevhenpavliuk commented 7 years ago

Hey @bladyk1,

You don't need ngMockE2E node module in your case. I think you just need to embed angular-mocks.js and add it as a dependency for your app. Try this:

exports.httpBackendMock = function() {
    angular.module('app').requires.push('ngMockE2E'); // Add ngMockE2E from angular-mocks.js as a dependency for your app.
    angular.module('app').run(function ($httpBackend) {
            $httpBackend.whenGET('..config.json')
                .respond([
                    {
                        ...
                    }
                ]);
        });

    // Embed angular-mocks.js
    const script = document.createElement('script');
    script.src = 'bower_components/angular-mocks/angular-mocks.js'; // The actual needs to be adjusted for your project.
    document.body.appendChild(script);
};
    var mockModule = require('./mocked-backend');
    browser.addMockModule('app', mockModule.httpBackendMock);

And don't forget to remove the module in afterEach:

    afterEach(() => {
        browser.removeMockModule('app');
    });

As you can see, you can avoid creating an extra module httpBackendMock.

Nevertheless, please, check out the updated README and this tiny example project I made this weekend. I hope it'll give you better insights. Please, tell me if not, and I'll try to help you further.

yevhenpavliuk commented 7 years ago

Hello @azornada-resilient (@andreasonny83),

Sorry for this tardy reply. I lost enthusiasm back then because my daily work changed so that there was no need in using this module, and I thought that other people didn't really use it. But recent issues and download numbers gave me a hope that it is not completely dead. So I got some enthusiasm back to continue working on the project.

I start looking into the issue, but I couldn't reproduce it. I made this tiny example project during this weekend.

I found out that if you remove a mock module at the end of it, it prevents all functions added under the name from running:

escribe('example without ngMockE2E', () => {
  beforeEach(() => {
    browser.addMockModule('example', () => {
      angular.module('example').requires.push('ngMockE2E');

      const script = document.createElement('script');
      script.src = 'bower_components/angular-mocks/angular-mocks.js';
      document.body.appendChild(script);
    });
  });

  afterEach(() => {
    browser.removeMockModule('example'); // For the mock module that's added in `beforeEach`.
    browser.removeMockModule('example'); // For the mock module that's added in `it`.
    // The number of removals should be equal to the number of additions.
    // Removing the mock module in `it` prevents all registered functions from execution.
  });

  it('should have heading "It works!" if the server responds "It works!"', () => {
    browser.addMockModule('example', () => {
      angular.module('example').
        run($httpBackend => {
          $httpBackend.when('GET', 'heading').respond('It works!');
        });
    });

    browser.get('/');
    expect($('h1').getText()).toEqual('It works!');

    // browser.removeMockModule('example'); // Removing the mock module in `it` prevents all registered functions from execution.
  });
});

It's not the issue you described, but it looked somewhat related, so I decided to let you know. In case your problem is still actual, please, give me an example of your project organization where I could reproduce the issue.

bladyk1 commented 7 years ago

Hi @yevhenpavliuk Really appreciate your help. I see most of examples I found till now about mocking http request is used with Jasmine. I'm using Protractor with Cucumber, but it should work I think

I changed my code to yours accordingly Instead of

script.src = 'bower_components/angular-mocks/angular-mocks.js';

I have

script.src = '/node_modules/angular-mocks/angular-mocks.js';

and now I received error: Error: Error while running module script app: unknown error: 'script' must be a string What else can be wrong ?

yevhenpavliuk commented 7 years ago

@azornada-resilient (@andreasonny83),

I've found how to reproduce the issue. You were right. It happens if downloading of angular-mocks.js takes longer. For instance, if the file is taken from a remote CDN instead of the local server.

I haven't come up with a solution yet. The idea is to have angular-mocks.js ready before the app bootstraps. So, yeah, as it's been mentioned before, embedScript isn't good enough.

yevhenpavliuk commented 7 years ago

@bladyk,

I have an assumption. The example code uses ES6 features (const in particular). Maybe your browser environment doesn't support that. Try replacing const with var.

Other than that, you're using /node_modules/angular-mocks/angular-mocks.js as the URL. Is the file available on your host?

Alternatively, just to make sure it works for you, try to put the entire contents of angular-mocks.js as a mock module:

browser.addMockModule('example', function() {
  // Copy and paste the source code of https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular-mocks.js here.
});

Instead of embedding a local script:

browser.addMockModule('example', function() {
  const script = document.createElement('script');
  script.src = '/node_modules/angular-mocks/angular-mocks.js';
  document.body.appendChild(script);
});