Bug 1579090 - Support ObjectFronts in WebConsole. r=Honza.

Since we may now have ObjectFronts in console messages as
well as in evaluation results, we need to make the webconsole
consume those fronts.

And because we have ObjectFronts, we can now avoid using the
DebuggerClient to release the actors, and simply call front.release.
This simplifies how we track created object, since we only need
to release "root" objects, which will also cause all the sub-fronts
to be released as well. Sadly, this was causing some test failures
in mochitests because some objects were released while the connection
was closed, so we now emit an event when all the actors are released,
which we track in tests to wait until everything is over.

As a side effect, we need to change how we handle stubs for
our tests, since fronts have cycical references and can't
be serialized directly. In order to handle that, we serialize
all front as a plain object with a `_grip` property, containing
the object grip. In the stub file, we don't expose the grips
directly, but Maps that contain those stubs "rehydrated": when
a _grip object is encountered, it's turned back into a front.

Differential Revision: https://phabricator.services.mozilla.com/D54509

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Nicolas Chevobbe 2019-12-04 09:03:53 +00:00
parent 5359a3b7e8
commit b4b0150837
30 changed files with 1060 additions and 837 deletions

View File

@ -3496,20 +3496,23 @@ Toolbox.prototype = {
},
inspectObjectActor: async function(objectActor, inspectFromAnnotation) {
const objectGrip =
objectActor && objectActor.getGrip ? objectActor.getGrip() : objectActor;
if (
this.currentToolId != "inspector" &&
objectActor.preview &&
objectActor.preview.nodeType === domNodeConstants.ELEMENT_NODE
objectGrip.preview &&
objectGrip.preview.nodeType === domNodeConstants.ELEMENT_NODE
) {
return this.viewElementInInspector(objectActor, inspectFromAnnotation);
return this.viewElementInInspector(objectGrip, inspectFromAnnotation);
}
if (objectActor.class == "Function") {
const { url, line } = objectActor.location;
if (objectGrip.class == "Function") {
const { url, line } = objectGrip.location;
return this.viewSourceInDebugger(url, line);
}
if (objectActor.type !== "null" && objectActor.type !== "undefined") {
if (objectGrip.type !== "null" && objectGrip.type !== "undefined") {
// Open then split console and inspect the object in the variables view,
// when the objectActor doesn't represent an undefined or null value.
if (this.currentToolId != "webconsole") {

View File

@ -119,16 +119,19 @@ function messageGetMatchingElements(id, cssSelectors) {
};
}
function messageGetTableData(id, grip, dataType) {
return async ({ dispatch, client }) => {
function messageGetTableData(id, front, dataType) {
return async ({ dispatch }) => {
const needEntries = ["Map", "WeakMap", "Set", "WeakSet"].includes(dataType);
const enumIndexedPropertiesOnly = getArrayTypeNames().includes(dataType);
const ignoreNonIndexedProperties = getArrayTypeNames().includes(dataType);
const results = await (needEntries
? client.fetchObjectEntries(grip)
: client.fetchObjectProperties(grip, enumIndexedPropertiesOnly));
const iteratorFront = await (needEntries
? front.enumEntries()
: front.enumProperties({
ignoreNonIndexedProperties,
}));
dispatch(messageUpdatePayload(id, results));
const { ownProperties } = await iteratorFront.all();
dispatch(messageUpdatePayload(id, ownProperties));
};
}

View File

@ -140,15 +140,15 @@ function setEditorWidth(width) {
* Dispatches a SHOW_OBJECT_IN_SIDEBAR action, with a grip property corresponding to the
* {actor} parameter in the {messageId} message.
*
* @param {String} actor: Actor id of the object we want to place in the sidebar.
* @param {String} actorID: Actor id of the object we want to place in the sidebar.
* @param {String} messageId: id of the message containing the {actor} parameter.
*/
function showMessageObjectInSidebar(actor, messageId) {
function showMessageObjectInSidebar(actorID, messageId) {
return ({ dispatch, getState }) => {
const { parameters } = getMessage(getState(), messageId);
if (Array.isArray(parameters)) {
for (const parameter of parameters) {
if (parameter.actor === actor) {
if (parameter && parameter.actorID === actorID) {
dispatch(showObjectInSidebar(parameter));
return;
}
@ -157,10 +157,10 @@ function showMessageObjectInSidebar(actor, messageId) {
};
}
function showObjectInSidebar(grip) {
function showObjectInSidebar(front) {
return {
type: SHOW_OBJECT_IN_SIDEBAR,
grip,
front,
};
}

View File

@ -4,8 +4,6 @@
"use strict";
const { ObjectFront } = require("devtools/shared/fronts/object");
class ConsoleCommands {
constructor({ debuggerClient, proxy, threadFront, currentTarget }) {
this.debuggerClient = debuggerClient;
@ -32,44 +30,6 @@ class ConsoleCommands {
return front.evaluateJSAsync(expression, options);
}
createObjectFront(object) {
return new ObjectFront(this.debuggerClient, object);
}
createLongStringFront(object) {
return this.proxy.webConsoleFront.longString(object);
}
releaseActor(actor) {
if (!actor) {
return null;
}
const objFront = this.debuggerClient.getFrontByID(actor);
if (objFront) {
return objFront.release();
}
// In case there's no object front, use the client's release method.
return this.debuggerClient.release(actor).catch(() => {});
}
async fetchObjectProperties(grip, ignoreNonIndexedProperties) {
const client = new ObjectFront(this.currentTarget.client, grip);
const iterator = await client.enumProperties({
ignoreNonIndexedProperties,
});
const { ownProperties } = await iterator.slice(0, iterator.count);
return ownProperties;
}
async fetchObjectEntries(grip) {
const client = new ObjectFront(this.currentTarget.client, grip);
const iterator = await client.enumEntries();
const { ownProperties } = await iterator.slice(0, iterator.count);
return ownProperties;
}
timeWarp(executionPoint) {
return this.threadFront.timeWarp(executionPoint);
}

View File

@ -54,9 +54,18 @@ class ConsoleTable extends Component {
componentWillMount() {
const { id, dispatch, parameters, tableData } = this.props;
const data = tableData || (parameters[0] && parameters[0].ownProperties);
const firstParam = Array.isArray(parameters) && parameters[0];
if (!firstParam) {
return;
}
if (!Array.isArray(parameters) || parameters.length === 0 || data) {
const data =
tableData ||
(firstParam.getGrip
? firstParam.getGrip().ownProperties
: firstParam.ownProperties);
if (data) {
return;
}
@ -125,7 +134,8 @@ class ConsoleTable extends Component {
render() {
const { parameters, tableData } = this.props;
const [valueGrip, headersGrip] = parameters;
const { valueGrip, headersGrip } = getValueAndHeadersGrip(parameters);
const headers =
headersGrip && headersGrip.preview ? headersGrip.preview.items : null;
@ -163,11 +173,30 @@ class ConsoleTable extends Component {
}
}
function getValueAndHeadersGrip(parameters) {
const [valueFront, headersFront] = parameters;
const headersGrip =
headersFront && headersFront.getGrip
? headersFront.getGrip()
: headersFront;
const valueGrip =
valueFront && valueFront.getGrip ? valueFront.getGrip() : valueFront;
return { valueGrip, headersGrip };
}
function getParametersDataType(parameters = null) {
if (!Array.isArray(parameters) || parameters.length === 0) {
return null;
}
return parameters[0].class;
const [firstParam] = parameters;
if (!firstParam || !firstParam.getGrip) {
return null;
}
const grip = firstParam.getGrip();
return grip.class;
}
const INDEX_NAME = "_index";
@ -232,19 +261,23 @@ function getTableItems(data = {}, type, headers = null) {
};
const propertyValue = getDescriptorValue(property);
const propertyValueGrip =
propertyValue && propertyValue.getGrip
? propertyValue.getGrip()
: propertyValue;
if (propertyValue && propertyValue.ownProperties) {
const entries = propertyValue.ownProperties;
if (propertyValueGrip && propertyValueGrip.ownProperties) {
const entries = propertyValueGrip.ownProperties;
for (const [key, entry] of Object.entries(entries)) {
item[key] = getDescriptorValue(entry);
}
} else if (
propertyValue &&
propertyValue.preview &&
propertyValueGrip &&
propertyValueGrip.preview &&
(type === "Map" || type === "WeakMap")
) {
item.key = propertyValue.preview.key;
item[VALUE_NAME] = propertyValue.preview.value;
item.key = propertyValueGrip.preview.key;
item[VALUE_NAME] = propertyValueGrip.preview.value;
} else {
item[VALUE_NAME] = propertyValue;
}
@ -324,9 +357,11 @@ function deprecatedGetTableItems(data = {}, type, headers = null) {
};
const property = data[index] ? data[index].value : undefined;
const propertyGrip =
property && property.getGrip ? property.getGrip() : property;
if (property && property.preview) {
const { preview } = property;
if (propertyGrip && propertyGrip.preview) {
const { preview } = propertyGrip;
const entries = preview.ownProperties || preview.items;
if (entries) {
for (const [key, entry] of Object.entries(entries)) {

View File

@ -72,14 +72,18 @@ function GripMessageBody(props) {
mode,
maybeScrollToBottom,
onCmdCtrlClick: (node, { depth, event, focused, expanded }) => {
const value = objectInspector.utils.node.getValue(node);
if (value) {
dispatch(actions.showObjectInSidebar(value));
const front = objectInspector.utils.node.getFront(node);
if (front) {
dispatch(actions.showObjectInSidebar(front));
}
},
};
if (typeof grip === "string" || (grip && grip.type === "longString")) {
if (
typeof grip === "string" ||
(grip && grip.type === "longString") ||
(grip && grip.getGrip && grip.getGrip().type === "longString")
) {
Object.assign(objectInspectorProps, {
useQuotes,
transformEmptyString: true,

View File

@ -264,7 +264,17 @@ class Message extends Component {
className: "devtools-button",
onClick: () =>
navigator.clipboard.writeText(
JSON.stringify(this.props.message, null, 2)
JSON.stringify(
this.props.message,
function(key, value) {
// The message can hold one or multiple fronts that we need to serialize
if (value && value.getGrip) {
return value.getGrip();
}
return value;
},
2
)
),
},
l10n.getStr(

View File

@ -57,13 +57,17 @@ function EvaluationResult(props) {
typeof message.messageText !== "undefined" &&
message.messageText !== null
) {
if (typeof message.messageText === "string") {
messageBody = message.messageText;
const messageText =
message.messageText && message.messageText.getGrip
? message.messageText.getGrip()
: message.messageText;
if (typeof messageText === "string") {
messageBody = messageText;
} else if (
typeof message.messageText === "object" &&
message.messageText.type === "longString"
typeof messageText === "object" &&
messageText.type === "longString"
) {
messageBody = `${message.messageText.initial}`;
messageBody = `${messageText.initial}`;
}
} else {
messageBody = GripMessageBody({

View File

@ -50,7 +50,7 @@ class SideBar extends Component {
return {
serviceContainer: PropTypes.object,
dispatch: PropTypes.func.isRequired,
grip: PropTypes.object,
front: PropTypes.object,
onResized: PropTypes.func,
};
}
@ -61,8 +61,8 @@ class SideBar extends Component {
}
shouldComponentUpdate(nextProps) {
const { grip } = nextProps;
return grip !== this.props.grip;
const { front } = nextProps;
return front !== this.props.front;
}
onClickSidebarClose() {
@ -70,9 +70,9 @@ class SideBar extends Component {
}
render() {
const { grip, serviceContainer } = this.props;
const { front, serviceContainer } = this.props;
const objectInspector = getObjectInspector(grip, serviceContainer, {
const objectInspector = getObjectInspector(front, serviceContainer, {
autoExpandDepth: 1,
mode: reps.MODE.SHORT,
autoFocusRoot: true,
@ -118,7 +118,7 @@ class SideBar extends Component {
function mapStateToProps(state, props) {
return {
grip: state.ui.gripInSidebar,
front: state.ui.frontInSidebar,
};
}

View File

@ -32,7 +32,7 @@ const actionTypes = {
PERSIST_TOGGLE: "PERSIST_TOGGLE",
PRIVATE_MESSAGES_CLEAR: "PRIVATE_MESSAGES_CLEAR",
REMOVE_NOTIFICATION: "REMOVE_NOTIFICATION",
REMOVED_ACTORS_CLEAR: "REMOVED_ACTORS_CLEAR",
FRONTS_TO_RELEASE_CLEAR: "FRONTS_TO_RELEASE_CLEAR",
REVERSE_SEARCH_INPUT_TOGGLE: "REVERSE_SEARCH_INPUT_TOGGLE",
SELECT_NETWORK_MESSAGE_TAB: "SELECT_NETWORK_MESSAGE_TAB",
SHOW_OBJECT_IN_SIDEBAR: "SHOW_OBJECT_IN_SIDEBAR",

View File

@ -9,7 +9,7 @@ const {
MESSAGES_CLEAR,
PRIVATE_MESSAGES_CLEAR,
MESSAGES_CLEAR_LOGPOINT,
REMOVED_ACTORS_CLEAR,
FRONTS_TO_RELEASE_CLEAR,
} = require("devtools/client/webconsole/constants");
/**
@ -32,13 +32,26 @@ function enableActorReleaser(webConsoleUI) {
MESSAGES_CLEAR_LOGPOINT,
].includes(type)
) {
state.messages.removedActors.forEach(actor =>
webConsoleUI.releaseActor(actor)
);
const promises = [];
state.messages.frontsToRelease.forEach(front => {
// We only release the front if it actually has a release method,
// and if it's not in the sidebar (where we might still need it).
if (
front &&
typeof front.release === "function" &&
(!state.ui.frontInSidebar ||
state.ui.frontInSidebar.actorID !== front.actorID)
) {
promises.push(front.release());
}
});
// Reset `removedActors` in message reducer.
// Emit an event we can listen to to make sure all the fronts were released.
Promise.all(promises).then(() => webConsoleUI.emit("fronts-released"));
// Reset `frontsToRelease` in message reducer.
state = reducer(state, {
type: REMOVED_ACTORS_CLEAR,
type: FRONTS_TO_RELEASE_CLEAR,
});
}

View File

@ -101,10 +101,9 @@ const MessageState = overrides =>
currentGroup: null,
// This group handles "warning groups" (Content Blocking, CORS, CSP, …)
warningGroupsById: new Map(),
// Array of removed actors (i.e. actors logged in removed messages) we keep track of
// in order to properly release them.
// This array is not supposed to be consumed by any UI component.
removedActors: [],
// Array of fronts to release (i.e. fronts logged in removed messages).
// This array *should not* be consumed by any UI component.
frontsToRelease: [],
// Map of the form {messageId : numberOfRepeat}
repeatById: {},
// Map of the form {messageId : networkInformation}
@ -130,7 +129,7 @@ function cloneState(state) {
messagesPayloadById: new Map(state.messagesPayloadById),
groupsById: new Map(state.groupsById),
currentGroup: state.currentGroup,
removedActors: [...state.removedActors],
frontsToRelease: [...state.frontsToRelease],
repeatById: { ...state.repeatById },
networkMessagesUpdateById: { ...state.networkMessagesUpdateById },
removedLogpointIds: new Set(state.removedLogpointIds),
@ -439,8 +438,8 @@ function messages(
return MessageState({
// Store all actors from removed messages. This array is used by
// `releaseActorsEnhancer` to release all of those backend actors.
removedActors: [...state.messagesById.values()].reduce((res, msg) => {
res.push(...getAllActorsInMessage(msg));
frontsToRelease: [...state.messagesById.values()].reduce((res, msg) => {
res.push(...getAllFrontsInMessage(msg));
return res;
}, []),
});
@ -617,10 +616,10 @@ function messages(
};
}
case constants.REMOVED_ACTORS_CLEAR:
case constants.FRONTS_TO_RELEASE_CLEAR:
return {
...state,
removedActors: [],
frontsToRelease: [],
};
case constants.WARNING_GROUPS_TOGGLE:
@ -856,7 +855,7 @@ function removeMessagesFromState(state, removedMessagesIds) {
return state;
}
const removedActors = [];
const frontsToRelease = [];
const visibleMessages = [...state.visibleMessages];
removedMessagesIds.forEach(id => {
const index = visibleMessages.indexOf(id);
@ -864,15 +863,15 @@ function removeMessagesFromState(state, removedMessagesIds) {
visibleMessages.splice(index, 1);
}
removedActors.push(...getAllActorsInMessage(state.messagesById.get(id)));
frontsToRelease.push(...getAllFrontsInMessage(state.messagesById.get(id)));
});
if (state.visibleMessages.length > visibleMessages.length) {
state.visibleMessages = visibleMessages;
}
if (removedActors.length > 0) {
state.removedActors = state.removedActors.concat(removedActors);
if (frontsToRelease.length > 0) {
state.frontsToRelease = state.frontsToRelease.concat(frontsToRelease);
}
const isInRemovedId = id => removedMessagesIds.includes(id);
@ -933,28 +932,31 @@ function removeMessagesFromState(state, removedMessagesIds) {
}
/**
* Get an array of all the actors logged in a specific message.
* Get an array of all the fronts logged in a specific message.
*
* @param {Message} message: The message to get actors from.
* @return {Array} An array containing all the actors logged in a message.
* @return {Array<ObjectFront|LongStringFront>} An array containing all the fronts logged
* in a message.
*/
function getAllActorsInMessage(message) {
function getAllFrontsInMessage(message) {
const { parameters, messageText } = message;
const actors = [];
const fronts = [];
const isFront = p => p && typeof p.release === "function";
if (Array.isArray(parameters)) {
message.parameters.forEach(parameter => {
if (parameter && parameter.actor) {
actors.push(parameter.actor);
if (isFront(parameter)) {
fronts.push(parameter);
}
});
}
if (messageText && messageText.actor) {
actors.push(messageText.actor);
if (isFront(messageText)) {
fronts.push(messageText);
}
return actors;
return fronts;
}
/**
@ -1351,27 +1353,30 @@ function isTextInParameter(text, regex, parameter) {
const matchStr = str =>
regex ? regex.test(str) : str.toLocaleLowerCase().includes(text);
if (parameter && parameter.class && matchStr(parameter.class)) {
const paramGrip =
parameter && parameter.getGrip ? parameter.getGrip() : parameter;
if (paramGrip && paramGrip.class && matchStr(paramGrip.class)) {
return true;
}
const parameterType = typeof parameter;
if (parameterType !== "object" && parameterType !== "undefined") {
const str = parameter + "";
const str = paramGrip + "";
if (matchStr(str)) {
return true;
}
}
const previewItems = getGripPreviewItems(parameter);
const previewItems = getGripPreviewItems(paramGrip);
for (const item of previewItems) {
if (isTextInParameter(text, regex, item)) {
return true;
}
}
if (parameter && parameter.ownProperties) {
for (const [key, desc] of Object.entries(parameter.ownProperties)) {
if (paramGrip && paramGrip.ownProperties) {
for (const [key, desc] of Object.entries(paramGrip.ownProperties)) {
if (matchStr(key)) {
return true;
}
@ -1436,10 +1441,12 @@ function isTextInMessageText(text, regex, messageText) {
: messageText.toLocaleLowerCase().includes(text);
}
if (messageText.type === "longString") {
const grip =
messageText && messageText.getGrip ? messageText.getGrip() : messageText;
if (grip && grip.type === "longString") {
return regex
? regex.test(messageText.initial)
: messageText.initial.toLocaleLowerCase().includes(text);
? regex.test(grip.initial)
: grip.initial.toLocaleLowerCase().includes(text);
}
return true;

View File

@ -33,7 +33,7 @@ const UiState = overrides =>
showContentMessages: false,
sidebarVisible: false,
timestampsVisible: true,
gripInSidebar: null,
frontInSidebar: null,
closeButtonVisible: false,
reverseSearchInputVisible: false,
reverseSearchInitialValue: "",
@ -60,17 +60,17 @@ function ui(state = UiState(), action) {
return {
...state,
sidebarVisible: false,
gripInSidebar: null,
frontInSidebar: null,
};
case INITIALIZE:
return { ...state, initialized: true };
case MESSAGES_CLEAR:
return { ...state, sidebarVisible: false, gripInSidebar: null };
return { ...state, sidebarVisible: false, frontInSidebar: null };
case SHOW_OBJECT_IN_SIDEBAR:
if (action.grip === state.gripInSidebar) {
if (action.front === state.frontInSidebar) {
return state;
}
return { ...state, sidebarVisible: true, gripInSidebar: action.grip };
return { ...state, sidebarVisible: true, frontInSidebar: action.front };
case SPLIT_CONSOLE_CLOSE_BUTTON_TOGGLE:
return { ...state, closeButtonVisible: action.shouldDisplayButton };
case REVERSE_SEARCH_INPUT_TOGGLE:

View File

@ -5,8 +5,6 @@
"use strict";
const { ObjectFront } = require("devtools/shared/fronts/object");
const {
gDevToolsBrowser,
} = require("devtools/client/framework/devtools-browser");
@ -19,9 +17,10 @@ add_task(async function() {
const hud = await BrowserConsoleManager.openBrowserConsoleOrFocus();
const { message, actor } = await obtainObjectWithCPOW(hud);
await testFrontEnd(hud, message);
await testBackEnd(hud, actor);
const { message, objectFront } = await obtainObjectWithCPOW(hud);
await testFrontEnd(message);
await testBackEnd(objectFront);
await clearOutput(hud, true);
});
async function obtainObjectWithCPOW(hud) {
@ -44,7 +43,7 @@ async function obtainObjectWithCPOW(hud) {
info("Obtain the object with CPOW");
const message = await waitFor(() => findMessage(hud, "cpow"));
const result = await hud.ui.evaluateJSAsync("result");
const { actor } = result.result;
const objectFront = result.result;
info("Cleanup");
await hud.ui.evaluateJSAsync("delete globalThis.result;");
@ -52,10 +51,10 @@ async function obtainObjectWithCPOW(hud) {
toolbox.topWindow.close();
await onToolboxDestroyed;
return { message, actor };
return { message, objectFront };
}
async function testFrontEnd(hud, message) {
async function testFrontEnd(message) {
const oi = message.querySelector(".tree");
const node = oi.querySelector(".tree-node");
is(node.textContent, "Object { cpow: CPOW }", "Got an object with a CPOW");
@ -71,26 +70,22 @@ async function testFrontEnd(hud, message) {
is(getObjectInspectorChildrenNodes(cpow).length, 0, "CPOW has no children");
}
async function testBackEnd(hud, actor) {
async function testBackEnd(objectFront) {
// Check that inspecting an object with CPOW doesn't throw in the server.
// This would be done in a mochitest-chrome suite, but that doesn't run in
// e10s, so it's harder to get ahold of a CPOW.
info("Creating an ObjectFront with: " + actor);
const objectFront = new ObjectFront(hud.ui.proxy.client, { actor });
// Before the fix for Bug 1382833, this wouldn't resolve due to a CPOW error
// in the ObjectActor.
const prototypeAndProperties = await objectFront.getPrototypeAndProperties();
// The CPOW is in the "cpow" property.
const cpow = prototypeAndProperties.ownProperties.cpow.value;
const cpowFront = prototypeAndProperties.ownProperties.cpow.value;
is(cpow.class, "CPOW", "The CPOW grip has the right class.");
is(cpowFront.getGrip().class, "CPOW", "The CPOW grip has the right class.");
// Check that various protocol request methods work for the CPOW.
const objClient = new ObjectFront(hud.ui.proxy.client, cpow);
let response = await objClient.getPrototypeAndProperties();
let response = await cpowFront.getPrototypeAndProperties();
is(
Reflect.ownKeys(response.ownProperties).length,
0,
@ -99,7 +94,7 @@ async function testBackEnd(hud, actor) {
is(response.ownSymbols.length, 0, "No symbol property was retrieved.");
is(response.prototype.type, "null", "The prototype is null.");
response = await objClient.enumProperties({ ignoreIndexedProperties: true });
response = await cpowFront.enumProperties({ ignoreIndexedProperties: true });
let slice = await response.slice(0, response.count);
is(
Reflect.ownKeys(slice.ownProperties).length,
@ -107,7 +102,7 @@ async function testBackEnd(hud, actor) {
"No property was retrieved."
);
response = await objClient.enumProperties({});
response = await cpowFront.enumProperties({});
slice = await response.slice(0, response.count);
is(
Reflect.ownKeys(slice.ownProperties).length,
@ -115,20 +110,20 @@ async function testBackEnd(hud, actor) {
"No property was retrieved."
);
response = await objClient.getOwnPropertyNames();
response = await cpowFront.getOwnPropertyNames();
is(response.ownPropertyNames.length, 0, "No property was retrieved.");
response = await objClient.getProperty("x");
response = await cpowFront.getProperty("x");
is(response.descriptor, undefined, "The property does not exist.");
response = await objClient.enumSymbols();
response = await cpowFront.enumSymbols();
slice = await response.slice(0, response.count);
is(slice.ownSymbols.length, 0, "No symbol property was retrieved.");
response = await objClient.getPrototype();
response = await cpowFront.getPrototype();
is(response.prototype.type, "null", "The prototype is null.");
response = await objClient.getDisplayString();
response = await cpowFront.getDisplayString();
is(response.displayString, "<cpow>", "The CPOW stringifies to <cpow>");
}

View File

@ -29,7 +29,10 @@ add_task(async function() {
hud = await BrowserConsoleManager.toggleBrowserConsole();
await testBrowserConsole(hud);
await closeConsole();
// clear and close the browser console.
await clearOutput(hud);
await BrowserConsoleManager.toggleBrowserConsole();
});
async function testMessages(hud) {

View File

@ -7,6 +7,7 @@ const {
STUBS_UPDATE_ENV,
getStubFilePath,
getCleanedPacket,
getSerializedPacket,
writeStubsToFile,
} = require("devtools/client/webconsole/test/browser/stub-generator-helpers");
@ -28,7 +29,6 @@ add_task(async function() {
ok(true, `${STUB_FILE} was updated`);
return;
}
const existingStubs = require(getStubFilePath(STUB_FILE));
const FAILURE_MSG =
"The consoleApi stubs file needs to be updated by running " +
@ -36,19 +36,18 @@ add_task(async function() {
"browser_webconsole_stubs_console_api.js --headless " +
"--setenv WEBCONSOLE_STUBS_UPDATE=true`";
if (generatedStubs.size !== existingStubs.stubPackets.size) {
if (generatedStubs.size !== existingStubs.rawPackets.size) {
ok(false, FAILURE_MSG);
return;
}
let failed = false;
for (const [key, packet] of generatedStubs) {
const packetStr = JSON.stringify(packet, null, 2);
const existingPacketStr = JSON.stringify(
existingStubs.stubPackets.get(key),
null,
2
const packetStr = getSerializedPacket(packet);
const existingPacketStr = getSerializedPacket(
existingStubs.rawPackets.get(key)
);
is(packetStr, existingPacketStr, `"${key}" packet has expected value`);
failed = failed || packetStr !== existingPacketStr;
}
@ -58,6 +57,8 @@ add_task(async function() {
} else {
ok(true, "Stubs are up to date");
}
await closeTabAndToolbox().catch(() => {});
});
async function generateConsoleApiStubs() {
@ -100,7 +101,6 @@ async function generateConsoleApiStubs() {
}
Services.prefs.clearUserPref(PREFS.FILTER.LOG);
await closeTabAndToolbox().catch(() => {});
return stubs;
}

View File

@ -6,6 +6,7 @@
const {
STUBS_UPDATE_ENV,
getCleanedPacket,
getSerializedPacket,
getStubFilePath,
writeStubsToFile,
} = require("devtools/client/webconsole/test/browser/stub-generator-helpers");
@ -35,18 +36,16 @@ add_task(async function() {
"browser_webconsole_stubs_evaluation_result.js --headless " +
"--setenv WEBCONSOLE_STUBS_UPDATE=true`";
if (generatedStubs.size !== existingStubs.stubPackets.size) {
if (generatedStubs.size !== existingStubs.rawPackets.size) {
ok(false, FAILURE_MSG);
return;
}
let failed = false;
for (const [key, packet] of generatedStubs) {
const packetStr = JSON.stringify(packet, null, 2);
const existingPacketStr = JSON.stringify(
existingStubs.stubPackets.get(key),
null,
2
const packetStr = getSerializedPacket(packet);
const existingPacketStr = getSerializedPacket(
existingStubs.rawPackets.get(key)
);
is(packetStr, existingPacketStr, `"${key}" packet has expected value`);
failed = failed || packetStr !== existingPacketStr;
@ -57,6 +56,8 @@ add_task(async function() {
} else {
ok(true, "Stubs are up to date");
}
await closeTabAndToolbox();
});
async function generateEvaluationResultStubs() {
@ -68,7 +69,6 @@ async function generateEvaluationResultStubs() {
stubs.set(key, getCleanedPacket(key, packet));
}
await closeTabAndToolbox();
return stubs;
}

View File

@ -6,6 +6,7 @@
const {
STUBS_UPDATE_ENV,
getCleanedPacket,
getSerializedPacket,
getStubFilePath,
writeStubsToFile,
} = require("devtools/client/webconsole/test/browser/stub-generator-helpers");
@ -36,18 +37,16 @@ add_task(async function() {
"browser_webconsole_stubs_page_error.js --headless " +
"--setenv WEBCONSOLE_STUBS_UPDATE=true`";
if (generatedStubs.size !== existingStubs.stubPackets.size) {
if (generatedStubs.size !== existingStubs.rawPackets.size) {
ok(false, FAILURE_MSG);
return;
}
let failed = false;
for (const [key, packet] of generatedStubs) {
const packetStr = JSON.stringify(packet, null, 2);
const existingPacketStr = JSON.stringify(
existingStubs.stubPackets.get(key),
null,
2
const packetStr = getSerializedPacket(packet);
const existingPacketStr = getSerializedPacket(
existingStubs.rawPackets.get(key)
);
is(packetStr, existingPacketStr, `"${key}" packet has expected value`);
failed = failed || packetStr !== existingPacketStr;
@ -58,6 +57,8 @@ add_task(async function() {
} else {
ok(true, "Stubs are up to date");
}
await closeTabAndToolbox();
});
async function generatePageErrorStubs() {
@ -85,7 +86,6 @@ async function generatePageErrorStubs() {
stubs.set(key, getCleanedPacket(key, packet));
}
await closeTabAndToolbox();
return stubs;
}

View File

@ -125,7 +125,15 @@ function logAllStoreChanges(hud) {
return { id, type, parameters, messageText };
}
);
info("messages : " + JSON.stringify(debugMessages));
info(
"messages : " +
JSON.stringify(debugMessages, function(key, value) {
if (value && value.getGrip) {
return value.getGrip();
}
return value;
})
);
});
}
@ -1578,13 +1586,21 @@ async function waitForLazyRequests(toolbox) {
}
/**
* Clear the console output and when for the "messages-cleared" event to be emitted.
* Clear the console output and wait for eventual object actors to be released.
*
* @param {WebConsole} hud
* @param {Object} An options object with the following properties:
* - {Boolean} keepStorage: true to prevent clearing the messages storage.
*/
async function clearOutput(hud, { keepStorage = false } = {}) {
const onMessagesCleared = hud.ui.once("messages-cleared");
hud.ui.clearOutput(!keepStorage);
await onMessagesCleared;
const { ui } = hud;
const promises = [ui.once("messages-cleared")];
// If there's an object inspector, we need to wait for the actors to be released.
if (ui.outputNode.querySelector(".object-inspector")) {
promises.push(ui.once("fronts-released"));
}
ui.clearOutput(!keepStorage);
await Promise.all(promises);
}

View File

@ -6,17 +6,21 @@
const ChromeUtils = require("ChromeUtils");
const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
const {
getAdHocFrontOrPrimitiveGrip,
} = require("devtools/shared/fronts/object");
const STUBS_FOLDER = "devtools/client/webconsole/test/node/fixtures/stubs/";
const STUBS_UPDATE_ENV = "WEBCONSOLE_STUBS_UPDATE";
const {
stubPackets,
} = require("devtools/client/webconsole/test/node/fixtures/stubs/index.js");
const cachedPackets = {};
// eslint-disable-next-line complexity
function getCleanedPacket(key, packet) {
const {
stubPackets,
} = require("devtools/client/webconsole/test/node/fixtures/stubs/index");
if (Object.keys(cachedPackets).includes(key)) {
return cachedPackets[key];
}
@ -90,17 +94,15 @@ function getCleanedPacket(key, packet) {
const newArgument = Object.assign({}, argument);
const existingArgument = existingPacket.message.arguments[i];
if (existingArgument) {
if (existingArgument && newArgument._grip) {
// Clean actor ids on each message.arguments item.
if (newArgument.actor) {
newArgument.actor = existingArgument.actor;
}
copyExistingActor(newArgument, existingArgument);
// `window`'s properties count can vary from OS to OS, so we
// clean the `ownPropertyLength` property from the grip.
if (newArgument.class === "Window") {
newArgument.ownPropertyLength =
existingArgument.ownPropertyLength;
if (newArgument._grip.class === "Window") {
newArgument._grip.ownPropertyLength =
existingArgument._grip.ownPropertyLength;
}
}
return newArgument;
@ -122,45 +124,58 @@ function getCleanedPacket(key, packet) {
}
}
if (res.result && existingPacket.result) {
if (res.result && res.result._grip && existingPacket.result) {
// Clean actor ids on evaluation result messages.
res.result.actor = existingPacket.result.actor;
if (res.result.preview) {
if (res.result.preview.timestamp) {
copyExistingActor(res.result, existingPacket.result);
if (res.result._grip.preview) {
if (res.result._grip.preview.timestamp) {
// Clean timestamp there too.
res.result.preview.timestamp =
existingPacket.result.preview.timestamp;
res.result._grip.preview.timestamp =
existingPacket.result._grip.preview.timestamp;
}
}
}
if (res.exception && existingPacket.exception) {
// Clean actor ids on exception messages.
if (existingPacket.exception.actor) {
res.exception.actor = existingPacket.exception.actor;
}
copyExistingActor(res.exception, existingPacket.exception);
if (res.exception.preview) {
if (res.exception.preview.timestamp) {
if (
res.exception._grip &&
res.exception._grip.preview &&
existingPacket.exception._grip &&
existingPacket.exception._grip.preview
) {
if (res.exception._grip.preview.timestamp) {
// Clean timestamp there too.
res.exception.preview.timestamp =
existingPacket.exception.preview.timestamp;
res.exception._grip.preview.timestamp =
existingPacket.exception._grip.preview.timestamp;
}
if (
typeof res.exception.preview.message === "object" &&
res.exception.preview.message.type === "longString"
typeof res.exception._grip.preview.message === "object" &&
res.exception._grip.preview.message._grip.type === "longString" &&
typeof existingPacket.exception._grip.preview.message === "object" &&
existingPacket.exception._grip.preview.message._grip.type ===
"longString"
) {
res.exception.preview.message.actor =
existingPacket.exception.preview.message.actor;
copyExistingActor(
res.exception._grip.preview.message,
existingPacket.exception._grip.preview.message
);
}
}
if (
typeof res.exceptionMessage === "object" &&
res.exceptionMessage.type === "longString"
res.exceptionMessage._grip &&
res.exceptionMessage._grip.type === "longString"
) {
res.exceptionMessage.actor = existingPacket.exceptionMessage.actor;
copyExistingActor(
res.exceptionMessage,
existingPacket.exceptionMessage
);
}
}
@ -179,10 +194,13 @@ function getCleanedPacket(key, packet) {
if (
typeof res.pageError.errorMessage === "object" &&
res.pageError.errorMessage.type === "longString"
res.pageError.errorMessage._grip &&
res.pageError.errorMessage._grip.type === "longString"
) {
res.pageError.errorMessage.actor =
existingPacket.pageError.errorMessage.actor;
copyExistingActor(
res.pageError.errorMessage,
existingPacket.pageError.errorMessage
);
}
if (res.pageError.sourceId) {
@ -276,10 +294,10 @@ function getCleanedPacket(key, packet) {
}
if (res.helperResult) {
if (res.helperResult.object) {
res.helperResult.object.actor =
existingPacket.helperResult.object.actor;
}
copyExistingActor(
res.helperResult.object,
existingPacket.helperResult.object
);
}
} else {
res = packet;
@ -289,6 +307,25 @@ function getCleanedPacket(key, packet) {
return res;
}
function copyExistingActor(front1, front2) {
if (!front1 || !front2) {
return;
}
if (front1.actorID && front2.actorID) {
front1.actorID = front2.actorID;
}
if (
front1._grip &&
front2._grip &&
front1._grip.actor &&
front2._grip.actor
) {
front1._grip.actor = front2._grip.actor;
}
}
/**
* Write stubs to a given file
*
@ -298,8 +335,8 @@ function getCleanedPacket(key, packet) {
async function writeStubsToFile(filePath, packets, isNetworkMessage) {
const serializedPackets = Array.from(packets.entries()).map(
([key, packet]) => {
const stringifiedPacket = JSON.stringify(packet, null, 2);
return `stubPackets.set(\`${key}\`, ${stringifiedPacket});`;
const stringifiedPacket = getSerializedPacket(packet);
return `rawPackets.set(\`${key}\`, ${stringifiedPacket});`;
}
);
@ -313,31 +350,32 @@ async function writeStubsToFile(filePath, packets, isNetworkMessage) {
* THIS FILE IS AUTOGENERATED. DO NOT MODIFY BY HAND. RUN TESTS IN FIXTURES/ TO UPDATE.
*/
const {
parsePacketsWithFronts,
} = require("devtools/client/webconsole/test/browser/stub-generator-helpers");
const { prepareMessage } = require("devtools/client/webconsole/utils/messages");
const {
ConsoleMessage,
NetworkEventMessage,
} = require("devtools/client/webconsole/types");
const stubPackets = new Map();
const rawPackets = new Map();
${serializedPackets.join("\n\n")}
const stubPackets = parsePacketsWithFronts(rawPackets);
const stubPreparedMessages = new Map();
for (const [key, packet] of Array.from(stubPackets.entries())) {
const transformedPacket = prepareMessage(${
isNetworkMessage ? "packet.networkInfo || packet" : "packet"
}, {
const transformedPacket = prepareMessage(packet, {
getNextId: () => "1",
});
const message = ${
isNetworkMessage
? "NetworkEventMessage(transformedPacket);"
: "ConsoleMessage(transformedPacket);"
}
const message = ConsoleMessage(transformedPacket);
stubPreparedMessages.set(key, message);
}
module.exports = {
rawPackets,
stubPreparedMessages,
stubPackets,
};
@ -351,9 +389,65 @@ function getStubFilePath(fileName, env, absolute = false) {
return absolute ? `${env.get("MOZ_DEVELOPER_REPO_DIR")}/${path}` : path;
}
function getSerializedPacket(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
);
}
/**
*
* @param {Map} rawPackets
*/
function parsePacketsWithFronts(rawPackets) {
const packets = new Map();
for (const [key, packet] of rawPackets.entries()) {
const newPacket = parsePacketAndCreateFronts(packet);
packets.set(key, newPacket);
}
return packets;
}
function parsePacketAndCreateFronts(packet) {
if (!packet) {
return packet;
}
if (Array.isArray(packet)) {
packet.forEach(parsePacketAndCreateFronts);
}
if (typeof packet === "object") {
for (const [key, value] of Object.entries(packet)) {
if (value && value._grip) {
packet[key] = getAdHocFrontOrPrimitiveGrip(value._grip, {
conn: {
poolFor: () => {},
addActorPool: () => {},
},
manage: () => {},
});
} else {
packet[key] = parsePacketAndCreateFronts(value);
}
}
}
return packet;
}
module.exports = {
STUBS_UPDATE_ENV,
getStubFilePath,
getCleanedPacket,
getSerializedPacket,
parsePacketsWithFronts,
writeStubsToFile,
};

View File

@ -8,52 +8,60 @@
* THIS FILE IS AUTOGENERATED. DO NOT MODIFY BY HAND. RUN TESTS IN FIXTURES/ TO UPDATE.
*/
const {
parsePacketsWithFronts,
} = require("devtools/client/webconsole/test/browser/stub-generator-helpers");
const { prepareMessage } = require("devtools/client/webconsole/utils/messages");
const {
ConsoleMessage,
NetworkEventMessage,
} = require("devtools/client/webconsole/types");
const stubPackets = new Map();
stubPackets.set(`new Date(0)`, {
"resultID": "1573385647471-0",
const rawPackets = new Map();
rawPackets.set(`new Date(0)`, {
"resultID": "1573832025018-0",
"input": "new Date(0)",
"result": {
"type": "object",
"actor": "server0.conn0.child1/obj23",
"class": "Date",
"ownPropertyLength": 0,
"extensible": true,
"frozen": false,
"sealed": false,
"preview": {
"timestamp": 0
}
"_grip": {
"type": "object",
"actor": "server0.conn0.child1/obj23",
"class": "Date",
"ownPropertyLength": 0,
"extensible": true,
"frozen": false,
"sealed": false,
"preview": {
"timestamp": 0
}
},
"actorID": "server0.conn0.child1/obj23"
},
"timestamp": 1572868073590,
"from": "server0.conn0.child1/consoleActor2"
"timestamp": 1573832025019
});
stubPackets.set(`asdf()`, {
"resultID": "1573385647554-1",
rawPackets.set(`asdf()`, {
"resultID": "1573832025112-1",
"errorMessageName": "JSMSG_NOT_DEFINED",
"exception": {
"type": "object",
"actor": "server0.conn0.child1/obj25",
"class": "Error",
"ownPropertyLength": 4,
"extensible": true,
"frozen": false,
"sealed": false,
"preview": {
"kind": "Error",
"name": "ReferenceError",
"message": "asdf is not defined",
"stack": "@debugger eval code:1:1\n",
"fileName": "debugger eval code",
"lineNumber": 1,
"columnNumber": 1
}
"_grip": {
"type": "object",
"actor": "server0.conn0.child1/obj25",
"class": "Error",
"ownPropertyLength": 4,
"extensible": true,
"frozen": false,
"sealed": false,
"preview": {
"kind": "Error",
"name": "ReferenceError",
"message": "asdf is not defined",
"stack": "@debugger eval code:1:1\n",
"fileName": "debugger eval code",
"lineNumber": 1,
"columnNumber": 1
}
},
"actorID": "server0.conn0.child1/obj25"
},
"exceptionMessage": "ReferenceError: asdf is not defined",
"exceptionDocURL": "https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Not_defined?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default",
@ -75,30 +83,32 @@ stubPackets.set(`asdf()`, {
"result": {
"type": "undefined"
},
"timestamp": 1572868073933,
"from": "server0.conn0.child1/consoleActor2"
"timestamp": 1573832025112
});
stubPackets.set(`1 + @`, {
"resultID": "1573385647562-2",
rawPackets.set(`1 + @`, {
"resultID": "1573832025117-2",
"errorMessageName": "JSMSG_ILLEGAL_CHARACTER",
"exception": {
"type": "object",
"actor": "server0.conn0.child1/obj26",
"class": "Error",
"ownPropertyLength": 4,
"extensible": true,
"frozen": false,
"sealed": false,
"preview": {
"kind": "Error",
"name": "SyntaxError",
"message": "illegal character",
"stack": "",
"fileName": "debugger eval code",
"lineNumber": 1,
"columnNumber": 4
}
"_grip": {
"type": "object",
"actor": "server0.conn0.child1/obj26",
"class": "Error",
"ownPropertyLength": 4,
"extensible": true,
"frozen": false,
"sealed": false,
"preview": {
"kind": "Error",
"name": "SyntaxError",
"message": "illegal character",
"stack": "",
"fileName": "debugger eval code",
"lineNumber": 1,
"columnNumber": 4
}
},
"actorID": "server0.conn0.child1/obj26"
},
"exceptionMessage": "SyntaxError: illegal character",
"exceptionDocURL": "https://developer.mozilla.org/docs/Web/JavaScript/Reference/Errors/Illegal_character?utm_source=mozilla&utm_medium=firefox-console-errors&utm_campaign=default",
@ -111,50 +121,51 @@ stubPackets.set(`1 + @`, {
"result": {
"type": "undefined"
},
"timestamp": 1572868073955,
"from": "server0.conn0.child1/consoleActor2"
"timestamp": 1573832025117
});
stubPackets.set(`inspect({a: 1})`, {
"resultID": "1573385647565-3",
rawPackets.set(`inspect({a: 1})`, {
"resultID": "1573832025122-3",
"helperResult": {
"type": "inspectObject",
"input": "inspect({a: 1})",
"object": {
"type": "object",
"actor": "server0.conn0.child1/obj28",
"class": "Object",
"ownPropertyLength": 1,
"extensible": true,
"frozen": false,
"sealed": false,
"preview": {
"kind": "Object",
"ownProperties": {
"a": {
"configurable": true,
"enumerable": true,
"writable": true,
"value": 1
}
},
"ownSymbols": [],
"ownPropertiesLength": 1,
"ownSymbolsLength": 0,
"safeGetterValues": {}
}
"_grip": {
"type": "object",
"actor": "server0.conn0.child1/obj28",
"class": "Object",
"ownPropertyLength": 1,
"extensible": true,
"frozen": false,
"sealed": false,
"preview": {
"kind": "Object",
"ownProperties": {
"a": {
"configurable": true,
"enumerable": true,
"writable": true,
"value": 1
}
},
"ownSymbols": [],
"ownPropertiesLength": 1,
"ownSymbolsLength": 0,
"safeGetterValues": {}
}
},
"actorID": "server0.conn0.child1/obj28"
}
},
"input": "inspect({a: 1})",
"result": {
"type": "undefined"
},
"timestamp": 1572868073976,
"from": "server0.conn0.child1/consoleActor2"
"timestamp": 1573832025123
});
stubPackets.set(`cd(document)`, {
"resultID": "1573385647570-4",
rawPackets.set(`cd(document)`, {
"resultID": "1573832025125-4",
"helperResult": {
"type": "error",
"message": "cdFunctionInvalidArgument"
@ -163,50 +174,57 @@ stubPackets.set(`cd(document)`, {
"result": {
"type": "undefined"
},
"timestamp": 1572868074010,
"from": "server0.conn0.child1/consoleActor2"
"timestamp": 1573832025126
});
stubPackets.set(`undefined`, {
"resultID": "1573385647572-5",
rawPackets.set(`undefined`, {
"resultID": "1573832025127-5",
"input": "undefined",
"result": {
"type": "undefined"
},
"timestamp": 1572868074023,
"from": "server0.conn0.child1/consoleActor2"
"timestamp": 1573832025128
});
stubPackets.set(`longString message Error`, {
"resultID": "1573385647576-6",
rawPackets.set(`longString message Error`, {
"resultID": "1573832025130-6",
"exception": {
"type": "object",
"actor": "server0.conn0.child1/obj32",
"class": "Error",
"ownPropertyLength": 4,
"extensible": true,
"frozen": false,
"sealed": false,
"preview": {
"kind": "Error",
"name": "Error",
"message": {
"type": "longString",
"actor": "server0.conn0.child1/longstractor33",
"length": 110000,
"initial": "Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error"
},
"stack": "@debugger eval code:1:7\n",
"fileName": "debugger eval code",
"lineNumber": 1,
"columnNumber": 7
}
"_grip": {
"type": "object",
"actor": "server0.conn0.child1/obj32",
"class": "Error",
"ownPropertyLength": 4,
"extensible": true,
"frozen": false,
"sealed": false,
"preview": {
"kind": "Error",
"name": "Error",
"message": {
"_grip": {
"type": "longString",
"actor": "server0.conn0.child1/longstractor33",
"length": 110000,
"initial": "Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error"
},
"actorID": "server0.conn0.child1/longstractor33"
},
"stack": "@debugger eval code:1:7\n",
"fileName": "debugger eval code",
"lineNumber": 1,
"columnNumber": 7
}
},
"actorID": "server0.conn0.child1/obj32"
},
"exceptionMessage": {
"type": "longString",
"actor": "server0.conn0.child1/longstractor34",
"length": 110007,
"initial": "Error: Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Lon"
"_grip": {
"type": "longString",
"actor": "server0.conn0.child1/longstractor34",
"length": 110007,
"initial": "Error: Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Lon"
},
"actorID": "server0.conn0.child1/longstractor34"
},
"exceptionStack": [
{
@ -227,12 +245,11 @@ stubPackets.set(`longString message Error`, {
"result": {
"type": "undefined"
},
"timestamp": 1572868074038,
"from": "server0.conn0.child1/consoleActor2"
"timestamp": 1573832025130
});
stubPackets.set(`eval throw ""`, {
"resultID": "1573385647580-7",
rawPackets.set(`eval throw ""`, {
"resultID": "1573832025134-7",
"exception": "",
"exceptionMessage": "",
"exceptionStack": [
@ -254,12 +271,11 @@ stubPackets.set(`eval throw ""`, {
"result": {
"type": "undefined"
},
"timestamp": 1572868074059,
"from": "server0.conn0.child1/consoleActor2"
"timestamp": 1573832025134
});
stubPackets.set(`eval throw "tomato"`, {
"resultID": "1573385647583-8",
rawPackets.set(`eval throw "tomato"`, {
"resultID": "1573832025137-8",
"exception": "tomato",
"exceptionMessage": "tomato",
"exceptionStack": [
@ -281,10 +297,12 @@ stubPackets.set(`eval throw "tomato"`, {
"result": {
"type": "undefined"
},
"timestamp": 1572868074071,
"from": "server0.conn0.child1/consoleActor2"
"timestamp": 1573832025138
});
const stubPackets = parsePacketsWithFronts(rawPackets);
const stubPreparedMessages = new Map();
for (const [key, packet] of Array.from(stubPackets.entries())) {
const transformedPacket = prepareMessage(packet, {
@ -295,6 +313,7 @@ for (const [key, packet] of Array.from(stubPackets.entries())) {
}
module.exports = {
rawPackets,
stubPreparedMessages,
stubPackets,
};

View File

@ -8,14 +8,17 @@
* THIS FILE IS AUTOGENERATED. DO NOT MODIFY BY HAND. RUN TESTS IN FIXTURES/ TO UPDATE.
*/
const {
parsePacketsWithFronts,
} = require("devtools/client/webconsole/test/browser/stub-generator-helpers");
const { prepareMessage } = require("devtools/client/webconsole/utils/messages");
const {
ConsoleMessage,
NetworkEventMessage,
} = require("devtools/client/webconsole/types");
const stubPackets = new Map();
stubPackets.set(`ReferenceError: asdf is not defined`, {
const rawPackets = new Map();
rawPackets.set(`ReferenceError: asdf is not defined`, {
"pageError": {
"errorMessage": "ReferenceError: asdf is not defined",
"errorMessageName": "JSMSG_NOT_DEFINED",
@ -27,7 +30,7 @@ stubPackets.set(`ReferenceError: asdf is not defined`, {
"columnNumber": 5,
"category": "content javascript",
"innerWindowID": 8589934593,
"timeStamp": 1572868283535,
"timeStamp": 1573832650066,
"warning": false,
"error": false,
"exception": true,
@ -78,7 +81,7 @@ stubPackets.set(`ReferenceError: asdf is not defined`, {
"type": "pageError"
});
stubPackets.set(`SyntaxError: redeclaration of let a`, {
rawPackets.set(`SyntaxError: redeclaration of let a`, {
"pageError": {
"errorMessage": "SyntaxError: redeclaration of let a",
"errorMessageName": "JSMSG_REDECLARED_VAR",
@ -90,7 +93,7 @@ stubPackets.set(`SyntaxError: redeclaration of let a`, {
"columnNumber": 9,
"category": "content javascript",
"innerWindowID": 8589934593,
"timeStamp": 1572868283903,
"timeStamp": 1573832650228,
"warning": false,
"error": false,
"exception": true,
@ -130,13 +133,16 @@ stubPackets.set(`SyntaxError: redeclaration of let a`, {
"type": "pageError"
});
stubPackets.set(`TypeError longString message`, {
rawPackets.set(`TypeError longString message`, {
"pageError": {
"errorMessage": {
"type": "longString",
"actor": "server0.conn0.child1/longstractor24",
"length": 110007,
"initial": "Error: Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Lon"
"_grip": {
"type": "longString",
"actor": "server0.conn0.child1/longstractor24",
"length": 110007,
"initial": "Error: Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Long error Lon"
},
"actorID": "server0.conn0.child1/longstractor24"
},
"errorMessageName": "",
"sourceName": "http://example.com/browser/devtools/client/webconsole/test/browser/test-console-api.html",
@ -146,7 +152,7 @@ stubPackets.set(`TypeError longString message`, {
"columnNumber": 7,
"category": "content javascript",
"innerWindowID": 8589934593,
"timeStamp": 1572868284293,
"timeStamp": 1573832650682,
"warning": false,
"error": false,
"exception": true,
@ -183,7 +189,7 @@ stubPackets.set(`TypeError longString message`, {
"type": "pageError"
});
stubPackets.set(`throw ""`, {
rawPackets.set(`throw ""`, {
"pageError": {
"errorMessage": "uncaught exception: ",
"errorMessageName": "JSMSG_UNCAUGHT_EXCEPTION",
@ -194,7 +200,7 @@ stubPackets.set(`throw ""`, {
"columnNumber": 1,
"category": "content javascript",
"innerWindowID": 8589934593,
"timeStamp": 1572868284458,
"timeStamp": 1573832650688,
"warning": false,
"error": false,
"exception": false,
@ -231,7 +237,7 @@ stubPackets.set(`throw ""`, {
"type": "pageError"
});
stubPackets.set(`throw "tomato"`, {
rawPackets.set(`throw "tomato"`, {
"pageError": {
"errorMessage": "uncaught exception: tomato",
"errorMessageName": "JSMSG_UNCAUGHT_EXCEPTION",
@ -242,7 +248,7 @@ stubPackets.set(`throw "tomato"`, {
"columnNumber": 1,
"category": "content javascript",
"innerWindowID": 8589934593,
"timeStamp": 1572868284565,
"timeStamp": 1573832650692,
"warning": false,
"error": false,
"exception": false,
@ -279,6 +285,9 @@ stubPackets.set(`throw "tomato"`, {
"type": "pageError"
});
const stubPackets = parsePacketsWithFronts(rawPackets);
const stubPreparedMessages = new Map();
for (const [key, packet] of Array.from(stubPackets.entries())) {
const transformedPacket = prepareMessage(packet, {
@ -289,6 +298,7 @@ for (const [key, packet] of Array.from(stubPackets.entries())) {
}
module.exports = {
rawPackets,
stubPreparedMessages,
stubPackets,
};

View File

@ -103,7 +103,9 @@ requireHacker.global_hook("default", (path, module) => {
react: () => getModule("devtools/client/shared/vendor/react-dev"),
"devtools/client/shared/vendor/react": () =>
getModule("devtools/client/shared/vendor/react-dev"),
chrome: () => `module.exports = { Cc: {}, Ci: {}, Cu: {} }`,
chrome: () =>
`module.exports = { Cc: {}, Ci: {}, Cu: {}, components: {stack: {caller: ""}} }`,
ChromeUtils: () => `module.exports = { import: () => ({}) }`,
// Some modules depend on Chrome APIs which don't work in mocha. When such a module
// is required, replace it with a mock version.
"devtools/shared/l10n": () =>
@ -113,9 +115,8 @@ requireHacker.global_hook("default", (path, module) => {
"devtools/shared/plural-form": () =>
getModule("devtools/client/webconsole/test/node/fixtures/PluralForm"),
Services: () => `module.exports = require("devtools-services")`,
"devtools/shared/fronts/object": () => `() => {}`,
"devtools/shared/fronts/string": () =>
`() => ({LongStringFront: () => {}})`,
"devtools/server/debugger-server": () =>
`module.exports = {DebuggerServer: {}}`,
"devtools/client/shared/components/SmartTrace": () => "{}",
"devtools/client/netmonitor/src/components/TabboxPanel": () => "{}",
"devtools/client/webconsole/utils/context-menu": () => "{}",

View File

@ -18,7 +18,6 @@ const {
getFirstMessage,
getLastMessage,
getPrivatePacket,
getWebConsoleUiMock,
setupActions,
setupStore,
} = require("devtools/client/webconsole/test/node/helpers");
@ -190,27 +189,27 @@ describe("private messages", () => {
it("releases private backend actors on PRIVATE_MESSAGES_CLEAR action", () => {
const releasedActors = [];
const { dispatch, getState } = setupStore([], {
webConsoleUI: getWebConsoleUiMock(null, {
releaseActor: actor => {
releasedActors.push(actor);
},
}),
});
const { dispatch, getState } = setupStore([]);
const mockFrontRelease = function() {
releasedActors.push(this.actorID);
};
const publicPacket = stubPackets.get(
"console.log('myarray', ['red', 'green', 'blue'])"
);
const privatePacket = getPrivatePacket("console.log('mymap')");
publicPacket.message.arguments[1].release = mockFrontRelease;
privatePacket.message.arguments[1].release = mockFrontRelease;
// Add a log message.
dispatch(
actions.messagesAdd([
stubPackets.get("console.log('myarray', ['red', 'green', 'blue'])"),
getPrivatePacket("console.log('mymap')"),
])
);
dispatch(actions.messagesAdd([publicPacket, privatePacket]));
const firstMessage = getFirstMessage(getState());
const firstMessageActor = firstMessage.parameters[1].actor;
const firstMessageActor = firstMessage.parameters[1].actorID;
const lastMessage = getLastMessage(getState());
const lastMessageActor = lastMessage.parameters[1].actor;
const lastMessageActor = lastMessage.parameters[1].actorID;
// Kick-off the actor release.
dispatch(actions.privateMessagesClear());

View File

@ -3,9 +3,7 @@
"use strict";
const {
clonePacket,
getFirstMessage,
getWebConsoleUiMock,
setupActions,
setupStore,
} = require("devtools/client/webconsole/test/node/helpers");
@ -26,39 +24,40 @@ describe("Release actor enhancer:", () => {
it("releases backend actors when limit reached adding a single message", () => {
const logLimit = 100;
const releasedActors = [];
const mockFrontRelease = function() {
releasedActors.push(this.actorID);
};
const { dispatch, getState } = setupStore([], {
storeOptions: { logLimit },
webConsoleUI: getWebConsoleUiMock(null, {
releaseActor: actor => {
releasedActors.push(actor);
},
}),
});
// Add a log message.
dispatch(
actions.messagesAdd([
stubPackets.get("console.log('myarray', ['red', 'green', 'blue'])"),
])
const packet = stubPackets.get(
"console.log('myarray', ['red', 'green', 'blue'])"
);
packet.message.arguments[1].release = mockFrontRelease;
dispatch(actions.messagesAdd([packet]));
const firstMessage = getFirstMessage(getState());
const firstMessageActor = firstMessage.parameters[1].actor;
const firstMessageActor = firstMessage.parameters[1].actorID;
// Add an evaluation result message (see Bug 1408321).
const evaluationResultPacket = stubPackets.get("new Date(0)");
evaluationResultPacket.result.release = mockFrontRelease;
dispatch(actions.messagesAdd([evaluationResultPacket]));
const secondMessageActor = evaluationResultPacket.result.actor;
const secondMessageActor = evaluationResultPacket.result.actorID;
const logCount = logLimit + 1;
const packet = clonePacket(
stubPackets.get("console.assert(false, {message: 'foobar'})")
const assertPacket = stubPackets.get(
"console.assert(false, {message: 'foobar'})"
);
const thirdMessageActor = packet.message.arguments[0].actor;
assertPacket.message.arguments[0].release = mockFrontRelease;
const thirdMessageActor = assertPacket.message.arguments[0].actorID;
for (let i = 1; i <= logCount; i++) {
packet.message.arguments.push(`message num ${i}`);
dispatch(actions.messagesAdd([packet]));
assertPacket.message.arguments.push(`message num ${i}`);
dispatch(actions.messagesAdd([assertPacket]));
}
expect(releasedActors.length).toBe(3);
@ -72,34 +71,35 @@ describe("Release actor enhancer:", () => {
const releasedActors = [];
const { dispatch, getState } = setupStore([], {
storeOptions: { logLimit },
webConsoleUI: getWebConsoleUiMock(null, {
releaseActor: actor => {
releasedActors.push(actor);
},
}),
});
const mockFrontRelease = function() {
releasedActors.push(this.actorID);
};
// Add a log message.
dispatch(
actions.messagesAdd([
stubPackets.get("console.log('myarray', ['red', 'green', 'blue'])"),
])
const logPacket = stubPackets.get(
"console.log('myarray', ['red', 'green', 'blue'])"
);
logPacket.message.arguments[1].release = mockFrontRelease;
dispatch(actions.messagesAdd([logPacket]));
const firstMessage = getFirstMessage(getState());
const firstMessageActor = firstMessage.parameters[1].actor;
const firstMessageActor = firstMessage.parameters[1].actorID;
// Add an evaluation result message (see Bug 1408321).
const evaluationResultPacket = stubPackets.get("new Date(0)");
evaluationResultPacket.result.release = mockFrontRelease;
dispatch(actions.messagesAdd([evaluationResultPacket]));
const secondMessageActor = evaluationResultPacket.result.actor;
const secondMessageActor = evaluationResultPacket.result.actorID;
// Add an assertion message.
const assertPacket = stubPackets.get(
"console.assert(false, {message: 'foobar'})"
);
assertPacket.message.arguments[0].release = mockFrontRelease;
dispatch(actions.messagesAdd([assertPacket]));
const thirdMessageActor = assertPacket.message.arguments[0].actor;
const thirdMessageActor = assertPacket.message.arguments[0].actorID;
// Add ${logLimit} messages so we prune the ones we added before.
const packets = [];
@ -122,39 +122,42 @@ describe("Release actor enhancer:", () => {
it("properly releases backend actors after clear", () => {
const releasedActors = [];
const { dispatch, getState } = setupStore([], {
webConsoleUI: getWebConsoleUiMock(null, {
releaseActor: actor => {
releasedActors.push(actor);
},
}),
});
const { dispatch, getState } = setupStore([]);
const mockFrontRelease = function() {
releasedActors.push(this.actorID);
};
// Add a log message.
dispatch(
actions.messagesAdd([
stubPackets.get("console.log('myarray', ['red', 'green', 'blue'])"),
])
const logPacket = stubPackets.get(
"console.log('myarray', ['red', 'green', 'blue'])"
);
logPacket.message.arguments[1].release = mockFrontRelease;
dispatch(actions.messagesAdd([logPacket]));
const firstMessage = getFirstMessage(getState());
const firstMessageActor = firstMessage.parameters[1].actor;
const firstMessageActor = firstMessage.parameters[1].actorID;
const packet = clonePacket(
stubPackets.get("console.assert(false, {message: 'foobar'})")
// Add an assertion message.
const assertPacket = stubPackets.get(
"console.assert(false, {message: 'foobar'})"
);
const secondMessageActor = packet.message.arguments[0].actor;
dispatch(actions.messagesAdd([packet]));
assertPacket.message.arguments[0].release = mockFrontRelease;
dispatch(actions.messagesAdd([assertPacket]));
const secondMessageActor = assertPacket.message.arguments[0].actorID;
// Add an evaluation result message (see Bug 1408321).
const evaluationResultPacket = stubPackets.get("new Date(0)");
evaluationResultPacket.result.release = mockFrontRelease;
dispatch(actions.messagesAdd([evaluationResultPacket]));
const thirdMessageActor = evaluationResultPacket.result.actor;
const thirdMessageActor = evaluationResultPacket.result.actorID;
// Add a message with a long string messageText property.
const longStringPacket = stubPackets.get("TypeError longString message");
longStringPacket.pageError.errorMessage.release = mockFrontRelease;
dispatch(actions.messagesAdd([longStringPacket]));
const fourthMessageActor = longStringPacket.pageError.errorMessage.actor;
const fourthMessageActor =
longStringPacket.pageError.errorMessage.actorID;
// Kick-off the actor release.
dispatch(actions.messagesClear());

View File

@ -29,9 +29,9 @@ describe("Testing UI", () => {
const message = stubPreparedMessages.get("inspect({a: 1})");
store.dispatch(actions.messagesAdd([packet]));
const actorId = message.parameters[0].actor;
const { actorID } = message.parameters[0];
const messageId = getFirstMessage(store.getState()).id;
store.dispatch(actions.showMessageObjectInSidebar(actorId, messageId));
store.dispatch(actions.showMessageObjectInSidebar(actorID, messageId));
expect(store.getState().ui.sidebarVisible).toEqual(true);
store.dispatch(actions.sidebarClose());
@ -45,9 +45,9 @@ describe("Testing UI", () => {
const message = stubPreparedMessages.get("inspect({a: 1})");
store.dispatch(actions.messagesAdd([packet]));
const actorId = message.parameters[0].actor;
const { actorID } = message.parameters[0];
const messageId = getFirstMessage(store.getState()).id;
store.dispatch(actions.showMessageObjectInSidebar(actorId, messageId));
store.dispatch(actions.showMessageObjectInSidebar(actorID, messageId));
expect(store.getState().ui.sidebarVisible).toEqual(true);
store.dispatch(actions.messagesClear());
@ -63,12 +63,12 @@ describe("Testing UI", () => {
const message = stubPreparedMessages.get("inspect({a: 1})");
store.dispatch(actions.messagesAdd([packet]));
const actorId = message.parameters[0].actor;
const { actorID } = message.parameters[0];
const messageId = getFirstMessage(store.getState()).id;
store.dispatch(actions.showMessageObjectInSidebar(actorId, messageId));
store.dispatch(actions.showMessageObjectInSidebar(actorID, messageId));
expect(store.getState().ui.sidebarVisible).toEqual(true);
expect(store.getState().ui.gripInSidebar).toEqual(message.parameters[0]);
expect(store.getState().ui.frontInSidebar).toEqual(message.parameters[0]);
});
it("sidebar is not updated for the same object", () => {
@ -76,15 +76,15 @@ describe("Testing UI", () => {
const message = stubPreparedMessages.get("inspect({a: 1})");
store.dispatch(actions.messagesAdd([packet]));
const actorId = message.parameters[0].actor;
const { actorID } = message.parameters[0];
const messageId = getFirstMessage(store.getState()).id;
store.dispatch(actions.showMessageObjectInSidebar(actorId, messageId));
store.dispatch(actions.showMessageObjectInSidebar(actorID, messageId));
expect(store.getState().ui.sidebarVisible).toEqual(true);
expect(store.getState().ui.gripInSidebar).toEqual(message.parameters[0]);
expect(store.getState().ui.frontInSidebar).toEqual(message.parameters[0]);
const state = store.getState().ui;
store.dispatch(actions.showMessageObjectInSidebar(actorId, messageId));
store.dispatch(actions.showMessageObjectInSidebar(actorID, messageId));
expect(store.getState().ui).toEqual(state);
});
@ -93,25 +93,25 @@ describe("Testing UI", () => {
const message = stubPreparedMessages.get("inspect({a: 1})");
store.dispatch(actions.messagesAdd([packet]));
const actorId = message.parameters[0].actor;
const { actorID } = message.parameters[0];
const messageId = getFirstMessage(store.getState()).id;
store.dispatch(actions.showMessageObjectInSidebar(actorId, messageId));
store.dispatch(actions.showMessageObjectInSidebar(actorID, messageId));
expect(store.getState().ui.sidebarVisible).toEqual(true);
expect(store.getState().ui.gripInSidebar).toEqual(message.parameters[0]);
expect(store.getState().ui.frontInSidebar).toEqual(message.parameters[0]);
const newPacket = stubPackets.get("new Date(0)");
const newMessage = stubPreparedMessages.get("new Date(0)");
store.dispatch(actions.messagesAdd([newPacket]));
const newActorId = newMessage.parameters[0].actor;
const newActorID = newMessage.parameters[0].actorID;
const newMessageId = getLastMessage(store.getState()).id;
store.dispatch(
actions.showMessageObjectInSidebar(newActorId, newMessageId)
actions.showMessageObjectInSidebar(newActorID, newMessageId)
);
expect(store.getState().ui.sidebarVisible).toEqual(true);
expect(store.getState().ui.gripInSidebar).toEqual(
expect(store.getState().ui.frontInSidebar).toEqual(
newMessage.parameters[0]
);
});

View File

@ -26,8 +26,22 @@ loader.lazyRequireGetter(
"devtools/client/shared/components/SmartTrace"
);
loader.lazyRequireGetter(
this,
"LongStringFront",
"devtools/shared/fronts/string",
true
);
loader.lazyRequireGetter(
this,
"ObjectFront",
"devtools/shared/fronts/object",
true
);
/**
* Create and return an ObjectInspector for the given grip.
* Create and return an ObjectInspector for the given front.
*
* @param {Object} grip
* The object grip to create an ObjectInspector for.
@ -39,7 +53,11 @@ loader.lazyRequireGetter(
* @returns {ObjectInspector}
* An ObjectInspector for the given grip.
*/
function getObjectInspector(grip, serviceContainer, override = {}) {
function getObjectInspector(
frontOrPrimitiveGrip,
serviceContainer,
override = {}
) {
let onDOMNodeMouseOver;
let onDOMNodeMouseOut;
let onInspectIconClick;
@ -60,7 +78,7 @@ function getObjectInspector(grip, serviceContainer, override = {}) {
: null;
}
const roots = createRootsFromGrip(grip, override.pathPrefix);
const roots = createRoots(frontOrPrimitiveGrip, override.pathPrefix);
const objectInspectorProps = {
autoExpandDepth: 0,
@ -86,29 +104,36 @@ function getObjectInspector(grip, serviceContainer, override = {}) {
}),
};
if (!(typeof grip === "string" || (grip && grip.type === "longString"))) {
Object.assign(objectInspectorProps, {
onDOMNodeMouseOver,
onDOMNodeMouseOut,
onInspectIconClick,
defaultRep: REPS.Grip,
});
}
Object.assign(objectInspectorProps, {
onDOMNodeMouseOver,
onDOMNodeMouseOut,
onInspectIconClick,
defaultRep: REPS.Grip,
});
if (override.autoFocusRoot) {
Object.assign(objectInspectorProps, {
focusedItem: roots[0],
focusedItem: objectInspectorProps.roots[0],
});
}
return ObjectInspector({ ...objectInspectorProps, ...override });
}
function createRootsFromGrip(grip, pathPrefix = "") {
function createRoots(frontOrPrimitiveGrip, pathPrefix = "") {
const isFront =
frontOrPrimitiveGrip instanceof ObjectFront ||
frontOrPrimitiveGrip instanceof LongStringFront;
const grip = isFront ? frontOrPrimitiveGrip.getGrip() : frontOrPrimitiveGrip;
return [
{
path: `${pathPrefix}${(grip && grip.actor) || JSON.stringify(grip)}`,
contents: { value: grip },
path: `${pathPrefix}${
frontOrPrimitiveGrip
? frontOrPrimitiveGrip.actorID || frontOrPrimitiveGrip.actor
: null
}`,
contents: { value: grip, front: isFront ? frontOrPrimitiveGrip : null },
},
];
}

View File

@ -356,24 +356,6 @@ class WebConsoleConnectionProxy {
this.webConsoleUI.wrapper.dispatchMessageUpdate(networkInfo, response);
}
/**
* Release an object actor.
*
* @param string actor
* The actor ID to send the request to.
*/
releaseActor(actor) {
if (this.client) {
const objFront = this.client.getFrontByID(actor);
if (objFront) {
objFront.release().catch(() => {});
return;
}
// In case there's no object front, use the client's release method.
this.client.release(actor).catch(() => {});
}
}
/**
* Disconnect the Web Console from the remote server.
*

View File

@ -17,6 +17,9 @@ var ChromeUtils = require("ChromeUtils");
const { BrowserLoader } = ChromeUtils.import(
"resource://devtools/client/shared/browser-loader.js"
);
const {
getAdHocFrontOrPrimitiveGrip,
} = require("devtools/shared/fronts/object");
loader.lazyRequireGetter(
this,
@ -245,11 +248,15 @@ class WebConsoleUI {
}
inspectObjectActor(objectActor) {
const webConsoleFront = this.webConsoleFront;
this.wrapper.dispatchMessageAdd(
{
helperResult: {
type: "inspectObject",
object: objectActor,
object:
objectActor && objectActor.getGrip
? objectActor
: getAdHocFrontOrPrimitiveGrip(objectActor, webConsoleFront),
},
},
true
@ -478,22 +485,6 @@ class WebConsoleUI {
}
}
/**
* Release an actor.
*
* @private
* @param string actor
* The actor ID you want to release.
*/
releaseActor(actor) {
const proxy = this.getProxy();
if (!proxy) {
return null;
}
return proxy.releaseActor(actor);
}
/**
* @param {String} expression
* @param {Object} options