Angular.js: angular-mock 1.5.1 TypeError:未定义不是构造函数(评估“ angular.element.cleanData(cleanUpNodes)”)

创建于 2016-03-16  ·  67评论  ·  资料来源: angular/angular.js

我的测试在angular-mock 1.5.0上工作正常,但在1.5.1下,所有测试失败,原因是:
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

investigation more info regression bug

最有用的评论

在尝试升级到v1.5.2之后,我在测试中也看到了这个问题。 将angular-mocks.js的第2776行更改为:
angular.element.cleanData(cleanUpNodes);
至:
if (angular.element.cleanData) angular.element.cleanData(cleanUpNodes);

解决此问题。 在我们的例子中,出于各种原因,我们试图监视angular.element。

所有67条评论

这很奇怪,因为在那段代码中没有调用构造函数。 也许您可以提供更多信息? 测试失败的副本,最好是我们可以运行的测试。

在这里,您可以找到一个测试,它什么也没做,但是我们进行的每个测试都会失败(仅适用于1.5.1版,可以使用1.5.0)。
Test Runner Karma,测试框架Jasmine。 项目设置“应用程序基础”
https://github.com/HamburgOOU/hoou-webapp/blob/master/test/controllerTest/AboutControllerTest.js

看来您正在使用ui-router,对吗?
您能否尝试创建在此处运行的测试: http ://plnkr.co/edit/tpl:vojSWqpk1yBjQbbPeXRH?

作为建议,您还应该尝试从测试中删除依赖项,并查看究竟是什么引发了错误(应用程序模块中有很多依赖项)

是的,使用angular-ui-router(0.2.18)。
Trommorow我将尝试查找导致它的依赖项。

+1,我在尝试测试提供程序时收到一个非常类似的错误。

TypeError:“未定义”不是函数(评估“ angular.element.cleanData(cleanUpNodes)”)
在../node_modules/angular-mocks/angular-mocks.js:2776
在../node_modules/angular-mocks/angular-mocks.js:2746

编辑:1.5.1版发生此错误,我切换回1.5.0,一切正常。

在这里看到这个: https :

@petebacondarwin undefined is not a constructor是PhantomJS在尝试调用未定义函数时产生的隐式错误。 等同于Chrome的a.something is not a function错误。

我们在Angular / Mock 1.5.1上遇到了类似的错误,这在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)

请注意,我们将jQuery与Angular一起使用。

这可能与https://github.com/angular/angular.js/commit/75373dd4bdae6c6035272942c69444c386f824cd相关

@nikrolls

angular.element(...)。data不是函数

我是否正确理解angular.element(...) (如果在Angular之前加载jQuery,别名为jQuery(...) )会返回没有data方法的东西? 好像很奇怪您可以在Chrome DevTools中启用“拒绝拒收”功能,然后在碰到此行时,检查究竟是什么返回以下表达式:

  1. angular.element
  2. angular.element(...) (用您实际拥有的内容代替圆点)
  3. ... (用angular.element的点代替圆点)

谢谢!

自从角度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

在这种情况下,当测试包含inject()函数时,总是会引发错误。 我猜spyOn($location, 'path');beforeEach功能可能是问题。

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
            });
        });
    });
});

@ 4kochi-您的问题实际上是您监视了一个函数,但未提供该间谍程序的实现。 换句话说,调用spyOn($location, path);会使用间谍函数覆盖$location.path方法,但该间谍函数会返回undefined 。 稍后,路由器尝试访问$location.path().search ,实际上是说undefined.search

您需要为间谍提供一个实现:伪造或传递:

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

感谢@petebacondarwin的提示,我有一个类似的想法。 但是我想知道为什么Angular 1.5.0可以使用完全相同的测试代码? 我错过了什么?

我在使用inject时遇到同样的问题,例如

  beforeEach(inject(function($rootScope) {

  }));

@ dagda1 ,您能否提供https://github.com/angular/angular.js/issues/14251#issuecomment -198276079中提到的信息(以及错误的确切堆栈跟踪信息)?

在尝试升级到v1.5.2之后,我在测试中也看到了这个问题。 将angular-mocks.js的第2776行更改为:
angular.element.cleanData(cleanUpNodes);
至:
if (angular.element.cleanData) angular.element.cleanData(cleanUpNodes);

解决此问题。 在我们的例子中,出于各种原因,我们试图监视angular.element。

在我们的例子中,出于各种原因,我们试图监视angular.element。

那解释了错误。

angular.element是一个非常基本的“功能”,在很大程度上依赖于内部。 我不建议将其存根。 (监视它并让事情通过应该是可以的)。

顺便说一句,将代码更改为if (angular.element.cleanData) angular.element.cleanData(cleanUpNodes);会导致内存泄漏,这可能导致因果报应在庞大的测试套件上崩溃。
(是的,它已经发生了:笑脸:)

