зеркало из 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.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({
|
||||
policies: {},
|
||||
|
|
|
@ -185,21 +185,24 @@ registerCleanupFunction(function() {
|
|||
/**
|
||||
* Watch console messages for failed propType definitions in React components.
|
||||
*/
|
||||
const ConsoleObserver = {
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
|
||||
function onConsoleMessage(subject) {
|
||||
const message = subject.wrappedJSObject.arguments[0];
|
||||
|
||||
observe: function(subject) {
|
||||
const message = subject.wrappedJSObject.arguments[0];
|
||||
if (message && /Failed propType/.test(message.toString())) {
|
||||
ok(false, message);
|
||||
}
|
||||
}
|
||||
|
||||
if (message && /Failed propType/.test(message.toString())) {
|
||||
ok(false, message);
|
||||
}
|
||||
},
|
||||
};
|
||||
const ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"].getService(
|
||||
Ci.nsIConsoleAPIStorage
|
||||
);
|
||||
|
||||
Services.obs.addObserver(ConsoleObserver, "console-api-log-event");
|
||||
ConsoleAPIStorage.addLogEventListener(
|
||||
onConsoleMessage,
|
||||
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal)
|
||||
);
|
||||
registerCleanupFunction(() => {
|
||||
Services.obs.removeObserver(ConsoleObserver, "console-api-log-event");
|
||||
ConsoleAPIStorage.removeLogEventListener(onConsoleMessage);
|
||||
});
|
||||
|
||||
Services.prefs.setBoolPref("devtools.inspector.three-pane-enabled", true);
|
||||
|
|
|
@ -200,7 +200,7 @@ function getConsoleTableMessageItems(targetActor, result) {
|
|||
* @param TargetActor targetActor
|
||||
* The related target actor
|
||||
* @param object message
|
||||
* The original message received from console-api-log-event.
|
||||
* The original message received from the console storage listener.
|
||||
* @return object
|
||||
* The object that can be sent to the remote client.
|
||||
*/
|
||||
|
|
|
@ -2044,7 +2044,7 @@ const WebConsoleActor = ActorClassWithSpec(webconsoleSpec, {
|
|||
* instance.
|
||||
*
|
||||
* @param object message
|
||||
* The original message received from console-api-log-event.
|
||||
* The original message received from the console storage listener.
|
||||
* @param boolean aUseObjectGlobal
|
||||
* If |true| the object global is determined and added as a debuggee,
|
||||
* otherwise |this.global| is used when makeDebuggeeValue() is invoked.
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
"use strict";
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
|
@ -12,6 +15,12 @@ ChromeUtils.defineModuleGetter(
|
|||
"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
|
||||
* 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;
|
||||
|
||||
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.cpmm.addMessageListener(
|
||||
"DevTools:StopForwardingContentProcessMessage",
|
||||
|
@ -53,81 +66,76 @@ ContentProcessForward.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case "console-api-log-event": {
|
||||
const consoleMsg = subject.wrappedJSObject;
|
||||
onConsoleAPILogEvent(subject, data) {
|
||||
const consoleMsg = subject.wrappedJSObject;
|
||||
|
||||
const msgData = {
|
||||
...consoleMsg,
|
||||
arguments: [],
|
||||
filename: consoleMsg.filename.substring(0, MSG_MGR_CONSOLE_INFO_MAX),
|
||||
functionName:
|
||||
consoleMsg.functionName &&
|
||||
consoleMsg.functionName.substring(0, MSG_MGR_CONSOLE_INFO_MAX),
|
||||
// Prevents cyclic object error when using msgData in sendAsyncMessage
|
||||
wrappedJSObject: null,
|
||||
};
|
||||
const msgData = {
|
||||
...consoleMsg,
|
||||
arguments: [],
|
||||
filename: consoleMsg.filename.substring(0, MSG_MGR_CONSOLE_INFO_MAX),
|
||||
functionName:
|
||||
consoleMsg.functionName &&
|
||||
consoleMsg.functionName.substring(0, MSG_MGR_CONSOLE_INFO_MAX),
|
||||
// Prevents cyclic object error when using msgData in sendAsyncMessage
|
||||
wrappedJSObject: null,
|
||||
};
|
||||
|
||||
// We can't send objects over the message manager, so we sanitize
|
||||
// them out, replacing those arguments with "<unavailable>".
|
||||
const unavailString = "<unavailable>";
|
||||
const unavailStringLength = unavailString.length * 2; // 2-bytes per char
|
||||
// We can't send objects over the message manager, so we sanitize
|
||||
// them out, replacing those arguments with "<unavailable>".
|
||||
const unavailString = "<unavailable>";
|
||||
const unavailStringLength = unavailString.length * 2; // 2-bytes per char
|
||||
|
||||
// When the sum of argument sizes reaches MSG_MGR_CONSOLE_MAX_SIZE,
|
||||
// replace all arguments with "<truncated>".
|
||||
let totalArgLength = 0;
|
||||
// When the sum of argument sizes reaches MSG_MGR_CONSOLE_MAX_SIZE,
|
||||
// replace all arguments with "<truncated>".
|
||||
let totalArgLength = 0;
|
||||
|
||||
// Walk through the arguments, checking the type and size.
|
||||
for (let arg of consoleMsg.arguments) {
|
||||
if (
|
||||
(typeof arg == "object" || typeof arg == "function") &&
|
||||
arg !== null
|
||||
) {
|
||||
if (
|
||||
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
|
||||
// prominent we can revisit.
|
||||
try {
|
||||
// If the argument is clonable, then send it as-is. If
|
||||
// cloning fails, fall back to the unavailable string.
|
||||
arg = Cu.cloneInto(arg, {});
|
||||
} 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;
|
||||
// Walk through the arguments, checking the type and size.
|
||||
for (let arg of consoleMsg.arguments) {
|
||||
if (
|
||||
(typeof arg == "object" || typeof arg == "function") &&
|
||||
arg !== null
|
||||
) {
|
||||
if (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
|
||||
// prominent we can revisit.
|
||||
try {
|
||||
// If the argument is clonable, then send it as-is. If
|
||||
// cloning fails, fall back to the unavailable string.
|
||||
arg = Cu.cloneInto(arg, {});
|
||||
} catch (e) {
|
||||
arg = unavailString;
|
||||
}
|
||||
} else {
|
||||
arg = unavailString;
|
||||
}
|
||||
|
||||
Services.cpmm.sendAsyncMessage("Console:Log", msgData);
|
||||
break;
|
||||
totalArgLength += unavailStringLength;
|
||||
} else if (typeof arg == "string") {
|
||||
totalArgLength += arg.length * 2; // 2-bytes per char
|
||||
} else {
|
||||
totalArgLength += MSG_MGR_CONSOLE_VAR_SIZE;
|
||||
}
|
||||
|
||||
case "xpcom-shutdown":
|
||||
this.uninit();
|
||||
if (totalArgLength <= MSG_MGR_CONSOLE_MAX_SIZE) {
|
||||
msgData.arguments.push(arg);
|
||||
} else {
|
||||
// arguments take up too much space
|
||||
msgData.arguments = ["<truncated>"];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Services.cpmm.sendAsyncMessage("Console:Log", msgData);
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
if (topic == "xpcom-shutdown") {
|
||||
this.uninit();
|
||||
}
|
||||
},
|
||||
|
||||
uninit() {
|
||||
Services.obs.removeObserver(this, "console-api-log-event");
|
||||
ConsoleAPIStorage.removeLogEventListener(this.onConsoleAPILogEvent);
|
||||
Services.obs.removeObserver(this, "xpcom-shutdown");
|
||||
Services.cpmm.removeMessageListener(
|
||||
"DevTools:StopForwardingContentProcessMessage",
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
"use strict";
|
||||
|
||||
const { Cc, Ci } = require("chrome");
|
||||
const Services = require("Services");
|
||||
const ChromeUtils = require("ChromeUtils");
|
||||
const {
|
||||
CONSOLE_WORKER_IDS,
|
||||
|
@ -59,7 +58,7 @@ class ConsoleAPIListener {
|
|||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
@ -72,24 +71,34 @@ class ConsoleAPIListener {
|
|||
addonId = null;
|
||||
|
||||
/**
|
||||
* Initialize the window.console API observer.
|
||||
* Initialize the window.console API listener.
|
||||
*/
|
||||
init() {
|
||||
// Note that the observer is process-wide. We will filter the messages as
|
||||
// needed, see CAL_observe().
|
||||
Services.obs.addObserver(this, "console-api-log-event");
|
||||
const ConsoleAPIStorage = Cc[
|
||||
"@mozilla.org/consoleAPI-storage;1"
|
||||
].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
|
||||
* observer service we forward them to the remote Web Console instance.
|
||||
* The console API message listener. When messages are received from the
|
||||
* ConsoleAPIStorage service we forward them to the remote Web Console instance.
|
||||
*
|
||||
* @param object message
|
||||
* The message object receives from the observer service.
|
||||
* @param string topic
|
||||
* The message topic received from the observer service.
|
||||
* The message object receives from the ConsoleAPIStorage service.
|
||||
*/
|
||||
observe(message, topic) {
|
||||
onConsoleAPILogEvent(message) {
|
||||
if (!this.handler) {
|
||||
return;
|
||||
}
|
||||
|
@ -233,7 +242,10 @@ class ConsoleAPIListener {
|
|||
* Destroy the console API listener.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -291,17 +291,23 @@ const TESTS = {
|
|||
// the text passed as argument
|
||||
function onConsoleWarningLogged(warningMessage) {
|
||||
return new Promise(resolve => {
|
||||
const observer = {
|
||||
observe(subject) {
|
||||
// This is the first argument passed to console.warn()
|
||||
const message = subject.wrappedJSObject.arguments[0];
|
||||
if (message.includes(warningMessage)) {
|
||||
Services.obs.removeObserver(observer, "console-api-log-event");
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
const ConsoleAPIStorage = Cc[
|
||||
"@mozilla.org/consoleAPI-storage;1"
|
||||
].getService(Ci.nsIConsoleAPIStorage);
|
||||
|
||||
const observer = subject => {
|
||||
// This is the first argument passed to console.warn()
|
||||
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;
|
||||
}
|
||||
|
||||
nsAutoString innerID, outerID;
|
||||
nsAutoString innerID;
|
||||
|
||||
MOZ_ASSERT(aData->mIDType != ConsoleCallData::eUnknown);
|
||||
if (aData->mIDType == ConsoleCallData::eString) {
|
||||
outerID = aData->mOuterIDString;
|
||||
innerID = aData->mInnerIDString;
|
||||
} else {
|
||||
MOZ_ASSERT(aData->mIDType == ConsoleCallData::eNumber);
|
||||
outerID.AppendInt(aData->mOuterIDNumber);
|
||||
innerID.AppendInt(aData->mInnerIDNumber);
|
||||
}
|
||||
|
||||
|
@ -1549,7 +1547,7 @@ void MainThreadConsoleData::ProcessCallData(
|
|||
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.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,12 @@ const STORAGE_MAX_EVENTS = 1000;
|
|||
|
||||
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(
|
||||
"{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.
|
||||
*
|
||||
* @param string aId
|
||||
* The ID of the inner window for which the event occurred or "jsm" for
|
||||
* 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
|
||||
* A JavaScript object you want to store.
|
||||
*/
|
||||
recordEvent: function CS_recordEvent(aId, aOuterId, aEvent) {
|
||||
recordEvent: function CS_recordEvent(aId, aEvent) {
|
||||
if (!_consoleStorage.has(aId)) {
|
||||
_consoleStorage.set(aId, []);
|
||||
}
|
||||
|
@ -120,8 +166,13 @@ ConsoleAPIStorageService.prototype = {
|
|||
storage.shift();
|
||||
}
|
||||
|
||||
Services.obs.notifyObservers(aEvent, "console-api-log-event", aOuterId);
|
||||
Services.obs.notifyObservers(aEvent, "console-storage-cache-event", aId);
|
||||
for (let { callback, clone } of _logEventListeners) {
|
||||
if (clone) {
|
||||
callback(Cu.cloneInto(aEvent, callback));
|
||||
} else {
|
||||
callback(aEvent);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -138,7 +138,7 @@ void ConsoleUtils::ReportForServiceWorkerScopeInternal(
|
|||
return;
|
||||
}
|
||||
|
||||
storage->RecordEvent(u"ServiceWorker"_ns, aScope, eventValue);
|
||||
storage->RecordEvent(u"ServiceWorker"_ns, eventValue);
|
||||
}
|
||||
|
||||
JSObject* ConsoleUtils::GetOrCreateSandbox(JSContext* aCx) {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIPrincipal.idl"
|
||||
|
||||
[scriptable, uuid(9e32a7b6-c4d1-4d9a-87b9-1ef6b75c27a9)]
|
||||
interface nsIConsoleAPIStorage : nsISupports
|
||||
|
@ -21,19 +22,36 @@ interface nsIConsoleAPIStorage : nsISupports
|
|||
*/
|
||||
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.
|
||||
*
|
||||
* @param string aId
|
||||
* The ID of the inner window for which the event occurred or "jsm" for
|
||||
* 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
|
||||
* 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.
|
||||
|
|
|
@ -3,6 +3,7 @@ skip-if = os == 'android'
|
|||
support-files =
|
||||
file_empty.html
|
||||
console.jsm
|
||||
head.js
|
||||
|
||||
[test_console.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]
|
||||
support-files =
|
||||
file_empty.html
|
||||
head.js
|
||||
|
||||
[test_bug659625.html]
|
||||
[test_bug978522.html]
|
||||
|
|
|
@ -4,30 +4,28 @@
|
|||
<meta charset="utf-8">
|
||||
<title>Test Console binding</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/javascript">
|
||||
|
||||
function consoleListener() {
|
||||
SpecialPowers.addObserver(this, "console-api-log-event");
|
||||
addConsoleStorageListener(this);
|
||||
}
|
||||
|
||||
var order = 0;
|
||||
consoleListener.prototype = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == "console-api-log-event") {
|
||||
var obj = aSubject.wrappedJSObject;
|
||||
ok(!obj.chromeContext, "Thils is not a chrome context");
|
||||
if (order + 1 == parseInt(obj.arguments[0])) {
|
||||
ok(true, "Message received: " + obj.arguments[0]);
|
||||
order++;
|
||||
}
|
||||
observe(obj) {
|
||||
ok(!obj.chromeContext, "Thils is not a chrome context");
|
||||
if (order + 1 == parseInt(obj.arguments[0])) {
|
||||
ok(true, "Message received: " + obj.arguments[0]);
|
||||
order++;
|
||||
}
|
||||
|
||||
if (order == 3) {
|
||||
SpecialPowers.removeObserver(this, "console-api-log-event");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
if (order == 3) {
|
||||
removeConsoleStorageListener(this);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
<meta charset="utf-8">
|
||||
<title>Test for count/countReset in console</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -12,11 +13,11 @@
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function ConsoleListener() {
|
||||
SpecialPowers.addObserver(this, "console-api-log-event");
|
||||
addConsoleStorageListener(this);
|
||||
}
|
||||
|
||||
ConsoleListener.prototype = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
observe(aSubject) {
|
||||
let obj = aSubject.wrappedJSObject;
|
||||
if (obj.arguments[0] != "test") {
|
||||
return;
|
||||
|
@ -36,7 +37,7 @@ ConsoleListener.prototype = {
|
|||
},
|
||||
|
||||
shutdown() {
|
||||
SpecialPowers.removeObserver(this, "console-api-log-event");
|
||||
removeConsoleStorageListener(this);
|
||||
},
|
||||
|
||||
waitFor(cb) {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
<script src="head.js"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
@ -29,52 +30,50 @@ function promiseConsoleListenerCalled() {
|
|||
let consoleListener = {
|
||||
count: 0,
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
if (aTopic == "console-api-log-event") {
|
||||
var obj = aSubject.wrappedJSObject;
|
||||
ok(obj.chromeContext, "JSM is always a chrome context");
|
||||
observe: function(aSubject) {
|
||||
var obj = aSubject.wrappedJSObject;
|
||||
ok(obj.chromeContext, "JSM is always a chrome context");
|
||||
|
||||
if (obj.innerID == JSM) {
|
||||
is(obj.ID, "jsm", "ID and InnerID are correctly set.");
|
||||
is(obj.arguments[0], "Hello world!", "Message matches");
|
||||
is(obj.consoleID, "", "No consoleID for console API");
|
||||
is(obj.prefix, "", "prefix is empty by default");
|
||||
if (obj.innerID == JSM) {
|
||||
is(obj.ID, "jsm", "ID and InnerID are correctly set.");
|
||||
is(obj.arguments[0], "Hello world!", "Message matches");
|
||||
is(obj.consoleID, "", "No consoleID for console API");
|
||||
is(obj.prefix, "", "prefix is empty by default");
|
||||
|
||||
// We want to see 2 messages from this innerID, the first is generated
|
||||
// by console.log, the second one from createInstance().log();
|
||||
++this.count;
|
||||
} else if (obj.innerID == "CUSTOM INNER") {
|
||||
is(obj.ID, "jsm", "ID and InnerID are correctly set.");
|
||||
is(obj.arguments[0], "Hello world!", "Message matches");
|
||||
is(obj.consoleID, "wow", "consoleID is set by consoleInstance");
|
||||
is(obj.prefix, "_PREFIX_", "prefix is set by consoleInstance");
|
||||
// We expect to see 2 messages from this innerID.
|
||||
++this.count;
|
||||
} else if (obj.innerID == "LEVEL") {
|
||||
// Nothing special... just we don't want to see 'invisible' messages.
|
||||
is(obj.ID, "jsm", "ID and InnerID are correctly set.");
|
||||
is(obj.arguments[0], "Hello world!", "Message matches");
|
||||
is(obj.prefix, "", "prefix is empty by default");
|
||||
// We expect to see 2 messages from this innerID.
|
||||
++this.count;
|
||||
} else if (obj.innerID == "NO PREF") {
|
||||
// Nothing special... just we don't want to see 'invisible' messages.
|
||||
is(obj.ID, "jsm", "ID and InnerID are correctly set.");
|
||||
is(obj.arguments[0], "Hello world!", "Message matches");
|
||||
is(obj.prefix, "", "prefix is empty by default");
|
||||
// We expect to see 2 messages from this innerID.
|
||||
++this.count;
|
||||
}
|
||||
// We want to see 2 messages from this innerID, the first is generated
|
||||
// by console.log, the second one from createInstance().log();
|
||||
++this.count;
|
||||
} else if (obj.innerID == "CUSTOM INNER") {
|
||||
is(obj.ID, "jsm", "ID and InnerID are correctly set.");
|
||||
is(obj.arguments[0], "Hello world!", "Message matches");
|
||||
is(obj.consoleID, "wow", "consoleID is set by consoleInstance");
|
||||
is(obj.prefix, "_PREFIX_", "prefix is set by consoleInstance");
|
||||
// We expect to see 2 messages from this innerID.
|
||||
++this.count;
|
||||
} else if (obj.innerID == "LEVEL") {
|
||||
// Nothing special... just we don't want to see 'invisible' messages.
|
||||
is(obj.ID, "jsm", "ID and InnerID are correctly set.");
|
||||
is(obj.arguments[0], "Hello world!", "Message matches");
|
||||
is(obj.prefix, "", "prefix is empty by default");
|
||||
// We expect to see 2 messages from this innerID.
|
||||
++this.count;
|
||||
} else if (obj.innerID == "NO PREF") {
|
||||
// Nothing special... just we don't want to see 'invisible' messages.
|
||||
is(obj.ID, "jsm", "ID and InnerID are correctly set.");
|
||||
is(obj.arguments[0], "Hello world!", "Message matches");
|
||||
is(obj.prefix, "", "prefix is empty by default");
|
||||
// We expect to see 2 messages from this innerID.
|
||||
++this.count;
|
||||
}
|
||||
|
||||
if (this.count == 8) {
|
||||
is(dumpCalled, 2, "Dump has been called!");
|
||||
Services.obs.removeObserver(consoleListener, "console-api-log-event");
|
||||
resolve();
|
||||
}
|
||||
if (this.count == 8) {
|
||||
is(dumpCalled, 2, "Dump has been called!");
|
||||
removeConsoleStorageListener(consoleListener);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
}
|
||||
Services.obs.addObserver(consoleListener, "console-api-log-event");
|
||||
addConsoleStorageListener(consoleListener);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
<meta charset="utf-8">
|
||||
<title>Test for timeStart/timeLog/timeEnd in console</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -15,11 +16,11 @@ var reduceTimePrecisionPrevPrefValue = SpecialPowers.getBoolPref("privacy.reduce
|
|||
SpecialPowers.setBoolPref("privacy.reduceTimerPrecision", false);
|
||||
|
||||
function ConsoleListener() {
|
||||
SpecialPowers.addObserver(this, "console-api-log-event");
|
||||
addConsoleStorageListener(this);
|
||||
}
|
||||
|
||||
ConsoleListener.prototype = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
observe(aSubject) {
|
||||
let obj = aSubject.wrappedJSObject;
|
||||
if (obj.arguments[0] != "test_bug1463614") {
|
||||
return;
|
||||
|
@ -34,7 +35,7 @@ ConsoleListener.prototype = {
|
|||
},
|
||||
|
||||
shutdown() {
|
||||
SpecialPowers.removeObserver(this, "console-api-log-event");
|
||||
removeConsoleStorageListener(this);
|
||||
},
|
||||
|
||||
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 => {
|
||||
function consoleListener() {
|
||||
Services.obs.addObserver(this, "console-api-log-event");
|
||||
addConsoleStorageListener(this);
|
||||
}
|
||||
|
||||
consoleListener.prototype = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
observe(aSubject) {
|
||||
let obj = aSubject.wrappedJSObject;
|
||||
Assert.ok(obj.arguments[0] === 42, "Message received!");
|
||||
Assert.ok(obj.ID === "jsm", "The ID is JSM");
|
||||
Assert.ok(obj.innerID.endsWith("test_basic.js"), "The innerID matches");
|
||||
|
||||
Services.obs.removeObserver(this, "console-api-log-event");
|
||||
removeConsoleStorageListener(this);
|
||||
resolve();
|
||||
},
|
||||
};
|
||||
|
|
|
@ -40,11 +40,11 @@ add_task(async function() {
|
|||
let t = 0;
|
||||
|
||||
function consoleListener() {
|
||||
Services.obs.addObserver(this, "console-api-log-event");
|
||||
addConsoleStorageListener(this);
|
||||
}
|
||||
|
||||
consoleListener.prototype = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
observe(aSubject) {
|
||||
let test = tests[t++];
|
||||
|
||||
let obj = aSubject.wrappedJSObject;
|
||||
|
@ -62,7 +62,7 @@ add_task(async function() {
|
|||
}
|
||||
|
||||
if (t === tests.length) {
|
||||
Services.obs.removeObserver(this, "console-api-log-event");
|
||||
removeConsoleStorageListener(this);
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
|
|
|
@ -6,11 +6,11 @@ const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|||
add_task(async function() {
|
||||
let p = new Promise(resolve => {
|
||||
function consoleListener() {
|
||||
Services.obs.addObserver(this, "console-api-log-event");
|
||||
addConsoleStorageListener(this);
|
||||
}
|
||||
|
||||
consoleListener.prototype = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
observe(aSubject) {
|
||||
let obj = aSubject.wrappedJSObject;
|
||||
Assert.ok(obj.arguments[0] === "Hello world!", "Message received!");
|
||||
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.level === "error", "The level is correct");
|
||||
|
||||
Services.obs.removeObserver(this, "console-api-log-event");
|
||||
removeConsoleStorageListener(this);
|
||||
resolve();
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[DEFAULT]
|
||||
head =
|
||||
head = head.js
|
||||
support-files =
|
||||
|
||||
[test_basic.js]
|
||||
|
|
|
@ -41,8 +41,6 @@ support-files =
|
|||
support-files =
|
||||
prevent_return_key.html
|
||||
[browser_ConsoleAPI_originAttributes.js]
|
||||
[browser_ConsoleAPITests.js]
|
||||
skip-if = e10s
|
||||
[browser_ConsoleStorageAPITests.js]
|
||||
[browser_ConsoleStoragePBTest_perwindowpb.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 EXPECTED_CONSOLE_ID = `addon/${FAKE_ADDON_ID}`;
|
||||
const EXPECTED_CONSOLE_MESSAGE_CONTENT = "fake-webext-addon-test-log-message";
|
||||
const ConsoleObserver = {
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
|
||||
|
||||
const ConsoleObserver = {
|
||||
init() {
|
||||
Services.obs.addObserver(this, "console-api-log-event");
|
||||
ConsoleAPIStorage.addLogEventListener(
|
||||
this.observe,
|
||||
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal)
|
||||
);
|
||||
},
|
||||
|
||||
uninit() {
|
||||
Services.obs.removeObserver(this, "console-api-log-event");
|
||||
ConsoleAPIStorage.removeLogEventListener(this.observe);
|
||||
},
|
||||
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == "console-api-log-event") {
|
||||
let consoleAPIMessage = aSubject.wrappedJSObject;
|
||||
observe(aSubject) {
|
||||
let consoleAPIMessage = aSubject.wrappedJSObject;
|
||||
|
||||
is(
|
||||
consoleAPIMessage.arguments[0],
|
||||
EXPECTED_CONSOLE_MESSAGE_CONTENT,
|
||||
"the consoleAPIMessage contains the expected message"
|
||||
);
|
||||
is(
|
||||
consoleAPIMessage.arguments[0],
|
||||
EXPECTED_CONSOLE_MESSAGE_CONTENT,
|
||||
"the consoleAPIMessage contains the expected message"
|
||||
);
|
||||
|
||||
is(
|
||||
consoleAPIMessage.addonId,
|
||||
FAKE_ADDON_ID,
|
||||
"the consoleAPImessage originAttributes contains the expected addonId"
|
||||
);
|
||||
is(
|
||||
consoleAPIMessage.addonId,
|
||||
FAKE_ADDON_ID,
|
||||
"the consoleAPImessage originAttributes contains the expected addonId"
|
||||
);
|
||||
|
||||
let cachedMessages = ConsoleAPIStorage.getEvents().filter(msg => {
|
||||
return msg.addonId == FAKE_ADDON_ID;
|
||||
});
|
||||
let cachedMessages = ConsoleAPIStorage.getEvents().filter(msg => {
|
||||
return msg.addonId == FAKE_ADDON_ID;
|
||||
});
|
||||
|
||||
is(
|
||||
cachedMessages.length,
|
||||
1,
|
||||
"found the expected cached console messages from the addon"
|
||||
);
|
||||
is(
|
||||
cachedMessages[0] && cachedMessages[0].addonId,
|
||||
FAKE_ADDON_ID,
|
||||
"the cached message originAttributes contains the expected addonId"
|
||||
);
|
||||
is(
|
||||
cachedMessages.length,
|
||||
1,
|
||||
"found the expected cached console messages from the addon"
|
||||
);
|
||||
is(
|
||||
cachedMessages[0] && cachedMessages[0].addonId,
|
||||
FAKE_ADDON_ID,
|
||||
"the cached message originAttributes contains the expected addonId"
|
||||
);
|
||||
|
||||
finish();
|
||||
}
|
||||
finish();
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -35,23 +35,20 @@ add_task(async function() {
|
|||
|
||||
let observerPromise = new Promise(resolve => {
|
||||
let apiCallCount = 0;
|
||||
let ConsoleObserver = {
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
|
||||
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == "console-storage-cache-event") {
|
||||
apiCallCount++;
|
||||
info(`Received ${apiCallCount} "console-storage-cache-event"`);
|
||||
if (apiCallCount == 4) {
|
||||
Services.obs.removeObserver(this, "console-storage-cache-event");
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
function observe(aSubject) {
|
||||
apiCallCount++;
|
||||
info(`Received ${apiCallCount} console log events`);
|
||||
if (apiCallCount == 4) {
|
||||
ConsoleAPIStorage.removeLogEventListener(observe);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
|
@ -60,7 +57,7 @@ add_task(async function() {
|
|||
content.console.warn("this", "is", "a", "warn", "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;
|
||||
|
||||
const innerWindowId = content.windowGlobalChild.innerWindowId;
|
||||
|
|
|
@ -9,7 +9,6 @@ function test() {
|
|||
let beforeEvents;
|
||||
let afterEvents;
|
||||
let storageShouldOccur;
|
||||
let consoleObserver;
|
||||
let testURI =
|
||||
"http://example.com/browser/dom/tests/browser/test-console-api.html";
|
||||
let ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"].getService(
|
||||
|
@ -34,30 +33,23 @@ function test() {
|
|||
function doTest(aIsPrivateMode, aWindow, aCallback) {
|
||||
BrowserTestUtils.browserLoaded(aWindow.gBrowser.selectedBrowser).then(
|
||||
() => {
|
||||
consoleObserver = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == "console-api-log-event") {
|
||||
afterEvents = ConsoleAPIStorage.getEvents(innerID);
|
||||
is(
|
||||
beforeEvents.length == afterEvents.length - 1,
|
||||
storageShouldOccur,
|
||||
"storage should" + (storageShouldOccur ? "" : " not") + " occur"
|
||||
);
|
||||
function observe(aSubject) {
|
||||
afterEvents = ConsoleAPIStorage.getEvents(innerID);
|
||||
is(
|
||||
beforeEvents.length == afterEvents.length - 1,
|
||||
storageShouldOccur,
|
||||
"storage should" + (storageShouldOccur ? "" : " not") + " occur"
|
||||
);
|
||||
|
||||
executeSoon(function() {
|
||||
Services.obs.removeObserver(
|
||||
consoleObserver,
|
||||
"console-api-log-event"
|
||||
);
|
||||
aCallback();
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
executeSoon(function() {
|
||||
ConsoleAPIStorage.removeLogEventListener(observe);
|
||||
aCallback();
|
||||
});
|
||||
}
|
||||
|
||||
aWindow.Services.obs.addObserver(
|
||||
consoleObserver,
|
||||
"console-api-log-event"
|
||||
ConsoleAPIStorage.addLogEventListener(
|
||||
observe,
|
||||
aWindow.document.nodePrincipal
|
||||
);
|
||||
aWindow.nativeConsole.log(
|
||||
"foo bar baz (private: " + aIsPrivateMode + ")"
|
||||
|
|
|
@ -9,26 +9,29 @@ add_task(async function() {
|
|||
|
||||
await BrowserTestUtils.withNewTab(TEST_URI, async aBrowser => {
|
||||
let duration = await SpecialPowers.spawn(aBrowser, [], function(opts) {
|
||||
const ConsoleAPIStorage = Cc[
|
||||
"@mozilla.org/consoleAPI-storage;1"
|
||||
].getService(Ci.nsIConsoleAPIStorage);
|
||||
|
||||
return new Promise(resolve => {
|
||||
let ConsoleObserver = {
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
|
||||
function observe(aSubject) {
|
||||
var obj = aSubject.wrappedJSObject;
|
||||
if (
|
||||
obj.arguments.length != 1 ||
|
||||
obj.arguments[0] != "bug1004814" ||
|
||||
obj.level != "timeEnd"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
observe(aSubject, aTopic, aData) {
|
||||
var obj = aSubject.wrappedJSObject;
|
||||
if (
|
||||
obj.arguments.length != 1 ||
|
||||
obj.arguments[0] != "bug1004814" ||
|
||||
obj.level != "timeEnd"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
ConsoleAPIStorage.removeLogEventListener(observe);
|
||||
resolve(obj.timer.duration);
|
||||
}
|
||||
|
||||
Services.obs.removeObserver(this, "console-api-log-event");
|
||||
resolve(obj.timer.duration);
|
||||
},
|
||||
};
|
||||
|
||||
Services.obs.addObserver(ConsoleObserver, "console-api-log-event");
|
||||
ConsoleAPIStorage.addLogEventListener(
|
||||
observe,
|
||||
Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal)
|
||||
);
|
||||
|
||||
var w = new content.Worker("worker_bug1004814.js");
|
||||
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) {
|
||||
function consoleListener() {
|
||||
that.SpecialPowers.addObserver(this, "console-api-log-event");
|
||||
addConsoleStorageListener(this);
|
||||
}
|
||||
|
||||
var promise = new Promise(resolve => {
|
||||
consoleListener.prototype = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
observe(aSubject) {
|
||||
that.ok(true, "Something has been received");
|
||||
that.is(aTopic, "console-api-log-event");
|
||||
|
||||
var obj = aSubject.wrappedJSObject;
|
||||
if (obj.arguments[0] && obj.arguments[0] === "pull called") {
|
||||
that.ok(true, "Message received!");
|
||||
that.SpecialPowers.removeObserver(this, "console-api-log-event");
|
||||
removeConsoleStorageListener(this);
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
|
|
|
@ -10,14 +10,37 @@ add_task(async function test() {
|
|||
await BrowserTestUtils.browserLoaded(gBrowser.getBrowserForTab(tab));
|
||||
|
||||
let promise = new Promise(resolve => {
|
||||
const ConsoleAPIStorage = SpecialPowers.Cc[
|
||||
"@mozilla.org/consoleAPI-storage;1"
|
||||
].getService(SpecialPowers.Ci.nsIConsoleAPIStorage);
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
var order = 0;
|
||||
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");
|
||||
|
||||
if (aTopic == "console-api-profiler") {
|
||||
|
@ -30,23 +53,6 @@ add_task(async function test() {
|
|||
is(order++, 0, "First a profiler message.");
|
||||
|
||||
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;
|
||||
function test() {
|
||||
const ConsoleAPIStorage = SpecialPowers.Cc[
|
||||
"@mozilla.org/consoleAPI-storage;1"
|
||||
].getService(SpecialPowers.Ci.nsIConsoleAPIStorage);
|
||||
|
||||
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 = {
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
if (aTopic == "console-api-log-event") {
|
||||
var obj = aSubject.wrappedJSObject;
|
||||
if (obj.arguments[0] == "Hello from the debugger script!" &&
|
||||
!consoleMessagesReceived) {
|
||||
consoleMessagesReceived++;
|
||||
ok(true, "Something has been received");
|
||||
Services.obs.removeObserver(this, "console-api-log-event");
|
||||
}
|
||||
observe: function(aSubject) {
|
||||
var obj = aSubject.wrappedJSObject;
|
||||
if (obj.arguments[0] == "Hello from the debugger script!" &&
|
||||
!consoleMessagesReceived) {
|
||||
consoleMessagesReceived++;
|
||||
ok(true, "Something has been received");
|
||||
ConsoleAPIStorage.removeLogEventListener(this.observe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,20 +12,23 @@
|
|||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
const ConsoleAPIStorage = SpecialPowers.Cc[
|
||||
"@mozilla.org/consoleAPI-storage;1"
|
||||
].getService(SpecialPowers.Ci.nsIConsoleAPIStorage);
|
||||
|
||||
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;
|
||||
consoleListener.prototype = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
observe(aSubject) {
|
||||
ok(true, "Something has been received");
|
||||
is(aTopic, "console-api-log-event");
|
||||
|
||||
var obj = aSubject.wrappedJSObject;
|
||||
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.type, 'foo/bar', "The type is correct");
|
||||
SimpleTest.finish();
|
||||
|
|
|
@ -11,21 +11,24 @@
|
|||
<script type="application/javascript">
|
||||
|
||||
function configureTest() {
|
||||
const ConsoleAPIStorage = SpecialPowers.Cc[
|
||||
"@mozilla.org/consoleAPI-storage;1"
|
||||
].getService(SpecialPowers.Ci.nsIConsoleAPIStorage);
|
||||
|
||||
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 = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == "console-api-log-event") {
|
||||
var obj = aSubject.wrappedJSObject;
|
||||
if (obj.arguments[0] == "So far so good") {
|
||||
ok(true, "Message received \\o/");
|
||||
observe(aSubject) {
|
||||
var obj = aSubject.wrappedJSObject;
|
||||
if (obj.arguments[0] == "So far so good") {
|
||||
ok(true, "Message received \\o/");
|
||||
|
||||
SpecialPowers.removeObserver(this, "console-api-log-event");
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
ConsoleAPIStorage.removeLogEventListener(this.observe);
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,26 +31,29 @@ function configureTest() {
|
|||
|
||||
var expected_errors_i = 0;
|
||||
|
||||
const ConsoleAPIStorage = SpecialPowers.Cc[
|
||||
"@mozilla.org/consoleAPI-storage;1"
|
||||
].getService(SpecialPowers.Ci.nsIConsoleAPIStorage);
|
||||
|
||||
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 = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == "console-api-log-event") {
|
||||
var obj = aSubject.wrappedJSObject;
|
||||
if (obj.arguments[0] == expected_errors[expected_errors_i]) {
|
||||
ok(true, "Expected error received: " + obj.arguments[0]);
|
||||
expected_errors_i++;
|
||||
}
|
||||
observe(aSubject) {
|
||||
var obj = aSubject.wrappedJSObject;
|
||||
if (obj.arguments[0] == expected_errors[expected_errors_i]) {
|
||||
ok(true, "Expected error received: " + obj.arguments[0]);
|
||||
expected_errors_i++;
|
||||
}
|
||||
|
||||
if (expected_errors_i == expected_errors.length) {
|
||||
// All errors have been received, this test has been completed
|
||||
// succesfully!
|
||||
SpecialPowers.removeObserver(this, "console-api-log-event");
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
if (expected_errors_i == expected_errors.length) {
|
||||
// All errors have been received, this test has been completed
|
||||
// succesfully!
|
||||
ConsoleAPIStorage.removeLogEventListener(this.observe);
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,23 +12,26 @@
|
|||
const WORKLET_SCRIPT = "worklet_console.js";
|
||||
|
||||
function configureTest() {
|
||||
const ConsoleAPIStorage = SpecialPowers.Cc[
|
||||
"@mozilla.org/consoleAPI-storage;1"
|
||||
].getService(SpecialPowers.Ci.nsIConsoleAPIStorage);
|
||||
|
||||
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 = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == "console-api-log-event") {
|
||||
var obj = aSubject.wrappedJSObject;
|
||||
if (obj.arguments[0] == "Hello world from a worklet") {
|
||||
ok(true, "Message received \\o/");
|
||||
is(obj.filename,
|
||||
new URL(WORKLET_SCRIPT, document.baseURI).toString());
|
||||
observe(aSubject) {
|
||||
var obj = aSubject.wrappedJSObject;
|
||||
if (obj.arguments[0] == "Hello world from a worklet") {
|
||||
ok(true, "Message received \\o/");
|
||||
is(obj.filename,
|
||||
new URL(WORKLET_SCRIPT, document.baseURI).toString());
|
||||
|
||||
SpecialPowers.removeObserver(this, "console-api-log-event");
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
ConsoleAPIStorage.removeLogEventListener(this.observe);
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,21 +11,24 @@
|
|||
<script type="application/javascript">
|
||||
|
||||
function configureTest() {
|
||||
const ConsoleAPIStorage = SpecialPowers.Cc[
|
||||
"@mozilla.org/consoleAPI-storage;1"
|
||||
].getService(SpecialPowers.Ci.nsIConsoleAPIStorage);
|
||||
|
||||
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 = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == "console-api-log-event") {
|
||||
var obj = aSubject.wrappedJSObject;
|
||||
if (obj.arguments[0] == "So far so good") {
|
||||
ok(true, "Message received \\o/");
|
||||
observe(aSubject) {
|
||||
var obj = aSubject.wrappedJSObject;
|
||||
if (obj.arguments[0] == "So far so good") {
|
||||
ok(true, "Message received \\o/");
|
||||
|
||||
SpecialPowers.removeObserver(this, "console-api-log-event");
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
ConsoleAPIStorage.removeLogEventListener(this.observe);
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
|
||||
const { debug, warn } = GeckoViewUtils.initLogging("Console");
|
||||
|
||||
const LOG_EVENT_TOPIC = "console-api-log-event";
|
||||
|
||||
var GeckoViewConsole = {
|
||||
_isEnabled: false,
|
||||
|
||||
|
@ -34,21 +32,24 @@ var GeckoViewConsole = {
|
|||
}
|
||||
|
||||
this._isEnabled = !!aVal;
|
||||
const ConsoleAPIStorage = Cc[
|
||||
"@mozilla.org/consoleAPI-storage;1"
|
||||
].getService(Ci.nsIConsoleAPIStorage);
|
||||
if (this._isEnabled) {
|
||||
Services.obs.addObserver(this, LOG_EVENT_TOPIC);
|
||||
} else {
|
||||
Services.obs.removeObserver(this, LOG_EVENT_TOPIC);
|
||||
this._consoleMessageListener = this._handleConsoleMessage.bind(this);
|
||||
ConsoleAPIStorage.addLogEventListener(
|
||||
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) {
|
||||
switch (aTopic) {
|
||||
case "nsPref:changed":
|
||||
this.enabled = Services.prefs.getBoolPref(aData, false);
|
||||
break;
|
||||
case LOG_EVENT_TOPIC:
|
||||
this._handleConsoleMessage(aSubject);
|
||||
break;
|
||||
if (aTopic == "nsPref:changed") {
|
||||
this.enabled = Services.prefs.getBoolPref(aData, false);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -21,11 +21,15 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
"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
|
||||
addDebuggerToGlobal(Cu.getGlobalForObject(this));
|
||||
|
||||
const OBSERVER_CONSOLE_API = "console-api-log-event";
|
||||
|
||||
const CONSOLE_API_LEVEL_MAP = {
|
||||
warn: "warning",
|
||||
};
|
||||
|
@ -97,7 +101,11 @@ class Runtime extends ContentProcessDomain {
|
|||
this.enabled = true;
|
||||
|
||||
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
|
||||
// after we replied to `enable` request.
|
||||
|
@ -116,7 +124,7 @@ class Runtime extends ContentProcessDomain {
|
|||
this.enabled = false;
|
||||
|
||||
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
|
||||
|
||||
/**
|
||||
|
@ -581,14 +594,8 @@ class Runtime extends ContentProcessDomain {
|
|||
* Console message.
|
||||
*/
|
||||
observe(subject, topic, data) {
|
||||
let entry;
|
||||
|
||||
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);
|
||||
if (subject instanceof Ci.nsIScriptError && subject.hasException) {
|
||||
let entry = fromScriptError(subject);
|
||||
this._emitExceptionThrown(entry);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,12 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
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;
|
||||
}
|
||||
|
||||
Services.obs.addObserver(
|
||||
ConsoleAPIStorage.addLogEventListener(
|
||||
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.
|
||||
this.#emitCachedMessages();
|
||||
|
||||
|
@ -85,18 +90,11 @@ class ConsoleAPIListener {
|
|||
return;
|
||||
}
|
||||
|
||||
Services.obs.removeObserver(
|
||||
this.#onConsoleAPIMessage,
|
||||
"console-api-log-event"
|
||||
);
|
||||
ConsoleAPIStorage.removeLogEventListener(this.#onConsoleAPIMessage);
|
||||
this.#listening = false;
|
||||
}
|
||||
|
||||
#emitCachedMessages() {
|
||||
const ConsoleAPIStorage = Cc[
|
||||
"@mozilla.org/consoleAPI-storage;1"
|
||||
].getService(Ci.nsIConsoleAPIStorage);
|
||||
|
||||
const cachedMessages = ConsoleAPIStorage.getEvents(this.#innerWindowId);
|
||||
for (const message of cachedMessages) {
|
||||
this.#onConsoleAPIMessage(message);
|
||||
|
|
|
@ -24,6 +24,9 @@ const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|||
const { clearTimeout, setTimeout } = ChromeUtils.import(
|
||||
"resource://gre/modules/Timer.jsm"
|
||||
);
|
||||
const ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"].getService(
|
||||
Ci.nsIConsoleAPIStorage
|
||||
);
|
||||
|
||||
var TestUtils = {
|
||||
executeSoon(callbackFn) {
|
||||
|
@ -34,6 +37,64 @@ var TestUtils = {
|
|||
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.
|
||||
*
|
||||
|
|
|
@ -137,17 +137,6 @@ SPConsoleListener.prototype = {
|
|||
m.innerWindowID = msg.innerWindowID;
|
||||
m.isScriptError = true;
|
||||
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);
|
||||
|
@ -159,7 +148,6 @@ SPConsoleListener.prototype = {
|
|||
});
|
||||
|
||||
if (!m.isScriptError && !m.isConsoleEvent && m.message === "SENTINEL") {
|
||||
Services.obs.removeObserver(this, "console-api-log-event");
|
||||
Services.console.unregisterListener(this);
|
||||
}
|
||||
},
|
||||
|
@ -1197,9 +1185,6 @@ class SpecialPowersChild extends JSWindowActorChild {
|
|||
registerConsoleListener(callback) {
|
||||
let listener = new SPConsoleListener(callback, this.contentWindow);
|
||||
Services.console.registerListener(listener);
|
||||
|
||||
// listen for dom/console events as well
|
||||
Services.obs.addObserver(listener, "console-api-log-event");
|
||||
}
|
||||
postConsoleSentinel() {
|
||||
Services.console.logStringMessage("SENTINEL");
|
||||
|
|
|
@ -411,21 +411,25 @@ let consoleAllowList = [
|
|||
'property "profileDir" is non-configurable and can\'t be deleted',
|
||||
];
|
||||
|
||||
let consoleListener = {
|
||||
observe(subject, topic, data) {
|
||||
let msg = subject.wrappedJSObject;
|
||||
let messageContents = msg.arguments[0]?.message || msg.arguments[0];
|
||||
if (
|
||||
msg.level == "error" &&
|
||||
!consoleAllowList.some(e => messageContents.includes(e))
|
||||
) {
|
||||
Assert.ok(false, "Unexpected console message: " + messageContents);
|
||||
}
|
||||
},
|
||||
};
|
||||
function observe(subject) {
|
||||
let msg = subject.wrappedJSObject;
|
||||
let messageContents = msg.arguments[0]?.message || msg.arguments[0];
|
||||
if (
|
||||
msg.level == "error" &&
|
||||
!consoleAllowList.some(e => messageContents.includes(e))
|
||||
) {
|
||||
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 () => {
|
||||
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() {
|
||||
let observed = TestUtils.topicObserved("console-api-log-event", msg => {
|
||||
let observed = TestUtils.consoleMessageObserved(msg => {
|
||||
return msg.wrappedJSObject.arguments[0].includes(
|
||||
"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() {
|
||||
let observed = TestUtils.topicObserved("console-api-log-event", msg => {
|
||||
let observed = TestUtils.consoleMessageObserved(msg => {
|
||||
return msg.wrappedJSObject.arguments[0].includes(
|
||||
"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() {
|
||||
let observed = TestUtils.topicObserved("console-api-log-event", msg => {
|
||||
let observed = TestUtils.consoleMessageObserved(msg => {
|
||||
return msg.wrappedJSObject.arguments[0].includes(
|
||||
"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
|
||||
* Browser Console, via console-api-log-event notifications.
|
||||
* Browser Console, via ConsoleAPIStorage notifications.
|
||||
*
|
||||
* @param {object} aFrame
|
||||
* 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.
|
||||
* @return {object[]}
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
* notification through the nsIObserverService.
|
||||
* Send a Console API message. This function will send a notification through
|
||||
* the nsIConsoleAPIStorage service.
|
||||
*
|
||||
* @param {object} aConsole
|
||||
* The instance of ConsoleAPI performing the logging.
|
||||
|
@ -584,7 +584,7 @@ function sendConsoleAPIMessage(aConsole, aLevel, aFrame, aArgs, aOptions = {}) {
|
|||
Ci.nsIConsoleAPIStorage
|
||||
);
|
||||
if (ConsoleAPIStorage) {
|
||||
ConsoleAPIStorage.recordEvent("jsm", null, consoleEvent);
|
||||
ConsoleAPIStorage.recordEvent("jsm", consoleEvent);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче