1

I have the following code ... and one of the tests is failing. Please help me in understanding why, and suggest me a way to rectify.

<html>
<head>
    <!-- Jasmine References -->
    <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script>
    <!-- Angular and Angular Mock references -->
    <script type="text/javascript" src="https://code.angularjs.org/1.4.0-rc.2/angular.min.js"></script>
    <script type="text/javascript" src="https://code.angularjs.org/1.4.0-rc.2/angular-mocks.js"></script>
    <!-- The code we need to test -->
    <script type="text/javascript" src="/js/index.js"></script>
</head>
<body></body>
<script type="text/javascript">

    var app = angular.module('peoplesearchApp',[]);

    app.controller('peopleSearchCtrl',function($scope,$http){
        $scope.textChanged = function() {
            // obtain the list of user whose name have the given prefix
            $http.get('/findusers?q='+$scope.searchString.trim()).success(function(data, status) {
                $scope.users = data;
            }).error(function(data, status) {
                console.log("Error: could not retrieve users");
            });
        };
        // make an initial call to retrieve all users
        $scope.searchString = "";
        $scope.textChanged();
    });

    describe('search people app tests', function () {

        var $controller, $httpBackend, $scope;

        // setup before each test run
        beforeEach(module('peoplesearchApp'));
        beforeEach(inject(function (_$controller_, _$httpBackend_) {
            $controller = _$controller_;
            $scope = {};
            $httpBackend = _$httpBackend_;
        }));

        describe('only the users that have their names starting from the search query should be visible', function () {

            it('should show all users for a blank query', function () {
                $httpBackend.expectGET('/findusers?q=').respond(['Sean','Yaw','Lucy','Eric','Rory','Heyley']);
                $controller('peopleSearchCtrl', {$scope: $scope});
                $httpBackend.flush();
                expect($scope.users).toEqual(['Sean','Yaw','Lucy','Eric','Rory','Heyley']);
            });

            it('should show only Rory for query=r', function () {
                $httpBackend.expectGET('/findusers?q=r').respond(['Rory']);
                $controller('peopleSearchCtrl', {$scope: $scope});
                $httpBackend.flush();
                expect($scope.users).toEqual(['Rory']);
            });

        });

    })

</script>
</html>

EDIT: The issue is that in the second test, I want to set $scope.searchString = "r" somehow before issuing a fake http request. I dont know how to do that.

The Error is:

Error: Unexpected request: GET /findusers?q=
Expected GET /findusers?q=r

CodePen : http://codepen.io/amarshanand/pen/MeJXdq

Amarsh
  • 11,214
  • 18
  • 53
  • 78

3 Answers3

1

Modifying a little bit the design of your code

app.controller('peopleSearchCtrl',function($scope,$http){
          console.log($scope);  

          $scope.textChanged = function(_searched) {
                // obtain the list of user whose name have the given prefix
                $http.get('/findusers?q='+_searched.trim()).success(function(data, status) {
                    $scope.users = data;
                }).error(function(data, status) {
                    console.log("Error: could not retrieve users");
                });
            };
            // make an initial call to retrieve all users
            $scope.searchString = "";
            $scope.textChanged($scope.searchString);
        });

The failed test it's working now:

it('should show only Rory for query=r', function () {     //faking the initialize call of the controller  
                  $httpBackend.expectGET('/findusers?q=').respond(['Sean','Yaw','Lucy','Eric','Rory','Heyley']);
                    $httpBackend.expectGET('/findusers?q=r').respond(['Rory']);
                    $controller('peopleSearchCtrl', {$scope: $scope});
                    $scope.textChanged('r');
                    $httpBackend.flush();
                    expect($scope.users).toEqual(['Rory']);
                });

Working codepen: http://codepen.io/gpincheiraa/pen/pbRKMZ

  • didnt work (does it work for you? just copy/paste the code in text editor and run it, if you have a few mins). perhaps because I am setting $scope = {}; in beforeEach(inject) – Amarsh Jun 26 '16 at 03:16
0

Immediate problem I see is this,

