Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Errors

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
// Tests pretty-printing of HTML file and its inner scripts.
"use strict";
const TEST_FILENAME = `doc-pretty-print-inline-scripts.html`;
const PRETTY_PRINTED_FILENAME = `${TEST_FILENAME}:formatted`;
const BREAKABLE_LINE_HINT_CHAR = `➤`;
// Import helpers for the inspector
Services.scriptloader.loadSubScript(
this
);
add_task(async function () {
const dbg = await initDebugger(TEST_FILENAME);
await selectSource(dbg, TEST_FILENAME);
clickElement(dbg, "prettyPrintButton");
await waitForSelectedSource(dbg, PRETTY_PRINTED_FILENAME);
const prettyPrintedSource = findSourceContent(dbg, PRETTY_PRINTED_FILENAME);
ok(prettyPrintedSource, "Pretty-printed source exists");
info("Check that the HTML file was pretty-printed as expected");
const expectedPrettyHtml = getExpectedPrettyPrintedHtml();
is(
prettyPrintedSource.value,
// ➤ is used to indicate breakable lines, we remove them to assert the actual
// content of the editor.
expectedPrettyHtml.replaceAll(BREAKABLE_LINE_HINT_CHAR, ""),
"HTML file is pretty printed as expected"
);
info("Check breakable lines");
const htmlLines = expectedPrettyHtml.split("\n");
const expectedBreakableLines = [];
htmlLines.forEach((line, index) => {
if (line.startsWith(BREAKABLE_LINE_HINT_CHAR)) {
// Lines in the debugger are 1-based
expectedBreakableLines.push(index + 1);
}
});
await assertBreakableLines(
dbg,
PRETTY_PRINTED_FILENAME,
htmlLines.length,
expectedBreakableLines
);
info("Check that console messages are pointing to pretty-printed file");
const { toolbox } = dbg;
await toolbox.selectTool("webconsole");
const { hud } = await dbg.toolbox.getPanel("webconsole");
info("Wait until messages are sourcemapped");
await waitFor(
() => !!findMessageByType(hud, PRETTY_PRINTED_FILENAME, ".log")
);
const firstMessage = await waitFor(() =>
findMessageByType(hud, "User information", ".log")
);
const firstMessageLink = firstMessage.querySelector(".frame-link-source");
is(
firstMessageLink.innerText,
`${PRETTY_PRINTED_FILENAME}:18:8`,
"first console message has expected location"
);
info(
"Click on the link of the first message to open the file in the debugger"
);
firstMessageLink.click();
await waitForSelectedSource(dbg, PRETTY_PRINTED_FILENAME);
ok(true, "pretty printed file was selected in debugger…");
await waitForSelectedLocation(dbg, 18);
ok(true, "…at the expected location");
info("Go back to the console to check an other message");
await toolbox.selectTool("webconsole");
const secondMessage = await waitFor(() =>
findMessageByType(hud, "42 yay", ".log")
);
const secondMessageLink = secondMessage.querySelector(".frame-link-source");
is(
secondMessageLink.innerText,
`${PRETTY_PRINTED_FILENAME}:41:12`,
"second console message has expected location"
);
info(
"Click on the link of the second message to open the file in the debugger"
);
secondMessageLink.click();
await waitForSelectedSource(dbg, PRETTY_PRINTED_FILENAME);
ok(true, "pretty printed file was selected in debugger…");
await waitForSelectedLocation(dbg, 41);
ok(true, "…at the expected location");
info("Check that event listener popup is pointing to pretty-printed file");
const inspector = await toolbox.selectTool("inspector");
const nodeFront = await getNodeFront("h1", inspector);
const markupContainer = inspector.markup.getContainer(nodeFront);
const evHolder = markupContainer.elt.querySelector(
".inspector-badge.interactive[data-event]"
);
const eventTooltip = inspector.markup.eventDetailsTooltip;
info("Open event tooltip.");
EventUtils.synthesizeMouseAtCenter(
evHolder,
{},
inspector.markup.doc.defaultView
);
await eventTooltip.once("shown");
ok(true, "event tooltip opened");
// wait for filename to be sourcemapped
await waitFor(() =>
eventTooltip.panel
.querySelector(".event-header")
?.innerText.includes(PRETTY_PRINTED_FILENAME)
);
const header = eventTooltip.panel.querySelector(".event-header");
const headerFilename = header.querySelector(
".event-tooltip-filename"
).innerText;
ok(
headerFilename.endsWith(`${PRETTY_PRINTED_FILENAME}:51`),
`Location in event tooltip is the pretty printed one (${headerFilename})`
);
info(
"Check that clicking on open debugger icon selects the pretty printed file"
);
header.querySelector(".event-tooltip-debugger-icon").click();
await waitForSelectedSource(dbg, PRETTY_PRINTED_FILENAME);
ok(true, "pretty printed file was selected in debugger…");
await waitForSelectedLocation(dbg, 51);
ok(true, "…at the expected location");
});
add_task(async function prettyPrintSingleLineDataUrl() {
const TEST_URL = `data:text/html,<meta charset=utf8><script>{"use strict"; globalThis.foo = function() {}}</script>`;
const PRETTY_PRINTED_URL = `${TEST_URL}:formatted`;
const dbg = await initDebuggerWithAbsoluteURL(TEST_URL);
await selectSource(dbg, TEST_URL);
clickElement(dbg, "prettyPrintButton");
const prettySource = await waitForSource(dbg, PRETTY_PRINTED_URL);
await waitForSelectedSource(dbg, prettySource);
const prettyPrintedSource = findSourceContent(dbg, PRETTY_PRINTED_URL);
ok(prettyPrintedSource, "Pretty-printed source exists");
info("Check that the HTML file was pretty-printed as expected");
const expectedPrettyHtml = `<meta charset=utf8><script>
{
'use strict';
globalThis.foo = function () {
}
}
</script>`;
is(
prettyPrintedSource.value,
expectedPrettyHtml,
"HTML file is pretty printed as expected"
);
});
/**
* Return the expected pretty-printed HTML. Lines starting with ➤ indicate breakable
* lines for easier maintenance.
*
* @returns {String}
*/
function getExpectedPrettyPrintedHtml() {
return `<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Debugger test page</title>
<!-- Added to check we don't handle non js scripts -->
<script id="json-data" type="application/json">
{ "foo": "bar" }
</script>
<!-- the unusual formatting is wanted to check inline scripts pretty printing -->
<script id="inline" type="application/javascript">
➤const userInfo = JSON.parse(document.getElementById('json-data').text);
➤console.log('User information: %o', userInfo);
➤document.addEventListener(
'click',
function onClick(e) {
➤ console.log('in inline script');
// this is
// something
➤ e.target;
➤ }
);
</script>
</head>
<body>
<h1>Minified</h1>
<!-- Checking that having empty inline scripts doesn't throw off pretty printing -->
<script></script>
<!-- Single line "minified" script -->
<script id="minified" type="module">
➤for (const x of [
42
]) {
➤ if (x > 0) {
➤ console.log(x, 'yay')
} else {
➤ console.log(x, 'booh')
}
➤}
</script>
<!-- Multiple line "minified" script, with content on the first line -->
<script>
{
'use strict';
➤ document.querySelector('h1').addEventListener('mousedown', e => {
➤ console.log('mousedown on h1')
➤ })
➤}
</script>
<hr><script>
➤const x = {
a: 1,
b: 2
➤};
</script><hr><!-- multiple scripts on same line --><script>
➤const y = [
1,
2,
3
];
➤y.map(i => i * 2)
</script>
</body>
</html>
`;
}