Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

angular-mock 1.5.1 TypeError: undefined is not a constructor (evaluating 'angular.element.cleanData(cleanUpNodes)') #14251

Closed
lazarDevelopment opened this issue Mar 16, 2016 · 67 comments

Comments

@lazarDevelopment
Copy link

My Tests working fine with angular-mock 1.5.0 but with 1.5.1 all Tests fail with:
TypeError: undefined is not a constructor (evaluating 'angular.element.cleanData(cleanUpNodes)') in ../node_modules/angular-mocks/angular-mocks.js (line 2776) $$cleanup@../node_modules/angular-mocks/angular-mocks.js:2776:32 $$afterEach@../node_modules/angular-mocks/angular-mocks.js:2746:23

@petebacondarwin
Copy link
Member

That is strange, since no constructor is being called in that bit of code. Perhaps you can provide some more information? A copy of a failing test, preferably one that we can run.

@lazarDevelopment
Copy link
Author

Here you can find a test, it does nothing but every test we have fails (only for version 1.5.1, 1.5.0 is fine).
Test Runner Karma, Test Framework Jasmine. Project Setup "Foundation for Apps"
https://github.com/HamburgOOU/hoou-webapp/blob/master/test/controllerTest/AboutControllerTest.js

@Narretz
Copy link
Contributor

Narretz commented Mar 16, 2016

It looks like you are using ui-router, is that right?
Can you try to create a test that runs here: http://plnkr.co/edit/tpl:vojSWqpk1yBjQbbPeXRH?

As a suggestion, you should also try to remove dependencies from your test, and see what exactly triggers the error (you have a lot of dependencies in the application module)

@lazarDevelopment
Copy link
Author

Yes, using angular-ui-router(0.2.18).
Trommorow I will try to find the dependency who causes it.

@scottmacdowell
Copy link

+1, I am receiving a very similar error trying to test a provider.

TypeError: 'undefined' is not a function (evaluating 'angular.element.cleanData(cleanUpNodes)')
at ../node_modules/angular-mocks/angular-mocks.js:2776
at ../node_modules/angular-mocks/angular-mocks.js:2746

Edit: This error occurs with ver 1.5.1, I switched back to 1.5.0 and everything works again.

@faceleg
Copy link

faceleg commented Mar 17, 2016

@nicole-ashley
Copy link

@petebacondarwin undefined is not a constructor is the cryptic error PhantomJS gives when you try to call a function that is not defined. It's equivalent to Chrome's a.something is not a function error.

We're getting a similar error on Angular/Mock 1.5.1, which is not an issue on 1.5.0:

# PhantomJS
TypeError: undefined is not a constructor (evaluating 'angular.element('<div ng-app></div>').data('$injector', $injector)') 
    in /bower_components/angular-mocks/angular-mocks.js (line 2102)
    /bower_components/angular-mocks/angular-mocks.js:2102:69
    invoke@/bower_components/angular/angular.js:4443:22
    /bower_components/angular/angular.js:4261:43
    getService@/bower_components/angular/angular.js:4402:46
    invoke@/bower_components/angular/angular.js:4434:23
    /bower_components/angular/angular.js:4261:43
    getService@/bower_components/angular/angular.js:4402:46
    invoke@/bower_components/angular/angular.js:4434:23
    /bower_components/angular/angular.js:4261:43
    getService@/bower_components/angular/angular.js:4402:46
    invoke@/bower_components/angular/angular.js:4434:23
    /bower_components/angular/angular.js:4265:85
    forEach@/bower_components/angular/angular.js:336:24
    createInjector@/bower_components/angular/angular.js:4265:10
    workFn@/bower_components/angular-mocks/angular-mocks.js:2922:60

# Chrome
TypeError: angular.element(...).data is not a function
        at $get (/bower_components/angular-mocks/angular-mocks.js:2102:65)
        at Object.invoke (/bower_components/angular/angular.js:4443:17)
        at /bower_components/angular/angular.js:4261:37
        at getService (/bower_components/angular/angular.js:4402:39)
        at Object.invoke (/bower_components/angular/angular.js:4434:13)
        at /bower_components/angular/angular.js:4261:37
        at getService (/bower_components/angular/angular.js:4402:39)
        at Object.invoke (/bower_components/angular/angular.js:4434:13)
        at /bower_components/angular/angular.js:4261:37
        at getService (/bower_components/angular/angular.js:4402:39)

Note that we use jQuery alongside Angular.

Could this be at all related to 75373dd?

@mgol
Copy link
Member

mgol commented Mar 18, 2016

@nikrolls

angular.element(...).data is not a function

Do I understand it right that angular.element(...) (which is aliased to jQuery(...) if you load jQuery before Angular) returns something that doesn't have the data method? That seems weird. Could you enable "break on rejections" in Chrome DevTools and then, when you hit this line, check what exactly return the following expressions:

  1. angular.element
  2. angular.element(...) (substitute the dots with what you really have there)
  3. ... (substitute the dots with what you had in angular.element)

Thanks!

