Bug 1634721 - [devtools] Preserve selected source context (original vs generated), even when stepping through non-source-mapped code. r=devtools-reviewers,bomsy

(Also removing source argument on the action as it is redundant with location.source)

Differential Revision: https://phabricator.services.mozilla.com/D176899
This commit is contained in:
Alexandre Poirot 2023-05-11 12:02:40 +00:00
Родитель 921f58a1f0
Коммит b188edf4f6
23 изменённых файлов: 198 добавлений и 61 удалений

Просмотреть файл

@ -224,6 +224,20 @@ describe("pause", () => {
const store = createStore(client, {}, sourceMapLoaderMock);
const { dispatch, getState } = store;
const originalSource = await dispatch(
actions.newGeneratedSource(makeSource("foo-original"))
);
const originalLocation = createLocation({
source: originalSource,
line: 3,
column: 0,
sourceActor: selectors.getFirstSourceActorForGeneratedSource(
getState(),
originalSource.id
),
});
const generatedSource = await dispatch(
actions.newGeneratedSource(makeSource("foo"))
);
@ -241,19 +255,6 @@ describe("pause", () => {
const { frames } = mockPauseInfo;
client.getFrames = async () => frames;
const originalSource = await dispatch(
actions.newGeneratedSource(makeSource("foo-original"))
);
const originalLocation = createLocation({
source: originalSource,
line: 3,
column: 0,
sourceActor: selectors.getFirstSourceActorForGeneratedSource(
getState(),
originalSource.id
),
});
await dispatch(actions.paused(mockPauseInfo));
expect(selectors.getFrames(getState(), "FakeThread")).toEqual([
{

Просмотреть файл

@ -28,7 +28,7 @@ import {
getSourceByURL,
getPrettySource,
getSelectedLocation,
getSelectedSource,
getShouldSelectOriginalLocation,
canPrettyPrintSource,
getIsCurrentThreadPaused,
getSourceTextContent,
@ -36,11 +36,15 @@ import {
} from "../../selectors";
// This is only used by jest tests (and within this module)
export const setSelectedLocation = (cx, source, location) => ({
export const setSelectedLocation = (
cx,
location,
shouldSelectOriginalLocation
) => ({
type: "SET_SELECTED_LOCATION",
cx,
source,
location,
shouldSelectOriginalLocation,
});
// This is only used by jest tests (and within this module)
@ -143,16 +147,24 @@ export function selectLocation(cx, location, { keepContext = true } = {}) {
// If the currently selected source is original, we will
// automatically map `location` to refer to the original source,
// even if that used to refer only to the generated source.
const selectedSource = getSelectedSource(getState());
if (
keepContext &&
selectedSource &&
selectedSource.isOriginal != isOriginalId(location.sourceId)
) {
// getRelatedMapLocation will just convert to the related generated/original location.
// i.e if the original location is passed, the related generated location will be returned and vice versa.
location = await getRelatedMapLocation(location, thunkArgs);
source = location.source;
let shouldSelectOriginalLocation = getShouldSelectOriginalLocation(
getState()
);
if (keepContext) {
if (shouldSelectOriginalLocation != isOriginalId(location.sourceId)) {
// getRelatedMapLocation will convert to the related generated/original location.
// i.e if the original location is passed, the related generated location will be returned and vice versa.
location = await getRelatedMapLocation(location, thunkArgs);
// Note that getRelatedMapLocation may return the exact same location.
// For example, if the source-map is half broken, it may return a generated location
// while we were selecting original locations. So we may be seeing bundles intermittently
// when stepping through broken source maps. And we will see original sources when stepping
// through functional original sources.
source = location.source;
}
} else {
shouldSelectOriginalLocation = isOriginalId(location.sourceId);
}
let sourceActor = location.sourceActor;
@ -168,7 +180,7 @@ export function selectLocation(cx, location, { keepContext = true } = {}) {
dispatch(addTab(source, sourceActor));
}
dispatch(setSelectedLocation(cx, source, location));
dispatch(setSelectedLocation(cx, location, shouldSelectOriginalLocation));
await dispatch(loadSourceText(cx, source, sourceActor));

Просмотреть файл

@ -83,6 +83,7 @@ describe("sources - new sources", () => {
},
],
getOriginalLocations: async items => items,
getOriginalLocation: location => location,
}
);
@ -104,6 +105,7 @@ describe("sources - new sources", () => {
{
getOriginalURLs,
getOriginalLocations: async items => items,
getOriginalLocation: location => location,
}
);
@ -119,6 +121,7 @@ describe("sources - new sources", () => {
{
getOriginalURLs: async () => new Promise(_ => {}),
getOriginalLocations: async items => items,
getOriginalLocation: location => location,
}
);
await dispatch(

Просмотреть файл

@ -105,7 +105,7 @@ describe("sources", () => {
it("should open a tab for the source", async () => {
const { dispatch, getState, cx } = createStore(mockCommandClient);
await dispatch(actions.newGeneratedSource(makeSource("foo.js")));
dispatch(actions.selectLocation(cx, initialLocation("foo.js")));
await dispatch(actions.selectLocation(cx, initialLocation("foo.js")));
const tabs = getSourceTabs(getState());
expect(tabs).toHaveLength(1);
@ -181,7 +181,7 @@ describe("sources", () => {
const location = createLocation({ source });
// set value
dispatch(actions.setSelectedLocation(cx, source, location));
dispatch(actions.setSelectedLocation(cx, location));
expect(getSelectedLocation(getState())).toEqual({
sourceId: source.id,
...location,

Просмотреть файл

@ -96,6 +96,16 @@ export function initialSourcesState(state) {
* See `createLocation` for the definition of this object.
*/
selectedLocation: undefined,
/**
* By default, if we have a source-mapped source, we would automatically try
* to select and show the content of the original source. But, if we explicitly
* select a generated source, we remember this choice. That, until we explicitly
* select an original source.
* Note that selections related to non-source-mapped sources should never
* change this setting.
*/
shouldSelectOriginalLocation: true,
};
/* eslint-disable sort-keys */
}
@ -114,7 +124,7 @@ function update(state = initialSourcesState(), action) {
case "SET_SELECTED_LOCATION": {
let pendingSelectedLocation = null;
if (action.source.url) {
if (action.location.source.url) {
pendingSelectedLocation = createPendingSelectedLocation(
action.location
);
@ -125,6 +135,7 @@ function update(state = initialSourcesState(), action) {
...state,
selectedLocation: action.location,
pendingSelectedLocation,
shouldSelectOriginalLocation: action.shouldSelectOriginalLocation,
};
}

Просмотреть файл

@ -132,6 +132,10 @@ export function getSelectedSourceId(state) {
return source?.id;
}
export function getShouldSelectOriginalLocation(state) {
return state.sources.shouldSelectOriginalLocation;
}
/**
* Gets the first source actor for the source and/or thread
* provided.
@ -150,6 +154,10 @@ export function getFirstSourceActorForGeneratedSource(
threadId
) {
let source = getSource(state, sourceId);
// The source may have been removed if we are being called by async code
if (!source) {
return null;
}
if (source.isOriginal) {
source = getSource(state, originalToGeneratedId(source.id));
}

Просмотреть файл

@ -40,6 +40,8 @@ skip-if = http3 # Bug 1829298
skip-if =
win11_2009 # Bug 1798331
http3 # Bug 1829298
[browser_dbg-features-breakpoints.js]
skip-if = http3 # Bug 1829298
[browser_dbg-features-source-tree.js]
skip-if = http3 # Bug 1829298
[browser_dbg-features-browser-toolbox-source-tree.js]

Просмотреть файл

@ -32,13 +32,14 @@ add_task(async function testBreakableLinesOverReloads() {
// because the sourcemap replaces the content of the original file
// and appends a few lines with a "WEBPACK FOOTER" comment
// All the appended lines are empty lines or comments, so none of them are breakable.
await assertBreakableLines(dbg, "original.js", 13, [
await assertBreakableLines(dbg, "original.js", 15, [
...getRange(1, 3),
...getRange(5, 8),
5,
...getRange(8, 10),
]);
info("Assert breakable lines of the simple first load of script.js");
await assertBreakableLines(dbg, "script.js", 3, [1, 3]);
await assertBreakableLines(dbg, "script.js", 9, [1, 5, 7, 8, 9]);
info("Assert breakable lines of the first iframe page load");
await assertBreakableLines(dbg, "iframe.html", 30, [

Просмотреть файл

@ -11,7 +11,7 @@ const TEST_URL = testServer.urlFor("index.html");
// getTokenFromPosition pauses 0.5s for each line,
// so this test is quite slow to complete
requestLongerTimeout(2);
requestLongerTimeout(4);
/**
* Cover the breakpoints positions/columns:
@ -56,26 +56,32 @@ add_task(async function testBreakableLinesOverReloads() {
// because the sourcemap replaces the content of the original file
// and appends a few lines with a "WEBPACK FOOTER" comment
// All the appended lines are empty lines or comments, so none of them are breakable.
await assertBreakablePositions(dbg, "original.js", 13, [
await assertBreakablePositions(dbg, "original.js", 15, [
{ line: 1, columns: [] },
{ line: 2, columns: [2, 9, 32] },
{ line: 3, columns: [] },
{ line: 5, columns: [] },
{ line: 6, columns: [2, 8] },
{ line: 7, columns: [2, 10] },
{ line: 8, columns: [] },
{ line: 8, columns: [2, 8] },
{ line: 9, columns: [2, 10] },
{ line: 10, columns: [] },
]);
info("Assert breakable lines of the simple first load of script.js");
await assertBreakablePositions(dbg, "script.js", 3, [
await assertBreakablePositions(dbg, "script.js", 9, [
{ line: 1, columns: [0, 8] },
{ line: 3, columns: [] },
{ line: 5, columns: [2, 10] },
{ line: 7, columns: [2, 9] },
{ line: 8, columns: [] },
{ line: 9, columns: [] },
]);
info("Pretty print first load of script.js and assert breakable lines");
await prettyPrint(dbg);
await assertBreakablePositions(dbg, "script.js:formatted", 3, [
await assertBreakablePositions(dbg, "script.js:formatted", 8, [
{ line: 1, columns: [0, 8] },
{ line: 4, columns: [2, 10] },
{ line: 6, columns: [2, 9] },
{ line: 7, columns: [] },
]);
await closeTab(dbg, "script.js:formatted");

Просмотреть файл

@ -0,0 +1,72 @@
/* 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/>. */
"use strict";
/**
* Assert that breakpoints and stepping works in various conditions
*/
const testServer = createVersionizedHttpTestServer(
"examples/sourcemaps-reload-uncompressed"
);
const TEST_URL = testServer.urlFor("index.html");
add_task(
async function testSteppingFromOriginalToGeneratedAndAnotherOriginal() {
const dbg = await initDebuggerWithAbsoluteURL(
TEST_URL,
"index.html",
"script.js",
"original.js"
);
await selectSource(dbg, "original.js");
await addBreakpoint(dbg, "original.js", 8);
assertBreakpointSnippet(dbg, 1, "await nonSourceMappedFunction();");
info("Test pausing on an original source");
invokeInTab("foo");
await waitForPaused(dbg, "original.js");
assertPausedAtSourceAndLine(dbg, findSource(dbg, "original.js").id, 8);
info("Then stepping into a generated source");
await stepIn(dbg);
assertPausedAtSourceAndLine(dbg, findSource(dbg, "script.js").id, 5);
info("Stepping another time within the same generated source");
await stepIn(dbg);
assertPausedAtSourceAndLine(dbg, findSource(dbg, "script.js").id, 7);
info("And finally stepping into another original source");
await stepIn(dbg);
assertPausedAtSourceAndLine(
dbg,
findSource(dbg, "removed-original.js").id,
4
);
info("Walk up the stack backward, until we resume execution");
await stepIn(dbg);
assertPausedAtSourceAndLine(
dbg,
findSource(dbg, "removed-original.js").id,
5
);
await stepIn(dbg);
assertPausedAtSourceAndLine(dbg, findSource(dbg, "script.js").id, 8);
await stepIn(dbg);
assertPausedAtSourceAndLine(dbg, findSource(dbg, "original.js").id, 9);
await stepIn(dbg);
assertPausedAtSourceAndLine(dbg, findSource(dbg, "original.js").id, 10);
// We can't use the `stepIn` helper as this last step will resume
// and the helper is expecting to pause again
await dbg.actions.stepIn(getThreadContext(dbg));
await assertNotPaused(dbg);
}
);

Просмотреть файл

@ -41,7 +41,7 @@ add_task(async function test() {
await stepIn(dbg);
await stepIn(dbg);
// Switch to original source
await dbg.actions.jumpToMappedSelectedLocation(getContext(dbg));
// Note that we are asserting against an original source here,
// See earlier comment about paused in bundle.js
assertPausedAtSourceAndLine(dbg, findSource(dbg, "step-in-test.js").id, 7679);
});

Просмотреть файл

@ -19,13 +19,13 @@ add_task(async function() {
info("Test reloading the debugger");
await reload(dbg, "simple1.js", "simple2.js");
is(countTabs(dbg), 2);
await waitForSelectedSource(dbg, "simple2.js");
is(countTabs(dbg), 2);
info("Test reloading the debuggee a second time");
await reload(dbg, "simple1.js", "simple2.js");
is(countTabs(dbg), 2);
await waitForSelectedSource(dbg, "simple2.js");
is(countTabs(dbg), 2);
});
add_task(async function() {

Просмотреть файл

@ -166,6 +166,7 @@ add_task(async function() {
);
dbg.actions.selectThread(getContext(dbg), iframeThread);
await waitForPausedThread(dbg, iframeThread);
await waitForSelectedSource(dbg, source);
assertPausedAtSourceAndLine(dbg, source.id, 3);
info("Resume the iframe target");

Просмотреть файл

@ -1,2 +1,2 @@
!function(e){var n={};function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:r})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var o in e)t.d(r,o,function(n){return e[n]}.bind(null,o));return r},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="",t(t.s=0)}([function(e,n,t){e.exports=t(1)},function(e,n){window.bar=function(){return new Promise(e=>setTimeout(e,100))},window.foo=async function(){await bar(),console.log("YO")}}]);
!function(e){var n={};function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:r})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var o in e)t.d(r,o,function(n){return e[n]}.bind(null,o));return r},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="",t(t.s=0)}([function(e,n,t){e.exports=t(1)},function(e,n){window.bar=function(){return new Promise(e=>setTimeout(e,100))},window.foo=async function(){await nonSourceMappedFunction(),console.log("YO")}}]);
//# sourceMappingURL=bundle.js.map

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -3,6 +3,8 @@ window.bar = function bar() {
}
window.foo = async function foo() {
await bar();
// This will call a function from script.js, itself calling a function
// from original-with-query.js
await nonSourceMappedFunction();
console.log("YO")
}

Просмотреть файл

@ -1,2 +1,8 @@
console.log("only one breakable line");
// And one non-breakable line
function nonSourceMappedFunction () {
console.log("non source mapped function");
// This will call a function from original-with-query.js
return originalWithQuery();
}

Просмотреть файл

@ -79,7 +79,9 @@ window.bar = function bar() {
};
window.foo = async function foo() {
await bar();
// This will call a function from script.js, itself calling a function
// from original-with-query.js
await nonSourceMappedFunction();
console.log("YO");
};

Просмотреть файл

@ -1 +1 @@
{"version":3,"sources":["webpack:///webpack/bootstrap 6fda1f7ea9ecbc1a2d5b","webpack:///./original.js"],"names":["window","bar","Promise","resolve","setTimeout","foo","console","log"],"mappings":";QAAA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;;QAEA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;;;QAGA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;QACA;QACA;QACA;QACA;QACA,KAAK;QACL;QACA;;QAEA;QACA;QACA;QACA,2BAA2B,0BAA0B,EAAE;QACvD,iCAAiC,eAAe;QAChD;QACA;QACA;;QAEA;QACA,sDAAsD,+DAA+D;;QAErH;QACA;;QAEA;QACA;;;;;;;;;;;;;;AC7DAA,OAAOC,GAAP,GAAa,SAASA,GAAT,GAAe;AAC1B,SAAO,IAAIC,OAAJ,CAAYC,WAAWC,WAAWD,OAAX,EAAoB,GAApB,CAAvB,CAAP;AACD,CAFD;;AAIAH,OAAOK,GAAP,GAAa,eAAeA,GAAf,GAAqB;AAChC,QAAMJ,KAAN;AACAK,UAAQC,GAAR,CAAY,IAAZ;AACD,CAHD,C","file":"bundle.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 6fda1f7ea9ecbc1a2d5b","window.bar = function bar() {\n return new Promise(resolve => setTimeout(resolve, 100))\n}\n\nwindow.foo = async function foo() {\n await bar();\n console.log(\"YO\")\n}\n\n\n\n// WEBPACK FOOTER //\n// ./original.js"],"sourceRoot":""}
{"version":3,"sources":["webpack:///webpack/bootstrap d343aa81956b90d9f67e","webpack:///./original.js"],"names":["window","bar","Promise","resolve","setTimeout","foo","nonSourceMappedFunction","console","log"],"mappings":";QAAA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;;QAEA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;;;QAGA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;QACA;QACA;QACA;QACA;QACA,KAAK;QACL;QACA;;QAEA;QACA;QACA;QACA,2BAA2B,0BAA0B,EAAE;QACvD,iCAAiC,eAAe;QAChD;QACA;QACA;;QAEA;QACA,sDAAsD,+DAA+D;;QAErH;QACA;;QAEA;QACA;;;;;;;;;;;;;;AC7DAA,OAAOC,GAAP,GAAa,SAASA,GAAT,GAAe;AAC1B,SAAO,IAAIC,OAAJ,CAAYC,WAAWC,WAAWD,OAAX,EAAoB,GAApB,CAAvB,CAAP;AACD,CAFD;;AAIAH,OAAOK,GAAP,GAAa,eAAeA,GAAf,GAAqB;AAChC;AACA;AACA,QAAMC,yBAAN;AACAC,UAAQC,GAAR,CAAY,IAAZ;AACD,CALD,C","file":"bundle.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap d343aa81956b90d9f67e","window.bar = function bar() {\n return new Promise(resolve => setTimeout(resolve, 100))\n}\n\nwindow.foo = async function foo() {\n // This will call a function from script.js, itself calling a function\n // from original-with-query.js\n await nonSourceMappedFunction();\n console.log(\"YO\")\n}\n\n\n\n// WEBPACK FOOTER //\n// ./original.js"],"sourceRoot":""}

Просмотреть файл

@ -3,6 +3,8 @@ window.bar = function bar() {
}
window.foo = async function foo() {
await bar();
// This will call a function from script.js, itself calling a function
// from original-with-query.js
await nonSourceMappedFunction();
console.log("YO")
}

Просмотреть файл

@ -1,2 +1,8 @@
console.log("only one breakable line");
// And one non-breakable line
function nonSourceMappedFunction () {
console.log("non source mapped function");
// This will call a function from removed-original.js
return removedOriginal();
}

Просмотреть файл

@ -121,7 +121,7 @@ const INTEGRATION_TEST_PAGE_SOURCES = [
// Webpack generated some extra sources:
"bootstrap 3b1a221408fdde86aa49",
"bootstrap a1ecee2f86e1d0ea3fb5",
"bootstrap 6fda1f7ea9ecbc1a2d5b",
"bootstrap d343aa81956b90d9f67e",
// There is 3 occurences, one per target (main thread, worker and iframe).
// But there is even more source actors (named evals and duplicated script tags).
"same-url.sjs",

Просмотреть файл

@ -28,7 +28,7 @@ addIntegrationTask(async function testReloadingStableOriginalSource(
info("Add initial breakpoint");
await selectSource(dbg, "original.js");
await addBreakpoint(dbg, "original.js", 6);
await addBreakpoint(dbg, "original.js", 8);
info("Check that only one breakpoint is set");
is(dbg.selectors.getBreakpointCount(), 1, "Only one breakpoint exists");
@ -40,22 +40,24 @@ addIntegrationTask(async function testReloadingStableOriginalSource(
info("Check that the breakpoint location info is correct");
let breakpoint = dbg.selectors.getBreakpointsList(dbg)[0];
is(breakpoint.location.line, 6);
is(breakpoint.location.line, 8);
if (isCompressed) {
is(breakpoint.generatedLocation.line, 1);
is(breakpoint.generatedLocation.column, 1056);
} else {
is(breakpoint.generatedLocation.line, 82);
is(breakpoint.generatedLocation.line, 84);
}
const expectedOriginalFileContentOnBreakpointLine = "await bar();";
const expectedGeneratedFileContentOnBreakpointLine = "await bar();";
const expectedOriginalFileContentOnBreakpointLine =
"await nonSourceMappedFunction();";
const expectedGeneratedFileContentOnBreakpointLine =
"await nonSourceMappedFunction();";
info("Check that the breakpoint is displayed on the correct line in the ui");
await assertBreakpoint(dbg, 6);
await assertBreakpoint(dbg, 8);
info("Check that breakpoint is on the first line within the function `foo`");
assertTextContentOnLine(dbg, 6, expectedOriginalFileContentOnBreakpointLine);
assertTextContentOnLine(dbg, 8, expectedOriginalFileContentOnBreakpointLine);
info(
"Check that the breakpoint is displayed in correct location in bundle.js (generated source)"
@ -64,10 +66,10 @@ addIntegrationTask(async function testReloadingStableOriginalSource(
if (isCompressed) {
await assertBreakpoint(dbg, 1);
} else {
await assertBreakpoint(dbg, 82);
await assertBreakpoint(dbg, 84);
assertTextContentOnLine(
dbg,
82,
84,
expectedGeneratedFileContentOnBreakpointLine
);
}