beforeEach(inject(function(_$controller_, _$httpBackend_, _$rootScope_) {
    $controller = _$controller_;
    scope = _$rootScope_.$new();

You should create new scope from $rootScope.

Update:

If this doesnt help, share the error that you get.

it('should show only Rory for query=r', function () {
    $httpBackend.expectGET('/findusers?q=').respond(['Sean','Yaw','Lucy','Eric','Rory','Heyley']);
    $httpBackend.expectGET('/findusers?q=r').respond(['Rory']);

    $controller('peopleSearchCtrl', {$scope: $scope});

    $scope.searchString = 'r';
    $scope.textChanged();    
    $httpBackend.flush();

    expect($scope.users).toEqual(['Rory']);
});

Please check if this helps.

Codepen that works http://codepen.io/anon/pen/ezgjOx

Muthukannan Kanniappan
  • 2,080
  • 1
  • 16
  • 18
0

There are couple of issues which I have observed in the attached code: 1. You instantiate $controller for every test which is not correct. Controller should be instantiate at the top level and we should be using that controller instance wherever is needed. So that we can reduce the code duplicacy and improve the test execution time.

  1. You have added $scope.searchString = ""; line before execution of $scope.textChanged(); which does not look good from coding perspective. In textChanged() itself, we should check whether $scope.searchString is blank or undefined and make Rest URL based on that.

  2. In the second test we will have to put the below lines in the start: httpBackend.when('GET', '/findusers?q=') .respond(['Sean','Yaw','Lucy','Eric','Rory','Heyley']); else it will complain the issue with /findusers?q= url

I have modified the above code a bit and made it working now:

<html>
<head>
    <!-- Jasmine References -->
    <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine.min.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/jasmine-html.min.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.3/boot.min.js"></script>
    <!-- Angular and Angular Mock references -->
    <script type="text/javascript" src="https://code.angularjs.org/1.4.0-rc.2/angular.min.js"></script>
    <script type="text/javascript" src="https://code.angularjs.org/1.4.0-rc.2/angular-mocks.js"></script>
</head>
<body></body>
<script type="text/javascript">

    var app = angular.module('peoplesearchApp',[]);

    app.controller('peopleSearchCtrl',function($scope,$http){
        $scope.textChanged = function() {
            // obtain the list of user whose name have the given prefix
            var searchUsers = ($scope.searchString) ? $scope.searchString.trim(): "";

            $http.get('/findusers?q=' + searchUsers).success(function(data, status) {
                $scope.users = data;
            }).error(function(data, status) {
                console.log("Error: could not retrieve users");
            });

        };
        // make an initial call to retrieve all users
        $scope.textChanged();
    });

    describe('search people app tests', function () {

        var controller, httpBackend, scope;

        // setup before each test run
        beforeEach(module('peoplesearchApp'));
        beforeEach(inject(function (_$controller_, _$httpBackend_, _$rootScope_) {
            scope = _$rootScope_.$new();
            httpBackend = _$httpBackend_;

            controller = _$controller_('peopleSearchCtrl', {$scope: scope});
        }));

        describe('only the users that have their names starting from the search query should be visible', function () {

            it('should show all users for a blank query', function () { 
                httpBackend.when('GET', '/findusers?q=').respond(['Sean','Yaw','Lucy','Eric','Rory','Heyley']);

                scope.textChanged();
                httpBackend.flush();
                expect(scope.users).toEqual(['Sean','Yaw','Lucy','Eric','Rory','Heyley']);
            });

            it('should show only Rory for query=r', function () {
                httpBackend.when('GET', '/findusers?q=')
                        .respond(['Sean','Yaw','Lucy','Eric','Rory','Heyley']);

                scope.searchString = 'r'; 

                httpBackend.when('GET', '/findusers?q=r')
                        .respond(['Rory']);
                scope.textChanged();
                httpBackend.flush();
                expect(scope.users).toEqual(['Rory']);
            });
        });

    })

</script>
</html>

I hope it will resolve your issues.

Cheers!

Suneet Bansal
  • 2,664
  • 1
  • 14
  • 18