blob: 225f042601f81eb2acd332c22da2a55d5ff24c01 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {assert} from 'chai';
import {getTestServerPort} from '../../shared/helper.js';
import {describe, it} from '../../shared/mocha-extensions.js';
import {getConsoleMessages, showVerboseMessages, waitForConsoleMessagesToBeNonEmpty} from '../helpers/console-helpers.js';
describe('The Console Tab', async () => {
it('shows BigInts formatted', async () => {
const messages = await getConsoleMessages('big-int', false, () => waitForConsoleMessagesToBeNonEmpty(5));
assert.deepEqual(messages, [
'1n',
'BigInt\xA0{2n}',
'[1n]',
'[BigInt]',
'null 1n BigInt\xA0{2n}',
]);
});
it('shows uncaught promises', async () => {
const messages = await getConsoleMessages('uncaught-promise', false, () => waitForConsoleMessagesToBeNonEmpty(2));
assert.deepEqual(messages, [
`Uncaught (in promise) Error: err1
at uncaught-promise.html:7`,
`Uncaught (in promise) Error: err2
at uncaught-promise.html:25`,
`Uncaught (in promise) DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
at throwDOMException (https://localhost:${
getTestServerPort()}/test/e2e/resources/console/uncaught-promise.html:40:7)
at catcher (https://localhost:${getTestServerPort()}/test/e2e/resources/console/uncaught-promise.html:33:5)`,
]);
});
it('shows structured objects', async () => {
const messages = await getConsoleMessages('structured-objects', false, () => waitForConsoleMessagesToBeNonEmpty(9));
assert.deepEqual(messages, [
'{}',
'ƒ Object() { [native code] }',
'{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ,\xA0…}',
'{foo: \'foo\'}',
'{bar: \'bar\'}',
'[\'test\']',
'(10)\xA0[\'test\', \'test2\', empty × 2, \'test4\', empty × 5, foo: {…}]',
'(200)\xA0[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …]',
'(2)\xA0[1, Array(2)]',
]);
});
it('escapes and substitutes correctly', async () => {
const messages = await getConsoleMessages('escaping', false, () => waitForConsoleMessagesToBeNonEmpty(9));
assert.deepEqual(messages, [
'Test for zero "0" in formatter',
'% self-escape1 dummy',
'%s self-escape2 dummy',
'%ss self-escape3 dummy',
'%sdummy%s self-escape4',
'%%% self-escape5 dummy',
'%dummy self-escape6',
'(2)\xA0[\'test\', \'test2\']',
'Array(2)',
]);
});
it('shows built-in objects', async () => {
const messages = await getConsoleMessages('built-ins', false, () => waitForConsoleMessagesToBeNonEmpty(29));
assert.deepEqual(messages, [
'/^url\\(\\s*(?:(?:\"(?:[^\\\\\\\"]|(?:\\\\[\\da-f]{1,6}\\s?|\\.))*\"|\'(?:[^\\\\\\\']|(?:\\\\[\\da-f]{1,6}\\s?|\\.))*\')|(?:[!#$%&*-~\\w]|(?:\\\\[\\da-f]{1,6}\\s?|\\.))*)\\s*\\)/i',
'/foo\\\\bar\\sbaz/i',
'Error\n at built-ins.html:13',
'Error: My error message\n at built-ins.html:16',
'Error: my multiline\nerror message\n at built-ins.html:19',
'ƒ () { return 1; }',
'ƒ () {\n return 2;\n }',
'ƒ ( /**/ foo/**/, /*/**/bar,\n /**/baz) {}',
'Arguments(2)\xA0[1, \'2\', callee: (...), Symbol(Symbol.iterator): ƒ]',
'Uint8Array\xA0[3]',
'Uint8Array(400)\xA0[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]',
'Uint8Array(400000000)\xA0[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …]',
'Uint16Array(3)\xA0[1, 2, 3]',
'Promise\xA0{<rejected>: -0}',
'Promise\xA0{<fulfilled>: 1}',
'Promise\xA0{<pending>}',
'Symbol()',
'Symbol(a)',
'{a: Symbol(), Symbol(a): 2}',
'Map(1)\xA0{{…} => {…}}',
'WeakMap\xA0{{…} => {…}}',
'Set(1)\xA0{{…}}',
'WeakSet\xA0{{…}}',
'Map(1)\xA0{Map(1) => WeakMap}',
'Map(1)\xA0{Map(0) => WeakMap}',
'Set(1)\xA0{WeakSet}',
'Set(1)\xA0{WeakSet}',
'Map(6)\xA0{\' from str \' => \' to str \', undefined => undefined, null => null, 42 => 42, {…} => {…}, …}',
'genFunction\xA0{<suspended>}',
]);
});
it('shows primitives', async () => {
const messages = await getConsoleMessages('primitives', false, () => waitForConsoleMessagesToBeNonEmpty(15));
assert.deepEqual(messages, [
'null',
'undefined',
'NaN',
'{}',
'[ƒ]',
'Infinity',
'-Infinity',
'Number\xA0{42}',
'String\xA0{\'abc\'}',
'0.12',
'-0',
'test',
'https://chromium.org',
'Number\xA0{42, 1: \'foo\', a: \'bar\'}',
'String\xA0{\'abc\', 3: \'foo\', 01: \'foo\', a: \'bar\'}',
]);
});
it('can handle prototype fields', async () => {
const messages = await getConsoleMessages('prototypes', false, () => waitForConsoleMessagesToBeNonEmpty(13));
assert.deepEqual(messages, [
'{enumerableProp: 4, __underscoreEnumerableProp__: 5, __underscoreNonEnumerableProp: 2, abc: 3, getFoo: ƒ,\xA0…}',
'{longSubNamespace: {…}}',
'namespace.longSubNamespace.x.className\xA0{}',
'{}',
'ArrayLike(5)\xA0[empty × 5]',
'ArrayLike(4294967295)\xA0[empty × 4294967295]',
'ArrayLike\xA0{length: -5}',
'ArrayLike\xA0{length: 5.6}',
'ArrayLike\xA0{length: NaN}',
'ArrayLike\xA0{length: Infinity}',
'ArrayLike\xA0{length: -0}',
'ArrayLike\xA0{length: 4294967296}',
'NonArrayWithLength\xA0{keys: Array(0)}',
]);
});
it('can show DOM interactions', async () => {
const messages = await getConsoleMessages('dom-interactions');
assert.deepEqual(messages, [
'',
'',
'',
'',
'#text',
'HTMLCollection\xA0[select, sel: select]',
'HTMLCollection\xA0[]',
'HTMLOptionsCollection(2)\xA0[option, option, selectedIndex: 0]',
'HTMLAllCollection(12)\xA0[html, head, body, div#first-child.c1.c2.c3, div#p, form, select, option, option, input, input, script, first-child: div#first-child.c1.c2.c3, p: div#p, sel: select, input: HTMLCollection(2)]',
'HTMLFormControlsCollection(3)\xA0[select, input, input, sel: select, input: RadioNodeList(2)]',
'RadioNodeList(2)\xA0[input, input, value: \'\']',
'DOMTokenList(3)\xA0[\'c1\', \'c2\', \'c3\', value: \'c1 c2 c3\']',
'DOMException: Failed to execute \'removeChild\' on \'Node\': The node to be removed is not a child of this node.',
]);
});
it('can handle sourceURLs in exceptions', async () => {
const messages =
await getConsoleMessages('source-url-exceptions', false, () => waitForConsoleMessagesToBeNonEmpty(1));
assert.deepEqual(messages, [
`Uncaught ReferenceError: FAIL is not defined
at foo (foo2.js:1)
at source-url-exceptions.html:9`,
]);
});
it('can handle repeated messages from data URLs in exceptions', async () => {
const messages =
await getConsoleMessages('data-url-exceptions', false, () => waitForConsoleMessagesToBeNonEmpty(1));
assert.deepEqual(messages, [
'msg', // 5 times from eval script, collapsed
'msg', // 5 times from data url script, collapsed
`Uncaught Error: Failed
at fail (data-url-exceptions.html:12)
at foo1 (data:text/javascript…pIHsgZm9vMSgpOyB9:1)
at foo2 (data:text/javascript…pIHsgZm9vMSgpOyB9:2)
at bar1 (data:text/javascript…9IAogYmFyMigpOw==:1)
at bar2 (data:text/javascript…9IAogYmFyMigpOw==:2)
at data:text/javascript…9IAogYmFyMigpOw==:3`,
]);
});
it('can show stackoverflow exceptions', async () => {
const messages = await getConsoleMessages('stack-overflow', false, () => waitForConsoleMessagesToBeNonEmpty(1));
assert.deepEqual(messages, [
`Uncaught RangeError: Maximum call stack size exceeded
at boo (foo2.js:2)
at boo (foo2.js:2)
at boo (foo2.js:2)
at boo (foo2.js:2)
at boo (foo2.js:2)
at boo (foo2.js:2)
at boo (foo2.js:2)
at boo (foo2.js:2)
at boo (foo2.js:2)
at boo (foo2.js:2)`,
]);
});
it('can show document.write messages', async () => {
const messages = await getConsoleMessages('document-write', false, () => waitForConsoleMessagesToBeNonEmpty(2));
assert.deepEqual(messages, [
'script element',
'document.write from onload',
]);
});
it('can show verbose promise unhandledrejections', async () => {
const messages = await getConsoleMessages('onunhandledrejection', false, async () => {
await waitForConsoleMessagesToBeNonEmpty(4);
await showVerboseMessages();
});
assert.deepEqual(messages, [
'onunhandledrejection1',
'onrejectionhandled1',
'onunhandledrejection2',
`Uncaught (in promise) Error: e
at runSecondPromiseRejection (onunhandledrejection.html:23)`,
'onrejectionhandled2',
]);
});
describe('shows messages from before', async () => {
it('iframe removal', async () => {
const messages =
await getConsoleMessages('navigation/after-removal', false, () => waitForConsoleMessagesToBeNonEmpty(3));
assert.deepEqual(messages, [
'A message with first argument string Second argument which should not be discarded',
'2011 \'A message with first argument integer\'',
'Window\xA0{window: Window, self: Window, document: document, name: \'\', location: Location,\xA0…} \'A message with first argument window\'',
]);
});
it('and after iframe navigation', async () => {
const messages =
await getConsoleMessages('navigation/after-navigation', false, () => waitForConsoleMessagesToBeNonEmpty(4));
assert.deepEqual(messages, [
'A message with first argument string Second argument which should not be discarded',
'2011 \'A message with first argument integer\'',
'Window\xA0{window: Window, self: Window, document: document, name: \'\', location: Location,\xA0…} \'A message with first argument window\'',
'After iframe navigation.',
]);
});
});
});