@4kochi
Copy link
Contributor

4kochi commented Mar 18, 2016

We have a similar problem since angular v1.5.1.

should update data with success with redirect
          PhantomJS 2.1.1 (Linux 0.0.0)
        TypeError: undefined is not an object (evaluating '$location.path(interpolate(nextRoute.redirectTo, nextRoute.params)).search') in /project/app/bower_components/angular-route/angular-route.js (line 601)
        commitRoute@/project/app/bower_components/angular-route/angular-route.js:601:82
        $broadcast@/project/app/bower_components/angular/angular.js:17207:33
        afterLocationChange@/project/app/bower_components/angular/angular.js:13127:28
        /project/app/bower_components/angular/angular.js:13113:32
        $eval@/project/app/bower_components/angular/angular.js:16884:28
        $digest@/project/app/bower_components/angular/angular.js:16700:36
        flush@/project/app/bower_components/angular-mocks/angular-mocks.js:1779:45
        /project/app/modules/main/partners/partners.spec.js:338:31
        invoke@/project/app/bower_components/angular/angular.js:4625:24
        workFn@/project/app/bower_components/angular-mocks/angular-mocks.js:2933:26
        Error: [$rootScope:inprog] $digest already in progress
        http://errors.angularjs.org/1.5.1/$rootScope/inprog?p0=%24digest (line 17242)
        beginPhase@/project/app/bower_components/angular/angular.js:17242:88
        $digest@/project/app/bower_components/angular/angular.js:16680:19
        flush@/project/app/bower_components/angular-mocks/angular-mocks.js:1779:45
        /project/app/modules/main/partners/partners.spec.js:385:39
        invoke@/project/app/bower_components/angular/angular.js:4625:24
        workFn@/project/app/bower_components/angular-mocks/angular-mocks.js:2933:26
        inject@/project/app/bower_components/angular-mocks/angular-mocks.js:2902:46
        /project/app/modules/main/partners/partners.spec.js:381:23
        undefined

In this case the error is always thrown when the tests includes the inject() function. I guess the spyOn($location, 'path'); in the beforeEach function could be the problem.

describe('ctrl test', function () {
    beforeEach(inject(function ($controller, $location) {
        spyOn($location, 'path');
    }));

    describe('save()', function () {
        it('should work', function(){
            inject(function ($location) {
                // some test code
            });
        });
    });
});

@matsko matsko modified the milestones: 1.5.2, 1.5.3 Mar 18, 2016
@petebacondarwin
Copy link
Member

@4kochi - you problem is actually that you have spied on a function but not provided an implementation for the spy. In other words, calling spyOn($location, path); overrides the $location.path method with a spy function but that spy function returns undefined. Later the router is trying to access $location.path().search, which is effectively saying undefined.search.

You need to provide an implementation for the spy: either a fake or a pass-through:

spyOn($location, 'path').andCallThrough();
spyOn($location, 'path').andCallFake(function(url) { return {...}; });

@4kochi
Copy link
Contributor

4kochi commented Mar 19, 2016

Thanks for the tip @petebacondarwin I had an similar idea. But I wonder then why the exact same test code works with Angular 1.5.0? Did I miss something?

@dagda1
Copy link

dagda1 commented Mar 20, 2016

I have the same issue when I use inject,e.g.

  beforeEach(inject(function($rootScope) {

  }));

@gkalpak
Copy link
Member

gkalpak commented Mar 20, 2016

@dagda1, could you provide the info mentioned in #14251 (comment) (as well as the exact stack trace for the error) ?

@KeithPepin
Copy link

I was seeing this problem as well with our tests after trying to upgrade to v1.5.2. Changing line 2776 of angular-mocks.js from:
angular.element.cleanData(cleanUpNodes);
To:
if (angular.element.cleanData) angular.element.cleanData(cleanUpNodes);

Fix the issue. In our case, we're trying to spy on angular.element for various reasons.

@gkalpak
Copy link
Member

gkalpak commented Mar 21, 2016

In our case, we're trying to spy on angular.element for various reasons.

That explains the error.

angular.element is a pretty basic "feature" and relied upon heavily internally. I wouldn't recommend stubbing it out. (Spying on it and letting things pass through should be OK though).

@gkalpak
Copy link
Member

gkalpak commented Mar 21, 2016

BTW, changing the code to if (angular.element.cleanData) angular.element.cleanData(cleanUpNodes); leads to memory leaks that can cause karma to crash on huge testsuites.
(Yes, it has happened already 😃)

@KeithPepin
Copy link

Thanks @gkalpak - unfortunately any sort of spy (even one that only calls through) seems to cause the same issue. Is there any other work around in the works or other suggestions to try?

@petebacondarwin
Copy link
Member

@KeithPepin angular.element is a tricky beast. Do you really need to spy on it? Can you give an example of your tests?

@prestonvanloon
Copy link

@gkalpak thank you!

petebacondarwin added a commit that referenced this issue Apr 8, 2016
@varun85jobs
Copy link