谢谢@gkalpak-不幸的是,任何形式的间谍(甚至只打来的间谍)似乎都会引起相同的问题。 作品中还有其他工作或其他建议可尝试吗?

@KeithPepin angular.element是一个棘手的野兽。 您真的需要监视吗? 您可以举一个测试示例吗?

我有同样的问题。
得到一些错误味精:

PhantomJS 2.1.1 (Linux 0.0.0) 首页单元测试 首页内容控制器测试 调用获取数据接口 encountered a declaration exception FAILED
    ReferenceError: Can't find variable: module in /client/modules/bootstrap/test/bootstrap.spec.js (line 4)
    /client/modules/bootstrap/test/bootstrap.spec.js:4:23
    global code@/client/modules/bootstrap/test/bootstrap.spec.js:3:9
PhantomJS 2.1.1 (Linux 0.0.0): Executed 1 of 1 (1 FAILED) ERROR (0.041 secs / 0.001 secs)

我的测试如下:

describe( '首页模块单元测试', function(){

    var $httpBackend,
        $indexFactory;

    beforeEach( module( 'Datatao.bootstrap' ) ); 

    beforeEach( inject( function( _$httpBackend_,  _IndexFactory_ ){ 
        $httpBackend    = _$httpBackend_;
        $indexFactory   = _IndexFactory_;
    }) ); 

    describe( '首页内容控制器测试', function(){
        it( '调用获取数据接口', function(){
            expect( true ).toBe( true ); 
        });
    });

});

我使用角度1.4.8和ui路由器0.2.15角度模拟1.5.2,但是将角度模拟降级到1.5.0之后,一切都很好。
如果您需要更多信息,请@me

@terminatorheart我们不支持使用不匹配的angular和angular-mock版本。 您是否尝试过同时使用1.5.2?

我试图在这里重新创建此问题https://github.com/petebacondarwin/issue-14251
但是karma start对我来说很好。 您能否建议项目中要失败的其他内容?

从1.5.0移至1.5.1时,我也遇到类似的错误。

我们有以下代码在应用程序启动前做一些额外的工作。 现在,它失败并出现以下错误。

var injMods = ['ng','tcpInitModule','mpyInitModule'];
var initInjector = angular.injector(injMods);

var tcpMembershipSvc = initInjector.get('tcpMembershipSvc');
//使用tcpMembershipSvc提供程序进行一些工作

//最后启动
angular.bootstrap(document,['tcpMainModule']);

错误:
未捕获的错误:[$ jector:unpr ]未知提供程序:$ rootElementProvider <-$ rootElement <-$ location <-$ route <-$ location
http://errors.angularjs.org/1.5.1/ $ injector / unpr?p0 =%24rootElementProvider%…%24rootElement%20%3C-%20%24location%20%3C-%20%24route%20%3C- %20%24位置

在单元测试中,它失败并显示以下错误。
错误:[$$ jecter:modulerr ]由于以下原因,无法实例化模块ng:
TypeError:“未定义”不是对象(正在评估“ Function.prototype.bind.apply”)
在实例化时(c:/app/internal_packages/angular/angular.js:4640)

@mlakmal您可以为您的问题创建可运行的演示,以供我们测试吗?

@petebacondarwin我已经在下面添加了plnker。

https://plnkr.co/edit/J32cQo4Fo9fkiRH3pF3L?p=preview

我还注意到v1.5.0上也出现了单元测试错误...

@mlakmal我认为

单元测试问题似乎是由于未定义Function.prototype.bind 。 您正在使用PhantomJS 1.x吗?

您的其他问题确实与ngRoute更改(5e37b2a)有关(实际上)是在暴露已经存在的问题。

最小复制为: angular.injector(['ng', 'ngRoute'])
另一个最小复制量(不涉及ngRoute )将是: angular.injector(['ng']).get('$location');

问题是$location服务取决于$rootElement 。 在启动应用程序之前,Angular不会提供$rootElement (因为在此之前未知)。 尝试在引导应用程序的上下文之外实例化$location ,将使注入程序尝试获取$rootElement并失败,因为此时没有$rootElement提供程序。 。

TBH,我想不出从自定义注入器加载ngRoute的理由( @mlakmal我很想知道有关您的用例的更多细节,即使只有OOC:smiley :)。

一个简单的解决方法是包括一个提供$rootElement的虚拟额外模块:

angular.module('fakeRootElement', []).value('$rootElement', angular.element('<div></div>'));
var initInjector = angular.injector(['ng', 'InitModule', 'fakeRootElement']);

更新了plnkr

现在,在实际问题上, $location使用$rootElement拦截所有click事件并以HTML5模式处理它们。 我们可以将其设为“可选”依赖项(例如,仅在定义了$rootElement注入它,或者提供一个虚拟的$rootElement并在引导过程中替换它)。
问题是我们应该吗?

