зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1756823
- Replace ConsoleAPIStorage observer calls with js array r=nchevobbe,webdriver-reviewers,geckoview-reviewers,agi,jdescottes
See the comment in the file explaining it. For a case of logging 100k numbers, this dropped the time per number from 15 microseconds to 9 with the console closed, and 55 microseconds to 38 with the console open. I think we could shave off more with a native approach, but I don't know that it's worth it and it's much more likely for that to introduce bugs. Differential Revision: https://phabricator.services.mozilla.com/D143782
This commit is contained in:
Родитель
e5f2d78d34
Коммит
04d1c8fd1e
|
@ -25,7 +25,14 @@ async function checkMessages(expectedResult) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Services.console.registerListener(errorListener);
|
Services.console.registerListener(errorListener);
|
||||||
Services.obs.addObserver(errorListener, "console-api-log-event");
|
|
||||||
|
const ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"].getService(
|
||||||
|
Ci.nsIConsoleAPIStorage
|
||||||
|
);
|
||||||
|
ConsoleAPIStorage.addLogEventListener(
|
||||||
|
errorListener.observe,
|
||||||
|
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal)
|
||||||
|
);
|
||||||
|
|
||||||
await setupPolicyEngineWithJson({
|
await setupPolicyEngineWithJson({
|
||||||
policies: {},
|
policies: {},
|
||||||
|
|
|
@ -185,21 +185,24 @@ registerCleanupFunction(function() {
|
||||||
/**
|
/**
|
||||||
* Watch console messages for failed propType definitions in React components.
|
* Watch console messages for failed propType definitions in React components.
|
||||||
*/
|
*/
|
||||||
const ConsoleObserver = {
|
function onConsoleMessage(subject) {
|
||||||
QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
|
const message = subject.wrappedJSObject.arguments[0];
|
||||||
|
|
||||||
observe: function(subject) {
|
if (message && /Failed propType/.test(message.toString())) {
|
||||||
const message = subject.wrappedJSObject.arguments[0];
|
ok(false, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (message && /Failed propType/.test(message.toString())) {
|
const ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"].getService(
|
||||||
ok(false, message);
|
Ci.nsIConsoleAPIStorage
|
||||||
}
|
);
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Services.obs.addObserver(ConsoleObserver, "console-api-log-event");
|
ConsoleAPIStorage.addLogEventListener(
|
||||||
|
onConsoleMessage,
|
||||||
|
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal)
|
||||||
|
);
|
||||||
registerCleanupFunction(() => {
|
registerCleanupFunction(() => {
|
||||||
Services.obs.removeObserver(ConsoleObserver, "console-api-log-event");
|
ConsoleAPIStorage.removeLogEventListener(onConsoleMessage);
|
||||||
});
|
});
|
||||||
|
|
||||||
Services.prefs.setBoolPref("devtools.inspector.three-pane-enabled", true);
|
Services.prefs.setBoolPref("devtools.inspector.three-pane-enabled", true);
|
||||||
|
|
|
@ -200,7 +200,7 @@ function getConsoleTableMessageItems(targetActor, result) {
|
||||||
* @param TargetActor targetActor
|
* @param TargetActor targetActor
|
||||||
* The related target actor
|
* The related target actor
|
||||||
* @param object message
|
* @param object message
|
||||||
* The original message received from console-api-log-event.
|
* The original message received from the console storage listener.
|
||||||
* @return object
|
* @return object
|
||||||
* The object that can be sent to the remote client.
|
* The object that can be sent to the remote client.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -2044,7 +2044,7 @@ const WebConsoleActor = ActorClassWithSpec(webconsoleSpec, {
|
||||||
* instance.
|
* instance.
|
||||||
*
|
*
|
||||||
* @param object message
|
* @param object message
|
||||||
* The original message received from console-api-log-event.
|
* The original message received from the console storage listener.
|
||||||
* @param boolean aUseObjectGlobal
|
* @param boolean aUseObjectGlobal
|
||||||
* If |true| the object global is determined and added as a debuggee,
|
* If |true| the object global is determined and added as a debuggee,
|
||||||
* otherwise |this.global| is used when makeDebuggeeValue() is invoked.
|
* otherwise |this.global| is used when makeDebuggeeValue() is invoked.
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||||
|
const { XPCOMUtils } = ChromeUtils.import(
|
||||||
|
"resource://gre/modules/XPCOMUtils.jsm"
|
||||||
|
);
|
||||||
|
|
||||||
ChromeUtils.defineModuleGetter(
|
ChromeUtils.defineModuleGetter(
|
||||||
this,
|
this,
|
||||||
|
@ -12,6 +15,12 @@ ChromeUtils.defineModuleGetter(
|
||||||
"resource://gre/modules/E10SUtils.jsm"
|
"resource://gre/modules/E10SUtils.jsm"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyGetter(this, "ConsoleAPIStorage", () => {
|
||||||
|
return Cc["@mozilla.org/consoleAPI-storage;1"].getService(
|
||||||
|
Ci.nsIConsoleAPIStorage
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The message manager has an upper limit on message sizes that it can
|
* The message manager has an upper limit on message sizes that it can
|
||||||
* reliably forward to the parent so we limit the size of console log event
|
* reliably forward to the parent so we limit the size of console log event
|
||||||
|
@ -34,7 +43,11 @@ const MSG_MGR_CONSOLE_VAR_SIZE = 8;
|
||||||
const MSG_MGR_CONSOLE_INFO_MAX = 1024;
|
const MSG_MGR_CONSOLE_INFO_MAX = 1024;
|
||||||
|
|
||||||
function ContentProcessForward() {
|
function ContentProcessForward() {
|
||||||
Services.obs.addObserver(this, "console-api-log-event");
|
this.onConsoleAPILogEvent = this.onConsoleAPILogEvent.bind(this);
|
||||||
|
ConsoleAPIStorage.addLogEventListener(
|
||||||
|
this.onConsoleAPILogEvent,
|
||||||
|
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal)
|
||||||
|
);
|
||||||
Services.obs.addObserver(this, "xpcom-shutdown");
|
Services.obs.addObserver(this, "xpcom-shutdown");
|
||||||
Services.cpmm.addMessageListener(
|
Services.cpmm.addMessageListener(
|
||||||
"DevTools:StopForwardingContentProcessMessage",
|
"DevTools:StopForwardingContentProcessMessage",
|
||||||
|
@ -53,81 +66,76 @@ ContentProcessForward.prototype = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
observe(subject, topic, data) {
|
onConsoleAPILogEvent(subject, data) {
|
||||||
switch (topic) {
|
const consoleMsg = subject.wrappedJSObject;
|
||||||
case "console-api-log-event": {
|
|
||||||
const consoleMsg = subject.wrappedJSObject;
|
|
||||||
|
|
||||||
const msgData = {
|
const msgData = {
|
||||||
...consoleMsg,
|
...consoleMsg,
|
||||||
arguments: [],
|
arguments: [],
|
||||||
filename: consoleMsg.filename.substring(0, MSG_MGR_CONSOLE_INFO_MAX),
|
filename: consoleMsg.filename.substring(0, MSG_MGR_CONSOLE_INFO_MAX),
|
||||||
functionName:
|
functionName:
|
||||||
consoleMsg.functionName &&
|
consoleMsg.functionName &&
|
||||||
consoleMsg.functionName.substring(0, MSG_MGR_CONSOLE_INFO_MAX),
|
consoleMsg.functionName.substring(0, MSG_MGR_CONSOLE_INFO_MAX),
|
||||||
// Prevents cyclic object error when using msgData in sendAsyncMessage
|
// Prevents cyclic object error when using msgData in sendAsyncMessage
|
||||||
wrappedJSObject: null,
|
wrappedJSObject: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
// We can't send objects over the message manager, so we sanitize
|
// We can't send objects over the message manager, so we sanitize
|
||||||
// them out, replacing those arguments with "<unavailable>".
|
// them out, replacing those arguments with "<unavailable>".
|
||||||
const unavailString = "<unavailable>";
|
const unavailString = "<unavailable>";
|
||||||
const unavailStringLength = unavailString.length * 2; // 2-bytes per char
|
const unavailStringLength = unavailString.length * 2; // 2-bytes per char
|
||||||
|
|
||||||
// When the sum of argument sizes reaches MSG_MGR_CONSOLE_MAX_SIZE,
|
// When the sum of argument sizes reaches MSG_MGR_CONSOLE_MAX_SIZE,
|
||||||
// replace all arguments with "<truncated>".
|
// replace all arguments with "<truncated>".
|
||||||
let totalArgLength = 0;
|
let totalArgLength = 0;
|
||||||
|
|
||||||
// Walk through the arguments, checking the type and size.
|
// Walk through the arguments, checking the type and size.
|
||||||
for (let arg of consoleMsg.arguments) {
|
for (let arg of consoleMsg.arguments) {
|
||||||
if (
|
if (
|
||||||
(typeof arg == "object" || typeof arg == "function") &&
|
(typeof arg == "object" || typeof arg == "function") &&
|
||||||
arg !== null
|
arg !== null
|
||||||
) {
|
) {
|
||||||
if (
|
if (Services.appinfo.remoteType === E10SUtils.EXTENSION_REMOTE_TYPE) {
|
||||||
Services.appinfo.remoteType === E10SUtils.EXTENSION_REMOTE_TYPE
|
// For OOP extensions: we want the developer to be able to see the
|
||||||
) {
|
// logs in the Browser Console. When the Addon Toolbox will be more
|
||||||
// For OOP extensions: we want the developer to be able to see the
|
// prominent we can revisit.
|
||||||
// logs in the Browser Console. When the Addon Toolbox will be more
|
try {
|
||||||
// prominent we can revisit.
|
// If the argument is clonable, then send it as-is. If
|
||||||
try {
|
// cloning fails, fall back to the unavailable string.
|
||||||
// If the argument is clonable, then send it as-is. If
|
arg = Cu.cloneInto(arg, {});
|
||||||
// cloning fails, fall back to the unavailable string.
|
} catch (e) {
|
||||||
arg = Cu.cloneInto(arg, {});
|
arg = unavailString;
|
||||||
} catch (e) {
|
|
||||||
arg = unavailString;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
arg = unavailString;
|
|
||||||
}
|
|
||||||
totalArgLength += unavailStringLength;
|
|
||||||
} else if (typeof arg == "string") {
|
|
||||||
totalArgLength += arg.length * 2; // 2-bytes per char
|
|
||||||
} else {
|
|
||||||
totalArgLength += MSG_MGR_CONSOLE_VAR_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (totalArgLength <= MSG_MGR_CONSOLE_MAX_SIZE) {
|
|
||||||
msgData.arguments.push(arg);
|
|
||||||
} else {
|
|
||||||
// arguments take up too much space
|
|
||||||
msgData.arguments = ["<truncated>"];
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
arg = unavailString;
|
||||||
}
|
}
|
||||||
|
totalArgLength += unavailStringLength;
|
||||||
Services.cpmm.sendAsyncMessage("Console:Log", msgData);
|
} else if (typeof arg == "string") {
|
||||||
break;
|
totalArgLength += arg.length * 2; // 2-bytes per char
|
||||||
|
} else {
|
||||||
|
totalArgLength += MSG_MGR_CONSOLE_VAR_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
case "xpcom-shutdown":
|
if (totalArgLength <= MSG_MGR_CONSOLE_MAX_SIZE) {
|
||||||
this.uninit();
|
msgData.arguments.push(arg);
|
||||||
|
} else {
|
||||||
|
// arguments take up too much space
|
||||||
|
msgData.arguments = ["<truncated>"];
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Services.cpmm.sendAsyncMessage("Console:Log", msgData);
|
||||||
|
},
|
||||||
|
|
||||||
|
observe(subject, topic, data) {
|
||||||
|
if (topic == "xpcom-shutdown") {
|
||||||
|
this.uninit();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
uninit() {
|
uninit() {
|
||||||
Services.obs.removeObserver(this, "console-api-log-event");
|
ConsoleAPIStorage.removeLogEventListener(this.onConsoleAPILogEvent);
|
||||||
Services.obs.removeObserver(this, "xpcom-shutdown");
|
Services.obs.removeObserver(this, "xpcom-shutdown");
|
||||||
Services.cpmm.removeMessageListener(
|
Services.cpmm.removeMessageListener(
|
||||||
"DevTools:StopForwardingContentProcessMessage",
|
"DevTools:StopForwardingContentProcessMessage",
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { Cc, Ci } = require("chrome");
|
const { Cc, Ci } = require("chrome");
|
||||||
const Services = require("Services");
|
|
||||||
const ChromeUtils = require("ChromeUtils");
|
const ChromeUtils = require("ChromeUtils");
|
||||||
const {
|
const {
|
||||||
CONSOLE_WORKER_IDS,
|
CONSOLE_WORKER_IDS,
|
||||||
|
@ -59,7 +58,7 @@ class ConsoleAPIListener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The function which is notified of window.console API calls. It is invoked with one
|
* The function which is notified of window.console API calls. It is invoked with one
|
||||||
* argument: the console API call object that comes from the observer service.
|
* argument: the console API call object that comes from the ConsoleAPIStorage service.
|
||||||
*
|
*
|
||||||
* @type function
|
* @type function
|
||||||
*/
|
*/
|
||||||
|
@ -72,24 +71,34 @@ class ConsoleAPIListener {
|
||||||
addonId = null;
|
addonId = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the window.console API observer.
|
* Initialize the window.console API listener.
|
||||||
*/
|
*/
|
||||||
init() {
|
init() {
|
||||||
// Note that the observer is process-wide. We will filter the messages as
|
const ConsoleAPIStorage = Cc[
|
||||||
// needed, see CAL_observe().
|
"@mozilla.org/consoleAPI-storage;1"
|
||||||
Services.obs.addObserver(this, "console-api-log-event");
|
].getService(Ci.nsIConsoleAPIStorage);
|
||||||
|
|
||||||
|
// Note that the listener is process-wide. We will filter the messages as
|
||||||
|
// needed, see onConsoleAPILogEvent().
|
||||||
|
this.onConsoleAPILogEvent = this.onConsoleAPILogEvent.bind(this);
|
||||||
|
ConsoleAPIStorage.addLogEventListener(
|
||||||
|
this.onConsoleAPILogEvent,
|
||||||
|
// We create a principal here to get the privileged principal of this
|
||||||
|
// script. Note that this is importantly *NOT* the principal of the
|
||||||
|
// content we are observing, as that would not have access to the
|
||||||
|
// message object created in ConsoleAPIStorage.jsm's scope.
|
||||||
|
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The console API message observer. When messages are received from the
|
* The console API message listener. When messages are received from the
|
||||||
* observer service we forward them to the remote Web Console instance.
|
* ConsoleAPIStorage service we forward them to the remote Web Console instance.
|
||||||
*
|
*
|
||||||
* @param object message
|
* @param object message
|
||||||
* The message object receives from the observer service.
|
* The message object receives from the ConsoleAPIStorage service.
|
||||||
* @param string topic
|
|
||||||
* The message topic received from the observer service.
|
|
||||||
*/
|
*/
|
||||||
observe(message, topic) {
|
onConsoleAPILogEvent(message) {
|
||||||
if (!this.handler) {
|
if (!this.handler) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -233,7 +242,10 @@ class ConsoleAPIListener {
|
||||||
* Destroy the console API listener.
|
* Destroy the console API listener.
|
||||||
*/
|
*/
|
||||||
destroy() {
|
destroy() {
|
||||||
Services.obs.removeObserver(this, "console-api-log-event");
|
const ConsoleAPIStorage = Cc[
|
||||||
|
"@mozilla.org/consoleAPI-storage;1"
|
||||||
|
].getService(Ci.nsIConsoleAPIStorage);
|
||||||
|
ConsoleAPIStorage.removeLogEventListener(this.onConsoleAPILogEvent);
|
||||||
this.window = this.handler = null;
|
this.window = this.handler = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -291,17 +291,23 @@ const TESTS = {
|
||||||
// the text passed as argument
|
// the text passed as argument
|
||||||
function onConsoleWarningLogged(warningMessage) {
|
function onConsoleWarningLogged(warningMessage) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const observer = {
|
const ConsoleAPIStorage = Cc[
|
||||||
observe(subject) {
|
"@mozilla.org/consoleAPI-storage;1"
|
||||||
// This is the first argument passed to console.warn()
|
].getService(Ci.nsIConsoleAPIStorage);
|
||||||
const message = subject.wrappedJSObject.arguments[0];
|
|
||||||
if (message.includes(warningMessage)) {
|
const observer = subject => {
|
||||||
Services.obs.removeObserver(observer, "console-api-log-event");
|
// This is the first argument passed to console.warn()
|
||||||
resolve();
|
const message = subject.wrappedJSObject.arguments[0];
|
||||||
}
|
if (message.includes(warningMessage)) {
|
||||||
},
|
ConsoleAPIStorage.removeLogEventListener(observer);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
Services.obs.addObserver(observer, "console-api-log-event");
|
|
||||||
|
ConsoleAPIStorage.addLogEventListener(
|
||||||
|
observer,
|
||||||
|
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1532,15 +1532,13 @@ void MainThreadConsoleData::ProcessCallData(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsAutoString innerID, outerID;
|
nsAutoString innerID;
|
||||||
|
|
||||||
MOZ_ASSERT(aData->mIDType != ConsoleCallData::eUnknown);
|
MOZ_ASSERT(aData->mIDType != ConsoleCallData::eUnknown);
|
||||||
if (aData->mIDType == ConsoleCallData::eString) {
|
if (aData->mIDType == ConsoleCallData::eString) {
|
||||||
outerID = aData->mOuterIDString;
|
|
||||||
innerID = aData->mInnerIDString;
|
innerID = aData->mInnerIDString;
|
||||||
} else {
|
} else {
|
||||||
MOZ_ASSERT(aData->mIDType == ConsoleCallData::eNumber);
|
MOZ_ASSERT(aData->mIDType == ConsoleCallData::eNumber);
|
||||||
outerID.AppendInt(aData->mOuterIDNumber);
|
|
||||||
innerID.AppendInt(aData->mInnerIDNumber);
|
innerID.AppendInt(aData->mInnerIDNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1549,7 +1547,7 @@ void MainThreadConsoleData::ProcessCallData(
|
||||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "ClearEvents failed");
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "ClearEvents failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NS_FAILED(mStorage->RecordEvent(innerID, outerID, eventValue))) {
|
if (NS_FAILED(mStorage->RecordEvent(innerID, eventValue))) {
|
||||||
NS_WARNING("Failed to record a console event.");
|
NS_WARNING("Failed to record a console event.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,12 @@ const STORAGE_MAX_EVENTS = 1000;
|
||||||
|
|
||||||
var _consoleStorage = new Map();
|
var _consoleStorage = new Map();
|
||||||
|
|
||||||
|
// NOTE: these listeners used to just be added as observers and notified via
|
||||||
|
// Services.obs.notifyObservers. However, that has enough overhead to be a
|
||||||
|
// problem for this. Using an explicit global array is much cheaper, and
|
||||||
|
// should be equivalent.
|
||||||
|
var _logEventListeners = [];
|
||||||
|
|
||||||
const CONSOLEAPISTORAGE_CID = Components.ID(
|
const CONSOLEAPISTORAGE_CID = Components.ID(
|
||||||
"{96cf7855-dfa9-4c6d-8276-f9705b4890f2}"
|
"{96cf7855-dfa9-4c6d-8276-f9705b4890f2}"
|
||||||
);
|
);
|
||||||
|
@ -94,19 +100,59 @@ ConsoleAPIStorageService.prototype = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a listener to be notified of log events.
|
||||||
|
*
|
||||||
|
* @param jsval [aListener]
|
||||||
|
* A JS listener which will be notified with the message object when
|
||||||
|
* a log event occurs.
|
||||||
|
* @param nsIPrincipal [aPrincipal]
|
||||||
|
* The principal of the listener - used to determine if we need to
|
||||||
|
* clone the message before forwarding it.
|
||||||
|
*/
|
||||||
|
addLogEventListener: function CS_addLogEventListener(aListener, aPrincipal) {
|
||||||
|
// If our listener has a less-privileged principal than us, then they won't
|
||||||
|
// be able to access the log event object which was populated for our
|
||||||
|
// scope. Accordingly we need to clone it for these listeners.
|
||||||
|
//
|
||||||
|
// XXX: AFAICT these listeners which we need to clone messages for are all
|
||||||
|
// tests. Alternative solutions are welcome.
|
||||||
|
const clone = !aPrincipal.subsumes(
|
||||||
|
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal)
|
||||||
|
);
|
||||||
|
_logEventListeners.push({
|
||||||
|
callback: aListener,
|
||||||
|
clone,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a listener added with `addLogEventListener`.
|
||||||
|
*
|
||||||
|
* @param jsval [aListener]
|
||||||
|
* A JS listener which was added with `addLogEventListener`.
|
||||||
|
*/
|
||||||
|
removeLogEventListener: function CS_removeLogEventListener(aListener) {
|
||||||
|
const index = _logEventListeners.findIndex(l => l.callback === aListener);
|
||||||
|
if (index != -1) {
|
||||||
|
_logEventListeners.splice(index, 1);
|
||||||
|
} else {
|
||||||
|
Cu.reportError(
|
||||||
|
"Attempted to remove a log event listener that does not exist."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Record an event associated with the given window ID.
|
* Record an event associated with the given window ID.
|
||||||
*
|
*
|
||||||
* @param string aId
|
* @param string aId
|
||||||
* The ID of the inner window for which the event occurred or "jsm" for
|
* The ID of the inner window for which the event occurred or "jsm" for
|
||||||
* messages logged from JavaScript modules..
|
* messages logged from JavaScript modules..
|
||||||
* @param string aOuterId
|
|
||||||
* This ID is used as 3rd parameters for the console-api-log-event
|
|
||||||
* notification.
|
|
||||||
* @param object aEvent
|
* @param object aEvent
|
||||||
* A JavaScript object you want to store.
|
* A JavaScript object you want to store.
|
||||||
*/
|
*/
|
||||||
recordEvent: function CS_recordEvent(aId, aOuterId, aEvent) {
|
recordEvent: function CS_recordEvent(aId, aEvent) {
|
||||||
if (!_consoleStorage.has(aId)) {
|
if (!_consoleStorage.has(aId)) {
|
||||||
_consoleStorage.set(aId, []);
|
_consoleStorage.set(aId, []);
|
||||||
}
|
}
|
||||||
|
@ -120,8 +166,13 @@ ConsoleAPIStorageService.prototype = {
|
||||||
storage.shift();
|
storage.shift();
|
||||||
}
|
}
|
||||||
|
|
||||||
Services.obs.notifyObservers(aEvent, "console-api-log-event", aOuterId);
|
for (let { callback, clone } of _logEventListeners) {
|
||||||
Services.obs.notifyObservers(aEvent, "console-storage-cache-event", aId);
|
if (clone) {
|
||||||
|
callback(Cu.cloneInto(aEvent, callback));
|
||||||
|
} else {
|
||||||
|
callback(aEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -138,7 +138,7 @@ void ConsoleUtils::ReportForServiceWorkerScopeInternal(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
storage->RecordEvent(u"ServiceWorker"_ns, aScope, eventValue);
|
storage->RecordEvent(u"ServiceWorker"_ns, eventValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject* ConsoleUtils::GetOrCreateSandbox(JSContext* aCx) {
|
JSObject* ConsoleUtils::GetOrCreateSandbox(JSContext* aCx) {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "nsISupports.idl"
|
#include "nsISupports.idl"
|
||||||
|
#include "nsIPrincipal.idl"
|
||||||
|
|
||||||
[scriptable, uuid(9e32a7b6-c4d1-4d9a-87b9-1ef6b75c27a9)]
|
[scriptable, uuid(9e32a7b6-c4d1-4d9a-87b9-1ef6b75c27a9)]
|
||||||
interface nsIConsoleAPIStorage : nsISupports
|
interface nsIConsoleAPIStorage : nsISupports
|
||||||
|
@ -21,19 +22,36 @@ interface nsIConsoleAPIStorage : nsISupports
|
||||||
*/
|
*/
|
||||||
jsval getEvents([optional] in AString aId);
|
jsval getEvents([optional] in AString aId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a listener to be notified of log events.
|
||||||
|
*
|
||||||
|
* @param jsval [aListener]
|
||||||
|
* A JS listener which will be notified with the message object when
|
||||||
|
* a log event occurs.
|
||||||
|
* @param nsIPrincipal [aPrincipal]
|
||||||
|
* The principal of the listener - used to determine if we need to
|
||||||
|
* clone the message before forwarding it.
|
||||||
|
*/
|
||||||
|
void addLogEventListener(in jsval aListener, in nsIPrincipal aPrincipal);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a listener added with `addLogEventListener`.
|
||||||
|
*
|
||||||
|
* @param jsval [aListener]
|
||||||
|
* A JS listener which was added with `addLogEventListener`.
|
||||||
|
*/
|
||||||
|
void removeLogEventListener(in jsval aListener);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Record an event associated with the given window ID.
|
* Record an event associated with the given window ID.
|
||||||
*
|
*
|
||||||
* @param string aId
|
* @param string aId
|
||||||
* The ID of the inner window for which the event occurred or "jsm" for
|
* The ID of the inner window for which the event occurred or "jsm" for
|
||||||
* messages logged from JavaScript modules..
|
* messages logged from JavaScript modules..
|
||||||
* @param string aOuterId
|
|
||||||
* This ID is used as 3rd parameters for the console-api-log-event
|
|
||||||
* notification.
|
|
||||||
* @param object aEvent
|
* @param object aEvent
|
||||||
* A JavaScript object you want to store.
|
* A JavaScript object you want to store.
|
||||||
*/
|
*/
|
||||||
void recordEvent(in AString aId, in AString aOuterId, in jsval aEvent);
|
void recordEvent(in AString aId, in jsval aEvent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear storage data for the given window.
|
* Clear storage data for the given window.
|
||||||
|
|
|
@ -3,6 +3,7 @@ skip-if = os == 'android'
|
||||||
support-files =
|
support-files =
|
||||||
file_empty.html
|
file_empty.html
|
||||||
console.jsm
|
console.jsm
|
||||||
|
head.js
|
||||||
|
|
||||||
[test_console.xhtml]
|
[test_console.xhtml]
|
||||||
[test_jsm.xhtml]
|
[test_jsm.xhtml]
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/**
|
||||||
|
* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
*/
|
||||||
|
|
||||||
|
const ConsoleAPIStorage = SpecialPowers.Cc[
|
||||||
|
"@mozilla.org/consoleAPI-storage;1"
|
||||||
|
].getService(SpecialPowers.Ci.nsIConsoleAPIStorage);
|
||||||
|
|
||||||
|
// This is intended to just be a drop-in replacement for an old observer
|
||||||
|
// notification.
|
||||||
|
function addConsoleStorageListener(listener) {
|
||||||
|
listener.__handler = (message, id) => {
|
||||||
|
listener.observe(message, id);
|
||||||
|
};
|
||||||
|
ConsoleAPIStorage.addLogEventListener(
|
||||||
|
listener.__handler,
|
||||||
|
SpecialPowers.wrap(document).nodePrincipal
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeConsoleStorageListener(listener) {
|
||||||
|
ConsoleAPIStorage.removeLogEventListener(listener.__handler);
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
support-files =
|
support-files =
|
||||||
file_empty.html
|
file_empty.html
|
||||||
|
head.js
|
||||||
|
|
||||||
[test_bug659625.html]
|
[test_bug659625.html]
|
||||||
[test_bug978522.html]
|
[test_bug978522.html]
|
||||||
|
|
|
@ -4,30 +4,28 @@
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Test Console binding</title>
|
<title>Test Console binding</title>
|
||||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script src="head.js"></script>
|
||||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
|
|
||||||
function consoleListener() {
|
function consoleListener() {
|
||||||
SpecialPowers.addObserver(this, "console-api-log-event");
|
addConsoleStorageListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
var order = 0;
|
var order = 0;
|
||||||
consoleListener.prototype = {
|
consoleListener.prototype = {
|
||||||
observe(aSubject, aTopic, aData) {
|
observe(obj) {
|
||||||
if (aTopic == "console-api-log-event") {
|
ok(!obj.chromeContext, "Thils is not a chrome context");
|
||||||
var obj = aSubject.wrappedJSObject;
|
if (order + 1 == parseInt(obj.arguments[0])) {
|
||||||
ok(!obj.chromeContext, "Thils is not a chrome context");
|
ok(true, "Message received: " + obj.arguments[0]);
|
||||||
if (order + 1 == parseInt(obj.arguments[0])) {
|
order++;
|
||||||
ok(true, "Message received: " + obj.arguments[0]);
|
}
|
||||||
order++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (order == 3) {
|
if (order == 3) {
|
||||||
SpecialPowers.removeObserver(this, "console-api-log-event");
|
removeConsoleStorageListener(this);
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Test for count/countReset in console</title>
|
<title>Test for count/countReset in console</title>
|
||||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script src="head.js"></script>
|
||||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -12,11 +13,11 @@
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
function ConsoleListener() {
|
function ConsoleListener() {
|
||||||
SpecialPowers.addObserver(this, "console-api-log-event");
|
addConsoleStorageListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConsoleListener.prototype = {
|
ConsoleListener.prototype = {
|
||||||
observe(aSubject, aTopic, aData) {
|
observe(aSubject) {
|
||||||
let obj = aSubject.wrappedJSObject;
|
let obj = aSubject.wrappedJSObject;
|
||||||
if (obj.arguments[0] != "test") {
|
if (obj.arguments[0] != "test") {
|
||||||
return;
|
return;
|
||||||
|
@ -36,7 +37,7 @@ ConsoleListener.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
shutdown() {
|
shutdown() {
|
||||||
SpecialPowers.removeObserver(this, "console-api-log-event");
|
removeConsoleStorageListener(this);
|
||||||
},
|
},
|
||||||
|
|
||||||
waitFor(cb) {
|
waitFor(cb) {
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||||
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||||
|
<script src="head.js"/>
|
||||||
|
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
|
@ -29,52 +30,50 @@ function promiseConsoleListenerCalled() {
|
||||||
let consoleListener = {
|
let consoleListener = {
|
||||||
count: 0,
|
count: 0,
|
||||||
|
|
||||||
observe: function(aSubject, aTopic, aData) {
|
observe: function(aSubject) {
|
||||||
if (aTopic == "console-api-log-event") {
|
var obj = aSubject.wrappedJSObject;
|
||||||
var obj = aSubject.wrappedJSObject;
|
ok(obj.chromeContext, "JSM is always a chrome context");
|
||||||
ok(obj.chromeContext, "JSM is always a chrome context");
|
|
||||||
|
|
||||||
if (obj.innerID == JSM) {
|
if (obj.innerID == JSM) {
|
||||||
is(obj.ID, "jsm", "ID and InnerID are correctly set.");
|
is(obj.ID, "jsm", "ID and InnerID are correctly set.");
|
||||||
is(obj.arguments[0], "Hello world!", "Message matches");
|
is(obj.arguments[0], "Hello world!", "Message matches");
|
||||||
is(obj.consoleID, "", "No consoleID for console API");
|
is(obj.consoleID, "", "No consoleID for console API");
|
||||||
is(obj.prefix, "", "prefix is empty by default");
|
is(obj.prefix, "", "prefix is empty by default");
|
||||||
|
|
||||||
// We want to see 2 messages from this innerID, the first is generated
|
// We want to see 2 messages from this innerID, the first is generated
|
||||||
// by console.log, the second one from createInstance().log();
|
// by console.log, the second one from createInstance().log();
|
||||||
++this.count;
|
++this.count;
|
||||||
} else if (obj.innerID == "CUSTOM INNER") {
|
} else if (obj.innerID == "CUSTOM INNER") {
|
||||||
is(obj.ID, "jsm", "ID and InnerID are correctly set.");
|
is(obj.ID, "jsm", "ID and InnerID are correctly set.");
|
||||||
is(obj.arguments[0], "Hello world!", "Message matches");
|
is(obj.arguments[0], "Hello world!", "Message matches");
|
||||||
is(obj.consoleID, "wow", "consoleID is set by consoleInstance");
|
is(obj.consoleID, "wow", "consoleID is set by consoleInstance");
|
||||||
is(obj.prefix, "_PREFIX_", "prefix is set by consoleInstance");
|
is(obj.prefix, "_PREFIX_", "prefix is set by consoleInstance");
|
||||||
// We expect to see 2 messages from this innerID.
|
// We expect to see 2 messages from this innerID.
|
||||||
++this.count;
|
++this.count;
|
||||||
} else if (obj.innerID == "LEVEL") {
|
} else if (obj.innerID == "LEVEL") {
|
||||||
// Nothing special... just we don't want to see 'invisible' messages.
|
// Nothing special... just we don't want to see 'invisible' messages.
|
||||||
is(obj.ID, "jsm", "ID and InnerID are correctly set.");
|
is(obj.ID, "jsm", "ID and InnerID are correctly set.");
|
||||||
is(obj.arguments[0], "Hello world!", "Message matches");
|
is(obj.arguments[0], "Hello world!", "Message matches");
|
||||||
is(obj.prefix, "", "prefix is empty by default");
|
is(obj.prefix, "", "prefix is empty by default");
|
||||||
// We expect to see 2 messages from this innerID.
|
// We expect to see 2 messages from this innerID.
|
||||||
++this.count;
|
++this.count;
|
||||||
} else if (obj.innerID == "NO PREF") {
|
} else if (obj.innerID == "NO PREF") {
|
||||||
// Nothing special... just we don't want to see 'invisible' messages.
|
// Nothing special... just we don't want to see 'invisible' messages.
|
||||||
is(obj.ID, "jsm", "ID and InnerID are correctly set.");
|
is(obj.ID, "jsm", "ID and InnerID are correctly set.");
|
||||||
is(obj.arguments[0], "Hello world!", "Message matches");
|
is(obj.arguments[0], "Hello world!", "Message matches");
|
||||||
is(obj.prefix, "", "prefix is empty by default");
|
is(obj.prefix, "", "prefix is empty by default");
|
||||||
// We expect to see 2 messages from this innerID.
|
// We expect to see 2 messages from this innerID.
|
||||||
++this.count;
|
++this.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.count == 8) {
|
if (this.count == 8) {
|
||||||
is(dumpCalled, 2, "Dump has been called!");
|
is(dumpCalled, 2, "Dump has been called!");
|
||||||
Services.obs.removeObserver(consoleListener, "console-api-log-event");
|
removeConsoleStorageListener(consoleListener);
|
||||||
resolve();
|
resolve();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Services.obs.addObserver(consoleListener, "console-api-log-event");
|
addConsoleStorageListener(consoleListener);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Test for timeStart/timeLog/timeEnd in console</title>
|
<title>Test for timeStart/timeLog/timeEnd in console</title>
|
||||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script src="head.js"></script>
|
||||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -15,11 +16,11 @@ var reduceTimePrecisionPrevPrefValue = SpecialPowers.getBoolPref("privacy.reduce
|
||||||
SpecialPowers.setBoolPref("privacy.reduceTimerPrecision", false);
|
SpecialPowers.setBoolPref("privacy.reduceTimerPrecision", false);
|
||||||
|
|
||||||
function ConsoleListener() {
|
function ConsoleListener() {
|
||||||
SpecialPowers.addObserver(this, "console-api-log-event");
|
addConsoleStorageListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConsoleListener.prototype = {
|
ConsoleListener.prototype = {
|
||||||
observe(aSubject, aTopic, aData) {
|
observe(aSubject) {
|
||||||
let obj = aSubject.wrappedJSObject;
|
let obj = aSubject.wrappedJSObject;
|
||||||
if (obj.arguments[0] != "test_bug1463614") {
|
if (obj.arguments[0] != "test_bug1463614") {
|
||||||
return;
|
return;
|
||||||
|
@ -34,7 +35,7 @@ ConsoleListener.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
shutdown() {
|
shutdown() {
|
||||||
SpecialPowers.removeObserver(this, "console-api-log-event");
|
removeConsoleStorageListener(this);
|
||||||
},
|
},
|
||||||
|
|
||||||
waitFor(cb) {
|
waitFor(cb) {
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
const ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"].getService(
|
||||||
|
Ci.nsIConsoleAPIStorage
|
||||||
|
);
|
||||||
|
|
||||||
|
// This is intended to just be a drop-in replacement for an old observer
|
||||||
|
// notification.
|
||||||
|
function addConsoleStorageListener(listener) {
|
||||||
|
listener.__handler = (message, id) => {
|
||||||
|
listener.observe(message, id);
|
||||||
|
};
|
||||||
|
ConsoleAPIStorage.addLogEventListener(
|
||||||
|
listener.__handler,
|
||||||
|
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeConsoleStorageListener(listener) {
|
||||||
|
ConsoleAPIStorage.removeLogEventListener(listener.__handler);
|
||||||
|
}
|
|
@ -8,17 +8,17 @@ add_task(async function() {
|
||||||
|
|
||||||
let p = new Promise(resolve => {
|
let p = new Promise(resolve => {
|
||||||
function consoleListener() {
|
function consoleListener() {
|
||||||
Services.obs.addObserver(this, "console-api-log-event");
|
addConsoleStorageListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
consoleListener.prototype = {
|
consoleListener.prototype = {
|
||||||
observe(aSubject, aTopic, aData) {
|
observe(aSubject) {
|
||||||
let obj = aSubject.wrappedJSObject;
|
let obj = aSubject.wrappedJSObject;
|
||||||
Assert.ok(obj.arguments[0] === 42, "Message received!");
|
Assert.ok(obj.arguments[0] === 42, "Message received!");
|
||||||
Assert.ok(obj.ID === "jsm", "The ID is JSM");
|
Assert.ok(obj.ID === "jsm", "The ID is JSM");
|
||||||
Assert.ok(obj.innerID.endsWith("test_basic.js"), "The innerID matches");
|
Assert.ok(obj.innerID.endsWith("test_basic.js"), "The innerID matches");
|
||||||
|
|
||||||
Services.obs.removeObserver(this, "console-api-log-event");
|
removeConsoleStorageListener(this);
|
||||||
resolve();
|
resolve();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -40,11 +40,11 @@ add_task(async function() {
|
||||||
let t = 0;
|
let t = 0;
|
||||||
|
|
||||||
function consoleListener() {
|
function consoleListener() {
|
||||||
Services.obs.addObserver(this, "console-api-log-event");
|
addConsoleStorageListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
consoleListener.prototype = {
|
consoleListener.prototype = {
|
||||||
observe(aSubject, aTopic, aData) {
|
observe(aSubject) {
|
||||||
let test = tests[t++];
|
let test = tests[t++];
|
||||||
|
|
||||||
let obj = aSubject.wrappedJSObject;
|
let obj = aSubject.wrappedJSObject;
|
||||||
|
@ -62,7 +62,7 @@ add_task(async function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t === tests.length) {
|
if (t === tests.length) {
|
||||||
Services.obs.removeObserver(this, "console-api-log-event");
|
removeConsoleStorageListener(this);
|
||||||
resolve();
|
resolve();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -6,11 +6,11 @@ const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||||
add_task(async function() {
|
add_task(async function() {
|
||||||
let p = new Promise(resolve => {
|
let p = new Promise(resolve => {
|
||||||
function consoleListener() {
|
function consoleListener() {
|
||||||
Services.obs.addObserver(this, "console-api-log-event");
|
addConsoleStorageListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
consoleListener.prototype = {
|
consoleListener.prototype = {
|
||||||
observe(aSubject, aTopic, aData) {
|
observe(aSubject) {
|
||||||
let obj = aSubject.wrappedJSObject;
|
let obj = aSubject.wrappedJSObject;
|
||||||
Assert.ok(obj.arguments[0] === "Hello world!", "Message received!");
|
Assert.ok(obj.arguments[0] === "Hello world!", "Message received!");
|
||||||
Assert.ok(obj.ID === "scope", "The ID is the scope");
|
Assert.ok(obj.ID === "scope", "The ID is the scope");
|
||||||
|
@ -23,7 +23,7 @@ add_task(async function() {
|
||||||
Assert.ok(obj.columnNumber === 24, "The columnNumber matches");
|
Assert.ok(obj.columnNumber === 24, "The columnNumber matches");
|
||||||
Assert.ok(obj.level === "error", "The level is correct");
|
Assert.ok(obj.level === "error", "The level is correct");
|
||||||
|
|
||||||
Services.obs.removeObserver(this, "console-api-log-event");
|
removeConsoleStorageListener(this);
|
||||||
resolve();
|
resolve();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
head =
|
head = head.js
|
||||||
support-files =
|
support-files =
|
||||||
|
|
||||||
[test_basic.js]
|
[test_basic.js]
|
||||||
|
|
|
@ -41,8 +41,6 @@ support-files =
|
||||||
support-files =
|
support-files =
|
||||||
prevent_return_key.html
|
prevent_return_key.html
|
||||||
[browser_ConsoleAPI_originAttributes.js]
|
[browser_ConsoleAPI_originAttributes.js]
|
||||||
[browser_ConsoleAPITests.js]
|
|
||||||
skip-if = e10s
|
|
||||||
[browser_ConsoleStorageAPITests.js]
|
[browser_ConsoleStorageAPITests.js]
|
||||||
[browser_ConsoleStoragePBTest_perwindowpb.js]
|
[browser_ConsoleStoragePBTest_perwindowpb.js]
|
||||||
[browser_data_document_crossOriginIsolated.js]
|
[browser_data_document_crossOriginIsolated.js]
|
||||||
|
|
|
@ -1,638 +0,0 @@
|
||||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
const TEST_URI =
|
|
||||||
"http://example.com/browser/dom/tests/browser/test-console-api.html";
|
|
||||||
|
|
||||||
add_task(async function() {
|
|
||||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URI);
|
|
||||||
registerCleanupFunction(() => gBrowser.removeTab(tab));
|
|
||||||
let browser = gBrowser.selectedBrowser;
|
|
||||||
|
|
||||||
await consoleAPISanityTest(browser);
|
|
||||||
await observeConsoleTest(browser);
|
|
||||||
await startTraceTest(browser);
|
|
||||||
await startLocationTest(browser);
|
|
||||||
await startNativeCallbackTest(browser);
|
|
||||||
await startGroupTest(browser);
|
|
||||||
await startTimeTest(browser);
|
|
||||||
await startTimeEndTest(browser);
|
|
||||||
await startTimeStampTest(browser);
|
|
||||||
await startEmptyTimeStampTest(browser);
|
|
||||||
await startEmptyTimerTest(browser);
|
|
||||||
});
|
|
||||||
|
|
||||||
function spawnWithObserver(browser, observerFunc, func) {
|
|
||||||
// Build the observer generating function.
|
|
||||||
let source = [
|
|
||||||
"const TEST_URI = 'http://example.com/browser/dom/tests/browser/test-console-api.html';",
|
|
||||||
// Create a promise to be resolved when the text is complete. It is stored
|
|
||||||
// on content, such that it can be waited on by calling waitForResolve. This
|
|
||||||
// is done rather than returning it from this function such that the
|
|
||||||
// initialization can be yeilded on before yeilding on the conclusion of the
|
|
||||||
// test.
|
|
||||||
"content._promise = new Promise(_resolve => {",
|
|
||||||
// These are variables which are used by the test runner to communicate
|
|
||||||
// state to the observer.
|
|
||||||
" let gLevel, gArgs, gStyle;",
|
|
||||||
" let expect = function(level) {",
|
|
||||||
" gLevel = level;",
|
|
||||||
" gArgs = Array.prototype.slice.call(arguments, 1);",
|
|
||||||
" }",
|
|
||||||
// To ease the transition to the new format, content.window is avaliable as gWindow
|
|
||||||
// in the content.
|
|
||||||
" let gWindow = content.window;",
|
|
||||||
// This method is called rather than _resolve such that the observer is removed
|
|
||||||
// before exiting the test
|
|
||||||
" let resolve = () => {",
|
|
||||||
" Services.obs.removeObserver(ConsoleObserver, 'console-api-log-event');",
|
|
||||||
" _resolve();",
|
|
||||||
" };",
|
|
||||||
// This is the observer itself, it calls the passed-in function whenever
|
|
||||||
// it encounters an event
|
|
||||||
" let ConsoleObserver = {",
|
|
||||||
" QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver]),",
|
|
||||||
" observe: function(aSubject, aTopic, aData) {",
|
|
||||||
" try {",
|
|
||||||
" (" + observerFunc.toString() + ")(aSubject.wrappedJSObject);",
|
|
||||||
" } catch (ex) {",
|
|
||||||
" ok(false, 'Exception thrown in observe: ' + ex);",
|
|
||||||
" }",
|
|
||||||
" }",
|
|
||||||
" };",
|
|
||||||
" Services.obs.addObserver(ConsoleObserver, 'console-api-log-event', false);",
|
|
||||||
// Call the initialization function (if present)
|
|
||||||
func ? "(" + func.toString() + ")();" : "",
|
|
||||||
"});",
|
|
||||||
].join("\n");
|
|
||||||
|
|
||||||
return SpecialPowers.spawn(browser, [], new Function(source));
|
|
||||||
}
|
|
||||||
|
|
||||||
function waitForResolve(browser) {
|
|
||||||
return SpecialPowers.spawn(browser, [], function() {
|
|
||||||
return content._promise;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function consoleAPISanityTest(browser) {
|
|
||||||
await SpecialPowers.spawn(browser, [], function() {
|
|
||||||
let win = XPCNativeWrapper.unwrap(content.window);
|
|
||||||
|
|
||||||
ok(win.console, "we have a console attached");
|
|
||||||
ok(win.console, "we have a console attached, 2nd attempt");
|
|
||||||
|
|
||||||
ok(win.console.log, "console.log is here");
|
|
||||||
ok(win.console.info, "console.info is here");
|
|
||||||
ok(win.console.warn, "console.warn is here");
|
|
||||||
ok(win.console.error, "console.error is here");
|
|
||||||
ok(win.console.exception, "console.exception is here");
|
|
||||||
ok(win.console.trace, "console.trace is here");
|
|
||||||
ok(win.console.dir, "console.dir is here");
|
|
||||||
ok(win.console.group, "console.group is here");
|
|
||||||
ok(win.console.groupCollapsed, "console.groupCollapsed is here");
|
|
||||||
ok(win.console.groupEnd, "console.groupEnd is here");
|
|
||||||
ok(win.console.time, "console.time is here");
|
|
||||||
ok(win.console.timeEnd, "console.timeEnd is here");
|
|
||||||
ok(win.console.timeStamp, "console.timeStamp is here");
|
|
||||||
ok(win.console.assert, "console.assert is here");
|
|
||||||
ok(win.console.count, "console.count is here");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// These globals are all defined in spawnWithObserver in a sub-process.
|
|
||||||
/* global gWindow, gArgs:true, gLevel:true, gStyle:true, expect, resolve */
|
|
||||||
function testConsoleData(aMessageObject) {
|
|
||||||
let messageWindow = Services.wm.getOuterWindowWithId(aMessageObject.ID);
|
|
||||||
is(messageWindow, gWindow, "found correct window by window ID");
|
|
||||||
|
|
||||||
is(aMessageObject.level, gLevel, "expected level received");
|
|
||||||
ok(aMessageObject.arguments, "we have arguments");
|
|
||||||
|
|
||||||
switch (gLevel) {
|
|
||||||
case "trace": {
|
|
||||||
is(aMessageObject.arguments.length, 0, "arguments.length matches");
|
|
||||||
is(
|
|
||||||
aMessageObject.stacktrace.toSource(),
|
|
||||||
gArgs.toSource(),
|
|
||||||
"stack trace is correct"
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "count": {
|
|
||||||
is(aMessageObject.counter.label, gArgs[0].label, "label matches");
|
|
||||||
is(aMessageObject.counter.count, gArgs[0].count, "count matches");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
is(
|
|
||||||
aMessageObject.arguments.length,
|
|
||||||
gArgs.length,
|
|
||||||
"arguments.length matches"
|
|
||||||
);
|
|
||||||
gArgs.forEach(function(a, i) {
|
|
||||||
// Waive Xray so that we don't get messed up by Xray ToString.
|
|
||||||
//
|
|
||||||
// It'd be nice to just use XPCNativeWrapper.unwrap here, but there are
|
|
||||||
// a number of dumb reasons we can't. See bug 868675.
|
|
||||||
var arg = aMessageObject.arguments[i];
|
|
||||||
if (Cu.isXrayWrapper(arg)) {
|
|
||||||
arg = arg.wrappedJSObject;
|
|
||||||
}
|
|
||||||
is(arg, a, "correct arg " + i);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (gStyle) {
|
|
||||||
is(
|
|
||||||
aMessageObject.styles.length,
|
|
||||||
gStyle.length,
|
|
||||||
"styles.length matches"
|
|
||||||
);
|
|
||||||
is(aMessageObject.styles + "", gStyle + "", "styles match");
|
|
||||||
} else {
|
|
||||||
ok(
|
|
||||||
!aMessageObject.styles || aMessageObject.styles.length === 0,
|
|
||||||
"styles match"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function observeConsoleTest(browser) {
|
|
||||||
await spawnWithObserver(browser, testConsoleData, function(opts) {
|
|
||||||
let win = XPCNativeWrapper.unwrap(content.window);
|
|
||||||
expect("log", "arg");
|
|
||||||
win.console.log("arg");
|
|
||||||
|
|
||||||
expect("info", "arg", "extra arg");
|
|
||||||
win.console.info("arg", "extra arg");
|
|
||||||
|
|
||||||
expect("warn", "Lesson 1: PI is approximately equal to 3");
|
|
||||||
win.console.warn(
|
|
||||||
"Lesson %d: %s is approximately equal to %1.0f",
|
|
||||||
1,
|
|
||||||
"PI",
|
|
||||||
3.14159
|
|
||||||
);
|
|
||||||
|
|
||||||
expect("warn", "Lesson 1: PI is approximately equal to 3.14");
|
|
||||||
win.console.warn(
|
|
||||||
"Lesson %d: %s is approximately equal to %1.2f",
|
|
||||||
1,
|
|
||||||
"PI",
|
|
||||||
3.14159
|
|
||||||
);
|
|
||||||
|
|
||||||
expect("warn", "Lesson 1: PI is approximately equal to 3.141590");
|
|
||||||
win.console.warn(
|
|
||||||
"Lesson %d: %s is approximately equal to %f",
|
|
||||||
1,
|
|
||||||
"PI",
|
|
||||||
3.14159
|
|
||||||
);
|
|
||||||
|
|
||||||
expect("warn", "Lesson 1: PI is approximately equal to 3.1415900");
|
|
||||||
win.console.warn(
|
|
||||||
"Lesson %d: %s is approximately equal to %0.7f",
|
|
||||||
1,
|
|
||||||
"PI",
|
|
||||||
3.14159
|
|
||||||
);
|
|
||||||
|
|
||||||
expect("log", "%d, %s, %l");
|
|
||||||
win.console.log("%d, %s, %l");
|
|
||||||
|
|
||||||
expect("log", "%a %b %g");
|
|
||||||
win.console.log("%a %b %g");
|
|
||||||
|
|
||||||
expect("log", "%a %b %g", "a", "b");
|
|
||||||
win.console.log("%a %b %g", "a", "b");
|
|
||||||
|
|
||||||
expect("log", "2, a, %l", 3);
|
|
||||||
win.console.log("%d, %s, %l", 2, "a", 3);
|
|
||||||
|
|
||||||
// Bug #692550 handle null and undefined.
|
|
||||||
expect("log", "null, undefined");
|
|
||||||
win.console.log("%s, %s", null, undefined);
|
|
||||||
|
|
||||||
// Bug #696288 handle object as first argument.
|
|
||||||
let obj = { a: 1 };
|
|
||||||
expect("log", obj, "a");
|
|
||||||
win.console.log(obj, "a");
|
|
||||||
|
|
||||||
expect("dir", win.toString());
|
|
||||||
win.console.dir(win);
|
|
||||||
|
|
||||||
expect("error", "arg");
|
|
||||||
win.console.error("arg");
|
|
||||||
|
|
||||||
expect("exception", "arg");
|
|
||||||
win.console.exception("arg");
|
|
||||||
|
|
||||||
expect("log", "foobar");
|
|
||||||
gStyle = ["color:red;foobar;;"];
|
|
||||||
win.console.log("%cfoobar", gStyle[0]);
|
|
||||||
|
|
||||||
let obj4 = { d: 4 };
|
|
||||||
expect("warn", "foobar", obj4, "test", "bazbazstr", "last");
|
|
||||||
gStyle = [null, null, null, "color:blue;", "color:red"];
|
|
||||||
win.console.warn(
|
|
||||||
"foobar%Otest%cbazbaz%s%clast",
|
|
||||||
obj4,
|
|
||||||
gStyle[3],
|
|
||||||
"str",
|
|
||||||
gStyle[4]
|
|
||||||
);
|
|
||||||
|
|
||||||
let obj3 = { c: 3 };
|
|
||||||
expect("info", "foobar", "bazbaz", obj3, "%comg", "color:yellow");
|
|
||||||
gStyle = [null, "color:pink;"];
|
|
||||||
win.console.info(
|
|
||||||
"foobar%cbazbaz",
|
|
||||||
gStyle[1],
|
|
||||||
obj3,
|
|
||||||
"%comg",
|
|
||||||
"color:yellow"
|
|
||||||
);
|
|
||||||
|
|
||||||
gStyle = null;
|
|
||||||
let obj2 = { b: 2 };
|
|
||||||
expect("log", "omg ", obj, " foo ", 4, obj2);
|
|
||||||
win.console.log("omg %o foo %o", obj, 4, obj2);
|
|
||||||
|
|
||||||
expect("assert", "message");
|
|
||||||
win.console.assert(false, "message");
|
|
||||||
|
|
||||||
expect("count", { label: "label a", count: 1 });
|
|
||||||
win.console.count("label a");
|
|
||||||
|
|
||||||
expect("count", { label: "label b", count: 1 });
|
|
||||||
win.console.count("label b");
|
|
||||||
|
|
||||||
expect("count", { label: "label a", count: 2 });
|
|
||||||
win.console.count("label a");
|
|
||||||
|
|
||||||
expect("count", { label: "label b", count: 2 });
|
|
||||||
win.console.count("label b");
|
|
||||||
dump("Resolving\n");
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
dump("There\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
function testTraceConsoleData(aMessageObject) {
|
|
||||||
let messageWindow = Services.wm.getOuterWindowWithId(aMessageObject.ID);
|
|
||||||
is(messageWindow, gWindow, "found correct window by window ID");
|
|
||||||
|
|
||||||
is(aMessageObject.level, gLevel, "expected level received");
|
|
||||||
ok(aMessageObject.arguments, "we have arguments");
|
|
||||||
|
|
||||||
is(gLevel, "trace", "gLevel should be trace");
|
|
||||||
is(aMessageObject.arguments.length, 0, "arguments.length matches");
|
|
||||||
dump(aMessageObject.stacktrace.toSource() + "\n" + gArgs.toSource() + "\n");
|
|
||||||
is(
|
|
||||||
aMessageObject.stacktrace.toSource(),
|
|
||||||
gArgs.toSource(),
|
|
||||||
"stack trace is correct"
|
|
||||||
);
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function startTraceTest(browser) {
|
|
||||||
dump("HERE\n");
|
|
||||||
await spawnWithObserver(browser, testTraceConsoleData, function(opts) {
|
|
||||||
dump("Observer attached\n");
|
|
||||||
gLevel = "trace";
|
|
||||||
gArgs = [
|
|
||||||
{
|
|
||||||
columnNumber: 9,
|
|
||||||
filename: TEST_URI,
|
|
||||||
functionName: "window.foobar585956c",
|
|
||||||
lineNumber: 6,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
columnNumber: 16,
|
|
||||||
filename: TEST_URI,
|
|
||||||
functionName: "foobar585956b",
|
|
||||||
lineNumber: 11,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
columnNumber: 16,
|
|
||||||
filename: TEST_URI,
|
|
||||||
functionName: "foobar585956a",
|
|
||||||
lineNumber: 15,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
columnNumber: 1,
|
|
||||||
filename: TEST_URI,
|
|
||||||
functionName: "onclick",
|
|
||||||
lineNumber: 1,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
BrowserTestUtils.synthesizeMouseAtCenter("#test-trace", {}, browser);
|
|
||||||
await waitForResolve(browser);
|
|
||||||
}
|
|
||||||
|
|
||||||
function testLocationData(aMessageObject) {
|
|
||||||
let messageWindow = Services.wm.getOuterWindowWithId(aMessageObject.ID);
|
|
||||||
is(messageWindow, gWindow, "found correct window by window ID");
|
|
||||||
|
|
||||||
is(aMessageObject.level, gLevel, "expected level received");
|
|
||||||
ok(aMessageObject.arguments, "we have arguments");
|
|
||||||
|
|
||||||
is(aMessageObject.filename, gArgs[0].filename, "filename matches");
|
|
||||||
is(aMessageObject.lineNumber, gArgs[0].lineNumber, "lineNumber matches");
|
|
||||||
is(
|
|
||||||
aMessageObject.functionName,
|
|
||||||
gArgs[0].functionName,
|
|
||||||
"functionName matches"
|
|
||||||
);
|
|
||||||
is(
|
|
||||||
aMessageObject.arguments.length,
|
|
||||||
gArgs[0].arguments.length,
|
|
||||||
"arguments.length matches"
|
|
||||||
);
|
|
||||||
gArgs[0].arguments.forEach(function(a, i) {
|
|
||||||
is(aMessageObject.arguments[i], a, "correct arg " + i);
|
|
||||||
});
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function startLocationTest(browser) {
|
|
||||||
await spawnWithObserver(browser, testLocationData, function(opts) {
|
|
||||||
gLevel = "log";
|
|
||||||
gArgs = [
|
|
||||||
{
|
|
||||||
filename: TEST_URI,
|
|
||||||
functionName: "foobar646025",
|
|
||||||
arguments: ["omg", "o", "d"],
|
|
||||||
lineNumber: 19,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
BrowserTestUtils.synthesizeMouseAtCenter("#test-location", {}, browser);
|
|
||||||
await waitForResolve(browser);
|
|
||||||
}
|
|
||||||
|
|
||||||
function testNativeCallback(aMessageObject) {
|
|
||||||
is(aMessageObject.level, "log", "expected level received");
|
|
||||||
is(aMessageObject.filename, "", "filename matches");
|
|
||||||
is(aMessageObject.lineNumber, 0, "lineNumber matches");
|
|
||||||
is(aMessageObject.functionName, "", "functionName matches");
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function startNativeCallbackTest(browser) {
|
|
||||||
await spawnWithObserver(browser, testNativeCallback);
|
|
||||||
|
|
||||||
BrowserTestUtils.synthesizeMouseAtCenter("#test-nativeCallback", {}, browser);
|
|
||||||
await waitForResolve(browser);
|
|
||||||
}
|
|
||||||
|
|
||||||
function testConsoleGroup(aMessageObject) {
|
|
||||||
let messageWindow = Services.wm.getOuterWindowWithId(aMessageObject.ID);
|
|
||||||
is(messageWindow, gWindow, "found correct window by window ID");
|
|
||||||
|
|
||||||
ok(
|
|
||||||
aMessageObject.level == "group" ||
|
|
||||||
aMessageObject.level == "groupCollapsed" ||
|
|
||||||
aMessageObject.level == "groupEnd",
|
|
||||||
"expected level received"
|
|
||||||
);
|
|
||||||
|
|
||||||
is(aMessageObject.functionName, "testGroups", "functionName matches");
|
|
||||||
ok(
|
|
||||||
aMessageObject.lineNumber >= 46 && aMessageObject.lineNumber <= 50,
|
|
||||||
"lineNumber matches"
|
|
||||||
);
|
|
||||||
if (aMessageObject.level == "groupCollapsed") {
|
|
||||||
is(aMessageObject.groupName, "a group", "groupCollapsed groupName matches");
|
|
||||||
is(aMessageObject.arguments[0], "a", "groupCollapsed arguments[0] matches");
|
|
||||||
is(
|
|
||||||
aMessageObject.arguments[1],
|
|
||||||
"group",
|
|
||||||
"groupCollapsed arguments[0] matches"
|
|
||||||
);
|
|
||||||
} else if (aMessageObject.level == "group") {
|
|
||||||
is(aMessageObject.groupName, "b group", "group groupName matches");
|
|
||||||
is(aMessageObject.arguments[0], "b", "group arguments[0] matches");
|
|
||||||
is(aMessageObject.arguments[1], "group", "group arguments[1] matches");
|
|
||||||
} else if (aMessageObject.level == "groupEnd") {
|
|
||||||
is(aMessageObject.groupName, "b group", "groupEnd groupName matches");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aMessageObject.level == "groupEnd") {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function startGroupTest(browser) {
|
|
||||||
await spawnWithObserver(browser, testConsoleGroup);
|
|
||||||
|
|
||||||
BrowserTestUtils.synthesizeMouseAtCenter("#test-groups", {}, browser);
|
|
||||||
await waitForResolve(browser);
|
|
||||||
}
|
|
||||||
|
|
||||||
function testConsoleTime(aMessageObject) {
|
|
||||||
let messageWindow = Services.wm.getOuterWindowWithId(aMessageObject.ID);
|
|
||||||
is(messageWindow, gWindow, "found correct window by window ID");
|
|
||||||
|
|
||||||
is(aMessageObject.level, gLevel, "expected level received");
|
|
||||||
|
|
||||||
is(aMessageObject.filename, gArgs[0].filename, "filename matches");
|
|
||||||
is(aMessageObject.lineNumber, gArgs[0].lineNumber, "lineNumber matches");
|
|
||||||
is(
|
|
||||||
aMessageObject.functionName,
|
|
||||||
gArgs[0].functionName,
|
|
||||||
"functionName matches"
|
|
||||||
);
|
|
||||||
is(aMessageObject.timer.name, gArgs[0].timer.name, "timer.name matches");
|
|
||||||
|
|
||||||
gArgs[0].arguments.forEach(function(a, i) {
|
|
||||||
is(aMessageObject.arguments[i], a, "correct arg " + i);
|
|
||||||
});
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function startTimeTest(browser) {
|
|
||||||
await spawnWithObserver(browser, testConsoleTime, function(opts) {
|
|
||||||
gLevel = "time";
|
|
||||||
gArgs = [
|
|
||||||
{
|
|
||||||
filename: TEST_URI,
|
|
||||||
lineNumber: 23,
|
|
||||||
functionName: "startTimer",
|
|
||||||
arguments: ["foo"],
|
|
||||||
timer: { name: "foo" },
|
|
||||||
},
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
BrowserTestUtils.synthesizeMouseAtCenter("#test-time", {}, browser);
|
|
||||||
await waitForResolve(browser);
|
|
||||||
}
|
|
||||||
|
|
||||||
function testConsoleTimeEnd(aMessageObject) {
|
|
||||||
let messageWindow = Services.wm.getOuterWindowWithId(aMessageObject.ID);
|
|
||||||
is(messageWindow, gWindow, "found correct window by window ID");
|
|
||||||
|
|
||||||
is(aMessageObject.level, gLevel, "expected level received");
|
|
||||||
ok(aMessageObject.arguments, "we have arguments");
|
|
||||||
|
|
||||||
is(aMessageObject.filename, gArgs[0].filename, "filename matches");
|
|
||||||
is(aMessageObject.lineNumber, gArgs[0].lineNumber, "lineNumber matches");
|
|
||||||
is(
|
|
||||||
aMessageObject.functionName,
|
|
||||||
gArgs[0].functionName,
|
|
||||||
"functionName matches"
|
|
||||||
);
|
|
||||||
is(
|
|
||||||
aMessageObject.arguments.length,
|
|
||||||
gArgs[0].arguments.length,
|
|
||||||
"arguments.length matches"
|
|
||||||
);
|
|
||||||
is(aMessageObject.timer.name, gArgs[0].timer.name, "timer name matches");
|
|
||||||
is(
|
|
||||||
typeof aMessageObject.timer.duration,
|
|
||||||
"number",
|
|
||||||
"timer duration is a number"
|
|
||||||
);
|
|
||||||
info("timer duration: " + aMessageObject.timer.duration);
|
|
||||||
ok(aMessageObject.timer.duration >= 0, "timer duration is positive");
|
|
||||||
|
|
||||||
gArgs[0].arguments.forEach(function(a, i) {
|
|
||||||
is(aMessageObject.arguments[i], a, "correct arg " + i);
|
|
||||||
});
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function startTimeEndTest(browser) {
|
|
||||||
await spawnWithObserver(browser, testConsoleTimeEnd, function(opts) {
|
|
||||||
gLevel = "timeEnd";
|
|
||||||
gArgs = [
|
|
||||||
{
|
|
||||||
filename: TEST_URI,
|
|
||||||
lineNumber: 27,
|
|
||||||
functionName: "stopTimer",
|
|
||||||
arguments: ["foo"],
|
|
||||||
timer: { name: "foo" },
|
|
||||||
},
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
BrowserTestUtils.synthesizeMouseAtCenter("#test-timeEnd", {}, browser);
|
|
||||||
await waitForResolve(browser);
|
|
||||||
}
|
|
||||||
|
|
||||||
function testConsoleTimeStamp(aMessageObject) {
|
|
||||||
let messageWindow = Services.wm.getOuterWindowWithId(aMessageObject.ID);
|
|
||||||
is(messageWindow, gWindow, "found correct window by window ID");
|
|
||||||
|
|
||||||
is(aMessageObject.level, gLevel, "expected level received");
|
|
||||||
|
|
||||||
is(aMessageObject.filename, gArgs[0].filename, "filename matches");
|
|
||||||
is(aMessageObject.lineNumber, gArgs[0].lineNumber, "lineNumber matches");
|
|
||||||
is(
|
|
||||||
aMessageObject.functionName,
|
|
||||||
gArgs[0].functionName,
|
|
||||||
"functionName matches"
|
|
||||||
);
|
|
||||||
ok(aMessageObject.timeStamp > 0, "timeStamp is a positive value");
|
|
||||||
|
|
||||||
gArgs[0].arguments.forEach(function(a, i) {
|
|
||||||
is(aMessageObject.arguments[i], a, "correct arg " + i);
|
|
||||||
});
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function startTimeStampTest(browser) {
|
|
||||||
await spawnWithObserver(browser, testConsoleTimeStamp, function() {
|
|
||||||
gLevel = "timeStamp";
|
|
||||||
gArgs = [
|
|
||||||
{
|
|
||||||
filename: TEST_URI,
|
|
||||||
lineNumber: 58,
|
|
||||||
functionName: "timeStamp",
|
|
||||||
arguments: ["!!!"],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
BrowserTestUtils.synthesizeMouseAtCenter("#test-timeStamp", {}, browser);
|
|
||||||
await waitForResolve(browser);
|
|
||||||
}
|
|
||||||
|
|
||||||
function testEmptyConsoleTimeStamp(aMessageObject) {
|
|
||||||
let messageWindow = Services.wm.getOuterWindowWithId(aMessageObject.ID);
|
|
||||||
is(messageWindow, gWindow, "found correct window by window ID");
|
|
||||||
|
|
||||||
is(aMessageObject.level, gLevel, "expected level received");
|
|
||||||
|
|
||||||
is(aMessageObject.filename, gArgs[0].filename, "filename matches");
|
|
||||||
is(aMessageObject.lineNumber, gArgs[0].lineNumber, "lineNumber matches");
|
|
||||||
is(
|
|
||||||
aMessageObject.functionName,
|
|
||||||
gArgs[0].functionName,
|
|
||||||
"functionName matches"
|
|
||||||
);
|
|
||||||
ok(aMessageObject.timeStamp > 0, "timeStamp is a positive value");
|
|
||||||
is(aMessageObject.arguments.length, 0, "we don't have arguments");
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function startEmptyTimeStampTest(browser) {
|
|
||||||
await spawnWithObserver(browser, testEmptyConsoleTimeStamp, function() {
|
|
||||||
gLevel = "timeStamp";
|
|
||||||
gArgs = [
|
|
||||||
{
|
|
||||||
filename: TEST_URI,
|
|
||||||
lineNumber: 58,
|
|
||||||
functionName: "timeStamp",
|
|
||||||
arguments: [],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
BrowserTestUtils.synthesizeMouseAtCenter("#test-emptyTimeStamp", {}, browser);
|
|
||||||
await waitForResolve(browser);
|
|
||||||
}
|
|
||||||
|
|
||||||
function testEmptyTimer(aMessageObject) {
|
|
||||||
let messageWindow = Services.wm.getOuterWindowWithId(aMessageObject.ID);
|
|
||||||
is(messageWindow, gWindow, "found correct window by window ID");
|
|
||||||
|
|
||||||
ok(
|
|
||||||
aMessageObject.level == "time" || aMessageObject.level == "timeEnd",
|
|
||||||
"expected level received"
|
|
||||||
);
|
|
||||||
is(aMessageObject.arguments.length, 1, "we have the default argument");
|
|
||||||
is(aMessageObject.arguments[0], "default", "we have the default argument");
|
|
||||||
ok(aMessageObject.timer, "we have a timer");
|
|
||||||
|
|
||||||
is(aMessageObject.functionName, "namelessTimer", "functionName matches");
|
|
||||||
ok(
|
|
||||||
aMessageObject.lineNumber == 31 || aMessageObject.lineNumber == 32,
|
|
||||||
"lineNumber matches"
|
|
||||||
);
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function startEmptyTimerTest(browser) {
|
|
||||||
await spawnWithObserver(browser, testEmptyTimer);
|
|
||||||
|
|
||||||
BrowserTestUtils.synthesizeMouseAtCenter("#test-namelessTimer", {}, browser);
|
|
||||||
await waitForResolve(browser);
|
|
||||||
}
|
|
|
@ -12,50 +12,50 @@ const { WebExtensionPolicy } = Cu.getGlobalForObject(
|
||||||
const FAKE_ADDON_ID = "test-webext-addon@mozilla.org";
|
const FAKE_ADDON_ID = "test-webext-addon@mozilla.org";
|
||||||
const EXPECTED_CONSOLE_ID = `addon/${FAKE_ADDON_ID}`;
|
const EXPECTED_CONSOLE_ID = `addon/${FAKE_ADDON_ID}`;
|
||||||
const EXPECTED_CONSOLE_MESSAGE_CONTENT = "fake-webext-addon-test-log-message";
|
const EXPECTED_CONSOLE_MESSAGE_CONTENT = "fake-webext-addon-test-log-message";
|
||||||
const ConsoleObserver = {
|
|
||||||
QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
|
|
||||||
|
|
||||||
|
const ConsoleObserver = {
|
||||||
init() {
|
init() {
|
||||||
Services.obs.addObserver(this, "console-api-log-event");
|
ConsoleAPIStorage.addLogEventListener(
|
||||||
|
this.observe,
|
||||||
|
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal)
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
uninit() {
|
uninit() {
|
||||||
Services.obs.removeObserver(this, "console-api-log-event");
|
ConsoleAPIStorage.removeLogEventListener(this.observe);
|
||||||
},
|
},
|
||||||
|
|
||||||
observe(aSubject, aTopic, aData) {
|
observe(aSubject) {
|
||||||
if (aTopic == "console-api-log-event") {
|
let consoleAPIMessage = aSubject.wrappedJSObject;
|
||||||
let consoleAPIMessage = aSubject.wrappedJSObject;
|
|
||||||
|
|
||||||
is(
|
is(
|
||||||
consoleAPIMessage.arguments[0],
|
consoleAPIMessage.arguments[0],
|
||||||
EXPECTED_CONSOLE_MESSAGE_CONTENT,
|
EXPECTED_CONSOLE_MESSAGE_CONTENT,
|
||||||
"the consoleAPIMessage contains the expected message"
|
"the consoleAPIMessage contains the expected message"
|
||||||
);
|
);
|
||||||
|
|
||||||
is(
|
is(
|
||||||
consoleAPIMessage.addonId,
|
consoleAPIMessage.addonId,
|
||||||
FAKE_ADDON_ID,
|
FAKE_ADDON_ID,
|
||||||
"the consoleAPImessage originAttributes contains the expected addonId"
|
"the consoleAPImessage originAttributes contains the expected addonId"
|
||||||
);
|
);
|
||||||
|
|
||||||
let cachedMessages = ConsoleAPIStorage.getEvents().filter(msg => {
|
let cachedMessages = ConsoleAPIStorage.getEvents().filter(msg => {
|
||||||
return msg.addonId == FAKE_ADDON_ID;
|
return msg.addonId == FAKE_ADDON_ID;
|
||||||
});
|
});
|
||||||
|
|
||||||
is(
|
is(
|
||||||
cachedMessages.length,
|
cachedMessages.length,
|
||||||
1,
|
1,
|
||||||
"found the expected cached console messages from the addon"
|
"found the expected cached console messages from the addon"
|
||||||
);
|
);
|
||||||
is(
|
is(
|
||||||
cachedMessages[0] && cachedMessages[0].addonId,
|
cachedMessages[0] && cachedMessages[0].addonId,
|
||||||
FAKE_ADDON_ID,
|
FAKE_ADDON_ID,
|
||||||
"the cached message originAttributes contains the expected addonId"
|
"the cached message originAttributes contains the expected addonId"
|
||||||
);
|
);
|
||||||
|
|
||||||
finish();
|
finish();
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -35,23 +35,20 @@ add_task(async function() {
|
||||||
|
|
||||||
let observerPromise = new Promise(resolve => {
|
let observerPromise = new Promise(resolve => {
|
||||||
let apiCallCount = 0;
|
let apiCallCount = 0;
|
||||||
let ConsoleObserver = {
|
function observe(aSubject) {
|
||||||
QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
|
apiCallCount++;
|
||||||
|
info(`Received ${apiCallCount} console log events`);
|
||||||
observe(aSubject, aTopic, aData) {
|
if (apiCallCount == 4) {
|
||||||
if (aTopic == "console-storage-cache-event") {
|
ConsoleAPIStorage.removeLogEventListener(observe);
|
||||||
apiCallCount++;
|
resolve();
|
||||||
info(`Received ${apiCallCount} "console-storage-cache-event"`);
|
}
|
||||||
if (apiCallCount == 4) {
|
}
|
||||||
Services.obs.removeObserver(this, "console-storage-cache-event");
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
info("Setting up observer");
|
info("Setting up observer");
|
||||||
Services.obs.addObserver(ConsoleObserver, "console-storage-cache-event");
|
ConsoleAPIStorage.addLogEventListener(
|
||||||
|
observe,
|
||||||
|
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
info("Emit a few console API logs");
|
info("Emit a few console API logs");
|
||||||
|
@ -60,7 +57,7 @@ add_task(async function() {
|
||||||
content.console.warn("this", "is", "a", "warn", "message");
|
content.console.warn("this", "is", "a", "warn", "message");
|
||||||
content.console.error("this", "is", "a", "error", "message");
|
content.console.error("this", "is", "a", "error", "message");
|
||||||
|
|
||||||
info("Wait for the corresponding console-storage-cache-event");
|
info("Wait for the corresponding log event");
|
||||||
await observerPromise;
|
await observerPromise;
|
||||||
|
|
||||||
const innerWindowId = content.windowGlobalChild.innerWindowId;
|
const innerWindowId = content.windowGlobalChild.innerWindowId;
|
||||||
|
|
|
@ -9,7 +9,6 @@ function test() {
|
||||||
let beforeEvents;
|
let beforeEvents;
|
||||||
let afterEvents;
|
let afterEvents;
|
||||||
let storageShouldOccur;
|
let storageShouldOccur;
|
||||||
let consoleObserver;
|
|
||||||
let testURI =
|
let testURI =
|
||||||
"http://example.com/browser/dom/tests/browser/test-console-api.html";
|
"http://example.com/browser/dom/tests/browser/test-console-api.html";
|
||||||
let ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"].getService(
|
let ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"].getService(
|
||||||
|
@ -34,30 +33,23 @@ function test() {
|
||||||
function doTest(aIsPrivateMode, aWindow, aCallback) {
|
function doTest(aIsPrivateMode, aWindow, aCallback) {
|
||||||
BrowserTestUtils.browserLoaded(aWindow.gBrowser.selectedBrowser).then(
|
BrowserTestUtils.browserLoaded(aWindow.gBrowser.selectedBrowser).then(
|
||||||
() => {
|
() => {
|
||||||
consoleObserver = {
|
function observe(aSubject) {
|
||||||
observe(aSubject, aTopic, aData) {
|
afterEvents = ConsoleAPIStorage.getEvents(innerID);
|
||||||
if (aTopic == "console-api-log-event") {
|
is(
|
||||||
afterEvents = ConsoleAPIStorage.getEvents(innerID);
|
beforeEvents.length == afterEvents.length - 1,
|
||||||
is(
|
storageShouldOccur,
|
||||||
beforeEvents.length == afterEvents.length - 1,
|
"storage should" + (storageShouldOccur ? "" : " not") + " occur"
|
||||||
storageShouldOccur,
|
);
|
||||||
"storage should" + (storageShouldOccur ? "" : " not") + " occur"
|
|
||||||
);
|
|
||||||
|
|
||||||
executeSoon(function() {
|
executeSoon(function() {
|
||||||
Services.obs.removeObserver(
|
ConsoleAPIStorage.removeLogEventListener(observe);
|
||||||
consoleObserver,
|
aCallback();
|
||||||
"console-api-log-event"
|
});
|
||||||
);
|
}
|
||||||
aCallback();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
aWindow.Services.obs.addObserver(
|
ConsoleAPIStorage.addLogEventListener(
|
||||||
consoleObserver,
|
observe,
|
||||||
"console-api-log-event"
|
aWindow.document.nodePrincipal
|
||||||
);
|
);
|
||||||
aWindow.nativeConsole.log(
|
aWindow.nativeConsole.log(
|
||||||
"foo bar baz (private: " + aIsPrivateMode + ")"
|
"foo bar baz (private: " + aIsPrivateMode + ")"
|
||||||
|
|
|
@ -9,26 +9,29 @@ add_task(async function() {
|
||||||
|
|
||||||
await BrowserTestUtils.withNewTab(TEST_URI, async aBrowser => {
|
await BrowserTestUtils.withNewTab(TEST_URI, async aBrowser => {
|
||||||
let duration = await SpecialPowers.spawn(aBrowser, [], function(opts) {
|
let duration = await SpecialPowers.spawn(aBrowser, [], function(opts) {
|
||||||
|
const ConsoleAPIStorage = Cc[
|
||||||
|
"@mozilla.org/consoleAPI-storage;1"
|
||||||
|
].getService(Ci.nsIConsoleAPIStorage);
|
||||||
|
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
let ConsoleObserver = {
|
function observe(aSubject) {
|
||||||
QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
|
var obj = aSubject.wrappedJSObject;
|
||||||
|
if (
|
||||||
|
obj.arguments.length != 1 ||
|
||||||
|
obj.arguments[0] != "bug1004814" ||
|
||||||
|
obj.level != "timeEnd"
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
observe(aSubject, aTopic, aData) {
|
ConsoleAPIStorage.removeLogEventListener(observe);
|
||||||
var obj = aSubject.wrappedJSObject;
|
resolve(obj.timer.duration);
|
||||||
if (
|
}
|
||||||
obj.arguments.length != 1 ||
|
|
||||||
obj.arguments[0] != "bug1004814" ||
|
|
||||||
obj.level != "timeEnd"
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Services.obs.removeObserver(this, "console-api-log-event");
|
ConsoleAPIStorage.addLogEventListener(
|
||||||
resolve(obj.timer.duration);
|
observe,
|
||||||
},
|
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal)
|
||||||
};
|
);
|
||||||
|
|
||||||
Services.obs.addObserver(ConsoleObserver, "console-api-log-event");
|
|
||||||
|
|
||||||
var w = new content.Worker("worker_bug1004814.js");
|
var w = new content.Worker("worker_bug1004814.js");
|
||||||
w.postMessage(true);
|
w.postMessage(true);
|
||||||
|
|
|
@ -287,21 +287,42 @@ async function test_codeExecution(compartment) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is intended to just be a drop-in replacement for an old observer
|
||||||
|
// notification.
|
||||||
|
function addConsoleStorageListener(listener) {
|
||||||
|
const ConsoleAPIStorage = SpecialPowers.Cc[
|
||||||
|
"@mozilla.org/consoleAPI-storage;1"
|
||||||
|
].getService(SpecialPowers.Ci.nsIConsoleAPIStorage);
|
||||||
|
listener.__handler = (message, id) => {
|
||||||
|
listener.observe(message, id);
|
||||||
|
};
|
||||||
|
ConsoleAPIStorage.addLogEventListener(
|
||||||
|
listener.__handler,
|
||||||
|
SpecialPowers.wrap(document).nodePrincipal
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeConsoleStorageListener(listener) {
|
||||||
|
const ConsoleAPIStorage = SpecialPowers.Cc[
|
||||||
|
"@mozilla.org/consoleAPI-storage;1"
|
||||||
|
].getService(SpecialPowers.Ci.nsIConsoleAPIStorage);
|
||||||
|
ConsoleAPIStorage.removeLogEventListener(listener.__handler);
|
||||||
|
}
|
||||||
|
|
||||||
async function test_codeExecution_continue(r, that) {
|
async function test_codeExecution_continue(r, that) {
|
||||||
function consoleListener() {
|
function consoleListener() {
|
||||||
that.SpecialPowers.addObserver(this, "console-api-log-event");
|
addConsoleStorageListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
var promise = new Promise(resolve => {
|
var promise = new Promise(resolve => {
|
||||||
consoleListener.prototype = {
|
consoleListener.prototype = {
|
||||||
observe(aSubject, aTopic, aData) {
|
observe(aSubject) {
|
||||||
that.ok(true, "Something has been received");
|
that.ok(true, "Something has been received");
|
||||||
that.is(aTopic, "console-api-log-event");
|
|
||||||
|
|
||||||
var obj = aSubject.wrappedJSObject;
|
var obj = aSubject.wrappedJSObject;
|
||||||
if (obj.arguments[0] && obj.arguments[0] === "pull called") {
|
if (obj.arguments[0] && obj.arguments[0] === "pull called") {
|
||||||
that.ok(true, "Message received!");
|
that.ok(true, "Message received!");
|
||||||
that.SpecialPowers.removeObserver(this, "console-api-log-event");
|
removeConsoleStorageListener(this);
|
||||||
resolve();
|
resolve();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,14 +10,37 @@ add_task(async function test() {
|
||||||
await BrowserTestUtils.browserLoaded(gBrowser.getBrowserForTab(tab));
|
await BrowserTestUtils.browserLoaded(gBrowser.getBrowserForTab(tab));
|
||||||
|
|
||||||
let promise = new Promise(resolve => {
|
let promise = new Promise(resolve => {
|
||||||
|
const ConsoleAPIStorage = SpecialPowers.Cc[
|
||||||
|
"@mozilla.org/consoleAPI-storage;1"
|
||||||
|
].getService(SpecialPowers.Ci.nsIConsoleAPIStorage);
|
||||||
|
|
||||||
function consoleListener() {
|
function consoleListener() {
|
||||||
Services.obs.addObserver(this, "console-api-log-event");
|
this.onConsoleLogEvent = this.onConsoleLogEvent.bind(this);
|
||||||
|
ConsoleAPIStorage.addLogEventListener(
|
||||||
|
this.onConsoleLogEvent,
|
||||||
|
SpecialPowers.wrap(document).nodePrincipal
|
||||||
|
);
|
||||||
Services.obs.addObserver(this, "console-api-profiler");
|
Services.obs.addObserver(this, "console-api-profiler");
|
||||||
}
|
}
|
||||||
|
|
||||||
var order = 0;
|
var order = 0;
|
||||||
consoleListener.prototype = {
|
consoleListener.prototype = {
|
||||||
observe: (aSubject, aTopic, aData) => {
|
onConsoleLogEvent(aSubject) {
|
||||||
|
var obj = aSubject.wrappedJSObject;
|
||||||
|
is(
|
||||||
|
obj.arguments[0],
|
||||||
|
"Hello world from a SharedWorker!",
|
||||||
|
"A message from a SharedWorker \\o/"
|
||||||
|
);
|
||||||
|
is(obj.ID, "sharedWorker_console.js", "The ID is SharedWorker");
|
||||||
|
is(obj.innerID, "SharedWorker", "The ID is SharedWorker");
|
||||||
|
is(order++, 1, "Then a log message.");
|
||||||
|
|
||||||
|
ConsoleAPIStorage.removeLogEventListener(this.onConsoleLogEvent);
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
|
||||||
|
observe: (aSubject, aTopic) => {
|
||||||
ok(true, "Something has been received");
|
ok(true, "Something has been received");
|
||||||
|
|
||||||
if (aTopic == "console-api-profiler") {
|
if (aTopic == "console-api-profiler") {
|
||||||
|
@ -30,23 +53,6 @@ add_task(async function test() {
|
||||||
is(order++, 0, "First a profiler message.");
|
is(order++, 0, "First a profiler message.");
|
||||||
|
|
||||||
Services.obs.removeObserver(cl, "console-api-profiler");
|
Services.obs.removeObserver(cl, "console-api-profiler");
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aTopic == "console-api-log-event") {
|
|
||||||
var obj = aSubject.wrappedJSObject;
|
|
||||||
is(
|
|
||||||
obj.arguments[0],
|
|
||||||
"Hello world from a SharedWorker!",
|
|
||||||
"A message from a SharedWorker \\o/"
|
|
||||||
);
|
|
||||||
is(obj.ID, "sharedWorker_console.js", "The ID is SharedWorker");
|
|
||||||
is(obj.innerID, "SharedWorker", "The ID is SharedWorker");
|
|
||||||
is(order++, 1, "Then a log message.");
|
|
||||||
|
|
||||||
Services.obs.removeObserver(cl, "console-api-log-event");
|
|
||||||
resolve();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,20 +22,23 @@
|
||||||
|
|
||||||
consoleMessagesReceived = 0;
|
consoleMessagesReceived = 0;
|
||||||
function test() {
|
function test() {
|
||||||
|
const ConsoleAPIStorage = SpecialPowers.Cc[
|
||||||
|
"@mozilla.org/consoleAPI-storage;1"
|
||||||
|
].getService(SpecialPowers.Ci.nsIConsoleAPIStorage);
|
||||||
|
|
||||||
function consoleListener() {
|
function consoleListener() {
|
||||||
Services.obs.addObserver(this, "console-api-log-event");
|
this.observe = this.observe.bind(this);
|
||||||
|
ConsoleAPIStorage.addLogEventListener(this.observe, SpecialPowers.wrap(document).nodePrincipal);
|
||||||
}
|
}
|
||||||
|
|
||||||
consoleListener.prototype = {
|
consoleListener.prototype = {
|
||||||
observe: function(aSubject, aTopic, aData) {
|
observe: function(aSubject) {
|
||||||
if (aTopic == "console-api-log-event") {
|
var obj = aSubject.wrappedJSObject;
|
||||||
var obj = aSubject.wrappedJSObject;
|
if (obj.arguments[0] == "Hello from the debugger script!" &&
|
||||||
if (obj.arguments[0] == "Hello from the debugger script!" &&
|
!consoleMessagesReceived) {
|
||||||
!consoleMessagesReceived) {
|
consoleMessagesReceived++;
|
||||||
consoleMessagesReceived++;
|
ok(true, "Something has been received");
|
||||||
ok(true, "Something has been received");
|
ConsoleAPIStorage.removeLogEventListener(this.observe);
|
||||||
Services.obs.removeObserver(this, "console-api-log-event");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,20 +12,23 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
const ConsoleAPIStorage = SpecialPowers.Cc[
|
||||||
|
"@mozilla.org/consoleAPI-storage;1"
|
||||||
|
].getService(SpecialPowers.Ci.nsIConsoleAPIStorage);
|
||||||
|
|
||||||
function consoleListener() {
|
function consoleListener() {
|
||||||
SpecialPowers.addObserver(this, "console-api-log-event");
|
this.observe = this.observe.bind(this);
|
||||||
|
ConsoleAPIStorage.addLogEventListener(this.observe, SpecialPowers.wrap(document).nodePrincipal);
|
||||||
}
|
}
|
||||||
|
|
||||||
var order = 0;
|
var order = 0;
|
||||||
consoleListener.prototype = {
|
consoleListener.prototype = {
|
||||||
observe(aSubject, aTopic, aData) {
|
observe(aSubject) {
|
||||||
ok(true, "Something has been received");
|
ok(true, "Something has been received");
|
||||||
is(aTopic, "console-api-log-event");
|
|
||||||
|
|
||||||
var obj = aSubject.wrappedJSObject;
|
var obj = aSubject.wrappedJSObject;
|
||||||
if (obj.arguments[0] && obj.arguments[0].msg === 'consoleAndBlobs') {
|
if (obj.arguments[0] && obj.arguments[0].msg === 'consoleAndBlobs') {
|
||||||
SpecialPowers.removeObserver(this, "console-api-log-event");
|
ConsoleAPIStorage.removeLogEventListener(this.observe);
|
||||||
is(obj.arguments[0].blob.size, 3, "The size is correct");
|
is(obj.arguments[0].blob.size, 3, "The size is correct");
|
||||||
is(obj.arguments[0].blob.type, 'foo/bar', "The type is correct");
|
is(obj.arguments[0].blob.type, 'foo/bar', "The type is correct");
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
|
|
|
@ -11,21 +11,24 @@
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
|
|
||||||
function configureTest() {
|
function configureTest() {
|
||||||
|
const ConsoleAPIStorage = SpecialPowers.Cc[
|
||||||
|
"@mozilla.org/consoleAPI-storage;1"
|
||||||
|
].getService(SpecialPowers.Ci.nsIConsoleAPIStorage);
|
||||||
|
|
||||||
function consoleListener() {
|
function consoleListener() {
|
||||||
SpecialPowers.addObserver(this, "console-api-log-event");
|
this.observe = this.observe.bind(this);
|
||||||
|
ConsoleAPIStorage.addLogEventListener(this.observe, SpecialPowers.wrap(document).nodePrincipal);
|
||||||
}
|
}
|
||||||
|
|
||||||
consoleListener.prototype = {
|
consoleListener.prototype = {
|
||||||
observe(aSubject, aTopic, aData) {
|
observe(aSubject) {
|
||||||
if (aTopic == "console-api-log-event") {
|
var obj = aSubject.wrappedJSObject;
|
||||||
var obj = aSubject.wrappedJSObject;
|
if (obj.arguments[0] == "So far so good") {
|
||||||
if (obj.arguments[0] == "So far so good") {
|
ok(true, "Message received \\o/");
|
||||||
ok(true, "Message received \\o/");
|
|
||||||
|
|
||||||
SpecialPowers.removeObserver(this, "console-api-log-event");
|
ConsoleAPIStorage.removeLogEventListener(this.observe);
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,26 +31,29 @@ function configureTest() {
|
||||||
|
|
||||||
var expected_errors_i = 0;
|
var expected_errors_i = 0;
|
||||||
|
|
||||||
|
const ConsoleAPIStorage = SpecialPowers.Cc[
|
||||||
|
"@mozilla.org/consoleAPI-storage;1"
|
||||||
|
].getService(SpecialPowers.Ci.nsIConsoleAPIStorage);
|
||||||
|
|
||||||
function consoleListener() {
|
function consoleListener() {
|
||||||
SpecialPowers.addObserver(this, "console-api-log-event");
|
this.observe = this.observe.bind(this);
|
||||||
|
ConsoleAPIStorage.addLogEventListener(this.observe, SpecialPowers.wrap(document).nodePrincipal);
|
||||||
}
|
}
|
||||||
|
|
||||||
consoleListener.prototype = {
|
consoleListener.prototype = {
|
||||||
observe(aSubject, aTopic, aData) {
|
observe(aSubject) {
|
||||||
if (aTopic == "console-api-log-event") {
|
var obj = aSubject.wrappedJSObject;
|
||||||
var obj = aSubject.wrappedJSObject;
|
if (obj.arguments[0] == expected_errors[expected_errors_i]) {
|
||||||
if (obj.arguments[0] == expected_errors[expected_errors_i]) {
|
ok(true, "Expected error received: " + obj.arguments[0]);
|
||||||
ok(true, "Expected error received: " + obj.arguments[0]);
|
expected_errors_i++;
|
||||||
expected_errors_i++;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (expected_errors_i == expected_errors.length) {
|
if (expected_errors_i == expected_errors.length) {
|
||||||
// All errors have been received, this test has been completed
|
// All errors have been received, this test has been completed
|
||||||
// succesfully!
|
// succesfully!
|
||||||
SpecialPowers.removeObserver(this, "console-api-log-event");
|
ConsoleAPIStorage.removeLogEventListener(this.observe);
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,23 +12,26 @@
|
||||||
const WORKLET_SCRIPT = "worklet_console.js";
|
const WORKLET_SCRIPT = "worklet_console.js";
|
||||||
|
|
||||||
function configureTest() {
|
function configureTest() {
|
||||||
|
const ConsoleAPIStorage = SpecialPowers.Cc[
|
||||||
|
"@mozilla.org/consoleAPI-storage;1"
|
||||||
|
].getService(SpecialPowers.Ci.nsIConsoleAPIStorage);
|
||||||
|
|
||||||
function consoleListener() {
|
function consoleListener() {
|
||||||
SpecialPowers.addObserver(this, "console-api-log-event");
|
this.observe = this.observe.bind(this);
|
||||||
|
ConsoleAPIStorage.addLogEventListener(this.observe, SpecialPowers.wrap(document).nodePrincipal);
|
||||||
}
|
}
|
||||||
|
|
||||||
consoleListener.prototype = {
|
consoleListener.prototype = {
|
||||||
observe(aSubject, aTopic, aData) {
|
observe(aSubject) {
|
||||||
if (aTopic == "console-api-log-event") {
|
var obj = aSubject.wrappedJSObject;
|
||||||
var obj = aSubject.wrappedJSObject;
|
if (obj.arguments[0] == "Hello world from a worklet") {
|
||||||
if (obj.arguments[0] == "Hello world from a worklet") {
|
ok(true, "Message received \\o/");
|
||||||
ok(true, "Message received \\o/");
|
is(obj.filename,
|
||||||
is(obj.filename,
|
new URL(WORKLET_SCRIPT, document.baseURI).toString());
|
||||||
new URL(WORKLET_SCRIPT, document.baseURI).toString());
|
|
||||||
|
|
||||||
SpecialPowers.removeObserver(this, "console-api-log-event");
|
ConsoleAPIStorage.removeLogEventListener(this.observe);
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,21 +11,24 @@
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
|
|
||||||
function configureTest() {
|
function configureTest() {
|
||||||
|
const ConsoleAPIStorage = SpecialPowers.Cc[
|
||||||
|
"@mozilla.org/consoleAPI-storage;1"
|
||||||
|
].getService(SpecialPowers.Ci.nsIConsoleAPIStorage);
|
||||||
|
|
||||||
function consoleListener() {
|
function consoleListener() {
|
||||||
SpecialPowers.addObserver(this, "console-api-log-event");
|
this.observe = this.observe.bind(this);
|
||||||
|
ConsoleAPIStorage.addLogEventListener(this.observe, SpecialPowers.wrap(document).nodePrincipal);
|
||||||
}
|
}
|
||||||
|
|
||||||
consoleListener.prototype = {
|
consoleListener.prototype = {
|
||||||
observe(aSubject, aTopic, aData) {
|
observe(aSubject) {
|
||||||
if (aTopic == "console-api-log-event") {
|
var obj = aSubject.wrappedJSObject;
|
||||||
var obj = aSubject.wrappedJSObject;
|
if (obj.arguments[0] == "So far so good") {
|
||||||
if (obj.arguments[0] == "So far so good") {
|
ok(true, "Message received \\o/");
|
||||||
ok(true, "Message received \\o/");
|
|
||||||
|
|
||||||
SpecialPowers.removeObserver(this, "console-api-log-event");
|
ConsoleAPIStorage.removeLogEventListener(this.observe);
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||||
|
|
||||||
const { debug, warn } = GeckoViewUtils.initLogging("Console");
|
const { debug, warn } = GeckoViewUtils.initLogging("Console");
|
||||||
|
|
||||||
const LOG_EVENT_TOPIC = "console-api-log-event";
|
|
||||||
|
|
||||||
var GeckoViewConsole = {
|
var GeckoViewConsole = {
|
||||||
_isEnabled: false,
|
_isEnabled: false,
|
||||||
|
|
||||||
|
@ -34,21 +32,24 @@ var GeckoViewConsole = {
|
||||||
}
|
}
|
||||||
|
|
||||||
this._isEnabled = !!aVal;
|
this._isEnabled = !!aVal;
|
||||||
|
const ConsoleAPIStorage = Cc[
|
||||||
|
"@mozilla.org/consoleAPI-storage;1"
|
||||||
|
].getService(Ci.nsIConsoleAPIStorage);
|
||||||
if (this._isEnabled) {
|
if (this._isEnabled) {
|
||||||
Services.obs.addObserver(this, LOG_EVENT_TOPIC);
|
this._consoleMessageListener = this._handleConsoleMessage.bind(this);
|
||||||
} else {
|
ConsoleAPIStorage.addLogEventListener(
|
||||||
Services.obs.removeObserver(this, LOG_EVENT_TOPIC);
|
this._consoleMessageListener,
|
||||||
|
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal)
|
||||||
|
);
|
||||||
|
} else if (this._consoleMessageListener) {
|
||||||
|
ConsoleAPIStorage.removeLogEventListener(this._consoleMessageListener);
|
||||||
|
delete this._consoleMessageListener;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
observe(aSubject, aTopic, aData) {
|
observe(aSubject, aTopic, aData) {
|
||||||
switch (aTopic) {
|
if (aTopic == "nsPref:changed") {
|
||||||
case "nsPref:changed":
|
this.enabled = Services.prefs.getBoolPref(aData, false);
|
||||||
this.enabled = Services.prefs.getBoolPref(aData, false);
|
|
||||||
break;
|
|
||||||
case LOG_EVENT_TOPIC:
|
|
||||||
this._handleConsoleMessage(aSubject);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -21,11 +21,15 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||||
"chrome://remote/content/cdp/domains/content/runtime/ExecutionContext.jsm",
|
"chrome://remote/content/cdp/domains/content/runtime/ExecutionContext.jsm",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyGetter(this, "ConsoleAPIStorage", () => {
|
||||||
|
return Cc["@mozilla.org/consoleAPI-storage;1"].getService(
|
||||||
|
Ci.nsIConsoleAPIStorage
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// Import the `Debugger` constructor in the current scope
|
// Import the `Debugger` constructor in the current scope
|
||||||
addDebuggerToGlobal(Cu.getGlobalForObject(this));
|
addDebuggerToGlobal(Cu.getGlobalForObject(this));
|
||||||
|
|
||||||
const OBSERVER_CONSOLE_API = "console-api-log-event";
|
|
||||||
|
|
||||||
const CONSOLE_API_LEVEL_MAP = {
|
const CONSOLE_API_LEVEL_MAP = {
|
||||||
warn: "warning",
|
warn: "warning",
|
||||||
};
|
};
|
||||||
|
@ -97,7 +101,11 @@ class Runtime extends ContentProcessDomain {
|
||||||
this.enabled = true;
|
this.enabled = true;
|
||||||
|
|
||||||
Services.console.registerListener(this);
|
Services.console.registerListener(this);
|
||||||
Services.obs.addObserver(this, OBSERVER_CONSOLE_API);
|
this.onConsoleLogEvent = this.onConsoleLogEvent.bind(this);
|
||||||
|
ConsoleAPIStorage.addLogEventListener(
|
||||||
|
this.onConsoleLogEvent,
|
||||||
|
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal)
|
||||||
|
);
|
||||||
|
|
||||||
// Spin the event loop in order to send the `executionContextCreated` event right
|
// Spin the event loop in order to send the `executionContextCreated` event right
|
||||||
// after we replied to `enable` request.
|
// after we replied to `enable` request.
|
||||||
|
@ -116,7 +124,7 @@ class Runtime extends ContentProcessDomain {
|
||||||
this.enabled = false;
|
this.enabled = false;
|
||||||
|
|
||||||
Services.console.unregisterListener(this);
|
Services.console.unregisterListener(this);
|
||||||
Services.obs.removeObserver(this, OBSERVER_CONSOLE_API);
|
ConsoleAPIStorage.removeLogEventListener(this.onConsoleLogEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -570,6 +578,11 @@ class Runtime extends ContentProcessDomain {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onConsoleLogEvent(message) {
|
||||||
|
let entry = fromConsoleAPI(message);
|
||||||
|
this._emitConsoleAPICalled(entry);
|
||||||
|
}
|
||||||
|
|
||||||
// nsIObserver
|
// nsIObserver
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -581,14 +594,8 @@ class Runtime extends ContentProcessDomain {
|
||||||
* Console message.
|
* Console message.
|
||||||
*/
|
*/
|
||||||
observe(subject, topic, data) {
|
observe(subject, topic, data) {
|
||||||
let entry;
|
if (subject instanceof Ci.nsIScriptError && subject.hasException) {
|
||||||
|
let entry = fromScriptError(subject);
|
||||||
if (topic == OBSERVER_CONSOLE_API) {
|
|
||||||
const message = subject.wrappedJSObject;
|
|
||||||
entry = fromConsoleAPI(message);
|
|
||||||
this._emitConsoleAPICalled(entry);
|
|
||||||
} else if (subject instanceof Ci.nsIScriptError && subject.hasException) {
|
|
||||||
entry = fromScriptError(subject);
|
|
||||||
this._emitExceptionThrown(entry);
|
this._emitExceptionThrown(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,12 @@ const { XPCOMUtils } = ChromeUtils.import(
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||||
EventEmitter: "resource://gre/modules/EventEmitter.jsm",
|
EventEmitter: "resource://gre/modules/EventEmitter.jsm",
|
||||||
Services: "resource://gre/modules/Services.jsm",
|
});
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyGetter(this, "ConsoleAPIStorage", () => {
|
||||||
|
return Cc["@mozilla.org/consoleAPI-storage;1"].getService(
|
||||||
|
Ci.nsIConsoleAPIStorage
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,12 +73,12 @@ class ConsoleAPIListener {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Services.obs.addObserver(
|
ConsoleAPIStorage.addLogEventListener(
|
||||||
this.#onConsoleAPIMessage,
|
this.#onConsoleAPIMessage,
|
||||||
"console-api-log-event"
|
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Emit cached messages after registering the observer, to make sure we
|
// Emit cached messages after registering the listener, to make sure we
|
||||||
// don't miss any message.
|
// don't miss any message.
|
||||||
this.#emitCachedMessages();
|
this.#emitCachedMessages();
|
||||||
|
|
||||||
|
@ -85,18 +90,11 @@ class ConsoleAPIListener {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Services.obs.removeObserver(
|
ConsoleAPIStorage.removeLogEventListener(this.#onConsoleAPIMessage);
|
||||||
this.#onConsoleAPIMessage,
|
|
||||||
"console-api-log-event"
|
|
||||||
);
|
|
||||||
this.#listening = false;
|
this.#listening = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#emitCachedMessages() {
|
#emitCachedMessages() {
|
||||||
const ConsoleAPIStorage = Cc[
|
|
||||||
"@mozilla.org/consoleAPI-storage;1"
|
|
||||||
].getService(Ci.nsIConsoleAPIStorage);
|
|
||||||
|
|
||||||
const cachedMessages = ConsoleAPIStorage.getEvents(this.#innerWindowId);
|
const cachedMessages = ConsoleAPIStorage.getEvents(this.#innerWindowId);
|
||||||
for (const message of cachedMessages) {
|
for (const message of cachedMessages) {
|
||||||
this.#onConsoleAPIMessage(message);
|
this.#onConsoleAPIMessage(message);
|
||||||
|
|
|
@ -24,6 +24,9 @@ const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||||
const { clearTimeout, setTimeout } = ChromeUtils.import(
|
const { clearTimeout, setTimeout } = ChromeUtils.import(
|
||||||
"resource://gre/modules/Timer.jsm"
|
"resource://gre/modules/Timer.jsm"
|
||||||
);
|
);
|
||||||
|
const ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"].getService(
|
||||||
|
Ci.nsIConsoleAPIStorage
|
||||||
|
);
|
||||||
|
|
||||||
var TestUtils = {
|
var TestUtils = {
|
||||||
executeSoon(callbackFn) {
|
executeSoon(callbackFn) {
|
||||||
|
@ -34,6 +37,64 @@ var TestUtils = {
|
||||||
return new Promise(resolve => this.executeSoon(resolve));
|
return new Promise(resolve => this.executeSoon(resolve));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for a console message matching the specified check function to be
|
||||||
|
* observed.
|
||||||
|
*
|
||||||
|
* @param {function} checkFn [optional]
|
||||||
|
* Called with the message as its argument, should return true if the
|
||||||
|
* notification is the expected one, or false if it should be ignored
|
||||||
|
* and listening should continue.
|
||||||
|
*
|
||||||
|
* @note Because this function is intended for testing, any error in checkFn
|
||||||
|
* will cause the returned promise to be rejected instead of waiting for
|
||||||
|
* the next notification, since this is probably a bug in the test.
|
||||||
|
*
|
||||||
|
* @return {Promise}
|
||||||
|
* @resolves The message from the observed notification.
|
||||||
|
*/
|
||||||
|
consoleMessageObserved(checkFn) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let removed = false;
|
||||||
|
function observe(message) {
|
||||||
|
try {
|
||||||
|
if (checkFn && !checkFn(message)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ConsoleAPIStorage.removeLogEventListener(observe);
|
||||||
|
// checkFn could reference objects that need to be destroyed before
|
||||||
|
// the end of the test, so avoid keeping a reference to it after the
|
||||||
|
// promise resolves.
|
||||||
|
checkFn = null;
|
||||||
|
removed = true;
|
||||||
|
|
||||||
|
resolve(message);
|
||||||
|
} catch (ex) {
|
||||||
|
ConsoleAPIStorage.removeLogEventListener(observe);
|
||||||
|
checkFn = null;
|
||||||
|
removed = true;
|
||||||
|
reject(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleAPIStorage.addLogEventListener(
|
||||||
|
observe,
|
||||||
|
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal)
|
||||||
|
);
|
||||||
|
|
||||||
|
TestUtils.promiseTestFinished?.then(() => {
|
||||||
|
if (removed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsoleAPIStorage.removeLogEventListener(observe);
|
||||||
|
let text =
|
||||||
|
"Console message observer not removed before the end of test";
|
||||||
|
reject(text);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Waits for the specified topic to be observed.
|
* Waits for the specified topic to be observed.
|
||||||
*
|
*
|
||||||
|
|
|
@ -137,17 +137,6 @@ SPConsoleListener.prototype = {
|
||||||
m.innerWindowID = msg.innerWindowID;
|
m.innerWindowID = msg.innerWindowID;
|
||||||
m.isScriptError = true;
|
m.isScriptError = true;
|
||||||
m.isWarning = (msg.flags & Ci.nsIScriptError.warningFlag) === 1;
|
m.isWarning = (msg.flags & Ci.nsIScriptError.warningFlag) === 1;
|
||||||
} else if (topic === "console-api-log-event") {
|
|
||||||
// This is a dom/console event.
|
|
||||||
let unwrapped = msg.wrappedJSObject;
|
|
||||||
m.errorMessage = unwrapped.arguments[0];
|
|
||||||
m.sourceName = unwrapped.filename;
|
|
||||||
m.lineNumber = unwrapped.lineNumber;
|
|
||||||
m.columnNumber = unwrapped.columnNumber;
|
|
||||||
m.windowID = unwrapped.ID;
|
|
||||||
m.innerWindowID = unwrapped.innerID;
|
|
||||||
m.isConsoleEvent = true;
|
|
||||||
m.isWarning = unwrapped.level === "warning";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.freeze(m);
|
Object.freeze(m);
|
||||||
|
@ -159,7 +148,6 @@ SPConsoleListener.prototype = {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!m.isScriptError && !m.isConsoleEvent && m.message === "SENTINEL") {
|
if (!m.isScriptError && !m.isConsoleEvent && m.message === "SENTINEL") {
|
||||||
Services.obs.removeObserver(this, "console-api-log-event");
|
|
||||||
Services.console.unregisterListener(this);
|
Services.console.unregisterListener(this);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1197,9 +1185,6 @@ class SpecialPowersChild extends JSWindowActorChild {
|
||||||
registerConsoleListener(callback) {
|
registerConsoleListener(callback) {
|
||||||
let listener = new SPConsoleListener(callback, this.contentWindow);
|
let listener = new SPConsoleListener(callback, this.contentWindow);
|
||||||
Services.console.registerListener(listener);
|
Services.console.registerListener(listener);
|
||||||
|
|
||||||
// listen for dom/console events as well
|
|
||||||
Services.obs.addObserver(listener, "console-api-log-event");
|
|
||||||
}
|
}
|
||||||
postConsoleSentinel() {
|
postConsoleSentinel() {
|
||||||
Services.console.logStringMessage("SENTINEL");
|
Services.console.logStringMessage("SENTINEL");
|
||||||
|
|
|
@ -411,21 +411,25 @@ let consoleAllowList = [
|
||||||
'property "profileDir" is non-configurable and can\'t be deleted',
|
'property "profileDir" is non-configurable and can\'t be deleted',
|
||||||
];
|
];
|
||||||
|
|
||||||
let consoleListener = {
|
function observe(subject) {
|
||||||
observe(subject, topic, data) {
|
let msg = subject.wrappedJSObject;
|
||||||
let msg = subject.wrappedJSObject;
|
let messageContents = msg.arguments[0]?.message || msg.arguments[0];
|
||||||
let messageContents = msg.arguments[0]?.message || msg.arguments[0];
|
if (
|
||||||
if (
|
msg.level == "error" &&
|
||||||
msg.level == "error" &&
|
!consoleAllowList.some(e => messageContents.includes(e))
|
||||||
!consoleAllowList.some(e => messageContents.includes(e))
|
) {
|
||||||
) {
|
Assert.ok(false, "Unexpected console message: " + messageContents);
|
||||||
Assert.ok(false, "Unexpected console message: " + messageContents);
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Services.obs.addObserver(consoleListener, "console-api-log-event");
|
const ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"].getService(
|
||||||
|
Ci.nsIConsoleAPIStorage
|
||||||
|
);
|
||||||
|
ConsoleAPIStorage.addLogEventListener(
|
||||||
|
observe,
|
||||||
|
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal)
|
||||||
|
);
|
||||||
|
|
||||||
registerCleanupFunction(async () => {
|
registerCleanupFunction(async () => {
|
||||||
Services.obs.removeObserver(consoleListener, "console-api-log-event");
|
ConsoleAPIStorage.removeLogEventListener(observe);
|
||||||
});
|
});
|
||||||
|
|
|
@ -24,7 +24,7 @@ add_task(async function test_installedresourceicon() {
|
||||||
});
|
});
|
||||||
|
|
||||||
add_task(async function test_installedhttpplace() {
|
add_task(async function test_installedhttpplace() {
|
||||||
let observed = TestUtils.topicObserved("console-api-log-event", msg => {
|
let observed = TestUtils.consoleMessageObserved(msg => {
|
||||||
return msg.wrappedJSObject.arguments[0].includes(
|
return msg.wrappedJSObject.arguments[0].includes(
|
||||||
"Content type does not match expected"
|
"Content type does not match expected"
|
||||||
);
|
);
|
||||||
|
|
|
@ -121,7 +121,7 @@ add_task(async function test_manifest_selection() {
|
||||||
});
|
});
|
||||||
|
|
||||||
add_task(async function test_load_favicon_invalid() {
|
add_task(async function test_load_favicon_invalid() {
|
||||||
let observed = TestUtils.topicObserved("console-api-log-event", msg => {
|
let observed = TestUtils.consoleMessageObserved(msg => {
|
||||||
return msg.wrappedJSObject.arguments[0].includes(
|
return msg.wrappedJSObject.arguments[0].includes(
|
||||||
"Content type does not match expected"
|
"Content type does not match expected"
|
||||||
);
|
);
|
||||||
|
@ -147,7 +147,7 @@ add_task(async function test_load_favicon_invalid() {
|
||||||
});
|
});
|
||||||
|
|
||||||
add_task(async function test_load_favicon_invalid_redirect() {
|
add_task(async function test_load_favicon_invalid_redirect() {
|
||||||
let observed = TestUtils.topicObserved("console-api-log-event", msg => {
|
let observed = TestUtils.consoleMessageObserved(msg => {
|
||||||
return msg.wrappedJSObject.arguments[0].includes(
|
return msg.wrappedJSObject.arguments[0].includes(
|
||||||
"Content type does not match expected"
|
"Content type does not match expected"
|
||||||
);
|
);
|
||||||
|
|
|
@ -355,7 +355,7 @@ function parseStack(aStack) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format a frame coming from Components.stack such that it can be used by the
|
* Format a frame coming from Components.stack such that it can be used by the
|
||||||
* Browser Console, via console-api-log-event notifications.
|
* Browser Console, via ConsoleAPIStorage notifications.
|
||||||
*
|
*
|
||||||
* @param {object} aFrame
|
* @param {object} aFrame
|
||||||
* The stack frame from which to begin the walk.
|
* The stack frame from which to begin the walk.
|
||||||
|
@ -363,7 +363,7 @@ function parseStack(aStack) {
|
||||||
* Maximum stack trace depth. Default is 0 - no depth limit.
|
* Maximum stack trace depth. Default is 0 - no depth limit.
|
||||||
* @return {object[]}
|
* @return {object[]}
|
||||||
* An array of {filename, lineNumber, functionName, language} objects.
|
* An array of {filename, lineNumber, functionName, language} objects.
|
||||||
* These objects follow the same format as other console-api-log-event
|
* These objects follow the same format as other ConsoleAPIStorage
|
||||||
* messages.
|
* messages.
|
||||||
*/
|
*/
|
||||||
function getStack(aFrame, aMaxDepth = 0) {
|
function getStack(aFrame, aMaxDepth = 0) {
|
||||||
|
@ -522,8 +522,8 @@ function createMultiLineDumper(aLevel) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a Console API message. This function will send a console-api-log-event
|
* Send a Console API message. This function will send a notification through
|
||||||
* notification through the nsIObserverService.
|
* the nsIConsoleAPIStorage service.
|
||||||
*
|
*
|
||||||
* @param {object} aConsole
|
* @param {object} aConsole
|
||||||
* The instance of ConsoleAPI performing the logging.
|
* The instance of ConsoleAPI performing the logging.
|
||||||
|
@ -584,7 +584,7 @@ function sendConsoleAPIMessage(aConsole, aLevel, aFrame, aArgs, aOptions = {}) {
|
||||||
Ci.nsIConsoleAPIStorage
|
Ci.nsIConsoleAPIStorage
|
||||||
);
|
);
|
||||||
if (ConsoleAPIStorage) {
|
if (ConsoleAPIStorage) {
|
||||||
ConsoleAPIStorage.recordEvent("jsm", null, consoleEvent);
|
ConsoleAPIStorage.recordEvent("jsm", consoleEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче