Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I mock the result in a $http.get promise when testing my AngularJS controller?

After much reading, it seems that the recommended way to call a web service from an AngularJS controller is to use a factory and return a promise from that.

Here I have a simple factory which calls a sample API.

myApp.factory('MyFactory', ['$http',function($http) { var people = {         requestPeople: function(x) {             var url = 'js/test.json';             return $http.get(url);         }     }; return people; }]); 

And this is how I call it in the controller

myApp.controller('MyCtrl1', ['$scope', 'MyFactory', function ($scope, MyFactory) {         MyFactory.requestPeople(22).then(function(result) {              $scope.peopleList = result;         }); }]); 

While it works fine, I would like to be able to mock the result that is passed in when then is called. Is this possible?

My attempt so far has produced nothing. This is my attempt:

//Fake service var mockService = {     requestPeople: function () {         return {             then: function () {                 return {"one":"three"};             }         }      } };   //Some setup beforeEach(module('myApp.controllers')); var ctrl, scope;  beforeEach(inject(function ($rootScope, $controller) {     scope = $rootScope.$new();      ctrl = $controller('MyCtrl1', { $scope: scope, MyFactory: mockService }); }));  //Test it('Event Types Empty should default to false', inject(function () {     expect(scope.peopleList.one).toBe('three'); })); 

The error that I get when running this in karma runner, is

TypeError: 'undefined' is not an object (evaluating 'scope.peopleList.one')

How can I get this test working with my mocked data?

like image 734
Mendhak Avatar asked Jul 24 '13 05:07

Mendhak


People also ask

What controller do you use in angular to mock remote data for testing?

The HttpClientTestingModule allows you to easily mock HTTP requests by providing you with the HttpTestingController service.

What are mocks in angular?

Mocking is the act of creating something that looks like the dependency but is something we control in our test. There are a few methods we can use to create mocks.

How to unit test HTTP GET request in angular?

This page will walk through Angular unit testing for HTTP GET request using HttpClientTestingModule and TestBed API. We will test Angular HttpClient.get method in our example. 1. When we create the project using CLI, it downloads and installs everything we need to test an Angular application. Angular uses Jasmine test framework.

How to test angular application in chrome?

To test Angular application, we need to run following command. The test result can be seen in command prompt as well as in browser. The above command will start Chrome browser and display test result. We can also use below URL to see test result in any browser. 2. Angular test uses Karma test runner.

What is the difference between @angular/core/testing and @ angular/common/http/testing?

@angular/core/testing contains core testing API such as TestBed . @angular/common/http/testing contains HTTP testing API such as HttpClientTestingModule and HttpTestingController . 1. Technologies Used

How to make HTTP GET request using ES6 promise in angular?

Open your Angular project in your favorite code editor and then go to app.module.ts file and import HttpClientModule service. Then also register it inside the imports array. Next, go to app.component.ts file. Here we will write the core logic to make the HTTP GET request and manage the response using the ES6 Promise in Angular.


1 Answers

I don't think $httpBackend is what you're after here, you want the whole factory to be mocked without it having a dependency on $http?

Take a look at $q, in particular the code sample under the Testing header. Your issue might be resolved with code that looks like this:

'use strict';  describe('mocking the factory response', function () {      beforeEach(module('myApp.controllers'));      var scope, fakeFactory, controller, q, deferred;      //Prepare the fake factory     beforeEach(function () {         fakeFactory = {             requestPeople: function () {                 deferred = q.defer();                 // Place the fake return object here                 deferred.resolve({ "one": "three" });                 return deferred.promise;             }         };         spyOn(fakeFactory, 'requestPeople').andCallThrough();     });      //Inject fake factory into controller     beforeEach(inject(function ($rootScope, $controller, $q) {         scope = $rootScope.$new();         q = $q;         controller = $controller('MyCtrl1', { $scope: scope, MyFactory: fakeFactory });     }));      it('The peopleList object is not defined yet', function () {         // Before $apply is called the promise hasn't resolved         expect(scope.peopleList).not.toBeDefined();     });      it('Applying the scope causes it to be defined', function () {         // This propagates the changes to the models         // This happens itself when you're on a web page, but not in a unit test framework         scope.$apply();         expect(scope.peopleList).toBeDefined();     });      it('Ensure that the method was invoked', function () {         scope.$apply();         expect(fakeFactory.requestPeople).toHaveBeenCalled();     });      it('Check the value returned', function () {         scope.$apply();         expect(scope.peopleList).toBe({ "one": "three" });     }); }); 

I've added some tests around what $apply does, I didn't know that until I started playing with this!

Gog

like image 92
GogLlundain Avatar answered Sep 26 '22 06:09

GogLlundain