Angular 6单元测试:afterAll \ nReferenceError中引发了错误:找不到变量:$

时间:2018-07-26 16:08:25

标签: angular karma-runner angular6

在运行我的单元测试时,即使它们通过了,在所有测试运行结束时,我也会经常遇到以下错误。

在运行PhantomJS的Jenkins CI构建上:

.PhantomJS 2.1.1 (Linux 0.0.0) ERROR
  {
    "message": "An error was thrown in afterAll\nReferenceError: Can't find variable: $ thrown",
    "str": "An error was thrown in afterAll\nReferenceError: Can't find variable: $ thrown"
  }

或在Chrome上

Chrome 67.0.3396 (Windows 7 0.0.0) ERROR
  {
    "message": "An error was thrown in afterAll\n[object ErrorEvent] thrown",
    "str": "An error was thrown in afterAll\n[object ErrorEvent] thrown"
  }

我也有非常不可靠的测试,有时它们不会成功,而有时相同的测试也会失败,因此我知道有些奇怪的事情发生了。

12 个答案:

答案 0 :(得分:14)

另一件对我有帮助并解决了一些问题的事情是在每次测试后添加声明以销毁灯具

  afterEach(() => {
    fixture.destroy();
  });

答案 1 :(得分:12)

我们面临着类似的问题,既有相同的间歇性错误,又有间歇性的失败测试。似乎是由于以下事实:当升级到Angular 6时,我们还升级到了Jasmine 3,其中以随机顺序运行测试现在显然是默认设置。通过将random设置为false,我们将不再看到这些问题。为此,我们在karma.conf.js中添加了此设置:

  config.set({
    client: {
      jasmine: {
        random: false
      }
    }
  })

答案 2 :(得分:10)

我的问题是,由于设置测试的一种非常愚蠢的方式,我的测试中出现了竞赛情况,但是我还是想在这里记录下来,因为我很难在互联网上找到问题的答案。

我要做的就是声明两个beforeEach函数来设置测试,而两个函数之一是异步的,所以我遇到了竞争状况,有时它们失灵并失败了。

这是我的测试的样子:

beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ HomeComponent ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(HomeComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

因此,为解决此问题,我将所有设置都放在一个同步的beforeEach中。

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [HomeComponent]
    }).compileComponents();
    fixture = TestBed.createComponent(HomeComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

我花了太多时间试图解决这个问题,所以我把它放在这里以拯救别人。

答案 3 :(得分:4)

发生此错误时,请检查karma打开的浏览器并检查其控制台是否有错误。通常,这里会有堆栈跟踪,这将帮助您解决问题。这也适用于业障引发的其他无法提供信息的错误。

答案 4 :(得分:3)

我有一个类似的问题,看来自Angular v6和Karma v3起,这个模糊的afterAll错误已经开始出现(https://github.com/jasmine/jasmine/issues/1523)。 对于我自己,此错误不会使测试失败,但会使套件失败。

查看了许多关于此问题的答案后,看来原因几乎总是不同的,这使得很难在线寻求帮助。可以希望在某个时候添加补丁更新,以冒出更好的错误。

我的错误

[INFO] HeadlessChrome 71.0.3542 (Linux 0.0.0) DialogComponent #apply should save. FAILED
[INFO]  Uncaught TypeError: Cannot read property 'nativeElement' of undefined thrown
[INFO]       [31m✗ [39m[31mshould save.[39m
[INFO]  Uncaught TypeError: Cannot read property 'nativeElement' of undefined thrown
[INFO] 
[INFO] HeadlessChrome 71.0.3542 (Linux 0.0.0) DialogComponent #apply should save. FAILED
[INFO]  Uncaught TypeError: Cannot read property 'nativeElement' of undefined thrown
[INFO] HeadlessChrome 71.0.3542 (Linux 0.0.0) DialogComponent #apply should save. FAILED
[INFO]  Uncaught TypeError: Cannot read property 'nativeElement' of undefined thrown
[INFO] HeadlessChrome 71.0.3542 (Linux 0.0.0) ERROR
[INFO]   {
[INFO]     "message": "An error was thrown in afterAll\nUncaught TypeError: Cannot read property 'nativeElement' of undefined thrown\nUncaught TypeError: Cannot read property 'nativeElement' of undefined thrown",
[INFO]     "str": "An error was thrown in afterAll\nUncaught TypeError: Cannot read property 'nativeElement' of undefined thrown\nUncaught TypeError: Cannot read property 'nativeElement' of undefined thrown"
[INFO]   }

找到有问题的测试

我收到了此afterAll错误消息,不知道是什么原因导致的,或者是什么测试触发了它。 我做的第一件事是安装karma-spec-reporternpm install karma-spec-reporter --save-dev

将此添加到karma.conf.js文件中的插件数组中: 这将为您提供规范报告者,将spec添加到报告者数组中:reporters: ['spec'],

下次运行测试时,有问题的测试后,控制台中将显示afterAll错误。

我的问题/解决方案

我发现测试正在调用htmlElement.click()。 我将其更改为:htmlElement.dispatchEvent(new Event('click)) 瞧,测试开始通过了。

摘要

作为一般规则,我现在避免在HTMLElement上使用.click()。 另外,当用户与UI交互时,它是通过事件完成的,因此它可以更正确地模仿用户的操作,这在测试时总是一件好事。

答案 5 :(得分:1)

此错误的具体问题是由于未模拟正在测试的组件的子组件引起的。在这种情况下,我有一个带有两个子组件的主页组件,这需要对子组件进行声明,而我无法对其进行模拟。

结果,子组件具有真正的依赖关系,这会间歇性地导致测试以这种非显而易见的方式失败(看起来不同的测试都是随机失败的,但事实并非如此)。

在这种情况下,如下模拟非常有效:

@Component({
    selector: 'app-exercise',
    template: '<p>Mock Exercise Component</p>'
})
class MockExerciseComponent {
}

@Component({
    selector: 'app-user',
    template: '<p>Mock User Component</p>'
})
class MockUserComponent {
}

describe('HomepageComponent', () => {
    let component: HomepageComponent;
    let fixture: ComponentFixture<HomepageComponent>;

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            // note you need to mock sub components!
            declarations: [HomepageComponent, MockExerciseComponent, MockUserComponent],

答案 6 :(得分:1)

我刚刚遇到了这个问题。我的问题与 HttpClient 有关。 我正在模拟一个 httpClient 返回错误 503 并且我没有在订阅上创建错误函数:

  httpClient.get('/api').subscribe(() => {
      fail('Should not return success');
    }, (data) => {
      expect(data.status).toEqual(503); // without adding this callback here, you will get the error of this question
    });
    const request = mock.expectOne('/api');

    request.flush({data: 'test'}, { status: 503, statusText: 'Internal Error'});

答案 7 :(得分:0)

就我而言

我正在使用karma-parallel,并且在更新执行人编号时,它起作用了(不知道为什么)

 parallelOptions: {
      executors: 4, // Earlier it was 5 I have updated it to 4 and it worked
      shardStrategy: 'round-robin',
      ......
 }

答案 8 :(得分:0)

就我而言,将导入从Observable更改为Rx库已解决了该问题

之前:

import { Observable } from 'rxjs/Observable';

之后:

import { Observable } from 'rxjs/Rx';

答案 9 :(得分:0)

一个可能的问题是,您的组件之一运行了第三方脚本,该脚本发出了失败的CORS请求。 (https://github.com/karma-runner/karma/issues/1268#issuecomment-70422477解决了我的问题)这可以使测试在Chrome上似乎可以正常运行,并在您的CI上间歇性地失败。

如有疑问,请遵循Rui(https://stackoverflow.com/a/56662721/3370010)的建议并打开控制台,即使所有测试都通过了。

答案 10 :(得分:0)

我也有类似的问题。在我的angular 10项目中。在10次中,有8次将失败,并出现所有错误。事实证明,在spec.ts文件中,导入应具有HttpClientTestingModule而不是HttpClientModule。尝试这个。它可以解决Afterall问题中的随机错误。

答案 11 :(得分:0)

我非常感谢 Oisin,因为 his answer 为我指明了正确的方向。请将此答案视为对他的补充。

但是,恕我直言,有两个方面需要澄清:

  1. 我们没有处理竞争条件。
    竞争条件意味着 props.setId 的两个实例并行运行,我们无法确定哪个先完成。实际上,非异步 beforeEach 首先运行,beforeEach 运行第二。
    每一次。
    当您有两个 async 并且其中一个是 beforeEach(包括使用 async 提供的闪亮 waitForAsync 包装器的那些)时,异步实例的执行被推送到执行队列结束。

  2. 我也找到了 Oisin 提出的解决方案:

<块引用>

[...] 将所有设置合二为一,同步 beforeEach。

... 太局限了。它不必是同步的。它可以是异步的,没有问题。

重要的一点是,@angular/core/testing 应该追着 TestBed.createComponent()已解决。
这就是全部。

为了清楚起见,这个随机示例:

TestBed.configureTestingModule()

... 应该变成:

import { TestBed, waitForAsync } from '@angular/core/testing';
// more imports...

describe('SomeComponent', () => {
  beforeEach(waitForAsync(() => {
    TestBed.configureTestingModule({
      declarations: [SomeComponent],
      imports: [SharedModule, RouterTestingModule, HttpClientTestingModule],
      providers: [{
        provide: SomeService, useValue: {
          someObservableMethod$: () => of()
        } as Partial<SomeService>
      }]
    })
      .overrideModule(MatIconModule, MatIconModuleMock)
      .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(SomeComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  /* tests here */
});

第二个(同步)import { TestBed, waitForAsync } from '@angular/core/testing'; // more imports... describe('SomeComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ declarations: [SomeComponent], imports: [SharedModule, RouterTestingModule, HttpClientTestingModule], providers: [{ provide: SomeService, useValue: { someObservableMethod$: () => of() } as Partial<SomeService> }] }) .overrideModule(MatIconModule, MatIconModuleMock) .compileComponents(); fixture = TestBed.createComponent(SomeComponent); component = fixture.componentInstance; fixture.detectChanges(); })); /* tests here */ }); 中的代码被附加到第一个(异步)beforeEach。就是这样。