blob: e04293450133595d7e3334e511437e68a1e838cb [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// 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 {step} from '../../shared/helper.js';
import {elementContainsTextWithSelector} from '../helpers/network-helpers.js';
import {openGoToLineQuickOpen} from '../helpers/quick_open-helpers.js';
import {togglePreferenceInSettingsTab} from '../helpers/settings-helpers.js';
import {
addBreakpointForLine,
isPrettyPrinted,
openFileInSourcesPanel,
openSourceCodeEditorForFile,
RESUME_BUTTON,
retrieveCodeMirrorEditorContent,
retrieveTopCallFrameScriptLocation,
waitForHighlightedLine,
} from '../helpers/sources-helpers.js';
const PRETTY_PRINT_BUTTON = '[aria-label="Pretty print"]';
const PRETTY_PRINTED_TOGGLE = 'devtools-text-editor.pretty-printed';
describe('The Sources Tab', function() {
it('can pretty-print a JavaScript file inline', async ({devToolsPage, inspectedPage}) => {
await openSourceCodeEditorForFile(
'minified-sourcecode.js', 'minified-sourcecode.html', devToolsPage, inspectedPage);
await step('can pretty-print successfully', async () => {
await devToolsPage.click(PRETTY_PRINT_BUTTON);
await devToolsPage.waitFor(PRETTY_PRINTED_TOGGLE);
const expectedLines = [
'// Copyright 2020 The Chromium Authors',
'// Use of this source code is governed by a BSD-style license that can be',
'// found in the LICENSE file.',
'// clang-format off',
'const notFormatted = {',
' something: \'not-formatted\'',
'};',
'console.log(\'Test for correct line number\');',
'function notFormattedFunction() {',
' console.log(\'second log\');',
' return {',
' field: 2 + 4',
' }',
'}',
';notFormattedFunction();',
'',
];
const updatedTextContent = await retrieveCodeMirrorEditorContent(devToolsPage);
assert.strictEqual(updatedTextContent.join('\n'), expectedLines.join('\n'));
});
await step('can un-pretty-print successfully', async () => {
await devToolsPage.click(PRETTY_PRINT_BUTTON);
await devToolsPage.waitForNone(PRETTY_PRINTED_TOGGLE);
const expectedLines = [
'// Copyright 2020 The Chromium Authors',
'// Use of this source code is governed by a BSD-style license that can be',
'// found in the LICENSE file.',
'// clang-format off',
'const notFormatted = {something: \'not-formatted\'};console.log(\'Test for correct line number\'); function notFormattedFunction() {',
'console.log(\'second log\'); return {field: 2+4}};',
'notFormattedFunction();',
'',
];
const updatedTextContent = await retrieveCodeMirrorEditorContent(devToolsPage);
assert.strictEqual(updatedTextContent.join('\n'), expectedLines.join('\n'));
});
});
it('can pretty print an inline json subtype file', async ({devToolsPage, inspectedPage}) => {
await openSourceCodeEditorForFile(
'json-subtype-ld.rawresponse', '../network/json-subtype-ld.rawresponse', devToolsPage, inspectedPage);
const editor = await devToolsPage.waitFor('[aria-label="Code editor"]');
await step('can pretty-print a json subtype', async () => {
const expectedPrettyLines = [
'{',
' "Keys": [',
' {',
' "Key1": "Value1",',
' "Key2": "Value2",',
' "Key3": true',
' },',
' {',
' "Key1": "Value1",',
' "Key2": "Value2",',
' "Key3": false',
' }',
' ]',
'}',
];
const actualPrettyText = await retrieveCodeMirrorEditorContent(devToolsPage);
assert.deepEqual(expectedPrettyLines, actualPrettyText);
});
await step('can highlight the pretty-printed text', async () => {
await devToolsPage.waitForFunction(() => isPrettyPrinted(devToolsPage));
assert.isTrue(await elementContainsTextWithSelector(editor, '"Value1"', '.token-string'));
assert.isTrue(await elementContainsTextWithSelector(editor, 'true', '.token-atom'));
});
await step('can un-pretty-print a json subtype file', async () => {
await devToolsPage.click(PRETTY_PRINT_BUTTON);
const expectedNotPrettyLines =
'{"Keys": [{"Key1": "Value1","Key2": "Value2","Key3": true},{"Key1": "Value1","Key2": "Value2","Key3": false}]},';
const actualNotPrettyText = await retrieveCodeMirrorEditorContent(devToolsPage);
assert.strictEqual(expectedNotPrettyLines, actualNotPrettyText.toString());
});
await step('can highlight the un-pretty-printed text', async () => {
await devToolsPage.waitForFunction(async () => !(await isPrettyPrinted(devToolsPage)));
assert.isTrue(await elementContainsTextWithSelector(editor, '"Value1"', '.token-string'));
assert.isTrue(await elementContainsTextWithSelector(editor, 'true', '.token-atom'));
});
});
it('can show error icons for pretty-printed file', async ({devToolsPage, inspectedPage}) => {
await openSourceCodeEditorForFile('minified-errors.js', 'minified-errors.html', devToolsPage, inspectedPage);
await step('shows 3 separate errors when pretty-printed', async () => {
await devToolsPage.click(PRETTY_PRINT_BUTTON);
await devToolsPage.waitFor(PRETTY_PRINTED_TOGGLE);
await devToolsPage.waitForFunction(async () => {
const icons = await devToolsPage.$$('devtools-icon.cm-messageIcon-error');
return icons.length === 3;
});
});
await step('shows 2 separate errors when un-pretty-printed', async () => {
await devToolsPage.click(PRETTY_PRINT_BUTTON);
await devToolsPage.waitForNone(PRETTY_PRINTED_TOGGLE);
await devToolsPage.waitForFunction(async () => {
const icons = await devToolsPage.$$('devtools-icon.cm-messageIcon-error');
return icons.length === 2;
});
});
});
it('can add breakpoint for pretty-printed file', async ({devToolsPage, inspectedPage}) => {
await openSourceCodeEditorForFile(
'minified-sourcecode.js', 'minified-sourcecode.html', devToolsPage, inspectedPage);
await devToolsPage.click(PRETTY_PRINT_BUTTON);
await devToolsPage.waitFor(PRETTY_PRINTED_TOGGLE);
// Set a breakpoint in line 6 of the pretty-printed view (which is the
// line with the label "6" not the 6th line from the top).
await addBreakpointForLine(6, devToolsPage);
const scriptLocation =
await retrieveTopCallFrameScriptLocation('notFormattedFunction();', inspectedPage.page, devToolsPage);
assert.deepEqual(scriptLocation, 'minified-sourcecode.js:6');
});
it('can add breakpoint on minified source and then break correctly on pretty-printed source',
async ({devToolsPage, inspectedPage}) => {
await openSourceCodeEditorForFile(
'minified-sourcecode.js', 'minified-sourcecode.html', devToolsPage, inspectedPage);
await addBreakpointForLine(6, devToolsPage);
await devToolsPage.click(PRETTY_PRINT_BUTTON);
await devToolsPage.waitFor(PRETTY_PRINTED_TOGGLE);
const scriptLocation =
await retrieveTopCallFrameScriptLocation('notFormattedFunction();', inspectedPage.page, devToolsPage);
assert.deepEqual(scriptLocation, 'minified-sourcecode.js:6');
});
it('can go to line in a pretty-printed file', async ({devToolsPage, inspectedPage}) => {
await openSourceCodeEditorForFile(
'minified-sourcecode.js', 'minified-sourcecode.html', devToolsPage, inspectedPage);
await devToolsPage.click(PRETTY_PRINT_BUTTON);
await devToolsPage.waitFor(PRETTY_PRINTED_TOGGLE);
await openGoToLineQuickOpen(devToolsPage);
await devToolsPage.typeText('6');
await devToolsPage.page.keyboard.press('Enter');
await waitForHighlightedLine(6, devToolsPage);
});
it('automatically pretty-prints minified code (by default)', async ({devToolsPage, inspectedPage}) => {
await openSourceCodeEditorForFile(
'minified-sourcecode-1.min.js', 'minified-sourcecode-1.html', devToolsPage, inspectedPage);
const lines = await retrieveCodeMirrorEditorContent(devToolsPage);
assert.lengthOf(lines, 23);
});
it('does not automatically pretty-print minified code (when disabled via settings)',
async ({devToolsPage, inspectedPage}) => {
await togglePreferenceInSettingsTab('Automatically pretty print minified sources', false, devToolsPage);
await openSourceCodeEditorForFile(
'minified-sourcecode-1.min.js', 'minified-sourcecode-1.html', devToolsPage, inspectedPage);
const lines = await retrieveCodeMirrorEditorContent(devToolsPage);
assert.lengthOf(lines, 3);
});
it('does not automatically pretty-print authored code', async ({devToolsPage, inspectedPage}) => {
await openSourceCodeEditorForFile(
'minified-sourcecode-1.js', 'minified-sourcecode-1.html', devToolsPage, inspectedPage);
const lines = await retrieveCodeMirrorEditorContent(devToolsPage);
assert.lengthOf(lines, 2);
});
it('shows execution position and inline variables in large pretty-printed minified code',
async ({devToolsPage, inspectedPage}) => {
await openFileInSourcesPanel('minified-sourcecode-2.html', devToolsPage, inspectedPage);
// Emulate the button click and wait for the script to open in the Sources panel.
const evalPromise = inspectedPage.evaluate('handleClick();');
await devToolsPage.waitFor('[aria-label="minified-sourcecode-2.min.js"][aria-selected="true"]');
// At some point execution position highlights and variable decorations should appear.
const [executionLine, executionToken, variableValues] = await Promise.all([
devToolsPage.waitFor('.cm-executionLine').then(el => el.evaluate(n => n.textContent)),
devToolsPage.waitFor('.cm-executionToken').then(el => el.evaluate(n => n.textContent)),
devToolsPage.waitFor('.cm-variableValues').then(el => el.evaluate(n => n.textContent)),
]);
assert.strictEqual(executionLine, ' debugger ;');
assert.strictEqual(executionToken, 'debugger');
assert.strictEqual(variableValues, 'y = 40999');
await Promise.all([
devToolsPage.click(RESUME_BUTTON),
evalPromise,
]);
});
});