@gkalpak ,您是正确的,我们正在使用Phantom JS 1.9.8并尝试移至v2,但由于构建代理程序要求更改节点版本,因此在我们这方面的延迟(我们仍在v0.12.x上) 。 我在本地将PhantomJS升级到v2,并且单元测试看起来不错。 任何想法如何解决PhantomJS 1问题?

您的解决方法很好地解决了注射器上的问题。 我可以继续使用该修复程序,直到将来我们迁移到AngularJS 2(做梦了……)。

关于ngRoute的用例:我们有一些服务在这些CommonModule和InitModule上使用ngRoute的提供程序。 因此,在创建以支持单元测试执行时,我们必须为这些模块添加ngRoute作为模块依赖项。 我认为我们可以将其从那些依赖项中删除,仅在单元测试需要时才添加ngRoute。

在为karma conf添加以下polyfill之后,PhantomJS 1单元测试问题已解决。 不知道为什么在角度1.5.x升级后突然出现此错误...

https://www.npmjs.com/package/phantomjs-polyfill

@mlakmal是PhantomJS之前未出现此问题的原因,是Angular没有使用Function.prototype.bind 。 我们现在做,因为支持本机类是必需的,并且所有受支持的浏览器都提供了它。 (请注意,未明确支持PhantomJS,这意味着我们不对其进行测试,但是很多人使用它(包括ngMaterial项目直到不久前)都不会出现问题。)

关于依赖ngRoute中的InitModule
ngRoute仅提供一个提供程序( $routeProvider ),仅对注册路由有用。 我仍然不明白为什么需要创建包括它的自己的注入器(考虑到每个注入器将创建服务的不同实例-每个注入器的服务都是单例)。
如果您只是在加载InitModule ,以便可以保留一些帮助程序服务,那么将这些帮助程序服务提取到独立模块( InitModule取决于)中可能是一个更好的主意。只能将该辅助模块加载到额外的进样器中。

@gkalpak我们在指令中使用了ngRoute的$ routeParams。 因此,这就是为什么我们将其添加到某些模块中的原因...但是我想我们可以将ngRoute模块分别添加到我们的spec文件中。

@mlakmal ,我的意思是我看不到在您手动创建的额外注射器(使用angular.injector([...]) )中需要ngRoute的必要性,因为那将是一个单独的注射器(具有单独的服务)实例)。

大家好,抱歉,几天后再次提出,但是我刚刚遇到了这个问题。

我正在通过所有电话监视angular.element ,但是不幸的是,它仍然无法正常工作。

spyOn( angular, 'element' ).andCallThrough();

有什么想法吗?

@mattgrande我在想如果没有演示,我们将

对于Jasmine 2.x btw来说,这不是问题,因为它将spied函数的所有属性复制到间谍中(请参见demo )。

Jasmine 1.x仍然存在问题,Jasmine 1.x不会复制属性(请参见demo )。
您可以通过自己复制属性(全部或仅必要的属性,例如cleanData )来解决此问题:

spyOn(angular, 'element').andCallThrough();

// Copy all properties
angular.extend(angular.element, angular.element.originalValue);
// or
// Copy `cleanData` only
angular.element.cleanData = angular.element.originalValue.cleanData;

TBH,我倾向于将其关闭为works as expected / won't fixangular.element()太基础了,如果有人监视它,他们最好为BC做准备(或使用Jasmine 2:stuck_out_tongue :)

ngMock内部解决此问题也很容易,例如,将angular.element.cleanData(...)更改

var ngEl = angular.element;
(ngEl.cleanData || (ngEl.originalValue && ngEl.originalValue.cleanData) || angular.noop)(...)

但是明天可能会有另一个测试库崩溃。

因此,由于:

(a)这只是Jasmine 1.x(不是2.x)的问题,
(b)它只会破坏测试,而不会破坏应用程序代码,并且
(c)修复起来很容易,

我(仍然)倾向于不“解决”这个问题。

@gkalpak我倾向于同意你的看法。 这是“已知问题页面”的另一种情况,不是吗?

使用@KeithPepin解决方案,

如果(angular.element.cleanData)
angular.element.cleanData(cleanUpNodes);

为我工作

谢谢你们我将尝试更新到Jasmine 2.x(没有太多更改),但是如果事实证明这太麻烦了,我将使用Keith的解决方案。

更新:原来我已经在使用Jasmine 2.1,但是我已更新到最新版本,并且没有任何影响。

我最终使用了@gkalpak的“ extend”方法。 谢谢!

@mattgrande ,您将茉莉花升级到了哪个版本? 奇怪的是它没有用,因为它在我使用茉莉v2.4.1的演示中似乎可以正常工作:

角球1.5.2和1.5.3的相同错误
(茉莉花2.4.1)

