3

I've been tasked with setting up some "Integrated Tests" (not "Unit Tests" or "UI tests" [aka. E2E/Protractor]). This integrated test is doing nothing more than testing the controller's $http POST request to the external API, and checking for an expected response case.

I've tried this: - no ngMock (should connect directly to http resources); - with ngMock (couldn't get through to http resource because passThrough() was undefined); - finally tried with ngMockE2E, passThrough() is supposedly working, but the request doesn't return either of success() or error().

I've tried $httpBackend.flush() and it says "there are no request to flush!" (since it is using passThrough() I presume the flush function is not needed).

I've tried $rootScope.$apply() and that doesn't make any difference.

Not sure how to get this working as expected, is this even possible without using Protractor...? Does anyone even do "integrated tests" for AngularJS apps? It looks like the standard is "unit tests" and "E2E tests", not so much "integrated tests".

The "unit tests" I've got setup use a mocked resource and that calls the success() and error() as expected.

Thoughts/ideas?

[Edit:] Found problem is related to Jasmine async testing. In Jasmine 1.X you need to use run() and waitsFor(), in Jasmine 2.X you can use done() (although I couldn't get 2.X working, it just broke all my tests). So now I'm receiving callback from the $http request but it's always error() being called. Now I have no idea why success() isn't being called. Any ideas?

BuildTester1
  • 625
  • 1
  • 7
  • 22
  • Not including the `angular-mocks.js` script should suffice as it will leave the default `$httpBackend` in place – Phil Nov 07 '14 at 00:43
  • @Phil When I try that, the success/error for the $http request are never fired. The tests show as successful (in jasmine), but I have a `console.log('hello');` inside the success/error that never fires. However, when I run my "unit tests" with the mocked $http request, those "hello" messages appear right away. So for some reason, performing the real request never fires the success/error callbacks, and that means I can't test the response case from the server. – BuildTester1 Nov 07 '14 at 00:51
  • You can use https://github.com/yearofmoo/ngMidwayTester, the setup is quite easy and similar to ngMock. So basically exclude ngMock and replace with ngMidwayTester. – wayne Nov 07 '14 at 03:17
  • @wayne (1) I took a look at ngMidwayTester and I have no idea how I would use that to test my app. It seems I would have to feed it a direct link to open, which seems counter-intuitive to what I want to do, which is to execute a specific piece of code that is making the $http request, ie. a method in my service, and just catch the callback. (2) I updated my original question, any idea as to why I can't get a success() result...? Is Karma or Jasmine incapable of making external calls? – BuildTester1 Nov 08 '14 at 22:30
  • You did not show how your service is implmented, so I don't know what to write to make the ngMidwayTester. If you have not read this http://www.yearofmoo.com/2013/01/full-spectrum-testing-with-angularjs-and-karma.html, it is quite good. You can forget about using ngMockE2E with passthrough because you are thinking it will be the same as ngMock like me when I first using it. ngMockE2E need to be written as a separate module or into your actual service implemetation to work. – wayne Nov 09 '14 at 03:01
  • you can read how to make ngMockE2E work. http://chariotsolutions.com/blog/post/angularjs-corner-ngmock-ngmocke2e-libraries/ and http://blogs.burnsidedigital.com/2013/09/and-httpbackend-mock-for-all-unit-e2e-testings/ – wayne Nov 09 '14 at 03:02
  • @wayne Turns out I got the integration test working without using `ngMockE2E` or `ngMidwayTester`. There was a slew of other issues I had to work through, but I managed to get it working now (see answer). – BuildTester1 Nov 10 '14 at 23:33

1 Answers1

2

Found the solution! Had several issues that I had to figure out.

  1. Jasmine async: when doing an $http request, the test will complete before the callback is run. So you have to wait for the callback before allowing Jasmine to run the expect() statement. In Jasmine 1.5 this means using run() and waitsFor(). In Jasmine 2.0 this means using done(). But setTimeout() and setInterval() won't work otherwise.

  2. Jasmine 2.0: when running app that has require.js/AngularJS, Jasmine will load all tests in parallel. But you need to make sure that the app has been bootstrap in the initial app_test.js file before running any of the other tests. See: "angularAMD must be bootstrapped" section.

  3. SSL issues: PhantomJS has trouble opening https:// links. Try connecting to the http:// variant. If that works, you know the issue is with SSL. You can modify your karma config for PhantomJS to pass an attribute (ie. --ssl-protocol=any) to get it working. Or ultimately try testing in another browser altogether (ie. ['Chrome', 'Firefox', 'Safari', 'IE']).

Example karma.conf.js file:

browsers: ['PhantomJS_SSL'],

customLaunchers: {
  'PhantomJS_SSL': {
    base: 'PhantomJS',
    flags: [
      '--ignore-ssl-errors=true', 
      '--ssl-protocol=any',
      '--web-security=false'
    ]
  }
},

To see if your $http requests are being called, use an application like Fiddler (free) to see what http requests are being run on your machine. When you run your karma/jasmine tests, it will show all requests that are being made.

BuildTester1
  • 625
  • 1
  • 7
  • 22