From 21f764c347c1609367110e88576d4b2705ac03a7 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Sat, 10 Jun 2017 01:09:02 +0200 Subject: [PATCH] build: report ngOnDestroy exceptions in unti tests (#5036) Monkey-patches TestBed.resetTestingModule such that any errors that occur during component destruction are thrown instead of silently logged. Also runs TestBed.resetTestingModule after each unit test. Without this patch, the combination of two behaviors is problematic for Angular Material: - TestBed.resetTestingModule catches errors thrown on fixture destruction and logs them without the errors ever being thrown. This means that any component errors that occur in ngOnDestroy can encounter errors silently and still pass unit tests. - TestBed.resetTestingModule is only called *before* a test is run, meaning that even *if* the aforementioned errors were thrown, they would be reported for the wrong test (the test that's about to start, not the test that just finished). --- test/karma-test-shim.js | 43 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/test/karma-test-shim.js b/test/karma-test-shim.js index 472b6a2528d..a451530c9c3 100644 --- a/test/karma-test-shim.js +++ b/test/karma-test-shim.js @@ -87,9 +87,50 @@ function configureTestBed() { jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; - testing.TestBed.initTestEnvironment( + var testBed = testing.TestBed.initTestEnvironment( testingBrowser.BrowserDynamicTestingModule, testingBrowser.platformBrowserDynamicTesting() ); + + patchTestBedToDestroyFixturesAfterEveryTest(testBed); + }); +} + +/** + * Monkey-patches TestBed.resetTestingModule such that any errors that occur during component + * destruction are thrown instead of silently logged. Also runs TestBed.resetTestingModule after + * each unit test. + * + * Without this patch, the combination of two behaviors is problematic for Angular Material: + * - TestBed.resetTestingModule catches errors thrown on fixture destruction and logs them without + * the errors ever being thrown. This means that any component errors that occur in ngOnDestroy + * can encounter errors silently and still pass unit tests. + * - TestBed.resetTestingModule is only called *before* a test is run, meaning that even *if* the + * aforementioned errors were thrown, they would be reported for the wrong test (the test that's + * about to start, not the test that just finished). + */ +function patchTestBedToDestroyFixturesAfterEveryTest(testBed) { + // Original resetTestingModule function of the TestBed. + var _resetTestingModule = testBed.resetTestingModule; + + // Monkey-patch the resetTestingModule to destroy fixtures outside of a try/catch block. + // With https://github.com/angular/angular/commit/2c5a67134198a090a24f6671dcdb7b102fea6eba + // errors when destroying components are no longer causing Jasmine to fail. + testBed.resetTestingModule = function() { + try { + this._activeFixtures.forEach(function (fixture) { fixture.destroy(); }); + } finally { + this._activeFixtures = []; + // Regardless of errors or not, run the original reset testing module function. + _resetTestingModule.call(this); + } + }; + + // Angular's testing package resets the testing module before each test. This doesn't work well + // for us because it doesn't allow developers to see what test actually failed. + // Fixing this by resetting the testing module after each test. + // https://github.com/angular/angular/blob/master/packages/core/testing/src/before_each.ts#L25 + afterEach(function() { + testBed.resetTestingModule(); }); }