茉莉花2.4.0; Angular版本1.5.2

嗨,我还有PhantomJS2,业力和茉莉花的未定义问题。 我正在使用最新版本的业力和茉莉花。 我的应用程序还使用ngRoute。

当我尝试注入$ rootScope和$ controller时,出现了我的问题。 我正在使用ngMock模拟我的模块之一。 作用域和控制器始终未定义。 但是,当我仅使用angular.module测试模块时,测试就会通过。 我没有使用spyOn。

关于可能是什么错误的任何建议?

从1.4.6升级到1.5.3时,我也遇到这个问题。

你们中的一个可以提供有关该问题的可运行演示吗?

@petebacondarwin这是travis失败的构建: https : //travis-ci.org/prestonvanloon/newrelic-angular/builds/118604417

编辑:这是导致它的PR https://github.com/prestonvanloon/newrelic-angular/pull/28

@prestonvanloon ,您的问题是您正在使用不同版本的angular和angular-mocks。
您应该始终使用匹配的版本。

@gkalpak谢谢!

@prestonvanloon :检查您使用的角度和角度模拟的版本。 我面临着同样的问题。 当我使用angular-mocks版本1.5.5和angular版本为1.4.7时,我遇到了相同的异常。 将我的角度版本升级到1.5.5时,没有出现任何错误,并且所有测试都成功运行。

谢谢@ varun85jobs@gkalpak ,这正是我的问题

大家好,我有一个Ionic项目,其角度版本为1.5.3,角度为1.5.3,但是我仍然遇到相同的错误。 会是什么呢?

嗨,这里是同样的问题,我刚刚尝试了1.5.5和1.5.3,但仍然有问题,因为临时解决方案我们使用1.5.0。

KeithPepin的答案已为我解决,但我不希望更改库的代码

我们仍然没有适当的用例来监视angular.element 。 没有这个,我们将无法修复。

有一个关于这个问题,一个问题在这里为好。
我从那里得到的答案,以防它对这里的任何人有所帮助:

我有同样的问题,解决此问题的方法是在测试中加载jquery:

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

从此评论中采纳了这个想法,因为我们还将jQuery与Angular一起使用。

我们仍然需要一个实际运行的复制品,其中所使用的所有角度模块版本都匹配。

我遇到了这个问题:angular.element.parent不是一个函数

@ kristoff2016 ,这似乎不是一个相同的问题。 请打开一个新期刊,提供更多信息,例如相关代码,确切的错误消息,您的环境(浏览器,操作系统等)。 现场复制(使用CodePen,Plnkr等)也受到高度赞赏:

就我而言,问题是我使用的是旧版本的karma-phantomjs-launcher(^ 0.1.4而不是^ 1.0.0),它依赖于较旧的PhantomJS。 使用[email protected] ,它可以正常工作。

+1将karma-phantomjs-launcher和phantomjs升级到2+可以达到目的

到目前为止,对我而言唯一有效的选择是降级为角/角点1.5.0

自从首次报道以来已经有几个月了,这里仍然没有实际的复制品(带有匹配的版本)! 我们无法解决看不见的问题。 :担心:

我将关闭此窗口,但是如果我们得到复制,将很乐意重新打开。

@gkalpak ,您好,感谢您抽出evil:。 我已经保存在这个plnkr中。 因此,以下代码对您而言可能没有多大意义,但是我们针对特定情况解决了此问题:

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

因此,这在测试时适用于1.5.0的angular和mocks,但不适用于1.5.1-1.5.7 。 我不知道这是否是这种情况,或者使用angular.element其他情况是否也会中断。

谢谢@vitorarins。 如前所述,覆盖angular.element这样的证书组件而不至少保留其属性是非常“顽皮的”事情。 使用上述angular.extend()技术,您会很好。

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

更新了plnkr

非常感谢@gkalpak! 我希望至少这可以为其他有此问题的人提供参考。 再次感谢很多!

嗨,我也面临着同样的问题。 但是使用角度选择。 在我的控制器中,我正在像这样初始化select。
angular.element('select')。select2();

增加了如下的监视功能:
var ngElement = angular.element('select');
angular.element = angular.extend(function(id){
尝试 {
返回ngElement.call(angular,id);
} catch(err){
返回$(id);
}
},ngElement);

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

    });

PhantomJS 2.1.1(Mac OS X 0.0.0)错误
TypeError:尝试分配给只读属性。
在/node_modules/angular/angular.min.js:9

我已经完全阅读了这篇文章,并使用了angular 1.5.7和jasmine 2.4.1。 但是问题仍然没有解决。

@lathaMaramganti不是:

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

但:

var ngElement = angular.element;

您需要保存原始函数以扩展它,而不是对其进行调用。

此页面是否有帮助?
0 / 5 - 0 等级