如何在我的Karma/Jasmine测试中调试"[object ErrorEvent] thrown"错误?

117
我有几个测试失败,只输出[object ErrorEvent] thrown。 我看不到控制台上任何有助于找到错误代码的信息。 是否需要进行某些操作才能跟踪这些错误呢?
[编辑]: 我正在运行Karma v1.70,Jasmine v2.7.0。

你能包含更多的错误信息吗?比如在错误前后多加几行代码? - Kevin
5
“[object ErrorEvent] thrown” 的意思是发生了一个“[object ErrorEvent]”错误事件。前后没有其他内容。 - Darrell Brogdon
1
真是走运,我在你发这个问题的同时也遇到了同样的问题,结果发现是一个“流氓”脚本标签(也可能是CSS链接)需要被移除(我的问题与CORS有关),或者在CSS的情况下,我只需添加crossorigin="anonymous"。检查你的代码是否存在这样的脚本/CSS标签,在我的情况下,我发现问题是由完全不同的组件引起的! - TheDude
{btsdaf} - angularrocks.com
1
@TheDude 你是如何缩小这个脚本的范围的?是逐行检查吗?还是有一些调试过程帮助你缩小了错误位置?我遇到了同样的问题,唯一可以依据的信息是:在 afterAll 中抛出了一个错误。如果我通过将 it() 改为 fit() 来隔离测试本身,即使只运行单个测试,错误仍然会被抛出。对于这种类型的错误,有什么调试建议吗? - Knight
你尝试过在单元测试中导入HttpClientTestingModule吗?这是我案例中有效的方法。 - Derek K
17个回答

126

提示:在运行测试时,只需打开 DevTools控制台,就可以找到抛出的确切错误。

作为快速修复,您可以尝试在不使用源映射的情况下运行测试

CLI v6.0.8及以上版本
--source-map=false

CLI v6.0.x早期版本
--sourceMap=false

CLI v1.x
--sourcemaps=false

缩写 ng test -sm=false 也可能起作用

关于这个问题,这里有一个开放的问题:https://github.com/angular/angular-cli/issues/7296

更新: 我也遇到了这个问题,所以我刚刚迁移到了最新的cli,并确保package.json中的所有软件包都已更新,同时我还完全重新安装了node_modules,因此现在该问题已经消失了。


3
这对我很有效。它帮助我发现问题出在未定义的输入绑定上。 - JP Lew
从Angular 6开始,--sourcemaps选项已经不存在。 - mwilson
10
对于angular-cli 6,--sourceMap=false似乎是有效的。 - skermajo
1
典型的前端解决方案 - Mcsky
2
这个解决方案不再起作用了。它曾经可以,但在6.2.4中不行了。 - Mike
7
有时候我会在随机组件中出现未捕获的 [object Object] 错误,而有些情况下则没有任何错误出现…… :S 我真烦 Angular 的测试。 - Gerardo Buenrostro González

53
如果sourcemap=false没有帮助,尝试以下步骤: 1)打开运行测试的浏览器 2)点击调试按钮 3)打开控制台
错误消息将会在那里显示。

enter image description here


8
我甚至不需要点击“调试”按钮,只需打开开发者控制台就能完成。 - chris31389
太棒了!我已经在所有地方添加了sourcemap选项,但最终这给了我所需的信息。 - SkarXa
1
“--sourcemaps=false” 这个东西对我不起作用,但这个方法完美地解决了问题!谢谢! - mrClean
如果浏览器在测试后立即关闭,那么这并没有什么帮助。我猜我会写一堆无用的测试来保持窗口打开,就像某种穴居人一样。 - CoryCoolguy

24

尝试从终端中运行测试以获取更详细的错误信息,例如:

ng test -sm=false

在您的测试中,您可以替换

标签。
it('should...')

使用

fit('should...') 

现在只有在fit前面的测试才会运行。 如果想要在运行测试后保持浏览器打开,请按照以下方式运行测试:

ng test -sm=false --single-run false

个人经历过这种错误两次。都是在调用fixture.detectChanges()时触发的。

第一次,我通过更加安全地在html文件中使用字符串插值解决了问题。

不安全示例:


<p>{{user.firstName}}</p>

更安全的示例(注意问号):

<p>{{user?.firstName}}</p>

属性绑定可能也适用于这种情况:

<p [innerText]="user?.firstName"></p>

第二次,我在我的 .html 文件中使用了 DatePipe,但我用它的模拟属性不是日期类型。
.html 文件:
<p>{{startDate | date: 'dd-MM-yyyy'}}</p>

.ts(模拟数据)文件(错误的):

let startDate = 'blablah';

.ts(模拟数据)文件(正确):

let startDate = '2018-01-26';

为什么“?”字符串解释更安全?在我的情况下,这很有效。 - Benjamin Castor
2
@DylanKapp 这个代码会在尝试读取对象属性之前检查对象是否为空。更多详情请参考 https://angular.io/guide/template-syntax#safe-navigation-operator。 - Christian Rondeau