@prestonvanloon : Check the version of angular and angular-mocks you are using. I was facing the same issue. When I was using angular-mocks version 1.5.5 and angular version was 1.4.7, I got the same exception. When I upgraded my angular version to 1.5.5, I did not get any errors and all the tests ran successfully.

@prestonvanloon
Copy link

Thanks @varun85jobs and @gkalpak, that was exactly my issue

@hristo-vrigazov
Copy link

Hey guys, I have an Ionic project with angular version 1.5.3 and angular-mocks 1.5.3, but I still get the same error. What could it be?

@gil13
Copy link

gil13 commented May 9, 2016

Hi, same problem here, I have just tried with 1.5.5 and 1.5.3 and still with problems, as temporal solution we use 1.5.0.

@hristo-vrigazov
Copy link

KeithPepin's answer fixed it for me, but I prefer not to change a library's code

@petebacondarwin
Copy link
Member

We still don't have a proper use case for spying on angular.element. Without this we can't move forward with a fix.

@yishaic
Copy link

yishaic commented May 15, 2016

There is a question about this issue here as well.
My answer from there, in case it will help anyone here:

I had the same problem and what fixed it to me was to load jquery in my tests:

files: [
      'bower_components/jquery/dist/jquery.js',
      'bower_components/angular/angular.js',
      'bower_components/angular-mocks/angular-mocks.js',
...
]

took the idea from this comment because we also use jQuery alongside Angular.

@petebacondarwin
Copy link
Member

We still need an actual running reproduction, where all the versions of angular modules used match.

@kristoff2016
Copy link

I got this issue: angular.element.parent is not a function

@gkalpak
Copy link
Member

gkalpak commented Jun 3, 2016

@kristoff2016, this doesn't seem like the same problem. Please open a new issue, providing more info, e.g. the relevant code, the exact error message, your environament (browser, OS etc). Live reproductions (using CodePen, Plnkr etc) are highly appreciated as well 😁

@gkalpak gkalpak closed this as completed Jun 3, 2016
@gkalpak gkalpak reopened this Jun 3, 2016
@oliamb
Copy link

oliamb commented Jun 6, 2016

In my case, the issue was that I was using an old version of karma-phantomjs-launcher (^0.1.4 instead of ^1.0.0) which relied on an older version of PhantomJS. With phantomjs-prebuilt@2.1.7, it is working properly.

@mcranston18
Copy link

+1 upgrading karma-phantomjs-launcher and phantomjs to 2+ did the trick

@vitorarins
Copy link

The only option that worked for me until now was downgrading to angular/angular-mocks 1.5.0

@gkalpak
Copy link
Member

gkalpak commented Jul 15, 2016

It's been months since this was first reported and there is still no actual reproduction (with matching versions) posted here!! We can't fix what we can't see. 😟

I am going to close this, but would be happy to re-open if we get a reproduction.

@gkalpak gkalpak closed this as completed Jul 15, 2016
@vitorarins
Copy link

Hi @gkalpak, thanks for taking the time. I was able to reproduce the problem, but apparently we were doing something really naughty in our code 🙈. I have saved in this plnkr. So the following code may not make much sense for you, but we did that as a work around for a very specific situation:

var elSelect = angular.element;
angular.element = function(id) {
        try {
            return elSelect.call(angular, id);
        } catch(err) {
            return $(id);
        }
    };

So this works for version 1.5.0 of angular and angular-mocks when testing, but not for 1.5.1-1.5.7. I don't know if it is this specific case or if other cases using angular.element could also break.

@gkalpak
Copy link
Member

gkalpak commented Jul 16, 2016

Thx @vitorarins. As mentioned before, it is a very "naughty" thing to overwrite such a certal component as angular.element and not at least preserve it's properties. Using the angular.extend() technique described above, you would be good though.

var ngElement = angular.element;
angular.element = angular.extend(function(id) {
  try {
    return ngElement.call(angular, id);
  } catch(err) {
    return $(id);
  }
}, ngElement);

Updated plnkr

@vitorarins
Copy link

Thank you very much @gkalpak! I hope that at least this serves as reference for other people having this problem. Again Thx a lot!

@lathaMaramganti
Copy link

Hi, I am also facing the same issue. But using angular select. In my controller I am initialising select like this.
angular.element('select').select2();

Added spy on as follows :
var ngElement = angular.element('select');
angular.element = angular.extend(function(id) {
try {
return ngElement.call(angular, id);
} catch(err) {
return $(id);
}
}, ngElement);

spyOn(ngElement, 'select2').and.callFake(function() {

    });

PhantomJS 2.1.1 (Mac OS X 0.0.0) ERROR
TypeError: Attempted to assign to readonly property.
at /node_modules/angular/angular.min.js:9

I had gone through this post fully and used angular 1.5.7 and jasmine 2.4.1. But still issue is not solved.

@mgol
Copy link
Member

mgol commented Jul 19, 2016

@lathaMaramganti It's not:

var ngElement = angular.element('select');

but:

var ngElement = angular.element;

You need to save the original function to extend it, not its invocation.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests