karma: [object ErrorEvent] thrown in angular app, Debug window.
Expected behaviour
Passing tests in the command line should match passing tests in the karma debugger.
Actual behaviour
In debug browser, a test that passes according to the command line fails in the debug browser with error message: [object ErrorEvent] thrown.
Environment Details
- Karma version (output of
karma --version): - Relevant part of your
karma.config.jsfile
There error itself is being thrown in zone.js/dist/zone.js: 195 , with zone.js version = 0.8.12.
From package.json
"devDependencies": {
"@ionic/app-scripts": "2.1.4",
"@types/jasmine": "^2.6.0",
"@types/node": "^8.0.19",
"angular2-template-loader": "^0.6.2",
"html-loader": "^0.5.1",
"istanbul-instrumenter-loader": "^3.0.0",
"jasmine": "^2.8.0",
"jasmine-spec-reporter": "^4.2.1",
"karma": "^1.7.1",
"karma-chrome-launcher": "^2.2.0",
"karma-coverage-istanbul-reporter": "^1.3.0",
"karma-jasmine": "^1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^2.0.5",
"null-loader": "^0.1.1",
"protractor": "^5.2.0",
"ts-loader": "^3.0.3",
"ts-node": "^3.3.0",
"typescript": "~2.4.0"
},
karma.conf.js
var webpackConfig = require('./webpack.test.js');
module.exports = function(config) {
var _config = {
basePath: '../',
frameworks: ['jasmine'],
files: [
{
pattern: './test-config/karma-test-shim.js',
watched: true
},
{
pattern: './src/assets/**/*',
watched: false,
included: false,
served: true,
nocache: false
}
],
proxies: {
'/assets/': '/base/src/assets/'
},
preprocessors: {
'./test-config/karma-test-shim.js': ['webpack', 'sourcemap']
},
webpack: webpackConfig,
webpackMiddleware: {
stats: 'errors-only'
},
webpackServer: {
noInfo: true
},
browserConsoleLogOptions: {
level: 'log',
format: '%b %T: %m',
terminal: true
},
coverageIstanbulReporter: {
reports: [ 'html', 'lcovonly' ],
fixWebpackSourcePaths: true
},
reporters: config.coverage ? ['kjhtml', 'dots', 'coverage-istanbul'] : ['kjhtml', 'dots'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
};
config.set(_config);
};
karma-test-shim.js
require('core-js/es6');
require('core-js/es7/reflect');
require('zone.js/dist/zone');
require('zone.js/dist/long-stack-trace-zone');
require('zone.js/dist/proxy');
require('zone.js/dist/sync-test');
require('zone.js/dist/jasmine-patch');
require('zone.js/dist/async-test');
require('zone.js/dist/fake-async-test');
var appContext = require.context('../src', true, /\.spec\.ts/);
appContext.keys().forEach(appContext);
var testing = require('@angular/core/testing');
var browser = require('@angular/platform-browser-dynamic/testing');
testing.TestBed.initTestEnvironment(browser.BrowserDynamicTestingModule, browser.platformBrowserDynamicTesting());
The test itself:
I removed the @Injectable tag in the hopes that it would isolate angular from the issue. The test “LocationService Lat/Lon to tile conversion should match for the two lat2TileY functions” (the last test) is the one that passes in the command line but fails in the debugger.
Also, I can get the test to pass if I comment out the two tests preceding the last test, but not if I comment out the second-to-last test or the third-to-last test only. Kind of puzzled as to how that’s happening.
import { Coordinates, Geolocation } from '@ionic-native/geolocation';
import { LocationNoAngular } from './location-no-angular';
import { LocationService } from './location.service';
import * as LocationTestData from './location-spec-data';
describe('LocationService', () => {
let locationService: LocationNoAngular;
const epsilon = .004;
beforeAll(() => {
locationService = new LocationNoAngular(new Geolocation());
});
describe('getDistanceFunction', () => {
it('should return zero for identical locations', () => {
const distance: number = locationService.getDistance(
LocationTestData.zeroDistanceTestPoint,
LocationTestData.zeroDistanceTestPoint
);
expect(Math.abs(distance)).toBeLessThan(epsilon);
});
it('should return 179.9 for distance between known coordinates', () => {
const distance: number = locationService.getDistance(
LocationTestData.knownDistanceTestPoint1,
LocationTestData.knownDistanceTestPoint2
);
expect(Math.abs(distance - LocationTestData.knownDistance)).toBeLessThan(epsilon);
});
});
describe('Lat/Lon to tile conversion', () => {
it('should map longitude to x tiles 0, 1, 2, 3 on lower bound', () => {
expect(locationService.lon2TileX(-180, 2)).toEqual(0);
expect(locationService.lon2TileX(-90, 2)).toEqual(1);
expect(locationService.lon2TileX(0, 2)).toEqual(2);
expect(locationService.lon2TileX(90, 2)).toEqual(3);
});
it('should map longitude to x tiles 0, 1, 2, 3 on upper boundbound', () => {
expect(locationService.lon2TileX(-91, 2)).toEqual(0);
expect(locationService.lon2TileX(-1, 2)).toEqual(1);
expect(locationService.lon2TileX(89, 2)).toEqual(2);
expect(locationService.lon2TileX(179, 2)).toEqual(3);
});
it('should match the alternative lat/lon to tile function', () => {
expect(locationService.lon2TileX(-91, 2)).toEqual(locationService.lon2TileXVerify(-91, 2));
expect(locationService.lon2TileX(-1, 2)).toEqual(locationService.lon2TileXVerify(-1, 2));
expect(locationService.lon2TileX(89, 2)).toEqual(locationService.lon2TileXVerify(89, 2));
expect(locationService.lon2TileX(179, 2)).toEqual(locationService.lon2TileXVerify(179, 2));
});
it('should map lat2TileY between 0, 1, 2, 3', () => {
expect(locationService.lat2TileY(-85, 2)).toEqual(3);
expect(locationService.lat2TileY(-66, 2)).toEqual(2);
expect(locationService.lat2TileY(1, 2)).toEqual(1);
expect(locationService.lat2TileY(67, 2)).toEqual(0);
expect(true).toBe(true);
});
it('should map lat2TileY between 0, 1, 2, 3', () => {
expect(locationService.lat2TileY(-85, 2)).toEqual(3);
expect(locationService.lat2TileY(-66, 2)).toEqual(2);
expect(locationService.lat2TileY(1, 2)).toEqual(1);
expect(locationService.lat2TileY(67, 2)).toEqual(0);
});
it('should match for the two lat2TileY functions', function() {
expect(locationService.lat2TileY(-85, 2)).toEqual(locationService.lat2TileYVerify(-85, 2));
expect(locationService.lat2TileY(-60, 2)).toEqual(locationService.lat2TileYVerify(-60, 2));
expect(locationService.lat2TileY(1, 2)).toEqual(locationService.lat2TileYVerify(1, 2));
expect(locationService.lat2TileY(67, 2)).toEqual(locationService.lat2TileYVerify(67, 2));
});
});
})
The LocationNoAngular class (abbreviated)
export class LocationNoAngular {
private locationSubscription: Subscription;
private currentLocation: Geoposition
public locationData: Subject<Geoposition>;
public readonly metersPerDegreeLat: number = 111111;
constructor(private geolocation: Geolocation) {
this.locationData = new Subject<any>();
}
...skipping some methods...
lon2TileXVerify(lon, zoom) {
return (Math.floor((lon + 180) / 360 * Math.pow(2, zoom)));
}
lat2TileYVerify(lat, zoom) {
return (Math.floor((1-Math.log(Math.tan(lat*Math.PI/180) + 1/Math.cos(lat*Math.PI/180))/Math.PI)/2 *Math.pow(2,zoom)));
}
// https://msdn.microsoft.com/en-us/library/bb259689.aspx
lon2TileX(lon, zoom) {
return Math.floor(((lon + 180) / 360) * Math.pow(2, zoom));
}
lat2TileY(lat, zoom) {
const sinLatitude: number = Math.sin(this.degreesToRadians(lat));
return Math.floor((.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI)) * Math.pow(2, zoom));
}
Steps to reproduce the behaviour
Hopefully the above information is enough, but happy to setup more detail if necessary. It’s an ionic3 project.
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Comments: 49 (6 by maintainers)
In case anyone still has this issue, I found the easiest way to see the real error : simply open your browser running the tests, and open the console. The error will be there.
What fixed it for me was taking this:
beforeEach(() => { fixture = TestBed.createComponent(ConversationComponent); component = fixture.componentInstance; fixture.detectChanges(); });and removing
fixture.detectChanges();Still not sure why this fixed it bu I had
[object ErrorEvent] thrownon just about all my specs until I removed itThis works for me
Just comment this line
Running tests with
ng test --source-map=falselet me see what the actual error message was, instead of the cryptic[object ErrorEvent] thrown. So I could narrow it down to exactly where the problem was.@trichetriche => That is fine if you are running the tests locally, but my problem is that the tests were working 100% correctly whenever I was using the browser on my local machine (no errors either in the browser or in the browser’s console), but they were failing on our CI/CD environment when it was running the Chrome Headless browser via Puppeteer.
If we look at the definition given in the docs for dixture.detectChanges(). I don’t think the solution given by @JonahElbaz is viable.
You must tell the TestBed to perform data binding by calling fixture.detectChanges(). Only then does the <h1> have the expected title.https://angular.io/guide/testing
any fix for this issue?
I have found the cause! It has nothing to do with karma, but the issue is caused by the
source-map-supportpackage which is installed by@angular/angular-cli.The Angular source maps refer to paths like
ng:///DynamicTestModule/YourComponent.ngfactory.jswhich triggers CORS errors.Should be fixed by https://github.com/evanw/node-source-map-support/pull/222 and/or by the Angular CLI.
For me, it helped to wrap the test-function with
async(...).Then I get the correct error instead of
[object ErrorEvent] thrownWe have had this issue for more than a year now. We have to switch between
--source-map=trueand--source-map=falseall the time. Can this issue be reopened?I found the solution but I don’t remember link to it.
The problem was caused by using “this.router.navigate([‘/login’]);” in ngOnInit method in completely other component. In your tests you need to specify:
and put this formula into “imports”, and also “LoginComponent” into “declarations”.
For anyone else who might be having this issue, I have a feeling it is likely related to: https://stackoverflow.com/questions/45722256/how-do-i-debug-a-object-errorevent-thrown-error-in-my-karma-jasmine-tests. I haven’t been able to identify the exact place in my code that’s triggering the error, but when porting most of the code over to an angular-cli-generated project and when using the default karma.conf.js, the problem goes away.
The only trace I have when executing tests is this:
I had the same issue and found the cause is this.router.navigate used in ngOnInit.
Solution: Add below code in spec.ts
const mockRoute = { navigate: jasmine.createSpy(‘navigate’) };
Likewise mock others nested function call.
I may be a bit late on this topic, but I agree with @leotm : the routing is in cause of those issues.
Like him, I commented this line
this.route.snapshot.params.versionIdand my error magically appeared (with source mapping disabled).I thought I should post a message, if it could help …
TL;DR: It may be related to testing routing.
I’m getting
[object ErrorEvent] throwntoo. I traced it to one line of code. Here’s my code snippet.The problem lies with the test environment attempting to evaluate the
this.route.snapshot.paramMap.get('id')part.If I replace it with
0,[object ErrorEvent] throwngoes away.My userService has a user like so:
public users = [ ["admin", "First name", "Surname", etc... ] ].So
0just gets this user, at index0.Otherwise when normally running my app,
this.route.snapshot.paramMap.get('id')is evaluated when the user selects a user to edit from my table of users.So in my HTML,
*ngFor="let user of users; index as i"loops to display all the users androuterLink="/edit/{{i}}"so you can click on edit buttons for each user, which when clicked go to e.g.http://localhost:4200/edit/0to edit the aforementioned admin user’s details.I changed the title to help others find your hint.
My guess is that you have a race or an async test that isn’t set up quite right. I would just assume that the debug case needs to be fixed and ignore that the command line passes.
This is probably not a karma-runner bug but reopen if you find more info suggesting it is. Esp. if you find that there is a better way to report that error.