18
这是因为Jasmine框架无法处理ErrorEvent类型,因此它无法提取错误消息并在该对象上调用error.toString()。我刚刚在Jasmine存储库中提交了一个问题https://github.com/jasmine/jasmine/issues/1594。只要它没有修复,您就可以在node_modules文件夹中临时修补已安装的jasmine包。在我的情况下,它是node_modules/jasmine/node_modules/lib/jasmine-core/jasmine.js,然后更改ExceptionFormatter的实现从这里开始。
if (error.name && error.message) {
    message += error.name + ': ' + error.message;
} else {
    message += error.toString() + ' thrown';
}

到这个

if (error.name && error.message) {
    message += error.name + ': ' + error.message;
} else if (error.message) {
    message += error.message;
} else {
    message += error.toString() + ' thrown';
}

它有助于识别问题。


3
这个方法适用于jasmine-core@2.99.1版本,在 node_modules/jasmine_core/lib/jasmine_core/jasmine.js 中需要进行修补。 - Roger Garza
非常好 - 花了一分钟才找到这篇文章,但它救了我的命。谢谢。相同的jasmine-core版本。 - mr rogers
更改后,它只为我打印了“未捕获”,这对我没有帮助。因此,我添加了代码来打印error对象及其属性。 if(error){ // message+=error; for(var propName in error) { propValue = error[propName] message+='error prop: '+propName+', value: '+propValue; } } . 这提供了额外的信息,帮助我进行调试 - 例如error prop: filename, value: blob:http://localhost:9881/11777e3a-28d8-414e-9047-cee7d328e843 - Manu Chadha

7

对我来说,这与在组件的ngOnInit中解决承诺有关。我必须使用asyncfakeAsync和tick,以及使用spyOn替换异步服务。

beforeEach(async(
  //... initialise testbed and component
))
beforeEach(fakeAsync(
  // ... setup mocks then call:
  component.ngOnInit()
  tick()
  fixture.detectChanges()
))

Angular - 如何对具有异步服务调用的组件进行单元测试


4

简述: 可能与路由测试有关。

我也遇到了[object ErrorEvent]的错误。 一个小时后,将其追踪到一行代码。

this.username = this.userService.getUser(this.route.snapshot.paramMap.get('id'))[0];

问题出在测试环境试图评估 this.route.snapshot.paramMap.get('id')
如果我用 0 替换它,[object ErrorEvent] thrown 就消失了。
我的 userService 有一个用户,像这样:
public users = [ ["admin", "First name", "Surname", etc... ] ].

所以,0 只是获取此用户,索引为 0

否则,在正常运行我的应用程序时,this.route.snapshot.paramMap.get('id') 在用户从我的用户表中选择要编辑的用户时进行评估。

因此,在我的 HTML 中,*ngFor="let user of users; index as i" 循环显示所有用户,然后使用 routerLink="/edit/{{i}}",因此您可以单击每个用户的编辑按钮,当单击时,转到例如 http://localhost:4200/edit/0,以编辑上述管理员用户的详细信息。


4

每个测试用例后进行清理操作怎么样:

  afterEach(() => {
    TestBed.resetTestingModule();
  })

我在某个地方读到,无论如何每次测试都会重置TestBed。 - bgerth
1
在我的情况下,它有助于为下一次测试进行清理。 - Sebastian Brestin

3

对我而言,这是因为我未为我订阅的API定义错误处理程序所导致的。

我的修复只涉及添加以下处理(err)的代码块:

it('reports an error to subscribers of api calls if not authenticated', (done) => {
    let obsDataFound = dataService.find(1);
    obsDataFound.subscribe((app) => {
        // not expecting this block to be called
        done();
    }, (err) => {
        // This is the err block that I added that solved the problem
        expect(true).toBeTruthy();
        done();
    });

    let testRequest = httpMock.expectOne({method: 'GET'});
    const mockErrorResponse = { status: 401, statusText: 'Unauthorized test status message' };
    testRequest.flush(appTest, mockErrorResponse);
});

这也是我的情况,我正在进行多播,其中一个订阅者没有处理错误。 - Ma Jerez

1
如果你在Karma测试运行器中打开Chrome窗口并检查控制台,会有所帮助。对我来说,这有助于发现应用程序无法在未定义的数组上使用Array.findIndex方法(因为数据结构是按日期字符串组织的,例如data [2018] [3] [28],而我指向了错误的日期),但测试仍然继续运行而不是停止。

非常感谢!我本来以为信息会出现在控制台中,你帮我节省了几个小时的时间 :) - Sébastien Tromp

1

我有同样的问题。这种错误发生的一种方式是在模板中尝试访问任何 null 或 undefined 的内容。确保在这些变量上进行安全检查。

例如,当组件加载时,如果 config 未定义,则会抛出 [object: ErrorEvent]。

template.html

<div *ngIf="config.options">
   .....
   ......
</div>

请这样做。
<div *ngIf="config?.options">
   .....
   ......
</div>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接