diff --git a/.eslintignore b/.eslintignore index f0fc934fb1e2..8926159d95de 100644 --- a/.eslintignore +++ b/.eslintignore @@ -63,7 +63,6 @@ devtools/client/debugger/bin/ devtools/client/debugger/configs/ devtools/client/debugger/dist/ devtools/client/debugger/images/ -devtools/client/debugger/packages/ devtools/client/debugger/test/mochitest/examples/ devtools/client/debugger/index.html devtools/client/debugger/webpack.config.js @@ -76,6 +75,7 @@ devtools/shared/css/generated/properties-db.js devtools/client/webconsole/test/node/fixtures/stubs/*.js !devtools/client/webconsole/test/node/fixtures/stubs/index.js devtools/client/shared/components/test/node/stubs/reps/*.js +devtools/client/shared/source-map-loader/test/browser/fixtures/*.js # Ignore devtools files testing sourcemaps / code style devtools/client/framework/test/code_* diff --git a/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/if.js b/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/if.js deleted file mode 100644 index 8e80a7db7908..000000000000 --- a/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/if.js +++ /dev/null @@ -1,12 +0,0 @@ -function componentWillReceiveProps(nextProps) { - console.log('start'); - const { selectedSource } = nextProps; - - if ( - nextProps.startPanelSize !== this.props.startPanelSize || - nextProps.endPanelSize !== this.props.endPanelSize - ) { - this.state.editor.codeMirror.setSize(); - } - console.log('done'); -} diff --git a/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/if.out.js b/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/if.out.js deleted file mode 100644 index 9f9707e956d1..000000000000 --- a/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/if.out.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -function componentWillReceiveProps(nextProps) { - console.log('start'); - var selectedSource = nextProps.selectedSource; - - - if (nextProps.startPanelSize !== this.props.startPanelSize || nextProps.endPanelSize !== this.props.endPanelSize) { - this.state.editor.codeMirror.setSize(); - } - console.log('done'); -} - -//# sourceMappingURL=if.out.js.map \ No newline at end of file diff --git a/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/intermingled-sources.js b/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/intermingled-sources.js deleted file mode 100644 index bd1ef86ee44a..000000000000 --- a/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/intermingled-sources.js +++ /dev/null @@ -1,28 +0,0 @@ -"use strict"; - -var decl = function () { - var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() { - return regeneratorRuntime.wrap(function _callee$(_context) { - while (1) { - switch (_context.prev = _context.next) { - case 0: - console.log("2"); - - case 1: - case "end": - return _context.stop(); - } - } - }, _callee, this); - })); - - return function decl() { - return _ref.apply(this, arguments); - }; -}(); - -function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } - -console.log("1"); - -console.log("3"); \ No newline at end of file diff --git a/devtools/client/debugger/packages/devtools-source-map/src/tests/getContentType.js b/devtools/client/debugger/packages/devtools-source-map/src/tests/getContentType.js deleted file mode 100644 index 03b77f032454..000000000000 --- a/devtools/client/debugger/packages/devtools-source-map/src/tests/getContentType.js +++ /dev/null @@ -1,20 +0,0 @@ -/* 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 . */ - -const { getContentType, contentMapForTesting } = require("../utils"); - -describe("getContentType", () => { - for (const ext in contentMapForTesting) { - test(`extension - ${ext}`, () => { - expect(getContentType(`whatever.${ext}`)).toEqual( - contentMapForTesting[ext] - ); - expect(getContentType(`whatever${ext}`)).toEqual("text/plain"); - }); - } - - test("bad extension", () => { - expect(getContentType("whatever.platypus")).toEqual("text/plain"); - }); -}); diff --git a/devtools/client/debugger/packages/devtools-source-map/src/tests/helpers.js b/devtools/client/debugger/packages/devtools-source-map/src/tests/helpers.js deleted file mode 100644 index 309f1019ec09..000000000000 --- a/devtools/client/debugger/packages/devtools-source-map/src/tests/helpers.js +++ /dev/null @@ -1,54 +0,0 @@ -/* 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 . */ - -const { isOriginalId } = require("../utils"); -const { getOriginalURLs } = require("../source-map"); - -const fs = require("fs"); -const path = require("path"); - -function formatLocations(locs) { - return locs.map(formatLocation).join(" -> "); -} - -function formatLocation(loc) { - const label = isOriginalId(loc.sourceId) ? "O" : "G"; - const col = loc.column === undefined ? "u" : loc.column; - return `${label}[${loc.line}, ${col}]`; -} - -function getMap(_path) { - const mapPath = path.join(__dirname, _path); - return fs.readFileSync(mapPath, "utf8"); -} - -async function setupBundleFixtureAndData(name) { - const source = { - id: `${name}.js`, - sourceMapURL: `${name}.js.map`, - sourceMapBaseURL: `http://example.com/${name}.js`, - }; - - require("../utils/network-request").networkRequest.mockImplementationOnce( - () => { - const content = getMap(`fixtures/${name}.js.map`); - return { content }; - } - ); - - return getOriginalURLs(source); -} -async function setupBundleFixture(name) { - const data = await setupBundleFixtureAndData(name); - - return data.map(item => item.url); -} - -module.exports = { - formatLocations, - formatLocation, - setupBundleFixture, - setupBundleFixtureAndData, - getMap, -}; diff --git a/devtools/client/debugger/packages/devtools-source-map/src/tests/locations.js b/devtools/client/debugger/packages/devtools-source-map/src/tests/locations.js deleted file mode 100644 index 059464e46ded..000000000000 --- a/devtools/client/debugger/packages/devtools-source-map/src/tests/locations.js +++ /dev/null @@ -1,146 +0,0 @@ -/* 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 . */ - -jest.mock("../utils/network-request"); -const { - getOriginalLocation, - getGeneratedLocation, - clearSourceMaps, -} = require("../source-map"); - -const { setupBundleFixture } = require("./helpers"); - -describe("getOriginalLocation", () => { - beforeEach(() => { - clearSourceMaps(); - }); - - test("maps a generated location", async () => { - await setupBundleFixture("bundle"); - const location = { - sourceId: "bundle.js", - line: 49, - }; - - const originalLocation = await getOriginalLocation(location); - expect(originalLocation).toEqual({ - column: 0, - line: 3, - sourceId: "bundle.js/originalSource-fe2c41d3535b76c158e39ba4f3ff826a", - sourceUrl: "webpack:///entry.js", - }); - }); - - test("does not map an original location", async () => { - const location = { - column: 0, - line: 3, - sourceId: "bundle.js/originalSource-fe2c41d3535b76c158e39ba4f3ff826a", - sourceUrl: "webpack:///entry.js", - }; - const originalLocation = await getOriginalLocation(location); - expect(originalLocation).toEqual(originalLocation); - }); -}); - -describe("getGeneratedLocation", () => { - beforeEach(() => { - clearSourceMaps(); - }); - - test("maps an original location", async () => { - await setupBundleFixture("bundle"); - const location = { - column: 0, - line: 3, - sourceId: "bundle.js/originalSource-fe2c41d3535b76c158e39ba4f3ff826a", - }; - - const source = { - url: "webpack:///entry.js", - id: "bundle.js/originalSource-fe2c41d3535b76c158e39ba4f3ff826a", - }; - - const generatedLocation = await getGeneratedLocation(location, source); - expect(generatedLocation).toEqual({ - sourceId: "bundle.js", - line: 49, - column: 0, - }); - }); - - test("location mapping is symmetric", async () => { - // we expect symmetric mappings, which means that if - // we map a generated location to an original location, - // and then map it back, we should get the original generated value. - // e.g. G[8, 0] -> O[5, 4] -> G[8, 0] - - await setupBundleFixture("if.out"); - - const genLoc1 = { - sourceId: "if.out.js", - column: 0, - line: 8, - }; - - const ifSource = { - url: "if.js", - id: "if.out.js/originalSource-5ad3141023dae912c5f8833c7e03beeb", - }; - - const oLoc = await getOriginalLocation(genLoc1); - const genLoc2 = await getGeneratedLocation(oLoc, ifSource); - - expect(genLoc2).toEqual({ - sourceId: "if.out.js", - column: 0, - line: 8, - }); - }); - - test("undefined column is handled like 0 column", async () => { - // we expect that an undefined column will be handled like a - // location w/ column 0. e.g. G[8, u] -> O[5, 4] -> G[8, 0] - - await setupBundleFixture("if.out"); - - const genLoc1 = { - sourceId: "if.out.js", - column: undefined, - line: 8, - }; - - const ifSource = { - url: "if.js", - id: "if.out.js/originalSource-5ad3141023dae912c5f8833c7e03beeb", - }; - - const oLoc = await getOriginalLocation(genLoc1); - const genLoc2 = await getGeneratedLocation(oLoc, ifSource); - // console.log(formatLocations([genLoc1, oLoc, genLoc2])); - - expect(genLoc2).toEqual({ - sourceId: "if.out.js", - column: 0, - line: 8, - }); - }); - - test("does not map an original location", async () => { - const location = { - column: 0, - line: 3, - sourceId: "bundle.js/originalSource-fe2c41d3535b76c158e39ba4f3ff826a", - sourceUrl: "webpack:///entry.js", - }; - - const source = { - url: "webpack:///entry.js", - id: "bundle.js/originalSource-fe2c41d3535b76c158e39ba4f3ff826a", - }; - - const generatedLocation = await getGeneratedLocation(location, source); - expect(generatedLocation).toEqual(generatedLocation); - }); -}); diff --git a/devtools/client/debugger/packages/devtools-source-map/src/tests/source-map.js b/devtools/client/debugger/packages/devtools-source-map/src/tests/source-map.js deleted file mode 100644 index 59cfa5b196f7..000000000000 --- a/devtools/client/debugger/packages/devtools-source-map/src/tests/source-map.js +++ /dev/null @@ -1,168 +0,0 @@ -/* 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 . */ - -jest.mock("../utils/network-request"); -const { networkRequest } = require("../utils/network-request"); - -const { - getOriginalURLs, - getOriginalLocation, - getGeneratedRangesForOriginal, - clearSourceMaps, -} = require("../source-map"); - -const { setupBundleFixture, setupBundleFixtureAndData } = require("./helpers"); - -describe("source maps", () => { - beforeEach(() => { - clearSourceMaps(); - }); - describe("getOriginalURLs", () => { - test("absolute URL", async () => { - const urls = await setupBundleFixture("absolute"); - expect(urls).toEqual(["http://example.com/cheese/heart.js"]); - }); - - test("source with a url", async () => { - const urls = await setupBundleFixture("bundle"); - expect(urls).toEqual([ - "webpack:///webpack/bootstrap%204ef8c7ec7c1df790781e", - "webpack:///entry.js", - "webpack:///times2.js", - "webpack:///output.js", - "webpack:///opts.js", - ]); - }); - - test("Empty sourceRoot resolution", async () => { - const urls = await setupBundleFixture("empty"); - expect(urls).toEqual(["http://example.com/heart.js"]); - }); - - test("Non-existing sourceRoot resolution", async () => { - const urls = await setupBundleFixture("noroot"); - expect(urls).toEqual(["http://example.com/heart.js"]); - }); - - test("Non-existing sourceRoot resolution with relative URLs", async () => { - const urls = await setupBundleFixture("noroot2"); - expect(urls).toEqual(["http://example.com/heart.js"]); - }); - }); - - describe("getGeneratedRangesForOriginal", () => { - test("the overall generated ranges on the source", async () => { - const data = await setupBundleFixtureAndData("intermingled-sources"); - - const ranges = await getGeneratedRangesForOriginal(data[0].id); - - expect(ranges).toEqual([ - { - start: { - line: 4, - column: 69, - }, - end: { - line: 9, - column: Infinity, - }, - }, - { - start: { - line: 11, - column: 0, - }, - end: { - line: 17, - column: 3, - }, - }, - { - start: { - line: 19, - column: 18, - }, - end: { - line: 19, - column: 22, - }, - }, - { - start: { - line: 26, - column: 0, - }, - end: { - line: 26, - column: Infinity, - }, - }, - { - start: { - line: 28, - column: 0, - }, - end: { - line: 28, - column: Infinity, - }, - }, - ]); - }); - - test("the merged generated ranges on the source", async () => { - const data = await setupBundleFixtureAndData("intermingled-sources"); - - const ranges = await getGeneratedRangesForOriginal(data[0].id, true); - - expect(ranges).toEqual([ - { - start: { - line: 4, - column: 69, - }, - end: { - line: 28, - column: Infinity, - }, - }, - ]); - }); - }); - - describe("Error handling", () => { - test("missing map", async () => { - const source = { - id: "missingmap.js", - sourceMapURL: "missingmap.js.map", - sourceMapBaseURL: "http:://example.com/missingmap.js", - }; - - networkRequest.mockImplementationOnce(() => { - throw new Error("Not found"); - }); - - let thrown = false; - try { - await getOriginalURLs(source); - } catch (e) { - thrown = true; - } - expect(thrown).toBe(true); - - const location = { - sourceId: "missingmap.js", - line: 49, - }; - - thrown = false; - try { - await getOriginalLocation(location); - } catch (e) { - thrown = true; - } - expect(thrown).toBe(false); - }); - }); -}); diff --git a/devtools/client/debugger/packages/devtools-source-map/src/tests/wasm-source-map.js b/devtools/client/debugger/packages/devtools-source-map/src/tests/wasm-source-map.js deleted file mode 100644 index f79d3420874e..000000000000 --- a/devtools/client/debugger/packages/devtools-source-map/src/tests/wasm-source-map.js +++ /dev/null @@ -1,129 +0,0 @@ -/* 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 . */ - -// Test WasmRemap - -const { WasmRemap } = require("../utils/wasmRemap"); -const { createConsumer } = require("../utils/createConsumer"); - -jest.mock("../utils/network-request"); - -describe("wasm source maps", () => { - test("smoke test", async () => { - const testMap1 = { - version: 3, - file: "min.js", - names: [], - sources: ["one.js", "two.js"], - sourceRoot: "/the/root", - mappings: "CAAC,IAAM,SACU,GAAC", - }; - const testMap1Entries = [ - { offset: 1, line: 1, column: 1 }, - { offset: 5, line: 1, column: 7 }, - { offset: 14, line: 2, column: 17 }, - { offset: 17, line: 2, column: 18 }, - ]; - - const map1 = await createConsumer(testMap1); - const remap1 = new WasmRemap(map1); - - expect(remap1.file).toEqual("min.js"); - expect(remap1.hasContentsOfAllSources()).toEqual(false); - expect(remap1.sources).toHaveLength(2); - expect(remap1.sources[0]).toEqual("/the/root/one.js"); - expect(remap1.sources[1]).toEqual("/the/root/two.js"); - - const expectedEntries = testMap1Entries.slice(0); - remap1.eachMapping(function(entry) { - const expected = expectedEntries.shift(); - expect(entry.generatedLine).toEqual(expected.offset); - expect(entry.generatedColumn).toEqual(0); - expect(entry.originalLine).toEqual(expected.line); - expect(entry.originalColumn).toEqual(expected.column); - expect(entry.name).toEqual(null); - }); - - const pos1 = remap1.originalPositionFor({ line: 5, column: 0 }); - expect(pos1.line).toEqual(1); - expect(pos1.column).toEqual(7); - expect(pos1.source).toEqual("/the/root/one.js"); - - const pos2 = remap1.generatedPositionFor({ - source: "/the/root/one.js", - line: 2, - column: 18, - }); - expect(pos2.line).toEqual(17); - expect(pos2.column).toEqual(0); - expect(pos2.lastColumn).toEqual(undefined); - - remap1.computeColumnSpans(); - const pos3 = remap1.allGeneratedPositionsFor({ - source: "/the/root/one.js", - line: 2, - column: 17, - }); - expect(pos3).toHaveLength(1); - expect(pos3[0].line).toEqual(14); - expect(pos3[0].column).toEqual(0); - expect(pos3[0].lastColumn).toEqual(0); - }); - - test("content presents", async () => { - const testMap2 = { - version: 3, - file: "none.js", - names: [], - sources: ["zero.js"], - mappings: "", - sourcesContent: ["//test"], - }; - - const map2 = await createConsumer(testMap2); - const remap2 = new WasmRemap(map2); - expect(remap2.file).toEqual("none.js"); - expect(remap2.hasContentsOfAllSources()).toEqual(true); - expect(remap2.sourceContentFor("zero.js")).toEqual("//test"); - }); - - test("read and transpose wasm map", async () => { - const source = { - id: "min.js", - sourceMapBaseURL: "wasm:http://example.com/whatever/:min.js", - sourceMapURL: "http://example.com/whatever/min.js.map", - isWasm: true, - }; - - require("../utils/network-request").networkRequest.mockImplementationOnce( - () => { - const content = JSON.stringify({ - version: 3, - file: "min.js", - names: [], - sources: ["one.js"], - mappings: "CAAC,IAAM", - }); - return { content }; - } - ); - - const { getOriginalURLs, getOriginalLocation } = require("../source-map"); - - const urls = await getOriginalURLs(source); - expect(urls).toEqual([ - { - id: "min.js/originalSource-2133f6ef6d6c464acad221082f398cf0", - url: "http://example.com/whatever/one.js", - }, - ]); - - const { line, column } = await getOriginalLocation({ - sourceId: source.id, - line: 5, - }); - expect(line).toEqual(1); - expect(column).toEqual(7); - }); -}); diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-pretty-print-sourcemap.js b/devtools/client/debugger/test/mochitest/browser_dbg-pretty-print-sourcemap.js index 435db0d505b1..e29ed842d67b 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg-pretty-print-sourcemap.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-pretty-print-sourcemap.js @@ -85,6 +85,14 @@ add_task(async () => { const source1 = findSource(dbg, "js1.min.js"); await selectSource(dbg, source1); + // The source may be reported as pretty printable while we are fetching the sourcemap, + // but once the sourcemap is reported to be failing, we no longer report to be pretty printable. + await waitFor( + () => + dbg.selectors.getSourceActorsForSource(source1.id)[0].sourceMapURL === "", + "Wait for the selector source to clear its sourceMapURL" + ); + assertPrettyPrintButton(dbg, L10N.getStr("sourceTabs.prettyPrint"), false); info( @@ -108,7 +116,11 @@ add_task(async () => { }); add_task(async () => { - const dbg = await initDebugger("doc-sourcemaps2.html", "main.min.js"); + const dbg = await initDebugger( + "doc-sourcemaps2.html", + "main.min.js", + "main.js" + ); info( " - Test source with sourceMappingURL, sourcemap and original files exist" diff --git a/devtools/client/shared/source-map-loader/moz.build b/devtools/client/shared/source-map-loader/moz.build index 86f36c57d819..c3cf26b35802 100644 --- a/devtools/client/shared/source-map-loader/moz.build +++ b/devtools/client/shared/source-map-loader/moz.build @@ -14,3 +14,5 @@ DevToolsModules( "source-map.js", "worker.js", ) + +BROWSER_CHROME_MANIFESTS += ["test/browser/browser.ini"] diff --git a/devtools/client/shared/source-map-loader/test/browser/browser.ini b/devtools/client/shared/source-map-loader/test/browser/browser.ini new file mode 100644 index 000000000000..dfe490158c72 --- /dev/null +++ b/devtools/client/shared/source-map-loader/test/browser/browser.ini @@ -0,0 +1,13 @@ +[DEFAULT] +tags = devtools +subsuite = devtools +support-files = + head.js + fixtures/* + !/devtools/client/shared/test/shared-head.js + !/devtools/client/shared/test/telemetry-test-helpers.js + +[browser_getContentType.js] +[browser_locations.js] +[browser_source-map.js] +[browser_wasm-source-map.js] diff --git a/devtools/client/shared/source-map-loader/test/browser/browser_getContentType.js b/devtools/client/shared/source-map-loader/test/browser/browser_getContentType.js new file mode 100644 index 000000000000..5ac402951cd0 --- /dev/null +++ b/devtools/client/shared/source-map-loader/test/browser/browser_getContentType.js @@ -0,0 +1,32 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Cover the automatic mapping of content type based on file extension + +const { + getContentType, + contentMapForTesting, +} = require("resource://devtools/client/shared/source-map-loader/utils/index.js"); + +add_task(async () => { + for (const ext in contentMapForTesting) { + is( + getContentType(`whatever.${ext}`), + contentMapForTesting[ext], + `${ext} file extension is correctly mapping the expected content type` + ); + } + is( + getContentType(`whateverjs`), + "text/plain", + `A valid extension in file name doesn't cause a special content type mapping` + ); + + is( + getContentType("whatever.platypus"), + "text/plain", + "Test unknown extension defaults to text plain" + ); +}); diff --git a/devtools/client/shared/source-map-loader/test/browser/browser_locations.js b/devtools/client/shared/source-map-loader/test/browser/browser_locations.js new file mode 100644 index 000000000000..50727ebd8814 --- /dev/null +++ b/devtools/client/shared/source-map-loader/test/browser/browser_locations.js @@ -0,0 +1,139 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Covert getOriginalLocation and getGeneratedLocation functions. + +add_task(async function testGetOriginalLocation() { + await fetchFixtureSourceMap("bundle"); + + const generatedLocation = { + sourceId: "bundle.js", + line: 49, + }; + + const originalLocation = await getOriginalLocation(generatedLocation); + Assert.deepEqual( + originalLocation, + { + column: 0, + line: 3, + sourceId: "bundle.js/originalSource-fe2c41d3535b76c158e39ba4f3ff826a", + sourceUrl: "webpack:///entry.js", + }, + "Mapped a generated location" + ); + + const originalLocation2 = await getOriginalLocation(originalLocation); + Assert.deepEqual( + originalLocation2, + originalLocation, + "original location maps to itself" + ); + + clearSourceMaps(); + const originalLocation3 = await getOriginalLocation(generatedLocation); + Assert.deepEqual( + originalLocation3, + generatedLocation, + "after clearing the source maps, the same generated location maps to itself" + ); +}); + +add_task(async function testGetGeneratedLocation() { + await fetchFixtureSourceMap("bundle"); + + const originalLocation = { + column: 0, + line: 3, + sourceId: "bundle.js/originalSource-fe2c41d3535b76c158e39ba4f3ff826a", + }; + + const source = { + url: "webpack:///entry.js", + id: "bundle.js/originalSource-fe2c41d3535b76c158e39ba4f3ff826a", + }; + + const generatedLocation = await getGeneratedLocation( + originalLocation, + source + ); + Assert.deepEqual( + generatedLocation, + { + sourceId: "bundle.js", + line: 49, + column: 0, + }, + "Map an original location" + ); + + { + clearSourceMaps(); + + const secondGeneratedLocation = await getGeneratedLocation( + originalLocation, + source + ); + Assert.deepEqual( + secondGeneratedLocation, + originalLocation, + "after clearing source maps, the same location no longer maps to an original location" + ); + } + + { + // we expect symmetric mappings, which means that if + // we map a generated location to an original location, + // and then map it back, we should get the original generated value. + // e.g. G[8, 0] -> O[5, 4] -> G[8, 0] + await fetchFixtureSourceMap("if.out"); + + const genLoc1 = { + sourceId: "if.out.js", + column: 0, + line: 8, + }; + + const ifSource = { + url: "if.js", + id: "if.out.js/originalSource-5ad3141023dae912c5f8833c7e03beeb", + }; + + const oLoc = await getOriginalLocation(genLoc1); + const genLoc2 = await getGeneratedLocation(oLoc, ifSource); + + Assert.deepEqual(genLoc2, genLoc1, "location mapping is symmetric"); + } + + { + // we expect that an undefined column will be handled like a + // location w/ column 0. e.g. G[8, u] -> O[5, 4] -> G[8, 0] + await fetchFixtureSourceMap("if.out"); + + const genLoc1 = { + sourceId: "if.out.js", + column: undefined, + line: 8, + }; + + const ifSource = { + url: "if.js", + id: "if.out.js/originalSource-5ad3141023dae912c5f8833c7e03beeb", + }; + + const oLoc = await getOriginalLocation(genLoc1); + const genLoc2 = await getGeneratedLocation(oLoc, ifSource); + + Assert.deepEqual( + genLoc2, + { + sourceId: "if.out.js", + column: 0, + line: 8, + }, + "undefined column is handled like 0 column" + ); + } +}); diff --git a/devtools/client/shared/source-map-loader/test/browser/browser_source-map.js b/devtools/client/shared/source-map-loader/test/browser/browser_source-map.js new file mode 100644 index 000000000000..f5ed826b36a4 --- /dev/null +++ b/devtools/client/shared/source-map-loader/test/browser/browser_source-map.js @@ -0,0 +1,160 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Cover the high level API of these modules: +// getOriginalURLs getGeneratedRangesForOriginal functions + +async function assertFixtureOriginalURLs( + fixtureName, + expectedUrls, + testMessage +) { + const originalSources = await fetchFixtureSourceMap(fixtureName); + const urls = originalSources.map(s => s.url); + Assert.deepEqual(urls, expectedUrls, testMessage); +} + +add_task(async function testGetOriginalURLs() { + await assertFixtureOriginalURLs( + "absolute", + ["https://example.com/cheese/heart.js"], + "Test absolute URL" + ); + + await assertFixtureOriginalURLs( + "bundle", + [ + "webpack:///webpack/bootstrap%204ef8c7ec7c1df790781e", + "webpack:///entry.js", + "webpack:///times2.js", + "webpack:///output.js", + "webpack:///opts.js", + ], + "Test source with a url" + ); + + await assertFixtureOriginalURLs( + "empty", + [`${URL_ROOT_SSL}fixtures/heart.js`], + "Test empty sourceRoot resolution" + ); + + await assertFixtureOriginalURLs( + "noroot", + [`${URL_ROOT_SSL}fixtures/heart.js`], + "Test Non-existing sourceRoot resolution" + ); + + await assertFixtureOriginalURLs( + "noroot2", + [`${URL_ROOT_SSL}fixtures/heart.js`], + "Test Non-existing sourceRoot resolution with relative URLs" + ); +}); + +add_task(async function testGetGeneratedRangesForOriginal() { + const originals = await fetchFixtureSourceMap("intermingled-sources"); + + const ranges = await getGeneratedRangesForOriginal(originals[0].id); + + Assert.deepEqual( + ranges, + [ + { + start: { + line: 4, + column: 69, + }, + end: { + line: 9, + column: Infinity, + }, + }, + { + start: { + line: 11, + column: 0, + }, + end: { + line: 17, + column: 3, + }, + }, + { + start: { + line: 19, + column: 18, + }, + end: { + line: 19, + column: 22, + }, + }, + { + start: { + line: 26, + column: 0, + }, + end: { + line: 26, + column: Infinity, + }, + }, + { + start: { + line: 28, + column: 0, + }, + end: { + line: 28, + column: Infinity, + }, + }, + ], + "Test the overall generated ranges on the source" + ); + + { + // Note that we have to clear the source map in order to get the merged ranges, + // otherwise we are still fetching the previous unmerged ones! + const secondOriginals = await fetchFixtureSourceMap("intermingled-sources"); + const mergedRanges = await getGeneratedRangesForOriginal( + secondOriginals[0].id, + true + ); + + Assert.deepEqual( + mergedRanges, + [ + { + start: { + line: 4, + column: 69, + }, + end: { + line: 28, + column: Infinity, + }, + }, + ], + "Test the merged generated ranges on the source" + ); + } +}); + +add_task(async function testErrorHandling() { + const source = { + id: "missingmap.js", + sourceMapURL: "missingmap.js.map", + // Notice the duplicated ":" which cause the error here + sourceMapBaseURL: "http:://example.com/missingmap.js", + }; + + await Assert.rejects( + getOriginalURLs(source), + /http::\/\/example.com\/missingmap.js is not a valid URL/, + "Throws on network error" + ); +}); diff --git a/devtools/client/shared/source-map-loader/test/browser/browser_wasm-source-map.js b/devtools/client/shared/source-map-loader/test/browser/browser_wasm-source-map.js new file mode 100644 index 000000000000..22662d91f60a --- /dev/null +++ b/devtools/client/shared/source-map-loader/test/browser/browser_wasm-source-map.js @@ -0,0 +1,125 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test source mappings WASM sources. +// This test is quite general and test various functions. + +const { WasmRemap } = browserRequire( + "resource://devtools/client/shared/source-map-loader/utils/wasmRemap.js" +); +const { createConsumer } = browserRequire( + "resource://devtools/client/shared/source-map-loader/utils/createConsumer.js" +); +const { SourceMapConsumer } = browserRequire( + "resource://devtools/client/shared/vendor/source-map/source-map.js" +); + +SourceMapConsumer.initialize({ + "lib/mappings.wasm": + "resource://devtools/client/shared/vendor/source-map/lib/mappings.wasm", +}); + +add_task(async function smokeTest() { + const testMap1 = { + version: 3, + file: "min.js", + names: [], + sources: ["one.js", "two.js"], + sourceRoot: "/the/root", + mappings: "CAAC,IAAM,SACU,GAAC", + }; + const testMap1Entries = [ + { offset: 1, line: 1, column: 1 }, + { offset: 5, line: 1, column: 7 }, + { offset: 14, line: 2, column: 17 }, + { offset: 17, line: 2, column: 18 }, + ]; + + const map1 = await createConsumer(testMap1); + + const remap1 = new WasmRemap(map1); + + is(remap1.file, "min.js"); + is(remap1.hasContentsOfAllSources(), false); + is(remap1.sources.length, 2); + is(remap1.sources[0], "/the/root/one.js"); + is(remap1.sources[1], "/the/root/two.js"); + + const expectedEntries = testMap1Entries.slice(0); + remap1.eachMapping(function(entry) { + const expected = expectedEntries.shift(); + is(entry.generatedLine, expected.offset); + is(entry.generatedColumn, 0); + is(entry.originalLine, expected.line); + is(entry.originalColumn, expected.column); + is(entry.name, null); + }); + + const pos1 = remap1.originalPositionFor({ line: 5, column: 0 }); + is(pos1.line, 1); + is(pos1.column, 7); + is(pos1.source, "/the/root/one.js"); + + const pos2 = remap1.generatedPositionFor({ + source: "/the/root/one.js", + line: 2, + column: 18, + }); + is(pos2.line, 17); + is(pos2.column, 0); + is(pos2.lastColumn, undefined); + + remap1.computeColumnSpans(); + const pos3 = remap1.allGeneratedPositionsFor({ + source: "/the/root/one.js", + line: 2, + column: 17, + }); + is(pos3.length, 1); + is(pos3[0].line, 14); + is(pos3[0].column, 0); + is(pos3[0].lastColumn, 0); +}); + +add_task(async function contentPresents() { + const testMap2 = { + version: 3, + file: "none.js", + names: [], + sources: ["zero.js"], + mappings: "", + sourcesContent: ["//test"], + }; + + const map2 = await createConsumer(testMap2); + const remap2 = new WasmRemap(map2); + is(remap2.file, "none.js"); + ok(remap2.hasContentsOfAllSources()); + is(remap2.sourceContentFor("zero.js"), "//test"); +}); + +add_task(async function readAndTransposeWasmMap() { + const source = { + id: "wasm.js", + sourceMapBaseURL: "wasm:http://example.com/whatever/:min.js", + sourceMapURL: `${URL_ROOT}fixtures/wasm.js.map`, + isWasm: true, + }; + + const urls = await getOriginalURLs(source); + Assert.deepEqual(urls, [ + { + id: "wasm.js/originalSource-63954a1c231200652c0d99c6a69cd178", + url: `${URL_ROOT}fixtures/one.js`, + }, + ]); + + const { line, column } = await getOriginalLocation({ + sourceId: source.id, + line: 5, + }); + is(line, 1); + is(column, 7); +}); diff --git a/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/absolute.js b/devtools/client/shared/source-map-loader/test/browser/fixtures/absolute.js similarity index 100% rename from devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/absolute.js rename to devtools/client/shared/source-map-loader/test/browser/fixtures/absolute.js diff --git a/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/absolute.js.map b/devtools/client/shared/source-map-loader/test/browser/fixtures/absolute.js.map similarity index 90% rename from devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/absolute.js.map rename to devtools/client/shared/source-map-loader/test/browser/fixtures/absolute.js.map index 4786aabcae30..0597515870db 100644 --- a/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/absolute.js.map +++ b/devtools/client/shared/source-map-loader/test/browser/fixtures/absolute.js.map @@ -6,5 +6,5 @@ "names": [], "mappings": ";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,uBAAe;AACf;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;;;;;;ACtCA;AACA,QAAO,SAAS;AAChB;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;;;;;ACfA;AACA;AACA;;;;;;;ACFA;AACA;AACA;;AAEA,mBAAkB;;;;;;;ACJlB;AACA;AACA", "file": "absolute.js", - "sourceRoot": "http://example.com/cheese/" + "sourceRoot": "https://example.com/cheese/" } diff --git a/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/bundle.js b/devtools/client/shared/source-map-loader/test/browser/fixtures/bundle.js similarity index 100% rename from devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/bundle.js rename to devtools/client/shared/source-map-loader/test/browser/fixtures/bundle.js diff --git a/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/bundle.js.map b/devtools/client/shared/source-map-loader/test/browser/fixtures/bundle.js.map similarity index 100% rename from devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/bundle.js.map rename to devtools/client/shared/source-map-loader/test/browser/fixtures/bundle.js.map diff --git a/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/empty.js b/devtools/client/shared/source-map-loader/test/browser/fixtures/empty.js similarity index 100% rename from devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/empty.js rename to devtools/client/shared/source-map-loader/test/browser/fixtures/empty.js diff --git a/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/empty.js.map b/devtools/client/shared/source-map-loader/test/browser/fixtures/empty.js.map similarity index 100% rename from devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/empty.js.map rename to devtools/client/shared/source-map-loader/test/browser/fixtures/empty.js.map diff --git a/devtools/client/shared/source-map-loader/test/browser/fixtures/if.js b/devtools/client/shared/source-map-loader/test/browser/fixtures/if.js new file mode 100644 index 000000000000..4ee69b19ef4c --- /dev/null +++ b/devtools/client/shared/source-map-loader/test/browser/fixtures/if.js @@ -0,0 +1,12 @@ +function componentWillReceiveProps(nextProps) { + console.log("start"); + const { selectedSource } = nextProps; + + if ( + nextProps.startPanelSize !== this.props.startPanelSize || + nextProps.endPanelSize !== this.props.endPanelSize + ) { + this.state.editor.codeMirror.setSize(); + } + console.log("done"); +} diff --git a/devtools/client/shared/source-map-loader/test/browser/fixtures/if.out.js b/devtools/client/shared/source-map-loader/test/browser/fixtures/if.out.js new file mode 100644 index 000000000000..9bb0752a9204 --- /dev/null +++ b/devtools/client/shared/source-map-loader/test/browser/fixtures/if.out.js @@ -0,0 +1,16 @@ +"use strict"; + +function componentWillReceiveProps(nextProps) { + console.log("start"); + var selectedSource = nextProps.selectedSource; + + if ( + nextProps.startPanelSize !== this.props.startPanelSize || + nextProps.endPanelSize !== this.props.endPanelSize + ) { + this.state.editor.codeMirror.setSize(); + } + console.log("done"); +} + +//# sourceMappingURL=if.out.js.map diff --git a/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/if.out.js.map b/devtools/client/shared/source-map-loader/test/browser/fixtures/if.out.js.map similarity index 100% rename from devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/if.out.js.map rename to devtools/client/shared/source-map-loader/test/browser/fixtures/if.out.js.map diff --git a/devtools/client/shared/source-map-loader/test/browser/fixtures/intermingled-sources.js b/devtools/client/shared/source-map-loader/test/browser/fixtures/intermingled-sources.js new file mode 100644 index 000000000000..c3d9a150bd3b --- /dev/null +++ b/devtools/client/shared/source-map-loader/test/browser/fixtures/intermingled-sources.js @@ -0,0 +1,62 @@ +"use strict"; + +var decl = (function() { + var _ref = _asyncToGenerator( + /*#__PURE__*/ regeneratorRuntime.mark(function _callee() { + return regeneratorRuntime.wrap( + function _callee$(_context) { + while (1) { + switch ((_context.prev = _context.next)) { + case 0: + console.log("2"); + + case 1: + case "end": + return _context.stop(); + } + } + }, + _callee, + this + ); + }) + ); + + return function decl() { + return _ref.apply(this, arguments); + }; +})(); + +function _asyncToGenerator(fn) { + return function() { + var gen = fn.apply(this, arguments); + return new Promise(function(resolve, reject) { + function step(key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error) { + reject(error); + return; + } + if (info.done) { + resolve(value); + } else { + return Promise.resolve(value).then( + function(value) { + step("next", value); + }, + function(err) { + step("throw", err); + } + ); + } + } + return step("next"); + }); + }; +} + +console.log("1"); + +console.log("3"); diff --git a/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/intermingled-sources.js.map b/devtools/client/shared/source-map-loader/test/browser/fixtures/intermingled-sources.js.map similarity index 100% rename from devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/intermingled-sources.js.map rename to devtools/client/shared/source-map-loader/test/browser/fixtures/intermingled-sources.js.map diff --git a/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/missingmap.js b/devtools/client/shared/source-map-loader/test/browser/fixtures/missingmap.js similarity index 100% rename from devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/missingmap.js rename to devtools/client/shared/source-map-loader/test/browser/fixtures/missingmap.js diff --git a/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/noroot.js b/devtools/client/shared/source-map-loader/test/browser/fixtures/noroot.js similarity index 100% rename from devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/noroot.js rename to devtools/client/shared/source-map-loader/test/browser/fixtures/noroot.js diff --git a/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/noroot.js.map b/devtools/client/shared/source-map-loader/test/browser/fixtures/noroot.js.map similarity index 100% rename from devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/noroot.js.map rename to devtools/client/shared/source-map-loader/test/browser/fixtures/noroot.js.map diff --git a/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/noroot2.js b/devtools/client/shared/source-map-loader/test/browser/fixtures/noroot2.js similarity index 100% rename from devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/noroot2.js rename to devtools/client/shared/source-map-loader/test/browser/fixtures/noroot2.js diff --git a/devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/noroot2.js.map b/devtools/client/shared/source-map-loader/test/browser/fixtures/noroot2.js.map similarity index 100% rename from devtools/client/debugger/packages/devtools-source-map/src/tests/fixtures/noroot2.js.map rename to devtools/client/shared/source-map-loader/test/browser/fixtures/noroot2.js.map diff --git a/devtools/client/shared/source-map-loader/test/browser/fixtures/wasm.js.map b/devtools/client/shared/source-map-loader/test/browser/fixtures/wasm.js.map new file mode 100644 index 000000000000..828f6a9aa493 --- /dev/null +++ b/devtools/client/shared/source-map-loader/test/browser/fixtures/wasm.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "file": "wasm.js", + "names": [], + "sources": ["one.js"], + "mappings": "CAAC,IAAM" +} diff --git a/devtools/client/shared/source-map-loader/test/browser/head.js b/devtools/client/shared/source-map-loader/test/browser/head.js new file mode 100644 index 000000000000..48cf853a73db --- /dev/null +++ b/devtools/client/shared/source-map-loader/test/browser/head.js @@ -0,0 +1,48 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/* import-globals-from ../../../../shared/test/shared-head.js */ +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/devtools/client/shared/test/shared-head.js", + this +); + +// source-map has to be loaded via a Browser Loader in order to be able to instantiate +// a web worker and have access to Worker symbol in globals +const { BrowserLoader } = ChromeUtils.import( + "resource://devtools/shared/loader/browser-loader.js" +); +const { require: browserRequire } = BrowserLoader({ + baseURI: "resource://devtools/", + window, +}); +delete window.getBrowserLoaderForWindow; + +const { + startSourceMapWorker, + getOriginalURLs, + getOriginalLocation, + getGeneratedLocation, + getGeneratedRangesForOriginal, + clearSourceMaps, +} = browserRequire( + "resource://devtools/client/shared/source-map-loader/index.js" +); + +startSourceMapWorker( + "resource://devtools/client/shared/source-map-loader/worker.js" +); + +function fetchFixtureSourceMap(name) { + clearSourceMaps(); + + const source = { + id: `${name}.js`, + sourceMapURL: `${name}.js.map`, + sourceMapBaseURL: `${URL_ROOT_SSL}fixtures/${name}.js`, + }; + + return getOriginalURLs(source); +}