Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

lazarDevelopment commented Mar 16, 2016

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

This comment has been minimized.

Copy link
Member

petebacondarwin commented Mar 16, 2016

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

This comment has been minimized.

Copy link
Author

lazarDevelopment commented Mar 16, 2016

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

This comment has been minimized.

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

This comment has been minimized.

Copy link
Author

lazarDevelopment commented Mar 16, 2016

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

@scottmacdowell

This comment has been minimized.

Copy link

scottmacdowell commented Mar 16, 2016

+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

This comment has been minimized.

Copy link

faceleg commented Mar 17, 2016

@nikrolls

This comment has been minimized.

Copy link

nikrolls commented Mar 18, 2016

@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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

Copy link
Member

petebacondarwin commented Mar 19, 2016

@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

This comment has been minimized.

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

This comment has been minimized.

Copy link

dagda1 commented Mar 20, 2016

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

  beforeEach(inject(function($rootScope) {

  }));
@gkalpak

This comment has been minimized.

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

This comment has been minimized.

Copy link

KeithPepin commented Mar 21, 2016

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

Copy link

KeithPepin commented Mar 22, 2016

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

This comment has been minimized.

Copy link
Member

petebacondarwin commented Mar 22, 2016

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

@prestonvanloon

This comment has been minimized.

Copy link

prestonvanloon commented Apr 7, 2016

@gkalpak thank you!

petebacondarwin added a commit that referenced this issue Apr 8, 2016

@varun85jobs

This comment has been minimized.

Copy link

varun85jobs commented Apr 19, 2016

@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

This comment has been minimized.

Copy link

prestonvanloon commented Apr 19, 2016

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

@hristo-vrigazov

This comment has been minimized.

Copy link

hristo-vrigazov commented May 7, 2016

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

This comment has been minimized.

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

This comment has been minimized.

Copy link

hristo-vrigazov commented May 9, 2016

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

@petebacondarwin

This comment has been minimized.

Copy link
Member

petebacondarwin commented May 10, 2016

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

This comment has been minimized.

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

This comment has been minimized.

Copy link
Member

petebacondarwin commented May 16, 2016

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

@kristoff2016

This comment has been minimized.

Copy link

kristoff2016 commented Jun 3, 2016

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

@gkalpak

This comment has been minimized.

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 Jun 3, 2016

@gkalpak gkalpak reopened this Jun 3, 2016

@oliamb

This comment has been minimized.

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

This comment has been minimized.

Copy link

mcranston18 commented Jun 22, 2016

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

@vitorarins

This comment has been minimized.

Copy link

vitorarins commented Jul 15, 2016

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

@gkalpak

This comment has been minimized.

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 Jul 15, 2016

@vitorarins

This comment has been minimized.

Copy link

vitorarins commented Jul 16, 2016

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

This comment has been minimized.

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

This comment has been minimized.

Copy link

vitorarins commented Jul 18, 2016

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

This comment has been minimized.

Copy link

lathaMaramganti commented Jul 19, 2016

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

This comment has been minimized.

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 join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.