実行中のすべてのテストの最後に、時々ユニットテストを実行すると、それらが合格したとしても、次のエラーが表示されます。
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"
}
また、テストは成功せず、同じテストが失敗することもあるため、何も変更せずに非常に信頼性の低いテストも行っているため、奇妙なことが起こっていることがわかりました。
同じ断続的なエラーと断続的に失敗するテストの両方で、同様の問題に直面していました。これは、Angular 6にアップグレードするときに、ランダムな順序でテストを実行することが明らかにデフォルトになったJasmine 3にアップグレードしたという事実によるものと思われます。 randomをfalseに設定することにより、これらの問題は発生しなくなりました。この設定をkarma.conf.jsに追加することでこれを行いました。
config.set({
client: {
jasmine: {
random: false
}
}
})
私の問題は、テストを設定する非常に愚かな方法のためにテストで競合状態があったことでしたが、インターネットで問題の答えを見つけるのに苦労したので、とにかくここにそれを文書化したいと思いました。
何とかして行ったのは、テストをセットアップするために2つのbeforeEach
関数を宣言することでした。2つのうちの1つは非同期だったため、競合状態に陥り、失敗することがありました。
テストは次のようになりました。
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ HomeComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(HomeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
これを解決するために、すべてのセットアップを1つの同期beforeEachに入れました。
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [HomeComponent]
}).compileComponents();
fixture = TestBed.createComponent(HomeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
これを理解しようとして時間を無駄にしたので、他の人を救うためにここに置いています。
私は同様の問題を抱えていました。Angular v6&Karma v3以降、このあいまいなafterAll
エラーが表示され始めたようです( https://github.com/jasmine/jasmine/ issues/152 )。私自身にとって、このエラーはテストに失敗しませんが、スイートに失敗します。
この問題に対する多くの答えを見た後、原因はほぼ常に異なっているようであり、オンラインでヘルプを見つけることが難しくなっています。より良いエラーを発生させるために、ある時点でパッチの更新が追加されることを期待できます。
[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-reporter
:npm install karma-spec-reporter --save-dev
をインストールすることでした
これをkarma.conf.js
ファイルのプラグイン配列に追加します。これにより、仕様レポーターが提供されます。spec
をレポーター配列に追加します:reporters: ['spec'],
次回テストを実行すると、問題のあるテストの後、コンソールにafterAll
エラーが表示されます。
テストがhtmlElement.click()
を呼び出していることがわかりました。これを次のように変更しました:htmlElement.dispatchEvent(new Event('click))
そして、テストが合格し始めました。
一般的なルールとして、HTMLElementで.click()
を使用することは避けます。また、ユーザーがUIを操作するときは、イベントを介して行われるため、ユーザーのアクションをより正確に模倣します。これは、テスト時に常に良いことです。
このエラーが発生した場合、karmaによって開かれたブラウザーを確認し、コンソールのエラーを確認してください。通常、問題の修正に役立つスタックトレースがあります。これは、情報以外のカルマによってスローされる他のエラーにも適用されます。
このエラーに関する私の特定の問題は、テストしているコンポーネントのサブコンポーネントをモックしていないことが原因でした。この場合、2つのサブコンポーネントを持つホームページコンポーネントがあり、サブコンポーネントの宣言が必要でしたが、モックできませんでした。
その結果、サブコンポーネントには、この非自明な方法で断続的にテストが失敗する実際の依存関係がありました(異なるテストがランダムに失敗するように見えますが、そうではありません)。
この場合、次のようなモックは非常にうまく機能します。
@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],