TypeError: undefined is not a constructor

Adam Plocher picture Adam Plocher · Aug 13, 2016 · Viewed 55.1k times · Source

I'm very new to Angular and I'm trying to figure much of this out still. I'm writing some tests using Angular 1.5.8 which I generated from the Yeoman Generator.

Specifically, I'm trying to figure out how to manipulate $httpBackend results (I'm not sure if that's important or not)...

In my app.js file I have the following code:

.run(['$rootScope', '$location', 'breadcrumbService', function ($rootScope, $location, breadcrumbService) {
    $rootScope.$on('$viewContentLoaded', function () {
        jQuery('html, body').animate({scrollTop: 0}, 200);
    });

    $rootScope.isEditMode = false;
    $rootScope.$on('$stateChangeSuccess', function () {
        // ------------ this next line is failing -----------
        $rootScope.isEditMode = $location.path().toLowerCase().endsWith('/edit') || $location.path().toLowerCase().endsWith('/new');
    });

    $rootScope.parseJson = function (value) {
        return angular.fromJson(value);
    };

    $rootScope.bc = breadcrumbService;

    $rootScope.title = "";
}])

The line about halfway down (where I added the comment) is failing. Specifically, the endsWith function is failing (toLower is fine), with this error:

PhantomJS 2.1.1 (Windows 8 0.0.0) Service: breadcrumbService should return breadcrumb label in json format FAILED
        TypeError: undefined is not a constructor (evaluating '$location.path().toLowerCase().endsWith('/edit')') in app/scripts/app.js (line 44)
        app/scripts/app.js:44:72
        $broadcast@bower_components/angular/angular.js:18005:33
        bower_components/angular-ui-router/release/angular-ui-router.js:3353:32
        processQueue@bower_components/angular/angular.js:16383:30
        bower_components/angular/angular.js:16399:39
        $eval@bower_components/angular/angular.js:17682:28
        $digest@bower_components/angular/angular.js:17495:36
        $apply@bower_components/angular/angular.js:17790:31
        done@bower_components/angular/angular.js:11831:53
        handleResponse@bower_components/angular-mocks/angular-mocks.js:1368:17
        flush@bower_components/angular-mocks/angular-mocks.js:1808:26
        test/spec/services/breadcrumbservice.js:33:27
        invoke@bower_components/angular/angular.js:4718:24
        workFn@bower_components/angular-mocks/angular-mocks.js:3085:26

Here is my test code (some junk modified from different examples - just trying to get it to work):

'use strict';

describe('Service: breadcrumbService', function () {

    // load the service's module
    beforeEach(module('myModule'));

    var $httpBackend, $rootScope, createController, authRequestHandler;
    beforeEach(inject(function($injector) {

        $httpBackend = $injector.get('$httpBackend');
        console.log('Is null? '+ ($httpBackend == null));
        $httpBackend.whenGET(/views\/.*/).respond(200, [{}, {}, {}]);

        authRequestHandler = $httpBackend.when('GET', '/api/v1/SiteStagings')
            .respond({userId: 'userX'}, {'A-Token': 'xxx'});

        // Get hold of a scope (i.e. the root scope)
        $rootScope = $injector.get('$rootScope');
        $httpBackend.flush();
    }));

    // instantiate service
    var breadcrumbService;
    beforeEach(inject(function (_breadcrumbService_) {
        breadcrumbService = _breadcrumbService_;
    }));

    it('svc should exist', function () {
        expect(!!breadcrumbService).toBe(true);
    });

    it('should return breadcrumb label in json format', function () {
        var result = breadcrumbService.getFromCache('site', 'SiteGroupStagings', 46, 'SiteGroupDesc');
        console.log(result);
        expect(!!result).toBe(true);

    });
});

I don't doubt that I'm doing something wrong here, I just can't quite understand what it is. What does this error really mean and why does it not like my call to endsWith?

Thanks

Answer

dgraf picture dgraf · Nov 21, 2016

undefined is not a constructor

is an error message PhantomJS displays when you tried to call a function that is not defined. It depends on the version of ECMAScript which your PhantomJS supports. So as you said it works fine in Chrome, because this browser supports the function you are using in test. In order to fix your problem and still be able to use PhantomJS you can replace the "unknown to PhantomJS" function with your own.