import { browser } from 'protractor'; import { SitePage } from './app.po'; /* tslint:disable:max-line-length */ describe('onerror handler', function() { let page: SitePage; beforeAll(() => { page = new SitePage(); page.navigateTo(''); }); it('(called without an error object) should call ga with a payload based on the message, url, row and column arguments', async () => { const message1 = await callOnError('Error: some error message', 'some-file.js', 12, 3, undefined); expect(message1).toEqual('some error message\nsome-file.js:12:3'); const message2 = await callOnError('Error: some error message', undefined, undefined, undefined, undefined); expect(message2).toEqual('some error message\nnull:?:?'); }); it('(called without an error object) should call ga with a payload that is no longer that 150 characters', async () => { const message = await callOnError( 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz' + 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz', 'some-file.js', 12, 3, undefined); expect(message).toEqual( 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz' + 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst'); }); it('(called with a Firefox on android style error) should call ga with a payload based on the error object', async () => { const message = await callOnError('Error: something terrible has happened. oh no. oh no.', undefined, undefined, undefined, { stack: `AppComponent@https://example.com/app/app.component.ts:31:29 createClass@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:12200:20 createDirectiveInstance@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:12049:37 createViewNodes@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:13487:53 createRootView@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:13377:5 callWithDebugContext@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:14778:39 debugCreateRootView@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:14079:12 ComponentFactory_.prototype.create@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:10998:37 ComponentFactoryBoundToModule.prototype.create@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:3958:16 ApplicationRef.prototype.bootstrap@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:5769:40 PlatformRef.prototype._moduleDoBootstrap/<@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:5496:74 PlatformRef.prototype._moduleDoBootstrap@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:5496:13 PlatformRef.prototype.bootstrapModuleFactory/ { const message = await callOnError('Error: something terrible has happened. oh no. oh no.', undefined, undefined, undefined, { stack: `AppComponent createClass createDirectiveInstance createViewNodes createRootView callWithDebugContext create bootstrap forEach@[native code] _moduleDoBootstrap onInvoke run onInvokeTask runTask drainMicroTaskQueue promiseReactionJob@[native code]` }); expect(message).toEqual(`something terrible has happened. oh no. oh no. AppComponent createClass createDirectiveInstance createViewNodes createRootView callWithDebugContext cr`); }); it('(called with a Opera 50 style error) should call ga with a payload based on the error object', async () => { const message = await callOnError('Error: something terrible has happened. oh no. oh no.', undefined, undefined, undefined, { stack: `Error: something terrible has happened. oh no. oh no. at new AppComponent (https://example.com/app/app.component.ts:31:29) at createClass (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:12200:20) at createDirectiveInstance (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:12049:37) at createViewNodes (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:13487:53) at createRootView (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:13377:5) at callWithDebugContext (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:14778:42) at Object.debugCreateRootView [as createRootView] (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:14079:12) at ComponentFactory_.create (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:10998:46) at ComponentFactoryBoundToModule.create (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:3958:29) at ApplicationRef.bootstrap (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:5769:57)` }); expect(message).toEqual(`something terrible has happened. oh no. oh no. new AppComponent@app.component.ts:31:29 createClass@core.umd.js:12200:20 createDirectiveInstance@core.u`); }); it('(called with a Chrome 64 style error) should call ga with a payload based on the error object', async () => { const message = await callOnError('Error: something terrible has happened. oh no. oh no.', undefined, undefined, undefined, { stack: `Error: something terrible has happened. oh no. oh no. at new AppComponent (https://example.com/app/app.component.ts:31:29) at createClass (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:12200:20) at createDirectiveInstance (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:12049:37) at createViewNodes (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:13487:53) at createRootView (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:13377:5) at callWithDebugContext (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:14778:42) at Object.debugCreateRootView [as createRootView] (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:14079:12) at ComponentFactory_.create (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:10998:46) at ComponentFactoryBoundToModule.create (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:3958:29) at ApplicationRef.bootstrap (https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:5769:57)` }); expect(message).toEqual(`something terrible has happened. oh no. oh no. new AppComponent@app.component.ts:31:29 createClass@core.umd.js:12200:20 createDirectiveInstance@core.u`); }); it('(called with a Firefox 58 style error) should call ga with a payload based on the error object', async () => { const message = await callOnError('Error: something terrible has happened. oh no. oh no.', undefined, undefined, undefined, { stack: `AppComponent@https://example.com/app/app.component.ts:31:29 createClass@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:12200:20 createDirectiveInstance@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:12049:37 createViewNodes@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:13487:53 createRootView@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:13377:5 callWithDebugContext@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:14778:39 debugCreateRootView@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:14079:12 ComponentFactory_.prototype.create@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:10998:37 ComponentFactoryBoundToModule.prototype.create@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:3958:16 ApplicationRef.prototype.bootstrap@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:5769:40 PlatformRef.prototype._moduleDoBootstrap/<@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:5496:74 PlatformRef.prototype._moduleDoBootstrap@https://example.com/packages/@angular/core@5.0.0/bundles/core.umd.js:5496:13 PlatformRef.prototype.bootstrapModuleFactory/ { const message = await callOnError('Error: something terrible has happened. oh no. oh no.', undefined, undefined, undefined, { stack: `Error: something terrible has happened. oh no. oh no. at AppComponent (eval code:31:21) at createClass (eval code:12200:13) at createDirectiveInstance (eval code:12049:5) at createViewNodes (eval code:13487:21) at createRootView (eval code:13377:5) at callWithDebugContext (eval code:14778:9) at debugCreateRootView (eval code:14079:5) at ComponentFactory_.prototype.create (eval code:10998:9) at ComponentFactoryBoundToModule.prototype.create (eval code:3958:9) at ApplicationRef.prototype.bootstrap (eval code:5769:9)` }); expect(message).toEqual(`something terrible has happened. oh no. oh no. AppComponent@???:31:21 createClass@???:12200:13 createDirectiveInstance@???:12049:5 createViewNodes@???`); }); async function callOnError(message, url, line, column, error) { await browser.executeScript(function() { // reset the ga queue (window as any).ga.q.length = 0; // post the error to the handler if (window.onerror) { window.onerror(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]); } }, message, url, line, column, error); const gaCalls = await page.ga(); const exceptionCall = gaCalls.find(call => call[0] === 'send' && call[1] === 'exception'); if (exceptionCall) { const payload = exceptionCall[2]; expect(payload.exFatal).toBe(true); return payload.exDescription; } } });