зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1757552 - [devtools] Generate actor-less reps stubs.r=bomsy.
This patch is introducing the machinery to automatically generate/check some stubs used by Reps. We're focusing on stubs that shouldn't be represented by a front as it's easier to deal with; we should then have follow up and incremental patches for each stubs. Some data can't be retrieved after being serialized/deserialized (`-0`, unsafe int, …), and in such case the associated test was modified to directly pass the object. Differential Revision: https://phabricator.services.mozilla.com/D139933
This commit is contained in:
Родитель
4b2d62bd4f
Коммит
e954c570c9
|
@ -74,6 +74,7 @@ devtools/client/preferences/
|
|||
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
|
||||
|
||||
# Ignore devtools files testing sourcemaps / code style
|
||||
devtools/client/framework/test/code_*
|
||||
|
|
|
@ -34,4 +34,7 @@ DevToolsModules(
|
|||
)
|
||||
|
||||
MOCHITEST_CHROME_MANIFESTS += ["test/chrome/chrome.ini"]
|
||||
BROWSER_CHROME_MANIFESTS += ["test/browser/browser.ini"]
|
||||
BROWSER_CHROME_MANIFESTS += [
|
||||
"test/browser/browser.ini",
|
||||
"test/node/stubs/reps/stubs.ini",
|
||||
]
|
||||
|
|
|
@ -6,3 +6,4 @@ support-files =
|
|||
!/devtools/client/shared/test/telemetry-test-helpers.js
|
||||
|
||||
[browser_notification_box_basic.js]
|
||||
[browser_reps_stubs.js]
|
||||
|
|
|
@ -0,0 +1,218 @@
|
|||
/* 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
|
||||
);
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf-8,stub generation";
|
||||
/**
|
||||
* A Map keyed by filename, and for which the value is also a Map, with the key being the
|
||||
* label for the stub, and the value the expression to evaluate to get the stub.
|
||||
*/
|
||||
const EXPRESSIONS_BY_FILE = {
|
||||
"infinity.js": new Map([
|
||||
["Infinity", `Infinity`],
|
||||
["NegativeInfinity", `-Infinity`],
|
||||
]),
|
||||
"nan.js": new Map([["NaN", `2 * document`]]),
|
||||
"null.js": new Map([["Null", `null`]]),
|
||||
"number.js": new Map([
|
||||
["Int", `2 + 3`],
|
||||
["True", `true`],
|
||||
["False", `false`],
|
||||
["NegZeroGrip", `1 / -Infinity`],
|
||||
]),
|
||||
"undefined.js": new Map([["Undefined", `undefined`]]),
|
||||
// XXX: File a bug blocking Bug 1671400 for enabling automatic generation for one of
|
||||
// the following file.
|
||||
// "accessible.js",
|
||||
// "accessor.js",
|
||||
// "attribute.js",
|
||||
// "big-int.js",
|
||||
// "comment-node.js",
|
||||
// "date-time.js",
|
||||
// "document-type.js",
|
||||
// "document.js",
|
||||
// "element-node.js",
|
||||
// "error.js",
|
||||
// "event.js",
|
||||
// "failure.js",
|
||||
// "function.js",
|
||||
// "grip-array.js",
|
||||
// "grip-map-entry.js",
|
||||
// "grip-map.js",
|
||||
// "grip.js",
|
||||
// "long-string.js",
|
||||
// "object-with-text.js",
|
||||
// "object-with-url.js",
|
||||
// "promise.js",
|
||||
// "regexp.js",
|
||||
// "stylesheet.js",
|
||||
// "symbol.js",
|
||||
// "text-node.js",
|
||||
// "window.js",
|
||||
};
|
||||
|
||||
add_task(async function() {
|
||||
const isStubsUpdate = env.get(STUBS_UPDATE_ENV) == "true";
|
||||
|
||||
const tab = await addTab(TEST_URI);
|
||||
const {
|
||||
CommandsFactory,
|
||||
} = require("devtools/shared/commands/commands-factory");
|
||||
const commands = await CommandsFactory.forTab(tab);
|
||||
await commands.targetCommand.startListening();
|
||||
|
||||
let failed = false;
|
||||
for (const stubFile of Object.keys(EXPRESSIONS_BY_FILE)) {
|
||||
info(`${isStubsUpdate ? "Update" : "Check"} ${stubFile}`);
|
||||
|
||||
const generatedStubs = await generateStubs(commands, stubFile);
|
||||
if (isStubsUpdate) {
|
||||
await writeStubsToFile(env, stubFile, generatedStubs);
|
||||
ok(true, `${stubFile} was updated`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const existingStubs = getStubFile(stubFile);
|
||||
if (generatedStubs.size !== existingStubs.size) {
|
||||
failed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const [key, packet] of generatedStubs) {
|
||||
const packetStr = getSerializedPacket(packet, { sortKeys: true });
|
||||
const grip = getSerializedPacket(existingStubs.get(key), {
|
||||
sortKeys: true,
|
||||
});
|
||||
is(packetStr, grip, `"${key}" packet has expected value`);
|
||||
failed = failed || packetStr !== grip;
|
||||
}
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
ok(
|
||||
false,
|
||||
"The reps stubs need to be updated by running `" +
|
||||
`mach test ${getCurrentTestFilePath()} --headless --setenv STUBS_UPDATE=true` +
|
||||
"`"
|
||||
);
|
||||
} else {
|
||||
ok(true, "Stubs are up to date");
|
||||
}
|
||||
|
||||
await removeTab(tab);
|
||||
});
|
||||
|
||||
async function generateStubs(commands, stubFile) {
|
||||
const stubs = new Map();
|
||||
|
||||
for (const [key, expression] of EXPRESSIONS_BY_FILE[stubFile]) {
|
||||
const { result } = await commands.scriptCommand.execute(expression);
|
||||
stubs.set(key, getCleanedPacket(key, result));
|
||||
}
|
||||
|
||||
return stubs;
|
||||
}
|
||||
|
||||
function getCleanedPacket(key, packet) {
|
||||
// TODO: Remove / normalize any data that is not stable
|
||||
return packet;
|
||||
}
|
||||
|
||||
// HELPER
|
||||
|
||||
const CHROME_PREFIX = "chrome://mochitests/content/browser/";
|
||||
const STUBS_FOLDER = "devtools/client/shared/components/test/node/stubs/reps/";
|
||||
const STUBS_UPDATE_ENV = "STUBS_UPDATE";
|
||||
|
||||
/**
|
||||
* Write stubs to a given file
|
||||
*
|
||||
* @param {Object} env
|
||||
* @param {String} fileName: The file to write the stubs in.
|
||||
* @param {Map} packets: A Map of the packets.
|
||||
*/
|
||||
async function writeStubsToFile(env, fileName, packets) {
|
||||
const mozRepo = env.get("MOZ_DEVELOPER_REPO_DIR");
|
||||
const filePath = `${mozRepo}/${STUBS_FOLDER + fileName}`;
|
||||
|
||||
const stubs = Array.from(packets.entries()).map(([key, packet]) => {
|
||||
const stringifiedPacket = getSerializedPacket(packet);
|
||||
return `stubs.set(\`${key}\`, ${stringifiedPacket});`;
|
||||
});
|
||||
|
||||
const fileContent = `/* 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";
|
||||
/*
|
||||
* THIS FILE IS AUTOGENERATED. DO NOT MODIFY BY HAND. RUN browser_reps_stubs.js with STUBS_UPDATE=true env TO UPDATE.
|
||||
*/
|
||||
|
||||
const stubs = new Map();
|
||||
${stubs.join("\n\n")}
|
||||
|
||||
module.exports = stubs;
|
||||
`;
|
||||
|
||||
const textEncoder = new TextEncoder();
|
||||
await IOUtils.write(filePath, textEncoder.encode(fileContent));
|
||||
}
|
||||
|
||||
function getStubFile(fileName) {
|
||||
return require(CHROME_PREFIX + STUBS_FOLDER + fileName);
|
||||
}
|
||||
|
||||
function sortObjectKeys(obj) {
|
||||
const isArray = Array.isArray(obj);
|
||||
const isObject = Object.prototype.toString.call(obj) === "[object Object]";
|
||||
const isFront = obj?._grip;
|
||||
|
||||
if (isObject && !isFront) {
|
||||
// Reorder keys for objects, but skip fronts to avoid infinite recursion.
|
||||
const sortedKeys = Object.keys(obj).sort((k1, k2) => k1.localeCompare(k2));
|
||||
const withSortedKeys = {};
|
||||
sortedKeys.forEach(k => {
|
||||
withSortedKeys[k] = k !== "stacktrace" ? sortObjectKeys(obj[k]) : obj[k];
|
||||
});
|
||||
return withSortedKeys;
|
||||
} else if (isArray) {
|
||||
return obj.map(item => sortObjectKeys(item));
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} packet
|
||||
* The packet to serialize.
|
||||
* @param {Object}
|
||||
* - {Boolean} sortKeys: pass true to sort all keys alphabetically in the
|
||||
* packet before serialization. For instance stub comparison should not
|
||||
* fail if the order of properties changed.
|
||||
*/
|
||||
function getSerializedPacket(packet, { sortKeys = false } = {}) {
|
||||
if (sortKeys) {
|
||||
packet = sortObjectKeys(packet);
|
||||
}
|
||||
|
||||
return JSON.stringify(
|
||||
packet,
|
||||
function(_, value) {
|
||||
// The message can have fronts that we need to serialize
|
||||
if (value && value._grip) {
|
||||
return { _grip: value._grip, actorID: value.actorID };
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
2
|
||||
);
|
||||
}
|
|
@ -67,7 +67,7 @@ describe("Boolean", () => {
|
|||
|
||||
describe("Negative Zero", () => {
|
||||
const stubNegativeZeroGrip = stubs.get("NegZeroGrip");
|
||||
const stubNegativeZeroValue = stubs.get("NegZeroValue");
|
||||
const stubNegativeZeroValue = -0;
|
||||
|
||||
it("correctly selects Number Rep for negative zero grip", () => {
|
||||
expect(getRep(stubNegativeZeroGrip)).toBe(Number.rep);
|
||||
|
@ -121,12 +121,11 @@ describe("Zero", () => {
|
|||
});
|
||||
|
||||
describe("Unsafe Int", () => {
|
||||
const stub = stubs.get("UnsafeInt");
|
||||
|
||||
it("renders with expected test content for a long number", () => {
|
||||
const renderedComponent = shallow(
|
||||
Rep({
|
||||
object: stub,
|
||||
// eslint-disable-next-line no-loss-of-precision
|
||||
object: 900719925474099122,
|
||||
shouldRenderTooltip: true,
|
||||
})
|
||||
);
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// This file is a fake test so we can have support files in the stubs.ini, which are then
|
||||
// referenced as support files in the webconsole mochitest ini file.
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(function() {
|
||||
ok(true, "this is not a test");
|
||||
});
|
|
@ -3,12 +3,16 @@
|
|||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
"use strict";
|
||||
/*
|
||||
* THIS FILE IS AUTOGENERATED. DO NOT MODIFY BY HAND. RUN browser_reps_stubs.js with STUBS_UPDATE=true env TO UPDATE.
|
||||
*/
|
||||
|
||||
const stubs = new Map();
|
||||
stubs.set("Infinity", {
|
||||
stubs.set(`Infinity`, {
|
||||
type: "Infinity",
|
||||
});
|
||||
stubs.set("NegativeInfinity", {
|
||||
|
||||
stubs.set(`NegativeInfinity`, {
|
||||
type: "-Infinity",
|
||||
});
|
||||
|
||||
|
|
|
@ -3,9 +3,12 @@
|
|||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
"use strict";
|
||||
/*
|
||||
* THIS FILE IS AUTOGENERATED. DO NOT MODIFY BY HAND. RUN browser_reps_stubs.js with STUBS_UPDATE=true env TO UPDATE.
|
||||
*/
|
||||
|
||||
const stubs = new Map();
|
||||
stubs.set("NaN", {
|
||||
stubs.set(`NaN`, {
|
||||
type: "NaN",
|
||||
});
|
||||
|
||||
|
|
|
@ -3,9 +3,12 @@
|
|||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
"use strict";
|
||||
/*
|
||||
* THIS FILE IS AUTOGENERATED. DO NOT MODIFY BY HAND. RUN browser_reps_stubs.js with STUBS_UPDATE=true env TO UPDATE.
|
||||
*/
|
||||
|
||||
const stubs = new Map();
|
||||
stubs.set("Null", {
|
||||
stubs.set(`Null`, {
|
||||
type: "null",
|
||||
});
|
||||
|
||||
|
|
|
@ -3,16 +3,19 @@
|
|||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
"use strict";
|
||||
/*
|
||||
* THIS FILE IS AUTOGENERATED. DO NOT MODIFY BY HAND. RUN browser_reps_stubs.js with STUBS_UPDATE=true env TO UPDATE.
|
||||
*/
|
||||
|
||||
const stubs = new Map();
|
||||
stubs.set("Int", 5);
|
||||
stubs.set("True", true);
|
||||
stubs.set("False", false);
|
||||
stubs.set("NegZeroValue", -0);
|
||||
stubs.set("NegZeroGrip", {
|
||||
stubs.set(`Int`, 5);
|
||||
|
||||
stubs.set(`True`, true);
|
||||
|
||||
stubs.set(`False`, false);
|
||||
|
||||
stubs.set(`NegZeroGrip`, {
|
||||
type: "-0",
|
||||
});
|
||||
// eslint-disable-next-line no-loss-of-precision
|
||||
stubs.set("UnsafeInt", 900719925474099122);
|
||||
|
||||
module.exports = stubs;
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
[DEFAULT]
|
||||
tags = devtools
|
||||
subsuite = devtools
|
||||
support-files =
|
||||
infinity.js
|
||||
nan.js
|
||||
null.js
|
||||
number.js
|
||||
undefined.js
|
||||
|
||||
[browser_dummy.js]
|
||||
skip-if=true #This is only here so we can expose the support files in other ini files.
|
|
@ -3,9 +3,12 @@
|
|||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
"use strict";
|
||||
/*
|
||||
* THIS FILE IS AUTOGENERATED. DO NOT MODIFY BY HAND. RUN browser_reps_stubs.js with STUBS_UPDATE=true env TO UPDATE.
|
||||
*/
|
||||
|
||||
const stubs = new Map();
|
||||
stubs.set("Undefined", {
|
||||
stubs.set(`Undefined`, {
|
||||
type: "undefined",
|
||||
});
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче