зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1561435 - Format testing/, a=automatic-formatting
# ignore-this-changeset Differential Revision: https://phabricator.services.mozilla.com/D35962 --HG-- extra : source : c0948f31e520ca087279cf429ca5f1db5a8341b8
This commit is contained in:
Родитель
4998c97d04
Коммит
2b036e45c5
|
@ -45,7 +45,6 @@ module.exports = {
|
|||
"overrides": [{
|
||||
"files": [
|
||||
"devtools/**",
|
||||
"testing/**",
|
||||
"toolkit/**",
|
||||
"tools/**",
|
||||
"uriloader/**",
|
||||
|
|
|
@ -40,7 +40,6 @@ toolkit/components/telemetry/datareporting-prefs.js
|
|||
toolkit/components/telemetry/healthreport-prefs.js
|
||||
|
||||
# Ignore all top-level directories for now.
|
||||
testing/**
|
||||
toolkit/**
|
||||
tools/**
|
||||
uriloader/**
|
||||
|
@ -81,6 +80,9 @@ devtools/server/**
|
|||
devtools/shared/**
|
||||
devtools/startup/**
|
||||
|
||||
# Ignore testing pref files which aren't parsed normally.
|
||||
testing/profiles/**/user.js
|
||||
|
||||
# Ignore CORS fixtures which require specific resource hashes.
|
||||
dom/security/test/sri/script*
|
||||
|
||||
|
|
|
@ -4,18 +4,23 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const {ElementNotAccessibleError} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const {Log} = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
const { ElementNotAccessibleError } = ChromeUtils.import(
|
||||
"chrome://marionette/content/error.js"
|
||||
);
|
||||
const { Log } = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", Log.get);
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "service", () => {
|
||||
try {
|
||||
return Cc["@mozilla.org/accessibilityService;1"]
|
||||
.getService(Ci.nsIAccessibilityService);
|
||||
return Cc["@mozilla.org/accessibilityService;1"].getService(
|
||||
Ci.nsIAccessibilityService
|
||||
);
|
||||
} catch (e) {
|
||||
logger.warn("Accessibility module is not present");
|
||||
return undefined;
|
||||
|
@ -81,7 +86,6 @@ accessibility.ActionableRoles = new Set([
|
|||
"switch",
|
||||
]);
|
||||
|
||||
|
||||
/**
|
||||
* Factory function that constructs a new {@code accessibility.Checks}
|
||||
* object with enforced strictness or not.
|
||||
|
@ -131,8 +135,9 @@ accessibility.Checks = class {
|
|||
}
|
||||
|
||||
// First, check if accessibility is ready.
|
||||
let docAcc = accessibility.service
|
||||
.getAccessibleFor(element.ownerDocument);
|
||||
let docAcc = accessibility.service.getAccessibleFor(
|
||||
element.ownerDocument
|
||||
);
|
||||
let state = {};
|
||||
docAcc.getState(state, {});
|
||||
if ((state.value & Ci.nsIAccessibleStates.STATE_BUSY) == 0) {
|
||||
|
@ -174,8 +179,9 @@ accessibility.Checks = class {
|
|||
},
|
||||
};
|
||||
Services.obs.addObserver(eventObserver, "accessible-event");
|
||||
}).catch(() => this.error(
|
||||
"Element does not have an accessible object", element));
|
||||
}).catch(() =>
|
||||
this.error("Element does not have an accessible object", element)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -191,7 +197,8 @@ accessibility.Checks = class {
|
|||
*/
|
||||
isActionableRole(accessible) {
|
||||
return accessibility.ActionableRoles.has(
|
||||
accessibility.service.getStringRole(accessible.role));
|
||||
accessibility.service.getStringRole(accessible.role)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -302,11 +309,13 @@ accessibility.Checks = class {
|
|||
|
||||
let message;
|
||||
if (visible && hiddenAccessibility) {
|
||||
message = "Element is not currently visible via the accessibility API " +
|
||||
"and may not be manipulated by it";
|
||||
message =
|
||||
"Element is not currently visible via the accessibility API " +
|
||||
"and may not be manipulated by it";
|
||||
} else if (!visible && !hiddenAccessibility) {
|
||||
message = "Element is currently only visible via the accessibility API " +
|
||||
"and can be manipulated by it";
|
||||
message =
|
||||
"Element is currently only visible via the accessibility API " +
|
||||
"and can be manipulated by it";
|
||||
}
|
||||
this.error(message, element);
|
||||
}
|
||||
|
@ -332,14 +341,18 @@ accessibility.Checks = class {
|
|||
|
||||
let win = element.ownerGlobal;
|
||||
let disabledAccessibility = this.matchState(
|
||||
accessible, accessibility.State.Unavailable);
|
||||
let explorable = win.getComputedStyle(element)
|
||||
.getPropertyValue("pointer-events") !== "none";
|
||||
accessible,
|
||||
accessibility.State.Unavailable
|
||||
);
|
||||
let explorable =
|
||||
win.getComputedStyle(element).getPropertyValue("pointer-events") !==
|
||||
"none";
|
||||
|
||||
let message;
|
||||
if (!explorable && !disabledAccessibility) {
|
||||
message = "Element is enabled but is not explorable via the " +
|
||||
"accessibility API";
|
||||
message =
|
||||
"Element is enabled but is not explorable via the " +
|
||||
"accessibility API";
|
||||
} else if (enabled && disabledAccessibility) {
|
||||
message = "Element is enabled but disabled via the accessibility API";
|
||||
} else if (!enabled && !disabledAccessibility) {
|
||||
|
@ -369,8 +382,9 @@ accessibility.Checks = class {
|
|||
if (!this.hasActionCount(accessible)) {
|
||||
message = "Element does not support any accessible actions";
|
||||
} else if (!this.isActionableRole(accessible)) {
|
||||
message = "Element does not have a correct accessibility role " +
|
||||
"and may not be manipulated via the accessibility API";
|
||||
message =
|
||||
"Element does not have a correct accessibility role " +
|
||||
"and may not be manipulated via the accessibility API";
|
||||
} else if (!this.hasValidName(accessible)) {
|
||||
message = "Element is missing an accessible name";
|
||||
} else if (!this.matchState(accessible, accessibility.State.Focusable)) {
|
||||
|
@ -405,14 +419,18 @@ accessibility.Checks = class {
|
|||
return;
|
||||
}
|
||||
|
||||
let selectedAccessibility =
|
||||
this.matchState(accessible, accessibility.State.Selected);
|
||||
let selectedAccessibility = this.matchState(
|
||||
accessible,
|
||||
accessibility.State.Selected
|
||||
);
|
||||
|
||||
let message;
|
||||
if (selected && !selectedAccessibility) {
|
||||
message = "Element is selected but not selected via the accessibility API";
|
||||
message =
|
||||
"Element is selected but not selected via the accessibility API";
|
||||
} else if (!selected && selectedAccessibility) {
|
||||
message = "Element is not selected but selected via the accessibility API";
|
||||
message =
|
||||
"Element is not selected but selected via the accessibility API";
|
||||
}
|
||||
this.error(message, element);
|
||||
}
|
||||
|
@ -433,7 +451,7 @@ accessibility.Checks = class {
|
|||
return;
|
||||
}
|
||||
if (element) {
|
||||
let {id, tagName, className} = element;
|
||||
let { id, tagName, className } = element;
|
||||
message += `: id: ${id}, tagName: ${tagName}, className: ${className}`;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,18 +7,20 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const {assert} = ChromeUtils.import("chrome://marionette/content/assert.js");
|
||||
const {element} = ChromeUtils.import("chrome://marionette/content/element.js");
|
||||
const { assert } = ChromeUtils.import("chrome://marionette/content/assert.js");
|
||||
const { element } = ChromeUtils.import(
|
||||
"chrome://marionette/content/element.js"
|
||||
);
|
||||
const {
|
||||
InvalidArgumentError,
|
||||
MoveTargetOutOfBoundsError,
|
||||
UnsupportedOperationError,
|
||||
} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const {event} = ChromeUtils.import("chrome://marionette/content/event.js");
|
||||
const {pprint} = ChromeUtils.import("chrome://marionette/content/format.js");
|
||||
const {Sleep} = ChromeUtils.import("chrome://marionette/content/sync.js");
|
||||
const { event } = ChromeUtils.import("chrome://marionette/content/event.js");
|
||||
const { pprint } = ChromeUtils.import("chrome://marionette/content/format.js");
|
||||
const { Sleep } = ChromeUtils.import("chrome://marionette/content/sync.js");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["action"];
|
||||
|
||||
|
@ -54,10 +56,10 @@ const ACTIONS = {
|
|||
|
||||
/** Map from normalized key value to UI Events modifier key name */
|
||||
const MODIFIER_NAME_LOOKUP = {
|
||||
"Alt": "alt",
|
||||
"Shift": "shift",
|
||||
"Control": "ctrl",
|
||||
"Meta": "meta",
|
||||
Alt: "alt",
|
||||
Shift: "shift",
|
||||
Control: "ctrl",
|
||||
Meta: "meta",
|
||||
};
|
||||
|
||||
/** Map from raw key (codepoint) to normalized key value */
|
||||
|
@ -202,7 +204,7 @@ const KEY_CODE_LOOKUP = {
|
|||
"@": "Digit2",
|
||||
"#": "Digit3",
|
||||
"3": "Digit3",
|
||||
"$": "Digit4",
|
||||
$: "Digit4",
|
||||
"4": "Digit4",
|
||||
"%": "Digit5",
|
||||
"5": "Digit5",
|
||||
|
@ -236,60 +238,60 @@ const KEY_CODE_LOOKUP = {
|
|||
"\uE016": "Insert",
|
||||
"<": "IntlBackslash",
|
||||
">": "IntlBackslash",
|
||||
"A": "KeyA",
|
||||
"a": "KeyA",
|
||||
"B": "KeyB",
|
||||
"b": "KeyB",
|
||||
"C": "KeyC",
|
||||
"c": "KeyC",
|
||||
"D": "KeyD",
|
||||
"d": "KeyD",
|
||||
"E": "KeyE",
|
||||
"e": "KeyE",
|
||||
"F": "KeyF",
|
||||
"f": "KeyF",
|
||||
"G": "KeyG",
|
||||
"g": "KeyG",
|
||||
"H": "KeyH",
|
||||
"h": "KeyH",
|
||||
"I": "KeyI",
|
||||
"i": "KeyI",
|
||||
"J": "KeyJ",
|
||||
"j": "KeyJ",
|
||||
"K": "KeyK",
|
||||
"k": "KeyK",
|
||||
"L": "KeyL",
|
||||
"l": "KeyL",
|
||||
"M": "KeyM",
|
||||
"m": "KeyM",
|
||||
"N": "KeyN",
|
||||
"n": "KeyN",
|
||||
"O": "KeyO",
|
||||
"o": "KeyO",
|
||||
"P": "KeyP",
|
||||
"p": "KeyP",
|
||||
"Q": "KeyQ",
|
||||
"q": "KeyQ",
|
||||
"R": "KeyR",
|
||||
"r": "KeyR",
|
||||
"S": "KeyS",
|
||||
"s": "KeyS",
|
||||
"T": "KeyT",
|
||||
"t": "KeyT",
|
||||
"U": "KeyU",
|
||||
"u": "KeyU",
|
||||
"V": "KeyV",
|
||||
"v": "KeyV",
|
||||
"W": "KeyW",
|
||||
"w": "KeyW",
|
||||
"X": "KeyX",
|
||||
"x": "KeyX",
|
||||
"Y": "KeyY",
|
||||
"y": "KeyY",
|
||||
"Z": "KeyZ",
|
||||
"z": "KeyZ",
|
||||
A: "KeyA",
|
||||
a: "KeyA",
|
||||
B: "KeyB",
|
||||
b: "KeyB",
|
||||
C: "KeyC",
|
||||
c: "KeyC",
|
||||
D: "KeyD",
|
||||
d: "KeyD",
|
||||
E: "KeyE",
|
||||
e: "KeyE",
|
||||
F: "KeyF",
|
||||
f: "KeyF",
|
||||
G: "KeyG",
|
||||
g: "KeyG",
|
||||
H: "KeyH",
|
||||
h: "KeyH",
|
||||
I: "KeyI",
|
||||
i: "KeyI",
|
||||
J: "KeyJ",
|
||||
j: "KeyJ",
|
||||
K: "KeyK",
|
||||
k: "KeyK",
|
||||
L: "KeyL",
|
||||
l: "KeyL",
|
||||
M: "KeyM",
|
||||
m: "KeyM",
|
||||
N: "KeyN",
|
||||
n: "KeyN",
|
||||
O: "KeyO",
|
||||
o: "KeyO",
|
||||
P: "KeyP",
|
||||
p: "KeyP",
|
||||
Q: "KeyQ",
|
||||
q: "KeyQ",
|
||||
R: "KeyR",
|
||||
r: "KeyR",
|
||||
S: "KeyS",
|
||||
s: "KeyS",
|
||||
T: "KeyT",
|
||||
t: "KeyT",
|
||||
U: "KeyU",
|
||||
u: "KeyU",
|
||||
V: "KeyV",
|
||||
v: "KeyV",
|
||||
W: "KeyW",
|
||||
w: "KeyW",
|
||||
X: "KeyX",
|
||||
x: "KeyX",
|
||||
Y: "KeyY",
|
||||
y: "KeyY",
|
||||
Z: "KeyZ",
|
||||
z: "KeyZ",
|
||||
"-": "Minus",
|
||||
"_": "Minus",
|
||||
_: "Minus",
|
||||
"\uE01A": "Numpad0",
|
||||
"\uE05C": "Numpad0",
|
||||
"\uE01B": "Numpad1",
|
||||
|
@ -323,7 +325,7 @@ const KEY_CODE_LOOKUP = {
|
|||
"\uE01F": "PageUp",
|
||||
".": "Period",
|
||||
">": "Period",
|
||||
"\"": "Quote",
|
||||
'"': "Quote",
|
||||
"'": "Quote",
|
||||
":": "Semicolon",
|
||||
";": "Semicolon",
|
||||
|
@ -367,9 +369,11 @@ action.PointerOrigin.get = function(obj) {
|
|||
assert.in(name, this, pprint`Unknown pointer-move origin: ${obj}`);
|
||||
origin = this[name];
|
||||
} else if (!element.isDOMElement(obj)) {
|
||||
throw new InvalidArgumentError("Expected 'origin' to be undefined, " +
|
||||
throw new InvalidArgumentError(
|
||||
"Expected 'origin' to be undefined, " +
|
||||
'"viewport", "pointer", ' +
|
||||
pprint`or an element, got: ${obj}`);
|
||||
pprint`or an element, got: ${obj}`
|
||||
);
|
||||
}
|
||||
return origin;
|
||||
};
|
||||
|
@ -465,10 +469,13 @@ class InputState {
|
|||
assert.in(type, ACTIONS, pprint`Unknown action type: ${type}`);
|
||||
let name = type == "none" ? "Null" : capitalize(type);
|
||||
if (name == "Pointer") {
|
||||
if (!obj.pointerType &&
|
||||
(!obj.parameters || !obj.parameters.pointerType)) {
|
||||
if (
|
||||
!obj.pointerType &&
|
||||
(!obj.parameters || !obj.parameters.pointerType)
|
||||
) {
|
||||
throw new InvalidArgumentError(
|
||||
pprint`Expected obj to have pointerType, got ${obj}`);
|
||||
pprint`Expected obj to have pointerType, got ${obj}`
|
||||
);
|
||||
}
|
||||
let pointerType = obj.pointerType || obj.parameters.pointerType;
|
||||
return new action.InputState[name](pointerType);
|
||||
|
@ -509,9 +516,10 @@ action.InputState.Key = class Key extends InputState {
|
|||
this[MODIFIER_NAME_LOOKUP[key]] = value;
|
||||
} else {
|
||||
throw new InvalidArgumentError(
|
||||
"Expected 'key' to be one of " +
|
||||
"Expected 'key' to be one of " +
|
||||
Object.keys(MODIFIER_NAME_LOOKUP) +
|
||||
pprint`, got ${key}`);
|
||||
pprint`, got ${key}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -578,8 +586,10 @@ action.InputState.Pointer = class Pointer extends InputState {
|
|||
constructor(subtype) {
|
||||
super();
|
||||
this.pressed = new Set();
|
||||
assert.defined(subtype,
|
||||
pprint`Expected subtype to be defined, got ${subtype}`);
|
||||
assert.defined(
|
||||
subtype,
|
||||
pprint`Expected subtype to be defined, got ${subtype}`
|
||||
);
|
||||
this.subtype = action.PointerType.get(subtype);
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
|
@ -613,7 +623,7 @@ action.InputState.Pointer = class Pointer extends InputState {
|
|||
return this.pressed.add(button);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Remove |button| from the set of pressed buttons.
|
||||
*
|
||||
* @param {number} button
|
||||
|
@ -687,13 +697,17 @@ action.Action = class {
|
|||
let subtype = actionItem.type;
|
||||
if (!subtypes.has(subtype)) {
|
||||
throw new InvalidArgumentError(
|
||||
`Unknown subtype for ${type} action: ${subtype}`);
|
||||
`Unknown subtype for ${type} action: ${subtype}`
|
||||
);
|
||||
}
|
||||
|
||||
let item = new action.Action(id, type, subtype);
|
||||
if (type === "pointer") {
|
||||
action.processPointerAction(id,
|
||||
action.PointerParameters.fromJSON(actionSequence.parameters), item);
|
||||
action.processPointerAction(
|
||||
id,
|
||||
action.PointerParameters.fromJSON(actionSequence.parameters),
|
||||
item
|
||||
);
|
||||
}
|
||||
|
||||
switch (item.subtype) {
|
||||
|
@ -703,35 +717,45 @@ action.Action = class {
|
|||
// TODO countGraphemes
|
||||
// TODO key.value could be a single code point like "\uE012"
|
||||
// (see rawKey) or "grapheme cluster"
|
||||
assert.string(key,
|
||||
"Expected 'value' to be a string that represents single code point " +
|
||||
pprint`or grapheme cluster, got ${key}`);
|
||||
assert.string(
|
||||
key,
|
||||
"Expected 'value' to be a string that represents single code point " +
|
||||
pprint`or grapheme cluster, got ${key}`
|
||||
);
|
||||
item.value = key;
|
||||
break;
|
||||
|
||||
case action.PointerDown:
|
||||
case action.PointerUp:
|
||||
assert.positiveInteger(actionItem.button,
|
||||
pprint`Expected 'button' (${actionItem.button}) to be >= 0`);
|
||||
assert.positiveInteger(
|
||||
actionItem.button,
|
||||
pprint`Expected 'button' (${actionItem.button}) to be >= 0`
|
||||
);
|
||||
item.button = actionItem.button;
|
||||
break;
|
||||
|
||||
case action.PointerMove:
|
||||
item.duration = actionItem.duration;
|
||||
if (typeof item.duration != "undefined") {
|
||||
assert.positiveInteger(item.duration,
|
||||
pprint`Expected 'duration' (${item.duration}) to be >= 0`);
|
||||
assert.positiveInteger(
|
||||
item.duration,
|
||||
pprint`Expected 'duration' (${item.duration}) to be >= 0`
|
||||
);
|
||||
}
|
||||
item.origin = action.PointerOrigin.get(actionItem.origin);
|
||||
item.x = actionItem.x;
|
||||
if (typeof item.x != "undefined") {
|
||||
assert.integer(item.x,
|
||||
pprint`Expected 'x' (${item.x}) to be an Integer`);
|
||||
assert.integer(
|
||||
item.x,
|
||||
pprint`Expected 'x' (${item.x}) to be an Integer`
|
||||
);
|
||||
}
|
||||
item.y = actionItem.y;
|
||||
if (typeof item.y != "undefined") {
|
||||
assert.integer(item.y,
|
||||
pprint`Expected 'y' (${item.y}) to be an Integer`);
|
||||
assert.integer(
|
||||
item.y,
|
||||
pprint`Expected 'y' (${item.y}) to be an Integer`
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -743,7 +767,8 @@ action.Action = class {
|
|||
if (typeof item.duration != "undefined") {
|
||||
// eslint-disable-next-line
|
||||
assert.positiveInteger(item.duration,
|
||||
pprint`Expected 'duration' (${item.duration}) to be >= 0`);
|
||||
pprint`Expected 'duration' (${item.duration}) to be >= 0`
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -773,8 +798,10 @@ action.Chain = class extends Array {
|
|||
* If <var>actions</var> is not an Array.
|
||||
*/
|
||||
static fromJSON(actions) {
|
||||
assert.array(actions,
|
||||
pprint`Expected 'actions' to be an array, got ${actions}`);
|
||||
assert.array(
|
||||
actions,
|
||||
pprint`Expected 'actions' to be an array, got ${actions}`
|
||||
);
|
||||
|
||||
let actionsByTick = new action.Chain();
|
||||
for (let actionSequence of actions) {
|
||||
|
@ -783,7 +810,7 @@ action.Chain = class extends Array {
|
|||
let inputSourceActions = action.Sequence.fromJSON(actionSequence);
|
||||
for (let i = 0; i < inputSourceActions.length; i++) {
|
||||
// new tick
|
||||
if (actionsByTick.length < (i + 1)) {
|
||||
if (actionsByTick.length < i + 1) {
|
||||
actionsByTick.push([]);
|
||||
}
|
||||
actionsByTick[i].push(inputSourceActions[i]);
|
||||
|
@ -823,16 +850,18 @@ action.Sequence = class extends Array {
|
|||
assert.string(id, pprint`Expected 'id' to be a string, got ${id}`);
|
||||
let actionItems = actionSequence.actions;
|
||||
assert.array(
|
||||
actionItems,
|
||||
"Expected 'actionSequence.actions' to be an array, " +
|
||||
pprint`got ${actionSequence.actions}`);
|
||||
actionItems,
|
||||
"Expected 'actionSequence.actions' to be an array, " +
|
||||
pprint`got ${actionSequence.actions}`
|
||||
);
|
||||
|
||||
if (!action.inputStateMap.has(id)) {
|
||||
action.inputStateMap.set(id, inputSourceState);
|
||||
} else if (!action.inputStateMap.get(id).is(inputSourceState)) {
|
||||
throw new InvalidArgumentError(
|
||||
`Expected ${id} to be mapped to ${inputSourceState}, ` +
|
||||
`got ${action.inputStateMap.get(id)}`);
|
||||
`Expected ${id} to be mapped to ${inputSourceState}, ` +
|
||||
`got ${action.inputStateMap.get(id)}`
|
||||
);
|
||||
}
|
||||
|
||||
let actions = new action.Sequence();
|
||||
|
@ -893,20 +922,26 @@ action.PointerParameters = class {
|
|||
* <code>act.type</code> or <code>pointerParams.pointerType</code>.
|
||||
*/
|
||||
action.processPointerAction = function(id, pointerParams, act) {
|
||||
if (action.inputStateMap.has(id) &&
|
||||
action.inputStateMap.get(id).type !== act.type) {
|
||||
if (
|
||||
action.inputStateMap.has(id) &&
|
||||
action.inputStateMap.get(id).type !== act.type
|
||||
) {
|
||||
throw new InvalidArgumentError(
|
||||
`Expected 'id' ${id} to be mapped to InputState whose type is ` +
|
||||
`Expected 'id' ${id} to be mapped to InputState whose type is ` +
|
||||
action.inputStateMap.get(id).type +
|
||||
pprint` , got ${act.type}`);
|
||||
pprint` , got ${act.type}`
|
||||
);
|
||||
}
|
||||
let pointerType = pointerParams.pointerType;
|
||||
if (action.inputStateMap.has(id) &&
|
||||
action.inputStateMap.get(id).subtype !== pointerType) {
|
||||
if (
|
||||
action.inputStateMap.has(id) &&
|
||||
action.inputStateMap.get(id).subtype !== pointerType
|
||||
) {
|
||||
throw new InvalidArgumentError(
|
||||
`Expected 'id' ${id} to be mapped to InputState whose subtype is ` +
|
||||
`Expected 'id' ${id} to be mapped to InputState whose subtype is ` +
|
||||
action.inputStateMap.get(id).subtype +
|
||||
pprint` , got ${pointerType}`);
|
||||
pprint` , got ${pointerType}`
|
||||
);
|
||||
}
|
||||
act.pointerType = pointerParams.pointerType;
|
||||
};
|
||||
|
@ -915,7 +950,7 @@ action.processPointerAction = function(id, pointerParams, act) {
|
|||
action.Key = class {
|
||||
constructor(rawKey) {
|
||||
this.key = NORMALIZED_KEY_LOOKUP[rawKey] || rawKey;
|
||||
this.code = KEY_CODE_LOOKUP[rawKey];
|
||||
this.code = KEY_CODE_LOOKUP[rawKey];
|
||||
this.location = KEY_LOCATION_LOOKUP[rawKey] || 0;
|
||||
this.altKey = false;
|
||||
this.shiftKey = false;
|
||||
|
@ -991,9 +1026,10 @@ action.dispatch = function(chain, win, specCompatPointerOrigin = true) {
|
|||
let chainEvents = (async () => {
|
||||
for (let tickActions of chain) {
|
||||
await action.dispatchTickActions(
|
||||
tickActions,
|
||||
action.computeTickDuration(tickActions),
|
||||
win);
|
||||
tickActions,
|
||||
action.computeTickDuration(tickActions),
|
||||
win
|
||||
);
|
||||
}
|
||||
})();
|
||||
return chainEvents;
|
||||
|
@ -1037,8 +1073,9 @@ action.dispatchTickActions = function(tickActions, tickDuration, win) {
|
|||
action.computeTickDuration = function(tickActions) {
|
||||
let max = 0;
|
||||
for (let a of tickActions) {
|
||||
let affectsWallClockTime = a.subtype == action.Pause ||
|
||||
(a.type == "pointer" && a.subtype == action.PointerMove);
|
||||
let affectsWallClockTime =
|
||||
a.subtype == action.Pause ||
|
||||
(a.type == "pointer" && a.subtype == action.PointerMove);
|
||||
if (affectsWallClockTime && a.duration) {
|
||||
max = Math.max(a.duration, max);
|
||||
}
|
||||
|
@ -1060,9 +1097,8 @@ action.computeTickDuration = function(tickActions) {
|
|||
* @return {Map.<string, number>}
|
||||
* x and y coordinates of pointer destination.
|
||||
*/
|
||||
action.computePointerDestination = function(
|
||||
a, inputState, center = undefined) {
|
||||
let {x, y} = a;
|
||||
action.computePointerDestination = function(a, inputState, center = undefined) {
|
||||
let { x, y } = a;
|
||||
switch (a.origin) {
|
||||
case action.PointerOrigin.Viewport:
|
||||
break;
|
||||
|
@ -1078,7 +1114,7 @@ action.computePointerDestination = function(
|
|||
x += center.x;
|
||||
y += center.y;
|
||||
}
|
||||
return {"x": x, "y": y};
|
||||
return { x, y };
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1111,8 +1147,7 @@ function toEvents(tickDuration, win) {
|
|||
return dispatchPointerUp(a, inputState, win);
|
||||
|
||||
case action.PointerMove:
|
||||
return dispatchPointerMove(
|
||||
a, inputState, tickDuration, win);
|
||||
return dispatchPointerMove(a, inputState, tickDuration, win);
|
||||
|
||||
case action.PointerCancel:
|
||||
throw new UnsupportedOperationError();
|
||||
|
@ -1149,7 +1184,7 @@ function dispatchKeyDown(a, inputState, win) {
|
|||
}
|
||||
|
||||
// Append a copy of |a| with keyUp subtype
|
||||
action.inputsToCancel.push(Object.assign({}, a, {subtype: action.KeyUp}));
|
||||
action.inputsToCancel.push(Object.assign({}, a, { subtype: action.KeyUp }));
|
||||
keyEvent.update(inputState);
|
||||
event.sendKeyDown(a.value, keyEvent, win);
|
||||
|
||||
|
@ -1213,7 +1248,7 @@ function dispatchPointerDown(a, inputState, win) {
|
|||
|
||||
inputState.press(a.button);
|
||||
// Append a copy of |a| with pointerUp subtype
|
||||
let copy = Object.assign({}, a, {subtype: action.PointerUp});
|
||||
let copy = Object.assign({}, a, { subtype: action.PointerUp });
|
||||
action.inputsToCancel.push(copy);
|
||||
|
||||
switch (inputState.subtype) {
|
||||
|
@ -1226,29 +1261,35 @@ function dispatchPointerDown(a, inputState, win) {
|
|||
event.DoubleClickTracker.resetClick();
|
||||
}
|
||||
} else if (event.DoubleClickTracker.isClicked()) {
|
||||
mouseEvent = Object.assign({},
|
||||
mouseEvent, {clickCount: 2});
|
||||
mouseEvent = Object.assign({}, mouseEvent, { clickCount: 2 });
|
||||
}
|
||||
event.synthesizeMouseAtPoint(
|
||||
inputState.x,
|
||||
inputState.y,
|
||||
mouseEvent,
|
||||
win
|
||||
);
|
||||
if (
|
||||
event.MouseButton.isSecondary(a.button) ||
|
||||
(mouseEvent.ctrlKey && Services.appinfo.OS !== "WINNT")
|
||||
) {
|
||||
let contextMenuEvent = Object.assign({}, mouseEvent, {
|
||||
type: "contextmenu",
|
||||
});
|
||||
event.synthesizeMouseAtPoint(
|
||||
inputState.x,
|
||||
inputState.y,
|
||||
mouseEvent,
|
||||
win);
|
||||
if (event.MouseButton.isSecondary(a.button) ||
|
||||
mouseEvent.ctrlKey && Services.appinfo.OS !== "WINNT") {
|
||||
let contextMenuEvent = Object.assign({},
|
||||
mouseEvent, {type: "contextmenu"});
|
||||
event.synthesizeMouseAtPoint(
|
||||
inputState.x,
|
||||
inputState.y,
|
||||
contextMenuEvent,
|
||||
win);
|
||||
contextMenuEvent,
|
||||
win
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case action.PointerType.Pen:
|
||||
case action.PointerType.Touch:
|
||||
throw new UnsupportedOperationError("Only 'mouse' pointer type is supported");
|
||||
throw new UnsupportedOperationError(
|
||||
"Only 'mouse' pointer type is supported"
|
||||
);
|
||||
|
||||
default:
|
||||
throw new TypeError(`Unknown pointer type: ${inputState.subtype}`);
|
||||
|
@ -1286,16 +1327,21 @@ function dispatchPointerUp(a, inputState, win) {
|
|||
let mouseEvent = new action.Mouse("mouseup", a.button);
|
||||
mouseEvent.update(inputState);
|
||||
if (event.DoubleClickTracker.isClicked()) {
|
||||
mouseEvent = Object.assign({},
|
||||
mouseEvent, {clickCount: 2});
|
||||
mouseEvent = Object.assign({}, mouseEvent, { clickCount: 2 });
|
||||
}
|
||||
event.synthesizeMouseAtPoint(
|
||||
inputState.x, inputState.y, mouseEvent, win);
|
||||
inputState.x,
|
||||
inputState.y,
|
||||
mouseEvent,
|
||||
win
|
||||
);
|
||||
break;
|
||||
|
||||
case action.PointerType.Pen:
|
||||
case action.PointerType.Touch:
|
||||
throw new UnsupportedOperationError("Only 'mouse' pointer type is supported");
|
||||
throw new UnsupportedOperationError(
|
||||
"Only 'mouse' pointer type is supported"
|
||||
);
|
||||
|
||||
default:
|
||||
throw new TypeError(`Unknown pointer type: ${inputState.subtype}`);
|
||||
|
@ -1340,12 +1386,14 @@ function dispatchPointerMove(a, inputState, tickDuration, win) {
|
|||
|
||||
if (!inViewPort(targetX, targetY, win)) {
|
||||
throw new MoveTargetOutOfBoundsError(
|
||||
`(${targetX}, ${targetY}) is out of bounds of viewport ` +
|
||||
`(${targetX}, ${targetY}) is out of bounds of viewport ` +
|
||||
`width (${win.innerWidth}) ` +
|
||||
`and height (${win.innerHeight})`);
|
||||
`and height (${win.innerHeight})`
|
||||
);
|
||||
}
|
||||
|
||||
const duration = typeof a.duration == "undefined" ? tickDuration : a.duration;
|
||||
const duration =
|
||||
typeof a.duration == "undefined" ? tickDuration : a.duration;
|
||||
if (duration === 0) {
|
||||
// move pointer to destination in one step
|
||||
performOnePointerMove(inputState, targetX, targetY, win);
|
||||
|
@ -1359,17 +1407,19 @@ function dispatchPointerMove(a, inputState, tickDuration, win) {
|
|||
let intermediatePointerEvents = (async () => {
|
||||
// wait |fps60| ms before performing first incremental pointer move
|
||||
await new Promise(resolveTimer =>
|
||||
timer.initWithCallback(resolveTimer, fps60, ONE_SHOT));
|
||||
timer.initWithCallback(resolveTimer, fps60, ONE_SHOT)
|
||||
);
|
||||
|
||||
let durationRatio = Math.floor(Date.now() - start) / duration;
|
||||
const epsilon = fps60 / duration / 10;
|
||||
while ((1 - durationRatio) > epsilon) {
|
||||
while (1 - durationRatio > epsilon) {
|
||||
let x = Math.floor(durationRatio * distanceX + startX);
|
||||
let y = Math.floor(durationRatio * distanceY + startY);
|
||||
performOnePointerMove(inputState, x, y, win);
|
||||
// wait |fps60| ms before performing next pointer move
|
||||
await new Promise(resolveTimer =>
|
||||
timer.initWithCallback(resolveTimer, fps60, ONE_SHOT));
|
||||
timer.initWithCallback(resolveTimer, fps60, ONE_SHOT)
|
||||
);
|
||||
|
||||
durationRatio = Math.floor(Date.now() - start) / duration;
|
||||
}
|
||||
|
@ -1377,12 +1427,14 @@ function dispatchPointerMove(a, inputState, tickDuration, win) {
|
|||
|
||||
// perform last pointer move after all incremental moves are resolved and
|
||||
// durationRatio is close enough to 1
|
||||
intermediatePointerEvents.then(() => {
|
||||
performOnePointerMove(inputState, targetX, targetY, win);
|
||||
resolve();
|
||||
}).catch(err => {
|
||||
reject(err);
|
||||
});
|
||||
intermediatePointerEvents
|
||||
.then(() => {
|
||||
performOnePointerMove(inputState, targetX, targetY, win);
|
||||
resolve();
|
||||
})
|
||||
.catch(err => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1401,7 +1453,9 @@ function performOnePointerMove(inputState, targetX, targetY, win) {
|
|||
|
||||
case action.PointerType.Pen:
|
||||
case action.PointerType.Touch:
|
||||
throw new UnsupportedOperationError("Only 'mouse' pointer type is supported");
|
||||
throw new UnsupportedOperationError(
|
||||
"Only 'mouse' pointer type is supported"
|
||||
);
|
||||
|
||||
default:
|
||||
throw new TypeError(`Unknown pointer type: ${inputState.subtype}`);
|
||||
|
|
|
@ -4,10 +4,16 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {AddonManager} = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
|
||||
const {FileUtils} = ChromeUtils.import("resource://gre/modules/FileUtils.jsm");
|
||||
const { AddonManager } = ChromeUtils.import(
|
||||
"resource://gre/modules/AddonManager.jsm"
|
||||
);
|
||||
const { FileUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/FileUtils.jsm"
|
||||
);
|
||||
|
||||
const {UnknownError} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const { UnknownError } = ChromeUtils.import(
|
||||
"chrome://marionette/content/error.js"
|
||||
);
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["Addon"];
|
||||
|
||||
|
@ -21,7 +27,9 @@ const ERRORS = {
|
|||
};
|
||||
|
||||
async function installAddon(file) {
|
||||
let install = await AddonManager.getInstallForFile(file, null, {source: "internal"});
|
||||
let install = await AddonManager.getInstallForFile(file, null, {
|
||||
source: "internal",
|
||||
});
|
||||
|
||||
if (install.error) {
|
||||
throw new UnknownError(ERRORS[install.error]);
|
||||
|
@ -76,7 +84,9 @@ class Addon {
|
|||
}
|
||||
} catch (e) {
|
||||
throw new UnknownError(
|
||||
`Could not install add-on: ${path}: ${e.message}`, e);
|
||||
`Could not install add-on: ${path}: ${e.message}`,
|
||||
e
|
||||
);
|
||||
}
|
||||
|
||||
return addon.id;
|
||||
|
@ -104,7 +114,9 @@ class Addon {
|
|||
onOperationCancelled: addon => {
|
||||
if (addon.id === candidate.id) {
|
||||
AddonManager.removeAddonListener(listener);
|
||||
throw new UnknownError(`Uninstall of ${candidate.id} has been canceled`);
|
||||
throw new UnknownError(
|
||||
`Uninstall of ${candidate.id} has been canceled`
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -4,9 +4,13 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { AppConstants } = ChromeUtils.import(
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const {
|
||||
InvalidArgumentError,
|
||||
|
@ -16,7 +20,7 @@ const {
|
|||
UnexpectedAlertOpenError,
|
||||
UnsupportedOperationError,
|
||||
} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const {pprint} = ChromeUtils.import("chrome://marionette/content/format.js");
|
||||
const { pprint } = ChromeUtils.import("chrome://marionette/content/format.js");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
evaluate: "chrome://marionette/content/evaluate.js",
|
||||
|
@ -27,9 +31,9 @@ this.EXPORTED_SYMBOLS = ["assert"];
|
|||
|
||||
const isFennec = () => AppConstants.platform == "android";
|
||||
const isFirefox = () =>
|
||||
Services.appinfo.ID == "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}";
|
||||
Services.appinfo.ID == "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}";
|
||||
const isThunderbird = () =>
|
||||
Services.appinfo.ID == "{3550f703-e582-4d05-9a08-453d09bdfdc6}";
|
||||
Services.appinfo.ID == "{3550f703-e582-4d05-9a08-453d09bdfdc6}";
|
||||
|
||||
/**
|
||||
* Shorthands for common assertions made in Marionette.
|
||||
|
@ -73,8 +77,9 @@ assert.acyclic = function(obj, msg = "", error = JavaScriptError) {
|
|||
* If <var>driver</var> does not have a session ID.
|
||||
*/
|
||||
assert.session = function(driver, msg = "") {
|
||||
assert.that(sessionID => sessionID,
|
||||
msg, InvalidSessionIDError)(driver.sessionID);
|
||||
assert.that(sessionID => sessionID, msg, InvalidSessionIDError)(
|
||||
driver.sessionID
|
||||
);
|
||||
return driver.sessionID;
|
||||
};
|
||||
|
||||
|
@ -103,8 +108,11 @@ assert.firefox = function(msg = "") {
|
|||
*/
|
||||
assert.desktop = function(msg = "") {
|
||||
msg = msg || "Only supported in desktop applications";
|
||||
assert.that(obj => isFirefox(obj) || isThunderbird(obj),
|
||||
msg, UnsupportedOperationError)();
|
||||
assert.that(
|
||||
obj => isFirefox(obj) || isThunderbird(obj),
|
||||
msg,
|
||||
UnsupportedOperationError
|
||||
)();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -137,7 +145,9 @@ assert.fennec = function(msg = "") {
|
|||
*/
|
||||
assert.content = function(context, msg = "") {
|
||||
msg = msg || "Only supported in content context";
|
||||
assert.that(c => c.toString() == "content", msg, UnsupportedOperationError)(context);
|
||||
assert.that(c => c.toString() == "content", msg, UnsupportedOperationError)(
|
||||
context
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -170,9 +180,9 @@ assert.open = function(context, msg = "") {
|
|||
}
|
||||
|
||||
msg = msg || "Browsing context has been discarded";
|
||||
return assert.that(ctx => ctx && !ctx.closed,
|
||||
msg,
|
||||
NoSuchWindowError)(context);
|
||||
return assert.that(ctx => ctx && !ctx.closed, msg, NoSuchWindowError)(
|
||||
context
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -187,9 +197,11 @@ assert.open = function(context, msg = "") {
|
|||
* If there is a user prompt.
|
||||
*/
|
||||
assert.noUserPrompt = function(dialog, msg = "") {
|
||||
assert.that(d => d === null || typeof d == "undefined",
|
||||
msg,
|
||||
UnexpectedAlertOpenError)(dialog);
|
||||
assert.that(
|
||||
d => d === null || typeof d == "undefined",
|
||||
msg,
|
||||
UnexpectedAlertOpenError
|
||||
)(dialog);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -410,8 +422,7 @@ assert.array = function(obj, msg = "") {
|
|||
* and which may throw <var>error</var> with <var>message</var>
|
||||
* if <var>predicate</var> evaluates to false.
|
||||
*/
|
||||
assert.that = function(
|
||||
predicate, message = "", error = InvalidArgumentError) {
|
||||
assert.that = function(predicate, message = "", error = InvalidArgumentError) {
|
||||
return obj => {
|
||||
if (!predicate(obj)) {
|
||||
throw new error(message);
|
||||
|
|
|
@ -5,16 +5,21 @@
|
|||
"use strict";
|
||||
/* global frame */
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const {WebElementEventTarget} = ChromeUtils.import("chrome://marionette/content/dom.js");
|
||||
const {element} = ChromeUtils.import("chrome://marionette/content/element.js");
|
||||
const {
|
||||
NoSuchWindowError,
|
||||
UnsupportedOperationError,
|
||||
} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const {Log} = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
const { WebElementEventTarget } = ChromeUtils.import(
|
||||
"chrome://marionette/content/dom.js"
|
||||
);
|
||||
const { element } = ChromeUtils.import(
|
||||
"chrome://marionette/content/element.js"
|
||||
);
|
||||
const { NoSuchWindowError, UnsupportedOperationError } = ChromeUtils.import(
|
||||
"chrome://marionette/content/error.js"
|
||||
);
|
||||
const { Log } = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
const {
|
||||
MessageManagerDestroyedPromise,
|
||||
waitForEvent,
|
||||
|
@ -81,7 +86,7 @@ browser.getBrowserForTab = function(tab) {
|
|||
if (tab && "browser" in tab) {
|
||||
return tab.browser;
|
||||
|
||||
// Firefox
|
||||
// Firefox
|
||||
} else if (tab && "linkedBrowser" in tab) {
|
||||
return tab.linkedBrowser;
|
||||
}
|
||||
|
@ -103,11 +108,11 @@ browser.getTabBrowser = function(window) {
|
|||
if ("BrowserApp" in window) {
|
||||
return window.BrowserApp;
|
||||
|
||||
// Firefox
|
||||
// Firefox
|
||||
} else if ("gBrowser" in window) {
|
||||
return window.gBrowser;
|
||||
|
||||
// Thunderbird
|
||||
// Thunderbird
|
||||
} else if (window.document.getElementById("tabmail")) {
|
||||
return window.document.getElementById("tabmail");
|
||||
}
|
||||
|
@ -173,8 +178,10 @@ browser.Context = class {
|
|||
get contentBrowser() {
|
||||
if (this.tab) {
|
||||
return browser.getBrowserForTab(this.tab);
|
||||
} else if (this.tabBrowser &&
|
||||
this.driver.isReftestBrowser(this.tabBrowser)) {
|
||||
} else if (
|
||||
this.tabBrowser &&
|
||||
this.driver.isReftestBrowser(this.tabBrowser)
|
||||
) {
|
||||
return this.tabBrowser;
|
||||
}
|
||||
|
||||
|
@ -232,7 +239,8 @@ browser.Context = class {
|
|||
return this.contentBrowser.contentTitle;
|
||||
}
|
||||
throw new NoSuchWindowError(
|
||||
"Current window does not have a content browser");
|
||||
"Current window does not have a content browser"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -251,7 +259,8 @@ browser.Context = class {
|
|||
return this.contentBrowser.currentURI;
|
||||
}
|
||||
throw new NoSuchWindowError(
|
||||
"Current window does not have a content browser");
|
||||
"Current window does not have a content browser"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -282,7 +291,9 @@ browser.Context = class {
|
|||
// The modal is a direct sibling of the browser element.
|
||||
// See tabbrowser.xml's getTabModalPromptBox.
|
||||
let modalElements = br.parentNode.getElementsByTagNameNS(
|
||||
XUL_NS, "tabmodalprompt");
|
||||
XUL_NS,
|
||||
"tabmodalprompt"
|
||||
);
|
||||
|
||||
return br.tabModalPromptBox.prompts.get(modalElements[0]);
|
||||
}
|
||||
|
@ -295,7 +306,8 @@ browser.Context = class {
|
|||
*/
|
||||
closeWindow() {
|
||||
let destroyed = new MessageManagerDestroyedPromise(
|
||||
this.window.messageManager);
|
||||
this.window.messageManager
|
||||
);
|
||||
let unloaded = waitForEvent(this.window, "unload");
|
||||
|
||||
this.window.close();
|
||||
|
@ -312,7 +324,7 @@ browser.Context = class {
|
|||
async focusWindow() {
|
||||
if (Services.focus.activeWindow != this.window) {
|
||||
let activated = waitForEvent(this.window, "activate");
|
||||
let focused = waitForEvent(this.window, "focus", {capture: true});
|
||||
let focused = waitForEvent(this.window, "focus", { capture: true });
|
||||
|
||||
this.window.focus();
|
||||
|
||||
|
@ -335,9 +347,11 @@ browser.Context = class {
|
|||
let win = this.window.OpenBrowserWindow();
|
||||
|
||||
let activated = waitForEvent(win, "activate");
|
||||
let focused = waitForEvent(win, "focus", {capture: true});
|
||||
let startup = waitForObserverTopic("browser-delayed-startup-finished",
|
||||
subject => subject == win);
|
||||
let focused = waitForEvent(win, "focus", { capture: true });
|
||||
let startup = waitForObserverTopic(
|
||||
"browser-delayed-startup-finished",
|
||||
subject => subject == win
|
||||
);
|
||||
|
||||
win.focus();
|
||||
await Promise.all([activated, focused, startup]);
|
||||
|
@ -352,7 +366,8 @@ browser.Context = class {
|
|||
|
||||
default:
|
||||
throw new UnsupportedOperationError(
|
||||
`openWindow() not supported in ${this.driver.appName}`);
|
||||
`openWindow() not supported in ${this.driver.appName}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -368,10 +383,12 @@ browser.Context = class {
|
|||
closeTab() {
|
||||
// If the current window is not a browser then close it directly. Do the
|
||||
// same if only one remaining tab is open, or no tab selected at all.
|
||||
if (!this.tabBrowser ||
|
||||
!this.tabBrowser.tabs ||
|
||||
this.tabBrowser.tabs.length === 1 ||
|
||||
!this.tab) {
|
||||
if (
|
||||
!this.tabBrowser ||
|
||||
!this.tabBrowser.tabs ||
|
||||
this.tabBrowser.tabs.length === 1 ||
|
||||
!this.tab
|
||||
) {
|
||||
return this.closeWindow();
|
||||
}
|
||||
|
||||
|
@ -392,7 +409,8 @@ browser.Context = class {
|
|||
|
||||
default:
|
||||
throw new UnsupportedOperationError(
|
||||
`closeTab() not supported in ${this.driver.appName}`);
|
||||
`closeTab() not supported in ${this.driver.appName}`
|
||||
);
|
||||
}
|
||||
|
||||
return Promise.all([destroyed, tabClosed]);
|
||||
|
@ -425,7 +443,8 @@ browser.Context = class {
|
|||
|
||||
default:
|
||||
throw new UnsupportedOperationError(
|
||||
`openTab() not supported in ${this.driver.appName}`);
|
||||
`openTab() not supported in ${this.driver.appName}`
|
||||
);
|
||||
}
|
||||
|
||||
await tabOpened;
|
||||
|
@ -482,7 +501,8 @@ browser.Context = class {
|
|||
|
||||
default:
|
||||
throw new UnsupportedOperationError(
|
||||
`switchToTab() not supported in ${this.driver.appName}`);
|
||||
`switchToTab() not supported in ${this.driver.appName}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -534,15 +554,15 @@ browser.Context = class {
|
|||
}
|
||||
|
||||
/**
|
||||
* This function intercepts commands interacting with content and queues
|
||||
* or executes them as needed.
|
||||
*
|
||||
* No commands interacting with content are safe to process until
|
||||
* the new listener script is loaded and registered itself.
|
||||
* This occurs when a command whose effect is asynchronous (such
|
||||
* as goBack) results in process change of the frame script and new
|
||||
* commands are subsequently posted to the server.
|
||||
*/
|
||||
* This function intercepts commands interacting with content and queues
|
||||
* or executes them as needed.
|
||||
*
|
||||
* No commands interacting with content are safe to process until
|
||||
* the new listener script is loaded and registered itself.
|
||||
* This occurs when a command whose effect is asynchronous (such
|
||||
* as goBack) results in process change of the frame script and new
|
||||
* commands are subsequently posted to the server.
|
||||
*/
|
||||
executeWhenReady(cb) {
|
||||
if (this._needsFlushPendingCommands) {
|
||||
this.pendingCommands.push(cb);
|
||||
|
|
|
@ -4,17 +4,19 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {Preferences} = ChromeUtils.import("resource://gre/modules/Preferences.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { Preferences } = ChromeUtils.import(
|
||||
"resource://gre/modules/Preferences.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const {assert} = ChromeUtils.import("chrome://marionette/content/assert.js");
|
||||
const {
|
||||
InvalidArgumentError,
|
||||
} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const {
|
||||
pprint,
|
||||
} = ChromeUtils.import("chrome://marionette/content/format.js");
|
||||
const { assert } = ChromeUtils.import("chrome://marionette/content/assert.js");
|
||||
const { InvalidArgumentError } = ChromeUtils.import(
|
||||
"chrome://marionette/content/error.js"
|
||||
);
|
||||
const { pprint } = ChromeUtils.import("chrome://marionette/content/format.js");
|
||||
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
|
||||
|
||||
|
@ -28,9 +30,13 @@ this.EXPORTED_SYMBOLS = [
|
|||
|
||||
// Enable testing this module, as Services.appinfo.* is not available
|
||||
// in xpcshell tests.
|
||||
const appinfo = {name: "<missing>", version: "<missing>"};
|
||||
try { appinfo.name = Services.appinfo.name.toLowerCase(); } catch (e) {}
|
||||
try { appinfo.version = Services.appinfo.version; } catch (e) {}
|
||||
const appinfo = { name: "<missing>", version: "<missing>" };
|
||||
try {
|
||||
appinfo.name = Services.appinfo.name.toLowerCase();
|
||||
} catch (e) {}
|
||||
try {
|
||||
appinfo.version = Services.appinfo.version;
|
||||
} catch (e) {}
|
||||
|
||||
/** Representation of WebDriver session timeouts. */
|
||||
class Timeouts {
|
||||
|
@ -43,7 +49,9 @@ class Timeouts {
|
|||
this.script = 30000;
|
||||
}
|
||||
|
||||
toString() { return "[object Timeouts]"; }
|
||||
toString() {
|
||||
return "[object Timeouts]";
|
||||
}
|
||||
|
||||
/** Marshals timeout durations to a JSON Object. */
|
||||
toJSON() {
|
||||
|
@ -55,28 +63,36 @@ class Timeouts {
|
|||
}
|
||||
|
||||
static fromJSON(json) {
|
||||
assert.object(json,
|
||||
pprint`Expected "timeouts" to be an object, got ${json}`);
|
||||
assert.object(
|
||||
json,
|
||||
pprint`Expected "timeouts" to be an object, got ${json}`
|
||||
);
|
||||
let t = new Timeouts();
|
||||
|
||||
for (let [type, ms] of Object.entries(json)) {
|
||||
switch (type) {
|
||||
case "implicit":
|
||||
t.implicit = assert.positiveInteger(ms,
|
||||
pprint`Expected ${type} to be a positive integer, got ${ms}`);
|
||||
t.implicit = assert.positiveInteger(
|
||||
ms,
|
||||
pprint`Expected ${type} to be a positive integer, got ${ms}`
|
||||
);
|
||||
break;
|
||||
|
||||
case "script":
|
||||
if (ms !== null) {
|
||||
assert.positiveInteger(ms,
|
||||
pprint`Expected ${type} to be a positive integer, got ${ms}`);
|
||||
assert.positiveInteger(
|
||||
ms,
|
||||
pprint`Expected ${type} to be a positive integer, got ${ms}`
|
||||
);
|
||||
}
|
||||
t.script = ms;
|
||||
break;
|
||||
|
||||
case "pageLoad":
|
||||
t.pageLoad = assert.positiveInteger(ms,
|
||||
pprint`Expected ${type} to be a positive integer, got ${ms}`);
|
||||
t.pageLoad = assert.positiveInteger(
|
||||
ms,
|
||||
pprint`Expected ${type} to be a positive integer, got ${ms}`
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -179,14 +195,19 @@ class Proxy {
|
|||
}
|
||||
|
||||
if (this.noProxy) {
|
||||
Preferences.set("network.proxy.no_proxies_on", this.noProxy.join(", "));
|
||||
Preferences.set(
|
||||
"network.proxy.no_proxies_on",
|
||||
this.noProxy.join(", ")
|
||||
);
|
||||
}
|
||||
return true;
|
||||
|
||||
case "pac":
|
||||
Preferences.set("network.proxy.type", 2);
|
||||
Preferences.set(
|
||||
"network.proxy.autoconfig_url", this.proxyAutoconfigUrl);
|
||||
"network.proxy.autoconfig_url",
|
||||
this.proxyAutoconfigUrl
|
||||
);
|
||||
return true;
|
||||
|
||||
case "system":
|
||||
|
@ -207,13 +228,17 @@ class Proxy {
|
|||
*/
|
||||
static fromJSON(json) {
|
||||
function stripBracketsFromIpv6Hostname(hostname) {
|
||||
return hostname.includes(":") ? hostname.replace(/[\[\]]/g, "") : hostname;
|
||||
return hostname.includes(":")
|
||||
? hostname.replace(/[\[\]]/g, "")
|
||||
: hostname;
|
||||
}
|
||||
|
||||
// Parse hostname and optional port from host
|
||||
function fromHost(scheme, host) {
|
||||
assert.string(host,
|
||||
pprint`Expected proxy "host" to be a string, got ${host}`);
|
||||
assert.string(
|
||||
host,
|
||||
pprint`Expected proxy "host" to be a string, got ${host}`
|
||||
);
|
||||
|
||||
if (host.includes("://")) {
|
||||
throw new InvalidArgumentError(`${host} contains a scheme`);
|
||||
|
@ -247,13 +272,16 @@ class Proxy {
|
|||
}
|
||||
}
|
||||
|
||||
if (url.username != "" ||
|
||||
url.password != "" ||
|
||||
url.pathname != "/" ||
|
||||
url.search != "" ||
|
||||
url.hash != "") {
|
||||
if (
|
||||
url.username != "" ||
|
||||
url.password != "" ||
|
||||
url.pathname != "/" ||
|
||||
url.search != "" ||
|
||||
url.hash != ""
|
||||
) {
|
||||
throw new InvalidArgumentError(
|
||||
`${host} was not of the form host[:port]`);
|
||||
`${host} was not of the form host[:port]`
|
||||
);
|
||||
}
|
||||
|
||||
return [hostname, port];
|
||||
|
@ -266,10 +294,15 @@ class Proxy {
|
|||
|
||||
assert.object(json, pprint`Expected "proxy" to be an object, got ${json}`);
|
||||
|
||||
assert.in("proxyType", json,
|
||||
pprint`Expected "proxyType" in "proxy" object, got ${json}`);
|
||||
p.proxyType = assert.string(json.proxyType,
|
||||
pprint`Expected "proxyType" to be a string, got ${json.proxyType}`);
|
||||
assert.in(
|
||||
"proxyType",
|
||||
json,
|
||||
pprint`Expected "proxyType" in "proxy" object, got ${json}`
|
||||
);
|
||||
p.proxyType = assert.string(
|
||||
json.proxyType,
|
||||
pprint`Expected "proxyType" to be a string, got ${json.proxyType}`
|
||||
);
|
||||
|
||||
switch (p.proxyType) {
|
||||
case "autodetect":
|
||||
|
@ -278,9 +311,11 @@ class Proxy {
|
|||
break;
|
||||
|
||||
case "pac":
|
||||
p.proxyAutoconfigUrl = assert.string(json.proxyAutoconfigUrl,
|
||||
`Expected "proxyAutoconfigUrl" to be a string, ` +
|
||||
pprint`got ${json.proxyAutoconfigUrl}`);
|
||||
p.proxyAutoconfigUrl = assert.string(
|
||||
json.proxyAutoconfigUrl,
|
||||
`Expected "proxyAutoconfigUrl" to be a string, ` +
|
||||
pprint`got ${json.proxyAutoconfigUrl}`
|
||||
);
|
||||
break;
|
||||
|
||||
case "manual":
|
||||
|
@ -295,23 +330,30 @@ class Proxy {
|
|||
}
|
||||
if (typeof json.socksProxy != "undefined") {
|
||||
[p.socksProxy, p.socksProxyPort] = fromHost("socks", json.socksProxy);
|
||||
p.socksVersion = assert.positiveInteger(json.socksVersion,
|
||||
pprint`Expected "socksVersion" to be a positive integer, got ${json.socksVersion}`);
|
||||
p.socksVersion = assert.positiveInteger(
|
||||
json.socksVersion,
|
||||
pprint`Expected "socksVersion" to be a positive integer, got ${
|
||||
json.socksVersion
|
||||
}`
|
||||
);
|
||||
}
|
||||
if (typeof json.noProxy != "undefined") {
|
||||
let entries = assert.array(json.noProxy,
|
||||
pprint`Expected "noProxy" to be an array, got ${json.noProxy}`);
|
||||
let entries = assert.array(
|
||||
json.noProxy,
|
||||
pprint`Expected "noProxy" to be an array, got ${json.noProxy}`
|
||||
);
|
||||
p.noProxy = entries.map(entry => {
|
||||
assert.string(entry,
|
||||
pprint`Expected "noProxy" entry to be a string, got ${entry}`);
|
||||
assert.string(
|
||||
entry,
|
||||
pprint`Expected "noProxy" entry to be a string, got ${entry}`
|
||||
);
|
||||
return stripBracketsFromIpv6Hostname(entry);
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentError(
|
||||
`Invalid type of proxy: ${p.proxyType}`);
|
||||
throw new InvalidArgumentError(`Invalid type of proxy: ${p.proxyType}`);
|
||||
}
|
||||
|
||||
return p;
|
||||
|
@ -358,7 +400,9 @@ class Proxy {
|
|||
});
|
||||
}
|
||||
|
||||
toString() { return "[object Proxy]"; }
|
||||
toString() {
|
||||
return "[object Proxy]";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -409,10 +453,16 @@ class Capabilities extends Map {
|
|||
// proprietary
|
||||
["moz:accessibilityChecks", false],
|
||||
["moz:buildID", Services.appinfo.appBuildID],
|
||||
["moz:headless", Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo).isHeadless],
|
||||
[
|
||||
"moz:headless",
|
||||
Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo).isHeadless,
|
||||
],
|
||||
["moz:processID", Services.appinfo.processID],
|
||||
["moz:profile", maybeProfile()],
|
||||
["moz:shutdownTimeout", Services.prefs.getIntPref("toolkit.asyncshutdown.crash_timeout")],
|
||||
[
|
||||
"moz:shutdownTimeout",
|
||||
Services.prefs.getIntPref("toolkit.asyncshutdown.crash_timeout"),
|
||||
],
|
||||
["moz:useNonSpecCompliantPointerOrigin", false],
|
||||
["moz:webdriverClick", true],
|
||||
]);
|
||||
|
@ -434,7 +484,9 @@ class Capabilities extends Map {
|
|||
return super.set(key, value);
|
||||
}
|
||||
|
||||
toString() { return "[object Capabilities]"; }
|
||||
toString() {
|
||||
return "[object Capabilities]";
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON serialisation of capabilities object.
|
||||
|
@ -460,8 +512,10 @@ class Capabilities extends Map {
|
|||
if (typeof json == "undefined" || json === null) {
|
||||
json = {};
|
||||
}
|
||||
assert.object(json,
|
||||
pprint`Expected "capabilities" to be an object, got ${json}"`);
|
||||
assert.object(
|
||||
json,
|
||||
pprint`Expected "capabilities" to be an object, got ${json}"`
|
||||
);
|
||||
|
||||
return Capabilities.match_(json);
|
||||
}
|
||||
|
@ -492,7 +546,9 @@ class Capabilities extends Map {
|
|||
if (appinfo.name == "firefox" && !v) {
|
||||
throw new InvalidArgumentError("setWindowRect cannot be disabled");
|
||||
} else if (appinfo.name != "firefox" && v) {
|
||||
throw new InvalidArgumentError("setWindowRect is only supported in Firefox desktop");
|
||||
throw new InvalidArgumentError(
|
||||
"setWindowRect is only supported in Firefox desktop"
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -508,7 +564,8 @@ class Capabilities extends Map {
|
|||
assert.string(v, pprint`Expected ${k} to be a string, got ${v}`);
|
||||
if (!Object.values(UnhandledPromptBehavior).includes(v)) {
|
||||
throw new InvalidArgumentError(
|
||||
`Unknown unhandled prompt behavior: ${v}`);
|
||||
`Unknown unhandled prompt behavior: ${v}`
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -583,7 +640,7 @@ function marshal(obj) {
|
|||
if (typeof v.toJSON == "function") {
|
||||
v = marshal(v.toJSON());
|
||||
|
||||
// Or do the same for object literals.
|
||||
// Or do the same for object literals.
|
||||
} else if (isObject(v)) {
|
||||
v = marshal(v);
|
||||
}
|
||||
|
|
|
@ -4,10 +4,14 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const {InvalidArgumentError} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const {Log} = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
const { InvalidArgumentError } = ChromeUtils.import(
|
||||
"chrome://marionette/content/error.js"
|
||||
);
|
||||
const { Log } = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", Log.get);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["crypto"]);
|
||||
|
@ -48,13 +52,9 @@ capture.element = function(node, highlights = []) {
|
|||
let win = node.ownerGlobal;
|
||||
let rect = node.getBoundingClientRect();
|
||||
|
||||
return capture.canvas(
|
||||
win,
|
||||
rect.left,
|
||||
rect.top,
|
||||
rect.width,
|
||||
rect.height,
|
||||
{highlights});
|
||||
return capture.canvas(win, rect.left, rect.top, rect.width, rect.height, {
|
||||
highlights,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -73,12 +73,13 @@ capture.element = function(node, highlights = []) {
|
|||
*/
|
||||
capture.viewport = function(win, highlights = []) {
|
||||
return capture.canvas(
|
||||
win,
|
||||
win.pageXOffset,
|
||||
win.pageYOffset,
|
||||
win.innerWidth,
|
||||
win.innerHeight,
|
||||
{highlights});
|
||||
win,
|
||||
win.pageXOffset,
|
||||
win.pageYOffset,
|
||||
win.innerWidth,
|
||||
win.innerHeight,
|
||||
{ highlights }
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -108,8 +109,14 @@ capture.viewport = function(win, highlights = []) {
|
|||
* The canvas on which the selection from the window's framebuffer
|
||||
* has been painted on.
|
||||
*/
|
||||
capture.canvas = function(win, left, top, width, height,
|
||||
{highlights = [], canvas = null, flags = null} = {}) {
|
||||
capture.canvas = function(
|
||||
win,
|
||||
left,
|
||||
top,
|
||||
width,
|
||||
height,
|
||||
{ highlights = [], canvas = null, flags = null } = {}
|
||||
) {
|
||||
const scale = win.devicePixelRatio;
|
||||
|
||||
if (canvas === null) {
|
||||
|
@ -117,14 +124,20 @@ capture.canvas = function(win, left, top, width, height,
|
|||
let canvasHeight = height * scale;
|
||||
|
||||
if (canvasWidth > MAX_SKIA_DIMENSIONS) {
|
||||
logger.warn("Reducing screenshot width because it exceeds " +
|
||||
MAX_SKIA_DIMENSIONS + " pixels");
|
||||
logger.warn(
|
||||
"Reducing screenshot width because it exceeds " +
|
||||
MAX_SKIA_DIMENSIONS +
|
||||
" pixels"
|
||||
);
|
||||
canvasWidth = MAX_SKIA_DIMENSIONS;
|
||||
}
|
||||
|
||||
if (canvasHeight > MAX_SKIA_DIMENSIONS) {
|
||||
logger.warn("Reducing screenshot height because it exceeds " +
|
||||
MAX_SKIA_DIMENSIONS + " pixels");
|
||||
logger.warn(
|
||||
"Reducing screenshot height because it exceeds " +
|
||||
MAX_SKIA_DIMENSIONS +
|
||||
" pixels"
|
||||
);
|
||||
canvasHeight = MAX_SKIA_DIMENSIONS;
|
||||
}
|
||||
|
||||
|
@ -173,11 +186,7 @@ capture.highlight_ = function(context, highlights, top = 0, left = 0) {
|
|||
let oy = -top;
|
||||
let ox = -left;
|
||||
|
||||
context.strokeRect(
|
||||
rect.left + ox,
|
||||
rect.top + oy,
|
||||
rect.width,
|
||||
rect.height);
|
||||
context.strokeRect(rect.left + ox, rect.top + oy, rect.width, rect.height);
|
||||
}
|
||||
|
||||
return context;
|
||||
|
@ -198,14 +207,14 @@ capture.toBase64 = function(canvas) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Hash the contents of an HTMLCanvasElement to a SHA-256 hex digest.
|
||||
*
|
||||
* @param {HTMLCanvasElement} canvas
|
||||
* The canvas to encode.
|
||||
*
|
||||
* @return {string}
|
||||
* A hex digest of the SHA-256 hash of the base64 encoded string.
|
||||
*/
|
||||
* Hash the contents of an HTMLCanvasElement to a SHA-256 hex digest.
|
||||
*
|
||||
* @param {HTMLCanvasElement} canvas
|
||||
* The canvas to encode.
|
||||
*
|
||||
* @return {string}
|
||||
* A hex digest of the SHA-256 hash of the base64 encoded string.
|
||||
*/
|
||||
capture.toHash = function(canvas) {
|
||||
let u = capture.toBase64(canvas);
|
||||
let buffer = new TextEncoder("utf-8").encode(u);
|
||||
|
@ -213,14 +222,14 @@ capture.toHash = function(canvas) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Convert buffer into to hex.
|
||||
*
|
||||
* @param {ArrayBuffer} buffer
|
||||
* The buffer containing the data to convert to hex.
|
||||
*
|
||||
* @return {string}
|
||||
* A hex digest of the input buffer.
|
||||
*/
|
||||
* Convert buffer into to hex.
|
||||
*
|
||||
* @param {ArrayBuffer} buffer
|
||||
* The buffer containing the data to convert to hex.
|
||||
*
|
||||
* @return {string}
|
||||
* A hex digest of the input buffer.
|
||||
*/
|
||||
function hex(buffer) {
|
||||
let hexCodes = [];
|
||||
let view = new DataView(buffer);
|
||||
|
|
|
@ -4,18 +4,22 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {Preferences} = ChromeUtils.import("resource://gre/modules/Preferences.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { Preferences } = ChromeUtils.import(
|
||||
"resource://gre/modules/Preferences.jsm"
|
||||
);
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"CertificateOverrideManager",
|
||||
"InsecureSweepingOverride",
|
||||
];
|
||||
|
||||
const registrar =
|
||||
Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
const sss = Cc["@mozilla.org/ssservice;1"]
|
||||
.getService(Ci.nsISiteSecurityService);
|
||||
const registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
const sss = Cc["@mozilla.org/ssservice;1"].getService(
|
||||
Ci.nsISiteSecurityService
|
||||
);
|
||||
|
||||
const CERT_PINNING_ENFORCEMENT_PREF = "security.cert_pinning.enforcement_level";
|
||||
const CID = Components.ID("{4b67cce0-a51c-11e6-9598-0800200c9a66}");
|
||||
|
@ -91,8 +95,7 @@ function InsecureSweepingOverride() {
|
|||
// make your life miserable.
|
||||
let service = function() {};
|
||||
service.prototype = {
|
||||
hasMatchingOverride(
|
||||
aHostName, aPort, aCert, aOverrideBits, aIsTemporary) {
|
||||
hasMatchingOverride(aHostName, aPort, aCert, aOverrideBits, aIsTemporary) {
|
||||
aIsTemporary.value = false;
|
||||
aOverrideBits.value = Error.Untrusted | Error.Mismatch | Error.Time;
|
||||
|
||||
|
|
|
@ -4,13 +4,15 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const {
|
||||
EnvironmentPrefs,
|
||||
MarionettePrefs,
|
||||
} = ChromeUtils.import("chrome://marionette/content/prefs.js", null);
|
||||
const { EnvironmentPrefs, MarionettePrefs } = ChromeUtils.import(
|
||||
"chrome://marionette/content/prefs.js",
|
||||
null
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Log: "chrome://marionette/content/log.js",
|
||||
|
@ -21,9 +23,14 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
XPCOMUtils.defineLazyGetter(this, "log", Log.get);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this, "env", "@mozilla.org/process/environment;1", "nsIEnvironment");
|
||||
this,
|
||||
"env",
|
||||
"@mozilla.org/process/environment;1",
|
||||
"nsIEnvironment"
|
||||
);
|
||||
|
||||
const XMLURI_PARSE_ERROR = "http://www.mozilla.org/newlayout/xml/parsererror.xml";
|
||||
const XMLURI_PARSE_ERROR =
|
||||
"http://www.mozilla.org/newlayout/xml/parsererror.xml";
|
||||
|
||||
const NOTIFY_RUNNING = "remote-active";
|
||||
|
||||
|
@ -60,7 +67,6 @@ const ENV_PRESERVE_PREFS = "MOZ_MARIONETTE_PREF_STATE_ACROSS_RESTARTS";
|
|||
// such backward compatibility has to be ensured at least for the last three
|
||||
// releases.
|
||||
const RECOMMENDED_PREFS = new Map([
|
||||
|
||||
// Make sure Shield doesn't hit the network.
|
||||
["app.normandy.api_url", ""],
|
||||
|
||||
|
@ -213,10 +219,7 @@ const RECOMMENDED_PREFS = new Map([
|
|||
["extensions.update.notifyUser", false],
|
||||
|
||||
// Make sure opening about:addons will not hit the network
|
||||
[
|
||||
"extensions.webservice.discoverURL",
|
||||
"http://%(server)s/dummy/discoveryURL",
|
||||
],
|
||||
["extensions.webservice.discoverURL", "http://%(server)s/dummy/discoveryURL"],
|
||||
|
||||
// Allow the application to have focus even it runs in the background
|
||||
["focusmanager.testmode", true],
|
||||
|
@ -283,11 +286,10 @@ const RECOMMENDED_PREFS = new Map([
|
|||
|
||||
// Prevent starting into safe mode after application crashes
|
||||
["toolkit.startup.max_resumed_crashes", -1],
|
||||
|
||||
]);
|
||||
|
||||
const isRemote = Services.appinfo.processType ==
|
||||
Services.appinfo.PROCESS_TYPE_CONTENT;
|
||||
const isRemote =
|
||||
Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT;
|
||||
|
||||
class MarionetteParentProcess {
|
||||
constructor() {
|
||||
|
@ -320,7 +322,7 @@ class MarionetteParentProcess {
|
|||
return MarionettePrefs.enabled;
|
||||
}
|
||||
|
||||
receiveMessage({name}) {
|
||||
receiveMessage({ name }) {
|
||||
switch (name) {
|
||||
case "Marionette:IsRunning":
|
||||
return this.running;
|
||||
|
@ -390,16 +392,20 @@ class MarionetteParentProcess {
|
|||
break;
|
||||
|
||||
case "toplevel-window-ready":
|
||||
subject.addEventListener("load", ev => {
|
||||
if (ev.target.documentElement.namespaceURI == XMLURI_PARSE_ERROR) {
|
||||
Services.obs.removeObserver(this, topic);
|
||||
subject.addEventListener(
|
||||
"load",
|
||||
ev => {
|
||||
if (ev.target.documentElement.namespaceURI == XMLURI_PARSE_ERROR) {
|
||||
Services.obs.removeObserver(this, topic);
|
||||
|
||||
let parserError = ev.target.querySelector("parsererror");
|
||||
log.fatal(parserError.textContent);
|
||||
this.uninit();
|
||||
Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
|
||||
}
|
||||
}, {once: true});
|
||||
let parserError = ev.target.querySelector("parsererror");
|
||||
log.fatal(parserError.textContent);
|
||||
this.uninit();
|
||||
Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
|
||||
}
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
break;
|
||||
|
||||
case "marionette-startup-requested":
|
||||
|
@ -409,14 +415,19 @@ class MarionetteParentProcess {
|
|||
// window may appear off-screen. Marionette should wait for it
|
||||
// to close.
|
||||
for (let win of Services.wm.getEnumerator(null)) {
|
||||
if (win.document.documentURI == "chrome://gfxsanity/content/sanityparent.html") {
|
||||
if (
|
||||
win.document.documentURI ==
|
||||
"chrome://gfxsanity/content/sanityparent.html"
|
||||
) {
|
||||
this.gfxWindow = win;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.gfxWindow) {
|
||||
log.trace("GFX sanity window detected, waiting until it has been closed...");
|
||||
log.trace(
|
||||
"GFX sanity window detected, waiting until it has been closed..."
|
||||
);
|
||||
Services.obs.addObserver(this, "domwindowclosed");
|
||||
} else {
|
||||
Services.obs.removeObserver(this, "toplevel-window-ready");
|
||||
|
@ -437,30 +448,38 @@ class MarionetteParentProcess {
|
|||
}
|
||||
|
||||
suppressSafeModeDialog(win) {
|
||||
win.addEventListener("load", () => {
|
||||
if (win.document.getElementById("safeModeDialog")) {
|
||||
// accept the dialog to start in safe-mode
|
||||
log.trace("Safe mode detected, supressing dialog");
|
||||
win.setTimeout(() => {
|
||||
win.document.documentElement.getButton("accept").click();
|
||||
});
|
||||
}
|
||||
}, {once: true});
|
||||
win.addEventListener(
|
||||
"load",
|
||||
() => {
|
||||
if (win.document.getElementById("safeModeDialog")) {
|
||||
// accept the dialog to start in safe-mode
|
||||
log.trace("Safe mode detected, supressing dialog");
|
||||
win.setTimeout(() => {
|
||||
win.document.documentElement.getButton("accept").click();
|
||||
});
|
||||
}
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
}
|
||||
|
||||
init(quit = true) {
|
||||
if (this.running || !this.enabled || !this.finalUIStartup) {
|
||||
log.debug(`Init aborted (running=${this.running}, ` +
|
||||
`enabled=${this.enabled}, finalUIStartup=${this.finalUIStartup})`);
|
||||
log.debug(
|
||||
`Init aborted (running=${this.running}, ` +
|
||||
`enabled=${this.enabled}, finalUIStartup=${this.finalUIStartup})`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
log.trace(`Waiting until startup recorder finished recording startup scripts...`);
|
||||
log.trace(
|
||||
`Waiting until startup recorder finished recording startup scripts...`
|
||||
);
|
||||
Services.tm.idleDispatchToMainThread(async () => {
|
||||
let startupRecorder = Promise.resolve();
|
||||
if ("@mozilla.org/test/startuprecorder;1" in Cc) {
|
||||
startupRecorder = Cc["@mozilla.org/test/startuprecorder;1"]
|
||||
.getService().wrappedJSObject.done;
|
||||
startupRecorder = Cc["@mozilla.org/test/startuprecorder;1"].getService()
|
||||
.wrappedJSObject.done;
|
||||
}
|
||||
await startupRecorder;
|
||||
log.trace(`All scripts recorded.`);
|
||||
|
|
|
@ -4,14 +4,13 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const {assert} = ChromeUtils.import("chrome://marionette/content/assert.js");
|
||||
const {
|
||||
InvalidCookieDomainError,
|
||||
UnableToSetCookieError,
|
||||
} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const {pprint} = ChromeUtils.import("chrome://marionette/content/format.js");
|
||||
const { assert } = ChromeUtils.import("chrome://marionette/content/assert.js");
|
||||
const { InvalidCookieDomainError, UnableToSetCookieError } = ChromeUtils.import(
|
||||
"chrome://marionette/content/error.js"
|
||||
);
|
||||
const { pprint } = ChromeUtils.import("chrome://marionette/content/format.js");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["cookie"];
|
||||
|
||||
|
@ -61,16 +60,28 @@ cookie.fromJSON = function(json) {
|
|||
newCookie.path = assert.string(json.path, "Cookie path must be string");
|
||||
}
|
||||
if (typeof json.domain != "undefined") {
|
||||
newCookie.domain = assert.string(json.domain, "Cookie domain must be string");
|
||||
newCookie.domain = assert.string(
|
||||
json.domain,
|
||||
"Cookie domain must be string"
|
||||
);
|
||||
}
|
||||
if (typeof json.secure != "undefined") {
|
||||
newCookie.secure = assert.boolean(json.secure, "Cookie secure flag must be boolean");
|
||||
newCookie.secure = assert.boolean(
|
||||
json.secure,
|
||||
"Cookie secure flag must be boolean"
|
||||
);
|
||||
}
|
||||
if (typeof json.httpOnly != "undefined") {
|
||||
newCookie.httpOnly = assert.boolean(json.httpOnly, "Cookie httpOnly flag must be boolean");
|
||||
newCookie.httpOnly = assert.boolean(
|
||||
json.httpOnly,
|
||||
"Cookie httpOnly flag must be boolean"
|
||||
);
|
||||
}
|
||||
if (typeof json.expiry != "undefined") {
|
||||
newCookie.expiry = assert.positiveInteger(json.expiry, "Cookie expiry must be a positive integer");
|
||||
newCookie.expiry = assert.positiveInteger(
|
||||
json.expiry,
|
||||
"Cookie expiry must be a positive integer"
|
||||
);
|
||||
}
|
||||
|
||||
return newCookie;
|
||||
|
@ -93,7 +104,7 @@ cookie.fromJSON = function(json) {
|
|||
* @throws {UnableToSetCookieError}
|
||||
* If an error occurred while trying to save the cookie.
|
||||
*/
|
||||
cookie.add = function(newCookie, {restrictToHost = null} = {}) {
|
||||
cookie.add = function(newCookie, { restrictToHost = null } = {}) {
|
||||
assert.string(newCookie.name, "Cookie name must be string");
|
||||
assert.string(newCookie.value, "Cookie value must be string");
|
||||
|
||||
|
@ -145,11 +156,15 @@ cookie.add = function(newCookie, {restrictToHost = null} = {}) {
|
|||
}
|
||||
|
||||
if (restrictToHost) {
|
||||
if (!restrictToHost.endsWith(newCookie.domain) &&
|
||||
("." + restrictToHost) !== newCookie.domain &&
|
||||
restrictToHost !== newCookie.domain) {
|
||||
throw new InvalidCookieDomainError(`Cookies may only be set ` +
|
||||
`for the current domain (${restrictToHost})`);
|
||||
if (
|
||||
!restrictToHost.endsWith(newCookie.domain) &&
|
||||
"." + restrictToHost !== newCookie.domain &&
|
||||
restrictToHost !== newCookie.domain
|
||||
) {
|
||||
throw new InvalidCookieDomainError(
|
||||
`Cookies may only be set ` +
|
||||
`for the current domain (${restrictToHost})`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,16 +175,17 @@ cookie.add = function(newCookie, {restrictToHost = null} = {}) {
|
|||
|
||||
try {
|
||||
cookie.manager.add(
|
||||
newCookie.domain,
|
||||
newCookie.path,
|
||||
newCookie.name,
|
||||
newCookie.value,
|
||||
newCookie.secure,
|
||||
newCookie.httpOnly,
|
||||
newCookie.session,
|
||||
newCookie.expiry,
|
||||
{} /* origin attributes */,
|
||||
Ci.nsICookie.SAMESITE_NONE);
|
||||
newCookie.domain,
|
||||
newCookie.path,
|
||||
newCookie.name,
|
||||
newCookie.value,
|
||||
newCookie.secure,
|
||||
newCookie.httpOnly,
|
||||
newCookie.session,
|
||||
newCookie.expiry,
|
||||
{} /* origin attributes */,
|
||||
Ci.nsICookie.SAMESITE_NONE
|
||||
);
|
||||
} catch (e) {
|
||||
throw new UnableToSetCookieError(e);
|
||||
}
|
||||
|
@ -183,11 +199,12 @@ cookie.add = function(newCookie, {restrictToHost = null} = {}) {
|
|||
*/
|
||||
cookie.remove = function(toDelete) {
|
||||
cookie.manager.remove(
|
||||
toDelete.domain,
|
||||
toDelete.name,
|
||||
toDelete.path,
|
||||
false,
|
||||
{} /* originAttributes */);
|
||||
toDelete.domain,
|
||||
toDelete.name,
|
||||
toDelete.path,
|
||||
false,
|
||||
{} /* originAttributes */
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -204,7 +221,7 @@ cookie.remove = function(toDelete) {
|
|||
* @return {Iterable.<Cookie>}
|
||||
* Iterator.
|
||||
*/
|
||||
cookie.iter = function* (host, currentPath = "/") {
|
||||
cookie.iter = function*(host, currentPath = "/") {
|
||||
assert.string(host, "host must be string");
|
||||
assert.string(currentPath, "currentPath must be string");
|
||||
|
||||
|
@ -215,15 +232,17 @@ cookie.iter = function* (host, currentPath = "/") {
|
|||
// take the hostname and progressively shorten
|
||||
let hostname = host;
|
||||
do {
|
||||
if ((cookie.host == "." + hostname || cookie.host == hostname) &&
|
||||
isForCurrentPath(cookie.path)) {
|
||||
if (
|
||||
(cookie.host == "." + hostname || cookie.host == hostname) &&
|
||||
isForCurrentPath(cookie.path)
|
||||
) {
|
||||
let data = {
|
||||
"name": cookie.name,
|
||||
"value": cookie.value,
|
||||
"path": cookie.path,
|
||||
"domain": cookie.host,
|
||||
"secure": cookie.isSecure,
|
||||
"httpOnly": cookie.isHttpOnly,
|
||||
name: cookie.name,
|
||||
value: cookie.value,
|
||||
path: cookie.path,
|
||||
domain: cookie.host,
|
||||
secure: cookie.isSecure,
|
||||
httpOnly: cookie.isHttpOnly,
|
||||
};
|
||||
|
||||
if (!cookie.isSession) {
|
||||
|
|
|
@ -4,9 +4,11 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const {Log} = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
const { Log } = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", Log.get);
|
||||
|
||||
|
@ -60,7 +62,7 @@ class WebElementEventTarget {
|
|||
* most once after being added. If true, the ``listener``
|
||||
* would automatically be removed when invoked.
|
||||
*/
|
||||
addEventListener(type, listener, {once = false} = {}) {
|
||||
addEventListener(type, listener, { once = false } = {}) {
|
||||
if (!(type in this.listeners)) {
|
||||
this.listeners[type] = [];
|
||||
}
|
||||
|
@ -70,7 +72,7 @@ class WebElementEventTarget {
|
|||
this.listeners[type].push(listener);
|
||||
}
|
||||
|
||||
this.mm.sendAsyncMessage("Marionette:DOM:AddEventListener", {type});
|
||||
this.mm.sendAsyncMessage("Marionette:DOM:AddEventListener", { type });
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -91,7 +93,9 @@ class WebElementEventTarget {
|
|||
if (stack[i] === listener) {
|
||||
stack.splice(i, 1);
|
||||
if (stack.length == 0) {
|
||||
this.mm.sendAsyncMessage("Marionette:DOM:RemoveEventListener", {type});
|
||||
this.mm.sendAsyncMessage("Marionette:DOM:RemoveEventListener", {
|
||||
type,
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -119,7 +123,7 @@ class WebElementEventTarget {
|
|||
});
|
||||
}
|
||||
|
||||
receiveMessage({name, data, objects}) {
|
||||
receiveMessage({ name, data, objects }) {
|
||||
if (name != "Marionette:DOM:OnEvent") {
|
||||
return;
|
||||
}
|
||||
|
@ -196,15 +200,15 @@ class ContentEventObserverService {
|
|||
}
|
||||
}
|
||||
|
||||
* [Symbol.iterator]() {
|
||||
*[Symbol.iterator]() {
|
||||
for (let ev of this.events) {
|
||||
yield ev;
|
||||
}
|
||||
}
|
||||
|
||||
handleEvent({type, target}) {
|
||||
handleEvent({ type, target }) {
|
||||
logger.trace(`Received DOM event ${type}`);
|
||||
this.sendAsyncMessage("Marionette:DOM:OnEvent", {type}, {target});
|
||||
this.sendAsyncMessage("Marionette:DOM:OnEvent", { type }, { target });
|
||||
}
|
||||
}
|
||||
this.ContentEventObserverService = ContentEventObserverService;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -5,16 +5,18 @@
|
|||
"use strict";
|
||||
/* global XPCNativeWrapper */
|
||||
|
||||
const {assert} = ChromeUtils.import("chrome://marionette/content/assert.js");
|
||||
const {atom} = ChromeUtils.import("chrome://marionette/content/atom.js");
|
||||
const { assert } = ChromeUtils.import("chrome://marionette/content/assert.js");
|
||||
const { atom } = ChromeUtils.import("chrome://marionette/content/atom.js");
|
||||
const {
|
||||
InvalidArgumentError,
|
||||
InvalidSelectorError,
|
||||
NoSuchElementError,
|
||||
StaleElementReferenceError,
|
||||
} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const {pprint} = ChromeUtils.import("chrome://marionette/content/format.js");
|
||||
const {PollPromise} = ChromeUtils.import("chrome://marionette/content/sync.js");
|
||||
const { pprint } = ChromeUtils.import("chrome://marionette/content/format.js");
|
||||
const { PollPromise } = ChromeUtils.import(
|
||||
"chrome://marionette/content/sync.js"
|
||||
);
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"ChromeWebElement",
|
||||
|
@ -35,11 +37,7 @@ const XBLNS = "http://www.mozilla.org/xbl";
|
|||
const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
/** XUL elements that support checked property. */
|
||||
const XUL_CHECKED_ELS = new Set([
|
||||
"button",
|
||||
"checkbox",
|
||||
"toolbarbutton",
|
||||
]);
|
||||
const XUL_CHECKED_ELS = new Set(["button", "checkbox", "toolbarbutton"]);
|
||||
|
||||
/** XUL elements that support selected property. */
|
||||
const XUL_SELECTED_ELS = new Set([
|
||||
|
@ -51,8 +49,9 @@ const XUL_SELECTED_ELS = new Set([
|
|||
"tab",
|
||||
]);
|
||||
|
||||
const uuidGen = Cc["@mozilla.org/uuid-generator;1"]
|
||||
.getService(Ci.nsIUUIDGenerator);
|
||||
const uuidGen = Cc["@mozilla.org/uuid-generator;1"].getService(
|
||||
Ci.nsIUUIDGenerator
|
||||
);
|
||||
|
||||
/**
|
||||
* This module provides shared functionality for dealing with DOM-
|
||||
|
@ -144,8 +143,8 @@ element.Store = class {
|
|||
|
||||
if (!(isDOMElement || isDOMWindow || isXULElement)) {
|
||||
throw new TypeError(
|
||||
"Expected an element or WindowProxy, " +
|
||||
pprint`got: ${el}`);
|
||||
"Expected an element or WindowProxy, " + pprint`got: ${el}`
|
||||
);
|
||||
}
|
||||
|
||||
for (let i in this.els) {
|
||||
|
@ -159,7 +158,7 @@ element.Store = class {
|
|||
return WebElement.fromUUID(i, context);
|
||||
}
|
||||
|
||||
// cleanup reference to gc'd element
|
||||
// cleanup reference to gc'd element
|
||||
} else {
|
||||
delete this.els[i];
|
||||
}
|
||||
|
@ -188,8 +187,7 @@ element.Store = class {
|
|||
*/
|
||||
has(webEl) {
|
||||
if (!(webEl instanceof WebElement)) {
|
||||
throw new TypeError(
|
||||
pprint`Expected web element, got: ${webEl}`);
|
||||
throw new TypeError(pprint`Expected web element, got: ${webEl}`);
|
||||
}
|
||||
return Object.keys(this.els).includes(webEl.uuid);
|
||||
}
|
||||
|
@ -220,12 +218,12 @@ element.Store = class {
|
|||
*/
|
||||
get(webEl, win) {
|
||||
if (!(webEl instanceof WebElement)) {
|
||||
throw new TypeError(
|
||||
pprint`Expected web element, got: ${webEl}`);
|
||||
throw new TypeError(pprint`Expected web element, got: ${webEl}`);
|
||||
}
|
||||
if (!this.has(webEl)) {
|
||||
throw new NoSuchElementError(
|
||||
"Web element reference not seen before: " + webEl.uuid);
|
||||
"Web element reference not seen before: " + webEl.uuid
|
||||
);
|
||||
}
|
||||
|
||||
let el;
|
||||
|
@ -238,10 +236,11 @@ element.Store = class {
|
|||
|
||||
if (element.isStale(el, win)) {
|
||||
throw new StaleElementReferenceError(
|
||||
pprint`The element reference of ${el || webEl.uuid} is stale; ` +
|
||||
"either the element is no longer attached to the DOM, " +
|
||||
"it is not in the current frame context, " +
|
||||
"or the document has been refreshed");
|
||||
pprint`The element reference of ${el || webEl.uuid} is stale; ` +
|
||||
"either the element is no longer attached to the DOM, " +
|
||||
"it is not in the current frame context, " +
|
||||
"or the document has been refreshed"
|
||||
);
|
||||
}
|
||||
|
||||
return el;
|
||||
|
@ -311,15 +310,20 @@ element.find = function(container, strategy, selector, opts = {}) {
|
|||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let findElements = new PollPromise((resolve, reject) => {
|
||||
let res = find_(container, strategy, selector, searchFn,
|
||||
{all, startNode});
|
||||
if (res.length > 0) {
|
||||
resolve(Array.from(res));
|
||||
} else {
|
||||
reject([]);
|
||||
}
|
||||
}, {timeout});
|
||||
let findElements = new PollPromise(
|
||||
(resolve, reject) => {
|
||||
let res = find_(container, strategy, selector, searchFn, {
|
||||
all,
|
||||
startNode,
|
||||
});
|
||||
if (res.length > 0) {
|
||||
resolve(Array.from(res));
|
||||
} else {
|
||||
reject([]);
|
||||
}
|
||||
},
|
||||
{ timeout }
|
||||
);
|
||||
|
||||
findElements.then(foundEls => {
|
||||
// the following code ought to be moved into findElement
|
||||
|
@ -328,8 +332,8 @@ element.find = function(container, strategy, selector, opts = {}) {
|
|||
let msg;
|
||||
switch (strategy) {
|
||||
case element.Strategy.AnonAttribute:
|
||||
msg = "Unable to locate anonymous element: " +
|
||||
JSON.stringify(selector);
|
||||
msg =
|
||||
"Unable to locate anonymous element: " + JSON.stringify(selector);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -347,8 +351,13 @@ element.find = function(container, strategy, selector, opts = {}) {
|
|||
});
|
||||
};
|
||||
|
||||
function find_(container, strategy, selector, searchFn,
|
||||
{startNode = null, all = false} = {}) {
|
||||
function find_(
|
||||
container,
|
||||
strategy,
|
||||
selector,
|
||||
searchFn,
|
||||
{ startNode = null, all = false } = {}
|
||||
) {
|
||||
let rootNode = container.shadowRoot || container.frame.document;
|
||||
|
||||
if (!startNode) {
|
||||
|
@ -372,7 +381,8 @@ function find_(container, strategy, selector, searchFn,
|
|||
res = searchFn(strategy, selector, rootNode, startNode);
|
||||
} catch (e) {
|
||||
throw new InvalidSelectorError(
|
||||
`Given ${strategy} expression "${selector}" is invalid: ${e}`);
|
||||
`Given ${strategy} expression "${selector}" is invalid: ${e}`
|
||||
);
|
||||
}
|
||||
|
||||
if (res) {
|
||||
|
@ -399,7 +409,12 @@ function find_(container, strategy, selector, searchFn,
|
|||
*/
|
||||
element.findByXPath = function(document, startNode, expression) {
|
||||
let iter = document.evaluate(
|
||||
expression, startNode, null, FIRST_ORDERED_NODE_TYPE, null);
|
||||
expression,
|
||||
startNode,
|
||||
null,
|
||||
FIRST_ORDERED_NODE_TYPE,
|
||||
null
|
||||
);
|
||||
return iter.singleNodeValue;
|
||||
};
|
||||
|
||||
|
@ -416,9 +431,14 @@ element.findByXPath = function(document, startNode, expression) {
|
|||
* @return {Iterable.<Node>}
|
||||
* Iterator over elements matching <var>expression</var>.
|
||||
*/
|
||||
element.findByXPathAll = function* (document, startNode, expression) {
|
||||
element.findByXPathAll = function*(document, startNode, expression) {
|
||||
let iter = document.evaluate(
|
||||
expression, startNode, null, ORDERED_NODE_ITERATOR_TYPE, null);
|
||||
expression,
|
||||
startNode,
|
||||
null,
|
||||
ORDERED_NODE_ITERATOR_TYPE,
|
||||
null
|
||||
);
|
||||
let el = iter.iterateNext();
|
||||
while (el) {
|
||||
yield el;
|
||||
|
@ -439,8 +459,10 @@ element.findByXPathAll = function* (document, startNode, expression) {
|
|||
* Sequence of link elements which text is <var>s</var>.
|
||||
*/
|
||||
element.findByLinkText = function(startNode, linkText) {
|
||||
return filterLinks(startNode,
|
||||
link => atom.getElementText(link).trim() === linkText);
|
||||
return filterLinks(
|
||||
startNode,
|
||||
link => atom.getElementText(link).trim() === linkText
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -457,8 +479,9 @@ element.findByLinkText = function(startNode, linkText) {
|
|||
* <var>linkText</var>.
|
||||
*/
|
||||
element.findByPartialLinkText = function(startNode, linkText) {
|
||||
return filterLinks(startNode,
|
||||
link => atom.getElementText(link).includes(linkText));
|
||||
return filterLinks(startNode, link =>
|
||||
atom.getElementText(link).includes(linkText)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -472,7 +495,7 @@ element.findByPartialLinkText = function(startNode, linkText) {
|
|||
* @return {Iterable.<XULElement>}
|
||||
* Iterator over anonymous elements.
|
||||
*/
|
||||
element.findAnonymousNodes = function* (document, node) {
|
||||
element.findAnonymousNodes = function*(document, node) {
|
||||
let anons = document.getAnonymousNodes(node) || [];
|
||||
for (let node of anons) {
|
||||
yield node;
|
||||
|
@ -522,23 +545,21 @@ function* filterLinks(startNode, predicate) {
|
|||
*/
|
||||
function findElement(strategy, selector, document, startNode = undefined) {
|
||||
switch (strategy) {
|
||||
case element.Strategy.ID:
|
||||
{
|
||||
if (startNode.getElementById) {
|
||||
return startNode.getElementById(selector);
|
||||
}
|
||||
let expr = `.//*[@id="${selector}"]`;
|
||||
return element.findByXPath(document, startNode, expr);
|
||||
case element.Strategy.ID: {
|
||||
if (startNode.getElementById) {
|
||||
return startNode.getElementById(selector);
|
||||
}
|
||||
let expr = `.//*[@id="${selector}"]`;
|
||||
return element.findByXPath(document, startNode, expr);
|
||||
}
|
||||
|
||||
case element.Strategy.Name:
|
||||
{
|
||||
if (startNode.getElementsByName) {
|
||||
return startNode.getElementsByName(selector)[0];
|
||||
}
|
||||
let expr = `.//*[@name="${selector}"]`;
|
||||
return element.findByXPath(document, startNode, expr);
|
||||
case element.Strategy.Name: {
|
||||
if (startNode.getElementsByName) {
|
||||
return startNode.getElementsByName(selector)[0];
|
||||
}
|
||||
let expr = `.//*[@name="${selector}"]`;
|
||||
return element.findByXPath(document, startNode, expr);
|
||||
}
|
||||
|
||||
case element.Strategy.ClassName:
|
||||
return startNode.getElementsByClassName(selector)[0];
|
||||
|
@ -578,7 +599,10 @@ function findElement(strategy, selector, document, startNode = undefined) {
|
|||
case element.Strategy.AnonAttribute:
|
||||
let attr = Object.keys(selector)[0];
|
||||
return document.getAnonymousElementByAttribute(
|
||||
startNode, attr, selector[attr]);
|
||||
startNode,
|
||||
attr,
|
||||
selector[attr]
|
||||
);
|
||||
}
|
||||
|
||||
throw new InvalidSelectorError(`No such strategy: ${strategy}`);
|
||||
|
@ -617,8 +641,13 @@ function findElements(strategy, selector, document, startNode = undefined) {
|
|||
if (startNode.getElementsByName) {
|
||||
return startNode.getElementsByName(selector);
|
||||
}
|
||||
return [...element.findByXPathAll(
|
||||
document, startNode, `.//*[@name="${selector}"]`)];
|
||||
return [
|
||||
...element.findByXPathAll(
|
||||
document,
|
||||
startNode,
|
||||
`.//*[@name="${selector}"]`
|
||||
),
|
||||
];
|
||||
|
||||
case element.Strategy.ClassName:
|
||||
return startNode.getElementsByClassName(selector);
|
||||
|
@ -641,7 +670,10 @@ function findElements(strategy, selector, document, startNode = undefined) {
|
|||
case element.Strategy.AnonAttribute:
|
||||
let attr = Object.keys(selector)[0];
|
||||
let el = document.getAnonymousElementByAttribute(
|
||||
startNode, attr, selector[attr]);
|
||||
startNode,
|
||||
attr,
|
||||
selector[attr]
|
||||
);
|
||||
if (el) {
|
||||
return [el];
|
||||
}
|
||||
|
@ -733,9 +765,7 @@ element.isStale = function(el, win = undefined) {
|
|||
win = el.ownerGlobal;
|
||||
}
|
||||
|
||||
if (el === null ||
|
||||
!el.ownerGlobal ||
|
||||
el.ownerDocument !== win.document) {
|
||||
if (el === null || !el.ownerGlobal || el.ownerDocument !== win.document) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -790,8 +820,11 @@ element.isSelected = function(el) {
|
|||
* True if element is read only.
|
||||
*/
|
||||
element.isReadOnly = function(el) {
|
||||
return element.isDOMElement(el) &&
|
||||
["input", "textarea"].includes(el.localName) && el.readOnly;
|
||||
return (
|
||||
element.isDOMElement(el) &&
|
||||
["input", "textarea"].includes(el.localName) &&
|
||||
el.readOnly
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -896,8 +929,10 @@ element.isMutableFormControl = function(el) {
|
|||
* True if editing host, false otherwise.
|
||||
*/
|
||||
element.isEditingHost = function(el) {
|
||||
return element.isDOMElement(el) &&
|
||||
(el.isContentEditable || el.ownerDocument.designMode == "on");
|
||||
return (
|
||||
element.isDOMElement(el) &&
|
||||
(el.isContentEditable || el.ownerDocument.designMode == "on")
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -956,8 +991,7 @@ element.isEditable = function(el) {
|
|||
* @throws TypeError
|
||||
* If <var>xOffset</var> or <var>yOffset</var> are not numbers.
|
||||
*/
|
||||
element.coordinates = function(
|
||||
node, xOffset = undefined, yOffset = undefined) {
|
||||
element.coordinates = function(node, xOffset = undefined, yOffset = undefined) {
|
||||
let box = node.getBoundingClientRect();
|
||||
|
||||
if (typeof xOffset == "undefined" || xOffset === null) {
|
||||
|
@ -998,14 +1032,16 @@ element.inViewport = function(el, x = undefined, y = undefined) {
|
|||
let vp = {
|
||||
top: win.pageYOffset,
|
||||
left: win.pageXOffset,
|
||||
bottom: (win.pageYOffset + win.innerHeight),
|
||||
right: (win.pageXOffset + win.innerWidth),
|
||||
bottom: win.pageYOffset + win.innerHeight,
|
||||
right: win.pageXOffset + win.innerWidth,
|
||||
};
|
||||
|
||||
return (vp.left <= c.x + win.pageXOffset &&
|
||||
c.x + win.pageXOffset <= vp.right &&
|
||||
vp.top <= c.y + win.pageYOffset &&
|
||||
c.y + win.pageYOffset <= vp.bottom);
|
||||
return (
|
||||
vp.left <= c.x + win.pageXOffset &&
|
||||
c.x + win.pageXOffset <= vp.right &&
|
||||
vp.top <= c.y + win.pageYOffset &&
|
||||
c.y + win.pageYOffset <= vp.bottom
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1163,7 +1199,7 @@ element.isObscured = function(el) {
|
|||
* `rect`.
|
||||
*/
|
||||
element.getInViewCentrePoint = function(rect, win) {
|
||||
const {floor, max, min} = Math;
|
||||
const { floor, max, min } = Math;
|
||||
|
||||
// calculate the intersection of the rect that is inside the viewport
|
||||
let visible = {
|
||||
|
@ -1181,7 +1217,7 @@ element.getInViewCentrePoint = function(rect, win) {
|
|||
x = floor(x);
|
||||
y = floor(y);
|
||||
|
||||
return {x, y};
|
||||
return { x, y };
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1232,7 +1268,7 @@ element.isKeyboardInteractable = () => true;
|
|||
*/
|
||||
element.scrollIntoView = function(el) {
|
||||
if (el.scrollIntoView) {
|
||||
el.scrollIntoView({block: "end", inline: "nearest", behavior: "instant"});
|
||||
el.scrollIntoView({ block: "end", inline: "nearest", behavior: "instant" });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1260,11 +1296,13 @@ element.isElement = function(node) {
|
|||
* True if <var>node</var> is a DOM element, false otherwise.
|
||||
*/
|
||||
element.isDOMElement = function(node) {
|
||||
return typeof node == "object" &&
|
||||
node !== null &&
|
||||
"nodeType" in node &&
|
||||
[ELEMENT_NODE, DOCUMENT_NODE].includes(node.nodeType) &&
|
||||
!element.isXULElement(node);
|
||||
return (
|
||||
typeof node == "object" &&
|
||||
node !== null &&
|
||||
"nodeType" in node &&
|
||||
[ELEMENT_NODE, DOCUMENT_NODE].includes(node.nodeType) &&
|
||||
!element.isXULElement(node)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1278,11 +1316,13 @@ element.isDOMElement = function(node) {
|
|||
* false otherwise.
|
||||
*/
|
||||
element.isXULElement = function(node) {
|
||||
return typeof node == "object" &&
|
||||
node !== null &&
|
||||
"nodeType" in node &&
|
||||
node.nodeType === node.ELEMENT_NODE &&
|
||||
[XBLNS, XULNS].includes(node.namespaceURI);
|
||||
return (
|
||||
typeof node == "object" &&
|
||||
node !== null &&
|
||||
"nodeType" in node &&
|
||||
node.nodeType === node.ELEMENT_NODE &&
|
||||
[XBLNS, XULNS].includes(node.namespaceURI)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1298,11 +1338,13 @@ element.isDOMWindow = function(node) {
|
|||
// TODO(ato): This should use Object.prototype.toString.call(node)
|
||||
// but it's not clear how to write a good xpcshell test for that,
|
||||
// seeing as we stub out a WindowProxy.
|
||||
return typeof node == "object" &&
|
||||
node !== null &&
|
||||
typeof node.toString == "function" &&
|
||||
node.toString() == "[object Window]" &&
|
||||
node.self === node;
|
||||
return (
|
||||
typeof node == "object" &&
|
||||
node !== null &&
|
||||
typeof node.toString == "function" &&
|
||||
node.toString() == "[object Window]" &&
|
||||
node.self === node
|
||||
);
|
||||
};
|
||||
|
||||
const boolEls = {
|
||||
|
@ -1428,8 +1470,9 @@ class WebElement {
|
|||
return new ChromeWebElement(uuid);
|
||||
}
|
||||
|
||||
throw new InvalidArgumentError("Expected DOM window/element " +
|
||||
pprint`or XUL element, got: ${node}`);
|
||||
throw new InvalidArgumentError(
|
||||
"Expected DOM window/element " + pprint`or XUL element, got: ${node}`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1469,7 +1512,8 @@ class WebElement {
|
|||
}
|
||||
|
||||
throw new InvalidArgumentError(
|
||||
pprint`Expected web element reference, got: ${json}`);
|
||||
pprint`Expected web element reference, got: ${json}`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1526,10 +1570,12 @@ class WebElement {
|
|||
return false;
|
||||
}
|
||||
|
||||
if ((ContentWebElement.Identifier in obj) ||
|
||||
(ContentWebWindow.Identifier in obj) ||
|
||||
(ContentWebFrame.Identifier in obj) ||
|
||||
(ChromeWebElement.Identifier in obj)) {
|
||||
if (
|
||||
ContentWebElement.Identifier in obj ||
|
||||
ContentWebWindow.Identifier in obj ||
|
||||
ContentWebFrame.Identifier in obj ||
|
||||
ChromeWebElement.Identifier in obj
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -1554,15 +1600,16 @@ this.WebElement = WebElement;
|
|||
*/
|
||||
class ContentWebElement extends WebElement {
|
||||
toJSON() {
|
||||
return {[ContentWebElement.Identifier]: this.uuid};
|
||||
return { [ContentWebElement.Identifier]: this.uuid };
|
||||
}
|
||||
|
||||
static fromJSON(json) {
|
||||
const {Identifier} = ContentWebElement;
|
||||
const { Identifier } = ContentWebElement;
|
||||
|
||||
if (!(Identifier in json)) {
|
||||
throw new InvalidArgumentError(
|
||||
pprint`Expected web element reference, got: ${json}`);
|
||||
pprint`Expected web element reference, got: ${json}`
|
||||
);
|
||||
}
|
||||
|
||||
let uuid = json[Identifier];
|
||||
|
@ -1579,13 +1626,14 @@ this.ContentWebElement = ContentWebElement;
|
|||
*/
|
||||
class ContentWebWindow extends WebElement {
|
||||
toJSON() {
|
||||
return {[ContentWebWindow.Identifier]: this.uuid};
|
||||
return { [ContentWebWindow.Identifier]: this.uuid };
|
||||
}
|
||||
|
||||
static fromJSON(json) {
|
||||
if (!(ContentWebWindow.Identifier in json)) {
|
||||
throw new InvalidArgumentError(
|
||||
pprint`Expected web window reference, got: ${json}`);
|
||||
pprint`Expected web window reference, got: ${json}`
|
||||
);
|
||||
}
|
||||
let uuid = json[ContentWebWindow.Identifier];
|
||||
return new ContentWebWindow(uuid);
|
||||
|
@ -1601,13 +1649,14 @@ this.ContentWebWindow = ContentWebWindow;
|
|||
*/
|
||||
class ContentWebFrame extends WebElement {
|
||||
toJSON() {
|
||||
return {[ContentWebFrame.Identifier]: this.uuid};
|
||||
return { [ContentWebFrame.Identifier]: this.uuid };
|
||||
}
|
||||
|
||||
static fromJSON(json) {
|
||||
if (!(ContentWebFrame.Identifier in json)) {
|
||||
throw new InvalidArgumentError(
|
||||
pprint`Expected web frame reference, got: ${json}`);
|
||||
pprint`Expected web frame reference, got: ${json}`
|
||||
);
|
||||
}
|
||||
let uuid = json[ContentWebFrame.Identifier];
|
||||
return new ContentWebFrame(uuid);
|
||||
|
@ -1622,13 +1671,15 @@ this.ContentWebFrame = ContentWebFrame;
|
|||
*/
|
||||
class ChromeWebElement extends WebElement {
|
||||
toJSON() {
|
||||
return {[ChromeWebElement.Identifier]: this.uuid};
|
||||
return { [ChromeWebElement.Identifier]: this.uuid };
|
||||
}
|
||||
|
||||
static fromJSON(json) {
|
||||
if (!(ChromeWebElement.Identifier in json)) {
|
||||
throw new InvalidArgumentError("Expected chrome element reference " +
|
||||
pprint`for XUL/XBL element, got: ${json}`);
|
||||
throw new InvalidArgumentError(
|
||||
"Expected chrome element reference " +
|
||||
pprint`for XUL/XBL element, got: ${json}`
|
||||
);
|
||||
}
|
||||
let uuid = json[ChromeWebElement.Identifier];
|
||||
return new ChromeWebElement(uuid);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {pprint} = ChromeUtils.import("chrome://marionette/content/format.js");
|
||||
const { pprint } = ChromeUtils.import("chrome://marionette/content/format.js");
|
||||
|
||||
const ERRORS = new Set([
|
||||
"ElementClickInterceptedError",
|
||||
|
@ -45,10 +45,7 @@ const BUILTIN_ERRORS = new Set([
|
|||
"URIError",
|
||||
]);
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"error",
|
||||
"stack",
|
||||
].concat(Array.from(ERRORS));
|
||||
this.EXPORTED_SYMBOLS = ["error", "stack"].concat(Array.from(ERRORS));
|
||||
|
||||
/** @namespace */
|
||||
this.error = {};
|
||||
|
@ -103,8 +100,7 @@ error.isError = function(val) {
|
|||
* false otherwise.
|
||||
*/
|
||||
error.isWebDriverError = function(obj) {
|
||||
return error.isError(obj) &&
|
||||
("name" in obj && ERRORS.has(obj.name));
|
||||
return error.isError(obj) && ("name" in obj && ERRORS.has(obj.name));
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -257,18 +253,20 @@ class ElementClickInterceptedError extends WebDriverError {
|
|||
|
||||
switch (obscuredEl.style.pointerEvents) {
|
||||
case "none":
|
||||
msg = pprint`Element ${obscuredEl} is not clickable ` +
|
||||
`at point (${coords.x},${coords.y}) ` +
|
||||
`because it does not have pointer events enabled, ` +
|
||||
pprint`and element ${overlayingEl} ` +
|
||||
`would receive the click instead`;
|
||||
msg =
|
||||
pprint`Element ${obscuredEl} is not clickable ` +
|
||||
`at point (${coords.x},${coords.y}) ` +
|
||||
`because it does not have pointer events enabled, ` +
|
||||
pprint`and element ${overlayingEl} ` +
|
||||
`would receive the click instead`;
|
||||
break;
|
||||
|
||||
default:
|
||||
msg = pprint`Element ${obscuredEl} is not clickable ` +
|
||||
`at point (${coords.x},${coords.y}) ` +
|
||||
pprint`because another element ${overlayingEl} ` +
|
||||
`obscures it`;
|
||||
msg =
|
||||
pprint`Element ${obscuredEl} is not clickable ` +
|
||||
`at point (${coords.x},${coords.y}) ` +
|
||||
pprint`because another element ${overlayingEl} ` +
|
||||
`obscures it`;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,19 +4,21 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {clearTimeout, setTimeout} = ChromeUtils.import("resource://gre/modules/Timer.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { clearTimeout, setTimeout } = ChromeUtils.import(
|
||||
"resource://gre/modules/Timer.jsm"
|
||||
);
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const {assert} = ChromeUtils.import("chrome://marionette/content/assert.js");
|
||||
const {
|
||||
element,
|
||||
WebElement,
|
||||
} = ChromeUtils.import("chrome://marionette/content/element.js");
|
||||
const {
|
||||
JavaScriptError,
|
||||
ScriptTimeoutError,
|
||||
} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const {Log} = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
const { assert } = ChromeUtils.import("chrome://marionette/content/assert.js");
|
||||
const { element, WebElement } = ChromeUtils.import(
|
||||
"chrome://marionette/content/element.js"
|
||||
);
|
||||
const { JavaScriptError, ScriptTimeoutError } = ChromeUtils.import(
|
||||
"chrome://marionette/content/error.js"
|
||||
);
|
||||
const { Log } = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "log", Log.get);
|
||||
|
||||
|
@ -84,13 +86,17 @@ this.evaluate = {};
|
|||
* @throws {ScriptTimeoutError}
|
||||
* If the script was interrupted due to script timeout.
|
||||
*/
|
||||
evaluate.sandbox = function(sb, script, args = [],
|
||||
{
|
||||
async = false,
|
||||
file = "dummy file",
|
||||
line = 0,
|
||||
timeout = DEFAULT_TIMEOUT,
|
||||
} = {}) {
|
||||
evaluate.sandbox = function(
|
||||
sb,
|
||||
script,
|
||||
args = [],
|
||||
{
|
||||
async = false,
|
||||
file = "dummy file",
|
||||
line = 0,
|
||||
timeout = DEFAULT_TIMEOUT,
|
||||
} = {}
|
||||
) {
|
||||
let unloadHandler;
|
||||
|
||||
// timeout handler
|
||||
|
@ -121,7 +127,9 @@ evaluate.sandbox = function(sb, script, args = [],
|
|||
}).apply(null, ${ARGUMENTS})`;
|
||||
|
||||
unloadHandler = sandbox.cloneInto(
|
||||
() => reject(new JavaScriptError("Document was unloaded")), sb);
|
||||
() => reject(new JavaScriptError("Document was unloaded")),
|
||||
sb
|
||||
);
|
||||
sb.window.onunload = unloadHandler;
|
||||
|
||||
let promises = [
|
||||
|
@ -132,28 +140,33 @@ evaluate.sandbox = function(sb, script, args = [],
|
|||
// Wait for the immediate result of calling evalInSandbox, or a timeout.
|
||||
// Only resolve the promise if the scriptPromise was resolved and is not
|
||||
// async, because the latter has to call resolve() itself.
|
||||
Promise.race(promises).then(value => {
|
||||
if (!async) {
|
||||
resolve(value);
|
||||
Promise.race(promises).then(
|
||||
value => {
|
||||
if (!async) {
|
||||
resolve(value);
|
||||
}
|
||||
},
|
||||
err => {
|
||||
reject(err);
|
||||
}
|
||||
}, err => {
|
||||
reject(err);
|
||||
});
|
||||
);
|
||||
});
|
||||
|
||||
// This block is mainly for async scripts, which escape the inner promise
|
||||
// when calling resolve() on their own. The timeout promise will be re-used
|
||||
// to break out after the initially setup timeout.
|
||||
return Promise.race([promise, timeoutPromise]).catch(err => {
|
||||
// Only raise valid errors for both the sync and async scripts.
|
||||
if (err instanceof ScriptTimeoutError) {
|
||||
throw err;
|
||||
}
|
||||
throw new JavaScriptError(err);
|
||||
}).finally(() => {
|
||||
clearTimeout(scriptTimeoutID);
|
||||
sb.window.removeEventListener("unload", unloadHandler);
|
||||
});
|
||||
return Promise.race([promise, timeoutPromise])
|
||||
.catch(err => {
|
||||
// Only raise valid errors for both the sync and async scripts.
|
||||
if (err instanceof ScriptTimeoutError) {
|
||||
throw err;
|
||||
}
|
||||
throw new JavaScriptError(err);
|
||||
})
|
||||
.finally(() => {
|
||||
clearTimeout(scriptTimeoutID);
|
||||
sb.window.removeEventListener("unload", unloadHandler);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -192,11 +205,11 @@ evaluate.fromJSON = function(obj, seenEls = undefined, win = undefined) {
|
|||
if (obj === null) {
|
||||
return obj;
|
||||
|
||||
// arrays
|
||||
// arrays
|
||||
} else if (Array.isArray(obj)) {
|
||||
return obj.map(e => evaluate.fromJSON(e, seenEls, win));
|
||||
|
||||
// web elements
|
||||
// web elements
|
||||
} else if (WebElement.isReference(obj)) {
|
||||
let webEl = WebElement.fromJSON(obj);
|
||||
if (seenEls) {
|
||||
|
@ -255,26 +268,28 @@ evaluate.toJSON = function(obj, seenEls) {
|
|||
if (t == "[object Undefined]" || t == "[object Null]") {
|
||||
return null;
|
||||
|
||||
// primitives
|
||||
} else if (t == "[object Boolean]" ||
|
||||
t == "[object Number]" ||
|
||||
t == "[object String]") {
|
||||
// primitives
|
||||
} else if (
|
||||
t == "[object Boolean]" ||
|
||||
t == "[object Number]" ||
|
||||
t == "[object String]"
|
||||
) {
|
||||
return obj;
|
||||
|
||||
// Array, NodeList, HTMLCollection, et al.
|
||||
// Array, NodeList, HTMLCollection, et al.
|
||||
} else if (element.isCollection(obj)) {
|
||||
assert.acyclic(obj);
|
||||
return [...obj].map(el => evaluate.toJSON(el, seenEls));
|
||||
|
||||
// WebElement
|
||||
// WebElement
|
||||
} else if (WebElement.isReference(obj)) {
|
||||
return obj;
|
||||
|
||||
// Element (HTMLElement, SVGElement, XULElement, et al.)
|
||||
// Element (HTMLElement, SVGElement, XULElement, et al.)
|
||||
} else if (element.isElement(obj)) {
|
||||
return seenEls.add(obj);
|
||||
|
||||
// custom JSON representation
|
||||
// custom JSON representation
|
||||
} else if (typeof obj.toJSON == "function") {
|
||||
let unsafeJSON = obj.toJSON();
|
||||
return evaluate.toJSON(unsafeJSON, seenEls);
|
||||
|
@ -318,17 +333,19 @@ evaluate.isCyclic = function(value, stack = []) {
|
|||
if (t == "[object Undefined]" || t == "[object Null]") {
|
||||
return false;
|
||||
|
||||
// primitives
|
||||
} else if (t == "[object Boolean]" ||
|
||||
t == "[object Number]" ||
|
||||
t == "[object String]") {
|
||||
// primitives
|
||||
} else if (
|
||||
t == "[object Boolean]" ||
|
||||
t == "[object Number]" ||
|
||||
t == "[object String]"
|
||||
) {
|
||||
return false;
|
||||
|
||||
// HTMLElement, SVGElement, XULElement, et al.
|
||||
// HTMLElement, SVGElement, XULElement, et al.
|
||||
} else if (element.isElement(value)) {
|
||||
return false;
|
||||
|
||||
// Array, NodeList, HTMLCollection, et al.
|
||||
// Array, NodeList, HTMLCollection, et al.
|
||||
} else if (element.isCollection(value)) {
|
||||
if (stack.includes(value)) {
|
||||
return true;
|
||||
|
@ -397,7 +414,7 @@ this.sandbox = {};
|
|||
* functions and DOM elements.
|
||||
*/
|
||||
sandbox.cloneInto = function(obj, sb) {
|
||||
return Cu.cloneInto(obj, sb, {cloneFunctions: true, wrapReflectors: true});
|
||||
return Cu.cloneInto(obj, sb, { cloneFunctions: true, wrapReflectors: true });
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -442,13 +459,16 @@ sandbox.augment = function(sb, adapter) {
|
|||
*/
|
||||
sandbox.create = function(win, principal = null, opts = {}) {
|
||||
let p = principal || win;
|
||||
opts = Object.assign({
|
||||
sameZoneAs: win,
|
||||
sandboxPrototype: win,
|
||||
wantComponents: true,
|
||||
wantXrays: true,
|
||||
wantGlobalProperties: ["ChromeUtils"],
|
||||
}, opts);
|
||||
opts = Object.assign(
|
||||
{
|
||||
sameZoneAs: win,
|
||||
sandboxPrototype: win,
|
||||
wantComponents: true,
|
||||
wantXrays: true,
|
||||
wantGlobalProperties: ["ChromeUtils"],
|
||||
},
|
||||
opts
|
||||
);
|
||||
return new Cu.Sandbox(p, opts);
|
||||
};
|
||||
|
||||
|
@ -472,8 +492,9 @@ sandbox.createMutable = function(win) {
|
|||
};
|
||||
|
||||
sandbox.createSystemPrincipal = function(win) {
|
||||
let principal = Cc["@mozilla.org/systemprincipal;1"]
|
||||
.createInstance(Ci.nsIPrincipal);
|
||||
let principal = Cc["@mozilla.org/systemprincipal;1"].createInstance(
|
||||
Ci.nsIPrincipal
|
||||
);
|
||||
return sandbox.create(win, principal);
|
||||
};
|
||||
|
||||
|
|
|
@ -5,13 +5,15 @@
|
|||
/** Provides functionality for creating and sending DOM events. */
|
||||
this.event = {};
|
||||
|
||||
"use strict";
|
||||
("use strict");
|
||||
/* global content, is */
|
||||
/* eslint-disable no-restricted-globals */
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const {element} = ChromeUtils.import("chrome://marionette/content/element.js");
|
||||
const { element } = ChromeUtils.import(
|
||||
"chrome://marionette/content/element.js"
|
||||
);
|
||||
|
||||
const dblclickTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
|
||||
|
@ -67,8 +69,11 @@ event.DoubleClickTracker = {
|
|||
event.DoubleClickTracker.cancelTimer();
|
||||
},
|
||||
startTimer() {
|
||||
dblclickTimer.initWithCallback(event.DoubleClickTracker.resetClick,
|
||||
DBLCLICK_INTERVAL, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
dblclickTimer.initWithCallback(
|
||||
event.DoubleClickTracker.resetClick,
|
||||
DBLCLICK_INTERVAL,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT
|
||||
);
|
||||
},
|
||||
cancelTimer() {
|
||||
dblclickTimer.cancel();
|
||||
|
@ -127,7 +132,11 @@ event.parseModifiers_ = function(modifiers) {
|
|||
event.synthesizeMouse = function(element, offsetX, offsetY, opts, win) {
|
||||
let rect = element.getBoundingClientRect();
|
||||
event.synthesizeMouseAtPoint(
|
||||
rect.left + offsetX, rect.top + offsetY, opts, win);
|
||||
rect.left + offsetX,
|
||||
rect.top + offsetY,
|
||||
opts,
|
||||
win
|
||||
);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -153,11 +162,11 @@ event.synthesizeMouseAtPoint = function(left, top, opts, win) {
|
|||
let button = opts.button || 0;
|
||||
let clickCount = opts.clickCount || 1;
|
||||
let modifiers = event.parseModifiers_(opts);
|
||||
let pressure = ("pressure" in opts) ? opts.pressure : 0;
|
||||
let inputSource = ("inputSource" in opts) ? opts.inputSource :
|
||||
win.MouseEvent.MOZ_SOURCE_MOUSE;
|
||||
let pressure = "pressure" in opts ? opts.pressure : 0;
|
||||
let inputSource =
|
||||
"inputSource" in opts ? opts.inputSource : win.MouseEvent.MOZ_SOURCE_MOUSE;
|
||||
let isDOMEventSynthesized =
|
||||
("isSynthesized" in opts) ? opts.isSynthesized : true;
|
||||
"isSynthesized" in opts ? opts.isSynthesized : true;
|
||||
let isWidgetEventSynthesized;
|
||||
if ("isWidgetEventSynthesized" in opts) {
|
||||
isWidgetEventSynthesized = opts.isWidgetEventSynthesized;
|
||||
|
@ -171,47 +180,50 @@ event.synthesizeMouseAtPoint = function(left, top, opts, win) {
|
|||
buttons = domutils.MOUSE_BUTTONS_NOT_SPECIFIED;
|
||||
}
|
||||
|
||||
if (("type" in opts) && opts.type) {
|
||||
if ("type" in opts && opts.type) {
|
||||
domutils.sendMouseEvent(
|
||||
opts.type,
|
||||
left,
|
||||
top,
|
||||
button,
|
||||
clickCount,
|
||||
modifiers,
|
||||
false,
|
||||
pressure,
|
||||
inputSource,
|
||||
isDOMEventSynthesized,
|
||||
isWidgetEventSynthesized,
|
||||
buttons);
|
||||
opts.type,
|
||||
left,
|
||||
top,
|
||||
button,
|
||||
clickCount,
|
||||
modifiers,
|
||||
false,
|
||||
pressure,
|
||||
inputSource,
|
||||
isDOMEventSynthesized,
|
||||
isWidgetEventSynthesized,
|
||||
buttons
|
||||
);
|
||||
} else {
|
||||
domutils.sendMouseEvent(
|
||||
"mousedown",
|
||||
left,
|
||||
top,
|
||||
button,
|
||||
clickCount,
|
||||
modifiers,
|
||||
false,
|
||||
pressure,
|
||||
inputSource,
|
||||
isDOMEventSynthesized,
|
||||
isWidgetEventSynthesized,
|
||||
buttons);
|
||||
"mousedown",
|
||||
left,
|
||||
top,
|
||||
button,
|
||||
clickCount,
|
||||
modifiers,
|
||||
false,
|
||||
pressure,
|
||||
inputSource,
|
||||
isDOMEventSynthesized,
|
||||
isWidgetEventSynthesized,
|
||||
buttons
|
||||
);
|
||||
domutils.sendMouseEvent(
|
||||
"mouseup",
|
||||
left,
|
||||
top,
|
||||
button,
|
||||
clickCount,
|
||||
modifiers,
|
||||
false,
|
||||
pressure,
|
||||
inputSource,
|
||||
isDOMEventSynthesized,
|
||||
isWidgetEventSynthesized,
|
||||
buttons);
|
||||
"mouseup",
|
||||
left,
|
||||
top,
|
||||
button,
|
||||
clickCount,
|
||||
modifiers,
|
||||
false,
|
||||
pressure,
|
||||
inputSource,
|
||||
isDOMEventSynthesized,
|
||||
isWidgetEventSynthesized,
|
||||
buttons
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -340,7 +352,7 @@ event.isKeypressFiredKey = function(key, win) {
|
|||
throw new TypeError("Unknown key: " + key);
|
||||
}
|
||||
|
||||
// if key generates a character, it must cause a keypress event
|
||||
// if key generates a character, it must cause a keypress event
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
@ -422,8 +434,9 @@ function getTIP_(win, callback) {
|
|||
if (TIPMap.has(win)) {
|
||||
tip = TIPMap.get(win);
|
||||
} else {
|
||||
tip = Cc["@mozilla.org/text-input-processor;1"]
|
||||
.createInstance(Ci.nsITextInputProcessor);
|
||||
tip = Cc["@mozilla.org/text-input-processor;1"].createInstance(
|
||||
Ci.nsITextInputProcessor
|
||||
);
|
||||
TIPMap.set(win, tip);
|
||||
}
|
||||
if (!tip.beginInputTransactionForTests(win, callback)) {
|
||||
|
@ -443,19 +456,19 @@ function getKeyboardEvent_(win) {
|
|||
return KeyboardEvent;
|
||||
} catch (ex) {}
|
||||
}
|
||||
if (typeof content != "undefined" && ("KeyboardEvent" in content)) {
|
||||
if (typeof content != "undefined" && "KeyboardEvent" in content) {
|
||||
return content.KeyboardEvent;
|
||||
}
|
||||
return win.KeyboardEvent;
|
||||
}
|
||||
|
||||
function createKeyboardEventDictionary_(key, keyEvent, win) {
|
||||
let result = {dictionary: null, flags: 0};
|
||||
let keyCodeIsDefined = "keyCode" in keyEvent &&
|
||||
keyEvent.keyCode != undefined;
|
||||
let result = { dictionary: null, flags: 0 };
|
||||
let keyCodeIsDefined = "keyCode" in keyEvent && keyEvent.keyCode != undefined;
|
||||
let keyCode =
|
||||
(keyCodeIsDefined && keyEvent.keyCode >= 0 && keyEvent.keyCode <= 255) ?
|
||||
keyEvent.keyCode : 0;
|
||||
keyCodeIsDefined && keyEvent.keyCode >= 0 && keyEvent.keyCode <= 255
|
||||
? keyEvent.keyCode
|
||||
: 0;
|
||||
let keyName = "Unidentified";
|
||||
|
||||
let printable = false;
|
||||
|
@ -516,22 +529,25 @@ function emulateToActivateModifiers_(TIP, keyEvent, win) {
|
|||
|
||||
let modifiers = {
|
||||
normal: [
|
||||
{key: "Alt", attr: "altKey"},
|
||||
{key: "AltGraph", attr: "altGraphKey"},
|
||||
{key: "Control", attr: "ctrlKey"},
|
||||
{key: "Fn", attr: "fnKey"},
|
||||
{key: "Meta", attr: "metaKey"},
|
||||
{key: "OS", attr: "osKey"},
|
||||
{key: "Shift", attr: "shiftKey"},
|
||||
{key: "Symbol", attr: "symbolKey"},
|
||||
{key: Services.appinfo.OS === "Darwin" ? "Meta" : "Control", attr: "accelKey"},
|
||||
{ key: "Alt", attr: "altKey" },
|
||||
{ key: "AltGraph", attr: "altGraphKey" },
|
||||
{ key: "Control", attr: "ctrlKey" },
|
||||
{ key: "Fn", attr: "fnKey" },
|
||||
{ key: "Meta", attr: "metaKey" },
|
||||
{ key: "OS", attr: "osKey" },
|
||||
{ key: "Shift", attr: "shiftKey" },
|
||||
{ key: "Symbol", attr: "symbolKey" },
|
||||
{
|
||||
key: Services.appinfo.OS === "Darwin" ? "Meta" : "Control",
|
||||
attr: "accelKey",
|
||||
},
|
||||
],
|
||||
lockable: [
|
||||
{key: "CapsLock", attr: "capsLockKey"},
|
||||
{key: "FnLock", attr: "fnLockKey"},
|
||||
{key: "NumLock", attr: "numLockKey"},
|
||||
{key: "ScrollLock", attr: "scrollLockKey"},
|
||||
{key: "SymbolLock", attr: "symbolLockKey"},
|
||||
{ key: "CapsLock", attr: "capsLockKey" },
|
||||
{ key: "FnLock", attr: "fnLockKey" },
|
||||
{ key: "NumLock", attr: "numLockKey" },
|
||||
{ key: "ScrollLock", attr: "scrollLockKey" },
|
||||
{ key: "SymbolLock", attr: "symbolLockKey" },
|
||||
],
|
||||
};
|
||||
|
||||
|
@ -542,9 +558,11 @@ function emulateToActivateModifiers_(TIP, keyEvent, win) {
|
|||
if (TIP.getModifierState(modifiers.normal[i].key)) {
|
||||
continue; // already activated.
|
||||
}
|
||||
let event = new KeyboardEvent("", {key: modifiers.normal[i].key});
|
||||
TIP.keydown(event,
|
||||
TIP.KEY_NON_PRINTABLE_KEY | TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
|
||||
let event = new KeyboardEvent("", { key: modifiers.normal[i].key });
|
||||
TIP.keydown(
|
||||
event,
|
||||
TIP.KEY_NON_PRINTABLE_KEY | TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT
|
||||
);
|
||||
modifiers.normal[i].activated = true;
|
||||
}
|
||||
|
||||
|
@ -555,11 +573,15 @@ function emulateToActivateModifiers_(TIP, keyEvent, win) {
|
|||
if (TIP.getModifierState(modifiers.lockable[j].key)) {
|
||||
continue; // already activated.
|
||||
}
|
||||
let event = new KeyboardEvent("", {key: modifiers.lockable[j].key});
|
||||
TIP.keydown(event,
|
||||
TIP.KEY_NON_PRINTABLE_KEY | TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
|
||||
TIP.keyup(event,
|
||||
TIP.KEY_NON_PRINTABLE_KEY | TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
|
||||
let event = new KeyboardEvent("", { key: modifiers.lockable[j].key });
|
||||
TIP.keydown(
|
||||
event,
|
||||
TIP.KEY_NON_PRINTABLE_KEY | TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT
|
||||
);
|
||||
TIP.keyup(
|
||||
event,
|
||||
TIP.KEY_NON_PRINTABLE_KEY | TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT
|
||||
);
|
||||
modifiers.lockable[j].activated = true;
|
||||
}
|
||||
|
||||
|
@ -575,9 +597,11 @@ function emulateToInactivateModifiers_(TIP, modifiers, win) {
|
|||
if (!modifiers.normal[i].activated) {
|
||||
continue;
|
||||
}
|
||||
let event = new KeyboardEvent("", {key: modifiers.normal[i].key});
|
||||
TIP.keyup(event,
|
||||
TIP.KEY_NON_PRINTABLE_KEY | TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
|
||||
let event = new KeyboardEvent("", { key: modifiers.normal[i].key });
|
||||
TIP.keyup(
|
||||
event,
|
||||
TIP.KEY_NON_PRINTABLE_KEY | TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT
|
||||
);
|
||||
}
|
||||
for (let j = 0; j < modifiers.lockable.length; j++) {
|
||||
if (!modifiers.lockable[j].activated) {
|
||||
|
@ -586,11 +610,15 @@ function emulateToInactivateModifiers_(TIP, modifiers, win) {
|
|||
if (!TIP.getModifierState(modifiers.lockable[j].key)) {
|
||||
continue; // who already inactivated this?
|
||||
}
|
||||
let event = new KeyboardEvent("", {key: modifiers.lockable[j].key});
|
||||
TIP.keydown(event,
|
||||
TIP.KEY_NON_PRINTABLE_KEY | TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
|
||||
TIP.keyup(event,
|
||||
TIP.KEY_NON_PRINTABLE_KEY | TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT);
|
||||
let event = new KeyboardEvent("", { key: modifiers.lockable[j].key });
|
||||
TIP.keydown(
|
||||
event,
|
||||
TIP.KEY_NON_PRINTABLE_KEY | TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT
|
||||
);
|
||||
TIP.keyup(
|
||||
event,
|
||||
TIP.KEY_NON_PRINTABLE_KEY | TIP.KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -778,9 +806,13 @@ function expectEvent_(expectedTarget, expectedEvent, testName) {
|
|||
* be removed.
|
||||
*/
|
||||
function checkExpectedEvent_(
|
||||
expectedTarget, expectedEvent, eventHandler, testName) {
|
||||
expectedTarget,
|
||||
expectedEvent,
|
||||
eventHandler,
|
||||
testName
|
||||
) {
|
||||
if (eventHandler) {
|
||||
let expectEvent = (expectedEvent.charAt(0) != "!");
|
||||
let expectEvent = expectedEvent.charAt(0) != "!";
|
||||
let type = expectEvent;
|
||||
if (!type) {
|
||||
type = expectedEvent.substring(1);
|
||||
|
@ -824,25 +856,25 @@ function checkExpectedEvent_(
|
|||
* Window object.
|
||||
*/
|
||||
event.synthesizeMouseExpectEvent = function(
|
||||
target, offsetX, offsetY, ev, expectedTarget, expectedEvent,
|
||||
testName, win) {
|
||||
let eventHandler = expectEvent_(
|
||||
expectedTarget,
|
||||
expectedEvent,
|
||||
testName);
|
||||
target,
|
||||
offsetX,
|
||||
offsetY,
|
||||
ev,
|
||||
expectedTarget,
|
||||
expectedEvent,
|
||||
testName,
|
||||
win
|
||||
) {
|
||||
let eventHandler = expectEvent_(expectedTarget, expectedEvent, testName);
|
||||
event.synthesizeMouse(target, offsetX, offsetY, ev, win);
|
||||
checkExpectedEvent_(
|
||||
expectedTarget,
|
||||
expectedEvent,
|
||||
eventHandler,
|
||||
testName);
|
||||
checkExpectedEvent_(expectedTarget, expectedEvent, eventHandler, testName);
|
||||
};
|
||||
|
||||
const MODIFIER_KEYCODES_LOOKUP = {
|
||||
"VK_SHIFT": "shiftKey",
|
||||
"VK_CONTROL": "ctrlKey",
|
||||
"VK_ALT": "altKey",
|
||||
"VK_META": "metaKey",
|
||||
VK_SHIFT: "shiftKey",
|
||||
VK_CONTROL: "ctrlKey",
|
||||
VK_ALT: "altKey",
|
||||
VK_META: "metaKey",
|
||||
};
|
||||
|
||||
const VIRTUAL_KEYCODE_LOOKUP = {
|
||||
|
@ -858,7 +890,7 @@ const VIRTUAL_KEYCODE_LOOKUP = {
|
|||
"\uE00A": "VK_ALT",
|
||||
"\uE00B": "VK_PAUSE",
|
||||
"\uE00C": "VK_ESCAPE",
|
||||
"\uE00D": "VK_SPACE", // printable
|
||||
"\uE00D": "VK_SPACE", // printable
|
||||
"\uE00E": "VK_PAGE_UP",
|
||||
"\uE00F": "VK_PAGE_DOWN",
|
||||
"\uE010": "VK_END",
|
||||
|
@ -996,7 +1028,7 @@ function isPrintable(c, win) {
|
|||
KeyboardEvent.DOM_VK_PLAY,
|
||||
KeyboardEvent.DOM_VK_RETURN,
|
||||
];
|
||||
return !(NON_PRINT_KEYS.includes(c));
|
||||
return !NON_PRINT_KEYS.includes(c);
|
||||
}
|
||||
|
||||
event.sendKeyDown = function(keyToSend, modifiers, win) {
|
||||
|
|
|
@ -4,10 +4,15 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const {Log} = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
const {MarionettePrefs} = ChromeUtils.import("chrome://marionette/content/prefs.js", null);
|
||||
const { Log } = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
const { MarionettePrefs } = ChromeUtils.import(
|
||||
"chrome://marionette/content/prefs.js",
|
||||
null
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "log", Log.get);
|
||||
|
||||
|
@ -36,8 +41,12 @@ const MAX_STRING_LENGTH = 250;
|
|||
function pprint(ss, ...values) {
|
||||
function pretty(val) {
|
||||
let proto = Object.prototype.toString.call(val);
|
||||
if (typeof val == "object" && val !== null &&
|
||||
"nodeType" in val && val.nodeType === ELEMENT_NODE) {
|
||||
if (
|
||||
typeof val == "object" &&
|
||||
val !== null &&
|
||||
"nodeType" in val &&
|
||||
val.nodeType === ELEMENT_NODE
|
||||
) {
|
||||
return prettyElement(val);
|
||||
} else if (["[object Window]", "[object ChromeWindow]"].includes(proto)) {
|
||||
return prettyWindowGlobal(val);
|
||||
|
@ -138,8 +147,8 @@ function truncate(strings, ...values) {
|
|||
case "[object String]":
|
||||
if (MarionettePrefs.truncateLog) {
|
||||
if (obj.length > MAX_STRING_LENGTH) {
|
||||
let s1 = obj.substring(0, (MAX_STRING_LENGTH / 2));
|
||||
let s2 = obj.substring(obj.length - (MAX_STRING_LENGTH / 2));
|
||||
let s1 = obj.substring(0, MAX_STRING_LENGTH / 2);
|
||||
let s2 = obj.substring(obj.length - MAX_STRING_LENGTH / 2);
|
||||
return `${s1} ... ${s2}`;
|
||||
}
|
||||
}
|
||||
|
@ -150,8 +159,10 @@ function truncate(strings, ...values) {
|
|||
|
||||
// arbitrary object
|
||||
default:
|
||||
if (Object.getOwnPropertyNames(obj).includes("toString") &&
|
||||
typeof obj.toString == "function") {
|
||||
if (
|
||||
Object.getOwnPropertyNames(obj).includes("toString") &&
|
||||
typeof obj.toString == "function"
|
||||
) {
|
||||
return walk(obj.toString());
|
||||
}
|
||||
|
||||
|
|
|
@ -5,21 +5,31 @@
|
|||
"use strict";
|
||||
/* eslint-disable no-restricted-globals */
|
||||
|
||||
const {Preferences} = ChromeUtils.import("resource://gre/modules/Preferences.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { Preferences } = ChromeUtils.import(
|
||||
"resource://gre/modules/Preferences.jsm"
|
||||
);
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const {accessibility} = ChromeUtils.import("chrome://marionette/content/accessibility.js");
|
||||
const {atom} = ChromeUtils.import("chrome://marionette/content/atom.js");
|
||||
const {element} = ChromeUtils.import("chrome://marionette/content/element.js");
|
||||
const { accessibility } = ChromeUtils.import(
|
||||
"chrome://marionette/content/accessibility.js"
|
||||
);
|
||||
const { atom } = ChromeUtils.import("chrome://marionette/content/atom.js");
|
||||
const { element } = ChromeUtils.import(
|
||||
"chrome://marionette/content/element.js"
|
||||
);
|
||||
const {
|
||||
ElementClickInterceptedError,
|
||||
ElementNotInteractableError,
|
||||
InvalidArgumentError,
|
||||
InvalidElementStateError,
|
||||
} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const {event} = ChromeUtils.import("chrome://marionette/content/event.js");
|
||||
const {pprint} = ChromeUtils.import("chrome://marionette/content/format.js");
|
||||
const {TimedPromise} = ChromeUtils.import("chrome://marionette/content/sync.js");
|
||||
const { event } = ChromeUtils.import("chrome://marionette/content/event.js");
|
||||
const { pprint } = ChromeUtils.import("chrome://marionette/content/format.js");
|
||||
const { TimedPromise } = ChromeUtils.import(
|
||||
"chrome://marionette/content/sync.js"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["File"]);
|
||||
|
||||
|
@ -62,11 +72,7 @@ const DISABLED_ATTRIBUTE_SUPPORTED_XUL = new Set([
|
|||
* Common form controls that user can change the value property
|
||||
* interactively.
|
||||
*/
|
||||
const COMMON_FORM_CONTROLS = new Set([
|
||||
"input",
|
||||
"textarea",
|
||||
"select",
|
||||
]);
|
||||
const COMMON_FORM_CONTROLS = new Set(["input", "textarea", "select"]);
|
||||
|
||||
/**
|
||||
* Input elements that do not fire <tt>input</tt> and <tt>change</tt>
|
||||
|
@ -123,7 +129,10 @@ this.interaction = {};
|
|||
* If <var>el</var> is not enabled.
|
||||
*/
|
||||
interaction.clickElement = async function(
|
||||
el, strict = false, specCompat = false) {
|
||||
el,
|
||||
strict = false,
|
||||
specCompat = false
|
||||
) {
|
||||
const a11y = accessibility.get(strict);
|
||||
if (element.isXULElement(el)) {
|
||||
await chromeClick(el, a11y);
|
||||
|
@ -139,8 +148,7 @@ async function webdriverClickElement(el, a11y) {
|
|||
|
||||
// step 3
|
||||
if (el.localName == "input" && el.type == "file") {
|
||||
throw new InvalidArgumentError(
|
||||
"Cannot click <input type=file> elements");
|
||||
throw new InvalidArgumentError("Cannot click <input type=file> elements");
|
||||
}
|
||||
|
||||
let containerEl = element.getContainer(el);
|
||||
|
@ -158,7 +166,8 @@ async function webdriverClickElement(el, a11y) {
|
|||
// there is no point in checking if it is pointer-interactable
|
||||
if (!element.isInView(containerEl)) {
|
||||
throw new ElementNotInteractableError(
|
||||
pprint`Element ${el} could not be scrolled into view`);
|
||||
pprint`Element ${el} could not be scrolled into view`
|
||||
);
|
||||
}
|
||||
|
||||
// step 7
|
||||
|
@ -209,7 +218,7 @@ async function chromeClick(el, a11y) {
|
|||
async function seleniumClickElement(el, a11y) {
|
||||
let win = getWindow(el);
|
||||
|
||||
let visibilityCheckEl = el;
|
||||
let visibilityCheckEl = el;
|
||||
if (el.localName == "option") {
|
||||
visibilityCheckEl = element.getContainer(el);
|
||||
}
|
||||
|
@ -319,7 +328,8 @@ interaction.clearElement = function(el) {
|
|||
}
|
||||
if (!element.isEditable(el)) {
|
||||
throw new InvalidElementStateError(
|
||||
pprint`Unable to clear element that cannot be edited: ${el}`);
|
||||
pprint`Unable to clear element that cannot be edited: ${el}`
|
||||
);
|
||||
}
|
||||
|
||||
if (!element.isInView(el)) {
|
||||
|
@ -327,7 +337,8 @@ interaction.clearElement = function(el) {
|
|||
}
|
||||
if (!element.isInView(el)) {
|
||||
throw new ElementNotInteractableError(
|
||||
pprint`Element ${el} could not be scrolled into view`);
|
||||
pprint`Element ${el} could not be scrolled into view`
|
||||
);
|
||||
}
|
||||
|
||||
if (element.isEditingHost(el)) {
|
||||
|
@ -349,7 +360,9 @@ function clearContentEditableElement(el) {
|
|||
|
||||
function clearResettableElement(el) {
|
||||
if (!element.isMutableFormControl(el)) {
|
||||
throw new InvalidElementStateError(pprint`Not an editable form control: ${el}`);
|
||||
throw new InvalidElementStateError(
|
||||
pprint`Not an editable form control: ${el}`
|
||||
);
|
||||
}
|
||||
|
||||
let isEmpty;
|
||||
|
@ -400,8 +413,8 @@ interaction.flushEventLoop = async function(el) {
|
|||
}
|
||||
};
|
||||
|
||||
win.addEventListener("unload", unloadEv, {mozSystemGroup: true});
|
||||
el.addEventListener("click", clickEv, {mozSystemGroup: true});
|
||||
win.addEventListener("unload", unloadEv, { mozSystemGroup: true });
|
||||
el.addEventListener("click", clickEv, { mozSystemGroup: true });
|
||||
};
|
||||
let removeListeners = () => {
|
||||
// only one event fires
|
||||
|
@ -409,8 +422,9 @@ interaction.flushEventLoop = async function(el) {
|
|||
el.removeEventListener("click", clickEv);
|
||||
};
|
||||
|
||||
return new TimedPromise(spinEventLoop, {timeout: 500, throws: null})
|
||||
.then(removeListeners);
|
||||
return new TimedPromise(spinEventLoop, { timeout: 500, throws: null }).then(
|
||||
removeListeners
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -489,7 +503,8 @@ interaction.uploadFiles = async function(el, paths) {
|
|||
files = Array.prototype.slice.call(el.files);
|
||||
} else if (paths.length > 1) {
|
||||
throw new InvalidArgumentError(
|
||||
pprint`Element ${el} doesn't accept multiple files`);
|
||||
pprint`Element ${el} doesn't accept multiple files`
|
||||
);
|
||||
}
|
||||
|
||||
for (let path of paths) {
|
||||
|
@ -547,24 +562,35 @@ interaction.setFormControlValue = function(el, value) {
|
|||
* @param {boolean=} webdriverClick
|
||||
* Use WebDriver specification compatible interactability definition.
|
||||
*/
|
||||
interaction.sendKeysToElement = async function(el, value,
|
||||
{
|
||||
strictFileInteractability = false,
|
||||
accessibilityChecks = false,
|
||||
webdriverClick = false,
|
||||
} = {}) {
|
||||
interaction.sendKeysToElement = async function(
|
||||
el,
|
||||
value,
|
||||
{
|
||||
strictFileInteractability = false,
|
||||
accessibilityChecks = false,
|
||||
webdriverClick = false,
|
||||
} = {}
|
||||
) {
|
||||
const a11y = accessibility.get(accessibilityChecks);
|
||||
|
||||
if (webdriverClick) {
|
||||
await webdriverSendKeysToElement(
|
||||
el, value, a11y, strictFileInteractability);
|
||||
el,
|
||||
value,
|
||||
a11y,
|
||||
strictFileInteractability
|
||||
);
|
||||
} else {
|
||||
await legacySendKeysToElement(el, value, a11y);
|
||||
}
|
||||
};
|
||||
|
||||
async function webdriverSendKeysToElement(el, value,
|
||||
a11y, strictFileInteractability) {
|
||||
async function webdriverSendKeysToElement(
|
||||
el,
|
||||
value,
|
||||
a11y,
|
||||
strictFileInteractability
|
||||
) {
|
||||
const win = getWindow(el);
|
||||
|
||||
if (el.type != "file" || strictFileInteractability) {
|
||||
|
@ -573,7 +599,8 @@ async function webdriverSendKeysToElement(el, value,
|
|||
// TODO: Wait for element to be keyboard-interactible
|
||||
if (!interaction.isKeyboardInteractable(containerEl)) {
|
||||
throw new ElementNotInteractableError(
|
||||
pprint`Element ${el} is not reachable by keyboard`);
|
||||
pprint`Element ${el} is not reachable by keyboard`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -589,8 +616,10 @@ async function webdriverSendKeysToElement(el, value,
|
|||
|
||||
event.input(el);
|
||||
event.change(el);
|
||||
} else if ((el.type == "date" || el.type == "time") &&
|
||||
Preferences.get("dom.forms.datetime")) {
|
||||
} else if (
|
||||
(el.type == "date" || el.type == "time") &&
|
||||
Preferences.get("dom.forms.datetime")
|
||||
) {
|
||||
interaction.setFormControlValue(el, value);
|
||||
} else {
|
||||
event.sendKeysToElement(value, el, win);
|
||||
|
@ -606,11 +635,13 @@ async function legacySendKeysToElement(el, value, a11y) {
|
|||
|
||||
event.input(el);
|
||||
event.change(el);
|
||||
} else if ((el.type == "date" || el.type == "time") &&
|
||||
Preferences.get("dom.forms.datetime")) {
|
||||
} else if (
|
||||
(el.type == "date" || el.type == "time") &&
|
||||
Preferences.get("dom.forms.datetime")
|
||||
) {
|
||||
interaction.setFormControlValue(el, value);
|
||||
} else {
|
||||
let visibilityCheckEl = el;
|
||||
let visibilityCheckEl = el;
|
||||
if (el.localName == "option") {
|
||||
visibilityCheckEl = element.getContainer(el);
|
||||
}
|
||||
|
@ -666,14 +697,19 @@ interaction.isElementEnabled = function(el, strict = false) {
|
|||
if (element.isXULElement(el)) {
|
||||
// check if XUL element supports disabled attribute
|
||||
if (DISABLED_ATTRIBUTE_SUPPORTED_XUL.has(el.tagName.toUpperCase())) {
|
||||
if (el.hasAttribute("disabled") && el.getAttribute("disabled") === "true") {
|
||||
if (
|
||||
el.hasAttribute("disabled") &&
|
||||
el.getAttribute("disabled") === "true"
|
||||
) {
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
} else if (["application/xml", "text/xml"].includes(win.document.contentType)) {
|
||||
} else if (
|
||||
["application/xml", "text/xml"].includes(win.document.contentType)
|
||||
) {
|
||||
enabled = false;
|
||||
} else {
|
||||
enabled = atom.isElementEnabled(el, {frame: win});
|
||||
enabled = atom.isElementEnabled(el, { frame: win });
|
||||
}
|
||||
|
||||
let a11y = accessibility.get(strict);
|
||||
|
|
|
@ -15,14 +15,17 @@
|
|||
* content retrieved.
|
||||
*/
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["DOMParser"]);
|
||||
XPCOMUtils.defineLazyGetter(this, "domParser", () => new DOMParser());
|
||||
|
||||
const {NoSuchElementError} =
|
||||
ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const { NoSuchElementError } = ChromeUtils.import(
|
||||
"chrome://marionette/content/error.js"
|
||||
);
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["l10n"];
|
||||
|
||||
|
@ -91,8 +94,7 @@ l10n.localizeProperty = function(urls, id) {
|
|||
}
|
||||
|
||||
if (property === null) {
|
||||
throw new NoSuchElementError(
|
||||
`Property with ID '${id}' hasn't been found`);
|
||||
throw new NoSuchElementError(`Property with ID '${id}' hasn't been found`);
|
||||
}
|
||||
|
||||
return property;
|
||||
|
|
|
@ -10,21 +10,25 @@
|
|||
|
||||
const winUtil = content.windowUtils;
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const {accessibility} = ChromeUtils.import("chrome://marionette/content/accessibility.js");
|
||||
const {action} = ChromeUtils.import("chrome://marionette/content/action.js");
|
||||
const {atom} = ChromeUtils.import("chrome://marionette/content/atom.js");
|
||||
const {
|
||||
Capabilities,
|
||||
PageLoadStrategy,
|
||||
} = ChromeUtils.import("chrome://marionette/content/capabilities.js");
|
||||
const {capture} = ChromeUtils.import("chrome://marionette/content/capture.js");
|
||||
const {
|
||||
element,
|
||||
WebElement,
|
||||
} = ChromeUtils.import("chrome://marionette/content/element.js");
|
||||
const { accessibility } = ChromeUtils.import(
|
||||
"chrome://marionette/content/accessibility.js"
|
||||
);
|
||||
const { action } = ChromeUtils.import("chrome://marionette/content/action.js");
|
||||
const { atom } = ChromeUtils.import("chrome://marionette/content/atom.js");
|
||||
const { Capabilities, PageLoadStrategy } = ChromeUtils.import(
|
||||
"chrome://marionette/content/capabilities.js"
|
||||
);
|
||||
const { capture } = ChromeUtils.import(
|
||||
"chrome://marionette/content/capture.js"
|
||||
);
|
||||
const { element, WebElement } = ChromeUtils.import(
|
||||
"chrome://marionette/content/element.js"
|
||||
);
|
||||
const {
|
||||
ElementNotInteractableError,
|
||||
InsecureCertificateError,
|
||||
|
@ -35,21 +39,35 @@ const {
|
|||
TimeoutError,
|
||||
UnknownError,
|
||||
} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const {Sandboxes, evaluate, sandbox} = ChromeUtils.import("chrome://marionette/content/evaluate.js");
|
||||
const {event} = ChromeUtils.import("chrome://marionette/content/event.js");
|
||||
const {ContentEventObserverService} = ChromeUtils.import("chrome://marionette/content/dom.js");
|
||||
const {pprint, truncate} = ChromeUtils.import("chrome://marionette/content/format.js");
|
||||
const {interaction} = ChromeUtils.import("chrome://marionette/content/interaction.js");
|
||||
const {legacyaction} = ChromeUtils.import("chrome://marionette/content/legacyaction.js");
|
||||
const {Log} = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
const {navigate} = ChromeUtils.import("chrome://marionette/content/navigate.js");
|
||||
const {proxy} = ChromeUtils.import("chrome://marionette/content/proxy.js");
|
||||
const { Sandboxes, evaluate, sandbox } = ChromeUtils.import(
|
||||
"chrome://marionette/content/evaluate.js"
|
||||
);
|
||||
const { event } = ChromeUtils.import("chrome://marionette/content/event.js");
|
||||
const { ContentEventObserverService } = ChromeUtils.import(
|
||||
"chrome://marionette/content/dom.js"
|
||||
);
|
||||
const { pprint, truncate } = ChromeUtils.import(
|
||||
"chrome://marionette/content/format.js"
|
||||
);
|
||||
const { interaction } = ChromeUtils.import(
|
||||
"chrome://marionette/content/interaction.js"
|
||||
);
|
||||
const { legacyaction } = ChromeUtils.import(
|
||||
"chrome://marionette/content/legacyaction.js"
|
||||
);
|
||||
const { Log } = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
const { navigate } = ChromeUtils.import(
|
||||
"chrome://marionette/content/navigate.js"
|
||||
);
|
||||
const { proxy } = ChromeUtils.import("chrome://marionette/content/proxy.js");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", () => Log.getWithPrefix(outerWindowID));
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", () =>
|
||||
Log.getWithPrefix(outerWindowID)
|
||||
);
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
|
||||
|
||||
let {outerWindowID} = winUtil;
|
||||
let curContainer = {frame: content, shadowRoot: null};
|
||||
let { outerWindowID } = winUtil;
|
||||
let curContainer = { frame: content, shadowRoot: null };
|
||||
|
||||
// Listen for click event to indicate one click has happened, so actions
|
||||
// code can send dblclick event
|
||||
|
@ -86,7 +104,9 @@ let multiLast = {};
|
|||
const sandboxes = new Sandboxes(() => curContainer.frame);
|
||||
|
||||
const eventObservers = new ContentEventObserverService(
|
||||
content, sendAsyncMessage.bind(this));
|
||||
content,
|
||||
sendAsyncMessage.bind(this)
|
||||
);
|
||||
|
||||
/**
|
||||
* The load listener singleton helps to keep track of active page load
|
||||
|
@ -124,8 +144,7 @@ const loadListener = {
|
|||
this.seenBeforeUnload = false;
|
||||
this.seenUnload = false;
|
||||
|
||||
this.timerPageLoad = Cc["@mozilla.org/timer;1"]
|
||||
.createInstance(Ci.nsITimer);
|
||||
this.timerPageLoad = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
this.timerPageUnload = null;
|
||||
|
||||
// In case the frame script has been moved to a differnt process,
|
||||
|
@ -165,7 +184,10 @@ const loadListener = {
|
|||
}
|
||||
|
||||
this.timerPageLoad.initWithCallback(
|
||||
this, timeout, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
this,
|
||||
timeout,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -202,8 +224,10 @@ const loadListener = {
|
|||
handleEvent(event) {
|
||||
// Only care about events from the currently selected browsing context,
|
||||
// whereby some of those do not bubble up to the window.
|
||||
if (event.target != curContainer.frame &&
|
||||
event.target != curContainer.frame.document) {
|
||||
if (
|
||||
event.target != curContainer.frame &&
|
||||
event.target != curContainer.frame.document
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -239,8 +263,10 @@ const loadListener = {
|
|||
|
||||
case "DOMContentLoaded":
|
||||
case "pageshow":
|
||||
this.handleReadyState(event.target.readyState,
|
||||
event.target.documentURI);
|
||||
this.handleReadyState(
|
||||
event.target.readyState,
|
||||
event.target.documentURI
|
||||
);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
@ -270,19 +296,23 @@ const loadListener = {
|
|||
finished = true;
|
||||
} else if (/about:.*(error)\?/.exec(documentURI)) {
|
||||
this.stop();
|
||||
sendError(new UnknownError(`Reached error page: ${documentURI}`),
|
||||
this.commandID);
|
||||
sendError(
|
||||
new UnknownError(`Reached error page: ${documentURI}`),
|
||||
this.commandID
|
||||
);
|
||||
finished = true;
|
||||
|
||||
// Return early with a page load strategy of eager, and also
|
||||
// special-case about:blocked pages which should be treated as
|
||||
// non-error pages but do not raise a pageshow event. about:blank
|
||||
// is also treaded specifically here, because it gets temporary
|
||||
// loaded for new content processes, and we only want to rely on
|
||||
// complete loads for it.
|
||||
} else if ((capabilities.get("pageLoadStrategy") === PageLoadStrategy.Eager &&
|
||||
// Return early with a page load strategy of eager, and also
|
||||
// special-case about:blocked pages which should be treated as
|
||||
// non-error pages but do not raise a pageshow event. about:blank
|
||||
// is also treaded specifically here, because it gets temporary
|
||||
// loaded for new content processes, and we only want to rely on
|
||||
// complete loads for it.
|
||||
} else if (
|
||||
(capabilities.get("pageLoadStrategy") === PageLoadStrategy.Eager &&
|
||||
documentURI != "about:blank") ||
|
||||
/about:blocked\?/.exec(documentURI)) {
|
||||
/about:blocked\?/.exec(documentURI)
|
||||
) {
|
||||
this.stop();
|
||||
sendOk(this.commandID);
|
||||
finished = true;
|
||||
|
@ -318,13 +348,18 @@ const loadListener = {
|
|||
if (this.seenBeforeUnload) {
|
||||
this.seenBeforeUnload = null;
|
||||
this.timerPageUnload.initWithCallback(
|
||||
this, 5000, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
this,
|
||||
5000,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT
|
||||
);
|
||||
|
||||
// If no page unload has been detected, ensure to properly stop
|
||||
// the load listener, and return from the currently active command.
|
||||
// If no page unload has been detected, ensure to properly stop
|
||||
// the load listener, and return from the currently active command.
|
||||
} else if (!this.seenUnload) {
|
||||
logger.debug("Canceled page load listener because no navigation " +
|
||||
"has been detected");
|
||||
logger.debug(
|
||||
"Canceled page load listener because no navigation " +
|
||||
"has been detected"
|
||||
);
|
||||
this.stop();
|
||||
sendOk(this.commandID);
|
||||
}
|
||||
|
@ -333,8 +368,9 @@ const loadListener = {
|
|||
case this.timerPageLoad:
|
||||
this.stop();
|
||||
sendError(
|
||||
new TimeoutError(`Timeout loading page after ${this.timeout}ms`),
|
||||
this.commandID);
|
||||
new TimeoutError(`Timeout loading page after ${this.timeout}ms`),
|
||||
this.commandID
|
||||
);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
@ -392,11 +428,17 @@ const loadListener = {
|
|||
* @param {string=} url
|
||||
* Optional URL, which is used to check if a page load is expected.
|
||||
*/
|
||||
navigate(trigger, commandID, timeout, loadEventExpected = true,
|
||||
useUnloadTimer = false) {
|
||||
navigate(
|
||||
trigger,
|
||||
commandID,
|
||||
timeout,
|
||||
loadEventExpected = true,
|
||||
useUnloadTimer = false
|
||||
) {
|
||||
// Only wait if the page load strategy is not `none`
|
||||
loadEventExpected = loadEventExpected &&
|
||||
(capabilities.get("pageLoadStrategy") !== PageLoadStrategy.None);
|
||||
loadEventExpected =
|
||||
loadEventExpected &&
|
||||
capabilities.get("pageLoadStrategy") !== PageLoadStrategy.None;
|
||||
|
||||
if (loadEventExpected) {
|
||||
let startTime = new Date().getTime();
|
||||
|
@ -405,26 +447,32 @@ const loadListener = {
|
|||
|
||||
return (async () => {
|
||||
await trigger();
|
||||
})().then(() => {
|
||||
if (!loadEventExpected) {
|
||||
sendOk(commandID);
|
||||
return;
|
||||
}
|
||||
})()
|
||||
.then(() => {
|
||||
if (!loadEventExpected) {
|
||||
sendOk(commandID);
|
||||
return;
|
||||
}
|
||||
|
||||
// If requested setup a timer to detect a possible page load
|
||||
if (useUnloadTimer) {
|
||||
this.timerPageUnload = Cc["@mozilla.org/timer;1"]
|
||||
.createInstance(Ci.nsITimer);
|
||||
this.timerPageUnload.initWithCallback(
|
||||
this, 200, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
}).catch(err => {
|
||||
if (loadEventExpected) {
|
||||
this.stop();
|
||||
}
|
||||
// If requested setup a timer to detect a possible page load
|
||||
if (useUnloadTimer) {
|
||||
this.timerPageUnload = Cc["@mozilla.org/timer;1"].createInstance(
|
||||
Ci.nsITimer
|
||||
);
|
||||
this.timerPageUnload.initWithCallback(
|
||||
this,
|
||||
200,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
if (loadEventExpected) {
|
||||
this.stop();
|
||||
}
|
||||
|
||||
sendError(err, commandID);
|
||||
});
|
||||
sendError(err, commandID);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -445,7 +493,7 @@ function registerSelf() {
|
|||
action.inputStateMap = new Map();
|
||||
action.inputsToCancel = [];
|
||||
|
||||
let reply = sendSyncMessage("Marionette:Register", {outerWindowID});
|
||||
let reply = sendSyncMessage("Marionette:Register", { outerWindowID });
|
||||
if (reply.length == 0) {
|
||||
logger.error("No reply from Marionette:Register");
|
||||
return;
|
||||
|
@ -454,7 +502,7 @@ function registerSelf() {
|
|||
if (reply[0].outerWindowID === outerWindowID) {
|
||||
logger.trace("Frame script registered");
|
||||
startListeners();
|
||||
sendAsyncMessage("Marionette:ListenersAttached", {outerWindowID});
|
||||
sendAsyncMessage("Marionette:ListenersAttached", { outerWindowID });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -484,8 +532,9 @@ function dispatch(fn) {
|
|||
resolve(rv);
|
||||
});
|
||||
|
||||
req.then(rv => sendResponse(rv, id), err => sendError(err, id))
|
||||
.catch(err => sendError(err, id));
|
||||
req
|
||||
.then(rv => sendResponse(rv, id), err => sendError(err, id))
|
||||
.catch(err => sendError(err, id));
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -522,7 +571,10 @@ function startListeners() {
|
|||
addMessageListener("Marionette:clickElement", clickElement);
|
||||
addMessageListener("Marionette:Deregister", deregister);
|
||||
addMessageListener("Marionette:DOM:AddEventListener", domAddEventListener);
|
||||
addMessageListener("Marionette:DOM:RemoveEventListener", domRemoveEventListener);
|
||||
addMessageListener(
|
||||
"Marionette:DOM:RemoveEventListener",
|
||||
domRemoveEventListener
|
||||
);
|
||||
addMessageListener("Marionette:execute", executeFn);
|
||||
addMessageListener("Marionette:executeInSandbox", executeInSandboxFn);
|
||||
addMessageListener("Marionette:findElementContent", findElementContentFn);
|
||||
|
@ -533,7 +585,10 @@ function startListeners() {
|
|||
addMessageListener("Marionette:getElementRect", getElementRectFn);
|
||||
addMessageListener("Marionette:getElementTagName", getElementTagNameFn);
|
||||
addMessageListener("Marionette:getElementText", getElementTextFn);
|
||||
addMessageListener("Marionette:getElementValueOfCssProperty", getElementValueOfCssPropertyFn);
|
||||
addMessageListener(
|
||||
"Marionette:getElementValueOfCssProperty",
|
||||
getElementValueOfCssPropertyFn
|
||||
);
|
||||
addMessageListener("Marionette:get", get);
|
||||
addMessageListener("Marionette:getPageSource", getPageSourceFn);
|
||||
addMessageListener("Marionette:goBack", goBack);
|
||||
|
@ -565,14 +620,23 @@ function deregister() {
|
|||
removeMessageListener("Marionette:execute", executeFn);
|
||||
removeMessageListener("Marionette:executeInSandbox", executeInSandboxFn);
|
||||
removeMessageListener("Marionette:findElementContent", findElementContentFn);
|
||||
removeMessageListener("Marionette:findElementsContent", findElementsContentFn);
|
||||
removeMessageListener(
|
||||
"Marionette:findElementsContent",
|
||||
findElementsContentFn
|
||||
);
|
||||
removeMessageListener("Marionette:getActiveElement", getActiveElementFn);
|
||||
removeMessageListener("Marionette:getElementAttribute", getElementAttributeFn);
|
||||
removeMessageListener(
|
||||
"Marionette:getElementAttribute",
|
||||
getElementAttributeFn
|
||||
);
|
||||
removeMessageListener("Marionette:getElementProperty", getElementPropertyFn);
|
||||
removeMessageListener("Marionette:getElementRect", getElementRectFn);
|
||||
removeMessageListener("Marionette:getElementTagName", getElementTagNameFn);
|
||||
removeMessageListener("Marionette:getElementText", getElementTextFn);
|
||||
removeMessageListener("Marionette:getElementValueOfCssProperty", getElementValueOfCssPropertyFn);
|
||||
removeMessageListener(
|
||||
"Marionette:getElementValueOfCssProperty",
|
||||
getElementValueOfCssPropertyFn
|
||||
);
|
||||
removeMessageListener("Marionette:get", get);
|
||||
removeMessageListener("Marionette:getPageSource", getPageSourceFn);
|
||||
removeMessageListener("Marionette:goBack", goBack);
|
||||
|
@ -597,7 +661,7 @@ function deregister() {
|
|||
function deleteSession() {
|
||||
seenEls.clear();
|
||||
// reset container frame to the top-most frame
|
||||
curContainer = {frame: content, shadowRoot: null};
|
||||
curContainer = { frame: content, shadowRoot: null };
|
||||
curContainer.frame.focus();
|
||||
legacyactions.touchIds = {};
|
||||
if (action.inputStateMap !== undefined) {
|
||||
|
@ -670,11 +734,13 @@ async function executeInSandbox(script, args, opts) {
|
|||
}
|
||||
|
||||
function emitTouchEvent(type, touch) {
|
||||
logger.info(`Emitting Touch event of type ${type} ` +
|
||||
logger.info(
|
||||
`Emitting Touch event of type ${type} ` +
|
||||
`to element with id: ${touch.target.id} ` +
|
||||
`and tag name: ${touch.target.tagName} ` +
|
||||
`at coordinates (${touch.clientX}), ` +
|
||||
`${touch.clientY}) relative to the viewport`);
|
||||
`${touch.clientY}) relative to the viewport`
|
||||
);
|
||||
|
||||
const win = curContainer.frame;
|
||||
let docShell = win.docShell;
|
||||
|
@ -699,15 +765,16 @@ function emitTouchEvent(type, touch) {
|
|||
// we get here if we're not in asyncPacZoomEnabled land, or if we're
|
||||
// the main process
|
||||
win.windowUtils.sendTouchEvent(
|
||||
type,
|
||||
[touch.identifier],
|
||||
[touch.clientX],
|
||||
[touch.clientY],
|
||||
[touch.radiusX],
|
||||
[touch.radiusY],
|
||||
[touch.rotationAngle],
|
||||
[touch.force],
|
||||
0);
|
||||
type,
|
||||
[touch.identifier],
|
||||
[touch.clientX],
|
||||
[touch.clientY],
|
||||
[touch.radiusX],
|
||||
[touch.radiusY],
|
||||
[touch.rotationAngle],
|
||||
[touch.force],
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -718,7 +785,8 @@ async function singleTap(el, corx, cory) {
|
|||
let visible = element.isVisible(el, corx, cory);
|
||||
if (!visible) {
|
||||
throw new ElementNotInteractableError(
|
||||
"Element is not currently visible and may not be manipulated");
|
||||
"Element is not currently visible and may not be manipulated"
|
||||
);
|
||||
}
|
||||
|
||||
let a11y = accessibility.get(capabilities.get("moz:accessibilityChecks"));
|
||||
|
@ -745,18 +813,25 @@ async function singleTap(el, corx, cory) {
|
|||
function createATouch(el, corx, cory, touchId) {
|
||||
let doc = el.ownerDocument;
|
||||
let win = doc.defaultView;
|
||||
let [clientX, clientY, pageX, pageY, screenX, screenY] =
|
||||
legacyactions.getCoordinateInfo(el, corx, cory);
|
||||
let [
|
||||
clientX,
|
||||
clientY,
|
||||
pageX,
|
||||
pageY,
|
||||
screenX,
|
||||
screenY,
|
||||
] = legacyactions.getCoordinateInfo(el, corx, cory);
|
||||
let atouch = doc.createTouch(
|
||||
win,
|
||||
el,
|
||||
touchId,
|
||||
pageX,
|
||||
pageY,
|
||||
screenX,
|
||||
screenY,
|
||||
clientX,
|
||||
clientY);
|
||||
win,
|
||||
el,
|
||||
touchId,
|
||||
pageX,
|
||||
pageY,
|
||||
screenX,
|
||||
screenY,
|
||||
clientX,
|
||||
clientY
|
||||
);
|
||||
return atouch;
|
||||
}
|
||||
|
||||
|
@ -769,8 +844,10 @@ function createATouch(el, corx, cory, touchId) {
|
|||
*/
|
||||
async function performActions(msg) {
|
||||
let chain = action.Chain.fromJSON(msg.actions);
|
||||
await action.dispatch(chain, curContainer.frame,
|
||||
!capabilities.get("moz:useNonSpecCompliantPointerOrigin"),
|
||||
await action.dispatch(
|
||||
chain,
|
||||
curContainer.frame,
|
||||
!capabilities.get("moz:useNonSpecCompliantPointerOrigin")
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -782,7 +859,10 @@ async function performActions(msg) {
|
|||
*/
|
||||
async function releaseActions() {
|
||||
await action.dispatchTickActions(
|
||||
action.inputsToCancel.reverse(), 0, curContainer.frame);
|
||||
action.inputsToCancel.reverse(),
|
||||
0,
|
||||
curContainer.frame
|
||||
);
|
||||
action.inputsToCancel.length = 0;
|
||||
action.inputStateMap.clear();
|
||||
|
||||
|
@ -798,11 +878,12 @@ function actionChain(chain, touchId) {
|
|||
touchProvider.emitTouchEvent = emitTouchEvent;
|
||||
|
||||
return legacyactions.dispatchActions(
|
||||
chain,
|
||||
touchId,
|
||||
curContainer,
|
||||
seenEls,
|
||||
touchProvider);
|
||||
chain,
|
||||
touchId,
|
||||
curContainer,
|
||||
seenEls,
|
||||
touchProvider
|
||||
);
|
||||
}
|
||||
|
||||
function emitMultiEvents(type, touch, touches) {
|
||||
|
@ -810,27 +891,37 @@ function emitMultiEvents(type, touch, touches) {
|
|||
let doc = target.ownerDocument;
|
||||
let win = doc.defaultView;
|
||||
// touches that are in the same document
|
||||
let documentTouches = doc.createTouchList(touches.filter(function(t) {
|
||||
return ((t.target.ownerDocument === doc) && (type != "touchcancel"));
|
||||
}));
|
||||
let documentTouches = doc.createTouchList(
|
||||
touches.filter(function(t) {
|
||||
return t.target.ownerDocument === doc && type != "touchcancel";
|
||||
})
|
||||
);
|
||||
// touches on the same target
|
||||
let targetTouches = doc.createTouchList(touches.filter(function(t) {
|
||||
return ((t.target === target) &&
|
||||
((type != "touchcancel") || (type != "touchend")));
|
||||
}));
|
||||
let targetTouches = doc.createTouchList(
|
||||
touches.filter(function(t) {
|
||||
return (
|
||||
t.target === target && (type != "touchcancel" || type != "touchend")
|
||||
);
|
||||
})
|
||||
);
|
||||
// Create changed touches
|
||||
let changedTouches = doc.createTouchList(touch);
|
||||
// Create the event object
|
||||
let event = doc.createEvent("TouchEvent");
|
||||
event.initTouchEvent(type,
|
||||
true,
|
||||
true,
|
||||
win,
|
||||
0,
|
||||
false, false, false, false,
|
||||
documentTouches,
|
||||
targetTouches,
|
||||
changedTouches);
|
||||
event.initTouchEvent(
|
||||
type,
|
||||
true,
|
||||
true,
|
||||
win,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
documentTouches,
|
||||
targetTouches,
|
||||
changedTouches
|
||||
);
|
||||
target.dispatchEvent(event);
|
||||
}
|
||||
|
||||
|
@ -909,15 +1000,16 @@ function setDispatch(batches, touches, batchIndex = 0) {
|
|||
let screenX = clientX + win.mozInnerScreenX;
|
||||
let screenY = clientY + win.mozInnerScreenY;
|
||||
touch = doc.createTouch(
|
||||
win,
|
||||
el,
|
||||
touchId,
|
||||
pageX,
|
||||
pageY,
|
||||
screenX,
|
||||
screenY,
|
||||
clientX,
|
||||
clientY);
|
||||
win,
|
||||
el,
|
||||
touchId,
|
||||
pageX,
|
||||
pageY,
|
||||
screenX,
|
||||
screenY,
|
||||
clientX,
|
||||
clientY
|
||||
);
|
||||
touches[touchIndex] = touch;
|
||||
multiLast[touchId] = touch;
|
||||
emitMultiEvents("touchmove", touch, touches);
|
||||
|
@ -936,9 +1028,13 @@ function setDispatch(batches, touches, batchIndex = 0) {
|
|||
|
||||
if (maxTime != 0) {
|
||||
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.initWithCallback(function() {
|
||||
setDispatch(batches, touches, batchIndex);
|
||||
}, maxTime, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
timer.initWithCallback(
|
||||
function() {
|
||||
setDispatch(batches, touches, batchIndex);
|
||||
},
|
||||
maxTime,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT
|
||||
);
|
||||
} else {
|
||||
setDispatch(batches, touches, batchIndex);
|
||||
}
|
||||
|
@ -1003,9 +1099,12 @@ function cancelRequest() {
|
|||
* Unix timestap when the navitation request got triggered.
|
||||
*/
|
||||
function waitForPageLoaded(msg) {
|
||||
let {commandID, pageTimeout, startTime} = msg.json;
|
||||
let { commandID, pageTimeout, startTime } = msg.json;
|
||||
loadListener.waitForLoadAfterFramescriptReload(
|
||||
commandID, pageTimeout, startTime);
|
||||
commandID,
|
||||
pageTimeout,
|
||||
startTime
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1015,14 +1114,16 @@ function waitForPageLoaded(msg) {
|
|||
* (in chrome space).
|
||||
*/
|
||||
function get(msg) {
|
||||
let {commandID, pageTimeout, url, loadEventExpected = null} = msg.json;
|
||||
let { commandID, pageTimeout, url, loadEventExpected = null } = msg.json;
|
||||
|
||||
try {
|
||||
if (typeof url == "string") {
|
||||
try {
|
||||
if (loadEventExpected === null) {
|
||||
loadEventExpected = navigate.isLoadEventExpected(
|
||||
curContainer.frame.location, url);
|
||||
curContainer.frame.location,
|
||||
url
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
let err = new InvalidArgumentError("Malformed URL: " + e.message);
|
||||
|
@ -1032,12 +1133,17 @@ function get(msg) {
|
|||
}
|
||||
|
||||
// We need to move to the top frame before navigating
|
||||
sendSyncMessage("Marionette:switchedToFrame", {frameValue: null});
|
||||
sendSyncMessage("Marionette:switchedToFrame", { frameValue: null });
|
||||
curContainer.frame = content;
|
||||
|
||||
loadListener.navigate(() => {
|
||||
curContainer.frame.location = url;
|
||||
}, commandID, pageTimeout, loadEventExpected);
|
||||
loadListener.navigate(
|
||||
() => {
|
||||
curContainer.frame.location = url;
|
||||
},
|
||||
commandID,
|
||||
pageTimeout,
|
||||
loadEventExpected
|
||||
);
|
||||
} catch (e) {
|
||||
sendError(e, commandID);
|
||||
}
|
||||
|
@ -1055,12 +1161,16 @@ function get(msg) {
|
|||
* finished loading.
|
||||
*/
|
||||
function goBack(msg) {
|
||||
let {commandID, pageTimeout} = msg.json;
|
||||
let { commandID, pageTimeout } = msg.json;
|
||||
|
||||
try {
|
||||
loadListener.navigate(() => {
|
||||
curContainer.frame.history.back();
|
||||
}, commandID, pageTimeout);
|
||||
loadListener.navigate(
|
||||
() => {
|
||||
curContainer.frame.history.back();
|
||||
},
|
||||
commandID,
|
||||
pageTimeout
|
||||
);
|
||||
} catch (e) {
|
||||
sendError(e, commandID);
|
||||
}
|
||||
|
@ -1078,12 +1188,16 @@ function goBack(msg) {
|
|||
* finished loading.
|
||||
*/
|
||||
function goForward(msg) {
|
||||
let {commandID, pageTimeout} = msg.json;
|
||||
let { commandID, pageTimeout } = msg.json;
|
||||
|
||||
try {
|
||||
loadListener.navigate(() => {
|
||||
curContainer.frame.history.forward();
|
||||
}, commandID, pageTimeout);
|
||||
loadListener.navigate(
|
||||
() => {
|
||||
curContainer.frame.history.forward();
|
||||
},
|
||||
commandID,
|
||||
pageTimeout
|
||||
);
|
||||
} catch (e) {
|
||||
sendError(e, commandID);
|
||||
}
|
||||
|
@ -1101,16 +1215,20 @@ function goForward(msg) {
|
|||
* finished loading.
|
||||
*/
|
||||
function refresh(msg) {
|
||||
let {commandID, pageTimeout} = msg.json;
|
||||
let { commandID, pageTimeout } = msg.json;
|
||||
|
||||
try {
|
||||
// We need to move to the top frame before navigating
|
||||
sendSyncMessage("Marionette:switchedToFrame", {frameValue: null});
|
||||
sendSyncMessage("Marionette:switchedToFrame", { frameValue: null });
|
||||
curContainer.frame = content;
|
||||
|
||||
loadListener.navigate(() => {
|
||||
curContainer.frame.location.reload(true);
|
||||
}, commandID, pageTimeout);
|
||||
loadListener.navigate(
|
||||
() => {
|
||||
curContainer.frame.location.reload(true);
|
||||
},
|
||||
commandID,
|
||||
pageTimeout
|
||||
);
|
||||
} catch (e) {
|
||||
sendError(e, commandID);
|
||||
}
|
||||
|
@ -1184,7 +1302,7 @@ function getActiveElement() {
|
|||
* finished loading.
|
||||
*/
|
||||
function clickElement(msg) {
|
||||
let {commandID, webElRef, pageTimeout} = msg.json;
|
||||
let { commandID, webElRef, pageTimeout } = msg.json;
|
||||
|
||||
try {
|
||||
let webEl = WebElement.fromJSON(webElRef);
|
||||
|
@ -1197,13 +1315,19 @@ function clickElement(msg) {
|
|||
loadEventExpected = false;
|
||||
}
|
||||
|
||||
loadListener.navigate(() => {
|
||||
return interaction.clickElement(
|
||||
loadListener.navigate(
|
||||
() => {
|
||||
return interaction.clickElement(
|
||||
el,
|
||||
capabilities.get("moz:accessibilityChecks"),
|
||||
capabilities.get("moz:webdriverClick")
|
||||
);
|
||||
}, commandID, pageTimeout, loadEventExpected, true);
|
||||
);
|
||||
},
|
||||
commandID,
|
||||
pageTimeout,
|
||||
loadEventExpected,
|
||||
true
|
||||
);
|
||||
} catch (e) {
|
||||
sendError(e, commandID);
|
||||
}
|
||||
|
@ -1252,7 +1376,9 @@ function getElementTagName(el) {
|
|||
*/
|
||||
function isElementDisplayed(el) {
|
||||
return interaction.isElementDisplayed(
|
||||
el, capabilities.get("moz:accessibilityChecks"));
|
||||
el,
|
||||
capabilities.get("moz:accessibilityChecks")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1282,7 +1408,9 @@ function getElementRect(el) {
|
|||
|
||||
function isElementEnabled(el) {
|
||||
return interaction.isElementEnabled(
|
||||
el, capabilities.get("moz:accessibilityChecks"));
|
||||
el,
|
||||
capabilities.get("moz:accessibilityChecks")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1293,7 +1421,9 @@ function isElementEnabled(el) {
|
|||
*/
|
||||
function isElementSelected(el) {
|
||||
return interaction.isElementSelected(
|
||||
el, capabilities.get("moz:accessibilityChecks"));
|
||||
el,
|
||||
capabilities.get("moz:accessibilityChecks")
|
||||
);
|
||||
}
|
||||
|
||||
async function sendKeysToElement(el, val) {
|
||||
|
@ -1348,8 +1478,9 @@ function switchToParentFrame(msg) {
|
|||
curContainer.frame = curContainer.frame.parent;
|
||||
let parentElement = seenEls.add(curContainer.frame);
|
||||
|
||||
sendSyncMessage(
|
||||
"Marionette:switchedToFrame", {frameValue: parentElement.uuid});
|
||||
sendSyncMessage("Marionette:switchedToFrame", {
|
||||
frameValue: parentElement.uuid,
|
||||
});
|
||||
|
||||
sendOk(msg.json.commandID);
|
||||
}
|
||||
|
@ -1372,10 +1503,12 @@ function switchToFrame(msg) {
|
|||
msg.json.element = null;
|
||||
}
|
||||
|
||||
if ((msg.json.id === null || msg.json.id === undefined) &&
|
||||
(msg.json.element == null)) {
|
||||
if (
|
||||
(msg.json.id === null || msg.json.id === undefined) &&
|
||||
msg.json.element == null
|
||||
) {
|
||||
// returning to root frame
|
||||
sendSyncMessage("Marionette:switchedToFrame", {frameValue: null});
|
||||
sendSyncMessage("Marionette:switchedToFrame", { frameValue: null });
|
||||
|
||||
curContainer.frame = content;
|
||||
if (msg.json.focus) {
|
||||
|
@ -1447,7 +1580,7 @@ function switchToFrame(msg) {
|
|||
} else {
|
||||
// If foundFrame is null at this point then we have the top
|
||||
// level browsing context so should treat it accordingly.
|
||||
sendSyncMessage("Marionette:switchedToFrame", {frameValue: null});
|
||||
sendSyncMessage("Marionette:switchedToFrame", { frameValue: null });
|
||||
curContainer.frame = content;
|
||||
|
||||
if (msg.json.focus) {
|
||||
|
@ -1481,7 +1614,9 @@ function switchToFrame(msg) {
|
|||
// send a synchronous message to let the server update the currently active
|
||||
// frame element (for getActiveFrame)
|
||||
let frameWebEl = seenEls.add(curContainer.frame.wrappedJSObject);
|
||||
sendSyncMessage("Marionette:switchedToFrame", {"frameValue": frameWebEl.uuid});
|
||||
sendSyncMessage("Marionette:switchedToFrame", {
|
||||
frameValue: frameWebEl.uuid,
|
||||
});
|
||||
|
||||
curContainer.frame = curContainer.frame.contentWindow;
|
||||
if (msg.json.focus) {
|
||||
|
@ -1527,14 +1662,14 @@ function takeScreenshot(format, opts = {}) {
|
|||
|
||||
let canvas;
|
||||
let highlightEls = highlights
|
||||
.map(ref => WebElement.fromUUID(ref, "content"))
|
||||
.map(webEl => seenEls.get(webEl, win));
|
||||
.map(ref => WebElement.fromUUID(ref, "content"))
|
||||
.map(webEl => seenEls.get(webEl, win));
|
||||
|
||||
// viewport
|
||||
if (!id && !full) {
|
||||
canvas = capture.viewport(win, highlightEls);
|
||||
|
||||
// element or full document element
|
||||
// element or full document element
|
||||
} else {
|
||||
let el;
|
||||
if (id) {
|
||||
|
@ -1592,10 +1727,14 @@ function flushRendering() {
|
|||
}
|
||||
flushWindow(content);
|
||||
|
||||
if (anyPendingPaintsGeneratedInDescendants &&
|
||||
!windowUtils.isMozAfterPaintPending) {
|
||||
logger.error("Descendant frame generated a MozAfterPaint event, " +
|
||||
"but the root document doesn't have one!");
|
||||
if (
|
||||
anyPendingPaintsGeneratedInDescendants &&
|
||||
!windowUtils.isMozAfterPaintPending
|
||||
) {
|
||||
logger.error(
|
||||
"Descendant frame generated a MozAfterPaint event, " +
|
||||
"but the root document doesn't have one!"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1611,12 +1750,16 @@ async function reftestWait(url, remote) {
|
|||
logger.debug(truncate`Waiting for page load of ${url}`);
|
||||
await new Promise(resolve => {
|
||||
let maybeResolve = event => {
|
||||
if (event.target === curContainer.frame.document &&
|
||||
event.target.location.href === url) {
|
||||
if (
|
||||
event.target === curContainer.frame.document &&
|
||||
event.target.location.href === url
|
||||
) {
|
||||
win = curContainer.frame;
|
||||
document = curContainer.frame.document;
|
||||
reftestWait = document.documentElement.classList.contains("reftest-wait");
|
||||
removeEventListener("load", maybeResolve, {once: true});
|
||||
reftestWait = document.documentElement.classList.contains(
|
||||
"reftest-wait"
|
||||
);
|
||||
removeEventListener("load", maybeResolve, { once: true });
|
||||
win.setTimeout(resolve, 0);
|
||||
}
|
||||
};
|
||||
|
@ -1643,7 +1786,7 @@ async function reftestWait(url, remote) {
|
|||
win.setTimeout(resolve, 0);
|
||||
}
|
||||
});
|
||||
observer.observe(root, {attributes: true});
|
||||
observer.observe(root, { attributes: true });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1659,7 +1802,7 @@ async function reftestWait(url, remote) {
|
|||
}
|
||||
if (windowUtils.isMozAfterPaintPending) {
|
||||
logger.debug(`reftestWait: ${windowUtils.isMozAfterPaintPending}`);
|
||||
win.addEventListener("MozAfterPaint", maybeResolve, {once: true});
|
||||
win.addEventListener("MozAfterPaint", maybeResolve, { once: true });
|
||||
} else {
|
||||
// resolve at the start of the next frame in case of leftover paints
|
||||
win.requestAnimationFrame(() => {
|
||||
|
|
|
@ -56,7 +56,10 @@ class Log {
|
|||
*/
|
||||
static getWithPrefix(prefix) {
|
||||
this.get();
|
||||
return StdLog.repository.getLoggerWithMessagePrefix("Marionette", `[${prefix}] `);
|
||||
return StdLog.repository.getLoggerWithMessagePrefix(
|
||||
"Marionette",
|
||||
`[${prefix}] `
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,15 +4,13 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {assert} = ChromeUtils.import("chrome://marionette/content/assert.js");
|
||||
const {error} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const {truncate} = ChromeUtils.import("chrome://marionette/content/format.js");
|
||||
const { assert } = ChromeUtils.import("chrome://marionette/content/assert.js");
|
||||
const { error } = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const { truncate } = ChromeUtils.import(
|
||||
"chrome://marionette/content/format.js"
|
||||
);
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"Command",
|
||||
"Message",
|
||||
"Response",
|
||||
];
|
||||
this.EXPORTED_SYMBOLS = ["Command", "Message", "Response"];
|
||||
|
||||
/** Representation of the packets transproted over the wire. */
|
||||
class Message {
|
||||
|
@ -56,7 +54,8 @@ class Message {
|
|||
|
||||
default:
|
||||
throw new TypeError(
|
||||
"Unrecognised message type in packet: " + JSON.stringify(data));
|
||||
"Unrecognised message type in packet: " + JSON.stringify(data)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -165,12 +164,7 @@ class Command extends Message {
|
|||
* Packet.
|
||||
*/
|
||||
toPacket() {
|
||||
return [
|
||||
Command.Type,
|
||||
this.id,
|
||||
this.name,
|
||||
this.parameters,
|
||||
];
|
||||
return [Command.Type, this.id, this.name, this.parameters];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -234,7 +228,7 @@ class Response extends Message {
|
|||
this.respHandler_ = assert.callable(respHandler);
|
||||
|
||||
this.error = null;
|
||||
this.body = {value: null};
|
||||
this.body = { value: null };
|
||||
|
||||
this.origin = Message.Origin.Server;
|
||||
this.sent = false;
|
||||
|
@ -299,12 +293,7 @@ class Response extends Message {
|
|||
* Packet.
|
||||
*/
|
||||
toPacket() {
|
||||
return [
|
||||
Response.Type,
|
||||
this.id,
|
||||
this.error,
|
||||
this.body,
|
||||
];
|
||||
return [Response.Type, this.id, this.error, this.body];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,10 +4,12 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const {Log} = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
const { Log } = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", Log.get);
|
||||
|
||||
|
@ -16,7 +18,7 @@ this.EXPORTED_SYMBOLS = ["modal"];
|
|||
const COMMON_DIALOG = "chrome://global/content/commonDialog.xul";
|
||||
|
||||
const isFirefox = () =>
|
||||
Services.appinfo.ID == "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}";
|
||||
Services.appinfo.ID == "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}";
|
||||
|
||||
/** @namespace */
|
||||
this.modal = {
|
||||
|
@ -40,8 +42,11 @@ modal.findModalDialogs = function(context) {
|
|||
for (let win of Services.wm.getEnumerator(null)) {
|
||||
// TODO: Use BrowserWindowTracker.getTopWindow for modal dialogs without
|
||||
// an opener.
|
||||
if (win.document.documentURI === COMMON_DIALOG &&
|
||||
win.opener && win.opener === context.window) {
|
||||
if (
|
||||
win.document.documentURI === COMMON_DIALOG &&
|
||||
win.opener &&
|
||||
win.opener === context.window
|
||||
) {
|
||||
return new modal.Dialog(() => context, Cu.getWeakReference(win));
|
||||
}
|
||||
}
|
||||
|
@ -51,8 +56,7 @@ modal.findModalDialogs = function(context) {
|
|||
// TODO: Find an adequate implementation for Fennec.
|
||||
if (context.tab && context.tabBrowser.getTabModalPromptBox) {
|
||||
let contentBrowser = context.contentBrowser;
|
||||
let promptManager =
|
||||
context.tabBrowser.getTabModalPromptBox(contentBrowser);
|
||||
let promptManager = context.tabBrowser.getTabModalPromptBox(contentBrowser);
|
||||
let prompts = promptManager.listPrompts();
|
||||
|
||||
if (prompts.length) {
|
||||
|
@ -105,8 +109,9 @@ modal.DialogObserver = class {
|
|||
handleEvent(event) {
|
||||
logger.trace(`Received event ${event.type}`);
|
||||
|
||||
let chromeWin = event.target.opener ? event.target.opener.ownerGlobal :
|
||||
event.target.ownerGlobal;
|
||||
let chromeWin = event.target.opener
|
||||
? event.target.opener.ownerGlobal
|
||||
: event.target.ownerGlobal;
|
||||
|
||||
let targetRef = Cu.getWeakReference(event.target);
|
||||
|
||||
|
@ -121,8 +126,9 @@ modal.DialogObserver = class {
|
|||
switch (topic) {
|
||||
case "common-dialog-loaded":
|
||||
case "tabmodal-dialog-loaded":
|
||||
let chromeWin = subject.opener ? subject.opener.ownerGlobal :
|
||||
subject.ownerGlobal;
|
||||
let chromeWin = subject.opener
|
||||
? subject.opener.ownerGlobal
|
||||
: subject.ownerGlobal;
|
||||
|
||||
// Always keep a weak reference to the current dialog
|
||||
let targetRef = Cu.getWeakReference(subject);
|
||||
|
@ -179,7 +185,9 @@ modal.Dialog = class {
|
|||
this.win_ = winRef;
|
||||
}
|
||||
|
||||
get curBrowser_() { return this.curBrowserFn_(); }
|
||||
get curBrowser_() {
|
||||
return this.curBrowserFn_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ChromeWindow associated with an open dialog window if
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
|
||||
|
||||
|
@ -51,8 +53,11 @@ navigate.isLoadEventExpected = function(current, future = undefined) {
|
|||
}
|
||||
|
||||
// If hashes are present and identical
|
||||
if (cur.href.includes("#") && fut.href.includes("#") &&
|
||||
cur.hash === fut.hash) {
|
||||
if (
|
||||
cur.href.includes("#") &&
|
||||
fut.href.includes("#") &&
|
||||
cur.hash === fut.hash
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,11 +24,13 @@
|
|||
* Called to clean up at the end of use
|
||||
*/
|
||||
|
||||
const {StreamUtils} =
|
||||
ChromeUtils.import("chrome://marionette/content/stream-utils.js");
|
||||
const { StreamUtils } = ChromeUtils.import(
|
||||
"chrome://marionette/content/stream-utils.js"
|
||||
);
|
||||
|
||||
const unicodeConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
const unicodeConverter = Cc[
|
||||
"@mozilla.org/intl/scriptableunicodeconverter"
|
||||
].createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
unicodeConverter.charset = "UTF-8";
|
||||
|
||||
const defer = function() {
|
||||
|
@ -72,20 +74,25 @@ function Packet(transport) {
|
|||
* Parsed packet of the matching type, or null if no types matched.
|
||||
*/
|
||||
Packet.fromHeader = function(header, transport) {
|
||||
return JSONPacket.fromHeader(header, transport) ||
|
||||
BulkPacket.fromHeader(header, transport);
|
||||
return (
|
||||
JSONPacket.fromHeader(header, transport) ||
|
||||
BulkPacket.fromHeader(header, transport)
|
||||
);
|
||||
};
|
||||
|
||||
Packet.prototype = {
|
||||
|
||||
get length() {
|
||||
return this._length;
|
||||
},
|
||||
|
||||
set length(length) {
|
||||
if (length > PACKET_LENGTH_MAX) {
|
||||
throw new Error("Packet length " + length +
|
||||
" exceeds the max length of " + PACKET_LENGTH_MAX);
|
||||
throw new Error(
|
||||
"Packet length " +
|
||||
length +
|
||||
" exceeds the max length of " +
|
||||
PACKET_LENGTH_MAX
|
||||
);
|
||||
}
|
||||
this._length = length;
|
||||
},
|
||||
|
@ -172,8 +179,14 @@ JSONPacket.prototype.read = function(stream, scriptableStream) {
|
|||
json = unicodeConverter.ConvertToUnicode(json);
|
||||
this._object = JSON.parse(json);
|
||||
} catch (e) {
|
||||
let msg = "Error parsing incoming packet: " + json + " (" + e +
|
||||
" - " + e.stack + ")";
|
||||
let msg =
|
||||
"Error parsing incoming packet: " +
|
||||
json +
|
||||
" (" +
|
||||
e +
|
||||
" - " +
|
||||
e.stack +
|
||||
")";
|
||||
console.error(msg);
|
||||
dump(msg + "\n");
|
||||
return;
|
||||
|
@ -184,8 +197,9 @@ JSONPacket.prototype.read = function(stream, scriptableStream) {
|
|||
|
||||
JSONPacket.prototype._readData = function(stream, scriptableStream) {
|
||||
let bytesToRead = Math.min(
|
||||
this.length - this._data.length,
|
||||
stream.available());
|
||||
this.length - this._data.length,
|
||||
stream.available()
|
||||
);
|
||||
this._data += scriptableStream.readBytes(bytesToRead);
|
||||
this._done = this._data.length === this.length;
|
||||
};
|
||||
|
@ -275,7 +289,7 @@ BulkPacket.prototype.read = function(stream) {
|
|||
actor: this.actor,
|
||||
type: this.type,
|
||||
length: this.length,
|
||||
copyTo: (output) => {
|
||||
copyTo: output => {
|
||||
let copying = StreamUtils.copyStream(stream, output, this.length);
|
||||
deferred.resolve(copying);
|
||||
return copying;
|
||||
|
@ -299,14 +313,16 @@ BulkPacket.prototype.read = function(stream) {
|
|||
BulkPacket.prototype.write = function(stream) {
|
||||
if (this._outgoingHeader === undefined) {
|
||||
// Format the serialized packet header to a buffer
|
||||
this._outgoingHeader = "bulk " + this.actor + " " + this.type + " " +
|
||||
this.length + ":";
|
||||
this._outgoingHeader =
|
||||
"bulk " + this.actor + " " + this.type + " " + this.length + ":";
|
||||
}
|
||||
|
||||
// Write the header, or whatever's left of it to write.
|
||||
if (this._outgoingHeader.length) {
|
||||
let written = stream.write(this._outgoingHeader,
|
||||
this._outgoingHeader.length);
|
||||
let written = stream.write(
|
||||
this._outgoingHeader,
|
||||
this._outgoingHeader.length
|
||||
);
|
||||
this._outgoingHeader = this._outgoingHeader.slice(written);
|
||||
return;
|
||||
}
|
||||
|
@ -317,7 +333,7 @@ BulkPacket.prototype.write = function(stream) {
|
|||
let deferred = defer();
|
||||
|
||||
this._readyForWriting.resolve({
|
||||
copyFrom: (input) => {
|
||||
copyFrom: input => {
|
||||
let copying = StreamUtils.copyStream(input, stream, this.length);
|
||||
deferred.resolve(copying);
|
||||
return copying;
|
||||
|
|
|
@ -4,25 +4,22 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {Log} = ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { Log } = ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "env",
|
||||
"@mozilla.org/process/environment;1",
|
||||
"nsIEnvironment");
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"env",
|
||||
"@mozilla.org/process/environment;1",
|
||||
"nsIEnvironment"
|
||||
);
|
||||
|
||||
const {
|
||||
PREF_BOOL,
|
||||
PREF_INT,
|
||||
PREF_INVALID,
|
||||
PREF_STRING,
|
||||
} = Ci.nsIPrefBranch;
|
||||
const { PREF_BOOL, PREF_INT, PREF_INVALID, PREF_STRING } = Ci.nsIPrefBranch;
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"Branch",
|
||||
"MarionettePrefs",
|
||||
];
|
||||
this.EXPORTED_SYMBOLS = ["Branch", "MarionettePrefs"];
|
||||
|
||||
class Branch {
|
||||
/**
|
||||
|
@ -245,7 +242,7 @@ class EnvironmentPrefs {
|
|||
*
|
||||
* @return {Iterable.<string, (string|boolean|number)>
|
||||
*/
|
||||
static* from(key) {
|
||||
static *from(key) {
|
||||
if (!env.exists(key)) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -4,25 +4,32 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const {
|
||||
error,
|
||||
WebDriverError,
|
||||
} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const {evaluate} = ChromeUtils.import("chrome://marionette/content/evaluate.js");
|
||||
const {Log} = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
const {modal} = ChromeUtils.import("chrome://marionette/content/modal.js");
|
||||
const {
|
||||
MessageManagerDestroyedPromise,
|
||||
} = ChromeUtils.import("chrome://marionette/content/sync.js");
|
||||
const { error, WebDriverError } = ChromeUtils.import(
|
||||
"chrome://marionette/content/error.js"
|
||||
);
|
||||
const { evaluate } = ChromeUtils.import(
|
||||
"chrome://marionette/content/evaluate.js"
|
||||
);
|
||||
const { Log } = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
const { modal } = ChromeUtils.import("chrome://marionette/content/modal.js");
|
||||
const { MessageManagerDestroyedPromise } = ChromeUtils.import(
|
||||
"chrome://marionette/content/sync.js"
|
||||
);
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["proxy"];
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "log", Log.get);
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this, "uuidgen", "@mozilla.org/uuid-generator;1", "nsIUUIDGenerator");
|
||||
this,
|
||||
"uuidgen",
|
||||
"@mozilla.org/uuid-generator;1",
|
||||
"nsIUUIDGenerator"
|
||||
);
|
||||
|
||||
// Proxy handler that traps requests to get a property. Will prioritise
|
||||
// properties that exist on the object's own prototype.
|
||||
|
@ -122,7 +129,7 @@ proxy.AsyncMessageChannel = class {
|
|||
let path = proxy.AsyncMessageChannel.makePath(uuid);
|
||||
let cb = msg => {
|
||||
this.activeMessageId = null;
|
||||
let {data, type} = msg.json;
|
||||
let { data, type } = msg.json;
|
||||
|
||||
switch (msg.json.type) {
|
||||
case proxy.AsyncMessageChannel.ReplyType.Ok:
|
||||
|
@ -143,7 +150,7 @@ proxy.AsyncMessageChannel = class {
|
|||
|
||||
// The currently selected tab or window is closing. Make sure to wait
|
||||
// until it's fully gone.
|
||||
this.closeHandler = async ({type, target}) => {
|
||||
this.closeHandler = async ({ type, target }) => {
|
||||
log.trace(`Received DOM event ${type} for ${target}`);
|
||||
|
||||
let messageManager;
|
||||
|
@ -200,8 +207,9 @@ proxy.AsyncMessageChannel = class {
|
|||
this.browser.window.addEventListener("unload", this.closeHandler);
|
||||
|
||||
if (this.browser.tab) {
|
||||
let node = this.browser.tab.addEventListener ?
|
||||
this.browser.tab : this.browser.contentBrowser;
|
||||
let node = this.browser.tab.addEventListener
|
||||
? this.browser.tab
|
||||
: this.browser.contentBrowser;
|
||||
node.addEventListener("TabClose", this.closeHandler);
|
||||
}
|
||||
}
|
||||
|
@ -217,8 +225,9 @@ proxy.AsyncMessageChannel = class {
|
|||
this.browser.window.removeEventListener("unload", this.closeHandler);
|
||||
|
||||
if (this.browser.tab) {
|
||||
let node = this.browser.tab.addEventListener ?
|
||||
this.browser.tab : this.browser.contentBrowser;
|
||||
let node = this.browser.tab.addEventListener
|
||||
? this.browser.tab
|
||||
: this.browser.contentBrowser;
|
||||
if (node) {
|
||||
node.removeEventListener("TabClose", this.closeHandler);
|
||||
}
|
||||
|
@ -271,7 +280,7 @@ proxy.AsyncMessageChannel = class {
|
|||
const path = proxy.AsyncMessageChannel.makePath(uuid);
|
||||
|
||||
let data = evaluate.toJSON(payload);
|
||||
const msg = {type, data};
|
||||
const msg = { type, data };
|
||||
|
||||
// here sendAsync is actually the content frame's
|
||||
// sendAsyncMessage(path, message) global
|
||||
|
|
|
@ -4,14 +4,22 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {Preferences} = ChromeUtils.import("resource://gre/modules/Preferences.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { Preferences } = ChromeUtils.import(
|
||||
"resource://gre/modules/Preferences.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const {assert} = ChromeUtils.import("chrome://marionette/content/assert.js");
|
||||
const {capture} = ChromeUtils.import("chrome://marionette/content/capture.js");
|
||||
const {InvalidArgumentError} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const {Log} = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
const { assert } = ChromeUtils.import("chrome://marionette/content/assert.js");
|
||||
const { capture } = ChromeUtils.import(
|
||||
"chrome://marionette/content/capture.js"
|
||||
);
|
||||
const { InvalidArgumentError } = ChromeUtils.import(
|
||||
"chrome://marionette/content/error.js"
|
||||
);
|
||||
const { Log } = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", Log.get);
|
||||
|
||||
|
@ -71,13 +79,15 @@ reftest.Runner = class {
|
|||
* String enum representing when screenshots should be taken
|
||||
*/
|
||||
setup(urlCount, screenshotMode) {
|
||||
this.parentWindow = assert.open(this.driver.getCurrentWindow());
|
||||
this.parentWindow = assert.open(this.driver.getCurrentWindow());
|
||||
|
||||
this.screenshotMode = SCREENSHOT_MODE[screenshotMode] ||
|
||||
SCREENSHOT_MODE.unexpected;
|
||||
this.screenshotMode =
|
||||
SCREENSHOT_MODE[screenshotMode] || SCREENSHOT_MODE.unexpected;
|
||||
|
||||
this.urlCount = Object.keys(urlCount || {})
|
||||
.reduce((map, key) => map.set(key, urlCount[key]), new Map());
|
||||
this.urlCount = Object.keys(urlCount || {}).reduce(
|
||||
(map, key) => map.set(key, urlCount[key]),
|
||||
new Map()
|
||||
);
|
||||
}
|
||||
|
||||
async ensureWindow(timeout, width, height) {
|
||||
|
@ -99,7 +109,8 @@ reftest.Runner = class {
|
|||
commandID: this.driver.listener.activeMessageId,
|
||||
pageTimeout: timeout,
|
||||
url: "about:blank",
|
||||
loadEventExpected: false});
|
||||
loadEventExpected: false,
|
||||
});
|
||||
} else {
|
||||
logger.debug("Using separate window");
|
||||
if (this.reftestWin && !this.reftestWin.closed) {
|
||||
|
@ -126,12 +137,13 @@ reftest.Runner = class {
|
|||
assert.positiveInteger(height);
|
||||
|
||||
let reftestWin = this.parentWindow.open(
|
||||
"chrome://marionette/content/reftest.xul",
|
||||
"reftest",
|
||||
`chrome,height=${height},width=${width}`);
|
||||
"chrome://marionette/content/reftest.xul",
|
||||
"reftest",
|
||||
`chrome,height=${height},width=${width}`
|
||||
);
|
||||
|
||||
await new Promise(resolve => {
|
||||
reftestWin.addEventListener("load", resolve, {once: true});
|
||||
reftestWin.addEventListener("load", resolve, { once: true });
|
||||
});
|
||||
return reftestWin;
|
||||
}
|
||||
|
@ -225,22 +237,33 @@ max-width: ${width}px; max-height: ${height}px`;
|
|||
* @return {Object}
|
||||
* Result object with fields status, message and extra.
|
||||
*/
|
||||
async run(testUrl, references, expected, timeout,
|
||||
width = DEFAULT_REFTEST_WIDTH,
|
||||
height = DEFAULT_REFTEST_HEIGHT) {
|
||||
async run(
|
||||
testUrl,
|
||||
references,
|
||||
expected,
|
||||
timeout,
|
||||
width = DEFAULT_REFTEST_WIDTH,
|
||||
height = DEFAULT_REFTEST_HEIGHT
|
||||
) {
|
||||
let timeoutHandle;
|
||||
|
||||
let timeoutPromise = new Promise(resolve => {
|
||||
timeoutHandle = this.parentWindow.setTimeout(() => {
|
||||
resolve({status: STATUS.TIMEOUT, message: null, extra: {}});
|
||||
resolve({ status: STATUS.TIMEOUT, message: null, extra: {} });
|
||||
}, timeout);
|
||||
});
|
||||
|
||||
let testRunner = (async () => {
|
||||
let result;
|
||||
try {
|
||||
result = await this.runTest(testUrl, references, expected, timeout,
|
||||
width, height);
|
||||
result = await this.runTest(
|
||||
testUrl,
|
||||
references,
|
||||
expected,
|
||||
timeout,
|
||||
width,
|
||||
height
|
||||
);
|
||||
} catch (e) {
|
||||
result = {
|
||||
status: STATUS.ERROR,
|
||||
|
@ -293,9 +316,15 @@ max-width: ${width}px; max-height: ${height}px`;
|
|||
let comparison;
|
||||
try {
|
||||
comparison = await this.compareUrls(
|
||||
win, lhsUrl, rhsUrl, relation, timeout, extras);
|
||||
win,
|
||||
lhsUrl,
|
||||
rhsUrl,
|
||||
relation,
|
||||
timeout,
|
||||
extras
|
||||
);
|
||||
} catch (e) {
|
||||
comparison = {lhs: null, rhs: null, passed: false, error: e};
|
||||
comparison = { lhs: null, rhs: null, passed: false, error: e };
|
||||
}
|
||||
if (comparison.error !== null) {
|
||||
result.status = STATUS.ERROR;
|
||||
|
@ -306,9 +335,11 @@ max-width: ${width}px; max-height: ${height}px`;
|
|||
function recordScreenshot() {
|
||||
let encodedLHS = comparison.lhs ? toBase64(comparison.lhs) : "";
|
||||
let encodedRHS = comparison.rhs ? toBase64(comparison.rhs) : "";
|
||||
screenshotData.push([{url: lhsUrl, screenshot: encodedLHS},
|
||||
screenshotData.push([
|
||||
{ url: lhsUrl, screenshot: encodedLHS },
|
||||
relation,
|
||||
{url: rhsUrl, screenshot: encodedRHS}]);
|
||||
{ url: rhsUrl, screenshot: encodedRHS },
|
||||
]);
|
||||
}
|
||||
|
||||
if (this.screenshotMode === SCREENSHOT_MODE.always) {
|
||||
|
@ -324,8 +355,10 @@ max-width: ${width}px; max-height: ${height}px`;
|
|||
} else {
|
||||
// Reached a leaf node so all of one reference chain passed
|
||||
result.status = STATUS.PASS;
|
||||
if (this.screenshotMode <= SCREENSHOT_MODE.fail &&
|
||||
expected != result.status) {
|
||||
if (
|
||||
this.screenshotMode <= SCREENSHOT_MODE.fail &&
|
||||
expected != result.status
|
||||
) {
|
||||
recordScreenshot();
|
||||
}
|
||||
done = true;
|
||||
|
@ -348,7 +381,9 @@ max-width: ${width}px; max-height: ${height}px`;
|
|||
canvasPool.push(screenshot.canvas);
|
||||
}
|
||||
});
|
||||
logger.debug(`Canvas pool (${cacheKey}) is of length ${canvasPool.length}`);
|
||||
logger.debug(
|
||||
`Canvas pool (${cacheKey}) is of length ${canvasPool.length}`
|
||||
);
|
||||
}
|
||||
|
||||
if (screenshotData.length) {
|
||||
|
@ -380,7 +415,10 @@ max-width: ${width}px; max-height: ${height}px`;
|
|||
|
||||
try {
|
||||
pixelsDifferent = this.windowUtils.compareCanvases(
|
||||
lhs.canvas, rhs.canvas, maxDifferences);
|
||||
lhs.canvas,
|
||||
rhs.canvas,
|
||||
maxDifferences
|
||||
);
|
||||
} catch (e) {
|
||||
passed = false;
|
||||
error = e;
|
||||
|
@ -388,22 +426,29 @@ max-width: ${width}px; max-height: ${height}px`;
|
|||
|
||||
if (error === null) {
|
||||
passed = this.isAcceptableDifference(
|
||||
maxDifferences.value, pixelsDifferent, extras.fuzzy);
|
||||
maxDifferences.value,
|
||||
pixelsDifferent,
|
||||
extras.fuzzy
|
||||
);
|
||||
switch (relation) {
|
||||
case "==":
|
||||
if (!passed) {
|
||||
logger.info(`Found ${pixelsDifferent} pixels different, ` +
|
||||
`maximum difference per channel ${maxDifferences.value}`);
|
||||
logger.info(
|
||||
`Found ${pixelsDifferent} pixels different, ` +
|
||||
`maximum difference per channel ${maxDifferences.value}`
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "!=":
|
||||
passed = !passed;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidArgumentError("Reftest operator should be '==' or '!='");
|
||||
throw new InvalidArgumentError(
|
||||
"Reftest operator should be '==' or '!='"
|
||||
);
|
||||
}
|
||||
}
|
||||
return {lhs, rhs, passed, error};
|
||||
return { lhs, rhs, passed, error };
|
||||
}
|
||||
|
||||
isAcceptableDifference(maxDifference, pixelsDifferent, allowed) {
|
||||
|
@ -412,14 +457,18 @@ max-width: ${width}px; max-height: ${height}px`;
|
|||
return pixelsDifferent === 0;
|
||||
}
|
||||
let [allowedDiff, allowedPixels] = allowed;
|
||||
logger.info(`Allowed ${allowedPixels.join("-")} pixels different, ` +
|
||||
`maximum difference per channel ${allowedDiff.join("-")}`);
|
||||
return ((pixelsDifferent === 0 && allowedPixels[0] == 0) ||
|
||||
(maxDifference === 0 && allowedDiff[0] == 0) ||
|
||||
((maxDifference >= allowedDiff[0] &&
|
||||
maxDifference <= allowedDiff[1]) &&
|
||||
(pixelsDifferent >= allowedPixels[0] ||
|
||||
pixelsDifferent <= allowedPixels[1])));
|
||||
logger.info(
|
||||
`Allowed ${allowedPixels.join("-")} pixels different, ` +
|
||||
`maximum difference per channel ${allowedDiff.join("-")}`
|
||||
);
|
||||
return (
|
||||
(pixelsDifferent === 0 && allowedPixels[0] == 0) ||
|
||||
(maxDifference === 0 && allowedDiff[0] == 0) ||
|
||||
(maxDifference >= allowedDiff[0] &&
|
||||
maxDifference <= allowedDiff[1] &&
|
||||
(pixelsDifferent >= allowedPixels[0] ||
|
||||
pixelsDifferent <= allowedPixels[1]))
|
||||
);
|
||||
}
|
||||
|
||||
ensureFocus(win) {
|
||||
|
@ -439,8 +488,10 @@ max-width: ${width}px; max-height: ${height}px`;
|
|||
let remainingCount = this.urlCount.get(url) || 1;
|
||||
let cache = remainingCount > 1;
|
||||
let cacheKey = browserRect.width + "x" + browserRect.height;
|
||||
logger.debug(`screenshot ${url} remainingCount: ` +
|
||||
`${remainingCount} cache: ${cache} cacheKey: ${cacheKey}`);
|
||||
logger.debug(
|
||||
`screenshot ${url} remainingCount: ` +
|
||||
`${remainingCount} cache: ${cache} cacheKey: ${cacheKey}`
|
||||
);
|
||||
let reuseCanvas = false;
|
||||
let sizedCache = this.canvasCache.get(cacheKey);
|
||||
if (sizedCache.has(url)) {
|
||||
|
@ -461,14 +512,19 @@ max-width: ${width}px; max-height: ${height}px`;
|
|||
reuseCanvas = !cache;
|
||||
|
||||
let ctxInterface = win.CanvasRenderingContext2D;
|
||||
let flags = ctxInterface.DRAWWINDOW_DRAW_CARET |
|
||||
ctxInterface.DRAWWINDOW_DRAW_VIEW |
|
||||
ctxInterface.DRAWWINDOW_USE_WIDGET_LAYERS;
|
||||
let flags =
|
||||
ctxInterface.DRAWWINDOW_DRAW_CARET |
|
||||
ctxInterface.DRAWWINDOW_DRAW_VIEW |
|
||||
ctxInterface.DRAWWINDOW_USE_WIDGET_LAYERS;
|
||||
|
||||
if (!(0 <= browserRect.left &&
|
||||
0 <= browserRect.top &&
|
||||
win.innerWidth >= browserRect.width &&
|
||||
win.innerHeight >= browserRect.height)) {
|
||||
if (
|
||||
!(
|
||||
0 <= browserRect.left &&
|
||||
0 <= browserRect.top &&
|
||||
win.innerWidth >= browserRect.width &&
|
||||
win.innerHeight >= browserRect.height
|
||||
)
|
||||
) {
|
||||
logger.error(`Invalid window dimensions:
|
||||
browserRect.left: ${browserRect.left}
|
||||
browserRect.top: ${browserRect.top}
|
||||
|
@ -499,16 +555,21 @@ browserRect.height: ${browserRect.height}`);
|
|||
await this.driver.listener.reftestWait(url, this.remote);
|
||||
|
||||
canvas = capture.canvas(
|
||||
win,
|
||||
0, // left
|
||||
0, // top
|
||||
browserRect.width,
|
||||
browserRect.height,
|
||||
{canvas, flags});
|
||||
win,
|
||||
0, // left
|
||||
0, // top
|
||||
browserRect.width,
|
||||
browserRect.height,
|
||||
{ canvas, flags }
|
||||
);
|
||||
}
|
||||
if (canvas.width !== browserRect.width ||
|
||||
canvas.height !== browserRect.height) {
|
||||
logger.warn(`Canvas dimensions changed to ${canvas.width}x${canvas.height}`);
|
||||
if (
|
||||
canvas.width !== browserRect.width ||
|
||||
canvas.height !== browserRect.height
|
||||
) {
|
||||
logger.warn(
|
||||
`Canvas dimensions changed to ${canvas.width}x${canvas.height}`
|
||||
);
|
||||
reuseCanvas = false;
|
||||
cache = false;
|
||||
}
|
||||
|
@ -516,7 +577,7 @@ browserRect.height: ${browserRect.height}`);
|
|||
sizedCache.set(url, canvas);
|
||||
}
|
||||
this.urlCount.set(url, remainingCount - 1);
|
||||
return {canvas, reuseCanvas};
|
||||
return { canvas, reuseCanvas };
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -7,36 +7,43 @@
|
|||
const CC = Components.Constructor;
|
||||
|
||||
const ServerSocket = CC(
|
||||
"@mozilla.org/network/server-socket;1",
|
||||
"nsIServerSocket",
|
||||
"initSpecialConnection");
|
||||
"@mozilla.org/network/server-socket;1",
|
||||
"nsIServerSocket",
|
||||
"initSpecialConnection"
|
||||
);
|
||||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const {assert} = ChromeUtils.import("chrome://marionette/content/assert.js");
|
||||
const {GeckoDriver} = ChromeUtils.import("chrome://marionette/content/driver.js");
|
||||
const {WebElement} = ChromeUtils.import("chrome://marionette/content/element.js");
|
||||
const {
|
||||
error,
|
||||
UnknownCommandError,
|
||||
} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const {
|
||||
Command,
|
||||
Message,
|
||||
Response,
|
||||
} = ChromeUtils.import("chrome://marionette/content/message.js");
|
||||
const {Log} = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
const {MarionettePrefs} = ChromeUtils.import("chrome://marionette/content/prefs.js", null);
|
||||
const {DebuggerTransport} = ChromeUtils.import("chrome://marionette/content/transport.js", null);
|
||||
const { assert } = ChromeUtils.import("chrome://marionette/content/assert.js");
|
||||
const { GeckoDriver } = ChromeUtils.import(
|
||||
"chrome://marionette/content/driver.js"
|
||||
);
|
||||
const { WebElement } = ChromeUtils.import(
|
||||
"chrome://marionette/content/element.js"
|
||||
);
|
||||
const { error, UnknownCommandError } = ChromeUtils.import(
|
||||
"chrome://marionette/content/error.js"
|
||||
);
|
||||
const { Command, Message, Response } = ChromeUtils.import(
|
||||
"chrome://marionette/content/message.js"
|
||||
);
|
||||
const { Log } = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
const { MarionettePrefs } = ChromeUtils.import(
|
||||
"chrome://marionette/content/prefs.js",
|
||||
null
|
||||
);
|
||||
const { DebuggerTransport } = ChromeUtils.import(
|
||||
"chrome://marionette/content/transport.js",
|
||||
null
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", Log.get);
|
||||
|
||||
const {KeepWhenOffline, LoopbackOnly} = Ci.nsIServerSocket;
|
||||
const { KeepWhenOffline, LoopbackOnly } = Ci.nsIServerSocket;
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"TCPConnection",
|
||||
"TCPListener",
|
||||
];
|
||||
this.EXPORTED_SYMBOLS = ["TCPConnection", "TCPListener"];
|
||||
|
||||
/** @namespace */
|
||||
this.server = {};
|
||||
|
@ -135,12 +142,17 @@ class TCPListener {
|
|||
let transport = new DebuggerTransport(input, output);
|
||||
|
||||
let conn = new TCPConnection(
|
||||
this.nextConnID++, transport, this.driverFactory.bind(this));
|
||||
this.nextConnID++,
|
||||
transport,
|
||||
this.driverFactory.bind(this)
|
||||
);
|
||||
conn.onclose = this.onConnectionClosed.bind(this);
|
||||
this.conns.add(conn);
|
||||
|
||||
logger.debug(`Accepted connection ${conn.id} ` +
|
||||
`from ${clientSocket.host}:${clientSocket.port}`);
|
||||
logger.debug(
|
||||
`Accepted connection ${conn.id} ` +
|
||||
`from ${clientSocket.host}:${clientSocket.port}`
|
||||
);
|
||||
conn.sayHello();
|
||||
transport.ready();
|
||||
}
|
||||
|
@ -212,7 +224,8 @@ class TCPConnection {
|
|||
// unable to determine how to respond
|
||||
if (!Array.isArray(data)) {
|
||||
let e = new TypeError(
|
||||
"Unable to unmarshal packet data: " + JSON.stringify(data));
|
||||
"Unable to unmarshal packet data: " + JSON.stringify(data)
|
||||
);
|
||||
error.report(e);
|
||||
return;
|
||||
}
|
||||
|
@ -260,7 +273,8 @@ class TCPConnection {
|
|||
let sendError = resp.sendError.bind(resp);
|
||||
|
||||
await this.despatch(cmd, resp)
|
||||
.then(sendResponse, sendError).catch(error.report);
|
||||
.then(sendResponse, sendError)
|
||||
.catch(error.report);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -282,15 +296,17 @@ class TCPConnection {
|
|||
}
|
||||
|
||||
if (cmd.name != "WebDriver:NewSession") {
|
||||
assert.session(this.driver,
|
||||
"Tried to run command without establishing a connection");
|
||||
assert.session(
|
||||
this.driver,
|
||||
"Tried to run command without establishing a connection"
|
||||
);
|
||||
}
|
||||
|
||||
let rv = await fn.bind(this.driver)(cmd);
|
||||
|
||||
if (rv != null) {
|
||||
if (rv instanceof WebElement || typeof rv != "object") {
|
||||
resp.body = {value: rv};
|
||||
resp.body = { value: rv };
|
||||
} else {
|
||||
resp.body = rv;
|
||||
}
|
||||
|
@ -392,7 +408,7 @@ class TCPConnection {
|
|||
}
|
||||
|
||||
log_(msg) {
|
||||
let dir = (msg.origin == Message.Origin.Client ? "->" : "<-");
|
||||
let dir = msg.origin == Message.Origin.Client ? "->" : "<-";
|
||||
logger.debug(`${this.id} ${dir} ${msg}`);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,12 +6,17 @@
|
|||
|
||||
const CC = Components.Constructor;
|
||||
|
||||
const {EventEmitter} = ChromeUtils.import("resource://gre/modules/EventEmitter.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { EventEmitter } = ChromeUtils.import(
|
||||
"resource://gre/modules/EventEmitter.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const IOUtil = Cc["@mozilla.org/io-util;1"].getService(Ci.nsIIOUtil);
|
||||
const ScriptableInputStream = CC("@mozilla.org/scriptableinputstream;1",
|
||||
"nsIScriptableInputStream", "init");
|
||||
const ScriptableInputStream = CC(
|
||||
"@mozilla.org/scriptableinputstream;1",
|
||||
"nsIScriptableInputStream",
|
||||
"init"
|
||||
);
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["StreamUtils"];
|
||||
|
||||
|
@ -68,8 +73,9 @@ function StreamCopier(input, output, length) {
|
|||
if (IOUtil.outputStreamIsBuffered(output)) {
|
||||
this.output = output;
|
||||
} else {
|
||||
this.output = Cc["@mozilla.org/network/buffered-output-stream;1"]
|
||||
.createInstance(Ci.nsIBufferedOutputStream);
|
||||
this.output = Cc[
|
||||
"@mozilla.org/network/buffered-output-stream;1"
|
||||
].createInstance(Ci.nsIBufferedOutputStream);
|
||||
this.output.init(output, BUFFER_SIZE);
|
||||
}
|
||||
this._length = length;
|
||||
|
@ -100,7 +106,6 @@ function StreamCopier(input, output, length) {
|
|||
StreamCopier._nextId = 0;
|
||||
|
||||
StreamCopier.prototype = {
|
||||
|
||||
copy() {
|
||||
// Dispatch to the next tick so that it's possible to attach a progress
|
||||
// event listener, even for extremely fast copies (like when testing).
|
||||
|
@ -133,8 +138,7 @@ StreamCopier.prototype = {
|
|||
}
|
||||
|
||||
this._amountLeft -= bytesCopied;
|
||||
this._debug("Copied: " + bytesCopied +
|
||||
", Left: " + this._amountLeft);
|
||||
this._debug("Copied: " + bytesCopied + ", Left: " + this._amountLeft);
|
||||
this._emitProgress();
|
||||
|
||||
if (this._amountLeft === 0) {
|
||||
|
@ -158,8 +162,10 @@ StreamCopier.prototype = {
|
|||
try {
|
||||
this.output.flush();
|
||||
} catch (e) {
|
||||
if (e.result == Cr.NS_BASE_STREAM_WOULD_BLOCK ||
|
||||
e.result == Cr.NS_ERROR_FAILURE) {
|
||||
if (
|
||||
e.result == Cr.NS_BASE_STREAM_WOULD_BLOCK ||
|
||||
e.result == Cr.NS_ERROR_FAILURE
|
||||
) {
|
||||
this._debug("Flush would block, will retry");
|
||||
this._streamReadyCallback = this._flush;
|
||||
this._debug("Waiting for output stream");
|
||||
|
@ -189,9 +195,7 @@ StreamCopier.prototype = {
|
|||
this._streamReadyCallback();
|
||||
},
|
||||
|
||||
_debug() {
|
||||
},
|
||||
|
||||
_debug() {},
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,17 +4,21 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { AppConstants } = ChromeUtils.import(
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
const {
|
||||
error,
|
||||
stack,
|
||||
TimeoutError,
|
||||
} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const {truncate} = ChromeUtils.import("chrome://marionette/content/format.js");
|
||||
const {Log} = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
const { error, stack, TimeoutError } = ChromeUtils.import(
|
||||
"chrome://marionette/content/error.js"
|
||||
);
|
||||
const { truncate } = ChromeUtils.import(
|
||||
"chrome://marionette/content/format.js"
|
||||
);
|
||||
const { Log } = ChromeUtils.import("chrome://marionette/content/log.js");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "log", Log.get);
|
||||
|
||||
|
@ -31,11 +35,10 @@ this.EXPORTED_SYMBOLS = [
|
|||
"waitForObserverTopic",
|
||||
];
|
||||
|
||||
const {TYPE_ONE_SHOT, TYPE_REPEATING_SLACK} = Ci.nsITimer;
|
||||
const { TYPE_ONE_SHOT, TYPE_REPEATING_SLACK } = Ci.nsITimer;
|
||||
|
||||
const PROMISE_TIMEOUT = AppConstants.DEBUG ? 4500 : 1500;
|
||||
|
||||
|
||||
/**
|
||||
* Dispatch a function to be executed on the main thread.
|
||||
*
|
||||
|
@ -115,7 +118,7 @@ function executeSoon(func) {
|
|||
* @throws {RangeError}
|
||||
* If `timeout` or `interval` are not unsigned integers.
|
||||
*/
|
||||
function PollPromise(func, {timeout = null, interval = 10} = {}) {
|
||||
function PollPromise(func, { timeout = null, interval = 10 } = {}) {
|
||||
const timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
|
||||
if (typeof func != "function") {
|
||||
|
@ -127,8 +130,10 @@ function PollPromise(func, {timeout = null, interval = 10} = {}) {
|
|||
if (typeof interval != "number") {
|
||||
throw new TypeError();
|
||||
}
|
||||
if ((timeout && (!Number.isInteger(timeout) || timeout < 0)) ||
|
||||
(!Number.isInteger(interval) || interval < 0)) {
|
||||
if (
|
||||
(timeout && (!Number.isInteger(timeout) || timeout < 0)) ||
|
||||
(!Number.isInteger(interval) || interval < 0)
|
||||
) {
|
||||
throw new RangeError();
|
||||
}
|
||||
|
||||
|
@ -141,18 +146,22 @@ function PollPromise(func, {timeout = null, interval = 10} = {}) {
|
|||
}
|
||||
|
||||
let evalFn = () => {
|
||||
new Promise(func).then(resolve, rejected => {
|
||||
if (error.isError(rejected)) {
|
||||
throw rejected;
|
||||
}
|
||||
new Promise(func)
|
||||
.then(resolve, rejected => {
|
||||
if (error.isError(rejected)) {
|
||||
throw rejected;
|
||||
}
|
||||
|
||||
// return if there is a timeout and set to 0,
|
||||
// allowing |func| to be evaluated at least once
|
||||
if (typeof end != "undefined" &&
|
||||
(start == end || new Date().getTime() >= end)) {
|
||||
resolve(rejected);
|
||||
}
|
||||
}).catch(reject);
|
||||
// return if there is a timeout and set to 0,
|
||||
// allowing |func| to be evaluated at least once
|
||||
if (
|
||||
typeof end != "undefined" &&
|
||||
(start == end || new Date().getTime() >= end)
|
||||
) {
|
||||
resolve(rejected);
|
||||
}
|
||||
})
|
||||
.catch(reject);
|
||||
};
|
||||
|
||||
// the repeating slack timer waits |interval|
|
||||
|
@ -160,13 +169,16 @@ function PollPromise(func, {timeout = null, interval = 10} = {}) {
|
|||
evalFn();
|
||||
|
||||
timer.init(evalFn, interval, TYPE_REPEATING_SLACK);
|
||||
}).then(res => {
|
||||
timer.cancel();
|
||||
return res;
|
||||
}, err => {
|
||||
timer.cancel();
|
||||
throw err;
|
||||
});
|
||||
}).then(
|
||||
res => {
|
||||
timer.cancel();
|
||||
return res;
|
||||
},
|
||||
err => {
|
||||
timer.cancel();
|
||||
throw err;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -198,8 +210,10 @@ function PollPromise(func, {timeout = null, interval = 10} = {}) {
|
|||
* @throws {RangeError}
|
||||
* If `timeout` is not an unsigned integer.
|
||||
*/
|
||||
function TimedPromise(fn,
|
||||
{timeout = PROMISE_TIMEOUT, throws = TimeoutError} = {}) {
|
||||
function TimedPromise(
|
||||
fn,
|
||||
{ timeout = PROMISE_TIMEOUT, throws = TimeoutError } = {}
|
||||
) {
|
||||
const timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
|
||||
if (typeof fn != "function") {
|
||||
|
@ -225,20 +239,23 @@ function TimedPromise(fn,
|
|||
}
|
||||
};
|
||||
|
||||
timer.initWithCallback({notify: bail}, timeout, TYPE_ONE_SHOT);
|
||||
timer.initWithCallback({ notify: bail }, timeout, TYPE_ONE_SHOT);
|
||||
|
||||
try {
|
||||
fn(resolve, reject);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
}).then(res => {
|
||||
timer.cancel();
|
||||
return res;
|
||||
}, err => {
|
||||
timer.cancel();
|
||||
throw err;
|
||||
});
|
||||
}).then(
|
||||
res => {
|
||||
timer.cancel();
|
||||
return res;
|
||||
},
|
||||
err => {
|
||||
timer.cancel();
|
||||
throw err;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -259,7 +276,7 @@ function Sleep(timeout) {
|
|||
if (typeof timeout != "number") {
|
||||
throw new TypeError();
|
||||
}
|
||||
return new TimedPromise(() => {}, {timeout, throws: null});
|
||||
return new TimedPromise(() => {}, { timeout, throws: null });
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -355,7 +372,7 @@ function IdlePromise(win) {
|
|||
* Time since last event firing, before `fn` will be invoked.
|
||||
*/
|
||||
class DebounceCallback {
|
||||
constructor(fn, {timeout = 250} = {}) {
|
||||
constructor(fn, { timeout = 250 } = {}) {
|
||||
if (typeof fn != "function" || typeof timeout != "number") {
|
||||
throw new TypeError();
|
||||
}
|
||||
|
@ -370,10 +387,14 @@ class DebounceCallback {
|
|||
|
||||
handleEvent(ev) {
|
||||
this.timer.cancel();
|
||||
this.timer.initWithCallback(() => {
|
||||
this.timer.cancel();
|
||||
this.fn(ev);
|
||||
}, this.timeout, TYPE_ONE_SHOT);
|
||||
this.timer.initWithCallback(
|
||||
() => {
|
||||
this.timer.cancel();
|
||||
this.fn(ev);
|
||||
},
|
||||
this.timeout,
|
||||
TYPE_ONE_SHOT
|
||||
);
|
||||
}
|
||||
}
|
||||
this.DebounceCallback = DebounceCallback;
|
||||
|
@ -435,8 +456,11 @@ this.DebounceCallback = DebounceCallback;
|
|||
* Promise which resolves to the received ``Event`` object, or rejects
|
||||
* in case of a failure.
|
||||
*/
|
||||
function waitForEvent(subject, eventName,
|
||||
{capture = false, checkFn = null, wantsUntrusted = false} = {}) {
|
||||
function waitForEvent(
|
||||
subject,
|
||||
eventName,
|
||||
{ capture = false, checkFn = null, wantsUntrusted = false } = {}
|
||||
) {
|
||||
if (subject == null || !("addEventListener" in subject)) {
|
||||
throw new TypeError();
|
||||
}
|
||||
|
@ -454,23 +478,28 @@ function waitForEvent(subject, eventName,
|
|||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
subject.addEventListener(eventName, function listener(event) {
|
||||
log.trace(`Received DOM event ${event.type} for ${event.target}`);
|
||||
try {
|
||||
if (checkFn && !checkFn(event)) {
|
||||
return;
|
||||
}
|
||||
subject.removeEventListener(eventName, listener, capture);
|
||||
executeSoon(() => resolve(event));
|
||||
} catch (ex) {
|
||||
subject.addEventListener(
|
||||
eventName,
|
||||
function listener(event) {
|
||||
log.trace(`Received DOM event ${event.type} for ${event.target}`);
|
||||
try {
|
||||
if (checkFn && !checkFn(event)) {
|
||||
return;
|
||||
}
|
||||
subject.removeEventListener(eventName, listener, capture);
|
||||
} catch (ex2) {
|
||||
// Maybe the provided object does not support removeEventListener.
|
||||
executeSoon(() => resolve(event));
|
||||
} catch (ex) {
|
||||
try {
|
||||
subject.removeEventListener(eventName, listener, capture);
|
||||
} catch (ex2) {
|
||||
// Maybe the provided object does not support removeEventListener.
|
||||
}
|
||||
executeSoon(() => reject(ex));
|
||||
}
|
||||
executeSoon(() => reject(ex));
|
||||
}
|
||||
}, capture, wantsUntrusted);
|
||||
},
|
||||
capture,
|
||||
wantsUntrusted
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -495,8 +524,11 @@ function waitForEvent(subject, eventName,
|
|||
* Promise which resolves to the data property of the received
|
||||
* ``Message``.
|
||||
*/
|
||||
function waitForMessage(messageManager, messageName,
|
||||
{checkFn = undefined} = {}) {
|
||||
function waitForMessage(
|
||||
messageManager,
|
||||
messageName,
|
||||
{ checkFn = undefined } = {}
|
||||
) {
|
||||
if (messageManager == null || !("addMessageListener" in messageManager)) {
|
||||
throw new TypeError();
|
||||
}
|
||||
|
@ -542,7 +574,7 @@ function waitForMessage(messageManager, messageName,
|
|||
* Promise which resolves to an array of ``subject``, and ``data`` from
|
||||
* the observed notification.
|
||||
*/
|
||||
function waitForObserverTopic(topic, {checkFn = null} = {}) {
|
||||
function waitForObserverTopic(topic, { checkFn = null } = {}) {
|
||||
if (typeof topic != "string") {
|
||||
throw new TypeError();
|
||||
}
|
||||
|
@ -558,7 +590,7 @@ function waitForObserverTopic(topic, {checkFn = null} = {}) {
|
|||
return;
|
||||
}
|
||||
Services.obs.removeObserver(observer, topic);
|
||||
resolve({subject, data});
|
||||
resolve({ subject, data });
|
||||
} catch (ex) {
|
||||
Services.obs.removeObserver(observer, topic);
|
||||
reject(ex);
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {action} = ChromeUtils.import("chrome://marionette/content/action.js");
|
||||
const {InvalidArgumentError} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const { action } = ChromeUtils.import("chrome://marionette/content/action.js");
|
||||
const { InvalidArgumentError } = ChromeUtils.import(
|
||||
"chrome://marionette/content/error.js"
|
||||
);
|
||||
|
||||
const XHTMLNS = "http://www.w3.org/1999/xhtml";
|
||||
|
||||
|
@ -18,48 +20,63 @@ const domEl = {
|
|||
action.inputStateMap = new Map();
|
||||
|
||||
add_test(function test_createAction() {
|
||||
Assert.throws(() => new action.Action(), InvalidArgumentError,
|
||||
"Missing Action constructor args");
|
||||
Assert.throws(() => new action.Action(1, 2), InvalidArgumentError,
|
||||
"Missing Action constructor args");
|
||||
Assert.throws(
|
||||
() => new action.Action(1, 2, "sometype"), /Expected string/, "Non-string arguments.");
|
||||
() => new action.Action(),
|
||||
InvalidArgumentError,
|
||||
"Missing Action constructor args"
|
||||
);
|
||||
Assert.throws(
|
||||
() => new action.Action(1, 2),
|
||||
InvalidArgumentError,
|
||||
"Missing Action constructor args"
|
||||
);
|
||||
Assert.throws(
|
||||
() => new action.Action(1, 2, "sometype"),
|
||||
/Expected string/,
|
||||
"Non-string arguments."
|
||||
);
|
||||
ok(new action.Action("id", "sometype", "sometype"));
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_defaultPointerParameters() {
|
||||
let defaultParameters = {pointerType: action.PointerType.Mouse};
|
||||
let defaultParameters = { pointerType: action.PointerType.Mouse };
|
||||
deepEqual(action.PointerParameters.fromJSON(), defaultParameters);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_processPointerParameters() {
|
||||
let check = (regex, message, arg) => checkErrors(
|
||||
regex, action.PointerParameters.fromJSON, [arg], message);
|
||||
let check = (regex, message, arg) =>
|
||||
checkErrors(regex, action.PointerParameters.fromJSON, [arg], message);
|
||||
let parametersData;
|
||||
for (let d of ["foo", "", "get", "Get"]) {
|
||||
parametersData = {pointerType: d};
|
||||
let message = `parametersData: [pointerType: ${parametersData.pointerType}]`;
|
||||
parametersData = { pointerType: d };
|
||||
let message = `parametersData: [pointerType: ${
|
||||
parametersData.pointerType
|
||||
}]`;
|
||||
check(/Unknown pointerType/, message, parametersData);
|
||||
}
|
||||
parametersData.pointerType = "mouse"; // TODO "pen";
|
||||
deepEqual(action.PointerParameters.fromJSON(parametersData),
|
||||
{pointerType: "mouse"}); // TODO action.PointerType.Pen});
|
||||
deepEqual(action.PointerParameters.fromJSON(parametersData), {
|
||||
pointerType: "mouse",
|
||||
}); // TODO action.PointerType.Pen});
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_processPointerUpDownAction() {
|
||||
let actionItem = {type: "pointerDown"};
|
||||
let actionSequence = {type: "pointer", id: "some_id"};
|
||||
let actionItem = { type: "pointerDown" };
|
||||
let actionSequence = { type: "pointer", id: "some_id" };
|
||||
for (let d of [-1, "a"]) {
|
||||
actionItem.button = d;
|
||||
checkErrors(
|
||||
/Expected 'button' \(.*\) to be >= 0/, action.Action.fromJSON, [actionSequence, actionItem],
|
||||
`button: ${actionItem.button}`);
|
||||
/Expected 'button' \(.*\) to be >= 0/,
|
||||
action.Action.fromJSON,
|
||||
[actionSequence, actionItem],
|
||||
`button: ${actionItem.button}`
|
||||
);
|
||||
}
|
||||
actionItem.button = 5;
|
||||
let act = action.Action.fromJSON(actionSequence, actionItem);
|
||||
|
@ -70,13 +87,18 @@ add_test(function test_processPointerUpDownAction() {
|
|||
|
||||
add_test(function test_validateActionDurationAndCoordinates() {
|
||||
let actionItem = {};
|
||||
let actionSequence = {id: "some_id"};
|
||||
let actionSequence = { id: "some_id" };
|
||||
let check = function(type, subtype, message = undefined) {
|
||||
message = message || `duration: ${actionItem.duration}, subtype: ${subtype}`;
|
||||
message =
|
||||
message || `duration: ${actionItem.duration}, subtype: ${subtype}`;
|
||||
actionItem.type = subtype;
|
||||
actionSequence.type = type;
|
||||
checkErrors(/Expected '.*' \(.*\) to be >= 0/,
|
||||
action.Action.fromJSON, [actionSequence, actionItem], message);
|
||||
checkErrors(
|
||||
/Expected '.*' \(.*\) to be >= 0/,
|
||||
action.Action.fromJSON,
|
||||
[actionSequence, actionItem],
|
||||
message
|
||||
);
|
||||
};
|
||||
for (let d of [-1, "a"]) {
|
||||
actionItem.duration = d;
|
||||
|
@ -88,45 +110,52 @@ add_test(function test_validateActionDurationAndCoordinates() {
|
|||
actionItem[name] = "a";
|
||||
actionItem.type = "pointerMove";
|
||||
actionSequence.type = "pointer";
|
||||
checkErrors(/Expected '.*' \(.*\) to be an Integer/,
|
||||
action.Action.fromJSON, [actionSequence, actionItem],
|
||||
`duration: ${actionItem.duration}, subtype: pointerMove`);
|
||||
checkErrors(
|
||||
/Expected '.*' \(.*\) to be an Integer/,
|
||||
action.Action.fromJSON,
|
||||
[actionSequence, actionItem],
|
||||
`duration: ${actionItem.duration}, subtype: pointerMove`
|
||||
);
|
||||
}
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_processPointerMoveActionOriginValidation() {
|
||||
let actionSequence = {type: "pointer", id: "some_id"};
|
||||
let actionItem = {duration: 5000, type: "pointerMove"};
|
||||
for (let d of [-1, {a: "blah"}, []]) {
|
||||
let actionSequence = { type: "pointer", id: "some_id" };
|
||||
let actionItem = { duration: 5000, type: "pointerMove" };
|
||||
for (let d of [-1, { a: "blah" }, []]) {
|
||||
actionItem.origin = d;
|
||||
|
||||
checkErrors(/Expected \'origin\' to be undefined, "viewport", "pointer", or an element/,
|
||||
action.Action.fromJSON,
|
||||
[actionSequence, actionItem],
|
||||
`actionItem.origin: (${getTypeString(d)})`);
|
||||
checkErrors(
|
||||
/Expected \'origin\' to be undefined, "viewport", "pointer", or an element/,
|
||||
action.Action.fromJSON,
|
||||
[actionSequence, actionItem],
|
||||
`actionItem.origin: (${getTypeString(d)})`
|
||||
);
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_processPointerMoveActionOriginStringValidation() {
|
||||
let actionSequence = {type: "pointer", id: "some_id"};
|
||||
let actionItem = {duration: 5000, type: "pointerMove"};
|
||||
let actionSequence = { type: "pointer", id: "some_id" };
|
||||
let actionItem = { duration: 5000, type: "pointerMove" };
|
||||
for (let d of ["a", "", "get", "Get"]) {
|
||||
actionItem.origin = d;
|
||||
checkErrors(/Unknown pointer-move origin/,
|
||||
action.Action.fromJSON,
|
||||
[actionSequence, actionItem],
|
||||
`actionItem.origin: ${d}`);
|
||||
checkErrors(
|
||||
/Unknown pointer-move origin/,
|
||||
action.Action.fromJSON,
|
||||
[actionSequence, actionItem],
|
||||
`actionItem.origin: ${d}`
|
||||
);
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_processPointerMoveActionElementOrigin() {
|
||||
let actionSequence = {type: "pointer", id: "some_id"};
|
||||
let actionItem = {duration: 5000, type: "pointerMove"};
|
||||
let actionSequence = { type: "pointer", id: "some_id" };
|
||||
let actionItem = { duration: 5000, type: "pointerMove" };
|
||||
actionItem.origin = domEl;
|
||||
let a = action.Action.fromJSON(actionSequence, actionItem);
|
||||
deepEqual(a.origin, actionItem.origin);
|
||||
|
@ -134,16 +163,16 @@ add_test(function test_processPointerMoveActionElementOrigin() {
|
|||
});
|
||||
|
||||
add_test(function test_processPointerMoveActionDefaultOrigin() {
|
||||
let actionSequence = {type: "pointer", id: "some_id"};
|
||||
let actionSequence = { type: "pointer", id: "some_id" };
|
||||
// origin left undefined
|
||||
let actionItem = {duration: 5000, type: "pointerMove"};
|
||||
let actionItem = { duration: 5000, type: "pointerMove" };
|
||||
let a = action.Action.fromJSON(actionSequence, actionItem);
|
||||
deepEqual(a.origin, action.PointerOrigin.Viewport);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_processPointerMoveAction() {
|
||||
let actionSequence = {id: "some_id", type: "pointer"};
|
||||
let actionSequence = { id: "some_id", type: "pointer" };
|
||||
let actionItems = [
|
||||
{
|
||||
duration: 5000,
|
||||
|
@ -191,7 +220,7 @@ add_test(function test_processPointerMoveAction() {
|
|||
});
|
||||
|
||||
add_test(function test_computePointerDestinationViewport() {
|
||||
let act = {type: "pointerMove", x: 100, y: 200, origin: "viewport"};
|
||||
let act = { type: "pointerMove", x: 100, y: 200, origin: "viewport" };
|
||||
let inputState = new action.InputState.Pointer(action.PointerType.Mouse);
|
||||
// these values should not affect the outcome
|
||||
inputState.x = "99";
|
||||
|
@ -204,7 +233,7 @@ add_test(function test_computePointerDestinationViewport() {
|
|||
});
|
||||
|
||||
add_test(function test_computePointerDestinationPointer() {
|
||||
let act = {type: "pointerMove", x: 100, y: 200, origin: "pointer"};
|
||||
let act = { type: "pointerMove", x: 100, y: 200, origin: "pointer" };
|
||||
let inputState = new action.InputState.Pointer(action.PointerType.Mouse);
|
||||
inputState.x = 10;
|
||||
inputState.y = 99;
|
||||
|
@ -212,29 +241,30 @@ add_test(function test_computePointerDestinationPointer() {
|
|||
equal(act.x + inputState.x, target.x);
|
||||
equal(act.y + inputState.y, target.y);
|
||||
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_computePointerDestinationElement() {
|
||||
// origin represents a web element
|
||||
// using an object literal instead to test default case in computePointerDestination
|
||||
let act = {type: "pointerMove", x: 100, y: 200, origin: {}};
|
||||
let act = { type: "pointerMove", x: 100, y: 200, origin: {} };
|
||||
let inputState = new action.InputState.Pointer(action.PointerType.Mouse);
|
||||
let elementCenter = {x: 10, y: 99};
|
||||
let elementCenter = { x: 10, y: 99 };
|
||||
let target = action.computePointerDestination(act, inputState, elementCenter);
|
||||
equal(act.x + elementCenter.x, target.x);
|
||||
equal(act.y + elementCenter.y, target.y);
|
||||
|
||||
Assert.throws(
|
||||
() => action.computePointerDestination(act, inputState, {a: 1}),
|
||||
InvalidArgumentError,
|
||||
"Invalid element center coordinates.");
|
||||
() => action.computePointerDestination(act, inputState, { a: 1 }),
|
||||
InvalidArgumentError,
|
||||
"Invalid element center coordinates."
|
||||
);
|
||||
|
||||
Assert.throws(
|
||||
() => action.computePointerDestination(act, inputState, undefined),
|
||||
InvalidArgumentError,
|
||||
"Undefined element center coordinates.");
|
||||
() => action.computePointerDestination(act, inputState, undefined),
|
||||
InvalidArgumentError,
|
||||
"Undefined element center coordinates."
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -280,8 +310,8 @@ add_test(function test_processPointerAction() {
|
|||
});
|
||||
|
||||
add_test(function test_processPauseAction() {
|
||||
let actionItem = {type: "pause", duration: 5000};
|
||||
let actionSequence = {id: "some_id"};
|
||||
let actionItem = { type: "pause", duration: 5000 };
|
||||
let actionSequence = { id: "some_id" };
|
||||
for (let type of ["none", "key", "pointer"]) {
|
||||
actionSequence.type = type;
|
||||
let act = action.Action.fromJSON(actionSequence, actionItem);
|
||||
|
@ -299,11 +329,16 @@ add_test(function test_processPauseAction() {
|
|||
});
|
||||
|
||||
add_test(function test_processActionSubtypeValidation() {
|
||||
let actionItem = {type: "dancing"};
|
||||
let actionSequence = {id: "some_id"};
|
||||
let actionItem = { type: "dancing" };
|
||||
let actionSequence = { id: "some_id" };
|
||||
let check = function(regex) {
|
||||
let message = `type: ${actionSequence.type}, subtype: ${actionItem.type}`;
|
||||
checkErrors(regex, action.Action.fromJSON, [actionSequence, actionItem], message);
|
||||
checkErrors(
|
||||
regex,
|
||||
action.Action.fromJSON,
|
||||
[actionSequence, actionItem],
|
||||
message
|
||||
);
|
||||
};
|
||||
for (let type of ["none", "key", "pointer"]) {
|
||||
actionSequence.type = type;
|
||||
|
@ -313,16 +348,22 @@ add_test(function test_processActionSubtypeValidation() {
|
|||
});
|
||||
|
||||
add_test(function test_processKeyActionUpDown() {
|
||||
let actionSequence = {type: "key", id: "some_id"};
|
||||
let actionItem = {type: "keyDown"};
|
||||
let actionSequence = { type: "key", id: "some_id" };
|
||||
let actionItem = { type: "keyDown" };
|
||||
|
||||
for (let v of [-1, undefined, [], ["a"], {length: 1}, null]) {
|
||||
for (let v of [-1, undefined, [], ["a"], { length: 1 }, null]) {
|
||||
actionItem.value = v;
|
||||
let message = `actionItem.value: (${getTypeString(v)})`;
|
||||
Assert.throws(() => action.Action.fromJSON(actionSequence, actionItem),
|
||||
InvalidArgumentError, message);
|
||||
Assert.throws(() => action.Action.fromJSON(actionSequence, actionItem),
|
||||
/Expected 'value' to be a string that represents single code point/, message);
|
||||
Assert.throws(
|
||||
() => action.Action.fromJSON(actionSequence, actionItem),
|
||||
InvalidArgumentError,
|
||||
message
|
||||
);
|
||||
Assert.throws(
|
||||
() => action.Action.fromJSON(actionSequence, actionItem),
|
||||
/Expected 'value' to be a string that represents single code point/,
|
||||
message
|
||||
);
|
||||
}
|
||||
|
||||
actionItem.value = "\uE004";
|
||||
|
@ -337,40 +378,50 @@ add_test(function test_processKeyActionUpDown() {
|
|||
});
|
||||
|
||||
add_test(function test_processInputSourceActionSequenceValidation() {
|
||||
let actionSequence = {type: "swim", id: "some id"};
|
||||
let check = (message, regex) => checkErrors(
|
||||
regex, action.Sequence.fromJSON, [actionSequence], message);
|
||||
let actionSequence = { type: "swim", id: "some id" };
|
||||
let check = (message, regex) =>
|
||||
checkErrors(regex, action.Sequence.fromJSON, [actionSequence], message);
|
||||
check(`actionSequence.type: ${actionSequence.type}`, /Unknown action type/);
|
||||
action.inputStateMap.clear();
|
||||
|
||||
actionSequence.type = "none";
|
||||
actionSequence.id = -1;
|
||||
check(`actionSequence.id: ${getTypeString(actionSequence.id)}`,
|
||||
/Expected 'id' to be a string/);
|
||||
check(
|
||||
`actionSequence.id: ${getTypeString(actionSequence.id)}`,
|
||||
/Expected 'id' to be a string/
|
||||
);
|
||||
action.inputStateMap.clear();
|
||||
|
||||
actionSequence.id = undefined;
|
||||
check(`actionSequence.id: ${getTypeString(actionSequence.id)}`,
|
||||
/Expected 'id' to be defined/);
|
||||
check(
|
||||
`actionSequence.id: ${getTypeString(actionSequence.id)}`,
|
||||
/Expected 'id' to be defined/
|
||||
);
|
||||
action.inputStateMap.clear();
|
||||
|
||||
actionSequence.id = "some_id";
|
||||
actionSequence.actions = -1;
|
||||
check(`actionSequence.actions: ${getTypeString(actionSequence.actions)}`,
|
||||
/Expected 'actionSequence.actions' to be an array/);
|
||||
check(
|
||||
`actionSequence.actions: ${getTypeString(actionSequence.actions)}`,
|
||||
/Expected 'actionSequence.actions' to be an array/
|
||||
);
|
||||
action.inputStateMap.clear();
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_processInputSourceActionSequence() {
|
||||
let actionItem = {type: "pause", duration: 5};
|
||||
let actionItem = { type: "pause", duration: 5 };
|
||||
let actionSequence = {
|
||||
type: "none",
|
||||
id: "some id",
|
||||
actions: [actionItem],
|
||||
};
|
||||
let expectedAction = new action.Action(actionSequence.id, "none", actionItem.type);
|
||||
let expectedAction = new action.Action(
|
||||
actionSequence.id,
|
||||
"none",
|
||||
actionItem.type
|
||||
);
|
||||
expectedAction.duration = actionItem.duration;
|
||||
let actions = action.Sequence.fromJSON(actionSequence);
|
||||
equal(actions.length, 1);
|
||||
|
@ -380,7 +431,7 @@ add_test(function test_processInputSourceActionSequence() {
|
|||
});
|
||||
|
||||
add_test(function test_processInputSourceActionSequencePointer() {
|
||||
let actionItem = {type: "pointerDown", button: 1};
|
||||
let actionItem = { type: "pointerDown", button: 1 };
|
||||
let actionSequence = {
|
||||
type: "pointer",
|
||||
id: "9",
|
||||
|
@ -390,7 +441,10 @@ add_test(function test_processInputSourceActionSequencePointer() {
|
|||
},
|
||||
};
|
||||
let expectedAction = new action.Action(
|
||||
actionSequence.id, actionSequence.type, actionItem.type);
|
||||
actionSequence.id,
|
||||
actionSequence.type,
|
||||
actionItem.type
|
||||
);
|
||||
expectedAction.pointerType = actionSequence.parameters.pointerType;
|
||||
expectedAction.button = actionItem.button;
|
||||
let actions = action.Sequence.fromJSON(actionSequence);
|
||||
|
@ -401,14 +455,17 @@ add_test(function test_processInputSourceActionSequencePointer() {
|
|||
});
|
||||
|
||||
add_test(function test_processInputSourceActionSequenceKey() {
|
||||
let actionItem = {type: "keyUp", value: "a"};
|
||||
let actionItem = { type: "keyUp", value: "a" };
|
||||
let actionSequence = {
|
||||
type: "key",
|
||||
id: "9",
|
||||
actions: [actionItem],
|
||||
};
|
||||
let expectedAction = new action.Action(
|
||||
actionSequence.id, actionSequence.type, actionItem.type);
|
||||
actionSequence.id,
|
||||
actionSequence.type,
|
||||
actionItem.type
|
||||
);
|
||||
expectedAction.value = actionItem.value;
|
||||
let actions = action.Sequence.fromJSON(actionSequence);
|
||||
equal(actions.length, 1);
|
||||
|
@ -417,10 +474,9 @@ add_test(function test_processInputSourceActionSequenceKey() {
|
|||
run_next_test();
|
||||
});
|
||||
|
||||
|
||||
add_test(function test_processInputSourceActionSequenceInputStateMap() {
|
||||
let id = "1";
|
||||
let actionItem = {type: "pause", duration: 5000};
|
||||
let actionItem = { type: "pause", duration: 5000 };
|
||||
let actionSequence = {
|
||||
type: "key",
|
||||
id,
|
||||
|
@ -428,8 +484,12 @@ add_test(function test_processInputSourceActionSequenceInputStateMap() {
|
|||
};
|
||||
let wrongInputState = new action.InputState.Null();
|
||||
action.inputStateMap.set(actionSequence.id, wrongInputState);
|
||||
checkErrors(/to be mapped to/, action.Sequence.fromJSON, [actionSequence],
|
||||
`${actionSequence.type} using ${wrongInputState}`);
|
||||
checkErrors(
|
||||
/to be mapped to/,
|
||||
action.Sequence.fromJSON,
|
||||
[actionSequence],
|
||||
`${actionSequence.type} using ${wrongInputState}`
|
||||
);
|
||||
action.inputStateMap.clear();
|
||||
let rightInputState = new action.InputState.Key();
|
||||
action.inputStateMap.set(id, rightInputState);
|
||||
|
@ -440,16 +500,18 @@ add_test(function test_processInputSourceActionSequenceInputStateMap() {
|
|||
});
|
||||
|
||||
add_test(function test_processPointerActionInputStateMap() {
|
||||
let actionItem = {type: "pointerDown"};
|
||||
let actionItem = { type: "pointerDown" };
|
||||
let id = "1";
|
||||
let parameters = {pointerType: "mouse"};
|
||||
let parameters = { pointerType: "mouse" };
|
||||
let a = new action.Action(id, "pointer", actionItem.type);
|
||||
let wrongInputState = new action.InputState.Key();
|
||||
action.inputStateMap.set(id, wrongInputState);
|
||||
checkErrors(
|
||||
/to be mapped to InputState whose type is/, action.processPointerAction,
|
||||
[id, parameters, a],
|
||||
`type "pointer" with ${wrongInputState.type} in inputState`);
|
||||
/to be mapped to InputState whose type is/,
|
||||
action.processPointerAction,
|
||||
[id, parameters, a],
|
||||
`type "pointer" with ${wrongInputState.type} in inputState`
|
||||
);
|
||||
action.inputStateMap.clear();
|
||||
|
||||
// TODO - uncomment once pen is supported
|
||||
|
@ -483,20 +545,32 @@ add_test(function test_createInputState() {
|
|||
equal(state.type, kind.toLowerCase());
|
||||
}
|
||||
}
|
||||
Assert.throws(() => new action.InputState.Pointer(), InvalidArgumentError,
|
||||
"Missing InputState.Pointer constructor arg");
|
||||
Assert.throws(() => new action.InputState.Pointer("foo"), InvalidArgumentError,
|
||||
"Invalid InputState.Pointer constructor arg");
|
||||
Assert.throws(
|
||||
() => new action.InputState.Pointer(),
|
||||
InvalidArgumentError,
|
||||
"Missing InputState.Pointer constructor arg"
|
||||
);
|
||||
Assert.throws(
|
||||
() => new action.InputState.Pointer("foo"),
|
||||
InvalidArgumentError,
|
||||
"Invalid InputState.Pointer constructor arg"
|
||||
);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_extractActionChainValidation() {
|
||||
for (let actions of [-1, "a", undefined, null]) {
|
||||
let message = `actions: ${getTypeString(actions)}`;
|
||||
Assert.throws(() => action.Chain.fromJSON(actions),
|
||||
InvalidArgumentError, message);
|
||||
Assert.throws(() => action.Chain.fromJSON(actions),
|
||||
/Expected 'actions' to be an array/, message);
|
||||
Assert.throws(
|
||||
() => action.Chain.fromJSON(actions),
|
||||
InvalidArgumentError,
|
||||
message
|
||||
);
|
||||
Assert.throws(
|
||||
() => action.Chain.fromJSON(actions),
|
||||
/Expected 'actions' to be an array/,
|
||||
message
|
||||
);
|
||||
}
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -507,13 +581,17 @@ add_test(function test_extractActionChainEmpty() {
|
|||
});
|
||||
|
||||
add_test(function test_extractActionChain_oneTickOneInput() {
|
||||
let actionItem = {type: "pause", duration: 5000};
|
||||
let actionItem = { type: "pause", duration: 5000 };
|
||||
let actionSequence = {
|
||||
type: "none",
|
||||
id: "some id",
|
||||
actions: [actionItem],
|
||||
};
|
||||
let expectedAction = new action.Action(actionSequence.id, "none", actionItem.type);
|
||||
let expectedAction = new action.Action(
|
||||
actionSequence.id,
|
||||
"none",
|
||||
actionItem.type
|
||||
);
|
||||
expectedAction.duration = actionItem.duration;
|
||||
let actionsByTick = action.Chain.fromJSON([actionSequence]);
|
||||
equal(1, actionsByTick.length);
|
||||
|
@ -561,20 +639,29 @@ add_test(function test_extractActionChain_twoAndThreeTicks() {
|
|||
id: "1",
|
||||
actions: keyActionItems,
|
||||
};
|
||||
let actionsByTick = action.Chain.fromJSON([keyActionSequence, mouseActionSequence]);
|
||||
let actionsByTick = action.Chain.fromJSON([
|
||||
keyActionSequence,
|
||||
mouseActionSequence,
|
||||
]);
|
||||
// number of ticks is same as longest action sequence
|
||||
equal(keyActionItems.length, actionsByTick.length);
|
||||
equal(2, actionsByTick[0].length);
|
||||
equal(2, actionsByTick[1].length);
|
||||
equal(1, actionsByTick[2].length);
|
||||
let expectedAction = new action.Action(keyActionSequence.id, "key", keyActionItems[2].type);
|
||||
let expectedAction = new action.Action(
|
||||
keyActionSequence.id,
|
||||
"key",
|
||||
keyActionItems[2].type
|
||||
);
|
||||
expectedAction.value = keyActionItems[2].value;
|
||||
deepEqual(actionsByTick[2][0], expectedAction);
|
||||
action.inputStateMap.clear();
|
||||
|
||||
// one empty action sequence
|
||||
actionsByTick = action.Chain.fromJSON(
|
||||
[keyActionSequence, {type: "none", id: "some", actions: []}]);
|
||||
actionsByTick = action.Chain.fromJSON([
|
||||
keyActionSequence,
|
||||
{ type: "none", id: "some", actions: [] },
|
||||
]);
|
||||
equal(keyActionItems.length, actionsByTick.length);
|
||||
equal(1, actionsByTick[0].length);
|
||||
action.inputStateMap.clear();
|
||||
|
@ -584,13 +671,13 @@ add_test(function test_extractActionChain_twoAndThreeTicks() {
|
|||
add_test(function test_computeTickDuration() {
|
||||
let expected = 8000;
|
||||
let tickActions = [
|
||||
{type: "none", subtype: "pause", duration: 5000},
|
||||
{type: "key", subtype: "pause", duration: 1000},
|
||||
{type: "pointer", subtype: "pointerMove", duration: 6000},
|
||||
{ type: "none", subtype: "pause", duration: 5000 },
|
||||
{ type: "key", subtype: "pause", duration: 1000 },
|
||||
{ type: "pointer", subtype: "pointerMove", duration: 6000 },
|
||||
// invalid because keyDown should not have duration, so duration should be ignored.
|
||||
{type: "key", subtype: "keyDown", duration: 100000},
|
||||
{type: "pointer", subtype: "pause", duration: expected},
|
||||
{type: "pointer", subtype: "pointerUp"},
|
||||
{ type: "key", subtype: "keyDown", duration: 100000 },
|
||||
{ type: "pointer", subtype: "pause", duration: expected },
|
||||
{ type: "pointer", subtype: "pointerUp" },
|
||||
];
|
||||
equal(expected, action.computeTickDuration(tickActions));
|
||||
run_next_test();
|
||||
|
@ -604,19 +691,18 @@ add_test(function test_computeTickDuration_empty() {
|
|||
add_test(function test_computeTickDuration_noDurations() {
|
||||
let tickActions = [
|
||||
// invalid because keyDown should not have duration, so duration should be ignored.
|
||||
{type: "key", subtype: "keyDown", duration: 100000},
|
||||
{ type: "key", subtype: "keyDown", duration: 100000 },
|
||||
// undefined duration permitted
|
||||
{type: "none", subtype: "pause"},
|
||||
{type: "pointer", subtype: "pointerMove"},
|
||||
{type: "pointer", subtype: "pointerDown"},
|
||||
{type: "key", subtype: "keyUp"},
|
||||
{ type: "none", subtype: "pause" },
|
||||
{ type: "pointer", subtype: "pointerMove" },
|
||||
{ type: "pointer", subtype: "pointerDown" },
|
||||
{ type: "key", subtype: "keyUp" },
|
||||
];
|
||||
|
||||
equal(0, action.computeTickDuration(tickActions));
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
|
||||
// helpers
|
||||
function getTypeString(obj) {
|
||||
return Object.prototype.toString.call(obj);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"use strict";
|
||||
/* eslint-disable no-array-constructor, no-new-object */
|
||||
|
||||
const {assert} = ChromeUtils.import("chrome://marionette/content/assert.js");
|
||||
const { assert } = ChromeUtils.import("chrome://marionette/content/assert.js");
|
||||
const {
|
||||
InvalidArgumentError,
|
||||
InvalidSessionIDError,
|
||||
|
@ -30,18 +30,24 @@ add_test(function test_acyclic() {
|
|||
cyclic.reference = cyclic;
|
||||
Assert.throws(() => assert.acyclic(cyclic, "", RangeError), RangeError);
|
||||
Assert.throws(() => assert.acyclic(cyclic, "foo"), /JavaScriptError: foo/);
|
||||
Assert.throws(() => assert.acyclic(cyclic, "bar", RangeError), /RangeError: bar/);
|
||||
Assert.throws(
|
||||
() => assert.acyclic(cyclic, "bar", RangeError),
|
||||
/RangeError: bar/
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_session() {
|
||||
assert.session({sessionID: "foo"});
|
||||
assert.session({ sessionID: "foo" });
|
||||
for (let typ of [null, undefined, ""]) {
|
||||
Assert.throws(() => assert.session({sessionId: typ}), InvalidSessionIDError);
|
||||
Assert.throws(
|
||||
() => assert.session({ sessionId: typ }),
|
||||
InvalidSessionIDError
|
||||
);
|
||||
}
|
||||
|
||||
Assert.throws(() => assert.session({sessionId: null}, "custom"), /custom/);
|
||||
Assert.throws(() => assert.session({ sessionId: null }, "custom"), /custom/);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -152,9 +158,9 @@ add_test(function test_string() {
|
|||
});
|
||||
|
||||
add_test(function test_open() {
|
||||
assert.open({closed: false});
|
||||
assert.open({ closed: false });
|
||||
|
||||
for (let typ of [null, undefined, {closed: true}]) {
|
||||
for (let typ of [null, undefined, { closed: true }]) {
|
||||
Assert.throws(() => assert.open(typ), NoSuchWindowError);
|
||||
}
|
||||
|
||||
|
@ -176,12 +182,12 @@ add_test(function test_object() {
|
|||
});
|
||||
|
||||
add_test(function test_in() {
|
||||
assert.in("foo", {foo: 42});
|
||||
assert.in("foo", { foo: 42 });
|
||||
for (let typ of [{}, 42, true, null, undefined]) {
|
||||
Assert.throws(() => assert.in("foo", typ), InvalidArgumentError);
|
||||
}
|
||||
|
||||
Assert.throws(() => assert.in("foo", {bar: 42}, "custom"), /custom/);
|
||||
Assert.throws(() => assert.in("foo", { bar: 42 }, "custom"), /custom/);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -201,8 +207,10 @@ add_test(function test_that() {
|
|||
equal(1, assert.that(n => n + 1)(1));
|
||||
Assert.throws(() => assert.that(() => false)(), InvalidArgumentError);
|
||||
Assert.throws(() => assert.that(val => val)(false), InvalidArgumentError);
|
||||
Assert.throws(() => assert.that(val => val, "foo", SessionNotCreatedError)(false),
|
||||
SessionNotCreatedError);
|
||||
Assert.throws(
|
||||
() => assert.that(val => val, "foo", SessionNotCreatedError)(false),
|
||||
SessionNotCreatedError
|
||||
);
|
||||
|
||||
Assert.throws(() => assert.that(() => false, "custom")(), /custom/);
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
const {Context} = ChromeUtils.import("chrome://marionette/content/browser.js");
|
||||
const { Context } = ChromeUtils.import(
|
||||
"chrome://marionette/content/browser.js"
|
||||
);
|
||||
|
||||
add_test(function test_Context() {
|
||||
ok(Context.hasOwnProperty("Chrome"));
|
||||
|
|
|
@ -4,9 +4,13 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {Preferences} = ChromeUtils.import("resource://gre/modules/Preferences.jsm");
|
||||
const { Preferences } = ChromeUtils.import(
|
||||
"resource://gre/modules/Preferences.jsm"
|
||||
);
|
||||
|
||||
const {InvalidArgumentError} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const { InvalidArgumentError } = ChromeUtils.import(
|
||||
"chrome://marionette/content/error.js"
|
||||
);
|
||||
const {
|
||||
Capabilities,
|
||||
PageLoadStrategy,
|
||||
|
@ -32,7 +36,7 @@ add_test(function test_Timeouts_toString() {
|
|||
|
||||
add_test(function test_Timeouts_toJSON() {
|
||||
let ts = new Timeouts();
|
||||
deepEqual(ts.toJSON(), {"implicit": 0, "pageLoad": 300000, "script": 30000});
|
||||
deepEqual(ts.toJSON(), { implicit: 0, pageLoad: 300000, script: 30000 });
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -67,7 +71,10 @@ add_test(function test_Timeouts_fromJSON_unrecognised_field() {
|
|||
|
||||
add_test(function test_Timeouts_fromJSON_invalid_types() {
|
||||
for (let value of [null, [], {}, false, "10", 2.5]) {
|
||||
Assert.throws(() => Timeouts.fromJSON({"implicit": value}), /InvalidArgumentError/);
|
||||
Assert.throws(
|
||||
() => Timeouts.fromJSON({ implicit: value }),
|
||||
/InvalidArgumentError/
|
||||
);
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
|
@ -75,7 +82,10 @@ add_test(function test_Timeouts_fromJSON_invalid_types() {
|
|||
|
||||
add_test(function test_Timeouts_fromJSON_bounds() {
|
||||
for (let value of [-1, Number.MAX_SAFE_INTEGER + 1]) {
|
||||
Assert.throws(() => Timeouts.fromJSON({"script": value}), /InvalidArgumentError/);
|
||||
Assert.throws(
|
||||
() => Timeouts.fromJSON({ script: value }),
|
||||
/InvalidArgumentError/
|
||||
);
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
|
@ -121,8 +131,10 @@ add_test(function test_Proxy_init() {
|
|||
ok(p.init());
|
||||
|
||||
equal(Preferences.get("network.proxy.type"), 2);
|
||||
equal(Preferences.get("network.proxy.autoconfig_url"),
|
||||
"http://localhost:1234");
|
||||
equal(
|
||||
Preferences.get("network.proxy.autoconfig_url"),
|
||||
"http://localhost:1234"
|
||||
);
|
||||
|
||||
// direct
|
||||
p = new Proxy();
|
||||
|
@ -187,15 +199,15 @@ add_test(function test_Proxy_toJSON() {
|
|||
p = new Proxy();
|
||||
p.proxyType = "pac";
|
||||
p.proxyAutoconfigUrl = "foo";
|
||||
deepEqual(p.toJSON(), {proxyType: "pac", proxyAutoconfigUrl: "foo"});
|
||||
deepEqual(p.toJSON(), { proxyType: "pac", proxyAutoconfigUrl: "foo" });
|
||||
|
||||
// manual proxy
|
||||
p = new Proxy();
|
||||
p.proxyType = "manual";
|
||||
deepEqual(p.toJSON(), {proxyType: "manual"});
|
||||
deepEqual(p.toJSON(), { proxyType: "manual" });
|
||||
|
||||
for (let proxy of ["ftpProxy", "httpProxy", "sslProxy", "socksProxy"]) {
|
||||
let expected = {proxyType: "manual"};
|
||||
let expected = { proxyType: "manual" };
|
||||
|
||||
p = new Proxy();
|
||||
p.proxyType = "manual";
|
||||
|
@ -232,7 +244,7 @@ add_test(function test_Proxy_toJSON() {
|
|||
p = new Proxy();
|
||||
p.proxyType = "manual";
|
||||
p.noProxy = ["2001:db8::1"];
|
||||
let expected = {proxyType: "manual", noProxy: "[2001:db8::1]"};
|
||||
let expected = { proxyType: "manual", noProxy: "[2001:db8::1]" };
|
||||
deepEqual(p.toJSON(), expected);
|
||||
|
||||
run_next_test();
|
||||
|
@ -249,36 +261,49 @@ add_test(function test_Proxy_fromJSON() {
|
|||
|
||||
// must contain a valid proxyType
|
||||
Assert.throws(() => Proxy.fromJSON({}), /InvalidArgumentError/);
|
||||
Assert.throws(() => Proxy.fromJSON({proxyType: "foo"}),
|
||||
/InvalidArgumentError/);
|
||||
Assert.throws(
|
||||
() => Proxy.fromJSON({ proxyType: "foo" }),
|
||||
/InvalidArgumentError/
|
||||
);
|
||||
|
||||
// autoconfig url
|
||||
for (let url of [true, 42, [], {}]) {
|
||||
Assert.throws(() => Proxy.fromJSON(
|
||||
{proxyType: "pac", proxyAutoconfigUrl: url}), /InvalidArgumentError/);
|
||||
Assert.throws(
|
||||
() => Proxy.fromJSON({ proxyType: "pac", proxyAutoconfigUrl: url }),
|
||||
/InvalidArgumentError/
|
||||
);
|
||||
}
|
||||
|
||||
p = new Proxy();
|
||||
p.proxyType = "pac";
|
||||
p.proxyAutoconfigUrl = "foo";
|
||||
deepEqual(p,
|
||||
Proxy.fromJSON({proxyType: "pac", proxyAutoconfigUrl: "foo"}));
|
||||
deepEqual(p, Proxy.fromJSON({ proxyType: "pac", proxyAutoconfigUrl: "foo" }));
|
||||
|
||||
// manual proxy
|
||||
p = new Proxy();
|
||||
p.proxyType = "manual";
|
||||
deepEqual(p, Proxy.fromJSON({proxyType: "manual"}));
|
||||
deepEqual(p, Proxy.fromJSON({ proxyType: "manual" }));
|
||||
|
||||
for (let proxy of ["httpProxy", "sslProxy", "ftpProxy", "socksProxy"]) {
|
||||
let manual = {proxyType: "manual"};
|
||||
let manual = { proxyType: "manual" };
|
||||
|
||||
// invalid hosts
|
||||
for (let host of [true, 42, [], {}, null, "http://foo",
|
||||
"foo:-1", "foo:65536", "foo/test", "foo#42", "foo?foo=bar",
|
||||
"2001:db8::1"]) {
|
||||
for (let host of [
|
||||
true,
|
||||
42,
|
||||
[],
|
||||
{},
|
||||
null,
|
||||
"http://foo",
|
||||
"foo:-1",
|
||||
"foo:65536",
|
||||
"foo/test",
|
||||
"foo#42",
|
||||
"foo?foo=bar",
|
||||
"2001:db8::1",
|
||||
]) {
|
||||
manual[proxy] = host;
|
||||
Assert.throws(() => Proxy.fromJSON(manual),
|
||||
/InvalidArgumentError/);
|
||||
Assert.throws(() => Proxy.fromJSON(manual), /InvalidArgumentError/);
|
||||
}
|
||||
|
||||
p = new Proxy();
|
||||
|
@ -289,13 +314,13 @@ add_test(function test_Proxy_fromJSON() {
|
|||
}
|
||||
|
||||
let host_map = {
|
||||
"foo:1": {hostname: "foo", port: 1},
|
||||
"foo:21": {hostname: "foo", port: 21},
|
||||
"foo:80": {hostname: "foo", port: 80},
|
||||
"foo:443": {hostname: "foo", port: 443},
|
||||
"foo:65535": {hostname: "foo", port: 65535},
|
||||
"127.0.0.1:42": {hostname: "127.0.0.1", port: 42},
|
||||
"[2001:db8::1]:42": {hostname: "2001:db8::1", port: "42"},
|
||||
"foo:1": { hostname: "foo", port: 1 },
|
||||
"foo:21": { hostname: "foo", port: 21 },
|
||||
"foo:80": { hostname: "foo", port: 80 },
|
||||
"foo:443": { hostname: "foo", port: 443 },
|
||||
"foo:65535": { hostname: "foo", port: 65535 },
|
||||
"127.0.0.1:42": { hostname: "127.0.0.1", port: 42 },
|
||||
"[2001:db8::1]:42": { hostname: "2001:db8::1", port: "42" },
|
||||
};
|
||||
|
||||
// valid proxy hosts with port
|
||||
|
@ -317,8 +342,7 @@ add_test(function test_Proxy_fromJSON() {
|
|||
if (proxy === "socksProxy") {
|
||||
p[`${proxy}Port`] = null;
|
||||
} else {
|
||||
let default_ports = {"ftpProxy": 21, "httpProxy": 80,
|
||||
"sslProxy": 443};
|
||||
let default_ports = { ftpProxy: 21, httpProxy: 80, sslProxy: 443 };
|
||||
|
||||
p[`${proxy}Port`] = default_ports[proxy];
|
||||
}
|
||||
|
@ -328,23 +352,24 @@ add_test(function test_Proxy_fromJSON() {
|
|||
}
|
||||
|
||||
// missing required socks version
|
||||
Assert.throws(() => Proxy.fromJSON(
|
||||
{proxyType: "manual", socksProxy: "foo:1234"}),
|
||||
/InvalidArgumentError/);
|
||||
Assert.throws(
|
||||
() => Proxy.fromJSON({ proxyType: "manual", socksProxy: "foo:1234" }),
|
||||
/InvalidArgumentError/
|
||||
);
|
||||
|
||||
// noProxy: invalid settings
|
||||
for (let noProxy of [true, 42, {}, null, "foo",
|
||||
[true], [42], [{}], [null]]) {
|
||||
Assert.throws(() => Proxy.fromJSON(
|
||||
{proxyType: "manual", noProxy}),
|
||||
/InvalidArgumentError/);
|
||||
for (let noProxy of [true, 42, {}, null, "foo", [true], [42], [{}], [null]]) {
|
||||
Assert.throws(
|
||||
() => Proxy.fromJSON({ proxyType: "manual", noProxy }),
|
||||
/InvalidArgumentError/
|
||||
);
|
||||
}
|
||||
|
||||
// noProxy: valid settings
|
||||
p = new Proxy();
|
||||
p.proxyType = "manual";
|
||||
for (let noProxy of [[], ["foo"], ["foo", "bar"], ["127.0.0.1"]]) {
|
||||
let manual = {proxyType: "manual", "noProxy": noProxy};
|
||||
let manual = { proxyType: "manual", noProxy };
|
||||
p.noProxy = noProxy;
|
||||
deepEqual(p, Proxy.fromJSON(manual));
|
||||
}
|
||||
|
@ -353,7 +378,7 @@ add_test(function test_Proxy_fromJSON() {
|
|||
p = new Proxy();
|
||||
p.proxyType = "manual";
|
||||
p.noProxy = ["2001:db8::1"];
|
||||
let manual = {proxyType: "manual", "noProxy": ["[2001:db8::1]"]};
|
||||
let manual = { proxyType: "manual", noProxy: ["[2001:db8::1]"] };
|
||||
deepEqual(p, Proxy.fromJSON(manual));
|
||||
|
||||
run_next_test();
|
||||
|
@ -422,15 +447,17 @@ add_test(function test_Capabilities_toJSON() {
|
|||
equal(caps.get("moz:buildID"), json["moz:buildID"]);
|
||||
equal(caps.get("moz:processID"), json["moz:processID"]);
|
||||
equal(caps.get("moz:profile"), json["moz:profile"]);
|
||||
equal(caps.get("moz:useNonSpecCompliantPointerOrigin"),
|
||||
json["moz:useNonSpecCompliantPointerOrigin"]);
|
||||
equal(
|
||||
caps.get("moz:useNonSpecCompliantPointerOrigin"),
|
||||
json["moz:useNonSpecCompliantPointerOrigin"]
|
||||
);
|
||||
equal(caps.get("moz:webdriverClick"), json["moz:webdriverClick"]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_Capabilities_fromJSON() {
|
||||
const {fromJSON} = Capabilities;
|
||||
const { fromJSON } = Capabilities;
|
||||
|
||||
// plain
|
||||
for (let typ of [{}, null, undefined]) {
|
||||
|
@ -443,58 +470,83 @@ add_test(function test_Capabilities_fromJSON() {
|
|||
// matching
|
||||
let caps = new Capabilities();
|
||||
|
||||
caps = fromJSON({acceptInsecureCerts: true});
|
||||
caps = fromJSON({ acceptInsecureCerts: true });
|
||||
equal(true, caps.get("acceptInsecureCerts"));
|
||||
caps = fromJSON({acceptInsecureCerts: false});
|
||||
caps = fromJSON({ acceptInsecureCerts: false });
|
||||
equal(false, caps.get("acceptInsecureCerts"));
|
||||
Assert.throws(() => fromJSON({acceptInsecureCerts: "foo"}), InvalidArgumentError);
|
||||
Assert.throws(
|
||||
() => fromJSON({ acceptInsecureCerts: "foo" }),
|
||||
InvalidArgumentError
|
||||
);
|
||||
|
||||
for (let strategy of Object.values(PageLoadStrategy)) {
|
||||
caps = fromJSON({pageLoadStrategy: strategy});
|
||||
caps = fromJSON({ pageLoadStrategy: strategy });
|
||||
equal(strategy, caps.get("pageLoadStrategy"));
|
||||
}
|
||||
Assert.throws(() => fromJSON({pageLoadStrategy: "foo"}), InvalidArgumentError);
|
||||
Assert.throws(() => fromJSON({pageLoadStrategy: null}), InvalidArgumentError);
|
||||
Assert.throws(
|
||||
() => fromJSON({ pageLoadStrategy: "foo" }),
|
||||
InvalidArgumentError
|
||||
);
|
||||
Assert.throws(
|
||||
() => fromJSON({ pageLoadStrategy: null }),
|
||||
InvalidArgumentError
|
||||
);
|
||||
|
||||
let proxyConfig = {proxyType: "manual"};
|
||||
caps = fromJSON({proxy: proxyConfig});
|
||||
let proxyConfig = { proxyType: "manual" };
|
||||
caps = fromJSON({ proxy: proxyConfig });
|
||||
equal("manual", caps.get("proxy").proxyType);
|
||||
|
||||
let timeoutsConfig = {implicit: 123};
|
||||
caps = fromJSON({timeouts: timeoutsConfig});
|
||||
let timeoutsConfig = { implicit: 123 };
|
||||
caps = fromJSON({ timeouts: timeoutsConfig });
|
||||
equal(123, caps.get("timeouts").implicit);
|
||||
|
||||
caps = fromJSON({setWindowRect: false});
|
||||
caps = fromJSON({ setWindowRect: false });
|
||||
equal(false, caps.get("setWindowRect"));
|
||||
Assert.throws(() => fromJSON({setWindowRect: true}), InvalidArgumentError);
|
||||
Assert.throws(() => fromJSON({ setWindowRect: true }), InvalidArgumentError);
|
||||
|
||||
caps = fromJSON({strictFileInteractability: false});
|
||||
caps = fromJSON({ strictFileInteractability: false });
|
||||
equal(false, caps.get("strictFileInteractability"));
|
||||
caps = fromJSON({strictFileInteractability: true});
|
||||
caps = fromJSON({ strictFileInteractability: true });
|
||||
equal(true, caps.get("strictFileInteractability"));
|
||||
|
||||
caps = fromJSON({"moz:accessibilityChecks": true});
|
||||
caps = fromJSON({ "moz:accessibilityChecks": true });
|
||||
equal(true, caps.get("moz:accessibilityChecks"));
|
||||
caps = fromJSON({"moz:accessibilityChecks": false});
|
||||
caps = fromJSON({ "moz:accessibilityChecks": false });
|
||||
equal(false, caps.get("moz:accessibilityChecks"));
|
||||
Assert.throws(() => fromJSON({"moz:accessibilityChecks": "foo"}), InvalidArgumentError);
|
||||
Assert.throws(() => fromJSON({"moz:accessibilityChecks": 1}), InvalidArgumentError);
|
||||
Assert.throws(
|
||||
() => fromJSON({ "moz:accessibilityChecks": "foo" }),
|
||||
InvalidArgumentError
|
||||
);
|
||||
Assert.throws(
|
||||
() => fromJSON({ "moz:accessibilityChecks": 1 }),
|
||||
InvalidArgumentError
|
||||
);
|
||||
|
||||
caps = fromJSON({"moz:useNonSpecCompliantPointerOrigin": false});
|
||||
caps = fromJSON({ "moz:useNonSpecCompliantPointerOrigin": false });
|
||||
equal(false, caps.get("moz:useNonSpecCompliantPointerOrigin"));
|
||||
caps = fromJSON({"moz:useNonSpecCompliantPointerOrigin": true});
|
||||
caps = fromJSON({ "moz:useNonSpecCompliantPointerOrigin": true });
|
||||
equal(true, caps.get("moz:useNonSpecCompliantPointerOrigin"));
|
||||
Assert.throws(() => fromJSON({"moz:useNonSpecCompliantPointerOrigin": "foo"}),
|
||||
InvalidArgumentError);
|
||||
Assert.throws(() => fromJSON({"moz:useNonSpecCompliantPointerOrigin": 1}),
|
||||
InvalidArgumentError);
|
||||
Assert.throws(
|
||||
() => fromJSON({ "moz:useNonSpecCompliantPointerOrigin": "foo" }),
|
||||
InvalidArgumentError
|
||||
);
|
||||
Assert.throws(
|
||||
() => fromJSON({ "moz:useNonSpecCompliantPointerOrigin": 1 }),
|
||||
InvalidArgumentError
|
||||
);
|
||||
|
||||
caps = fromJSON({"moz:webdriverClick": true});
|
||||
caps = fromJSON({ "moz:webdriverClick": true });
|
||||
equal(true, caps.get("moz:webdriverClick"));
|
||||
caps = fromJSON({"moz:webdriverClick": false});
|
||||
caps = fromJSON({ "moz:webdriverClick": false });
|
||||
equal(false, caps.get("moz:webdriverClick"));
|
||||
Assert.throws(() => fromJSON({"moz:webdriverClick": "foo"}), InvalidArgumentError);
|
||||
Assert.throws(() => fromJSON({"moz:webdriverClick": 1}), InvalidArgumentError);
|
||||
Assert.throws(
|
||||
() => fromJSON({ "moz:webdriverClick": "foo" }),
|
||||
InvalidArgumentError
|
||||
);
|
||||
Assert.throws(
|
||||
() => fromJSON({ "moz:webdriverClick": 1 }),
|
||||
InvalidArgumentError
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -506,26 +558,26 @@ add_test(function test_marshal() {
|
|||
// drop empty fields
|
||||
deepEqual({}, proxy.toJSON());
|
||||
proxy.proxyType = "manual";
|
||||
deepEqual({proxyType: "manual"}, proxy.toJSON());
|
||||
deepEqual({ proxyType: "manual" }, proxy.toJSON());
|
||||
proxy.proxyType = null;
|
||||
deepEqual({}, proxy.toJSON());
|
||||
proxy.proxyType = undefined;
|
||||
deepEqual({}, proxy.toJSON());
|
||||
|
||||
// iterate over object literals
|
||||
proxy.proxyType = {foo: "bar"};
|
||||
deepEqual({proxyType: {foo: "bar"}}, proxy.toJSON());
|
||||
proxy.proxyType = { foo: "bar" };
|
||||
deepEqual({ proxyType: { foo: "bar" } }, proxy.toJSON());
|
||||
|
||||
// iterate over complex object that implement toJSON
|
||||
proxy.proxyType = new Proxy();
|
||||
deepEqual({}, proxy.toJSON());
|
||||
proxy.proxyType.proxyType = "manual";
|
||||
deepEqual({proxyType: {proxyType: "manual"}}, proxy.toJSON());
|
||||
deepEqual({ proxyType: { proxyType: "manual" } }, proxy.toJSON());
|
||||
|
||||
// drop objects with no entries
|
||||
proxy.proxyType = {foo: {}};
|
||||
proxy.proxyType = { foo: {} };
|
||||
deepEqual({}, proxy.toJSON());
|
||||
proxy.proxyType = {foo: new Proxy()};
|
||||
proxy.proxyType = { foo: new Proxy() };
|
||||
deepEqual({}, proxy.toJSON());
|
||||
|
||||
run_next_test();
|
||||
|
|
|
@ -2,14 +2,24 @@
|
|||
* 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 {cookie} = ChromeUtils.import("chrome://marionette/content/cookie.js");
|
||||
const { cookie } = ChromeUtils.import("chrome://marionette/content/cookie.js");
|
||||
|
||||
/* eslint-disable mozilla/use-chromeutils-generateqi */
|
||||
|
||||
cookie.manager = {
|
||||
cookies: [],
|
||||
|
||||
add(domain, path, name, value, secure, httpOnly, session, expiry, originAttributes) {
|
||||
add(
|
||||
domain,
|
||||
path,
|
||||
name,
|
||||
value,
|
||||
secure,
|
||||
httpOnly,
|
||||
session,
|
||||
expiry,
|
||||
originAttributes
|
||||
) {
|
||||
if (name === "fail") {
|
||||
throw new Error("An error occurred while adding cookie");
|
||||
}
|
||||
|
@ -30,9 +40,11 @@ cookie.manager = {
|
|||
remove(host, name, path) {
|
||||
for (let i = 0; i < this.cookies.length; ++i) {
|
||||
let candidate = this.cookies[i];
|
||||
if (candidate.host === host &&
|
||||
candidate.name === name &&
|
||||
candidate.path === path) {
|
||||
if (
|
||||
candidate.host === host &&
|
||||
candidate.name === name &&
|
||||
candidate.path === path
|
||||
) {
|
||||
return this.cookies.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
@ -40,8 +52,9 @@ cookie.manager = {
|
|||
},
|
||||
|
||||
getCookiesFromHost(host) {
|
||||
let hostCookies = this.cookies.filter(c => c.host === host ||
|
||||
c.host === "." + host);
|
||||
let hostCookies = this.cookies.filter(
|
||||
c => c.host === host || c.host === "." + host
|
||||
);
|
||||
|
||||
return hostCookies;
|
||||
},
|
||||
|
@ -55,8 +68,14 @@ add_test(function test_fromJSON() {
|
|||
|
||||
// name and value
|
||||
for (let invalidType of [42, true, [], {}, null, undefined]) {
|
||||
Assert.throws(() => cookie.fromJSON({name: invalidType}), /Cookie name must be string/);
|
||||
Assert.throws(() => cookie.fromJSON({name: "foo", value: invalidType}), /Cookie value must be string/);
|
||||
Assert.throws(
|
||||
() => cookie.fromJSON({ name: invalidType }),
|
||||
/Cookie name must be string/
|
||||
);
|
||||
Assert.throws(
|
||||
() => cookie.fromJSON({ name: "foo", value: invalidType }),
|
||||
/Cookie value must be string/
|
||||
);
|
||||
}
|
||||
|
||||
// domain
|
||||
|
@ -66,7 +85,10 @@ add_test(function test_fromJSON() {
|
|||
value: "bar",
|
||||
domain: invalidType,
|
||||
};
|
||||
Assert.throws(() => cookie.fromJSON(domainTest), /Cookie domain must be string/);
|
||||
Assert.throws(
|
||||
() => cookie.fromJSON(domainTest),
|
||||
/Cookie domain must be string/
|
||||
);
|
||||
}
|
||||
let domainTest = {
|
||||
name: "foo",
|
||||
|
@ -83,7 +105,10 @@ add_test(function test_fromJSON() {
|
|||
value: "bar",
|
||||
path: invalidType,
|
||||
};
|
||||
Assert.throws(() => cookie.fromJSON(pathTest), /Cookie path must be string/);
|
||||
Assert.throws(
|
||||
() => cookie.fromJSON(pathTest),
|
||||
/Cookie path must be string/
|
||||
);
|
||||
}
|
||||
|
||||
// secure
|
||||
|
@ -93,7 +118,10 @@ add_test(function test_fromJSON() {
|
|||
value: "bar",
|
||||
secure: invalidType,
|
||||
};
|
||||
Assert.throws(() => cookie.fromJSON(secureTest), /Cookie secure flag must be boolean/);
|
||||
Assert.throws(
|
||||
() => cookie.fromJSON(secureTest),
|
||||
/Cookie secure flag must be boolean/
|
||||
);
|
||||
}
|
||||
|
||||
// httpOnly
|
||||
|
@ -103,21 +131,35 @@ add_test(function test_fromJSON() {
|
|||
value: "bar",
|
||||
httpOnly: invalidType,
|
||||
};
|
||||
Assert.throws(() => cookie.fromJSON(httpOnlyTest), /Cookie httpOnly flag must be boolean/);
|
||||
Assert.throws(
|
||||
() => cookie.fromJSON(httpOnlyTest),
|
||||
/Cookie httpOnly flag must be boolean/
|
||||
);
|
||||
}
|
||||
|
||||
// expiry
|
||||
for (let invalidType of [-1, Number.MAX_SAFE_INTEGER + 1, "foo", true, [], {}, null]) {
|
||||
for (let invalidType of [
|
||||
-1,
|
||||
Number.MAX_SAFE_INTEGER + 1,
|
||||
"foo",
|
||||
true,
|
||||
[],
|
||||
{},
|
||||
null,
|
||||
]) {
|
||||
let expiryTest = {
|
||||
name: "foo",
|
||||
value: "bar",
|
||||
expiry: invalidType,
|
||||
};
|
||||
Assert.throws(() => cookie.fromJSON(expiryTest), /Cookie expiry must be a positive integer/);
|
||||
Assert.throws(
|
||||
() => cookie.fromJSON(expiryTest),
|
||||
/Cookie expiry must be a positive integer/
|
||||
);
|
||||
}
|
||||
|
||||
// bare requirements
|
||||
let bare = cookie.fromJSON({name: "name", value: "value"});
|
||||
let bare = cookie.fromJSON({ name: "name", value: "value" });
|
||||
equal("name", bare.name);
|
||||
equal("value", bare.value);
|
||||
for (let missing of ["path", "secure", "httpOnly", "session", "expiry"]) {
|
||||
|
@ -150,14 +192,17 @@ add_test(function test_add() {
|
|||
|
||||
for (let invalidType of [42, true, [], {}, null, undefined]) {
|
||||
Assert.throws(
|
||||
() => cookie.add({name: invalidType}),
|
||||
/Cookie name must be string/);
|
||||
() => cookie.add({ name: invalidType }),
|
||||
/Cookie name must be string/
|
||||
);
|
||||
Assert.throws(
|
||||
() => cookie.add({name: "name", value: invalidType}),
|
||||
/Cookie value must be string/);
|
||||
() => cookie.add({ name: "name", value: invalidType }),
|
||||
/Cookie value must be string/
|
||||
);
|
||||
Assert.throws(
|
||||
() => cookie.add({name: "name", value: "value", domain: invalidType}),
|
||||
/Cookie domain must be string/);
|
||||
() => cookie.add({ name: "name", value: "value", domain: invalidType }),
|
||||
/Cookie domain must be string/
|
||||
);
|
||||
}
|
||||
|
||||
cookie.add({
|
||||
|
@ -180,8 +225,8 @@ add_test(function test_add() {
|
|||
equal(2, cookie.manager.cookies.length);
|
||||
|
||||
Assert.throws(() => {
|
||||
let biscuit = {name: "name3", value: "value3", domain: "domain3"};
|
||||
cookie.add(biscuit, {restrictToHost: "other domain"});
|
||||
let biscuit = { name: "name3", value: "value3", domain: "domain3" };
|
||||
cookie.add(biscuit, { restrictToHost: "other domain" });
|
||||
}, /Cookies may only be set for the current domain/);
|
||||
|
||||
cookie.add({
|
||||
|
@ -207,7 +252,7 @@ add_test(function test_add() {
|
|||
equal(".domain", cookie.manager.cookies[4].host);
|
||||
|
||||
Assert.throws(() => {
|
||||
cookie.add({name: "fail", value: "value6", domain: "domain6"});
|
||||
cookie.add({ name: "fail", value: "value6", domain: "domain6" });
|
||||
}, /UnableToSetCookieError/);
|
||||
|
||||
run_next_test();
|
||||
|
|
|
@ -14,7 +14,7 @@ class MessageSender {
|
|||
}
|
||||
|
||||
sendAsyncMessage(name, data, objects) {
|
||||
this.sent.push({name, data, objects});
|
||||
this.sent.push({ name, data, objects });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,12 +60,11 @@ add_test(function test_addEventListener() {
|
|||
equal(eventTarget.listeners.click[0], listener);
|
||||
|
||||
// should have sent a registration message
|
||||
deepEqual(
|
||||
ipc.sent[0], {
|
||||
name: "Marionette:DOM:AddEventListener",
|
||||
data: {type: "click"},
|
||||
objects: undefined,
|
||||
});
|
||||
deepEqual(ipc.sent[0], {
|
||||
name: "Marionette:DOM:AddEventListener",
|
||||
data: { type: "click" },
|
||||
objects: undefined,
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -86,17 +85,16 @@ add_test(function test_WebElementEventTarget_addEventListener_once() {
|
|||
let ipc = new MessageSender();
|
||||
let eventTarget = new WebElementEventTarget(ipc);
|
||||
|
||||
eventTarget.addEventListener("click", () => {}, {once: true});
|
||||
eventTarget.addEventListener("click", () => {}, { once: true });
|
||||
equal(eventTarget.listeners.click[0].once, true);
|
||||
|
||||
eventTarget.dispatchEvent({type: "click"});
|
||||
eventTarget.dispatchEvent({ type: "click" });
|
||||
equal(eventTarget.listeners.click.length, 0);
|
||||
deepEqual(
|
||||
ipc.sent[1], {
|
||||
name: "Marionette:DOM:RemoveEventListener",
|
||||
data: {type: "click"},
|
||||
objects: undefined,
|
||||
});
|
||||
deepEqual(ipc.sent[1], {
|
||||
name: "Marionette:DOM:RemoveEventListener",
|
||||
data: { type: "click" },
|
||||
objects: undefined,
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -131,13 +129,11 @@ add_test(function test_WebElementEventTarget_removeEventListener() {
|
|||
|
||||
eventTarget.removeEventListener("click", firstListener);
|
||||
equal(eventTarget.listeners.click.length, 0);
|
||||
deepEqual(
|
||||
ipc.sent[ipc.sent.length - 1],
|
||||
{
|
||||
name: "Marionette:DOM:RemoveEventListener",
|
||||
data: {type: "click"},
|
||||
objects: undefined,
|
||||
});
|
||||
deepEqual(ipc.sent[ipc.sent.length - 1], {
|
||||
name: "Marionette:DOM:RemoveEventListener",
|
||||
data: { type: "click" },
|
||||
objects: undefined,
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -147,9 +143,9 @@ add_test(function test_WebElementEventTarget_dispatchEvent() {
|
|||
let eventTarget = new WebElementEventTarget(ipc);
|
||||
|
||||
let listenerCalled = false;
|
||||
let listener = () => listenerCalled = true;
|
||||
let listener = () => (listenerCalled = true);
|
||||
eventTarget.addEventListener("click", listener);
|
||||
eventTarget.dispatchEvent({type: "click"});
|
||||
eventTarget.dispatchEvent({ type: "click" });
|
||||
ok(listenerCalled);
|
||||
|
||||
run_next_test();
|
||||
|
@ -168,7 +164,7 @@ add_test(function test_WebElementEventTarget_dispatchEvent_multipleListeners() {
|
|||
eventTarget.addEventListener("click", listenerA);
|
||||
eventTarget.addEventListener("click", listenerA);
|
||||
eventTarget.addEventListener("click", listenerB);
|
||||
eventTarget.dispatchEvent({type: "click"});
|
||||
eventTarget.dispatchEvent({ type: "click" });
|
||||
equal(clicksA, 1);
|
||||
equal(clicksB, 1);
|
||||
|
||||
|
@ -179,7 +175,9 @@ add_test(function test_ContentEventObserverService_add() {
|
|||
let ipc = new MessageSender();
|
||||
let win = new Window();
|
||||
let obs = new ContentEventObserverService(
|
||||
win, ipc.sendAsyncMessage.bind(ipc));
|
||||
win,
|
||||
ipc.sendAsyncMessage.bind(ipc)
|
||||
);
|
||||
|
||||
equal(obs.events.size, 0);
|
||||
equal(win.events.length, 0);
|
||||
|
@ -201,7 +199,9 @@ add_test(function test_ContentEventObserverService_remove() {
|
|||
let ipc = new MessageSender();
|
||||
let win = new Window();
|
||||
let obs = new ContentEventObserverService(
|
||||
win, ipc.sendAsyncMessage.bind(ipc));
|
||||
win,
|
||||
ipc.sendAsyncMessage.bind(ipc)
|
||||
);
|
||||
|
||||
obs.remove("foo");
|
||||
equal(obs.events.size, 0);
|
||||
|
@ -239,7 +239,9 @@ add_test(function test_ContentEventObserverService_clear() {
|
|||
let ipc = new MessageSender();
|
||||
let win = new Window();
|
||||
let obs = new ContentEventObserverService(
|
||||
win, ipc.sendAsyncMessage.bind(ipc));
|
||||
win,
|
||||
ipc.sendAsyncMessage.bind(ipc)
|
||||
);
|
||||
|
||||
obs.clear();
|
||||
equal(obs.events.size, 0);
|
||||
|
@ -262,15 +264,16 @@ add_test(function test_ContentEventObserverService_handleEvent() {
|
|||
let ipc = new MessageSender();
|
||||
let win = new Window();
|
||||
let obs = new ContentEventObserverService(
|
||||
win, ipc.sendAsyncMessage.bind(ipc));
|
||||
win,
|
||||
ipc.sendAsyncMessage.bind(ipc)
|
||||
);
|
||||
|
||||
obs.handleEvent({type: "click", target: win});
|
||||
deepEqual(
|
||||
ipc.sent[0], {
|
||||
name: "Marionette:DOM:OnEvent",
|
||||
data: {type: "click"},
|
||||
objects: {"target": win},
|
||||
});
|
||||
obs.handleEvent({ type: "click", target: win });
|
||||
deepEqual(ipc.sent[0], {
|
||||
name: "Marionette:DOM:OnEvent",
|
||||
data: { type: "click" },
|
||||
objects: { target: win },
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
|
|
@ -10,7 +10,9 @@ const {
|
|||
element,
|
||||
WebElement,
|
||||
} = ChromeUtils.import("chrome://marionette/content/element.js");
|
||||
const {InvalidArgumentError} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const { InvalidArgumentError } = ChromeUtils.import(
|
||||
"chrome://marionette/content/error.js"
|
||||
);
|
||||
|
||||
const SVGNS = "http://www.w3.org/2000/svg";
|
||||
const XBLNS = "http://www.mozilla.org/xbl";
|
||||
|
@ -27,8 +29,12 @@ class Element {
|
|||
}
|
||||
}
|
||||
|
||||
get nodeType() { return 1; }
|
||||
get ELEMENT_NODE() { return 1; }
|
||||
get nodeType() {
|
||||
return 1;
|
||||
}
|
||||
get ELEMENT_NODE() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// this is a severely limited CSS selector
|
||||
// that only supports lists of tag names
|
||||
|
@ -46,7 +52,7 @@ class DOMElement extends Element {
|
|||
this.namespaceURI = XHTMLNS;
|
||||
}
|
||||
if (typeof this.ownerDocument == "undefined") {
|
||||
this.ownerDocument = {designMode: "off"};
|
||||
this.ownerDocument = { designMode: "off" };
|
||||
}
|
||||
if (typeof this.type == "undefined") {
|
||||
this.type = "text";
|
||||
|
@ -56,7 +62,10 @@ class DOMElement extends Element {
|
|||
this.selected = false;
|
||||
}
|
||||
|
||||
if (this.localName == "input" && ["checkbox", "radio"].includes(this.type)) {
|
||||
if (
|
||||
this.localName == "input" &&
|
||||
["checkbox", "radio"].includes(this.type)
|
||||
) {
|
||||
this.checked = false;
|
||||
}
|
||||
}
|
||||
|
@ -98,14 +107,22 @@ const xulEl = new XULElement("browser");
|
|||
const xblEl = new XBLElement("framebox");
|
||||
|
||||
class WindowProxy {
|
||||
get parent() { return this; }
|
||||
get self() { return this; }
|
||||
toString() { return "[object Window]"; }
|
||||
get parent() {
|
||||
return this;
|
||||
}
|
||||
get self() {
|
||||
return this;
|
||||
}
|
||||
toString() {
|
||||
return "[object Window]";
|
||||
}
|
||||
}
|
||||
const domWin = new WindowProxy();
|
||||
const domFrame = new class extends WindowProxy {
|
||||
get parent() { return domWin; }
|
||||
};
|
||||
const domFrame = new (class extends WindowProxy {
|
||||
get parent() {
|
||||
return domWin;
|
||||
}
|
||||
})();
|
||||
|
||||
add_test(function test_findClosest() {
|
||||
equal(element.findClosest(domEl, "foo"), null);
|
||||
|
@ -119,7 +136,7 @@ add_test(function test_findClosest() {
|
|||
});
|
||||
|
||||
add_test(function test_isSelected() {
|
||||
let checkbox = new DOMElement("input", {type: "checkbox"});
|
||||
let checkbox = new DOMElement("input", { type: "checkbox" });
|
||||
ok(!element.isSelected(checkbox));
|
||||
checkbox.checked = true;
|
||||
ok(element.isSelected(checkbox));
|
||||
|
@ -203,41 +220,45 @@ add_test(function test_isDOMWindow() {
|
|||
add_test(function test_isReadOnly() {
|
||||
ok(!element.isReadOnly(null));
|
||||
ok(!element.isReadOnly(domEl));
|
||||
ok(!element.isReadOnly(new DOMElement("p", {readOnly: true})));
|
||||
ok(element.isReadOnly(new DOMElement("input", {readOnly: true})));
|
||||
ok(element.isReadOnly(new DOMElement("textarea", {readOnly: true})));
|
||||
ok(!element.isReadOnly(new DOMElement("p", { readOnly: true })));
|
||||
ok(element.isReadOnly(new DOMElement("input", { readOnly: true })));
|
||||
ok(element.isReadOnly(new DOMElement("textarea", { readOnly: true })));
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_isDisabled() {
|
||||
ok(!element.isDisabled(new DOMElement("p")));
|
||||
ok(!element.isDisabled(new SVGElement("rect", {disabled: true})));
|
||||
ok(!element.isDisabled(new XULElement("browser", {disabled: true})));
|
||||
ok(!element.isDisabled(new SVGElement("rect", { disabled: true })));
|
||||
ok(!element.isDisabled(new XULElement("browser", { disabled: true })));
|
||||
|
||||
let select = new DOMElement("select", {disabled: true});
|
||||
let select = new DOMElement("select", { disabled: true });
|
||||
let option = new DOMElement("option");
|
||||
option.parentNode = select;
|
||||
ok(element.isDisabled(option));
|
||||
|
||||
let optgroup = new DOMElement("optgroup", {disabled: true});
|
||||
let optgroup = new DOMElement("optgroup", { disabled: true });
|
||||
option.parentNode = optgroup;
|
||||
optgroup.parentNode = select;
|
||||
select.disabled = false;
|
||||
ok(element.isDisabled(option));
|
||||
|
||||
ok(element.isDisabled(new DOMElement("button", {disabled: true})));
|
||||
ok(element.isDisabled(new DOMElement("input", {disabled: true})));
|
||||
ok(element.isDisabled(new DOMElement("select", {disabled: true})));
|
||||
ok(element.isDisabled(new DOMElement("textarea", {disabled: true})));
|
||||
ok(element.isDisabled(new DOMElement("button", { disabled: true })));
|
||||
ok(element.isDisabled(new DOMElement("input", { disabled: true })));
|
||||
ok(element.isDisabled(new DOMElement("select", { disabled: true })));
|
||||
ok(element.isDisabled(new DOMElement("textarea", { disabled: true })));
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_isEditingHost() {
|
||||
ok(!element.isEditingHost(null));
|
||||
ok(element.isEditingHost(new DOMElement("p", {isContentEditable: true})));
|
||||
ok(element.isEditingHost(new DOMElement("p", {ownerDocument: {designMode: "on"}})));
|
||||
ok(element.isEditingHost(new DOMElement("p", { isContentEditable: true })));
|
||||
ok(
|
||||
element.isEditingHost(
|
||||
new DOMElement("p", { ownerDocument: { designMode: "on" } })
|
||||
)
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -245,26 +266,45 @@ add_test(function test_isEditingHost() {
|
|||
add_test(function test_isEditable() {
|
||||
ok(!element.isEditable(null));
|
||||
ok(!element.isEditable(domEl));
|
||||
ok(!element.isEditable(new DOMElement("textarea", {readOnly: true})));
|
||||
ok(!element.isEditable(new DOMElement("textarea", {disabled: true})));
|
||||
ok(!element.isEditable(new DOMElement("textarea", { readOnly: true })));
|
||||
ok(!element.isEditable(new DOMElement("textarea", { disabled: true })));
|
||||
|
||||
for (let type of ["checkbox", "radio", "hidden", "submit", "button", "image"]) {
|
||||
ok(!element.isEditable(new DOMElement("input", {type})));
|
||||
for (let type of [
|
||||
"checkbox",
|
||||
"radio",
|
||||
"hidden",
|
||||
"submit",
|
||||
"button",
|
||||
"image",
|
||||
]) {
|
||||
ok(!element.isEditable(new DOMElement("input", { type })));
|
||||
}
|
||||
ok(element.isEditable(new DOMElement("input", {type: "text"})));
|
||||
ok(element.isEditable(new DOMElement("input", { type: "text" })));
|
||||
ok(element.isEditable(new DOMElement("input")));
|
||||
|
||||
ok(element.isEditable(new DOMElement("textarea")));
|
||||
ok(element.isEditable(new DOMElement("p", {ownerDocument: {designMode: "on"}})));
|
||||
ok(element.isEditable(new DOMElement("p", {isContentEditable: true})));
|
||||
ok(
|
||||
element.isEditable(
|
||||
new DOMElement("p", { ownerDocument: { designMode: "on" } })
|
||||
)
|
||||
);
|
||||
ok(element.isEditable(new DOMElement("p", { isContentEditable: true })));
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_isMutableFormControlElement() {
|
||||
ok(!element.isMutableFormControl(null));
|
||||
ok(!element.isMutableFormControl(new DOMElement("textarea", {readOnly: true})));
|
||||
ok(!element.isMutableFormControl(new DOMElement("textarea", {disabled: true})));
|
||||
ok(
|
||||
!element.isMutableFormControl(
|
||||
new DOMElement("textarea", { readOnly: true })
|
||||
)
|
||||
);
|
||||
ok(
|
||||
!element.isMutableFormControl(
|
||||
new DOMElement("textarea", { disabled: true })
|
||||
)
|
||||
);
|
||||
|
||||
const mutableStates = new Set([
|
||||
"color",
|
||||
|
@ -283,14 +323,24 @@ add_test(function test_isMutableFormControlElement() {
|
|||
"week",
|
||||
]);
|
||||
for (let type of mutableStates) {
|
||||
ok(element.isMutableFormControl(new DOMElement("input", {type})));
|
||||
ok(element.isMutableFormControl(new DOMElement("input", { type })));
|
||||
}
|
||||
ok(element.isMutableFormControl(new DOMElement("textarea")));
|
||||
|
||||
ok(!element.isMutableFormControl(new DOMElement("input", {type: "hidden"})));
|
||||
ok(
|
||||
!element.isMutableFormControl(new DOMElement("input", { type: "hidden" }))
|
||||
);
|
||||
ok(!element.isMutableFormControl(new DOMElement("p")));
|
||||
ok(!element.isMutableFormControl(new DOMElement("p", {isContentEditable: true})));
|
||||
ok(!element.isMutableFormControl(new DOMElement("p", {ownerDocument: {designMode: "on"}})));
|
||||
ok(
|
||||
!element.isMutableFormControl(
|
||||
new DOMElement("p", { isContentEditable: true })
|
||||
)
|
||||
);
|
||||
ok(
|
||||
!element.isMutableFormControl(
|
||||
new DOMElement("p", { ownerDocument: { designMode: "on" } })
|
||||
)
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -302,21 +352,48 @@ add_test(function test_coordinates() {
|
|||
equal("number", typeof p.x);
|
||||
equal("number", typeof p.y);
|
||||
|
||||
deepEqual({x: 50, y: 50}, element.coordinates(domEl));
|
||||
deepEqual({x: 10, y: 10}, element.coordinates(domEl, 10, 10));
|
||||
deepEqual({x: -5, y: -5}, element.coordinates(domEl, -5, -5));
|
||||
deepEqual({ x: 50, y: 50 }, element.coordinates(domEl));
|
||||
deepEqual({ x: 10, y: 10 }, element.coordinates(domEl, 10, 10));
|
||||
deepEqual({ x: -5, y: -5 }, element.coordinates(domEl, -5, -5));
|
||||
|
||||
Assert.throws(() => element.coordinates(null), /node is null/);
|
||||
|
||||
Assert.throws(() => element.coordinates(domEl, "string", undefined), /Offset must be a number/);
|
||||
Assert.throws(() => element.coordinates(domEl, undefined, "string"), /Offset must be a number/);
|
||||
Assert.throws(() => element.coordinates(domEl, "string", "string"), /Offset must be a number/);
|
||||
Assert.throws(() => element.coordinates(domEl, {}, undefined), /Offset must be a number/);
|
||||
Assert.throws(() => element.coordinates(domEl, undefined, {}), /Offset must be a number/);
|
||||
Assert.throws(() => element.coordinates(domEl, {}, {}), /Offset must be a number/);
|
||||
Assert.throws(() => element.coordinates(domEl, [], undefined), /Offset must be a number/);
|
||||
Assert.throws(() => element.coordinates(domEl, undefined, []), /Offset must be a number/);
|
||||
Assert.throws(() => element.coordinates(domEl, [], []), /Offset must be a number/);
|
||||
Assert.throws(
|
||||
() => element.coordinates(domEl, "string", undefined),
|
||||
/Offset must be a number/
|
||||
);
|
||||
Assert.throws(
|
||||
() => element.coordinates(domEl, undefined, "string"),
|
||||
/Offset must be a number/
|
||||
);
|
||||
Assert.throws(
|
||||
() => element.coordinates(domEl, "string", "string"),
|
||||
/Offset must be a number/
|
||||
);
|
||||
Assert.throws(
|
||||
() => element.coordinates(domEl, {}, undefined),
|
||||
/Offset must be a number/
|
||||
);
|
||||
Assert.throws(
|
||||
() => element.coordinates(domEl, undefined, {}),
|
||||
/Offset must be a number/
|
||||
);
|
||||
Assert.throws(
|
||||
() => element.coordinates(domEl, {}, {}),
|
||||
/Offset must be a number/
|
||||
);
|
||||
Assert.throws(
|
||||
() => element.coordinates(domEl, [], undefined),
|
||||
/Offset must be a number/
|
||||
);
|
||||
Assert.throws(
|
||||
() => element.coordinates(domEl, undefined, []),
|
||||
/Offset must be a number/
|
||||
);
|
||||
Assert.throws(
|
||||
() => element.coordinates(domEl, [], []),
|
||||
/Offset must be a number/
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -358,9 +435,9 @@ add_test(function test_WebElement_from() {
|
|||
});
|
||||
|
||||
add_test(function test_WebElement_fromJSON_ContentWebElement() {
|
||||
const {Identifier} = ContentWebElement;
|
||||
const { Identifier } = ContentWebElement;
|
||||
|
||||
let ref = {[Identifier]: "foo"};
|
||||
let ref = { [Identifier]: "foo" };
|
||||
let webEl = WebElement.fromJSON(ref);
|
||||
ok(webEl instanceof ContentWebElement);
|
||||
equal(webEl.uuid, "foo");
|
||||
|
@ -376,7 +453,7 @@ add_test(function test_WebElement_fromJSON_ContentWebElement() {
|
|||
});
|
||||
|
||||
add_test(function test_WebElement_fromJSON_ContentWebWindow() {
|
||||
let ref = {[ContentWebWindow.Identifier]: "foo"};
|
||||
let ref = { [ContentWebWindow.Identifier]: "foo" };
|
||||
let win = WebElement.fromJSON(ref);
|
||||
ok(win instanceof ContentWebWindow);
|
||||
equal(win.uuid, "foo");
|
||||
|
@ -385,7 +462,7 @@ add_test(function test_WebElement_fromJSON_ContentWebWindow() {
|
|||
});
|
||||
|
||||
add_test(function test_WebElement_fromJSON_ContentWebFrame() {
|
||||
let ref = {[ContentWebFrame.Identifier]: "foo"};
|
||||
let ref = { [ContentWebFrame.Identifier]: "foo" };
|
||||
let frame = WebElement.fromJSON(ref);
|
||||
ok(frame instanceof ContentWebFrame);
|
||||
equal(frame.uuid, "foo");
|
||||
|
@ -394,7 +471,7 @@ add_test(function test_WebElement_fromJSON_ContentWebFrame() {
|
|||
});
|
||||
|
||||
add_test(function test_WebElement_fromJSON_ChromeWebElement() {
|
||||
let ref = {[ChromeWebElement.Identifier]: "foo"};
|
||||
let ref = { [ChromeWebElement.Identifier]: "foo" };
|
||||
let el = WebElement.fromJSON(ref);
|
||||
ok(el instanceof ChromeWebElement);
|
||||
equal(el.uuid, "foo");
|
||||
|
@ -427,10 +504,10 @@ add_test(function test_WebElement_isReference() {
|
|||
ok(!WebElement.isReference(t));
|
||||
}
|
||||
|
||||
ok(WebElement.isReference({[ContentWebElement.Identifier]: "foo"}));
|
||||
ok(WebElement.isReference({[ContentWebWindow.Identifier]: "foo"}));
|
||||
ok(WebElement.isReference({[ContentWebFrame.Identifier]: "foo"}));
|
||||
ok(WebElement.isReference({[ChromeWebElement.Identifier]: "foo"}));
|
||||
ok(WebElement.isReference({ [ContentWebElement.Identifier]: "foo" }));
|
||||
ok(WebElement.isReference({ [ContentWebWindow.Identifier]: "foo" }));
|
||||
ok(WebElement.isReference({ [ContentWebFrame.Identifier]: "foo" }));
|
||||
ok(WebElement.isReference({ [ChromeWebElement.Identifier]: "foo" }));
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -441,7 +518,7 @@ add_test(function test_WebElement_generateUUID() {
|
|||
});
|
||||
|
||||
add_test(function test_ContentWebElement_toJSON() {
|
||||
const {Identifier} = ContentWebElement;
|
||||
const { Identifier } = ContentWebElement;
|
||||
|
||||
let el = new ContentWebElement("foo");
|
||||
let json = el.toJSON();
|
||||
|
@ -453,9 +530,9 @@ add_test(function test_ContentWebElement_toJSON() {
|
|||
});
|
||||
|
||||
add_test(function test_ContentWebElement_fromJSON() {
|
||||
const {Identifier} = ContentWebElement;
|
||||
const { Identifier } = ContentWebElement;
|
||||
|
||||
let el = ContentWebElement.fromJSON({[Identifier]: "foo"});
|
||||
let el = ContentWebElement.fromJSON({ [Identifier]: "foo" });
|
||||
ok(el instanceof ContentWebElement);
|
||||
equal(el.uuid, "foo");
|
||||
|
||||
|
@ -474,7 +551,7 @@ add_test(function test_ContentWebWindow_toJSON() {
|
|||
});
|
||||
|
||||
add_test(function test_ContentWebWindow_fromJSON() {
|
||||
let ref = {[ContentWebWindow.Identifier]: "foo"};
|
||||
let ref = { [ContentWebWindow.Identifier]: "foo" };
|
||||
let win = ContentWebWindow.fromJSON(ref);
|
||||
ok(win instanceof ContentWebWindow);
|
||||
equal(win.uuid, "foo");
|
||||
|
@ -492,7 +569,7 @@ add_test(function test_ContentWebFrame_toJSON() {
|
|||
});
|
||||
|
||||
add_test(function test_ContentWebFrame_fromJSON() {
|
||||
let ref = {[ContentWebFrame.Identifier]: "foo"};
|
||||
let ref = { [ContentWebFrame.Identifier]: "foo" };
|
||||
let win = ContentWebFrame.fromJSON(ref);
|
||||
ok(win instanceof ContentWebFrame);
|
||||
equal(win.uuid, "foo");
|
||||
|
@ -510,7 +587,7 @@ add_test(function test_ChromeWebElement_toJSON() {
|
|||
});
|
||||
|
||||
add_test(function test_ChromeWebElement_fromJSON() {
|
||||
let ref = {[ChromeWebElement.Identifier]: "foo"};
|
||||
let ref = { [ChromeWebElement.Identifier]: "foo" };
|
||||
let win = ChromeWebElement.fromJSON(ref);
|
||||
ok(win instanceof ChromeWebElement);
|
||||
equal(win.uuid, "foo");
|
||||
|
|
|
@ -33,7 +33,7 @@ const {
|
|||
} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
|
||||
function notok(condition) {
|
||||
ok(!(condition));
|
||||
ok(!condition);
|
||||
}
|
||||
|
||||
add_test(function test_isError() {
|
||||
|
@ -105,12 +105,16 @@ add_test(function test_stringify() {
|
|||
equal("<unprintable error>", error.stringify());
|
||||
equal("<unprintable error>", error.stringify("foo"));
|
||||
equal("[object Object]", error.stringify({}));
|
||||
equal("[object Object]\nfoo", error.stringify({stack: "foo"}));
|
||||
equal("[object Object]\nfoo", error.stringify({ stack: "foo" }));
|
||||
equal("Error: foo", error.stringify(new Error("foo")).split("\n")[0]);
|
||||
equal("WebDriverError: foo",
|
||||
error.stringify(new WebDriverError("foo")).split("\n")[0]);
|
||||
equal("InvalidArgumentError: foo",
|
||||
error.stringify(new InvalidArgumentError("foo")).split("\n")[0]);
|
||||
equal(
|
||||
"WebDriverError: foo",
|
||||
error.stringify(new WebDriverError("foo")).split("\n")[0]
|
||||
);
|
||||
equal(
|
||||
"InvalidArgumentError: foo",
|
||||
error.stringify(new InvalidArgumentError("foo")).split("\n")[0]
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -144,18 +148,23 @@ add_test(function test_toJSON() {
|
|||
});
|
||||
|
||||
add_test(function test_fromJSON() {
|
||||
Assert.throws(() => WebDriverError.fromJSON({error: "foo"}),
|
||||
/Not of WebDriverError descent/);
|
||||
Assert.throws(() => WebDriverError.fromJSON({error: "Error"}),
|
||||
/Not of WebDriverError descent/);
|
||||
Assert.throws(() => WebDriverError.fromJSON({}),
|
||||
/Undeserialisable error type/);
|
||||
Assert.throws(() => WebDriverError.fromJSON(undefined),
|
||||
/TypeError/);
|
||||
Assert.throws(
|
||||
() => WebDriverError.fromJSON({ error: "foo" }),
|
||||
/Not of WebDriverError descent/
|
||||
);
|
||||
Assert.throws(
|
||||
() => WebDriverError.fromJSON({ error: "Error" }),
|
||||
/Not of WebDriverError descent/
|
||||
);
|
||||
Assert.throws(
|
||||
() => WebDriverError.fromJSON({}),
|
||||
/Undeserialisable error type/
|
||||
);
|
||||
Assert.throws(() => WebDriverError.fromJSON(undefined), /TypeError/);
|
||||
|
||||
// stacks will be different
|
||||
let e1 = new WebDriverError("1");
|
||||
let e1r = WebDriverError.fromJSON({error: "webdriver error", message: "1"});
|
||||
let e1r = WebDriverError.fromJSON({ error: "webdriver error", message: "1" });
|
||||
ok(e1r instanceof WebDriverError);
|
||||
equal(e1r.name, e1.name);
|
||||
equal(e1r.status, e1.status);
|
||||
|
@ -163,7 +172,10 @@ add_test(function test_fromJSON() {
|
|||
|
||||
// stacks will be different
|
||||
let e2 = new InvalidArgumentError("2");
|
||||
let e2r = WebDriverError.fromJSON({error: "invalid argument", message: "2"});
|
||||
let e2r = WebDriverError.fromJSON({
|
||||
error: "invalid argument",
|
||||
message: "2",
|
||||
});
|
||||
ok(e2r instanceof WebDriverError);
|
||||
ok(e2r instanceof InvalidArgumentError);
|
||||
equal(e2r.name, e2.name);
|
||||
|
@ -171,7 +183,7 @@ add_test(function test_fromJSON() {
|
|||
equal(e2r.message, e2.message);
|
||||
|
||||
// test stacks
|
||||
let e3j = {error: "no such element", message: "3", stacktrace: "4"};
|
||||
let e3j = { error: "no such element", message: "3", stacktrace: "4" };
|
||||
let e3r = WebDriverError.fromJSON(e3j);
|
||||
ok(e3r instanceof WebDriverError);
|
||||
ok(e3r instanceof NoSuchElementError);
|
||||
|
@ -203,13 +215,13 @@ add_test(function test_WebDriverError() {
|
|||
add_test(function test_ElementClickInterceptedError() {
|
||||
let otherEl = {
|
||||
hasAttribute: attr => attr in otherEl,
|
||||
getAttribute: attr => attr in otherEl ? otherEl[attr] : null,
|
||||
getAttribute: attr => (attr in otherEl ? otherEl[attr] : null),
|
||||
nodeType: 1,
|
||||
localName: "a",
|
||||
};
|
||||
let obscuredEl = {
|
||||
hasAttribute: attr => attr in obscuredEl,
|
||||
getAttribute: attr => attr in obscuredEl ? obscuredEl[attr] : null,
|
||||
getAttribute: attr => (attr in obscuredEl ? obscuredEl[attr] : null),
|
||||
nodeType: 1,
|
||||
localName: "b",
|
||||
ownerDocument: {
|
||||
|
@ -222,20 +234,24 @@ add_test(function test_ElementClickInterceptedError() {
|
|||
},
|
||||
};
|
||||
|
||||
let err1 = new ElementClickInterceptedError(obscuredEl, {x: 1, y: 2});
|
||||
let err1 = new ElementClickInterceptedError(obscuredEl, { x: 1, y: 2 });
|
||||
equal("ElementClickInterceptedError", err1.name);
|
||||
equal("Element <b> is not clickable at point (1,2) " +
|
||||
equal(
|
||||
"Element <b> is not clickable at point (1,2) " +
|
||||
"because another element <a> obscures it",
|
||||
err1.message);
|
||||
err1.message
|
||||
);
|
||||
equal("element click intercepted", err1.status);
|
||||
ok(err1 instanceof WebDriverError);
|
||||
|
||||
obscuredEl.style.pointerEvents = "none";
|
||||
let err2 = new ElementClickInterceptedError(obscuredEl, {x: 1, y: 2});
|
||||
equal("Element <b> is not clickable at point (1,2) " +
|
||||
let err2 = new ElementClickInterceptedError(obscuredEl, { x: 1, y: 2 });
|
||||
equal(
|
||||
"Element <b> is not clickable at point (1,2) " +
|
||||
"because it does not have pointer events enabled, " +
|
||||
"and element <a> would receive the click instead",
|
||||
err2.message);
|
||||
err2.message
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
const {element, WebElement} = ChromeUtils.import("chrome://marionette/content/element.js");
|
||||
const {evaluate} = ChromeUtils.import("chrome://marionette/content/evaluate.js");
|
||||
const { element, WebElement } = ChromeUtils.import(
|
||||
"chrome://marionette/content/element.js"
|
||||
);
|
||||
const { evaluate } = ChromeUtils.import(
|
||||
"chrome://marionette/content/evaluate.js"
|
||||
);
|
||||
|
||||
const SVGNS = "http://www.w3.org/2000/svg";
|
||||
const XBLNS = "http://www.mozilla.org/xbl";
|
||||
|
@ -16,8 +20,12 @@ class Element {
|
|||
}
|
||||
}
|
||||
|
||||
get nodeType() { return 1; }
|
||||
get ELEMENT_NODE() { return 1; }
|
||||
get nodeType() {
|
||||
return 1;
|
||||
}
|
||||
get ELEMENT_NODE() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
class DOMElement extends Element {
|
||||
|
@ -75,17 +83,34 @@ add_test(function test_toJSON_types() {
|
|||
ok(evaluate.toJSON(xblEl, seenEls) instanceof WebElement);
|
||||
|
||||
// toJSON
|
||||
equal("foo", evaluate.toJSON({toJSON() { return "foo"; }}));
|
||||
equal(
|
||||
"foo",
|
||||
evaluate.toJSON({
|
||||
toJSON() {
|
||||
return "foo";
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
// arbitrary object
|
||||
deepEqual({foo: "bar"}, evaluate.toJSON({foo: "bar"}));
|
||||
deepEqual({ foo: "bar" }, evaluate.toJSON({ foo: "bar" }));
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
|
||||
add_test(function test_toJSON_sequences() {
|
||||
let input = [null, true, [], domEl, {toJSON() { return "foo"; }}, {bar: "baz"}];
|
||||
let input = [
|
||||
null,
|
||||
true,
|
||||
[],
|
||||
domEl,
|
||||
{
|
||||
toJSON() {
|
||||
return "foo";
|
||||
},
|
||||
},
|
||||
{ bar: "baz" },
|
||||
];
|
||||
let actual = evaluate.toJSON(input, seenEls);
|
||||
|
||||
equal(null, actual[0]);
|
||||
|
@ -93,19 +118,23 @@ add_test(function test_toJSON_sequences() {
|
|||
deepEqual([], actual[2]);
|
||||
ok(actual[3] instanceof WebElement);
|
||||
equal("foo", actual[4]);
|
||||
deepEqual({bar: "baz"}, actual[5]);
|
||||
deepEqual({ bar: "baz" }, actual[5]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_toJSON_objects() {
|
||||
let input = {
|
||||
"null": null,
|
||||
"boolean": true,
|
||||
"array": [],
|
||||
"webElement": domEl,
|
||||
"toJSON": {toJSON() { return "foo"; }},
|
||||
"object": {"bar": "baz"},
|
||||
null: null,
|
||||
boolean: true,
|
||||
array: [],
|
||||
webElement: domEl,
|
||||
toJSON: {
|
||||
toJSON() {
|
||||
return "foo";
|
||||
},
|
||||
},
|
||||
object: { bar: "baz" },
|
||||
};
|
||||
let actual = evaluate.toJSON(input, seenEls);
|
||||
|
||||
|
@ -114,7 +143,7 @@ add_test(function test_toJSON_objects() {
|
|||
deepEqual([], actual.array);
|
||||
ok(actual.webElement instanceof WebElement);
|
||||
equal("foo", actual.toJSON);
|
||||
deepEqual({"bar": "baz"}, actual.object);
|
||||
deepEqual({ bar: "baz" }, actual.object);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -146,7 +175,7 @@ add_test(function test_isCyclic_array() {
|
|||
add_test(function test_isCyclic_arrayInObject() {
|
||||
let arr = [];
|
||||
arr.push(arr);
|
||||
ok(evaluate.isCyclic({arr}));
|
||||
ok(evaluate.isCyclic({ arr }));
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
|
|
@ -2,20 +2,22 @@
|
|||
* 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 {pprint, truncate} = ChromeUtils.import("chrome://marionette/content/format.js");
|
||||
const { pprint, truncate } = ChromeUtils.import(
|
||||
"chrome://marionette/content/format.js"
|
||||
);
|
||||
|
||||
const MAX_STRING_LENGTH = 250;
|
||||
const HALF = "x".repeat(MAX_STRING_LENGTH / 2);
|
||||
|
||||
add_test(function test_pprint() {
|
||||
equal('[object Object] {"foo":"bar"}', pprint`${{foo: "bar"}}`);
|
||||
equal('[object Object] {"foo":"bar"}', pprint`${{ foo: "bar" }}`);
|
||||
|
||||
equal("[object Number] 42", pprint`${42}`);
|
||||
equal("[object Boolean] true", pprint`${true}`);
|
||||
equal("[object Undefined] undefined", pprint`${undefined}`);
|
||||
equal("[object Null] null", pprint`${null}`);
|
||||
|
||||
let complexObj = {toJSON: () => "foo"};
|
||||
let complexObj = { toJSON: () => "foo" };
|
||||
equal('[object Object] "foo"', pprint`${complexObj}`);
|
||||
|
||||
let cyclic = {};
|
||||
|
@ -24,7 +26,7 @@ add_test(function test_pprint() {
|
|||
|
||||
let el = {
|
||||
hasAttribute: attr => attr in el,
|
||||
getAttribute: attr => attr in el ? el[attr] : null,
|
||||
getAttribute: attr => (attr in el ? el[attr] : null),
|
||||
nodeType: 1,
|
||||
localName: "input",
|
||||
id: "foo",
|
||||
|
@ -34,8 +36,10 @@ add_test(function test_pprint() {
|
|||
src: "s",
|
||||
type: "t",
|
||||
};
|
||||
equal('<input id="foo" class="a b" href="#" name="bar" src="s" type="t">',
|
||||
pprint`${el}`);
|
||||
equal(
|
||||
'<input id="foo" class="a b" href="#" name="bar" src="s" type="t">',
|
||||
pprint`${el}`
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -75,25 +79,38 @@ add_test(function test_truncate_string() {
|
|||
add_test(function test_truncate_array() {
|
||||
equal(truncate`${["foo"]}`, JSON.stringify(["foo"]));
|
||||
equal(truncate`${"foo"} ${["bar"]}`, `foo ${JSON.stringify(["bar"])}`);
|
||||
equal(truncate`${["x".repeat(260)]}`, JSON.stringify([`${HALF} ... ${HALF}`]));
|
||||
equal(
|
||||
truncate`${["x".repeat(260)]}`,
|
||||
JSON.stringify([`${HALF} ... ${HALF}`])
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_truncate_object() {
|
||||
equal(truncate`${{}}`, JSON.stringify({}));
|
||||
equal(truncate`${{foo: "bar"}}`, JSON.stringify({foo: "bar"}));
|
||||
equal(truncate`${{foo: "x".repeat(260)}}`, JSON.stringify({foo: `${HALF} ... ${HALF}`}));
|
||||
equal(truncate`${{foo: ["bar"]}}`, JSON.stringify({foo: ["bar"]}));
|
||||
equal(truncate`${{foo: ["bar", {baz: 42}]}}`, JSON.stringify({foo: ["bar", {baz: 42}]}));
|
||||
equal(truncate`${{ foo: "bar" }}`, JSON.stringify({ foo: "bar" }));
|
||||
equal(
|
||||
truncate`${{ foo: "x".repeat(260) }}`,
|
||||
JSON.stringify({ foo: `${HALF} ... ${HALF}` })
|
||||
);
|
||||
equal(truncate`${{ foo: ["bar"] }}`, JSON.stringify({ foo: ["bar"] }));
|
||||
equal(
|
||||
truncate`${{ foo: ["bar", { baz: 42 }] }}`,
|
||||
JSON.stringify({ foo: ["bar", { baz: 42 }] })
|
||||
);
|
||||
|
||||
let complex = {
|
||||
toString() { return "hello world"; },
|
||||
toString() {
|
||||
return "hello world";
|
||||
},
|
||||
};
|
||||
equal(truncate`${complex}`, "hello world");
|
||||
|
||||
let longComplex = {
|
||||
toString() { return "x".repeat(260); },
|
||||
toString() {
|
||||
return "x".repeat(260);
|
||||
},
|
||||
};
|
||||
equal(truncate`${longComplex}`, `${HALF} ... ${HALF}`);
|
||||
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
* 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 {
|
||||
InvalidArgumentError,
|
||||
WebDriverError,
|
||||
} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const {Command, Message, Response} = ChromeUtils.import("chrome://marionette/content/message.js");
|
||||
const { InvalidArgumentError, WebDriverError } = ChromeUtils.import(
|
||||
"chrome://marionette/content/error.js"
|
||||
);
|
||||
const { Command, Message, Response } = ChromeUtils.import(
|
||||
"chrome://marionette/content/message.js"
|
||||
);
|
||||
|
||||
add_test(function test_Message_Origin() {
|
||||
equal(0, Message.Origin.Client);
|
||||
|
@ -22,17 +23,19 @@ add_test(function test_Message_fromPacket() {
|
|||
|
||||
ok(Message.fromPacket(cmd.toPacket()) instanceof Command);
|
||||
ok(Message.fromPacket(resp.toPacket()) instanceof Response);
|
||||
Assert.throws(() => Message.fromPacket([3, 4, 5, 6]),
|
||||
/Unrecognised message type in packet/);
|
||||
Assert.throws(
|
||||
() => Message.fromPacket([3, 4, 5, 6]),
|
||||
/Unrecognised message type in packet/
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_Command() {
|
||||
let cmd = new Command(42, "foo", {bar: "baz"});
|
||||
let cmd = new Command(42, "foo", { bar: "baz" });
|
||||
equal(42, cmd.id);
|
||||
equal("foo", cmd.name);
|
||||
deepEqual({bar: "baz"}, cmd.parameters);
|
||||
deepEqual({ bar: "baz" }, cmd.parameters);
|
||||
equal(null, cmd.onerror);
|
||||
equal(null, cmd.onresult);
|
||||
equal(Message.Origin.Client, cmd.origin);
|
||||
|
@ -46,8 +49,8 @@ add_test(function test_Command_onresponse() {
|
|||
let onresultOk = false;
|
||||
|
||||
let cmd = new Command(7, "foo");
|
||||
cmd.onerror = () => onerrorOk = true;
|
||||
cmd.onresult = () => onresultOk = true;
|
||||
cmd.onerror = () => (onerrorOk = true);
|
||||
cmd.onresult = () => (onresultOk = true);
|
||||
|
||||
let errorResp = new Response(8, () => {});
|
||||
errorResp.error = new WebDriverError("foo");
|
||||
|
@ -66,7 +69,7 @@ add_test(function test_Command_onresponse() {
|
|||
});
|
||||
|
||||
add_test(function test_Command_ctor() {
|
||||
let cmd = new Command(42, "bar", {bar: "baz"});
|
||||
let cmd = new Command(42, "bar", { bar: "baz" });
|
||||
let msg = cmd.toPacket();
|
||||
|
||||
equal(Command.Type, msg[0]);
|
||||
|
@ -78,14 +81,14 @@ add_test(function test_Command_ctor() {
|
|||
});
|
||||
|
||||
add_test(function test_Command_toString() {
|
||||
let cmd = new Command(42, "foo", {bar: "baz"});
|
||||
let cmd = new Command(42, "foo", { bar: "baz" });
|
||||
equal(JSON.stringify(cmd.toPacket()), cmd.toString());
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_Command_fromPacket() {
|
||||
let c1 = new Command(42, "foo", {bar: "baz"});
|
||||
let c1 = new Command(42, "foo", { bar: "baz" });
|
||||
|
||||
let msg = c1.toPacket();
|
||||
let c2 = Command.fromPacket(msg);
|
||||
|
@ -94,14 +97,32 @@ add_test(function test_Command_fromPacket() {
|
|||
equal(c1.name, c2.name);
|
||||
equal(c1.parameters, c2.parameters);
|
||||
|
||||
Assert.throws(() => Command.fromPacket([null, 2, "foo", {}]), /InvalidArgumentError/);
|
||||
Assert.throws(() => Command.fromPacket([1, 2, "foo", {}]), /InvalidArgumentError/);
|
||||
Assert.throws(() => Command.fromPacket([0, null, "foo", {}]), /InvalidArgumentError/);
|
||||
Assert.throws(() => Command.fromPacket([0, 2, null, {}]), /InvalidArgumentError/);
|
||||
Assert.throws(() => Command.fromPacket([0, 2, "foo", false]), /InvalidArgumentError/);
|
||||
Assert.throws(
|
||||
() => Command.fromPacket([null, 2, "foo", {}]),
|
||||
/InvalidArgumentError/
|
||||
);
|
||||
Assert.throws(
|
||||
() => Command.fromPacket([1, 2, "foo", {}]),
|
||||
/InvalidArgumentError/
|
||||
);
|
||||
Assert.throws(
|
||||
() => Command.fromPacket([0, null, "foo", {}]),
|
||||
/InvalidArgumentError/
|
||||
);
|
||||
Assert.throws(
|
||||
() => Command.fromPacket([0, 2, null, {}]),
|
||||
/InvalidArgumentError/
|
||||
);
|
||||
Assert.throws(
|
||||
() => Command.fromPacket([0, 2, "foo", false]),
|
||||
/InvalidArgumentError/
|
||||
);
|
||||
|
||||
let nullParams = Command.fromPacket([0, 2, "foo", null]);
|
||||
equal("[object Object]", Object.prototype.toString.call(nullParams.parameters));
|
||||
equal(
|
||||
"[object Object]",
|
||||
Object.prototype.toString.call(nullParams.parameters)
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -127,7 +148,7 @@ add_test(function test_Response_ctor() {
|
|||
|
||||
add_test(function test_Response_sendConditionally() {
|
||||
let fired = false;
|
||||
let resp = new Response(42, () => fired = true);
|
||||
let resp = new Response(42, () => (fired = true));
|
||||
resp.sendConditionally(() => false);
|
||||
equal(false, resp.sent);
|
||||
equal(false, fired);
|
||||
|
@ -140,7 +161,7 @@ add_test(function test_Response_sendConditionally() {
|
|||
|
||||
add_test(function test_Response_send() {
|
||||
let fired = false;
|
||||
let resp = new Response(42, () => fired = true);
|
||||
let resp = new Response(42, () => (fired = true));
|
||||
resp.send();
|
||||
equal(true, resp.sent);
|
||||
equal(true, fired);
|
||||
|
@ -231,10 +252,22 @@ add_test(function test_Response_fromPacket() {
|
|||
equal(r1.error, r2.error);
|
||||
equal(r1.body, r2.body);
|
||||
|
||||
Assert.throws(() => Response.fromPacket([null, 2, "foo", {}]), InvalidArgumentError);
|
||||
Assert.throws(() => Response.fromPacket([0, 2, "foo", {}]), InvalidArgumentError);
|
||||
Assert.throws(() => Response.fromPacket([1, null, "foo", {}]), InvalidArgumentError);
|
||||
Assert.throws(() => Response.fromPacket([1, 2, null, {}]), InvalidArgumentError);
|
||||
Assert.throws(
|
||||
() => Response.fromPacket([null, 2, "foo", {}]),
|
||||
InvalidArgumentError
|
||||
);
|
||||
Assert.throws(
|
||||
() => Response.fromPacket([0, 2, "foo", {}]),
|
||||
InvalidArgumentError
|
||||
);
|
||||
Assert.throws(
|
||||
() => Response.fromPacket([1, null, "foo", {}]),
|
||||
InvalidArgumentError
|
||||
);
|
||||
Assert.throws(
|
||||
() => Response.fromPacket([1, 2, null, {}]),
|
||||
InvalidArgumentError
|
||||
);
|
||||
Response.fromPacket([1, 2, "foo", null]);
|
||||
|
||||
run_next_test();
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {InvalidArgumentError} = ChromeUtils.import("chrome://marionette/content/error.js");
|
||||
const {modal} = ChromeUtils.import("chrome://marionette/content/modal.js");
|
||||
const { InvalidArgumentError } = ChromeUtils.import(
|
||||
"chrome://marionette/content/error.js"
|
||||
);
|
||||
const { modal } = ChromeUtils.import("chrome://marionette/content/modal.js");
|
||||
|
||||
const mockModalDialog = {
|
||||
opener: {
|
||||
|
@ -57,7 +59,11 @@ add_test(function test_registerDialogClosedEventHandler() {
|
|||
let observer = new modal.DialogObserver();
|
||||
let mockChromeWindow = {
|
||||
addEventListener(event, cb) {
|
||||
equal(event, "DOMModalDialogClosed", "registered event for closing modal");
|
||||
equal(
|
||||
event,
|
||||
"DOMModalDialogClosed",
|
||||
"registered event for closing modal"
|
||||
);
|
||||
equal(cb, observer, "set itself as handler");
|
||||
run_next_test();
|
||||
},
|
||||
|
@ -71,8 +77,16 @@ add_test(function test_handleCallbackOpenModalDialog() {
|
|||
|
||||
observer.add((action, target, win) => {
|
||||
equal(action, modal.ACTION_OPENED, "'opened' action has been passed");
|
||||
equal(target.get(), mockModalDialog, "weak reference has been created for target");
|
||||
equal(win, mockModalDialog.opener.ownerGlobal, "chrome window has been passed");
|
||||
equal(
|
||||
target.get(),
|
||||
mockModalDialog,
|
||||
"weak reference has been created for target"
|
||||
);
|
||||
equal(
|
||||
win,
|
||||
mockModalDialog.opener.ownerGlobal,
|
||||
"chrome window has been passed"
|
||||
);
|
||||
run_next_test();
|
||||
});
|
||||
observer.observe(mockModalDialog, "common-dialog-loaded");
|
||||
|
@ -83,11 +97,22 @@ add_test(function test_handleCallbackCloseModalDialog() {
|
|||
|
||||
observer.add((action, target, win) => {
|
||||
equal(action, modal.ACTION_CLOSED, "'closed' action has been passed");
|
||||
equal(target.get(), mockModalDialog, "weak reference has been created for target");
|
||||
equal(win, mockModalDialog.opener.ownerGlobal, "chrome window has been passed");
|
||||
equal(
|
||||
target.get(),
|
||||
mockModalDialog,
|
||||
"weak reference has been created for target"
|
||||
);
|
||||
equal(
|
||||
win,
|
||||
mockModalDialog.opener.ownerGlobal,
|
||||
"chrome window has been passed"
|
||||
);
|
||||
run_next_test();
|
||||
});
|
||||
observer.handleEvent({type: "DOMModalDialogClosed", target: mockModalDialog});
|
||||
observer.handleEvent({
|
||||
type: "DOMModalDialogClosed",
|
||||
target: mockModalDialog,
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_handleCallbackOpenTabModalDialog() {
|
||||
|
@ -95,7 +120,11 @@ add_test(function test_handleCallbackOpenTabModalDialog() {
|
|||
|
||||
observer.add((action, target, win) => {
|
||||
equal(action, modal.ACTION_OPENED, "'opened' action has been passed");
|
||||
equal(target.get(), mockTabModalDialog, "weak reference has been created for target");
|
||||
equal(
|
||||
target.get(),
|
||||
mockTabModalDialog,
|
||||
"weak reference has been created for target"
|
||||
);
|
||||
equal(win, mockTabModalDialog.ownerGlobal, "chrome window has been passed");
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -107,9 +136,16 @@ add_test(function test_handleCallbackCloseTabModalDialog() {
|
|||
|
||||
observer.add((action, target, win) => {
|
||||
equal(action, modal.ACTION_CLOSED, "'closed' action has been passed");
|
||||
equal(target.get(), mockTabModalDialog, "weak reference has been created for target");
|
||||
equal(
|
||||
target.get(),
|
||||
mockTabModalDialog,
|
||||
"weak reference has been created for target"
|
||||
);
|
||||
equal(win, mockTabModalDialog.ownerGlobal, "chrome window has been passed");
|
||||
run_next_test();
|
||||
});
|
||||
observer.handleEvent({type: "DOMModalDialogClosed", target: mockTabModalDialog});
|
||||
observer.handleEvent({
|
||||
type: "DOMModalDialogClosed",
|
||||
target: mockTabModalDialog,
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,11 +2,15 @@
|
|||
* 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 {navigate} = ChromeUtils.import("chrome://marionette/content/navigate.js");
|
||||
const { navigate } = ChromeUtils.import(
|
||||
"chrome://marionette/content/navigate.js"
|
||||
);
|
||||
|
||||
add_test(function test_isLoadEventExpected() {
|
||||
Assert.throws(() => navigate.isLoadEventExpected(undefined),
|
||||
/Expected at least one URL/);
|
||||
Assert.throws(
|
||||
() => navigate.isLoadEventExpected(undefined),
|
||||
/Expected at least one URL/
|
||||
);
|
||||
|
||||
equal(true, navigate.isLoadEventExpected("http://a/"));
|
||||
equal(true, navigate.isLoadEventExpected("http://a/", "http://a/"));
|
||||
|
@ -16,7 +20,10 @@ add_test(function test_isLoadEventExpected() {
|
|||
equal(true, navigate.isLoadEventExpected("http://a/#a", "http://a/#A"));
|
||||
equal(false, navigate.isLoadEventExpected("http://a/#a", "http://a/#a"));
|
||||
|
||||
equal(false, navigate.isLoadEventExpected("http://a/", "javascript:whatever"));
|
||||
equal(
|
||||
false,
|
||||
navigate.isLoadEventExpected("http://a/", "javascript:whatever")
|
||||
);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
|
|
@ -4,18 +4,23 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {Log} = ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { Log } = ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this, "env", "@mozilla.org/process/environment;1", "nsIEnvironment");
|
||||
this,
|
||||
"env",
|
||||
"@mozilla.org/process/environment;1",
|
||||
"nsIEnvironment"
|
||||
);
|
||||
|
||||
const {
|
||||
Branch,
|
||||
EnvironmentPrefs,
|
||||
MarionettePrefs,
|
||||
} = ChromeUtils.import("chrome://marionette/content/prefs.js", null);
|
||||
const { Branch, EnvironmentPrefs, MarionettePrefs } = ChromeUtils.import(
|
||||
"chrome://marionette/content/prefs.js",
|
||||
null
|
||||
);
|
||||
|
||||
function reset() {
|
||||
Services.prefs.setBoolPref("test.bool", false);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* 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 {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const {
|
||||
DebounceCallback,
|
||||
|
@ -121,7 +121,9 @@ add_test(function test_executeSoon_callback() {
|
|||
}
|
||||
|
||||
let a;
|
||||
sync.executeSoon(() => { a = 1; });
|
||||
sync.executeSoon(() => {
|
||||
a = 1;
|
||||
});
|
||||
executeSoon(() => equal(1, a));
|
||||
|
||||
run_next_test();
|
||||
|
@ -139,13 +141,13 @@ add_test(function test_PollPromise_funcTypes() {
|
|||
|
||||
add_test(function test_PollPromise_timeoutTypes() {
|
||||
for (let timeout of ["foo", true, [], {}]) {
|
||||
Assert.throws(() => new PollPromise(() => {}, {timeout}), /TypeError/);
|
||||
Assert.throws(() => new PollPromise(() => {}, { timeout }), /TypeError/);
|
||||
}
|
||||
for (let timeout of [1.2, -1]) {
|
||||
Assert.throws(() => new PollPromise(() => {}, {timeout}), /RangeError/);
|
||||
Assert.throws(() => new PollPromise(() => {}, { timeout }), /RangeError/);
|
||||
}
|
||||
for (let timeout of [null, undefined, 42]) {
|
||||
new PollPromise(resolve => resolve(1), {timeout});
|
||||
new PollPromise(resolve => resolve(1), { timeout });
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
|
@ -153,12 +155,12 @@ add_test(function test_PollPromise_timeoutTypes() {
|
|||
|
||||
add_test(function test_PollPromise_intervalTypes() {
|
||||
for (let interval of ["foo", null, true, [], {}]) {
|
||||
Assert.throws(() => new PollPromise(() => {}, {interval}), /TypeError/);
|
||||
Assert.throws(() => new PollPromise(() => {}, { interval }), /TypeError/);
|
||||
}
|
||||
for (let interval of [1.2, -1]) {
|
||||
Assert.throws(() => new PollPromise(() => {}, {interval}), /RangeError/);
|
||||
Assert.throws(() => new PollPromise(() => {}, { interval }), /RangeError/);
|
||||
}
|
||||
new PollPromise(() => {}, {interval: 42});
|
||||
new PollPromise(() => {}, { interval: 42 });
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -197,33 +199,42 @@ add_task(async function test_PollPromise_zeroTimeout() {
|
|||
// run at least once when timeout is 0
|
||||
let nevals = 0;
|
||||
let start = new Date().getTime();
|
||||
await new PollPromise((resolve, reject) => {
|
||||
++nevals;
|
||||
reject();
|
||||
}, {timeout: 0});
|
||||
await new PollPromise(
|
||||
(resolve, reject) => {
|
||||
++nevals;
|
||||
reject();
|
||||
},
|
||||
{ timeout: 0 }
|
||||
);
|
||||
let end = new Date().getTime();
|
||||
equal(1, nevals);
|
||||
less((end - start), 500);
|
||||
less(end - start, 500);
|
||||
});
|
||||
|
||||
add_task(async function test_PollPromise_timeoutElapse() {
|
||||
let nevals = 0;
|
||||
let start = new Date().getTime();
|
||||
await new PollPromise((resolve, reject) => {
|
||||
++nevals;
|
||||
reject();
|
||||
}, {timeout: 100});
|
||||
await new PollPromise(
|
||||
(resolve, reject) => {
|
||||
++nevals;
|
||||
reject();
|
||||
},
|
||||
{ timeout: 100 }
|
||||
);
|
||||
let end = new Date().getTime();
|
||||
lessOrEqual(nevals, 11);
|
||||
greaterOrEqual((end - start), 100);
|
||||
greaterOrEqual(end - start, 100);
|
||||
});
|
||||
|
||||
add_task(async function test_PollPromise_interval() {
|
||||
let nevals = 0;
|
||||
await new PollPromise((resolve, reject) => {
|
||||
++nevals;
|
||||
reject();
|
||||
}, {timeout: 100, interval: 100});
|
||||
await new PollPromise(
|
||||
(resolve, reject) => {
|
||||
++nevals;
|
||||
reject();
|
||||
},
|
||||
{ timeout: 100, interval: 100 }
|
||||
);
|
||||
equal(2, nevals);
|
||||
});
|
||||
|
||||
|
@ -232,19 +243,27 @@ add_test(function test_TimedPromise_funcTypes() {
|
|||
Assert.throws(() => new TimedPromise(type), /TypeError/);
|
||||
}
|
||||
new TimedPromise(resolve => resolve());
|
||||
new TimedPromise(function(resolve) { resolve(); });
|
||||
new TimedPromise(function(resolve) {
|
||||
resolve();
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_TimedPromise_timeoutTypes() {
|
||||
for (let timeout of ["foo", null, true, [], {}]) {
|
||||
Assert.throws(() => new TimedPromise(resolve => resolve(), {timeout}), /TypeError/);
|
||||
Assert.throws(
|
||||
() => new TimedPromise(resolve => resolve(), { timeout }),
|
||||
/TypeError/
|
||||
);
|
||||
}
|
||||
for (let timeout of [1.2, -1]) {
|
||||
Assert.throws(() => new TimedPromise(resolve => resolve(), {timeout}), /RangeError/);
|
||||
Assert.throws(
|
||||
() => new TimedPromise(resolve => resolve(), { timeout }),
|
||||
/RangeError/
|
||||
);
|
||||
}
|
||||
new TimedPromise(resolve => resolve(), {timeout: 42});
|
||||
new TimedPromise(resolve => resolve(), { timeout: 42 });
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -275,10 +294,16 @@ add_test(function test_DebounceCallback_constructor() {
|
|||
Assert.throws(() => new DebounceCallback(cb), /TypeError/);
|
||||
}
|
||||
for (let timeout of ["foo", true, [], {}, () => {}]) {
|
||||
Assert.throws(() => new DebounceCallback(() => {}, {timeout}), /TypeError/);
|
||||
Assert.throws(
|
||||
() => new DebounceCallback(() => {}, { timeout }),
|
||||
/TypeError/
|
||||
);
|
||||
}
|
||||
for (let timeout of [-1, 2.3, NaN]) {
|
||||
Assert.throws(() => new DebounceCallback(() => {}, {timeout}), /RangeError/);
|
||||
Assert.throws(
|
||||
() => new DebounceCallback(() => {}, { timeout }),
|
||||
/RangeError/
|
||||
);
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
|
@ -326,15 +351,17 @@ add_task(async function test_waitForEvent_captureTypes() {
|
|||
let element = new MockElement();
|
||||
|
||||
for (let capture of ["foo", 42, [], {}]) {
|
||||
Assert.throws(() => waitForEvent(
|
||||
element, "click", {capture}), /TypeError/);
|
||||
Assert.throws(
|
||||
() => waitForEvent(element, "click", { capture }),
|
||||
/TypeError/
|
||||
);
|
||||
}
|
||||
|
||||
for (let capture of [null, undefined, false, true]) {
|
||||
let expected_capture = (capture == null) ? false : capture;
|
||||
let expected_capture = capture == null ? false : capture;
|
||||
|
||||
element = new MockElement();
|
||||
let clicked = waitForEvent(element, "click", {capture});
|
||||
let clicked = waitForEvent(element, "click", { capture });
|
||||
element.click();
|
||||
let event = await clicked;
|
||||
equal(element, event.target);
|
||||
|
@ -346,17 +373,19 @@ add_task(async function test_waitForEvent_checkFnTypes() {
|
|||
let element = new MockElement();
|
||||
|
||||
for (let checkFn of ["foo", 42, true, [], {}]) {
|
||||
Assert.throws(() => waitForEvent(
|
||||
element, "click", {checkFn}), /TypeError/);
|
||||
Assert.throws(
|
||||
() => waitForEvent(element, "click", { checkFn }),
|
||||
/TypeError/
|
||||
);
|
||||
}
|
||||
|
||||
let count;
|
||||
for (let checkFn of [null, undefined, event => count++ > 0]) {
|
||||
let expected_count = (checkFn == null) ? 0 : 2;
|
||||
let expected_count = checkFn == null ? 0 : 2;
|
||||
count = 0;
|
||||
|
||||
element = new MockElement();
|
||||
let clicked = waitForEvent(element, "click", {checkFn});
|
||||
let clicked = waitForEvent(element, "click", { checkFn });
|
||||
element.click();
|
||||
element.click();
|
||||
let event = await clicked;
|
||||
|
@ -369,15 +398,17 @@ add_task(async function test_waitForEvent_wantsUntrustedTypes() {
|
|||
let element = new MockElement();
|
||||
|
||||
for (let wantsUntrusted of ["foo", 42, [], {}]) {
|
||||
Assert.throws(() => waitForEvent(
|
||||
element, "click", {wantsUntrusted}), /TypeError/);
|
||||
Assert.throws(
|
||||
() => waitForEvent(element, "click", { wantsUntrusted }),
|
||||
/TypeError/
|
||||
);
|
||||
}
|
||||
|
||||
for (let wantsUntrusted of [null, undefined, false, true]) {
|
||||
let expected_untrusted = (wantsUntrusted == null) ? false : wantsUntrusted;
|
||||
let expected_untrusted = wantsUntrusted == null ? false : wantsUntrusted;
|
||||
|
||||
element = new MockElement();
|
||||
let clicked = waitForEvent(element, "click", {wantsUntrusted});
|
||||
let clicked = waitForEvent(element, "click", { wantsUntrusted });
|
||||
element.click();
|
||||
let event = await clicked;
|
||||
equal(element, event.target);
|
||||
|
@ -396,7 +427,7 @@ add_task(async function test_waitForMessage_messageManagerAndMessageTypes() {
|
|||
Assert.throws(() => waitForEvent(messageManager, message), /TypeError/);
|
||||
}
|
||||
|
||||
let data = {"foo": "bar"};
|
||||
let data = { foo: "bar" };
|
||||
let sent = waitForMessage(messageManager, "message");
|
||||
messageManager.send("message", data);
|
||||
equal(data, await sent);
|
||||
|
@ -406,18 +437,20 @@ add_task(async function test_waitForMessage_checkFnTypes() {
|
|||
let messageManager = new MessageManager();
|
||||
|
||||
for (let checkFn of ["foo", 42, true, [], {}]) {
|
||||
Assert.throws(() => waitForMessage(
|
||||
messageManager, "message", {checkFn}), /TypeError/);
|
||||
Assert.throws(
|
||||
() => waitForMessage(messageManager, "message", { checkFn }),
|
||||
/TypeError/
|
||||
);
|
||||
}
|
||||
|
||||
let data1 = {"fo": "bar"};
|
||||
let data2 = {"foo": "bar"};
|
||||
let data1 = { fo: "bar" };
|
||||
let data2 = { foo: "bar" };
|
||||
|
||||
for (let checkFn of [null, undefined, msg => "foo" in msg.data]) {
|
||||
let expected_data = (checkFn == null) ? data1 : data2;
|
||||
let expected_data = checkFn == null ? data1 : data2;
|
||||
|
||||
messageManager = new MessageManager();
|
||||
let sent = waitForMessage(messageManager, "message", {checkFn});
|
||||
let sent = waitForMessage(messageManager, "message", { checkFn });
|
||||
messageManager.send("message", data1);
|
||||
messageManager.send("message", data2);
|
||||
equal(expected_data, await sent);
|
||||
|
@ -429,7 +462,7 @@ add_task(async function test_waitForObserverTopic_topicTypes() {
|
|||
Assert.throws(() => waitForObserverTopic(topic), /TypeError/);
|
||||
}
|
||||
|
||||
let data = {"foo": "bar"};
|
||||
let data = { foo: "bar" };
|
||||
let sent = waitForObserverTopic("message");
|
||||
Services.obs.notifyObservers(this, "message", data);
|
||||
let result = await sent;
|
||||
|
@ -439,15 +472,17 @@ add_task(async function test_waitForObserverTopic_topicTypes() {
|
|||
|
||||
add_task(async function test_waitForObserverTopic_checkFnTypes() {
|
||||
for (let checkFn of ["foo", 42, true, [], {}]) {
|
||||
Assert.throws(() => waitForObserverTopic(
|
||||
"message", {checkFn}), /TypeError/);
|
||||
Assert.throws(
|
||||
() => waitForObserverTopic("message", { checkFn }),
|
||||
/TypeError/
|
||||
);
|
||||
}
|
||||
|
||||
let data1 = {"fo": "bar"};
|
||||
let data2 = {"foo": "bar"};
|
||||
let data1 = { fo: "bar" };
|
||||
let data2 = { foo: "bar" };
|
||||
|
||||
for (let checkFn of [null, undefined, (subject, data) => data == data2]) {
|
||||
let expected_data = (checkFn == null) ? data1 : data2;
|
||||
let expected_data = checkFn == null ? data1 : data2;
|
||||
|
||||
let sent = waitForObserverTopic("message");
|
||||
Services.obs.notifyObservers(this, "message", data1);
|
||||
|
|
|
@ -8,30 +8,34 @@
|
|||
|
||||
const CC = Components.Constructor;
|
||||
|
||||
const {EventEmitter} = ChromeUtils.import("resource://gre/modules/EventEmitter.jsm");
|
||||
const {
|
||||
StreamUtils,
|
||||
} = ChromeUtils.import("chrome://marionette/content/stream-utils.js");
|
||||
const {
|
||||
BulkPacket,
|
||||
JSONPacket,
|
||||
Packet,
|
||||
} = ChromeUtils.import("chrome://marionette/content/packets.js");
|
||||
const {
|
||||
executeSoon,
|
||||
} = ChromeUtils.import("chrome://marionette/content/sync.js");
|
||||
const { EventEmitter } = ChromeUtils.import(
|
||||
"resource://gre/modules/EventEmitter.jsm"
|
||||
);
|
||||
const { StreamUtils } = ChromeUtils.import(
|
||||
"chrome://marionette/content/stream-utils.js"
|
||||
);
|
||||
const { BulkPacket, JSONPacket, Packet } = ChromeUtils.import(
|
||||
"chrome://marionette/content/packets.js"
|
||||
);
|
||||
const { executeSoon } = ChromeUtils.import(
|
||||
"chrome://marionette/content/sync.js"
|
||||
);
|
||||
|
||||
const flags = {wantVerbose: false, wantLogging: false};
|
||||
const flags = { wantVerbose: false, wantLogging: false };
|
||||
|
||||
const dumpv =
|
||||
flags.wantVerbose ?
|
||||
function(msg) { dump(msg + "\n"); } :
|
||||
function() {};
|
||||
const dumpv = flags.wantVerbose
|
||||
? function(msg) {
|
||||
dump(msg + "\n");
|
||||
}
|
||||
: function() {};
|
||||
|
||||
const Pipe = CC("@mozilla.org/pipe;1", "nsIPipe", "init");
|
||||
|
||||
const ScriptableInputStream = CC("@mozilla.org/scriptableinputstream;1",
|
||||
"nsIScriptableInputStream", "init");
|
||||
const ScriptableInputStream = CC(
|
||||
"@mozilla.org/scriptableinputstream;1",
|
||||
"nsIScriptableInputStream",
|
||||
"init"
|
||||
);
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["DebuggerTransport"];
|
||||
|
||||
|
@ -361,9 +365,12 @@ DebuggerTransport.prototype = {
|
|||
*/
|
||||
onInputStreamReady(stream) {
|
||||
try {
|
||||
while (stream.available() && this._incomingEnabled &&
|
||||
this._processIncoming(stream, stream.available())) {
|
||||
// Loop until there is nothing more to process
|
||||
while (
|
||||
stream.available() &&
|
||||
this._incomingEnabled &&
|
||||
this._processIncoming(stream, stream.available())
|
||||
) {
|
||||
// Loop until there is nothing more to process
|
||||
}
|
||||
this._waitForIncoming();
|
||||
} catch (e) {
|
||||
|
@ -407,8 +414,9 @@ DebuggerTransport.prototype = {
|
|||
// header pattern.
|
||||
this._incoming = Packet.fromHeader(this._incomingHeader, this);
|
||||
if (!this._incoming) {
|
||||
throw new Error("No packet types for header: " +
|
||||
this._incomingHeader);
|
||||
throw new Error(
|
||||
"No packet types for header: " + this._incomingHeader
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -446,8 +454,11 @@ DebuggerTransport.prototype = {
|
|||
*/
|
||||
_readHeader() {
|
||||
let amountToRead = PACKET_HEADER_MAX - this._incomingHeader.length;
|
||||
this._incomingHeader +=
|
||||
StreamUtils.delimitedRead(this._scriptableInput, ":", amountToRead);
|
||||
this._incomingHeader += StreamUtils.delimitedRead(
|
||||
this._scriptableInput,
|
||||
":",
|
||||
amountToRead
|
||||
);
|
||||
if (flags.wantVerbose) {
|
||||
dumpv("Header read: " + this._incomingHeader);
|
||||
}
|
||||
|
@ -486,7 +497,7 @@ DebuggerTransport.prototype = {
|
|||
*/
|
||||
_onJSONObjectReady(object) {
|
||||
executeSoon(() => {
|
||||
// Ensure the transport is still alive by the time this runs.
|
||||
// Ensure the transport is still alive by the time this runs.
|
||||
if (this.active) {
|
||||
this.emit("packet", object);
|
||||
this.hooks.onPacket(object);
|
||||
|
@ -502,7 +513,7 @@ DebuggerTransport.prototype = {
|
|||
*/
|
||||
_onBulkReadReady(...args) {
|
||||
executeSoon(() => {
|
||||
// Ensure the transport is still alive by the time this runs.
|
||||
// Ensure the transport is still alive by the time this runs.
|
||||
if (this.active) {
|
||||
this.emit("bulkpacket", ...args);
|
||||
this.hooks.onBulkPacket(...args);
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -6,12 +6,10 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = [
|
||||
"ContentTask",
|
||||
];
|
||||
var EXPORTED_SYMBOLS = ["ContentTask"];
|
||||
|
||||
const {Promise} = ChromeUtils.import("resource://gre/modules/Promise.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Promise } = ChromeUtils.import("resource://gre/modules/Promise.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const FRAME_SCRIPT = "resource://testing-common/content-task.js";
|
||||
|
||||
|
@ -77,13 +75,11 @@ var ContentTask = {
|
|||
let id = gMessageID++;
|
||||
gPromises.set(id, deferred);
|
||||
|
||||
browser.messageManager.sendAsyncMessage(
|
||||
"content-task:spawn",
|
||||
{
|
||||
id,
|
||||
runnable: task.toString(),
|
||||
arg,
|
||||
});
|
||||
browser.messageManager.sendAsyncMessage("content-task:spawn", {
|
||||
id,
|
||||
runnable: task.toString(),
|
||||
arg,
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
@ -113,19 +109,40 @@ var ContentMessageListener = {
|
|||
}
|
||||
} else if (aMessage.name == "content-task:test-result") {
|
||||
let data = aMessage.data;
|
||||
ContentTask._testScope.record(data.condition, data.name, null, data.stack);
|
||||
ContentTask._testScope.record(
|
||||
data.condition,
|
||||
data.name,
|
||||
null,
|
||||
data.stack
|
||||
);
|
||||
} else if (aMessage.name == "content-task:test-info") {
|
||||
ContentTask._testScope.info(aMessage.data.name);
|
||||
} else if (aMessage.name == "content-task:test-todo") {
|
||||
ContentTask._testScope.todo(aMessage.data.expr, aMessage.data.name);
|
||||
} else if (aMessage.name == "content-task:test-todo_is") {
|
||||
ContentTask._testScope.todo_is(aMessage.data.a, aMessage.data.b, aMessage.data.name);
|
||||
ContentTask._testScope.todo_is(
|
||||
aMessage.data.a,
|
||||
aMessage.data.b,
|
||||
aMessage.data.name
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Services.mm.addMessageListener("content-task:complete", ContentMessageListener);
|
||||
Services.mm.addMessageListener("content-task:test-result", ContentMessageListener);
|
||||
Services.mm.addMessageListener("content-task:test-info", ContentMessageListener);
|
||||
Services.mm.addMessageListener("content-task:test-todo", ContentMessageListener);
|
||||
Services.mm.addMessageListener("content-task:test-todo_is", ContentMessageListener);
|
||||
Services.mm.addMessageListener(
|
||||
"content-task:test-result",
|
||||
ContentMessageListener
|
||||
);
|
||||
Services.mm.addMessageListener(
|
||||
"content-task:test-info",
|
||||
ContentMessageListener
|
||||
);
|
||||
Services.mm.addMessageListener(
|
||||
"content-task:test-todo",
|
||||
ContentMessageListener
|
||||
);
|
||||
Services.mm.addMessageListener(
|
||||
"content-task:test-todo_is",
|
||||
ContentMessageListener
|
||||
);
|
||||
|
|
|
@ -12,12 +12,12 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = [
|
||||
"ContentTaskUtils",
|
||||
];
|
||||
var EXPORTED_SYMBOLS = ["ContentTaskUtils"];
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {clearInterval, setInterval, setTimeout} = ChromeUtils.import("resource://gre/modules/Timer.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { clearInterval, setInterval, setTimeout } = ChromeUtils.import(
|
||||
"resource://gre/modules/Timer.jsm"
|
||||
);
|
||||
|
||||
var ContentTaskUtils = {
|
||||
/**
|
||||
|
@ -30,14 +30,17 @@ var ContentTaskUtils = {
|
|||
*/
|
||||
is_hidden(element) {
|
||||
var style = element.ownerGlobal.getComputedStyle(element);
|
||||
if (style.display == "none")
|
||||
if (style.display == "none") {
|
||||
return true;
|
||||
if (style.visibility != "visible")
|
||||
}
|
||||
if (style.visibility != "visible") {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Hiding a parent element will hide all its children
|
||||
if (element.parentNode != element.ownerDocument)
|
||||
if (element.parentNode != element.ownerDocument) {
|
||||
return ContentTaskUtils.is_hidden(element.parentNode);
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
@ -52,14 +55,17 @@ var ContentTaskUtils = {
|
|||
*/
|
||||
is_visible(element) {
|
||||
var style = element.ownerGlobal.getComputedStyle(element);
|
||||
if (style.display == "none")
|
||||
if (style.display == "none") {
|
||||
return false;
|
||||
if (style.visibility != "visible")
|
||||
}
|
||||
if (style.visibility != "visible") {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Hiding a parent element will hide all its children
|
||||
if (element.parentNode != element.ownerDocument)
|
||||
if (element.parentNode != element.ownerDocument) {
|
||||
return ContentTaskUtils.is_visible(element.parentNode);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
@ -146,22 +152,27 @@ var ContentTaskUtils = {
|
|||
*/
|
||||
waitForEvent(subject, eventName, capture, checkFn, wantsUntrusted = false) {
|
||||
return new Promise((resolve, reject) => {
|
||||
subject.addEventListener(eventName, function listener(event) {
|
||||
try {
|
||||
if (checkFn && !checkFn(event)) {
|
||||
return;
|
||||
}
|
||||
subject.removeEventListener(eventName, listener, capture);
|
||||
setTimeout(() => resolve(event), 0);
|
||||
} catch (ex) {
|
||||
subject.addEventListener(
|
||||
eventName,
|
||||
function listener(event) {
|
||||
try {
|
||||
if (checkFn && !checkFn(event)) {
|
||||
return;
|
||||
}
|
||||
subject.removeEventListener(eventName, listener, capture);
|
||||
} catch (ex2) {
|
||||
// Maybe the provided object does not support removeEventListener.
|
||||
setTimeout(() => resolve(event), 0);
|
||||
} catch (ex) {
|
||||
try {
|
||||
subject.removeEventListener(eventName, listener, capture);
|
||||
} catch (ex2) {
|
||||
// Maybe the provided object does not support removeEventListener.
|
||||
}
|
||||
setTimeout(() => reject(ex), 0);
|
||||
}
|
||||
setTimeout(() => reject(ex), 0);
|
||||
}
|
||||
}, capture, wantsUntrusted);
|
||||
},
|
||||
capture,
|
||||
wantsUntrusted
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -179,7 +190,7 @@ var ContentTaskUtils = {
|
|||
return content._EventUtils;
|
||||
}
|
||||
|
||||
let EventUtils = content._EventUtils = {};
|
||||
let EventUtils = (content._EventUtils = {});
|
||||
|
||||
EventUtils.window = {};
|
||||
EventUtils.parent = EventUtils.window;
|
||||
|
@ -192,7 +203,9 @@ var ContentTaskUtils = {
|
|||
EventUtils.KeyboardEvent = content.KeyboardEvent;
|
||||
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils);
|
||||
"chrome://mochikit/content/tests/SimpleTest/EventUtils.js",
|
||||
EventUtils
|
||||
);
|
||||
|
||||
return EventUtils;
|
||||
},
|
||||
|
|
|
@ -4,9 +4,11 @@
|
|||
|
||||
var Cm = Components.manager;
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const { generateUUID } = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
|
||||
const { generateUUID } = Cc["@mozilla.org/uuid-generator;1"].getService(
|
||||
Ci.nsIUUIDGenerator
|
||||
);
|
||||
|
||||
function AboutPage(aboutHost, chromeURL, uriFlags) {
|
||||
this.chromeURL = chromeURL;
|
||||
|
@ -18,14 +20,14 @@ function AboutPage(aboutHost, chromeURL, uriFlags) {
|
|||
|
||||
AboutPage.prototype = {
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIAboutModule]),
|
||||
getURIFlags(aURI) { // eslint-disable-line no-unused-vars
|
||||
getURIFlags(aURI) {
|
||||
// eslint-disable-line no-unused-vars
|
||||
return this.uriFlags;
|
||||
},
|
||||
|
||||
newChannel(aURI, aLoadInfo) {
|
||||
let newURI = Services.io.newURI(this.chromeURL);
|
||||
let channel = Services.io.newChannelFromURIWithLoadInfo(newURI,
|
||||
aLoadInfo);
|
||||
let channel = Services.io.newChannelFromURIWithLoadInfo(newURI, aLoadInfo);
|
||||
channel.originalURI = aURI;
|
||||
|
||||
if (this.uriFlags & Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT) {
|
||||
|
@ -43,27 +45,35 @@ AboutPage.prototype = {
|
|||
|
||||
register() {
|
||||
Cm.QueryInterface(Ci.nsIComponentRegistrar).registerFactory(
|
||||
this.classID, this.description,
|
||||
"@mozilla.org/network/protocol/about;1?what=" + this.aboutHost, this);
|
||||
this.classID,
|
||||
this.description,
|
||||
"@mozilla.org/network/protocol/about;1?what=" + this.aboutHost,
|
||||
this
|
||||
);
|
||||
},
|
||||
|
||||
unregister() {
|
||||
Cm.QueryInterface(Ci.nsIComponentRegistrar).unregisterFactory(
|
||||
this.classID, this);
|
||||
this.classID,
|
||||
this
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
const gRegisteredPages = new Map();
|
||||
|
||||
addMessageListener("browser-test-utils:about-registration:register", msg => {
|
||||
let {aboutModule, pageURI, flags} = msg.data;
|
||||
let { aboutModule, pageURI, flags } = msg.data;
|
||||
if (gRegisteredPages.has(aboutModule)) {
|
||||
gRegisteredPages.get(aboutModule).unregister();
|
||||
}
|
||||
let moduleObj = new AboutPage(aboutModule, pageURI, flags);
|
||||
moduleObj.register();
|
||||
gRegisteredPages.set(aboutModule, moduleObj);
|
||||
sendAsyncMessage("browser-test-utils:about-registration:registered", aboutModule);
|
||||
sendAsyncMessage(
|
||||
"browser-test-utils:about-registration:registered",
|
||||
aboutModule
|
||||
);
|
||||
});
|
||||
|
||||
addMessageListener("browser-test-utils:about-registration:unregister", msg => {
|
||||
|
@ -73,5 +83,8 @@ addMessageListener("browser-test-utils:about-registration:unregister", msg => {
|
|||
moduleObj.unregister();
|
||||
gRegisteredPages.delete(aboutModule);
|
||||
}
|
||||
sendAsyncMessage("browser-test-utils:about-registration:unregistered", aboutModule);
|
||||
sendAsyncMessage(
|
||||
"browser-test-utils:about-registration:unregistered",
|
||||
aboutModule
|
||||
);
|
||||
});
|
||||
|
|
|
@ -8,7 +8,10 @@
|
|||
|
||||
ChromeUtils.import("resource://testing-common/Task.jsm", this);
|
||||
ChromeUtils.import("resource://testing-common/ContentTaskUtils.jsm", this);
|
||||
const AssertCls = ChromeUtils.import("resource://testing-common/Assert.jsm", null).Assert;
|
||||
const AssertCls = ChromeUtils.import(
|
||||
"resource://testing-common/Assert.jsm",
|
||||
null
|
||||
).Assert;
|
||||
|
||||
addMessageListener("content-task:spawn", function(msg) {
|
||||
let id = msg.data.id;
|
||||
|
@ -37,15 +40,15 @@ addMessageListener("content-task:spawn", function(msg) {
|
|||
var isnot = Assert.notEqual.bind(Assert);
|
||||
|
||||
function todo(expr, name) {
|
||||
sendAsyncMessage("content-task:test-todo", {id, expr, name});
|
||||
sendAsyncMessage("content-task:test-todo", { id, expr, name });
|
||||
}
|
||||
|
||||
function todo_is(a, b, name) {
|
||||
sendAsyncMessage("content-task:test-todo_is", {id, a, b, name});
|
||||
sendAsyncMessage("content-task:test-todo_is", { id, a, b, name });
|
||||
}
|
||||
|
||||
function info(name) {
|
||||
sendAsyncMessage("content-task:test-info", {id, name});
|
||||
sendAsyncMessage("content-task:test-info", { id, name });
|
||||
}
|
||||
/* eslint-enable no-unused-vars */
|
||||
|
||||
|
@ -58,17 +61,20 @@ addMessageListener("content-task:spawn", function(msg) {
|
|||
// eslint-disable-next-line no-eval
|
||||
let runnable = eval(runnablestr);
|
||||
let iterator = runnable.call(this, msg.data.arg);
|
||||
Task.spawn(iterator).then((val) => {
|
||||
sendAsyncMessage("content-task:complete", {
|
||||
id,
|
||||
result: val,
|
||||
});
|
||||
}, (e) => {
|
||||
sendAsyncMessage("content-task:complete", {
|
||||
id,
|
||||
error: e.toString(),
|
||||
});
|
||||
});
|
||||
Task.spawn(iterator).then(
|
||||
val => {
|
||||
sendAsyncMessage("content-task:complete", {
|
||||
id,
|
||||
result: val,
|
||||
});
|
||||
},
|
||||
e => {
|
||||
sendAsyncMessage("content-task:complete", {
|
||||
id,
|
||||
error: e.toString(),
|
||||
});
|
||||
}
|
||||
);
|
||||
} catch (e) {
|
||||
sendAsyncMessage("content-task:complete", {
|
||||
id,
|
||||
|
|
|
@ -6,18 +6,30 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
addEventListener("DOMContentLoaded", function(event) {
|
||||
let subframe = event.target != content.document;
|
||||
// For error page, internalURL is 'about:neterror?...', and visibleURL
|
||||
// is the original URL.
|
||||
sendAsyncMessage("browser-test-utils:DOMContentLoadedEvent",
|
||||
{subframe, internalURL: event.target.documentURI,
|
||||
visibleURL: content.document.location.href});
|
||||
}, true);
|
||||
addEventListener(
|
||||
"DOMContentLoaded",
|
||||
function(event) {
|
||||
let subframe = event.target != content.document;
|
||||
// For error page, internalURL is 'about:neterror?...', and visibleURL
|
||||
// is the original URL.
|
||||
sendAsyncMessage("browser-test-utils:DOMContentLoadedEvent", {
|
||||
subframe,
|
||||
internalURL: event.target.documentURI,
|
||||
visibleURL: content.document.location.href,
|
||||
});
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
addEventListener("load", function(event) {
|
||||
let subframe = event.target != content.document;
|
||||
sendAsyncMessage("browser-test-utils:loadEvent",
|
||||
{subframe, internalURL: event.target.documentURI,
|
||||
visibleURL: content.document.location.href});
|
||||
}, true);
|
||||
addEventListener(
|
||||
"load",
|
||||
function(event) {
|
||||
let subframe = event.target != content.document;
|
||||
sendAsyncMessage("browser-test-utils:loadEvent", {
|
||||
subframe,
|
||||
internalURL: event.target.documentURI,
|
||||
visibleURL: content.document.location.href,
|
||||
});
|
||||
},
|
||||
true
|
||||
);
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* 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 {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {setTimeout} = ChromeUtils.import("resource://gre/modules/Timer.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { setTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm");
|
||||
|
||||
var EXPORTED_SYMBOLS = ["ContentCollector"];
|
||||
|
||||
|
@ -14,11 +14,11 @@ var EXPORTED_SYMBOLS = ["ContentCollector"];
|
|||
|
||||
var ContentCollector = {
|
||||
init() {
|
||||
let processType = Services.appinfo.processType;
|
||||
if (processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
|
||||
// In the main process, we handle triggering collections in browser-test.js
|
||||
return;
|
||||
}
|
||||
let processType = Services.appinfo.processType;
|
||||
if (processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
|
||||
// In the main process, we handle triggering collections in browser-test.js
|
||||
return;
|
||||
}
|
||||
|
||||
Services.cpmm.addMessageListener("browser-test:collect-request", this);
|
||||
},
|
||||
|
@ -59,6 +59,5 @@ var ContentCollector = {
|
|||
|
||||
Services.cpmm.removeMessageListener("browser-test:collect-request", this);
|
||||
},
|
||||
|
||||
};
|
||||
ContentCollector.init();
|
||||
|
|
|
@ -4,13 +4,24 @@
|
|||
|
||||
/* globals ExtensionAPI */
|
||||
|
||||
const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { AppConstants } = ChromeUtils.import(
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function loadChromeScripts(win) {
|
||||
Services.scriptloader.loadSubScript("chrome://mochikit/content/chrome-harness.js", win);
|
||||
Services.scriptloader.loadSubScript("chrome://mochikit/content/mochitest-e10s-utils.js", win);
|
||||
Services.scriptloader.loadSubScript("chrome://mochikit/content/browser-test.js", win);
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochikit/content/chrome-harness.js",
|
||||
win
|
||||
);
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochikit/content/mochitest-e10s-utils.js",
|
||||
win
|
||||
);
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochikit/content/browser-test.js",
|
||||
win
|
||||
);
|
||||
}
|
||||
|
||||
// ///// Android ///////
|
||||
|
@ -23,10 +34,11 @@ const windowTracker = {
|
|||
async observe(window, topic, data) {
|
||||
if (topic === "chrome-document-global-created") {
|
||||
await new Promise(resolve =>
|
||||
window.addEventListener("DOMContentLoaded", resolve, {once: true}));
|
||||
window.addEventListener("DOMContentLoaded", resolve, { once: true })
|
||||
);
|
||||
|
||||
let {document} = window;
|
||||
let {documentURI} = document;
|
||||
let { document } = window;
|
||||
let { documentURI } = document;
|
||||
|
||||
if (documentURI !== AppConstants.BROWSER_CHROME_URL) {
|
||||
return;
|
||||
|
@ -60,7 +72,8 @@ function androidStartup() {
|
|||
// ///// Desktop ///////
|
||||
|
||||
// Special case for Thunderbird windows.
|
||||
const IS_THUNDERBIRD = Services.appinfo.ID == "{3550f703-e582-4d05-9a08-453d09bdfdc6}";
|
||||
const IS_THUNDERBIRD =
|
||||
Services.appinfo.ID == "{3550f703-e582-4d05-9a08-453d09bdfdc6}";
|
||||
const WINDOW_TYPE = IS_THUNDERBIRD ? "mail:3pane" : "navigator:browser";
|
||||
|
||||
var WindowListener = {
|
||||
|
@ -68,8 +81,11 @@ var WindowListener = {
|
|||
// needs to happen in all navigator:browser windows should go here.
|
||||
setupWindow(win) {
|
||||
win.nativeConsole = win.console;
|
||||
ChromeUtils.defineModuleGetter(win, "console",
|
||||
"resource://gre/modules/Console.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
win,
|
||||
"console",
|
||||
"resource://gre/modules/Console.jsm"
|
||||
);
|
||||
},
|
||||
|
||||
tearDownWindow(win) {
|
||||
|
@ -82,11 +98,17 @@ var WindowListener = {
|
|||
onOpenWindow(xulWin) {
|
||||
let win = xulWin.docShell.domWindow;
|
||||
|
||||
win.addEventListener("load", function() {
|
||||
if (win.document.documentElement.getAttribute("windowtype") == WINDOW_TYPE) {
|
||||
WindowListener.setupWindow(win);
|
||||
}
|
||||
}, {once: true});
|
||||
win.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
if (
|
||||
win.document.documentElement.getAttribute("windowtype") == WINDOW_TYPE
|
||||
) {
|
||||
WindowListener.setupWindow(win);
|
||||
}
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -99,8 +121,17 @@ function loadMochitest(e) {
|
|||
|
||||
// for mochitest-plain, navigating to the url is all we need
|
||||
if (!IS_THUNDERBIRD) {
|
||||
win.loadURI(url, null, null, null, null, null, null, null,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
win.loadURI(
|
||||
url,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
Services.scriptSecurityManager.getSystemPrincipal()
|
||||
);
|
||||
}
|
||||
if (flavor == "mochitest") {
|
||||
return;
|
||||
|
@ -114,9 +145,14 @@ function loadMochitest(e) {
|
|||
|
||||
this.mochikit = class extends ExtensionAPI {
|
||||
onStartup() {
|
||||
let aomStartup = Cc["@mozilla.org/addons/addon-manager-startup;1"]
|
||||
.getService(Ci.amIAddonManagerStartup);
|
||||
const manifestURI = Services.io.newURI("manifest.json", null, this.extension.rootURI);
|
||||
let aomStartup = Cc[
|
||||
"@mozilla.org/addons/addon-manager-startup;1"
|
||||
].getService(Ci.amIAddonManagerStartup);
|
||||
const manifestURI = Services.io.newURI(
|
||||
"manifest.json",
|
||||
null,
|
||||
this.extension.rootURI
|
||||
);
|
||||
const targetURL = this.extension.rootURI.resolve("content/");
|
||||
this.chromeHandle = aomStartup.registerChrome(manifestURI, [
|
||||
["content", "mochikit", targetURL],
|
||||
|
|
|
@ -9,5 +9,5 @@ const { setTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm");
|
|||
add_task(async function() {
|
||||
requestLongerTimeout(2);
|
||||
ok(true, "Collecting baseline coverage for javascript (.js) file types.");
|
||||
await new Promise((c) => setTimeout(c, 30 * 1000));
|
||||
await new Promise(c => setTimeout(c, 30 * 1000));
|
||||
});
|
||||
|
|
|
@ -10,13 +10,16 @@ add_task(async function() {
|
|||
requestLongerTimeout(2);
|
||||
let newWin = await BrowserTestUtils.openNewBrowserWindow();
|
||||
|
||||
await BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url: "about:blank",
|
||||
}, async function(browser) {
|
||||
ok(true, "Collecting baseline coverage for browser-chrome tests.");
|
||||
await new Promise((c) => setTimeout(c, 30 * 1000));
|
||||
});
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: "about:blank",
|
||||
},
|
||||
async function(browser) {
|
||||
ok(true, "Collecting baseline coverage for browser-chrome tests.");
|
||||
await new Promise(c => setTimeout(c, 30 * 1000));
|
||||
}
|
||||
);
|
||||
|
||||
await BrowserTestUtils.closeWindow(newWin);
|
||||
});
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -4,8 +4,8 @@
|
|||
* 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/. */
|
||||
|
||||
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
var {NetUtil} = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
|
||||
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
var { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
/* import-globals-from manifestLibrary.js */
|
||||
|
||||
|
@ -32,9 +32,9 @@ function getChromeURI(url) {
|
|||
*/
|
||||
function getResolvedURI(url) {
|
||||
var chromeURI = getChromeURI(url);
|
||||
var resolvedURI = Cc["@mozilla.org/chrome/chrome-registry;1"].
|
||||
getService(Ci.nsIChromeRegistry).
|
||||
convertChromeURL(chromeURI);
|
||||
var resolvedURI = Cc["@mozilla.org/chrome/chrome-registry;1"]
|
||||
.getService(Ci.nsIChromeRegistry)
|
||||
.convertChromeURL(chromeURI);
|
||||
|
||||
try {
|
||||
resolvedURI = resolvedURI.QueryInterface(Ci.nsIJARURI);
|
||||
|
@ -53,8 +53,9 @@ function getResolvedURI(url) {
|
|||
* resolvedURI: nsIURI (from getResolvedURI) that points to a file:/// url
|
||||
*/
|
||||
function getChromeDir(resolvedURI) {
|
||||
var fileHandler = Cc["@mozilla.org/network/protocol;1?name=file"].
|
||||
getService(Ci.nsIFileProtocolHandler);
|
||||
var fileHandler = Cc["@mozilla.org/network/protocol;1?name=file"].getService(
|
||||
Ci.nsIFileProtocolHandler
|
||||
);
|
||||
var chromeDir = fileHandler.getFileFromURLSpec(resolvedURI.spec);
|
||||
return chromeDir.parent.QueryInterface(Ci.nsIFile);
|
||||
}
|
||||
|
@ -112,11 +113,13 @@ function extractJarToTmp(jar) {
|
|||
// in strict mode (which is turned on in debug builds)
|
||||
tmpdir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, parseInt("0777", 8));
|
||||
|
||||
var zReader = Cc["@mozilla.org/libjar/zip-reader;1"].
|
||||
createInstance(Ci.nsIZipReader);
|
||||
var zReader = Cc["@mozilla.org/libjar/zip-reader;1"].createInstance(
|
||||
Ci.nsIZipReader
|
||||
);
|
||||
|
||||
var fileHandler = Cc["@mozilla.org/network/protocol;1?name=file"].
|
||||
getService(Ci.nsIFileProtocolHandler);
|
||||
var fileHandler = Cc["@mozilla.org/network/protocol;1?name=file"].getService(
|
||||
Ci.nsIFileProtocolHandler
|
||||
);
|
||||
|
||||
var fileName = fileHandler.getFileFromURLSpec(jar.JARFile.spec);
|
||||
zReader.open(fileName);
|
||||
|
@ -163,7 +166,7 @@ function getTestFilePath(path) {
|
|||
// Get the chrome/jar uri for the current mochitest file
|
||||
// gTestPath being defined by the test harness in browser-chrome tests
|
||||
// or window is being used for mochitest-browser
|
||||
var baseURI = typeof(gTestPath) == "string" ? gTestPath : window.location.href;
|
||||
var baseURI = typeof gTestPath == "string" ? gTestPath : window.location.href;
|
||||
var parentURI = getResolvedURI(getRootDirectory(baseURI));
|
||||
var file;
|
||||
if (parentURI.JARFile) {
|
||||
|
@ -171,19 +174,19 @@ function getTestFilePath(path) {
|
|||
file = extractJarToTmp(parentURI);
|
||||
} else {
|
||||
// Otherwise, we can directly cast it to a file URI
|
||||
var fileHandler = Cc["@mozilla.org/network/protocol;1?name=file"].
|
||||
getService(Ci.nsIFileProtocolHandler);
|
||||
var fileHandler = Cc[
|
||||
"@mozilla.org/network/protocol;1?name=file"
|
||||
].getService(Ci.nsIFileProtocolHandler);
|
||||
file = fileHandler.getFileFromURLSpec(parentURI.spec);
|
||||
}
|
||||
// Then walk by the given relative path
|
||||
path.split("/")
|
||||
.forEach(function(p) {
|
||||
if (p == "..") {
|
||||
file = file.parent;
|
||||
} else if (p != ".") {
|
||||
file.append(p);
|
||||
}
|
||||
});
|
||||
path.split("/").forEach(function(p) {
|
||||
if (p == "..") {
|
||||
file = file.parent;
|
||||
} else if (p != ".") {
|
||||
file.append(p);
|
||||
}
|
||||
});
|
||||
return file.path;
|
||||
}
|
||||
|
||||
|
@ -199,8 +202,7 @@ function buildRelativePath(jarentryname, destdir, basepath) {
|
|||
|
||||
var parts = jarentryname.split("/");
|
||||
|
||||
var targetFile = Cc["@mozilla.org/file/local;1"]
|
||||
.createInstance(Ci.nsIFile);
|
||||
var targetFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
targetFile.initWithFile(destdir);
|
||||
|
||||
for (var i = baseParts.length; i < parts.length; i++) {
|
||||
|
@ -216,14 +218,19 @@ function readConfig(filename) {
|
|||
var configFile = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
configFile.append(filename);
|
||||
|
||||
if (!configFile.exists())
|
||||
if (!configFile.exists()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
var fileInStream = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Ci.nsIFileInputStream);
|
||||
var fileInStream = Cc[
|
||||
"@mozilla.org/network/file-input-stream;1"
|
||||
].createInstance(Ci.nsIFileInputStream);
|
||||
fileInStream.init(configFile, -1, 0, 0);
|
||||
|
||||
var str = NetUtil.readInputStreamToString(fileInStream, fileInStream.available());
|
||||
var str = NetUtil.readInputStreamToString(
|
||||
fileInStream,
|
||||
fileInStream.available()
|
||||
);
|
||||
fileInStream.close();
|
||||
return JSON.parse(str);
|
||||
}
|
||||
|
@ -248,5 +255,9 @@ function getTestList(params, callback) {
|
|||
}
|
||||
}
|
||||
params = config;
|
||||
getTestManifest("http://mochi.test:8888/" + params.manifestFile, params, callback);
|
||||
getTestManifest(
|
||||
"http://mochi.test:8888/" + params.manifestFile,
|
||||
params,
|
||||
callback
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function skipTests(tests, startTestPattern, endTestPattern) {
|
||||
var startIndex = 0, endIndex = tests.length - 1;
|
||||
var startIndex = 0,
|
||||
endIndex = tests.length - 1;
|
||||
for (var i = 0; i < tests.length; ++i) {
|
||||
var test_path;
|
||||
if ((tests[i] instanceof Object) && ("test" in tests[i])) {
|
||||
if (tests[i] instanceof Object && "test" in tests[i]) {
|
||||
test_path = tests[i].test.url;
|
||||
} else if ((tests[i] instanceof Object) && ("url" in tests[i])) {
|
||||
} else if (tests[i] instanceof Object && "url" in tests[i]) {
|
||||
test_path = tests[i].url;
|
||||
} else {
|
||||
test_path = tests[i];
|
||||
|
|
|
@ -26,10 +26,22 @@ function parseTestManifest(testManifest, params, callback) {
|
|||
}
|
||||
if (params.testRoot != "tests" && params.testRoot !== undefined) {
|
||||
let name = params.baseurl + "/" + params.testRoot + "/" + path;
|
||||
links[name] = {"test": {"url": name, "expected": obj.expected, "uses-unsafe-cpows": obj["uses-unsafe-cpows"]}};
|
||||
links[name] = {
|
||||
test: {
|
||||
url: name,
|
||||
expected: obj.expected,
|
||||
"uses-unsafe-cpows": obj["uses-unsafe-cpows"],
|
||||
},
|
||||
};
|
||||
} else {
|
||||
let name = params.testPrefix + path;
|
||||
paths.push({"test": {"url": name, "expected": obj.expected, "uses-unsafe-cpows": obj["uses-unsafe-cpows"]}});
|
||||
paths.push({
|
||||
test: {
|
||||
url: name,
|
||||
expected: obj.expected,
|
||||
"uses-unsafe-cpows": obj["uses-unsafe-cpows"],
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
if (paths.length > 0) {
|
||||
|
@ -48,11 +60,23 @@ function getTestManifest(url, params, callback) {
|
|||
try {
|
||||
parseTestManifest(JSON.parse(req.responseText), params, callback);
|
||||
} catch (e) {
|
||||
dump("TEST-UNEXPECTED-FAIL: manifestLibrary.js | error parsing " + url + " (" + e + ")\n");
|
||||
dump(
|
||||
"TEST-UNEXPECTED-FAIL: manifestLibrary.js | error parsing " +
|
||||
url +
|
||||
" (" +
|
||||
e +
|
||||
")\n"
|
||||
);
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
dump("TEST-UNEXPECTED-FAIL: manifestLibrary.js | error loading " + url + " (HTTP " + req.status + ")\n");
|
||||
dump(
|
||||
"TEST-UNEXPECTED-FAIL: manifestLibrary.js | error loading " +
|
||||
url +
|
||||
" (HTTP " +
|
||||
req.status +
|
||||
")\n"
|
||||
);
|
||||
callback({});
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +127,7 @@ function filterTests(filter, testList, runOnly) {
|
|||
if (Object.keys(runtests).length) {
|
||||
for (let i = 0; i < testList.length; i++) {
|
||||
let testpath;
|
||||
if ((testList[i] instanceof Object) && ("test" in testList[i])) {
|
||||
if (testList[i] instanceof Object && "test" in testList[i]) {
|
||||
testpath = testList[i].test.url;
|
||||
} else {
|
||||
testpath = testList[i];
|
||||
|
@ -135,7 +159,7 @@ function filterTests(filter, testList, runOnly) {
|
|||
for (let i = 0; i < filteredTests.length; i++) {
|
||||
let found = false;
|
||||
let testpath;
|
||||
if ((filteredTests[i] instanceof Object) && ("test" in filteredTests[i])) {
|
||||
if (filteredTests[i] instanceof Object && "test" in filteredTests[i]) {
|
||||
testpath = filteredTests[i].test.url;
|
||||
} else {
|
||||
testpath = filteredTests[i];
|
||||
|
|
|
@ -3,9 +3,16 @@
|
|||
function e10s_init() {
|
||||
// Listen for an 'oop-browser-crashed' event and log it so people analysing
|
||||
// test logs have a clue about what is going on.
|
||||
window.addEventListener("oop-browser-crashed", (event) => {
|
||||
let uri = event.target.currentURI;
|
||||
Cu.reportError("remote browser crashed while on " +
|
||||
(uri ? uri.spec : "<unknown>") + "\n");
|
||||
}, true);
|
||||
window.addEventListener(
|
||||
"oop-browser-crashed",
|
||||
event => {
|
||||
let uri = event.target.currentURI;
|
||||
Cu.reportError(
|
||||
"remote browser crashed while on " +
|
||||
(uri ? uri.spec : "<unknown>") +
|
||||
"\n"
|
||||
);
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
// Disable automatic network detection, so tests work correctly when
|
||||
// not connected to a network.
|
||||
// eslint-disable-next-line mozilla/use-services
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
|
||||
ios.manageOfflineStatus = false;
|
||||
ios.offline = false;
|
||||
|
||||
|
@ -38,18 +37,99 @@ var server; // for use in the shutdown handler, if necessary
|
|||
SELECT, SMALL, SPAN, STRIKE, STRONG, STYLE, SUB,
|
||||
SUP, TABLE, TBODY, TD, TEXTAREA, TFOOT, TH, THEAD,
|
||||
TITLE, TR, TT, U, UL, VAR */
|
||||
var tags = ["A", "ABBR", "ACRONYM", "ADDRESS", "APPLET", "AREA", "B", "BASE",
|
||||
"BASEFONT", "BDO", "BIG", "BLOCKQUOTE", "BODY", "BR", "BUTTON",
|
||||
"CAPTION", "CENTER", "CITE", "CODE", "COL", "COLGROUP", "DD",
|
||||
"DEL", "DFN", "DIR", "DIV", "DL", "DT", "EM", "FIELDSET", "FONT",
|
||||
"FORM", "FRAME", "FRAMESET", "H1", "H2", "H3", "H4", "H5", "H6",
|
||||
"HEAD", "HR", "HTML", "I", "IFRAME", "IMG", "INPUT", "INS",
|
||||
"ISINDEX", "KBD", "LABEL", "LEGEND", "LI", "LINK", "MAP", "MENU",
|
||||
"META", "NOFRAMES", "NOSCRIPT", "OBJECT", "OL", "OPTGROUP",
|
||||
"OPTION", "P", "PARAM", "PRE", "Q", "S", "SAMP", "SCRIPT",
|
||||
"SELECT", "SMALL", "SPAN", "STRIKE", "STRONG", "STYLE", "SUB",
|
||||
"SUP", "TABLE", "TBODY", "TD", "TEXTAREA", "TFOOT", "TH", "THEAD",
|
||||
"TITLE", "TR", "TT", "U", "UL", "VAR"];
|
||||
var tags = [
|
||||
"A",
|
||||
"ABBR",
|
||||
"ACRONYM",
|
||||
"ADDRESS",
|
||||
"APPLET",
|
||||
"AREA",
|
||||
"B",
|
||||
"BASE",
|
||||
"BASEFONT",
|
||||
"BDO",
|
||||
"BIG",
|
||||
"BLOCKQUOTE",
|
||||
"BODY",
|
||||
"BR",
|
||||
"BUTTON",
|
||||
"CAPTION",
|
||||
"CENTER",
|
||||
"CITE",
|
||||
"CODE",
|
||||
"COL",
|
||||
"COLGROUP",
|
||||
"DD",
|
||||
"DEL",
|
||||
"DFN",
|
||||
"DIR",
|
||||
"DIV",
|
||||
"DL",
|
||||
"DT",
|
||||
"EM",
|
||||
"FIELDSET",
|
||||
"FONT",
|
||||
"FORM",
|
||||
"FRAME",
|
||||
"FRAMESET",
|
||||
"H1",
|
||||
"H2",
|
||||
"H3",
|
||||
"H4",
|
||||
"H5",
|
||||
"H6",
|
||||
"HEAD",
|
||||
"HR",
|
||||
"HTML",
|
||||
"I",
|
||||
"IFRAME",
|
||||
"IMG",
|
||||
"INPUT",
|
||||
"INS",
|
||||
"ISINDEX",
|
||||
"KBD",
|
||||
"LABEL",
|
||||
"LEGEND",
|
||||
"LI",
|
||||
"LINK",
|
||||
"MAP",
|
||||
"MENU",
|
||||
"META",
|
||||
"NOFRAMES",
|
||||
"NOSCRIPT",
|
||||
"OBJECT",
|
||||
"OL",
|
||||
"OPTGROUP",
|
||||
"OPTION",
|
||||
"P",
|
||||
"PARAM",
|
||||
"PRE",
|
||||
"Q",
|
||||
"S",
|
||||
"SAMP",
|
||||
"SCRIPT",
|
||||
"SELECT",
|
||||
"SMALL",
|
||||
"SPAN",
|
||||
"STRIKE",
|
||||
"STRONG",
|
||||
"STYLE",
|
||||
"SUB",
|
||||
"SUP",
|
||||
"TABLE",
|
||||
"TBODY",
|
||||
"TD",
|
||||
"TEXTAREA",
|
||||
"TFOOT",
|
||||
"TH",
|
||||
"THEAD",
|
||||
"TITLE",
|
||||
"TR",
|
||||
"TT",
|
||||
"U",
|
||||
"UL",
|
||||
"VAR",
|
||||
];
|
||||
|
||||
/**
|
||||
* Below, we'll use makeTagFunc to create a function for each of the
|
||||
|
@ -93,7 +173,7 @@ function makeTagFunc(tagName) {
|
|||
function makeTags() {
|
||||
// map our global HTML generation functions
|
||||
for (let tag of tags) {
|
||||
this[tag] = makeTagFunc(tag.toLowerCase());
|
||||
this[tag] = makeTagFunc(tag.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,7 +217,7 @@ function runServer() {
|
|||
|
||||
// verify server address
|
||||
// if a.b.c.d or 'localhost'
|
||||
if (typeof(_SERVER_ADDR) != "undefined") {
|
||||
if (typeof _SERVER_ADDR != "undefined") {
|
||||
if (_SERVER_ADDR == "localhost") {
|
||||
gServerAddress = _SERVER_ADDR;
|
||||
} else {
|
||||
|
@ -145,40 +225,49 @@ function runServer() {
|
|||
if (quads.length == 4) {
|
||||
var invalid = false;
|
||||
for (var i = 0; i < 4; i++) {
|
||||
if (quads[i] < 0 || quads[i] > 255)
|
||||
if (quads[i] < 0 || quads[i] > 255) {
|
||||
invalid = true;
|
||||
}
|
||||
}
|
||||
if (!invalid)
|
||||
if (!invalid) {
|
||||
gServerAddress = _SERVER_ADDR;
|
||||
else
|
||||
throw new Error("invalid _SERVER_ADDR, please specify a valid IP Address");
|
||||
} else {
|
||||
throw new Error(
|
||||
"invalid _SERVER_ADDR, please specify a valid IP Address"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Error("please define _SERVER_ADDR (as an ip address) before running server.js");
|
||||
throw new Error(
|
||||
"please define _SERVER_ADDR (as an ip address) before running server.js"
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof(_SERVER_PORT) != "undefined") {
|
||||
if (parseInt(_SERVER_PORT) > 0 && parseInt(_SERVER_PORT) < 65536)
|
||||
if (typeof _SERVER_PORT != "undefined") {
|
||||
if (parseInt(_SERVER_PORT) > 0 && parseInt(_SERVER_PORT) < 65536) {
|
||||
SERVER_PORT = _SERVER_PORT;
|
||||
}
|
||||
} else {
|
||||
throw new Error("please define _SERVER_PORT (as a port number) before running server.js");
|
||||
throw new Error(
|
||||
"please define _SERVER_PORT (as a port number) before running server.js"
|
||||
);
|
||||
}
|
||||
|
||||
// If DISPLAY_RESULTS is not specified, it defaults to true
|
||||
if (typeof(_DISPLAY_RESULTS) != "undefined") {
|
||||
if (typeof _DISPLAY_RESULTS != "undefined") {
|
||||
displayResults = _DISPLAY_RESULTS;
|
||||
}
|
||||
|
||||
server._start(SERVER_PORT, gServerAddress);
|
||||
|
||||
// touch a file in the profile directory to indicate we're alive
|
||||
var foStream = Cc["@mozilla.org/network/file-output-stream;1"]
|
||||
.createInstance(Ci.nsIFileOutputStream);
|
||||
var serverAlive = Cc["@mozilla.org/file/local;1"]
|
||||
.createInstance(Ci.nsIFile);
|
||||
var foStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(
|
||||
Ci.nsIFileOutputStream
|
||||
);
|
||||
var serverAlive = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
|
||||
if (typeof(_PROFILE_PATH) == "undefined") {
|
||||
if (typeof _PROFILE_PATH == "undefined") {
|
||||
serverAlive.initWithFile(serverBasePath);
|
||||
serverAlive.append("mochitesttestingprofile");
|
||||
} else {
|
||||
|
@ -188,14 +277,16 @@ function runServer() {
|
|||
// Create a file to inform the harness that the server is ready
|
||||
if (serverAlive.exists()) {
|
||||
serverAlive.append("server_alive.txt");
|
||||
foStream.init(serverAlive,
|
||||
0x02 | 0x08 | 0x20, 436, 0); // write, create, truncate
|
||||
foStream.init(serverAlive, 0x02 | 0x08 | 0x20, 436, 0); // write, create, truncate
|
||||
var data = "It's alive!";
|
||||
foStream.write(data, data.length);
|
||||
foStream.close();
|
||||
} else {
|
||||
throw new Error("Failed to create server_alive.txt because " + serverAlive.path +
|
||||
" could not be found.");
|
||||
throw new Error(
|
||||
"Failed to create server_alive.txt because " +
|
||||
serverAlive.path +
|
||||
" could not be found."
|
||||
);
|
||||
}
|
||||
|
||||
makeTags();
|
||||
|
@ -204,18 +295,18 @@ function runServer() {
|
|||
// The following is threading magic to spin an event loop -- this has to
|
||||
// happen manually in xpcshell for the server to actually work.
|
||||
//
|
||||
var thread = Cc["@mozilla.org/thread-manager;1"]
|
||||
.getService()
|
||||
.currentThread;
|
||||
while (!server.isStopped())
|
||||
var thread = Cc["@mozilla.org/thread-manager;1"].getService().currentThread;
|
||||
while (!server.isStopped()) {
|
||||
thread.processNextEvent(true);
|
||||
}
|
||||
|
||||
// Server stopped by /server/shutdown handler -- go through pending events
|
||||
// and return.
|
||||
|
||||
// get rid of any pending requests
|
||||
while (thread.hasPendingEvents())
|
||||
while (thread.hasPendingEvents()) {
|
||||
thread.processNextEvent(true);
|
||||
}
|
||||
}
|
||||
|
||||
/** Creates and returns an HTTP server configured to serve Mochitests. */
|
||||
|
@ -238,17 +329,18 @@ function createMochitestServer(serverBasePath) {
|
|||
server.registerContentType("wasm", "application/wasm");
|
||||
server.setIndexHandler(defaultDirHandler);
|
||||
|
||||
var serverRoot =
|
||||
{
|
||||
getFile: function getFile(path) {
|
||||
var file = serverBasePath.clone().QueryInterface(Ci.nsIFile);
|
||||
path.split("/").forEach(function(p) {
|
||||
file.appendRelativePath(p);
|
||||
});
|
||||
return file;
|
||||
},
|
||||
QueryInterface(aIID) { return this; },
|
||||
};
|
||||
var serverRoot = {
|
||||
getFile: function getFile(path) {
|
||||
var file = serverBasePath.clone().QueryInterface(Ci.nsIFile);
|
||||
path.split("/").forEach(function(p) {
|
||||
file.appendRelativePath(p);
|
||||
});
|
||||
return file;
|
||||
},
|
||||
QueryInterface(aIID) {
|
||||
return this;
|
||||
},
|
||||
};
|
||||
|
||||
server.setObjectState("SERVER_ROOT", serverRoot);
|
||||
|
||||
|
@ -267,27 +359,32 @@ function processLocations(server) {
|
|||
serverLocations.append("server-locations.txt");
|
||||
|
||||
const PR_RDONLY = 0x01;
|
||||
var fis = new FileInputStream(serverLocations, PR_RDONLY, 292 /* 0444 */,
|
||||
Ci.nsIFileInputStream.CLOSE_ON_EOF);
|
||||
var fis = new FileInputStream(
|
||||
serverLocations,
|
||||
PR_RDONLY,
|
||||
292 /* 0444 */,
|
||||
Ci.nsIFileInputStream.CLOSE_ON_EOF
|
||||
);
|
||||
|
||||
var lis = new ConverterInputStream(fis, "UTF-8", 1024, 0x0);
|
||||
lis.QueryInterface(Ci.nsIUnicharLineInputStream);
|
||||
|
||||
const LINE_REGEXP =
|
||||
new RegExp("^([a-z][-a-z0-9+.]*)" +
|
||||
"://" +
|
||||
"(" +
|
||||
"\\d+\\.\\d+\\.\\d+\\.\\d+" +
|
||||
"|" +
|
||||
"(?:[a-z0-9](?:[-a-z0-9]*[a-z0-9])?\\.)*" +
|
||||
"[a-z](?:[-a-z0-9]*[a-z0-9])?" +
|
||||
")" +
|
||||
":" +
|
||||
"(\\d+)" +
|
||||
"(?:" +
|
||||
"\\s+" +
|
||||
"(\\S+(?:,\\S+)*)" +
|
||||
")?$");
|
||||
const LINE_REGEXP = new RegExp(
|
||||
"^([a-z][-a-z0-9+.]*)" +
|
||||
"://" +
|
||||
"(" +
|
||||
"\\d+\\.\\d+\\.\\d+\\.\\d+" +
|
||||
"|" +
|
||||
"(?:[a-z0-9](?:[-a-z0-9]*[a-z0-9])?\\.)*" +
|
||||
"[a-z](?:[-a-z0-9]*[a-z0-9])?" +
|
||||
")" +
|
||||
":" +
|
||||
"(\\d+)" +
|
||||
"(?:" +
|
||||
"\\s+" +
|
||||
"(\\S+(?:,\\S+)*)" +
|
||||
")?$"
|
||||
);
|
||||
|
||||
var line = {};
|
||||
var lineno = 0;
|
||||
|
@ -297,19 +394,24 @@ function processLocations(server) {
|
|||
lineno++;
|
||||
|
||||
var lineValue = line.value;
|
||||
if (lineValue.charAt(0) == "#" || lineValue == "")
|
||||
if (lineValue.charAt(0) == "#" || lineValue == "") {
|
||||
continue;
|
||||
}
|
||||
|
||||
var match = LINE_REGEXP.exec(lineValue);
|
||||
if (!match)
|
||||
if (!match) {
|
||||
throw new Error("Syntax error in server-locations.txt, line " + lineno);
|
||||
}
|
||||
|
||||
var [, scheme, host, port, options] = match;
|
||||
if (options) {
|
||||
if (options.split(",").includes("primary")) {
|
||||
if (seenPrimary) {
|
||||
throw new Error("Multiple primary locations in server-locations.txt, " +
|
||||
"line " + lineno);
|
||||
throw new Error(
|
||||
"Multiple primary locations in server-locations.txt, " +
|
||||
"line " +
|
||||
lineno
|
||||
);
|
||||
}
|
||||
|
||||
server.identity.setPrimary(scheme, host, port);
|
||||
|
@ -319,8 +421,7 @@ function processLocations(server) {
|
|||
}
|
||||
|
||||
server.identity.add(scheme, host, port);
|
||||
}
|
||||
while (more);
|
||||
} while (more);
|
||||
}
|
||||
|
||||
// PATH HANDLERS
|
||||
|
@ -340,8 +441,9 @@ function serverShutdown(metadata, response) {
|
|||
// /server/debug?[012]
|
||||
function serverDebug(metadata, response) {
|
||||
response.setStatusLine(metadata.httpVersion, 400, "Bad debugging level");
|
||||
if (metadata.queryString.length !== 1)
|
||||
if (metadata.queryString.length !== 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
var mode;
|
||||
if (metadata.queryString === "0") {
|
||||
|
@ -409,10 +511,12 @@ function list(requestPath, directory, recurse) {
|
|||
// Sort files by name, so that tests can be run in a pre-defined order inside
|
||||
// a given directory (see bug 384823)
|
||||
function leafNameComparator(first, second) {
|
||||
if (first.leafName < second.leafName)
|
||||
if (first.leafName < second.leafName) {
|
||||
return -1;
|
||||
if (first.leafName > second.leafName)
|
||||
}
|
||||
if (first.leafName > second.leafName) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
files.sort(leafNameComparator);
|
||||
|
@ -428,8 +532,8 @@ function list(requestPath, directory, recurse) {
|
|||
[links[key], childCount] = list(key, file, recurse);
|
||||
count += childCount;
|
||||
} else if (file.leafName.charAt(0) != ".") {
|
||||
links[key] = {"test": {"url": key, "expected": "pass"}};
|
||||
}
|
||||
links[key] = { test: { url: key, expected: "pass" } };
|
||||
}
|
||||
}
|
||||
|
||||
return [links, count];
|
||||
|
@ -441,20 +545,23 @@ function list(requestPath, directory, recurse) {
|
|||
* a supporting file.
|
||||
*/
|
||||
function isTest(filename, pattern) {
|
||||
if (pattern)
|
||||
if (pattern) {
|
||||
return pattern.test(filename);
|
||||
}
|
||||
|
||||
// File name is a URL style path to a test file, make sure that we check for
|
||||
// tests that start with the appropriate prefix.
|
||||
var testPrefix = typeof(_TEST_PREFIX) == "string" ? _TEST_PREFIX : "test_";
|
||||
var testPrefix = typeof _TEST_PREFIX == "string" ? _TEST_PREFIX : "test_";
|
||||
var testPattern = new RegExp("^" + testPrefix);
|
||||
|
||||
var pathPieces = filename.split("/");
|
||||
|
||||
return testPattern.test(pathPieces[pathPieces.length - 1]) &&
|
||||
!filename.includes(".js") &&
|
||||
!filename.includes(".css") &&
|
||||
!/\^headers\^$/.test(filename);
|
||||
return (
|
||||
testPattern.test(pathPieces[pathPieces.length - 1]) &&
|
||||
!filename.includes(".js") &&
|
||||
!filename.includes(".css") &&
|
||||
!/\^headers\^$/.test(filename)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -465,11 +572,12 @@ function linksToListItems(links) {
|
|||
var children = "";
|
||||
for (let link in links) {
|
||||
const value = links[link];
|
||||
var classVal = (!isTest(link) && !(value instanceof Object))
|
||||
? "non-test invisible"
|
||||
: "test";
|
||||
var classVal =
|
||||
!isTest(link) && !(value instanceof Object)
|
||||
? "non-test invisible"
|
||||
: "test";
|
||||
if (value instanceof Object) {
|
||||
children = UL({class: "testdir"}, linksToListItems(value));
|
||||
children = UL({ class: "testdir" }, linksToListItems(value));
|
||||
} else {
|
||||
children = "";
|
||||
}
|
||||
|
@ -477,14 +585,20 @@ function linksToListItems(links) {
|
|||
var bug_title = link.match(/test_bug\S+/);
|
||||
var bug_num = null;
|
||||
if (bug_title != null) {
|
||||
bug_num = bug_title[0].match(/\d+/);
|
||||
bug_num = bug_title[0].match(/\d+/);
|
||||
}
|
||||
|
||||
if ((bug_title == null) || (bug_num == null)) {
|
||||
response += LI({class: classVal}, A({href: link}, link), children);
|
||||
if (bug_title == null || bug_num == null) {
|
||||
response += LI({ class: classVal }, A({ href: link }, link), children);
|
||||
} else {
|
||||
var bug_url = "https://bugzilla.mozilla.org/show_bug.cgi?id=" + bug_num;
|
||||
response += LI({class: classVal}, A({href: link}, link), " - ", A({href: bug_url}, "Bug " + bug_num), children);
|
||||
response += LI(
|
||||
{ class: classVal },
|
||||
A({ href: link }, link),
|
||||
" - ",
|
||||
A({ href: bug_url }, "Bug " + bug_num),
|
||||
children
|
||||
);
|
||||
}
|
||||
}
|
||||
return response;
|
||||
|
@ -497,40 +611,48 @@ function linksToTableRows(links, recursionLevel) {
|
|||
var response = "";
|
||||
for (let link in links) {
|
||||
const value = links[link];
|
||||
var classVal = (!isTest(link) && ((value instanceof Object) && ("test" in value)))
|
||||
? "non-test invisible"
|
||||
: "";
|
||||
var classVal =
|
||||
!isTest(link) && (value instanceof Object && "test" in value)
|
||||
? "non-test invisible"
|
||||
: "";
|
||||
|
||||
var spacer = "padding-left: " + (10 * recursionLevel) + "px";
|
||||
var spacer = "padding-left: " + 10 * recursionLevel + "px";
|
||||
|
||||
if ((value instanceof Object) && !("test" in value)) {
|
||||
response += TR({class: "dir", id: "tr-" + link },
|
||||
TD({colspan: "3"}, " "),
|
||||
TD({style: spacer},
|
||||
A({href: link}, link)));
|
||||
if (value instanceof Object && !("test" in value)) {
|
||||
response += TR(
|
||||
{ class: "dir", id: "tr-" + link },
|
||||
TD({ colspan: "3" }, " "),
|
||||
TD({ style: spacer }, A({ href: link }, link))
|
||||
);
|
||||
response += linksToTableRows(value, recursionLevel + 1);
|
||||
} else {
|
||||
var bug_title = link.match(/test_bug\S+/);
|
||||
var bug_num = null;
|
||||
if (bug_title != null) {
|
||||
bug_num = bug_title[0].match(/\d+/);
|
||||
bug_num = bug_title[0].match(/\d+/);
|
||||
}
|
||||
if ((bug_title == null) || (bug_num == null)) {
|
||||
response += TR({class: classVal, id: "tr-" + link },
|
||||
TD("0"),
|
||||
TD("0"),
|
||||
TD("0"),
|
||||
TD({style: spacer},
|
||||
A({href: link}, link)));
|
||||
if (bug_title == null || bug_num == null) {
|
||||
response += TR(
|
||||
{ class: classVal, id: "tr-" + link },
|
||||
TD("0"),
|
||||
TD("0"),
|
||||
TD("0"),
|
||||
TD({ style: spacer }, A({ href: link }, link))
|
||||
);
|
||||
} else {
|
||||
var bug_url = "https://bugzilla.mozilla.org/show_bug.cgi?id=" + bug_num;
|
||||
response += TR({class: classVal, id: "tr-" + link },
|
||||
TD("0"),
|
||||
TD("0"),
|
||||
TD("0"),
|
||||
TD({style: spacer},
|
||||
A({href: link}, link), " - ",
|
||||
A({href: bug_url}, "Bug " + bug_num)));
|
||||
response += TR(
|
||||
{ class: classVal, id: "tr-" + link },
|
||||
TD("0"),
|
||||
TD("0"),
|
||||
TD("0"),
|
||||
TD(
|
||||
{ style: spacer },
|
||||
A({ href: link }, link),
|
||||
" - ",
|
||||
A({ href: bug_url }, "Bug " + bug_num)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -540,9 +662,9 @@ function linksToTableRows(links, recursionLevel) {
|
|||
function arrayOfTestFiles(linkArray, fileArray, testPattern) {
|
||||
for (let link in linkArray) {
|
||||
const value = linkArray[link];
|
||||
if ((value instanceof Object) && !("test" in value)) {
|
||||
if (value instanceof Object && !("test" in value)) {
|
||||
arrayOfTestFiles(value, fileArray, testPattern);
|
||||
} else if (isTest(link, testPattern) && (value instanceof Object)) {
|
||||
} else if (isTest(link, testPattern) && value instanceof Object) {
|
||||
fileArray.push(value.test);
|
||||
}
|
||||
}
|
||||
|
@ -553,7 +675,9 @@ function arrayOfTestFiles(linkArray, fileArray, testPattern) {
|
|||
function jsonArrayOfTestFiles(links) {
|
||||
var testFiles = [];
|
||||
arrayOfTestFiles(links, testFiles);
|
||||
testFiles = testFiles.map(function(file) { return '"' + file.url + '"'; });
|
||||
testFiles = testFiles.map(function(file) {
|
||||
return '"' + file.url + '"';
|
||||
});
|
||||
|
||||
return "[" + testFiles.join(",\n") + "]";
|
||||
}
|
||||
|
@ -562,19 +686,11 @@ function jsonArrayOfTestFiles(links) {
|
|||
* Produce a normal directory listing.
|
||||
*/
|
||||
function regularListing(metadata, response) {
|
||||
var [links] = list(metadata.path,
|
||||
metadata.getProperty("directory"),
|
||||
false);
|
||||
var [links] = list(metadata.path, metadata.getProperty("directory"), false);
|
||||
response.write(
|
||||
HTML(
|
||||
HEAD(
|
||||
TITLE("mochitest index ", metadata.path)
|
||||
),
|
||||
BODY(
|
||||
BR(),
|
||||
A({href: ".."}, "Up a level"),
|
||||
UL(linksToListItems(links))
|
||||
)
|
||||
HEAD(TITLE("mochitest index ", metadata.path)),
|
||||
BODY(BR(), A({ href: ".." }, "Up a level"), UL(linksToListItems(links)))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -584,21 +700,29 @@ function regularListing(metadata, response) {
|
|||
* it into an object for creating a table of clickable links for each test.
|
||||
*/
|
||||
function convertManifestToTestLinks(root, manifest) {
|
||||
const {NetUtil} = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
|
||||
const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
var manifestFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
manifestFile.initWithFile(serverBasePath);
|
||||
manifestFile.append(manifest);
|
||||
|
||||
var manifestStream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
|
||||
var manifestStream = Cc[
|
||||
"@mozilla.org/network/file-input-stream;1"
|
||||
].createInstance(Ci.nsIFileInputStream);
|
||||
manifestStream.init(manifestFile, -1, 0, 0);
|
||||
|
||||
var manifestObj = JSON.parse(NetUtil.readInputStreamToString(manifestStream,
|
||||
manifestStream.available()));
|
||||
var manifestObj = JSON.parse(
|
||||
NetUtil.readInputStreamToString(manifestStream, manifestStream.available())
|
||||
);
|
||||
var paths = manifestObj.tests;
|
||||
var pathPrefix = "/" + root + "/";
|
||||
return [paths.reduce(function(t, p) { t[pathPrefix + p.path] = true; return t; }, {}),
|
||||
paths.length];
|
||||
return [
|
||||
paths.reduce(function(t, p) {
|
||||
t[pathPrefix + p.path] = true;
|
||||
return t;
|
||||
}, {}),
|
||||
paths.length,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -609,98 +733,125 @@ function testListing(metadata, response) {
|
|||
var links = {};
|
||||
var count = 0;
|
||||
if (!metadata.queryString.includes("manifestFile")) {
|
||||
[links, count] = list(metadata.path,
|
||||
metadata.getProperty("directory"),
|
||||
true);
|
||||
} else if (typeof(Components) != undefined) {
|
||||
[links, count] = list(
|
||||
metadata.path,
|
||||
metadata.getProperty("directory"),
|
||||
true
|
||||
);
|
||||
} else if (typeof Components != undefined) {
|
||||
var manifest = metadata.queryString.match(/manifestFile=([^&]+)/)[1];
|
||||
|
||||
[links, count] = convertManifestToTestLinks(metadata.path.split("/")[1],
|
||||
manifest);
|
||||
[links, count] = convertManifestToTestLinks(
|
||||
metadata.path.split("/")[1],
|
||||
manifest
|
||||
);
|
||||
}
|
||||
|
||||
var table_class = metadata.queryString.indexOf("hideResultsTable=1") > -1 ? "invisible" : "";
|
||||
var table_class =
|
||||
metadata.queryString.indexOf("hideResultsTable=1") > -1 ? "invisible" : "";
|
||||
|
||||
let testname = (metadata.queryString.indexOf("testname=") > -1)
|
||||
? metadata.queryString.match(/testname=([^&]+)/)[1]
|
||||
: "";
|
||||
let testname =
|
||||
metadata.queryString.indexOf("testname=") > -1
|
||||
? metadata.queryString.match(/testname=([^&]+)/)[1]
|
||||
: "";
|
||||
|
||||
dumpn("count: " + count);
|
||||
var tests = testname
|
||||
? "['/" + testname + "']"
|
||||
: jsonArrayOfTestFiles(links);
|
||||
var tests = testname ? "['/" + testname + "']" : jsonArrayOfTestFiles(links);
|
||||
response.write(
|
||||
HTML(
|
||||
HEAD(
|
||||
TITLE("MochiTest | ", metadata.path),
|
||||
LINK({rel: "stylesheet",
|
||||
type: "text/css", href: "/static/harness.css"}
|
||||
),
|
||||
SCRIPT({type: "text/javascript",
|
||||
src: "/tests/SimpleTest/StructuredLog.jsm"}),
|
||||
SCRIPT({type: "text/javascript",
|
||||
src: "/tests/SimpleTest/LogController.js"}),
|
||||
SCRIPT({type: "text/javascript",
|
||||
src: "/tests/SimpleTest/MemoryStats.js"}),
|
||||
SCRIPT({type: "text/javascript",
|
||||
src: "/tests/SimpleTest/TestRunner.js"}),
|
||||
SCRIPT({type: "text/javascript",
|
||||
src: "/tests/SimpleTest/MozillaLogger.js"}),
|
||||
SCRIPT({type: "text/javascript",
|
||||
src: "/chunkifyTests.js"}),
|
||||
SCRIPT({type: "text/javascript",
|
||||
src: "/manifestLibrary.js"}),
|
||||
SCRIPT({type: "text/javascript",
|
||||
src: "/tests/SimpleTest/setup.js"}),
|
||||
SCRIPT({type: "text/javascript"},
|
||||
"window.onload = hookup; gTestList=" + tests + ";"
|
||||
LINK({
|
||||
rel: "stylesheet",
|
||||
type: "text/css",
|
||||
href: "/static/harness.css",
|
||||
}),
|
||||
SCRIPT({
|
||||
type: "text/javascript",
|
||||
src: "/tests/SimpleTest/StructuredLog.jsm",
|
||||
}),
|
||||
SCRIPT({
|
||||
type: "text/javascript",
|
||||
src: "/tests/SimpleTest/LogController.js",
|
||||
}),
|
||||
SCRIPT({
|
||||
type: "text/javascript",
|
||||
src: "/tests/SimpleTest/MemoryStats.js",
|
||||
}),
|
||||
SCRIPT({
|
||||
type: "text/javascript",
|
||||
src: "/tests/SimpleTest/TestRunner.js",
|
||||
}),
|
||||
SCRIPT({
|
||||
type: "text/javascript",
|
||||
src: "/tests/SimpleTest/MozillaLogger.js",
|
||||
}),
|
||||
SCRIPT({ type: "text/javascript", src: "/chunkifyTests.js" }),
|
||||
SCRIPT({ type: "text/javascript", src: "/manifestLibrary.js" }),
|
||||
SCRIPT({ type: "text/javascript", src: "/tests/SimpleTest/setup.js" }),
|
||||
SCRIPT(
|
||||
{ type: "text/javascript" },
|
||||
"window.onload = hookup; gTestList=" + tests + ";"
|
||||
)
|
||||
),
|
||||
BODY(
|
||||
DIV({class: "container"},
|
||||
H2("--> ", A({href: "#", id: "runtests"}, "Run Tests"), " <--"),
|
||||
P({style: "float: right;"},
|
||||
DIV(
|
||||
{ class: "container" },
|
||||
H2("--> ", A({ href: "#", id: "runtests" }, "Run Tests"), " <--"),
|
||||
P(
|
||||
{ style: "float: right;" },
|
||||
SMALL(
|
||||
"Based on the ",
|
||||
A({href: "http://www.mochikit.com/"}, "MochiKit"),
|
||||
A({ href: "http://www.mochikit.com/" }, "MochiKit"),
|
||||
" unit tests."
|
||||
)
|
||||
),
|
||||
DIV({class: "status"},
|
||||
H1({id: "indicator"}, "Status"),
|
||||
H2({id: "pass"}, "Passed: ", SPAN({id: "pass-count"}, "0")),
|
||||
H2({id: "fail"}, "Failed: ", SPAN({id: "fail-count"}, "0")),
|
||||
H2({id: "fail"}, "Todo: ", SPAN({id: "todo-count"}, "0"))
|
||||
DIV(
|
||||
{ class: "status" },
|
||||
H1({ id: "indicator" }, "Status"),
|
||||
H2({ id: "pass" }, "Passed: ", SPAN({ id: "pass-count" }, "0")),
|
||||
H2({ id: "fail" }, "Failed: ", SPAN({ id: "fail-count" }, "0")),
|
||||
H2({ id: "fail" }, "Todo: ", SPAN({ id: "todo-count" }, "0"))
|
||||
),
|
||||
DIV({class: "clear"}),
|
||||
DIV({id: "current-test"},
|
||||
B("Currently Executing: ",
|
||||
SPAN({id: "current-test-path"}, "_")
|
||||
)
|
||||
DIV({ class: "clear" }),
|
||||
DIV(
|
||||
{ id: "current-test" },
|
||||
B("Currently Executing: ", SPAN({ id: "current-test-path" }, "_"))
|
||||
),
|
||||
DIV({class: "clear"}),
|
||||
DIV({class: "frameholder"},
|
||||
IFRAME({scrolling: "no", id: "testframe", "allowfullscreen": true})
|
||||
DIV({ class: "clear" }),
|
||||
DIV(
|
||||
{ class: "frameholder" },
|
||||
IFRAME({ scrolling: "no", id: "testframe", allowfullscreen: true })
|
||||
),
|
||||
DIV({class: "clear"}),
|
||||
DIV({class: "toggle"},
|
||||
A({href: "#", id: "toggleNonTests"}, "Show Non-Tests"),
|
||||
DIV({ class: "clear" }),
|
||||
DIV(
|
||||
{ class: "toggle" },
|
||||
A({ href: "#", id: "toggleNonTests" }, "Show Non-Tests"),
|
||||
BR()
|
||||
),
|
||||
|
||||
(
|
||||
displayResults ?
|
||||
TABLE({cellpadding: 0, cellspacing: 0, class: table_class, id: "test-table"},
|
||||
TR(TD("Passed"), TD("Failed"), TD("Todo"), TD("Test Files")),
|
||||
linksToTableRows(links, 0)
|
||||
) : ""
|
||||
),
|
||||
|
||||
displayResults
|
||||
? TABLE(
|
||||
{
|
||||
cellpadding: 0,
|
||||
cellspacing: 0,
|
||||
class: table_class,
|
||||
id: "test-table",
|
||||
},
|
||||
TR(TD("Passed"), TD("Failed"), TD("Todo"), TD("Test Files")),
|
||||
linksToTableRows(links, 0)
|
||||
)
|
||||
: "",
|
||||
BR(),
|
||||
TABLE({cellpadding: 0, cellspacing: 0, border: 1, bordercolor: "red", id: "fail-table"}
|
||||
),
|
||||
TABLE({
|
||||
cellpadding: 0,
|
||||
cellspacing: 0,
|
||||
border: 1,
|
||||
bordercolor: "red",
|
||||
id: "fail-table",
|
||||
}),
|
||||
|
||||
DIV({class: "clear"})
|
||||
DIV({ class: "clear" })
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -4,12 +4,13 @@
|
|||
|
||||
// Defined by Marionette.
|
||||
/* global __webDriverArguments */
|
||||
const flavor = __webDriverArguments[0].flavor;
|
||||
const flavor = __webDriverArguments[0].flavor;
|
||||
const url = __webDriverArguments[0].testUrl;
|
||||
|
||||
// eslint-disable-next-line mozilla/use-services
|
||||
let wm = Cc["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Ci.nsIWindowMediator);
|
||||
let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(
|
||||
Ci.nsIWindowMediator
|
||||
);
|
||||
let win = wm.getMostRecentWindow("navigator:browser");
|
||||
if (!win) {
|
||||
win = wm.getMostRecentWindow("mail:3pane");
|
||||
|
@ -17,5 +18,5 @@ if (!win) {
|
|||
|
||||
// mochikit's bootstrap.js has set up a listener for this event. It's
|
||||
// used so bootstrap.js knows which flavor and url to load.
|
||||
let ev = new CustomEvent("mochitest-load", {"detail": [flavor, url]});
|
||||
let ev = new CustomEvent("mochitest-load", { detail: [flavor, url] });
|
||||
win.dispatchEvent(ev);
|
||||
|
|
|
@ -5,12 +5,19 @@ function getLastEventDetails(browser) {
|
|||
}
|
||||
|
||||
add_task(async function() {
|
||||
let onClickEvt = 'document.getElementById("out").textContent = event.target.localName + "," + event.clientX + "," + event.clientY;';
|
||||
const url = "<body onclick='" + onClickEvt + "' style='margin: 0'>" +
|
||||
"<button id='one' style='margin: 0; margin-left: 16px; margin-top: 14px; width: 30px; height: 40px;'>Test</button>" +
|
||||
"<div onmousedown='event.preventDefault()' style='margin: 0; width: 80px; height: 60px;'>Other</div>" +
|
||||
"<span id='out'></span></body>";
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "data:text/html," + url);
|
||||
let onClickEvt =
|
||||
'document.getElementById("out").textContent = event.target.localName + "," + event.clientX + "," + event.clientY;';
|
||||
const url =
|
||||
"<body onclick='" +
|
||||
onClickEvt +
|
||||
"' style='margin: 0'>" +
|
||||
"<button id='one' style='margin: 0; margin-left: 16px; margin-top: 14px; width: 30px; height: 40px;'>Test</button>" +
|
||||
"<div onmousedown='event.preventDefault()' style='margin: 0; width: 80px; height: 60px;'>Other</div>" +
|
||||
"<span id='out'></span></body>";
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
"data:text/html," + url
|
||||
);
|
||||
|
||||
let browser = tab.linkedBrowser;
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter("#one", {}, browser);
|
||||
|
@ -34,25 +41,53 @@ add_task(async function() {
|
|||
details = await getLastEventDetails(browser);
|
||||
is(details, "div,40,84", "synthesizeMouseAtCenter with complex selector");
|
||||
|
||||
let cancelled = await BrowserTestUtils.synthesizeMouseAtCenter("body > div", { type: "mousedown" }, browser);
|
||||
let cancelled = await BrowserTestUtils.synthesizeMouseAtCenter(
|
||||
"body > div",
|
||||
{ type: "mousedown" },
|
||||
browser
|
||||
);
|
||||
details = await getLastEventDetails(browser);
|
||||
is(details, "div,40,84", "synthesizeMouseAtCenter mousedown with complex selector");
|
||||
ok(cancelled, "synthesizeMouseAtCenter mousedown with complex selector not cancelled");
|
||||
is(
|
||||
details,
|
||||
"div,40,84",
|
||||
"synthesizeMouseAtCenter mousedown with complex selector"
|
||||
);
|
||||
ok(
|
||||
cancelled,
|
||||
"synthesizeMouseAtCenter mousedown with complex selector not cancelled"
|
||||
);
|
||||
|
||||
cancelled = await BrowserTestUtils.synthesizeMouseAtCenter("body > div", { type: "mouseup" }, browser);
|
||||
cancelled = await BrowserTestUtils.synthesizeMouseAtCenter(
|
||||
"body > div",
|
||||
{ type: "mouseup" },
|
||||
browser
|
||||
);
|
||||
details = await getLastEventDetails(browser);
|
||||
is(details, "div,40,84", "synthesizeMouseAtCenter mouseup with complex selector");
|
||||
ok(!cancelled, "synthesizeMouseAtCenter mouseup with complex selector cancelled");
|
||||
is(
|
||||
details,
|
||||
"div,40,84",
|
||||
"synthesizeMouseAtCenter mouseup with complex selector"
|
||||
);
|
||||
ok(
|
||||
!cancelled,
|
||||
"synthesizeMouseAtCenter mouseup with complex selector cancelled"
|
||||
);
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
||||
add_task(async function() {
|
||||
await BrowserTestUtils.registerAboutPage(
|
||||
registerCleanupFunction, "about-pages-are-cool",
|
||||
getRootDirectory(gTestPath) + "dummy.html", 0);
|
||||
registerCleanupFunction,
|
||||
"about-pages-are-cool",
|
||||
getRootDirectory(gTestPath) + "dummy.html",
|
||||
0
|
||||
);
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser, "about:about-pages-are-cool", true);
|
||||
gBrowser,
|
||||
"about:about-pages-are-cool",
|
||||
true
|
||||
);
|
||||
ok(tab, "Successfully created an about: page and loaded it.");
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
try {
|
||||
|
@ -61,11 +96,20 @@ add_task(async function() {
|
|||
} catch (ex) {
|
||||
ok(false, "Should not throw unregistering a known about: page");
|
||||
}
|
||||
await BrowserTestUtils.unregisterAboutPage("random-other-about-page").then(() => {
|
||||
ok(false, "Should not have succeeded unregistering an unknown about: page.");
|
||||
}, () => {
|
||||
ok(true, "Should have returned a rejected promise trying to unregister an unknown about page");
|
||||
});
|
||||
await BrowserTestUtils.unregisterAboutPage("random-other-about-page").then(
|
||||
() => {
|
||||
ok(
|
||||
false,
|
||||
"Should not have succeeded unregistering an unknown about: page."
|
||||
);
|
||||
},
|
||||
() => {
|
||||
ok(
|
||||
true,
|
||||
"Should have returned a rejected promise trying to unregister an unknown about page"
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function testWaitForEvent() {
|
||||
|
@ -76,16 +120,28 @@ add_task(async function testWaitForEvent() {
|
|||
// Use capturing phase to make sure the event listener added by
|
||||
// BrowserTestUtils.waitForEvent is called before the normal event listener
|
||||
// below.
|
||||
let eventPromise = BrowserTestUtils.waitForEvent(gBrowser, "dummyevent", true);
|
||||
let eventPromise = BrowserTestUtils.waitForEvent(
|
||||
gBrowser,
|
||||
"dummyevent",
|
||||
true
|
||||
);
|
||||
eventPromise.then(() => {
|
||||
waitForEventResolved = true;
|
||||
});
|
||||
// Add normal event listener that is called after the event listener added by
|
||||
// BrowserTestUtils.waitForEvent.
|
||||
gBrowser.addEventListener("dummyevent", () => {
|
||||
eventListenerCalled = true;
|
||||
is(waitForEventResolved, false, "BrowserTestUtils.waitForEvent promise resolution handler shouldn't be called at this point.");
|
||||
}, { once: true });
|
||||
gBrowser.addEventListener(
|
||||
"dummyevent",
|
||||
() => {
|
||||
eventListenerCalled = true;
|
||||
is(
|
||||
waitForEventResolved,
|
||||
false,
|
||||
"BrowserTestUtils.waitForEvent promise resolution handler shouldn't be called at this point."
|
||||
);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
var event = new CustomEvent("dummyevent");
|
||||
gBrowser.dispatchEvent(event);
|
||||
|
|
|
@ -4,8 +4,11 @@
|
|||
|
||||
function isDOMLoaded(browser) {
|
||||
return ContentTask.spawn(browser, null, async function() {
|
||||
Assert.equal(content.document.readyState, "complete",
|
||||
"Browser should be loaded.");
|
||||
Assert.equal(
|
||||
content.document.readyState,
|
||||
"complete",
|
||||
"Browser should be loaded."
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -28,14 +31,18 @@ add_task(async function() {
|
|||
`http://test:80`,
|
||||
];
|
||||
// Add tabs, get the respective browsers
|
||||
let browsers = tabURLs.map(u => BrowserTestUtils.addTab(gBrowser, u).linkedBrowser);
|
||||
let browsers = tabURLs.map(
|
||||
u => BrowserTestUtils.addTab(gBrowser, u).linkedBrowser
|
||||
);
|
||||
|
||||
// wait for promises to settle
|
||||
await Promise.all((function* () {
|
||||
for (let b of browsers) {
|
||||
yield BrowserTestUtils.browserLoaded(b);
|
||||
}
|
||||
})());
|
||||
await Promise.all(
|
||||
(function*() {
|
||||
for (let b of browsers) {
|
||||
yield BrowserTestUtils.browserLoaded(b);
|
||||
}
|
||||
})()
|
||||
);
|
||||
for (const browser of browsers) {
|
||||
await isDOMLoaded(browser);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
setExpectedFailuresForSelfTest(8);
|
||||
|
||||
// Keep "JSMPromise" separate so "Promise" still refers to native Promises.
|
||||
let JSMPromise = ChromeUtils.import("resource://gre/modules/Promise.jsm", {}).Promise;
|
||||
let JSMPromise = ChromeUtils.import("resource://gre/modules/Promise.jsm", {})
|
||||
.Promise;
|
||||
|
||||
async function rejectOnNextTick(error) {
|
||||
await Promise.resolve();
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
setExpectedFailuresForSelfTest(3);
|
||||
|
||||
// Keep "JSMPromise" separate so "Promise" still refers to native Promises.
|
||||
let JSMPromise = ChromeUtils.import("resource://gre/modules/Promise.jsm", {}).Promise;
|
||||
let JSMPromise = ChromeUtils.import("resource://gre/modules/Promise.jsm", {})
|
||||
.Promise;
|
||||
|
||||
function test() {
|
||||
Promise.reject(new Error("Promise rejection."));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
function test() {
|
||||
let {Promise} = ChromeUtils.import("resource://gre/modules/Promise.jsm");
|
||||
const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
||||
let { Promise } = ChromeUtils.import("resource://gre/modules/Promise.jsm");
|
||||
const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
||||
let decoder = new TextDecoder();
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
@ -10,35 +10,46 @@ function test() {
|
|||
}, "getTestFilePath rejects absolute paths");
|
||||
|
||||
Promise.all([
|
||||
OS.File.exists(getTestFilePath("browser_getTestFile.js"))
|
||||
.then(function(exists) {
|
||||
ok(exists, "getTestFilePath consider the path as being relative");
|
||||
}),
|
||||
OS.File.exists(getTestFilePath("browser_getTestFile.js")).then(function(
|
||||
exists
|
||||
) {
|
||||
ok(exists, "getTestFilePath consider the path as being relative");
|
||||
}),
|
||||
|
||||
OS.File.exists(getTestFilePath("./browser_getTestFile.js"))
|
||||
.then(function(exists) {
|
||||
ok(exists, "getTestFilePath also accepts explicit relative path");
|
||||
}),
|
||||
OS.File.exists(getTestFilePath("./browser_getTestFile.js")).then(function(
|
||||
exists
|
||||
) {
|
||||
ok(exists, "getTestFilePath also accepts explicit relative path");
|
||||
}),
|
||||
|
||||
OS.File.exists(getTestFilePath("./browser_getTestFileTypo.xul"))
|
||||
.then(function(exists) {
|
||||
OS.File.exists(getTestFilePath("./browser_getTestFileTypo.xul")).then(
|
||||
function(exists) {
|
||||
ok(!exists, "getTestFilePath do not throw if the file doesn't exists");
|
||||
}),
|
||||
}
|
||||
),
|
||||
|
||||
OS.File.read(getTestFilePath("test-dir/test-file"))
|
||||
.then(function(array) {
|
||||
is(decoder.decode(array), "foo\n", "getTestFilePath can reach sub-folder files 1/2");
|
||||
}),
|
||||
OS.File.read(getTestFilePath("test-dir/test-file")).then(function(array) {
|
||||
is(
|
||||
decoder.decode(array),
|
||||
"foo\n",
|
||||
"getTestFilePath can reach sub-folder files 1/2"
|
||||
);
|
||||
}),
|
||||
|
||||
OS.File.read(getTestFilePath("./test-dir/test-file"))
|
||||
.then(function(array) {
|
||||
is(decoder.decode(array), "foo\n", "getTestFilePath can reach sub-folder files 2/2");
|
||||
}),
|
||||
|
||||
]).then(function() {
|
||||
finish();
|
||||
}, function(error) {
|
||||
ok(false, error);
|
||||
finish();
|
||||
});
|
||||
OS.File.read(getTestFilePath("./test-dir/test-file")).then(function(array) {
|
||||
is(
|
||||
decoder.decode(array),
|
||||
"foo\n",
|
||||
"getTestFilePath can reach sub-folder files 2/2"
|
||||
);
|
||||
}),
|
||||
]).then(
|
||||
function() {
|
||||
finish();
|
||||
},
|
||||
function(error) {
|
||||
ok(false, error);
|
||||
finish();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,11 @@ var testVar;
|
|||
|
||||
registerCleanupFunction(function() {
|
||||
ok(true, "I'm a cleanup function in test file");
|
||||
is(this.testVar, "I'm a var in test file", "Test cleanup function scope is correct");
|
||||
is(
|
||||
this.testVar,
|
||||
"I'm a var in test file",
|
||||
"Test cleanup function scope is correct"
|
||||
);
|
||||
});
|
||||
|
||||
function test() {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
function test() {
|
||||
ok(SimpleTest.harnessParameters, "Should have parameters");
|
||||
}
|
||||
|
||||
|
|
|
@ -5,8 +5,9 @@ function test() {
|
|||
// this will throw an exception if we are not running with privileges
|
||||
try {
|
||||
// eslint-disable-next-line no-unused-vars, mozilla/use-services
|
||||
var prefs = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefBranch);
|
||||
var prefs = Cc["@mozilla.org/preferences-service;1"].getService(
|
||||
Ci.nsIPrefBranch
|
||||
);
|
||||
} catch (e) {
|
||||
hasPrivileges = false;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Keep "JSMPromise" separate so "Promise" still refers to native Promises.
|
||||
let JSMPromise = ChromeUtils.import("resource://gre/modules/Promise.jsm", {}).Promise;
|
||||
let JSMPromise = ChromeUtils.import("resource://gre/modules/Promise.jsm", {})
|
||||
.Promise;
|
||||
|
||||
ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm", this);
|
||||
PromiseTestUtils.whitelistRejectionsGlobally(/Whitelisted rejection./);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
const gBaseURL = "https://example.com/browser/testing/mochitest/tests/browser/";
|
||||
|
||||
function promiseTabLoadEvent(tab, url) {
|
||||
|
@ -18,7 +17,11 @@ add_task(async function() {
|
|||
let browser = gBrowser.selectedBrowser;
|
||||
await SimpleTest.promiseFocus(browser, true);
|
||||
|
||||
is(document.activeElement, browser, "Browser is focused when about:blank is loaded");
|
||||
is(
|
||||
document.activeElement,
|
||||
browser,
|
||||
"Browser is focused when about:blank is loaded"
|
||||
);
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
gURLBar.focus();
|
||||
|
@ -35,7 +38,11 @@ add_task(async function() {
|
|||
if (browser.contentWindow) {
|
||||
await SimpleTest.promiseFocus(browser.contentWindow, true);
|
||||
|
||||
is(document.activeElement, browser, "Browser is focused when about:blank is loaded");
|
||||
is(
|
||||
document.activeElement,
|
||||
browser,
|
||||
"Browser is focused when about:blank is loaded"
|
||||
);
|
||||
}
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
|
@ -55,11 +62,19 @@ add_task(async function() {
|
|||
|
||||
await SimpleTest.promiseFocus(browser.contentWindow);
|
||||
|
||||
is(document.activeElement, browser, "Browser is focused when page is loaded");
|
||||
is(
|
||||
document.activeElement,
|
||||
browser,
|
||||
"Browser is focused when page is loaded"
|
||||
);
|
||||
|
||||
await SimpleTest.promiseFocus(browser.contentWindow.frames[0]);
|
||||
|
||||
is(browser.contentWindow.document.activeElement.localName, "iframe", "Child iframe is focused");
|
||||
is(
|
||||
browser.contentWindow.document.activeElement.localName,
|
||||
"iframe",
|
||||
"Child iframe is focused"
|
||||
);
|
||||
}
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
|
@ -67,13 +82,20 @@ add_task(async function() {
|
|||
|
||||
// Pass a browser to promiseFocus
|
||||
add_task(async function() {
|
||||
await BrowserTestUtils.openNewForegroundTab(gBrowser, gBaseURL + "waitForFocusPage.html");
|
||||
await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
gBaseURL + "waitForFocusPage.html"
|
||||
);
|
||||
|
||||
gURLBar.focus();
|
||||
|
||||
await SimpleTest.promiseFocus(gBrowser.selectedBrowser);
|
||||
|
||||
is(document.activeElement, gBrowser.selectedBrowser, "Browser is focused when promiseFocus is passed a browser");
|
||||
is(
|
||||
document.activeElement,
|
||||
gBrowser.selectedBrowser,
|
||||
"Browser is focused when promiseFocus is passed a browser"
|
||||
);
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
|
|
@ -8,5 +8,9 @@ ok(true, "I'm a test in head file");
|
|||
|
||||
registerCleanupFunction(function() {
|
||||
ok(true, "I'm a cleanup function in head file");
|
||||
is(this.headVar, "I'm a var in head file", "Head cleanup function scope is correct");
|
||||
is(
|
||||
this.headVar,
|
||||
"I'm a var in head file",
|
||||
"Head cleanup function scope is correct"
|
||||
);
|
||||
});
|
||||
|
|
|
@ -4,13 +4,11 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = [
|
||||
"makeFakeAppDir",
|
||||
];
|
||||
var EXPORTED_SYMBOLS = ["makeFakeAppDir"];
|
||||
|
||||
const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
||||
const {Promise} = ChromeUtils.import("resource://gre/modules/Promise.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
||||
const { Promise } = ChromeUtils.import("resource://gre/modules/Promise.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
// Reference needed in order for fake app dir provider to be active.
|
||||
var gFakeAppDirectoryProvider;
|
||||
|
@ -72,8 +70,10 @@ var makeFakeAppDir = function() {
|
|||
},
|
||||
|
||||
QueryInterace(iid) {
|
||||
if (iid.equals(Ci.nsIDirectoryServiceProvider) ||
|
||||
iid.equals(Ci.nsISupports)) {
|
||||
if (
|
||||
iid.equals(Ci.nsIDirectoryServiceProvider) ||
|
||||
iid.equals(Ci.nsISupports)
|
||||
) {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,19 +4,16 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = [
|
||||
"newAppInfo",
|
||||
"getAppInfo",
|
||||
"updateAppInfo",
|
||||
];
|
||||
var EXPORTED_SYMBOLS = ["newAppInfo", "getAppInfo", "updateAppInfo"];
|
||||
|
||||
|
||||
let origPlatformInfo = Cc["@mozilla.org/xre/app-info;1"]
|
||||
.getService(Ci.nsIPlatformInfo);
|
||||
let origPlatformInfo = Cc["@mozilla.org/xre/app-info;1"].getService(
|
||||
Ci.nsIPlatformInfo
|
||||
);
|
||||
|
||||
// eslint-disable-next-line mozilla/use-services
|
||||
let origRuntime = Cc["@mozilla.org/xre/app-info;1"]
|
||||
.getService(Ci.nsIXULRuntime);
|
||||
let origRuntime = Cc["@mozilla.org/xre/app-info;1"].getService(
|
||||
Ci.nsIXULRuntime
|
||||
);
|
||||
|
||||
/**
|
||||
* Create new XULAppInfo instance with specified options.
|
||||
|
@ -32,13 +29,13 @@ let origRuntime = Cc["@mozilla.org/xre/app-info;1"]
|
|||
* extraProps: extra properties added to XULAppInfo
|
||||
*/
|
||||
var newAppInfo = function(options = {}) {
|
||||
let ID = ("ID" in options) ? options.ID : "xpcshell@tests.mozilla.org";
|
||||
let name = ("name" in options) ? options.name : "xpcshell";
|
||||
let version = ("version" in options) ? options.version : "1";
|
||||
let platformVersion
|
||||
= ("platformVersion" in options) ? options.platformVersion : "p-ver";
|
||||
let OS = ("OS" in options) ? options.OS : "XPCShell";
|
||||
let extraProps = ("extraProps" in options) ? options.extraProps : {};
|
||||
let ID = "ID" in options ? options.ID : "xpcshell@tests.mozilla.org";
|
||||
let name = "name" in options ? options.name : "xpcshell";
|
||||
let version = "version" in options ? options.version : "1";
|
||||
let platformVersion =
|
||||
"platformVersion" in options ? options.platformVersion : "p-ver";
|
||||
let OS = "OS" in options ? options.OS : "XPCShell";
|
||||
let extraProps = "extraProps" in options ? options.extraProps : {};
|
||||
|
||||
let appInfo = {
|
||||
// nsIXULAppInfo
|
||||
|
@ -68,9 +65,7 @@ var newAppInfo = function(options = {}) {
|
|||
},
|
||||
};
|
||||
|
||||
let interfaces = [Ci.nsIXULAppInfo,
|
||||
Ci.nsIPlatformInfo,
|
||||
Ci.nsIXULRuntime];
|
||||
let interfaces = [Ci.nsIXULAppInfo, Ci.nsIPlatformInfo, Ci.nsIXULRuntime];
|
||||
if ("nsIWinAppHelper" in Ci) {
|
||||
interfaces.push(Ci.nsIWinAppHelper);
|
||||
}
|
||||
|
@ -98,7 +93,9 @@ var currentAppInfo = newAppInfo();
|
|||
/**
|
||||
* Obtain a reference to the current object used to define XULAppInfo.
|
||||
*/
|
||||
var getAppInfo = function() { return currentAppInfo; };
|
||||
var getAppInfo = function() {
|
||||
return currentAppInfo;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the current application info.
|
||||
|
@ -117,7 +114,10 @@ var updateAppInfo = function(options) {
|
|||
|
||||
// Unregister an existing factory if one exists.
|
||||
try {
|
||||
let existing = Components.manager.getClassObjectByContractID(contractid, Ci.nsIFactory);
|
||||
let existing = Components.manager.getClassObjectByContractID(
|
||||
contractid,
|
||||
Ci.nsIFactory
|
||||
);
|
||||
registrar.unregisterFactory(id, existing);
|
||||
} catch (ex) {}
|
||||
|
||||
|
|
|
@ -12,14 +12,17 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = [
|
||||
"Assert",
|
||||
];
|
||||
var EXPORTED_SYMBOLS = ["Assert"];
|
||||
|
||||
const {ObjectUtils} = ChromeUtils.import("resource://gre/modules/ObjectUtils.jsm");
|
||||
const { ObjectUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/ObjectUtils.jsm"
|
||||
);
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Promise",
|
||||
"resource://gre/modules/Promise.jsm"
|
||||
);
|
||||
/**
|
||||
* 1. The assert module provides functions that throw AssertionError's when
|
||||
* particular conditions are not met.
|
||||
|
@ -33,12 +36,14 @@ ChromeUtils.defineModuleGetter(this, "Promise",
|
|||
* test-only modules. This is false when the reporter is set by content scripts,
|
||||
* because they may still run in the parent process.
|
||||
*/
|
||||
var Assert = this.Assert = function(reporterFunc, isDefault) {
|
||||
if (reporterFunc)
|
||||
var Assert = (this.Assert = function(reporterFunc, isDefault) {
|
||||
if (reporterFunc) {
|
||||
this.setReporter(reporterFunc);
|
||||
if (isDefault)
|
||||
}
|
||||
if (isDefault) {
|
||||
Assert.setReporter(reporterFunc);
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// This allows using the Assert object as an additional global instance.
|
||||
Object.setPrototypeOf(Assert, Assert.prototype);
|
||||
|
@ -66,7 +71,7 @@ function truncate(text, newLength = kTruncateLength) {
|
|||
if (typeof text == "string") {
|
||||
return text.length < newLength ? text : text.slice(0, newLength);
|
||||
}
|
||||
return text;
|
||||
return text;
|
||||
}
|
||||
|
||||
function getMessage(error, prefix = "") {
|
||||
|
@ -86,8 +91,13 @@ function getMessage(error, prefix = "") {
|
|||
let message = prefix;
|
||||
if (error.operator) {
|
||||
let truncateLength = error.truncate ? kTruncateLength : Infinity;
|
||||
message += (prefix ? " - " : "") + truncate(actual, truncateLength) + " " +
|
||||
error.operator + " " + truncate(expected, truncateLength);
|
||||
message +=
|
||||
(prefix ? " - " : "") +
|
||||
truncate(actual, truncateLength) +
|
||||
" " +
|
||||
error.operator +
|
||||
" " +
|
||||
truncate(expected, truncateLength);
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
@ -191,11 +201,21 @@ proto.setReporter = function(reporterFunc) {
|
|||
* @param truncate (optional) [true]
|
||||
* (boolean) Whether or not `actual` and `expected` should be truncated when printing
|
||||
*/
|
||||
proto.report = function(failed, actual, expected, message, operator, truncate = true) {
|
||||
proto.report = function(
|
||||
failed,
|
||||
actual,
|
||||
expected,
|
||||
message,
|
||||
operator,
|
||||
truncate = true
|
||||
) {
|
||||
// Although not ideal, we allow a "null" message due to the way some of the extension tests
|
||||
// work.
|
||||
if (message !== undefined && message !== null && typeof message != "string") {
|
||||
this.ok(false, `Expected a string or undefined for the error message to Assert.*, got ${typeof message}`);
|
||||
this.ok(
|
||||
false,
|
||||
`Expected a string or undefined for the error message to Assert.*, got ${typeof message}`
|
||||
);
|
||||
}
|
||||
let err = new Assert.AssertionError({
|
||||
message,
|
||||
|
@ -228,7 +248,13 @@ proto.report = function(failed, actual, expected, message, operator, truncate =
|
|||
*/
|
||||
proto.ok = function(value, message) {
|
||||
if (arguments.length > 2) {
|
||||
this.report(true, false, true, "Too many arguments passed to `Assert.ok()`", "==");
|
||||
this.report(
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
"Too many arguments passed to `Assert.ok()`",
|
||||
"=="
|
||||
);
|
||||
} else {
|
||||
this.report(!value, value, true, message, "==");
|
||||
}
|
||||
|
@ -281,7 +307,14 @@ proto.notEqual = function notEqual(actual, expected, message) {
|
|||
* (string) Short explanation of the expected result
|
||||
*/
|
||||
proto.deepEqual = function deepEqual(actual, expected, message) {
|
||||
this.report(!ObjectUtils.deepEqual(actual, expected), actual, expected, message, "deepEqual", false);
|
||||
this.report(
|
||||
!ObjectUtils.deepEqual(actual, expected),
|
||||
actual,
|
||||
expected,
|
||||
message,
|
||||
"deepEqual",
|
||||
false
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -296,7 +329,14 @@ proto.deepEqual = function deepEqual(actual, expected, message) {
|
|||
* (string) Short explanation of the expected result
|
||||
*/
|
||||
proto.notDeepEqual = function notDeepEqual(actual, expected, message) {
|
||||
this.report(ObjectUtils.deepEqual(actual, expected), actual, expected, message, "notDeepEqual", false);
|
||||
this.report(
|
||||
ObjectUtils.deepEqual(actual, expected),
|
||||
actual,
|
||||
expected,
|
||||
message,
|
||||
"notDeepEqual",
|
||||
false
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -331,14 +371,21 @@ proto.notStrictEqual = function notStrictEqual(actual, expected, message) {
|
|||
|
||||
function checkExpectedArgument(instance, funcName, expected) {
|
||||
if (!expected) {
|
||||
instance.ok(false, `Error: The 'expected' argument was not supplied to Assert.${funcName}()`);
|
||||
instance.ok(
|
||||
false,
|
||||
`Error: The 'expected' argument was not supplied to Assert.${funcName}()`
|
||||
);
|
||||
}
|
||||
|
||||
if (!instanceOf(expected, "RegExp") &&
|
||||
typeof expected !== "function" &&
|
||||
typeof expected !== "object") {
|
||||
instance.ok(false,
|
||||
`Error: The 'expected' argument to Assert.${funcName}() must be a RegExp, function or an object`);
|
||||
if (
|
||||
!instanceOf(expected, "RegExp") &&
|
||||
typeof expected !== "function" &&
|
||||
typeof expected !== "object"
|
||||
) {
|
||||
instance.ok(
|
||||
false,
|
||||
`Error: The 'expected' argument to Assert.${funcName}() must be a RegExp, function or an object`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -349,10 +396,12 @@ function expectedException(actual, expected) {
|
|||
|
||||
if (instanceOf(expected, "RegExp")) {
|
||||
return expected.test(actual);
|
||||
// We need to guard against the right hand parameter of "instanceof" lacking
|
||||
// the "prototype" property, which is true of arrow functions in particular.
|
||||
} else if (!(typeof expected === "function" && !expected.prototype) &&
|
||||
actual instanceof expected) {
|
||||
// We need to guard against the right hand parameter of "instanceof" lacking
|
||||
// the "prototype" property, which is true of arrow functions in particular.
|
||||
} else if (
|
||||
!(typeof expected === "function" && !expected.prototype) &&
|
||||
actual instanceof expected
|
||||
) {
|
||||
return true;
|
||||
} else if (expected.call({}, actual) === true) {
|
||||
return true;
|
||||
|
@ -393,14 +442,15 @@ proto.throws = function(block, expected, message) {
|
|||
actual = e;
|
||||
}
|
||||
|
||||
message = (expected.name ? " (" + expected.name + ")." : ".") +
|
||||
(message ? " " + message : ".");
|
||||
message =
|
||||
(expected.name ? " (" + expected.name + ")." : ".") +
|
||||
(message ? " " + message : ".");
|
||||
|
||||
if (!actual) {
|
||||
this.report(true, actual, expected, "Missing expected exception" + message);
|
||||
}
|
||||
|
||||
if ((actual && !expectedException(actual, expected))) {
|
||||
if (actual && !expectedException(actual, expected)) {
|
||||
throw actual;
|
||||
}
|
||||
|
||||
|
@ -421,17 +471,25 @@ proto.throws = function(block, expected, message) {
|
|||
proto.rejects = function(promise, expected, message) {
|
||||
checkExpectedArgument(this, "rejects", expected);
|
||||
return new Promise((resolve, reject) => {
|
||||
return promise.then(
|
||||
() => this.report(true, null, expected, "Missing expected exception " + message),
|
||||
err => {
|
||||
if (!expectedException(err, expected)) {
|
||||
reject(err);
|
||||
return;
|
||||
return promise
|
||||
.then(
|
||||
() =>
|
||||
this.report(
|
||||
true,
|
||||
null,
|
||||
expected,
|
||||
"Missing expected exception " + message
|
||||
),
|
||||
err => {
|
||||
if (!expectedException(err, expected)) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
this.report(false, err, expected, message);
|
||||
resolve();
|
||||
}
|
||||
this.report(false, err, expected, message);
|
||||
resolve();
|
||||
}
|
||||
).catch(reject);
|
||||
)
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = [
|
||||
"CoverageCollector",
|
||||
];
|
||||
var EXPORTED_SYMBOLS = ["CoverageCollector"];
|
||||
|
||||
/* globals Debugger */
|
||||
const {addDebuggerToGlobal} = ChromeUtils.import("resource://gre/modules/jsdebugger.jsm");
|
||||
const { addDebuggerToGlobal } = ChromeUtils.import(
|
||||
"resource://gre/modules/jsdebugger.jsm"
|
||||
);
|
||||
addDebuggerToGlobal(Cu.getGlobalForObject(this));
|
||||
|
||||
/**
|
||||
|
@ -22,7 +22,7 @@ var CoverageCollector = function(prefix) {
|
|||
this._dbg.addAllGlobalsAsDebuggees();
|
||||
this._scripts = this._dbg.findScripts();
|
||||
|
||||
this._dbg.onNewScript = (script) => {
|
||||
this._dbg.onNewScript = script => {
|
||||
this._scripts.push(script);
|
||||
};
|
||||
|
||||
|
@ -44,7 +44,7 @@ CoverageCollector.prototype._getLinesCovered = function() {
|
|||
}
|
||||
|
||||
cov.forEach(covered => {
|
||||
let {lineNumber, columnNumber, offset, count} = covered;
|
||||
let { lineNumber, columnNumber, offset, count } = covered;
|
||||
if (!count) {
|
||||
return;
|
||||
}
|
||||
|
@ -71,10 +71,11 @@ CoverageCollector.prototype._getLinesCovered = function() {
|
|||
// any offset on a particular line, that line must have been covered.
|
||||
for (let scriptName in currentCoverage) {
|
||||
for (let key in currentCoverage[scriptName]) {
|
||||
if (!this._allCoverage[scriptName] ||
|
||||
!this._allCoverage[scriptName][key] ||
|
||||
(this._allCoverage[scriptName][key] <
|
||||
currentCoverage[scriptName][key])) {
|
||||
if (
|
||||
!this._allCoverage[scriptName] ||
|
||||
!this._allCoverage[scriptName][key] ||
|
||||
this._allCoverage[scriptName][key] < currentCoverage[scriptName][key]
|
||||
) {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
let [lineNumber, colNumber, offset] = key.split("#");
|
||||
if (!coveredLines[scriptName]) {
|
||||
|
@ -100,7 +101,7 @@ CoverageCollector.prototype._getUncoveredLines = function() {
|
|||
}
|
||||
|
||||
// Get all lines in the script
|
||||
scriptOffsets.forEach( function(element, index) {
|
||||
scriptOffsets.forEach(function(element, index) {
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
@ -138,11 +139,11 @@ CoverageCollector.prototype._getMethodNames = function() {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get all lines contained within the method and
|
||||
* push a record of the form:
|
||||
* <method name> : <lines covered>
|
||||
*/
|
||||
scriptOffsets.forEach( function(element, index) {
|
||||
* Get all lines contained within the method and
|
||||
* push a record of the form:
|
||||
* <method name> : <lines covered>
|
||||
*/
|
||||
scriptOffsets.forEach(function(element, index) {
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
@ -161,14 +162,17 @@ CoverageCollector.prototype._getMethodNames = function() {
|
|||
*/
|
||||
CoverageCollector.prototype.recordTestCoverage = function(testName) {
|
||||
let ccov_scope = {};
|
||||
const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm", ccov_scope);
|
||||
const { OS } = ChromeUtils.import(
|
||||
"resource://gre/modules/osfile.jsm",
|
||||
ccov_scope
|
||||
);
|
||||
|
||||
dump("Collecting coverage for: " + testName + "\n");
|
||||
let rawLines = this._getLinesCovered(testName);
|
||||
let methods = this._getMethodNames();
|
||||
let uncoveredLines = this._getUncoveredLines();
|
||||
let result = [];
|
||||
let versionControlBlock = {version: 1.0};
|
||||
let versionControlBlock = { version: 1.0 };
|
||||
result.push(versionControlBlock);
|
||||
|
||||
for (let scriptName in rawLines) {
|
||||
|
@ -180,8 +184,13 @@ CoverageCollector.prototype.recordTestCoverage = function(testName) {
|
|||
uncovered: [],
|
||||
};
|
||||
|
||||
if (typeof(methods[scriptName]) != "undefined" && methods[scriptName] != null) {
|
||||
for (let [methodName, methodLines] of Object.entries(methods[scriptName])) {
|
||||
if (
|
||||
typeof methods[scriptName] != "undefined" &&
|
||||
methods[scriptName] != null
|
||||
) {
|
||||
for (let [methodName, methodLines] of Object.entries(
|
||||
methods[scriptName]
|
||||
)) {
|
||||
rec.methods[methodName] = methodLines;
|
||||
}
|
||||
}
|
||||
|
@ -199,7 +208,7 @@ CoverageCollector.prototype.recordTestCoverage = function(testName) {
|
|||
let arr = this._encoder.encode(JSON.stringify(result, null, 2));
|
||||
let path = this._prefix + "/jscov_" + Date.now() + ".json";
|
||||
dump("Writing coverage to: " + path + "\n");
|
||||
return OS.File.writeAtomic(path, arr, {tmpPath: path + ".tmp"});
|
||||
return OS.File.writeAtomic(path, arr, { tmpPath: path + ".tmp" });
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,9 +8,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = [
|
||||
"FileTestUtils",
|
||||
];
|
||||
var EXPORTED_SYMBOLS = ["FileTestUtils"];
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/AsyncShutdown.jsm", this);
|
||||
ChromeUtils.import("resource://gre/modules/DownloadPaths.jsm", this);
|
||||
|
@ -91,8 +89,10 @@ var FileTestUtils = {
|
|||
// error if the file existed before, and was recently deleted. There is no
|
||||
// way to distinguish this from an access list issue because checking for
|
||||
// the file existence would also result in the same error.
|
||||
if (!(ex instanceof OS.File.Error) ||
|
||||
!(ex.becauseNoSuchFile || ex.becauseAccessDenied)) {
|
||||
if (
|
||||
!(ex instanceof OS.File.Error) ||
|
||||
!(ex.becauseNoSuchFile || ex.becauseAccessDenied)
|
||||
) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +103,9 @@ var FileTestUtils = {
|
|||
* Returns a reference to a global temporary directory that will be deleted
|
||||
* when all tests terminate.
|
||||
*/
|
||||
XPCOMUtils.defineLazyGetter(FileTestUtils, "_globalTemporaryDirectory",
|
||||
XPCOMUtils.defineLazyGetter(
|
||||
FileTestUtils,
|
||||
"_globalTemporaryDirectory",
|
||||
function() {
|
||||
// While previous test runs should have deleted their temporary directories,
|
||||
// on Windows they might still be pending deletion on the physical file
|
||||
|
@ -112,7 +114,8 @@ XPCOMUtils.defineLazyGetter(FileTestUtils, "_globalTemporaryDirectory",
|
|||
let randomNumber = Math.floor(Math.random() * 1000000);
|
||||
let dir = FileUtils.getFile("TmpD", ["testdir-" + randomNumber]);
|
||||
dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
|
||||
AsyncShutdown.profileBeforeChange.addBlocker("Removing test files",
|
||||
AsyncShutdown.profileBeforeChange.addBlocker(
|
||||
"Removing test files",
|
||||
async () => {
|
||||
// Remove the files we know about first.
|
||||
for (let path of gPathsToRemove) {
|
||||
|
@ -126,13 +129,16 @@ XPCOMUtils.defineLazyGetter(FileTestUtils, "_globalTemporaryDirectory",
|
|||
// Detect any extra files, like the ".part" files of downloads.
|
||||
let iterator = new OS.File.DirectoryIterator(dir.path);
|
||||
try {
|
||||
await iterator.forEach(entry => this.tolerantRemove(entry.path,
|
||||
entry.isDir));
|
||||
await iterator.forEach(entry =>
|
||||
this.tolerantRemove(entry.path, entry.isDir)
|
||||
);
|
||||
} finally {
|
||||
iterator.close();
|
||||
}
|
||||
// This will fail if any test leaves inaccessible files behind.
|
||||
await OS.File.removeEmptyDir(dir.path);
|
||||
});
|
||||
}
|
||||
);
|
||||
return dir;
|
||||
});
|
||||
}
|
||||
);
|
||||
|
|
|
@ -4,19 +4,22 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = [
|
||||
"MockRegistrar",
|
||||
];
|
||||
var EXPORTED_SYMBOLS = ["MockRegistrar"];
|
||||
|
||||
const Cm = Components.manager;
|
||||
|
||||
const {Log} = ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const { Log } = ChromeUtils.import("resource://gre/modules/Log.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
var logger = Log.repository.getLogger("MockRegistrar");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "UUIDGen",
|
||||
"@mozilla.org/uuid-generator;1",
|
||||
"nsIUUIDGenerator");
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"UUIDGen",
|
||||
"@mozilla.org/uuid-generator;1",
|
||||
"nsIUUIDGenerator"
|
||||
);
|
||||
|
||||
var MockRegistrar = Object.freeze({
|
||||
_registeredComponents: new Map(),
|
||||
|
@ -80,10 +83,12 @@ var MockRegistrar = Object.freeze({
|
|||
QueryInterface: ChromeUtils.generateQI([Ci.nsIFactory]),
|
||||
};
|
||||
|
||||
this.registrar.registerFactory(cid,
|
||||
"A Mock for " + contractID,
|
||||
contractID,
|
||||
factory);
|
||||
this.registrar.registerFactory(
|
||||
cid,
|
||||
"A Mock for " + contractID,
|
||||
contractID,
|
||||
factory
|
||||
);
|
||||
|
||||
this._registeredComponents.set(cid, {
|
||||
contractID,
|
||||
|
@ -109,9 +114,12 @@ var MockRegistrar = Object.freeze({
|
|||
if (component.originalCID) {
|
||||
// Passing `null` for the factory re-maps the contract ID to the
|
||||
// entry for its original CID.
|
||||
this.registrar.registerFactory(component.originalCID, "",
|
||||
component.contractID,
|
||||
null);
|
||||
this.registrar.registerFactory(
|
||||
component.originalCID,
|
||||
"",
|
||||
component.contractID,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
this._registeredComponents.delete(cid);
|
||||
|
@ -125,5 +133,4 @@ var MockRegistrar = Object.freeze({
|
|||
this.unregister(cid);
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["MockRegistry"];
|
||||
|
||||
const {MockRegistrar} = ChromeUtils.import("resource://testing-common/MockRegistrar.jsm");
|
||||
const { MockRegistrar } = ChromeUtils.import(
|
||||
"resource://testing-common/MockRegistrar.jsm"
|
||||
);
|
||||
|
||||
class MockRegistry {
|
||||
constructor() {
|
||||
|
@ -27,7 +28,7 @@ class MockRegistry {
|
|||
* subset of the interface used in tests. In particular, only values
|
||||
* of type string are supported.
|
||||
*/
|
||||
function MockWindowsRegKey() { }
|
||||
function MockWindowsRegKey() {}
|
||||
MockWindowsRegKey.prototype = {
|
||||
values: null,
|
||||
|
||||
|
@ -48,8 +49,9 @@ class MockRegistry {
|
|||
},
|
||||
|
||||
get valueCount() {
|
||||
if (!this.values)
|
||||
if (!this.values) {
|
||||
throw Cr.NS_ERROR_FAILURE;
|
||||
}
|
||||
return this.values.size;
|
||||
},
|
||||
|
||||
|
@ -65,8 +67,9 @@ class MockRegistry {
|
|||
},
|
||||
|
||||
getValueName(index) {
|
||||
if (!this.values || index >= this.values.size)
|
||||
if (!this.values || index >= this.values.size) {
|
||||
throw Cr.NS_ERROR_FAILURE;
|
||||
}
|
||||
let names = Array.from(this.values.keys());
|
||||
return names[index];
|
||||
},
|
||||
|
@ -79,7 +82,10 @@ class MockRegistry {
|
|||
},
|
||||
};
|
||||
|
||||
this.cid = MockRegistrar.register("@mozilla.org/windows-registry-key;1", MockWindowsRegKey);
|
||||
this.cid = MockRegistrar.register(
|
||||
"@mozilla.org/windows-registry-key;1",
|
||||
MockWindowsRegKey
|
||||
);
|
||||
}
|
||||
|
||||
shutdown() {
|
||||
|
|
|
@ -2,21 +2,31 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["sinon"];
|
||||
|
||||
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
// ================================================
|
||||
// Load mocking/stubbing library sinon
|
||||
// docs: http://sinonjs.org/releases/v7.2.7/
|
||||
const {clearInterval, clearTimeout, setInterval, setIntervalWithTarget, setTimeout, setTimeoutWithTarget} = ChromeUtils.import("resource://gre/modules/Timer.jsm");
|
||||
const {
|
||||
clearInterval,
|
||||
clearTimeout,
|
||||
setInterval,
|
||||
setIntervalWithTarget,
|
||||
setTimeout,
|
||||
setTimeoutWithTarget,
|
||||
} = ChromeUtils.import("resource://gre/modules/Timer.jsm");
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const global = {
|
||||
clearInterval,
|
||||
clearTimeout,
|
||||
setInterval,
|
||||
setIntervalWithTarget,
|
||||
setTimeout,
|
||||
setTimeoutWithTarget,
|
||||
clearInterval,
|
||||
clearTimeout,
|
||||
setInterval,
|
||||
setIntervalWithTarget,
|
||||
setTimeout,
|
||||
setTimeoutWithTarget,
|
||||
};
|
||||
Services.scriptloader.loadSubScript("resource://testing-common/sinon-7.2.7.js", this);
|
||||
Services.scriptloader.loadSubScript(
|
||||
"resource://testing-common/sinon-7.2.7.js",
|
||||
this
|
||||
);
|
||||
const sinon = global.sinon;
|
||||
// ================================================
|
||||
|
|
|
@ -4,10 +4,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = [
|
||||
"StructuredLogger",
|
||||
"StructuredFormatter",
|
||||
];
|
||||
var EXPORTED_SYMBOLS = ["StructuredLogger", "StructuredFormatter"];
|
||||
|
||||
/**
|
||||
* TestLogger: Logger class generating messages compliant with the
|
||||
|
@ -34,12 +31,19 @@ var StructuredLogger = function(name, dumpFun = dump, mutators = []) {
|
|||
*/
|
||||
StructuredLogger.prototype = {
|
||||
testStart(test) {
|
||||
var data = {test: this._testId(test)};
|
||||
var data = { test: this._testId(test) };
|
||||
this._logData("test_start", data);
|
||||
},
|
||||
|
||||
testStatus(test, subtest, status, expected = "PASS",
|
||||
message = null, stack = null, extra = null) {
|
||||
testStatus(
|
||||
test,
|
||||
subtest,
|
||||
status,
|
||||
expected = "PASS",
|
||||
message = null,
|
||||
stack = null,
|
||||
extra = null
|
||||
) {
|
||||
if (subtest === null || subtest === undefined) {
|
||||
// Fix for assertions that don't pass in a name
|
||||
subtest = "undefined assertion name";
|
||||
|
@ -67,8 +71,15 @@ StructuredLogger.prototype = {
|
|||
this._logData("test_status", data);
|
||||
},
|
||||
|
||||
testEnd(test, status, expected = "OK", message = null, stack = null, extra = null) {
|
||||
var data = {test: this._testId(test), status};
|
||||
testEnd(
|
||||
test,
|
||||
status,
|
||||
expected = "OK",
|
||||
message = null,
|
||||
stack = null,
|
||||
extra = null
|
||||
) {
|
||||
var data = { test: this._testId(test), status };
|
||||
|
||||
if (expected != status && status != "SKIP") {
|
||||
data.expected = expected;
|
||||
|
@ -87,16 +98,25 @@ StructuredLogger.prototype = {
|
|||
},
|
||||
|
||||
assertionCount(test, count, minExpected = 0, maxExpected = 0) {
|
||||
var data = {test: this._testId(test),
|
||||
min_expected: minExpected,
|
||||
max_expected: maxExpected,
|
||||
count};
|
||||
var data = {
|
||||
test: this._testId(test),
|
||||
min_expected: minExpected,
|
||||
max_expected: maxExpected,
|
||||
count,
|
||||
};
|
||||
|
||||
this._logData("assertion_count", data);
|
||||
},
|
||||
|
||||
suiteStart(tests, name = null, runinfo = null, versioninfo = null, deviceinfo = null, extra = null) {
|
||||
var data = {tests: tests.map(x => this._testId(x))};
|
||||
suiteStart(
|
||||
tests,
|
||||
name = null,
|
||||
runinfo = null,
|
||||
versioninfo = null,
|
||||
deviceinfo = null,
|
||||
extra = null
|
||||
) {
|
||||
var data = { tests: tests.map(x => this._testId(x)) };
|
||||
if (name !== null) {
|
||||
data.name = name;
|
||||
}
|
||||
|
@ -130,7 +150,6 @@ StructuredLogger.prototype = {
|
|||
this._logData("suite_end", data);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Unstructured logging functions. The "extra" parameter can always by used to
|
||||
* log suite specific data. If a "stack" field is provided it is logged at the
|
||||
|
@ -179,7 +198,6 @@ StructuredLogger.prototype = {
|
|||
});
|
||||
},
|
||||
|
||||
|
||||
_logData(action, data = {}) {
|
||||
var allData = {
|
||||
action,
|
||||
|
@ -208,17 +226,15 @@ StructuredLogger.prototype = {
|
|||
},
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* StructuredFormatter: Formatter class turning structured messages
|
||||
* into human-readable messages.
|
||||
*/
|
||||
var StructuredFormatter = function() {
|
||||
this.testStartTimes = {};
|
||||
this.testStartTimes = {};
|
||||
};
|
||||
|
||||
StructuredFormatter.prototype = {
|
||||
|
||||
log(message) {
|
||||
return message.message;
|
||||
},
|
||||
|
@ -234,25 +250,40 @@ StructuredFormatter.prototype = {
|
|||
},
|
||||
|
||||
test_status(message) {
|
||||
var statusInfo = message.test + " | " + message.subtest +
|
||||
(message.message ? " | " + message.message : "");
|
||||
var statusInfo =
|
||||
message.test +
|
||||
" | " +
|
||||
message.subtest +
|
||||
(message.message ? " | " + message.message : "");
|
||||
if (message.expected) {
|
||||
return "TEST-UNEXPECTED-" + message.status + " | " + statusInfo +
|
||||
" - expected: " + message.expected;
|
||||
return (
|
||||
"TEST-UNEXPECTED-" +
|
||||
message.status +
|
||||
" | " +
|
||||
statusInfo +
|
||||
" - expected: " +
|
||||
message.expected
|
||||
);
|
||||
}
|
||||
return "TEST-" + message.status + " | " + statusInfo;
|
||||
return "TEST-" + message.status + " | " + statusInfo;
|
||||
},
|
||||
|
||||
test_end(message) {
|
||||
var startTime = this.testStartTimes[message.test];
|
||||
delete this.testStartTimes[message.test];
|
||||
var statusInfo = message.test + (message.message ? " | " + String(message.message) : "");
|
||||
var statusInfo =
|
||||
message.test + (message.message ? " | " + String(message.message) : "");
|
||||
var result;
|
||||
if (message.expected) {
|
||||
result = "TEST-UNEXPECTED-" + message.status + " | " + statusInfo +
|
||||
" - expected: " + message.expected;
|
||||
result =
|
||||
"TEST-UNEXPECTED-" +
|
||||
message.status +
|
||||
" | " +
|
||||
statusInfo +
|
||||
" - expected: " +
|
||||
message.expected;
|
||||
} else {
|
||||
return "TEST-" + message.status + " | " + statusInfo;
|
||||
return "TEST-" + message.status + " | " + statusInfo;
|
||||
}
|
||||
result = result + " | took " + message.time - startTime + "ms";
|
||||
return result;
|
||||
|
@ -262,4 +293,3 @@ StructuredFormatter.prototype = {
|
|||
return "SUITE-END | took " + message.time - this.suiteStartTime + "ms";
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = [
|
||||
"TestUtils",
|
||||
];
|
||||
var EXPORTED_SYMBOLS = ["TestUtils"];
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {clearInterval, setInterval} = ChromeUtils.import("resource://gre/modules/Timer.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { clearInterval, setInterval } = ChromeUtils.import(
|
||||
"resource://gre/modules/Timer.jsm"
|
||||
);
|
||||
|
||||
var TestUtils = {
|
||||
executeSoon(callbackFn) {
|
||||
|
@ -89,19 +89,23 @@ var TestUtils = {
|
|||
*/
|
||||
waitForPrefChange(prefName, checkFn) {
|
||||
return new Promise((resolve, reject) => {
|
||||
Services.prefs.addObserver(prefName, function observer(subject, topic, data) {
|
||||
Services.prefs.addObserver(prefName, function observer(
|
||||
subject,
|
||||
topic,
|
||||
data
|
||||
) {
|
||||
try {
|
||||
let prefValue = null;
|
||||
switch (Services.prefs.getPrefType(prefName)) {
|
||||
case Services.prefs.PREF_STRING:
|
||||
prefValue = Services.prefs.getStringPref(prefName);
|
||||
break;
|
||||
case Services.prefs.PREF_INT:
|
||||
prefValue = Services.prefs.getIntPref(prefName);
|
||||
break;
|
||||
case Services.prefs.PREF_BOOL:
|
||||
prefValue = Services.prefs.getBoolPref(prefName);
|
||||
break;
|
||||
case Services.prefs.PREF_STRING:
|
||||
prefValue = Services.prefs.getStringPref(prefName);
|
||||
break;
|
||||
case Services.prefs.PREF_INT:
|
||||
prefValue = Services.prefs.getIntPref(prefName);
|
||||
break;
|
||||
case Services.prefs.PREF_BOOL:
|
||||
prefValue = Services.prefs.getBoolPref(prefName);
|
||||
break;
|
||||
}
|
||||
if (checkFn && !checkFn(prefValue)) {
|
||||
return;
|
||||
|
@ -129,7 +133,10 @@ var TestUtils = {
|
|||
eltOrRect = eltOrRect.getBoundingClientRect();
|
||||
}
|
||||
let { left, top, width, height } = eltOrRect;
|
||||
let canvas = win.document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
|
||||
let canvas = win.document.createElementNS(
|
||||
"http://www.w3.org/1999/xhtml",
|
||||
"canvas"
|
||||
);
|
||||
let ctx = canvas.getContext("2d");
|
||||
let ratio = win.devicePixelRatio;
|
||||
canvas.width = width * ratio;
|
||||
|
@ -139,7 +146,7 @@ var TestUtils = {
|
|||
return canvas.toDataURL();
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* Will poll a condition function until it returns true.
|
||||
*
|
||||
* @param condition
|
||||
|
|
|
@ -33,17 +33,26 @@ function run_test() {
|
|||
return objChain.slice(-clsChain.length) === clsChain;
|
||||
}
|
||||
|
||||
assert.ok(indirectInstanceOf(ns.Assert.AssertionError.prototype, Error),
|
||||
"Assert.AssertionError instanceof Error");
|
||||
assert.ok(
|
||||
indirectInstanceOf(ns.Assert.AssertionError.prototype, Error),
|
||||
"Assert.AssertionError instanceof Error"
|
||||
);
|
||||
|
||||
assert.throws(makeBlock(assert.ok, false),
|
||||
ns.Assert.AssertionError, "ok(false)");
|
||||
assert.throws(
|
||||
makeBlock(assert.ok, false),
|
||||
ns.Assert.AssertionError,
|
||||
"ok(false)"
|
||||
);
|
||||
|
||||
assert.ok(true, "ok(true)");
|
||||
|
||||
assert.ok("test", "ok('test')");
|
||||
|
||||
assert.throws(makeBlock(assert.equal, true, false), ns.Assert.AssertionError, "equal");
|
||||
assert.throws(
|
||||
makeBlock(assert.equal, true, false),
|
||||
ns.Assert.AssertionError,
|
||||
"equal"
|
||||
);
|
||||
|
||||
assert.equal(null, null, "equal");
|
||||
|
||||
|
@ -55,57 +64,94 @@ function run_test() {
|
|||
|
||||
assert.notEqual(true, false, "notEqual");
|
||||
|
||||
assert.throws(makeBlock(assert.notEqual, true, true),
|
||||
ns.Assert.AssertionError, "notEqual");
|
||||
assert.throws(
|
||||
makeBlock(assert.notEqual, true, true),
|
||||
ns.Assert.AssertionError,
|
||||
"notEqual"
|
||||
);
|
||||
|
||||
assert.throws(makeBlock(assert.strictEqual, 2, "2"),
|
||||
ns.Assert.AssertionError, "strictEqual");
|
||||
assert.throws(
|
||||
makeBlock(assert.strictEqual, 2, "2"),
|
||||
ns.Assert.AssertionError,
|
||||
"strictEqual"
|
||||
);
|
||||
|
||||
assert.throws(makeBlock(assert.strictEqual, null, undefined),
|
||||
ns.Assert.AssertionError, "strictEqual");
|
||||
assert.throws(
|
||||
makeBlock(assert.strictEqual, null, undefined),
|
||||
ns.Assert.AssertionError,
|
||||
"strictEqual"
|
||||
);
|
||||
|
||||
assert.notStrictEqual(2, "2", "notStrictEqual");
|
||||
|
||||
// deepEquals joy!
|
||||
// 7.2
|
||||
assert.deepEqual(new Date(2000, 3, 14), new Date(2000, 3, 14), "deepEqual date");
|
||||
assert.deepEqual(
|
||||
new Date(2000, 3, 14),
|
||||
new Date(2000, 3, 14),
|
||||
"deepEqual date"
|
||||
);
|
||||
assert.deepEqual(new Date(NaN), new Date(NaN), "deepEqual invalid dates");
|
||||
|
||||
assert.throws(makeBlock(assert.deepEqual, new Date(), new Date(2000, 3, 14)),
|
||||
ns.Assert.AssertionError,
|
||||
"deepEqual date");
|
||||
assert.throws(
|
||||
makeBlock(assert.deepEqual, new Date(), new Date(2000, 3, 14)),
|
||||
ns.Assert.AssertionError,
|
||||
"deepEqual date"
|
||||
);
|
||||
|
||||
// 7.3
|
||||
assert.deepEqual(/a/, /a/);
|
||||
assert.deepEqual(/a/g, /a/g);
|
||||
assert.deepEqual(/a/i, /a/i);
|
||||
assert.deepEqual(/a/m, /a/m);
|
||||
assert.deepEqual(/a/igm, /a/igm);
|
||||
assert.throws(makeBlock(assert.deepEqual, /ab/, /a/), ns.Assert.AssertionError);
|
||||
assert.throws(makeBlock(assert.deepEqual, /a/g, /a/), ns.Assert.AssertionError);
|
||||
assert.throws(makeBlock(assert.deepEqual, /a/i, /a/), ns.Assert.AssertionError);
|
||||
assert.throws(makeBlock(assert.deepEqual, /a/m, /a/), ns.Assert.AssertionError);
|
||||
assert.throws(makeBlock(assert.deepEqual, /a/igm, /a/im), ns.Assert.AssertionError);
|
||||
assert.deepEqual(/a/gim, /a/gim);
|
||||
assert.throws(
|
||||
makeBlock(assert.deepEqual, /ab/, /a/),
|
||||
ns.Assert.AssertionError
|
||||
);
|
||||
assert.throws(
|
||||
makeBlock(assert.deepEqual, /a/g, /a/),
|
||||
ns.Assert.AssertionError
|
||||
);
|
||||
assert.throws(
|
||||
makeBlock(assert.deepEqual, /a/i, /a/),
|
||||
ns.Assert.AssertionError
|
||||
);
|
||||
assert.throws(
|
||||
makeBlock(assert.deepEqual, /a/m, /a/),
|
||||
ns.Assert.AssertionError
|
||||
);
|
||||
assert.throws(
|
||||
makeBlock(assert.deepEqual, /a/gim, /a/im),
|
||||
ns.Assert.AssertionError
|
||||
);
|
||||
|
||||
let re1 = /a/;
|
||||
re1.lastIndex = 3;
|
||||
assert.throws(makeBlock(assert.deepEqual, re1, /a/), ns.Assert.AssertionError);
|
||||
assert.throws(
|
||||
makeBlock(assert.deepEqual, re1, /a/),
|
||||
ns.Assert.AssertionError
|
||||
);
|
||||
|
||||
// 7.4
|
||||
assert.deepEqual(4, "4", "deepEqual == check");
|
||||
assert.deepEqual(true, 1, "deepEqual == check");
|
||||
assert.throws(makeBlock(assert.deepEqual, 4, "5"),
|
||||
ns.Assert.AssertionError,
|
||||
"deepEqual == check");
|
||||
assert.throws(
|
||||
makeBlock(assert.deepEqual, 4, "5"),
|
||||
ns.Assert.AssertionError,
|
||||
"deepEqual == check"
|
||||
);
|
||||
|
||||
// 7.5
|
||||
// having the same number of owned properties && the same set of keys
|
||||
assert.deepEqual({a: 4}, {a: 4});
|
||||
assert.deepEqual({a: 4, b: "2"}, {a: 4, b: "2"});
|
||||
assert.deepEqual({ a: 4 }, { a: 4 });
|
||||
assert.deepEqual({ a: 4, b: "2" }, { a: 4, b: "2" });
|
||||
assert.deepEqual([4], ["4"]);
|
||||
assert.throws(makeBlock(assert.deepEqual, {a: 4}, {a: 4, b: true}),
|
||||
ns.Assert.AssertionError);
|
||||
assert.deepEqual(["a"], {0: "a"});
|
||||
assert.throws(
|
||||
makeBlock(assert.deepEqual, { a: 4 }, { a: 4, b: true }),
|
||||
ns.Assert.AssertionError
|
||||
);
|
||||
assert.deepEqual(["a"], { 0: "a" });
|
||||
|
||||
let a1 = [1, 2, 3];
|
||||
let a2 = [1, 2, 3];
|
||||
|
@ -113,12 +159,16 @@ function run_test() {
|
|||
a1.b = true;
|
||||
a2.b = true;
|
||||
a2.a = "test";
|
||||
assert.throws(makeBlock(assert.deepEqual, Object.keys(a1), Object.keys(a2)),
|
||||
ns.Assert.AssertionError);
|
||||
assert.throws(
|
||||
makeBlock(assert.deepEqual, Object.keys(a1), Object.keys(a2)),
|
||||
ns.Assert.AssertionError
|
||||
);
|
||||
assert.deepEqual(a1, a2);
|
||||
|
||||
let nbRoot = {
|
||||
toString() { return this.first + " " + this.last; },
|
||||
toString() {
|
||||
return this.first + " " + this.last;
|
||||
},
|
||||
};
|
||||
|
||||
function nameBuilder(first, last) {
|
||||
|
@ -142,7 +192,10 @@ function run_test() {
|
|||
|
||||
nameBuilder2.prototype = Object;
|
||||
nb2 = new nameBuilder2("Ryan", "Dahl");
|
||||
assert.throws(makeBlock(assert.deepEqual, nb1, nb2), ns.Assert.AssertionError);
|
||||
assert.throws(
|
||||
makeBlock(assert.deepEqual, nb1, nb2),
|
||||
ns.Assert.AssertionError
|
||||
);
|
||||
|
||||
// String literal + object
|
||||
assert.throws(makeBlock(assert.deepEqual, "a", {}), ns.Assert.AssertionError);
|
||||
|
@ -155,10 +208,19 @@ function run_test() {
|
|||
makeBlock(thrower, ns.Assert.AssertionError);
|
||||
|
||||
// the basic calls work
|
||||
assert.throws(makeBlock(thrower, ns.Assert.AssertionError),
|
||||
ns.Assert.AssertionError, "message");
|
||||
assert.throws(makeBlock(thrower, ns.Assert.AssertionError), ns.Assert.AssertionError);
|
||||
assert.throws(makeBlock(thrower, ns.Assert.AssertionError), ns.Assert.AssertionError);
|
||||
assert.throws(
|
||||
makeBlock(thrower, ns.Assert.AssertionError),
|
||||
ns.Assert.AssertionError,
|
||||
"message"
|
||||
);
|
||||
assert.throws(
|
||||
makeBlock(thrower, ns.Assert.AssertionError),
|
||||
ns.Assert.AssertionError
|
||||
);
|
||||
assert.throws(
|
||||
makeBlock(thrower, ns.Assert.AssertionError),
|
||||
ns.Assert.AssertionError
|
||||
);
|
||||
|
||||
// if not passing an error, catch all.
|
||||
assert.throws(makeBlock(thrower, TypeError), TypeError);
|
||||
|
@ -171,9 +233,12 @@ function run_test() {
|
|||
threw = true;
|
||||
assert.ok(e instanceof TypeError, "type");
|
||||
}
|
||||
assert.equal(true, threw,
|
||||
"Assert.throws with an explicit error is eating extra errors",
|
||||
ns.Assert.AssertionError);
|
||||
assert.equal(
|
||||
true,
|
||||
threw,
|
||||
"Assert.throws with an explicit error is eating extra errors",
|
||||
ns.Assert.AssertionError
|
||||
);
|
||||
threw = false;
|
||||
|
||||
function ifError(err) {
|
||||
|
@ -188,12 +253,9 @@ function run_test() {
|
|||
// make sure that validating using constructor really works
|
||||
threw = false;
|
||||
try {
|
||||
assert.throws(
|
||||
function() {
|
||||
throw new Error({});
|
||||
},
|
||||
Array
|
||||
);
|
||||
assert.throws(function() {
|
||||
throw new Error({});
|
||||
}, Array);
|
||||
} catch (e) {
|
||||
threw = true;
|
||||
}
|
||||
|
@ -204,14 +266,14 @@ function run_test() {
|
|||
|
||||
// use a fn to validate error object
|
||||
assert.throws(makeBlock(thrower, TypeError), function(err) {
|
||||
if ((err instanceof TypeError) && /test/.test(err)) {
|
||||
if (err instanceof TypeError && /test/.test(err)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
// do the same with an arrow function
|
||||
assert.throws(makeBlock(thrower, TypeError), err => {
|
||||
if ((err instanceof TypeError) && /test/.test(err)) {
|
||||
if (err instanceof TypeError && /test/.test(err)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -221,8 +283,10 @@ function run_test() {
|
|||
try {
|
||||
assert.equal(actual, "");
|
||||
} catch (e) {
|
||||
assert.equal(e.toString(),
|
||||
["AssertionError:", expected, "==", '""'].join(" "));
|
||||
assert.equal(
|
||||
e.toString(),
|
||||
["AssertionError:", expected, "==", '""'].join(" ")
|
||||
);
|
||||
}
|
||||
}
|
||||
testAssertionMessage(undefined, '"undefined"');
|
||||
|
@ -242,9 +306,11 @@ function run_test() {
|
|||
testAssertionMessage(/abc/gim, '"/abc/gim"');
|
||||
testAssertionMessage(function f() {}, '"function f() {}"');
|
||||
testAssertionMessage({}, "{}");
|
||||
testAssertionMessage({a: undefined, b: null}, '{"a":"undefined","b":null}');
|
||||
testAssertionMessage({a: NaN, b: Infinity, c: -Infinity},
|
||||
'{"a":"NaN","b":"Infinity","c":"-Infinity"}');
|
||||
testAssertionMessage({ a: undefined, b: null }, '{"a":"undefined","b":null}');
|
||||
testAssertionMessage(
|
||||
{ a: NaN, b: Infinity, c: -Infinity },
|
||||
'{"a":"NaN","b":"Infinity","c":"-Infinity"}'
|
||||
);
|
||||
|
||||
// https://github.com/joyent/node/issues/2893
|
||||
try {
|
||||
|
@ -253,7 +319,10 @@ function run_test() {
|
|||
});
|
||||
} catch (e) {
|
||||
threw = true;
|
||||
assert.equal(e.message, "Error: The 'expected' argument was not supplied to Assert.throws() - false == true");
|
||||
assert.equal(
|
||||
e.message,
|
||||
"Error: The 'expected' argument was not supplied to Assert.throws() - false == true"
|
||||
);
|
||||
}
|
||||
assert.ok(threw);
|
||||
|
||||
|
@ -285,20 +354,27 @@ function run_test() {
|
|||
// Test XPCShell-test integration:
|
||||
ok(true, "OK, this went well");
|
||||
deepEqual(/a/g, /a/g, "deep equal should work on RegExp");
|
||||
deepEqual(/a/igm, /a/igm, "deep equal should work on RegExp");
|
||||
deepEqual({a: 4, b: "1"}, {b: "1", a: 4}, "deep equal should work on regular Object");
|
||||
deepEqual(/a/gim, /a/gim, "deep equal should work on RegExp");
|
||||
deepEqual(
|
||||
{ a: 4, b: "1" },
|
||||
{ b: "1", a: 4 },
|
||||
"deep equal should work on regular Object"
|
||||
);
|
||||
deepEqual(a1, a2, "deep equal should work on Array with Object properties");
|
||||
|
||||
// Test robustness of reporting:
|
||||
equal(new ns.Assert.AssertionError({
|
||||
actual: {
|
||||
toJSON() {
|
||||
throw new Error("bam!");
|
||||
equal(
|
||||
new ns.Assert.AssertionError({
|
||||
actual: {
|
||||
toJSON() {
|
||||
throw new Error("bam!");
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: "foo",
|
||||
operator: "=",
|
||||
}).message, "[object Object] = \"foo\"");
|
||||
expected: "foo",
|
||||
operator: "=",
|
||||
}).message,
|
||||
'[object Object] = "foo"'
|
||||
);
|
||||
|
||||
let message;
|
||||
assert.greater(3, 2);
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const {MockRegistrar} = ChromeUtils.import("resource://testing-common/MockRegistrar.jsm");
|
||||
const { MockRegistrar } = ChromeUtils.import(
|
||||
"resource://testing-common/MockRegistrar.jsm"
|
||||
);
|
||||
|
||||
function platformInfo(injectedValue) {
|
||||
this.platformVersion = injectedValue;
|
||||
|
@ -21,21 +23,43 @@ add_test(function test_register() {
|
|||
};
|
||||
|
||||
MockRegistrar.register("@mozilla.org/xre/app-info;1", localPlatformInfo);
|
||||
Assert.equal(Cc["@mozilla.org/xre/app-info;1"].createInstance(Ci.nsIPlatformInfo).platformVersion, "local version");
|
||||
Assert.equal(
|
||||
Cc["@mozilla.org/xre/app-info;1"].createInstance(Ci.nsIPlatformInfo)
|
||||
.platformVersion,
|
||||
"local version"
|
||||
);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_register_with_arguments() {
|
||||
MockRegistrar.register("@mozilla.org/xre/app-info;1", platformInfo, ["override"]);
|
||||
Assert.equal(Cc["@mozilla.org/xre/app-info;1"].createInstance(Ci.nsIPlatformInfo).platformVersion, "override");
|
||||
MockRegistrar.register("@mozilla.org/xre/app-info;1", platformInfo, [
|
||||
"override",
|
||||
]);
|
||||
Assert.equal(
|
||||
Cc["@mozilla.org/xre/app-info;1"].createInstance(Ci.nsIPlatformInfo)
|
||||
.platformVersion,
|
||||
"override"
|
||||
);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_register_twice() {
|
||||
MockRegistrar.register("@mozilla.org/xre/app-info;1", platformInfo, ["override"]);
|
||||
Assert.equal(Cc["@mozilla.org/xre/app-info;1"].createInstance(Ci.nsIPlatformInfo).platformVersion, "override");
|
||||
MockRegistrar.register("@mozilla.org/xre/app-info;1", platformInfo, [
|
||||
"override",
|
||||
]);
|
||||
Assert.equal(
|
||||
Cc["@mozilla.org/xre/app-info;1"].createInstance(Ci.nsIPlatformInfo)
|
||||
.platformVersion,
|
||||
"override"
|
||||
);
|
||||
|
||||
MockRegistrar.register("@mozilla.org/xre/app-info;1", platformInfo, ["override again"]);
|
||||
Assert.equal(Cc["@mozilla.org/xre/app-info;1"].createInstance(Ci.nsIPlatformInfo).platformVersion, "override again");
|
||||
MockRegistrar.register("@mozilla.org/xre/app-info;1", platformInfo, [
|
||||
"override again",
|
||||
]);
|
||||
Assert.equal(
|
||||
Cc["@mozilla.org/xre/app-info;1"].createInstance(Ci.nsIPlatformInfo)
|
||||
.platformVersion,
|
||||
"override again"
|
||||
);
|
||||
run_next_test();
|
||||
});
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function run_test() {
|
||||
const {StructuredLogger} = ChromeUtils.import("resource://testing-common/StructuredLog.jsm");
|
||||
const { StructuredLogger } = ChromeUtils.import(
|
||||
"resource://testing-common/StructuredLog.jsm"
|
||||
);
|
||||
|
||||
let testBuffer = [];
|
||||
|
||||
|
@ -37,13 +39,12 @@ function run_test() {
|
|||
level: "INFO",
|
||||
});
|
||||
|
||||
logger.info("Test message",
|
||||
{foo: "bar"});
|
||||
logger.info("Test message", { foo: "bar" });
|
||||
assertLastMsg({
|
||||
action: "log",
|
||||
message: "Test message",
|
||||
level: "INFO",
|
||||
extra: {foo: "bar"},
|
||||
extra: { foo: "bar" },
|
||||
});
|
||||
|
||||
// Test end / start actions
|
||||
|
@ -110,8 +111,14 @@ function run_test() {
|
|||
expected: "PASS",
|
||||
});
|
||||
|
||||
logger.testStatus("aTest", "bar", "FAIL", "PASS", null,
|
||||
"Many\nlines\nof\nstack\n");
|
||||
logger.testStatus(
|
||||
"aTest",
|
||||
"bar",
|
||||
"FAIL",
|
||||
"PASS",
|
||||
null,
|
||||
"Many\nlines\nof\nstack\n"
|
||||
);
|
||||
assertLastMsg({
|
||||
action: "test_status",
|
||||
test: "aTest",
|
||||
|
|
|
@ -3,169 +3,164 @@
|
|||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function toArray(iter) {
|
||||
if (iter === null) {
|
||||
return null;
|
||||
}
|
||||
return Array.prototype.slice.call(iter);
|
||||
if (iter === null) {
|
||||
return null;
|
||||
}
|
||||
return Array.prototype.slice.call(iter);
|
||||
}
|
||||
|
||||
function find(selector, elem) {
|
||||
if (!elem) {
|
||||
elem = document;
|
||||
}
|
||||
return elem.querySelector(selector);
|
||||
if (!elem) {
|
||||
elem = document;
|
||||
}
|
||||
return elem.querySelector(selector);
|
||||
}
|
||||
|
||||
function find_all(selector, elem) {
|
||||
if (!elem) {
|
||||
elem = document;
|
||||
}
|
||||
return toArray(elem.querySelectorAll(selector));
|
||||
if (!elem) {
|
||||
elem = document;
|
||||
}
|
||||
return toArray(elem.querySelectorAll(selector));
|
||||
}
|
||||
|
||||
addEventListener("DOMContentLoaded", function() {
|
||||
reset_sort_headers();
|
||||
reset_sort_headers();
|
||||
|
||||
split_debug_onto_two_rows();
|
||||
split_debug_onto_two_rows();
|
||||
|
||||
find_all(".col-links a.screenshot").forEach(function(elem) {
|
||||
elem.addEventListener("click",
|
||||
function(event) {
|
||||
var node = elem;
|
||||
while (node && !node.classList.contains("results-table-row")) {
|
||||
node = node.parentNode;
|
||||
}
|
||||
if (node != null) {
|
||||
if (node.nextSibling &&
|
||||
node.nextSibling.classList.contains("debug")) {
|
||||
var href = find(".screenshot img", node.nextSibling).src;
|
||||
window.open(href);
|
||||
}
|
||||
}
|
||||
event.preventDefault();
|
||||
});
|
||||
find_all(".col-links a.screenshot").forEach(function(elem) {
|
||||
elem.addEventListener("click", function(event) {
|
||||
var node = elem;
|
||||
while (node && !node.classList.contains("results-table-row")) {
|
||||
node = node.parentNode;
|
||||
}
|
||||
if (node != null) {
|
||||
if (node.nextSibling && node.nextSibling.classList.contains("debug")) {
|
||||
var href = find(".screenshot img", node.nextSibling).src;
|
||||
window.open(href);
|
||||
}
|
||||
}
|
||||
event.preventDefault();
|
||||
});
|
||||
});
|
||||
|
||||
find_all(".screenshot a").forEach(function(elem) {
|
||||
elem.addEventListener("click",
|
||||
function(event) {
|
||||
window.open(find("img", elem).getAttribute("src"));
|
||||
event.preventDefault();
|
||||
});
|
||||
find_all(".screenshot a").forEach(function(elem) {
|
||||
elem.addEventListener("click", function(event) {
|
||||
window.open(find("img", elem).getAttribute("src"));
|
||||
event.preventDefault();
|
||||
});
|
||||
});
|
||||
|
||||
find_all(".sortable").forEach(function(elem) {
|
||||
elem.addEventListener("click",
|
||||
function(event) {
|
||||
toggle_sort_states(elem);
|
||||
var colIndex = toArray(elem.parentNode.childNodes).indexOf(elem);
|
||||
var key = elem.classList.contains("numeric") ? key_num : key_alpha;
|
||||
sort_table(elem, key(colIndex));
|
||||
});
|
||||
find_all(".sortable").forEach(function(elem) {
|
||||
elem.addEventListener("click", function(event) {
|
||||
toggle_sort_states(elem);
|
||||
var colIndex = toArray(elem.parentNode.childNodes).indexOf(elem);
|
||||
var key = elem.classList.contains("numeric") ? key_num : key_alpha;
|
||||
sort_table(elem, key(colIndex));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function sort_table(clicked, key_func) {
|
||||
one_row_for_data();
|
||||
var rows = find_all(".results-table-row");
|
||||
var reversed = !clicked.classList.contains("asc");
|
||||
one_row_for_data();
|
||||
var rows = find_all(".results-table-row");
|
||||
var reversed = !clicked.classList.contains("asc");
|
||||
|
||||
var sorted_rows = sort(rows, key_func, reversed);
|
||||
var sorted_rows = sort(rows, key_func, reversed);
|
||||
|
||||
var parent = document.getElementById("results-table-body");
|
||||
sorted_rows.forEach(function(elem) {
|
||||
parent.appendChild(elem);
|
||||
});
|
||||
var parent = document.getElementById("results-table-body");
|
||||
sorted_rows.forEach(function(elem) {
|
||||
parent.appendChild(elem);
|
||||
});
|
||||
|
||||
split_debug_onto_two_rows();
|
||||
split_debug_onto_two_rows();
|
||||
}
|
||||
|
||||
function sort(items, key_func, reversed) {
|
||||
var sort_array = items.map(function(item, i) {
|
||||
return [key_func(item), i];
|
||||
});
|
||||
var multiplier = reversed ? -1 : 1;
|
||||
var sort_array = items.map(function(item, i) {
|
||||
return [key_func(item), i];
|
||||
});
|
||||
var multiplier = reversed ? -1 : 1;
|
||||
|
||||
sort_array.sort(function(a, b) {
|
||||
var key_a = a[0];
|
||||
var key_b = b[0];
|
||||
return multiplier * (key_a >= key_b ? 1 : -1);
|
||||
});
|
||||
sort_array.sort(function(a, b) {
|
||||
var key_a = a[0];
|
||||
var key_b = b[0];
|
||||
return multiplier * (key_a >= key_b ? 1 : -1);
|
||||
});
|
||||
|
||||
return sort_array.map(function(item) {
|
||||
var index = item[1];
|
||||
return items[index];
|
||||
});
|
||||
return sort_array.map(function(item) {
|
||||
var index = item[1];
|
||||
return items[index];
|
||||
});
|
||||
}
|
||||
|
||||
function key_alpha(col_index) {
|
||||
return function(elem) {
|
||||
return elem.childNodes[col_index].firstChild.data.toLowerCase();
|
||||
};
|
||||
return function(elem) {
|
||||
return elem.childNodes[col_index].firstChild.data.toLowerCase();
|
||||
};
|
||||
}
|
||||
|
||||
function key_num(col_index) {
|
||||
return function(elem) {
|
||||
return parseFloat(elem.childNodes[col_index].firstChild.data);
|
||||
};
|
||||
return function(elem) {
|
||||
return parseFloat(elem.childNodes[col_index].firstChild.data);
|
||||
};
|
||||
}
|
||||
|
||||
function reset_sort_headers() {
|
||||
find_all(".sort-icon").forEach(function(elem) {
|
||||
elem.remove();
|
||||
});
|
||||
find_all(".sortable").forEach(function(elem) {
|
||||
var icon = document.createElement("div");
|
||||
icon.className = "sort-icon";
|
||||
icon.textContent = "vvv";
|
||||
elem.insertBefore(icon, elem.firstChild);
|
||||
elem.classList.remove("desc", "active");
|
||||
elem.classList.add("asc", "inactive");
|
||||
});
|
||||
find_all(".sort-icon").forEach(function(elem) {
|
||||
elem.remove();
|
||||
});
|
||||
find_all(".sortable").forEach(function(elem) {
|
||||
var icon = document.createElement("div");
|
||||
icon.className = "sort-icon";
|
||||
icon.textContent = "vvv";
|
||||
elem.insertBefore(icon, elem.firstChild);
|
||||
elem.classList.remove("desc", "active");
|
||||
elem.classList.add("asc", "inactive");
|
||||
});
|
||||
}
|
||||
|
||||
function toggle_sort_states(elem) {
|
||||
// if active, toggle between asc and desc
|
||||
if (elem.classList.contains("active")) {
|
||||
elem.classList.toggle("asc");
|
||||
elem.classList.toggle("desc");
|
||||
}
|
||||
// if active, toggle between asc and desc
|
||||
if (elem.classList.contains("active")) {
|
||||
elem.classList.toggle("asc");
|
||||
elem.classList.toggle("desc");
|
||||
}
|
||||
|
||||
// if inactive, reset all other functions and add ascending active
|
||||
if (elem.classList.contains("inactive")) {
|
||||
reset_sort_headers();
|
||||
elem.classList.remove("inactive");
|
||||
elem.classList.add("active");
|
||||
}
|
||||
// if inactive, reset all other functions and add ascending active
|
||||
if (elem.classList.contains("inactive")) {
|
||||
reset_sort_headers();
|
||||
elem.classList.remove("inactive");
|
||||
elem.classList.add("active");
|
||||
}
|
||||
}
|
||||
|
||||
function split_debug_onto_two_rows() {
|
||||
find_all("tr.results-table-row").forEach(function(elem) {
|
||||
var new_row = document.createElement("tr");
|
||||
new_row.className = "debug";
|
||||
elem.parentNode.insertBefore(new_row, elem.nextSibling);
|
||||
find_all(".debug", elem).forEach(function(td_elem) {
|
||||
if (find(".log", td_elem)) {
|
||||
new_row.appendChild(td_elem);
|
||||
td_elem.colSpan = 5;
|
||||
} else {
|
||||
td_elem.remove();
|
||||
}
|
||||
});
|
||||
find_all("tr.results-table-row").forEach(function(elem) {
|
||||
var new_row = document.createElement("tr");
|
||||
new_row.className = "debug";
|
||||
elem.parentNode.insertBefore(new_row, elem.nextSibling);
|
||||
find_all(".debug", elem).forEach(function(td_elem) {
|
||||
if (find(".log", td_elem)) {
|
||||
new_row.appendChild(td_elem);
|
||||
td_elem.colSpan = 5;
|
||||
} else {
|
||||
td_elem.remove();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function one_row_for_data() {
|
||||
find_all("tr.results-table-row").forEach(function(elem) {
|
||||
if (elem.nextSibling.classList.contains("debug")) {
|
||||
toArray(elem.nextSibling.childNodes).forEach(
|
||||
function(td_elem) {
|
||||
elem.appendChild(td_elem);
|
||||
});
|
||||
} else {
|
||||
var new_td = document.createElement("td");
|
||||
new_td.className = "debug";
|
||||
elem.appendChild(new_td);
|
||||
}
|
||||
});
|
||||
find_all("tr.results-table-row").forEach(function(elem) {
|
||||
if (elem.nextSibling.classList.contains("debug")) {
|
||||
toArray(elem.nextSibling.childNodes).forEach(function(td_elem) {
|
||||
elem.appendChild(td_elem);
|
||||
});
|
||||
} else {
|
||||
var new_td = document.createElement("td");
|
||||
new_td.className = "debug";
|
||||
elem.appendChild(new_td);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -17,7 +17,9 @@ function receiveMessage(event) {
|
|||
function sendResult(_type, _value) {
|
||||
// send result back to background runner script
|
||||
raptorLog(`sending result back to runner: ${_type} ${_value}`);
|
||||
chrome.runtime.sendMessage({"type": _type, "value": _value}, function(response) {
|
||||
chrome.runtime.sendMessage({ type: _type, value: _value }, function(
|
||||
response
|
||||
) {
|
||||
raptorLog(response.text);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ function raptorContentHandler() {
|
|||
sendPageloadReady();
|
||||
|
||||
// retrieve test settings from local ext storage
|
||||
if (typeof(browser) !== "undefined") {
|
||||
if (typeof browser !== "undefined") {
|
||||
// firefox, returns promise
|
||||
browser.storage.local.get("settings").then(function(item) {
|
||||
setup(item.settings);
|
||||
|
@ -73,7 +73,7 @@ function raptorContentHandler() {
|
|||
function sendPageloadReady() {
|
||||
// send message to runnerjs indicating pageloadjs is ready to start getting measures
|
||||
raptorLog("sending pageloadjs-ready message to runnerjs");
|
||||
chrome.runtime.sendMessage({"type": "pageloadjs-ready"}, function(response) {
|
||||
chrome.runtime.sendMessage({ type: "pageloadjs-ready" }, function(response) {
|
||||
if (response !== undefined) {
|
||||
raptorLog(`${response.text}`);
|
||||
}
|
||||
|
@ -155,9 +155,11 @@ function measureHero() {
|
|||
var resultType = `hero:${heroFound}`;
|
||||
raptorLog(`found ${resultType}`);
|
||||
// calculcate result: performance.timing.fetchStart - time when we got hero element
|
||||
perfData.measure(name = resultType,
|
||||
startMark = startMeasure,
|
||||
endMark = heroFound);
|
||||
perfData.measure(
|
||||
(name = resultType),
|
||||
(startMark = startMeasure),
|
||||
(endMark = heroFound)
|
||||
);
|
||||
var perfResult = perfData.getEntriesByName(resultType);
|
||||
var _result = Math.round(perfResult[0].duration);
|
||||
sendResult(resultType, _result);
|
||||
|
@ -167,27 +169,30 @@ function measureHero() {
|
|||
});
|
||||
}
|
||||
// we want the element 100% visible on the viewport
|
||||
var options = {root: null, rootMargin: "0px", threshold: [1]};
|
||||
var options = { root: null, rootMargin: "0px", threshold: [1] };
|
||||
try {
|
||||
obs = new window.IntersectionObserver(callbackHero, options);
|
||||
heroElementsFound.forEach(function(el) {
|
||||
// if hero element is one we want to measure, add it to the observer
|
||||
if (heroesToCapture.indexOf(el.getAttribute("elementtiming")) > -1)
|
||||
if (heroesToCapture.indexOf(el.getAttribute("elementtiming")) > -1) {
|
||||
obs.observe(el);
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
raptorLog(err);
|
||||
}
|
||||
} else {
|
||||
raptorLog("couldn't find hero element");
|
||||
raptorLog("couldn't find hero element");
|
||||
}
|
||||
}
|
||||
|
||||
function measureFNBPaint() {
|
||||
var x = window.performance.timing.timeToNonBlankPaint;
|
||||
|
||||
if (typeof(x) == "undefined") {
|
||||
raptorLog("ERROR: timeToNonBlankPaint is undefined; ensure the pref is enabled");
|
||||
if (typeof x == "undefined") {
|
||||
raptorLog(
|
||||
"ERROR: timeToNonBlankPaint is undefined; ensure the pref is enabled"
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (x > 0) {
|
||||
|
@ -198,10 +203,14 @@ function measureFNBPaint() {
|
|||
} else {
|
||||
gRetryCounter += 1;
|
||||
if (gRetryCounter <= 10) {
|
||||
raptorLog(`fnbpaint is not yet available, retry number ${gRetryCounter}...`);
|
||||
raptorLog(
|
||||
`fnbpaint is not yet available, retry number ${gRetryCounter}...`
|
||||
);
|
||||
window.setTimeout(measureFNBPaint, 100);
|
||||
} else {
|
||||
raptorLog(`unable to get a value for fnbpaint after ${gRetryCounter} retries`);
|
||||
raptorLog(
|
||||
`unable to get a value for fnbpaint after ${gRetryCounter} retries`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -209,8 +218,10 @@ function measureFNBPaint() {
|
|||
function measureDCF() {
|
||||
var x = window.performance.timing.timeToDOMContentFlushed;
|
||||
|
||||
if (typeof(x) == "undefined") {
|
||||
raptorLog("ERROR: domContentFlushed is undefined; ensure the pref is enabled");
|
||||
if (typeof x == "undefined") {
|
||||
raptorLog(
|
||||
"ERROR: domContentFlushed is undefined; ensure the pref is enabled"
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (x > 0) {
|
||||
|
@ -221,7 +232,9 @@ function measureDCF() {
|
|||
} else {
|
||||
gRetryCounter += 1;
|
||||
if (gRetryCounter <= 10) {
|
||||
raptorLog(`dcf is not yet available (0), retry number ${gRetryCounter}...`);
|
||||
raptorLog(
|
||||
`dcf is not yet available (0), retry number ${gRetryCounter}...`
|
||||
);
|
||||
window.setTimeout(measureDCF, 100);
|
||||
} else {
|
||||
raptorLog(`unable to get a value for dcf after ${gRetryCounter} retries`);
|
||||
|
@ -232,8 +245,10 @@ function measureDCF() {
|
|||
function measureTTFI() {
|
||||
var x = window.performance.timing.timeToFirstInteractive;
|
||||
|
||||
if (typeof(x) == "undefined") {
|
||||
raptorLog("ERROR: timeToFirstInteractive is undefined; ensure the pref is enabled");
|
||||
if (typeof x == "undefined") {
|
||||
raptorLog(
|
||||
"ERROR: timeToFirstInteractive is undefined; ensure the pref is enabled"
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (x > 0) {
|
||||
|
@ -250,7 +265,9 @@ function measureTTFI() {
|
|||
// times out at 30 seconds). Some pages will never get 5 seconds
|
||||
// without a busy period!
|
||||
if (gRetryCounter <= 25 * (1000 / 200)) {
|
||||
raptorLog(`TTFI is not yet available (0), retry number ${gRetryCounter}...`);
|
||||
raptorLog(
|
||||
`TTFI is not yet available (0), retry number ${gRetryCounter}...`
|
||||
);
|
||||
window.setTimeout(measureTTFI, 200);
|
||||
} else {
|
||||
// unable to get a value for TTFI - negative value will be filtered out later
|
||||
|
@ -267,13 +284,16 @@ function measureFCP() {
|
|||
|
||||
// Firefox implementation of FCP is not yet spec-compliant (see Bug 1519410)
|
||||
result = window.performance.timing.timeToContentfulPaint;
|
||||
if (typeof(result) == "undefined") {
|
||||
if (typeof result == "undefined") {
|
||||
// we're on chromium
|
||||
result = 0;
|
||||
let perfEntries = perfData.getEntriesByType("paint");
|
||||
|
||||
if (perfEntries.length >= 2) {
|
||||
if (perfEntries[1].name == "first-contentful-paint" && perfEntries[1].startTime != undefined) {
|
||||
if (
|
||||
perfEntries[1].name == "first-contentful-paint" &&
|
||||
perfEntries[1].startTime != undefined
|
||||
) {
|
||||
// this value is actually the final measurement / time to get the FCP event in MS
|
||||
result = perfEntries[1].startTime;
|
||||
}
|
||||
|
@ -282,7 +302,7 @@ function measureFCP() {
|
|||
|
||||
if (result > 0) {
|
||||
raptorLog("got time to first-contentful-paint");
|
||||
if (typeof(browser) !== "undefined") {
|
||||
if (typeof browser !== "undefined") {
|
||||
// Firefox returns a timestamp, not the actual measurement in MS; need to calculate result
|
||||
var startTime = perfData.timing.fetchStart;
|
||||
result = result - startTime;
|
||||
|
@ -293,10 +313,14 @@ function measureFCP() {
|
|||
} else {
|
||||
gRetryCounter += 1;
|
||||
if (gRetryCounter <= 10) {
|
||||
raptorLog(`time to first-contentful-paint is not yet available (0), retry number ${gRetryCounter}...`);
|
||||
raptorLog(
|
||||
`time to first-contentful-paint is not yet available (0), retry number ${gRetryCounter}...`
|
||||
);
|
||||
window.setTimeout(measureFCP, 100);
|
||||
} else {
|
||||
raptorLog(`unable to get a value for time-to-fcp after ${gRetryCounter} retries`);
|
||||
raptorLog(
|
||||
`unable to get a value for time-to-fcp after ${gRetryCounter} retries`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -304,7 +328,7 @@ function measureFCP() {
|
|||
function measureLoadTime() {
|
||||
var x = window.performance.timing.loadEventStart;
|
||||
|
||||
if (typeof(x) == "undefined") {
|
||||
if (typeof x == "undefined") {
|
||||
raptorLog("ERROR: loadEventStart is undefined");
|
||||
return;
|
||||
}
|
||||
|
@ -316,10 +340,14 @@ function measureLoadTime() {
|
|||
} else {
|
||||
gRetryCounter += 1;
|
||||
if (gRetryCounter <= 40 * (1000 / 200)) {
|
||||
raptorLog(`loadEventStart is not yet available (0), retry number ${gRetryCounter}...`);
|
||||
raptorLog(
|
||||
`loadEventStart is not yet available (0), retry number ${gRetryCounter}...`
|
||||
);
|
||||
window.setTimeout(measureLoadTime, 100);
|
||||
} else {
|
||||
raptorLog(`unable to get a value for loadEventStart after ${gRetryCounter} retries`);
|
||||
raptorLog(
|
||||
`unable to get a value for loadEventStart after ${gRetryCounter} retries`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -327,7 +355,9 @@ function measureLoadTime() {
|
|||
function sendResult(_type, _value) {
|
||||
// send result back to background runner script
|
||||
raptorLog(`sending result back to runner: ${_type} ${_value}`);
|
||||
chrome.runtime.sendMessage({"type": _type, "value": _value}, function(response) {
|
||||
chrome.runtime.sendMessage({ type: _type, value: _value }, function(
|
||||
response
|
||||
) {
|
||||
if (response !== undefined) {
|
||||
raptorLog(response.text);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
/* 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/. */
|
||||
|
@ -73,16 +72,16 @@ var debugMode = 0;
|
|||
var screenCapture = false;
|
||||
|
||||
var results = {
|
||||
"name": "",
|
||||
"page": "",
|
||||
"type": "",
|
||||
"browser_cycle": 0,
|
||||
"expected_browser_cycles": 0,
|
||||
"cold": false,
|
||||
"lower_is_better": true,
|
||||
"alert_change_type": "relative",
|
||||
"alert_threshold": 2.0,
|
||||
"measurements": {},
|
||||
name: "",
|
||||
page: "",
|
||||
type: "",
|
||||
browser_cycle: 0,
|
||||
expected_browser_cycles: 0,
|
||||
cold: false,
|
||||
lower_is_better: true,
|
||||
alert_change_type: "relative",
|
||||
alert_threshold: 2.0,
|
||||
measurements: {},
|
||||
};
|
||||
|
||||
function getTestSettings() {
|
||||
|
@ -127,7 +126,8 @@ function getTestSettings() {
|
|||
results.type = testType;
|
||||
results.unit = settings.unit;
|
||||
results.subtest_unit = settings.subtest_unit;
|
||||
results.subtest_lower_is_better = settings.subtest_lower_is_better === true;
|
||||
results.subtest_lower_is_better =
|
||||
settings.subtest_lower_is_better === true;
|
||||
|
||||
if (settings.gecko_profile === true) {
|
||||
results.extra_options = ["gecko_profile"];
|
||||
|
@ -182,16 +182,18 @@ function getTestSettings() {
|
|||
}
|
||||
|
||||
// write options to storage that our content script needs to know
|
||||
if (["firefox", "geckoview", "refbrow", "fenix"].includes(browserName)) {
|
||||
if (
|
||||
["firefox", "geckoview", "refbrow", "fenix"].includes(browserName)
|
||||
) {
|
||||
ext.storage.local.clear().then(function() {
|
||||
ext.storage.local.set({settings}).then(function() {
|
||||
ext.storage.local.set({ settings }).then(function() {
|
||||
raptorLog("wrote settings to ext local storage");
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
ext.storage.local.clear(function() {
|
||||
ext.storage.local.set({settings}, function() {
|
||||
ext.storage.local.set({ settings }, function() {
|
||||
raptorLog("wrote settings to ext local storage");
|
||||
resolve();
|
||||
});
|
||||
|
@ -239,7 +241,7 @@ function testTabCreated(tab) {
|
|||
testTabID = tab.id;
|
||||
postToControlServer("status", `opened new empty tab: ${testTabID}`);
|
||||
// update raptor browser toolbar icon text, for a visual indicator when debugging
|
||||
ext.browserAction.setTitle({title: "Raptor RUNNING"});
|
||||
ext.browserAction.setTitle({ title: "Raptor RUNNING" });
|
||||
}
|
||||
|
||||
function testTabRemoved(tab) {
|
||||
|
@ -282,12 +284,14 @@ async function waitForResult() {
|
|||
break;
|
||||
|
||||
case TEST_PAGE_LOAD:
|
||||
if (!isHeroPending &&
|
||||
!isFNBPaintPending &&
|
||||
!isFCPPending &&
|
||||
!isDCFPending &&
|
||||
!isTTFIPending &&
|
||||
!isLoadTimePending) {
|
||||
if (
|
||||
!isHeroPending &&
|
||||
!isFNBPaintPending &&
|
||||
!isFCPPending &&
|
||||
!isDCFPending &&
|
||||
!isTTFIPending &&
|
||||
!isLoadTimePending
|
||||
) {
|
||||
raptorLog("no more results pending; resolving checkForResult");
|
||||
resolve();
|
||||
} else {
|
||||
|
@ -336,7 +340,8 @@ async function getScreenCapture() {
|
|||
screenshotUri = await ext.tabs.captureVisibleTab();
|
||||
} else {
|
||||
screenshotUri = await new Promise(resolve =>
|
||||
ext.tabs.captureVisibleTab(resolve));
|
||||
ext.tabs.captureVisibleTab(resolve)
|
||||
);
|
||||
}
|
||||
postToControlServer("screenshot", [screenshotUri, testName, pageCycle]);
|
||||
} catch (e) {
|
||||
|
@ -345,7 +350,10 @@ async function getScreenCapture() {
|
|||
}
|
||||
|
||||
async function startGeckoProfiling() {
|
||||
postToControlServer("status", `starting Gecko profiling for threads: ${geckoThreads}`);
|
||||
postToControlServer(
|
||||
"status",
|
||||
`starting Gecko profiling for threads: ${geckoThreads}`
|
||||
);
|
||||
await browser.geckoProfiler.start({
|
||||
bufferSize: geckoEntries,
|
||||
interval: geckoInterval,
|
||||
|
@ -380,7 +388,8 @@ async function nextCycle() {
|
|||
if (isBackgroundTest) {
|
||||
postToControlServer(
|
||||
"end_background",
|
||||
`bringing app to foreground, pausing for ${foregroundDelay / 1000} seconds`
|
||||
`bringing app to foreground, pausing for ${foregroundDelay /
|
||||
1000} seconds`
|
||||
);
|
||||
// wait a bit to be sure the app is in foreground before starting
|
||||
// new test, or finishing test
|
||||
|
@ -412,16 +421,21 @@ async function nextCycle() {
|
|||
isHeroPending = true;
|
||||
pendingHeroes = Array.from(settings.measure.hero);
|
||||
}
|
||||
if (getFNBPaint)
|
||||
if (getFNBPaint) {
|
||||
isFNBPaintPending = true;
|
||||
if (getFCP)
|
||||
}
|
||||
if (getFCP) {
|
||||
isFCPPending = true;
|
||||
if (getDCF)
|
||||
}
|
||||
if (getDCF) {
|
||||
isDCFPending = true;
|
||||
if (getTTFI)
|
||||
}
|
||||
if (getTTFI) {
|
||||
isTTFIPending = true;
|
||||
if (getLoadTime)
|
||||
}
|
||||
if (getLoadTime) {
|
||||
isLoadTimePending = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case TEST_SCENARIO:
|
||||
|
@ -435,34 +449,34 @@ async function nextCycle() {
|
|||
postToControlServer("status", `closing Tab: ${testTabID}`);
|
||||
|
||||
// open new tab
|
||||
ext.tabs.create({url: "about:blank"});
|
||||
ext.tabs.create({ url: "about:blank" });
|
||||
postToControlServer("status", "Open new tab");
|
||||
}
|
||||
setTimeout(function() {
|
||||
postToControlServer("status", `update tab: ${testTabID}`);
|
||||
|
||||
// update the test page - browse to our test URL
|
||||
ext.tabs.update(testTabID, {url: testURL}, testTabUpdated);
|
||||
ext.tabs.update(testTabID, { url: testURL }, testTabUpdated);
|
||||
|
||||
if (testType == TEST_SCENARIO) {
|
||||
scenarioTimer();
|
||||
}
|
||||
}, newTabDelay);
|
||||
}, pageCycleDelay);
|
||||
} else {
|
||||
verifyResults();
|
||||
}
|
||||
}, newTabDelay);
|
||||
}, pageCycleDelay);
|
||||
} else {
|
||||
verifyResults();
|
||||
}
|
||||
}
|
||||
|
||||
async function timeoutAlarmListener() {
|
||||
console.error(`raptor-page-timeout on ${testURL}`);
|
||||
|
||||
var pendingMetrics = {
|
||||
"hero": isHeroPending,
|
||||
hero: isHeroPending,
|
||||
"fnb paint": isFNBPaintPending,
|
||||
"fcp": isFCPPending,
|
||||
"dcf": isDCFPending,
|
||||
"ttfi": isTTFIPending,
|
||||
fcp: isFCPPending,
|
||||
dcf: isDCFPending,
|
||||
ttfi: isTTFIPending,
|
||||
"load time": isLoadTimePending,
|
||||
};
|
||||
|
||||
|
@ -483,13 +497,19 @@ function setTimeoutAlarm(timeoutName, timeoutMS) {
|
|||
var now = Date.now(); // eslint-disable-line mozilla/avoid-Date-timing
|
||||
var timeout_when = now + timeoutMS;
|
||||
ext.alarms.create(timeoutName, { when: timeout_when });
|
||||
raptorLog(`now is ${now}, set raptor alarm ${timeoutName} to expire ` +
|
||||
`at ${timeout_when}`);
|
||||
raptorLog(
|
||||
`now is ${now}, set raptor alarm ${timeoutName} to expire ` +
|
||||
`at ${timeout_when}`
|
||||
);
|
||||
}
|
||||
|
||||
function cancelTimeoutAlarm(timeoutName) {
|
||||
if (browserName === "firefox" || browserName === "geckoview" ||
|
||||
browserName === "refbrow" || browserName === "fenix") {
|
||||
if (
|
||||
browserName === "firefox" ||
|
||||
browserName === "geckoview" ||
|
||||
browserName === "refbrow" ||
|
||||
browserName === "fenix"
|
||||
) {
|
||||
var clearAlarm = ext.alarms.clear(timeoutName);
|
||||
clearAlarm.then(function(onCleared) {
|
||||
if (onCleared) {
|
||||
|
@ -514,17 +534,18 @@ function resultListener(request, sender, sendResponse) {
|
|||
// check if this is a message from pageloaderjs indicating it is ready to start
|
||||
if (request.type == "pageloadjs-ready") {
|
||||
raptorLog("received pageloadjs-ready!");
|
||||
sendResponse({text: "pageloadjs-ready-response"});
|
||||
sendResponse({ text: "pageloadjs-ready-response" });
|
||||
collectResults();
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.type && request.value) {
|
||||
raptorLog(`result: ${request.type} ${request.value}`);
|
||||
sendResponse({text: `confirmed ${request.type}`});
|
||||
sendResponse({ text: `confirmed ${request.type}` });
|
||||
|
||||
if (!(request.type in results.measurements))
|
||||
if (!(request.type in results.measurements)) {
|
||||
results.measurements[request.type] = [];
|
||||
}
|
||||
|
||||
switch (testType) {
|
||||
case TEST_BENCHMARK:
|
||||
|
@ -578,8 +599,10 @@ function verifyResults() {
|
|||
if (count == pageCycles) {
|
||||
raptorLog(`have ${count} results for ${x}, as expected`);
|
||||
} else {
|
||||
raptorLog(`ERROR: expected ${pageCycles} results for ${x} ` +
|
||||
`but only have ${count}`);
|
||||
raptorLog(
|
||||
`ERROR: expected ${pageCycles} results for ${x} ` +
|
||||
`but only have ${count}`
|
||||
);
|
||||
}
|
||||
}
|
||||
postToControlServer("results", results);
|
||||
|
@ -607,7 +630,7 @@ function postToControlServer(msgType, msgData = "") {
|
|||
if (msgType != "screenshot") {
|
||||
raptorLog(`${msgData}`);
|
||||
}
|
||||
var data = { "type": `webext_${msgType}`, "data": msgData};
|
||||
var data = { type: `webext_${msgType}`, data: msgData };
|
||||
client.send(JSON.stringify(data));
|
||||
}
|
||||
if (msgType == "results") {
|
||||
|
@ -682,16 +705,22 @@ function raptorRunner() {
|
|||
|
||||
// create new empty tab, which starts the test; we want to
|
||||
// wait some time for the browser to settle before beginning
|
||||
let text = `* pausing ${postStartupDelay / 1000} seconds to let browser settle... *`;
|
||||
let text = `* pausing ${postStartupDelay /
|
||||
1000} seconds to let browser settle... *`;
|
||||
postToControlServer("status", text);
|
||||
|
||||
// on geckoview you can't create a new tab; only using existing tab - set it blank first
|
||||
if (config.browser == "geckoview" || config.browser == "refbrow" ||
|
||||
config.browser == "fenix") {
|
||||
setTimeout(function() { nextCycle(); }, postStartupDelay);
|
||||
if (
|
||||
config.browser == "geckoview" ||
|
||||
config.browser == "refbrow" ||
|
||||
config.browser == "fenix"
|
||||
) {
|
||||
setTimeout(function() {
|
||||
nextCycle();
|
||||
}, postStartupDelay);
|
||||
} else {
|
||||
setTimeout(function() {
|
||||
ext.tabs.create({url: "about:blank"});
|
||||
ext.tabs.create({ url: "about:blank" });
|
||||
nextCycle();
|
||||
}, postStartupDelay);
|
||||
}
|
||||
|
|
|
@ -4,23 +4,34 @@
|
|||
|
||||
/* globals ExtensionAPI */
|
||||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const {FileUtils} = ChromeUtils.import("resource://gre/modules/FileUtils.jsm");
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { FileUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/FileUtils.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "resProto",
|
||||
"@mozilla.org/network/protocol;1?name=resource",
|
||||
"nsISubstitutingProtocolHandler");
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"resProto",
|
||||
"@mozilla.org/network/protocol;1?name=resource",
|
||||
"nsISubstitutingProtocolHandler"
|
||||
);
|
||||
|
||||
this.specialpowers = class extends ExtensionAPI {
|
||||
onStartup() {
|
||||
let uri = Services.io.newURI("content/", null, this.extension.rootURI);
|
||||
resProto.setSubstitutionWithFlags("specialpowers", uri,
|
||||
resProto.ALLOW_CONTENT_ACCESS);
|
||||
resProto.setSubstitutionWithFlags(
|
||||
"specialpowers",
|
||||
uri,
|
||||
resProto.ALLOW_CONTENT_ACCESS
|
||||
);
|
||||
|
||||
// Register special testing modules.
|
||||
Components.manager.QueryInterface(Ci.nsIComponentRegistrar)
|
||||
.autoRegister(FileUtils.getFile("ProfD", ["tests.manifest"]));
|
||||
Components.manager
|
||||
.QueryInterface(Ci.nsIComponentRegistrar)
|
||||
.autoRegister(FileUtils.getFile("ProfD", ["tests.manifest"]));
|
||||
|
||||
ChromeUtils.registerWindowActor("SpecialPowers", {
|
||||
allFrames: true,
|
||||
|
|
|
@ -14,12 +14,15 @@ Cu.forcePermissiveCOWs();
|
|||
|
||||
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
var oldClassID = "";
|
||||
var newClassID = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID();
|
||||
var newClassID = Cc["@mozilla.org/uuid-generator;1"]
|
||||
.getService(Ci.nsIUUIDGenerator)
|
||||
.generateUUID();
|
||||
var newFactory = function(window) {
|
||||
return {
|
||||
createInstance(aOuter, aIID) {
|
||||
if (aOuter)
|
||||
if (aOuter) {
|
||||
throw Cr.NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
return new MockColorPickerInstance(window).QueryInterface(aIID);
|
||||
},
|
||||
lockFactory(aLock) {
|
||||
|
@ -38,8 +41,10 @@ var MockColorPicker = {
|
|||
oldClassID = registrar.contractIDToCID(CONTRACT_ID);
|
||||
} catch (ex) {
|
||||
oldClassID = "";
|
||||
dump("TEST-INFO | can't get colorpicker registered component, " +
|
||||
"assuming there is none");
|
||||
dump(
|
||||
"TEST-INFO | can't get colorpicker registered component, " +
|
||||
"assuming there is none"
|
||||
);
|
||||
}
|
||||
registrar.registerFactory(newClassID, "", CONTRACT_ID, this.factory);
|
||||
}
|
||||
|
@ -95,8 +100,12 @@ MockColorPickerInstance.prototype = {
|
|||
result = MockColorPicker.returnColor;
|
||||
}
|
||||
} catch (ex) {
|
||||
dump("TEST-UNEXPECTED-FAIL | Exception in MockColorPicker.jsm open() " +
|
||||
"method: " + ex + "\n");
|
||||
dump(
|
||||
"TEST-UNEXPECTED-FAIL | Exception in MockColorPicker.jsm open() " +
|
||||
"method: " +
|
||||
ex +
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
if (aColorPickerShownCallback) {
|
||||
aColorPickerShownCallback.done(result);
|
||||
|
|
|
@ -8,9 +8,12 @@ const Cm = Components.manager;
|
|||
|
||||
const CONTRACT_ID = "@mozilla.org/filepicker;1";
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm"
|
||||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
// Allow stuff from this scope to be accessed from non-privileged scopes. This
|
||||
// would crash if used outside of automation.
|
||||
|
@ -18,12 +21,15 @@ Cu.forcePermissiveCOWs();
|
|||
|
||||
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
var oldClassID;
|
||||
var newClassID = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID();
|
||||
var newClassID = Cc["@mozilla.org/uuid-generator;1"]
|
||||
.getService(Ci.nsIUUIDGenerator)
|
||||
.generateUUID();
|
||||
var newFactory = function(window) {
|
||||
return {
|
||||
createInstance(aOuter, aIID) {
|
||||
if (aOuter)
|
||||
if (aOuter) {
|
||||
throw Cr.NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
return new MockFilePickerInstance(window).QueryInterface(aIID);
|
||||
},
|
||||
lockFactory(aLock) {
|
||||
|
@ -101,11 +107,12 @@ var MockFilePicker = {
|
|||
file.append("testfile");
|
||||
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o644);
|
||||
let promise = this.window.File.createFromNsIFile(file)
|
||||
.then(domFile => domFile, () => null)
|
||||
// domFile can be null.
|
||||
.then(domFile => {
|
||||
this.returnData = [this.internalFileData({ nsIFile: file, domFile })];
|
||||
}).then(() => file);
|
||||
.then(domFile => domFile, () => null)
|
||||
// domFile can be null.
|
||||
.then(domFile => {
|
||||
this.returnData = [this.internalFileData({ nsIFile: file, domFile })];
|
||||
})
|
||||
.then(() => file);
|
||||
|
||||
this.pendingPromises = [promise];
|
||||
|
||||
|
@ -115,7 +122,9 @@ var MockFilePicker = {
|
|||
|
||||
useBlobFile() {
|
||||
var blob = new this.window.Blob([]);
|
||||
var file = new this.window.File([blob], "helloworld.txt", { type: "plain/text" });
|
||||
var file = new this.window.File([blob], "helloworld.txt", {
|
||||
type: "plain/text",
|
||||
});
|
||||
this.returnData = [this.internalFileData({ domFile: file })];
|
||||
this.pendingPromises = [];
|
||||
},
|
||||
|
@ -134,10 +143,14 @@ var MockFilePicker = {
|
|||
if (file instanceof this.window.File) {
|
||||
this.returnData.push(this.internalFileData({ domFile: file }));
|
||||
} else {
|
||||
let promise = this.window.File.createFromNsIFile(file, { existenceCheck: false });
|
||||
let promise = this.window.File.createFromNsIFile(file, {
|
||||
existenceCheck: false,
|
||||
});
|
||||
|
||||
promise.then(domFile => {
|
||||
this.returnData.push(this.internalFileData({ nsIFile: file, domFile }));
|
||||
this.returnData.push(
|
||||
this.internalFileData({ nsIFile: file, domFile })
|
||||
);
|
||||
});
|
||||
this.pendingPromises.push(promise);
|
||||
}
|
||||
|
@ -163,12 +176,14 @@ MockFilePickerInstance.prototype = {
|
|||
this.parent = aParent;
|
||||
},
|
||||
appendFilter(aTitle, aFilter) {
|
||||
if (typeof MockFilePicker.appendFilterCallback == "function")
|
||||
if (typeof MockFilePicker.appendFilterCallback == "function") {
|
||||
MockFilePicker.appendFilterCallback(this, aTitle, aFilter);
|
||||
}
|
||||
},
|
||||
appendFilters(aFilterMask) {
|
||||
if (typeof MockFilePicker.appendFiltersCallback == "function")
|
||||
if (typeof MockFilePicker.appendFiltersCallback == "function") {
|
||||
MockFilePicker.appendFiltersCallback(this, aFilterMask);
|
||||
}
|
||||
},
|
||||
defaultString: "",
|
||||
defaultExtension: "",
|
||||
|
@ -201,14 +216,16 @@ MockFilePickerInstance.prototype = {
|
|||
return null;
|
||||
},
|
||||
get fileURL() {
|
||||
if (MockFilePicker.returnData.length >= 1 &&
|
||||
MockFilePicker.returnData[0].nsIFile) {
|
||||
if (
|
||||
MockFilePicker.returnData.length >= 1 &&
|
||||
MockFilePicker.returnData[0].nsIFile
|
||||
) {
|
||||
return Services.io.newFileURI(MockFilePicker.returnData[0].nsIFile);
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
* getFiles(asDOM) {
|
||||
*getFiles(asDOM) {
|
||||
for (let d of MockFilePicker.returnData) {
|
||||
if (asDOM) {
|
||||
yield d.domFile || d.domDirectory;
|
||||
|
@ -229,54 +246,64 @@ MockFilePickerInstance.prototype = {
|
|||
MockFilePicker.showing = true;
|
||||
this.window.setTimeout(() => {
|
||||
// Maybe all the pending promises are already resolved, but we want to be sure.
|
||||
Promise.all(MockFilePicker.pendingPromises).then(() => {
|
||||
return Ci.nsIFilePicker.returnOK;
|
||||
}, () => {
|
||||
return Ci.nsIFilePicker.returnCancel;
|
||||
}).then(result => {
|
||||
// Nothing else has to be done.
|
||||
MockFilePicker.pendingPromises = [];
|
||||
|
||||
if (result == Ci.nsIFilePicker.returnCancel) {
|
||||
return result;
|
||||
}
|
||||
|
||||
MockFilePicker.displayDirectory = this.displayDirectory;
|
||||
MockFilePicker.displaySpecialDirectory = this.displaySpecialDirectory;
|
||||
MockFilePicker.shown = true;
|
||||
if (typeof MockFilePicker.showCallback == "function") {
|
||||
try {
|
||||
var returnValue = MockFilePicker.showCallback(this);
|
||||
if (typeof returnValue != "undefined") {
|
||||
return returnValue;
|
||||
}
|
||||
} catch (ex) {
|
||||
Promise.all(MockFilePicker.pendingPromises)
|
||||
.then(
|
||||
() => {
|
||||
return Ci.nsIFilePicker.returnOK;
|
||||
},
|
||||
() => {
|
||||
return Ci.nsIFilePicker.returnCancel;
|
||||
}
|
||||
}
|
||||
)
|
||||
.then(result => {
|
||||
// Nothing else has to be done.
|
||||
MockFilePicker.pendingPromises = [];
|
||||
|
||||
return MockFilePicker.returnValue;
|
||||
}).then(result => {
|
||||
// Some additional result file can be set by the callback. Let's
|
||||
// resolve the pending promises again.
|
||||
return Promise.all(MockFilePicker.pendingPromises).then(() => {
|
||||
return result;
|
||||
}, () => {
|
||||
return Ci.nsIFilePicker.returnCancel;
|
||||
if (result == Ci.nsIFilePicker.returnCancel) {
|
||||
return result;
|
||||
}
|
||||
|
||||
MockFilePicker.displayDirectory = this.displayDirectory;
|
||||
MockFilePicker.displaySpecialDirectory = this.displaySpecialDirectory;
|
||||
MockFilePicker.shown = true;
|
||||
if (typeof MockFilePicker.showCallback == "function") {
|
||||
try {
|
||||
var returnValue = MockFilePicker.showCallback(this);
|
||||
if (typeof returnValue != "undefined") {
|
||||
return returnValue;
|
||||
}
|
||||
} catch (ex) {
|
||||
return Ci.nsIFilePicker.returnCancel;
|
||||
}
|
||||
}
|
||||
|
||||
return MockFilePicker.returnValue;
|
||||
})
|
||||
.then(result => {
|
||||
// Some additional result file can be set by the callback. Let's
|
||||
// resolve the pending promises again.
|
||||
return Promise.all(MockFilePicker.pendingPromises).then(
|
||||
() => {
|
||||
return result;
|
||||
},
|
||||
() => {
|
||||
return Ci.nsIFilePicker.returnCancel;
|
||||
}
|
||||
);
|
||||
})
|
||||
.then(result => {
|
||||
MockFilePicker.pendingPromises = [];
|
||||
|
||||
if (aFilePickerShownCallback) {
|
||||
aFilePickerShownCallback.done(result);
|
||||
}
|
||||
|
||||
if (typeof MockFilePicker.afterOpenCallback == "function") {
|
||||
this.window.setTimeout(() => {
|
||||
MockFilePicker.afterOpenCallback(this);
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
}).then(result => {
|
||||
MockFilePicker.pendingPromises = [];
|
||||
|
||||
if (aFilePickerShownCallback) {
|
||||
aFilePickerShownCallback.done(result);
|
||||
}
|
||||
|
||||
if (typeof MockFilePicker.afterOpenCallback == "function") {
|
||||
this.window.setTimeout(() => {
|
||||
MockFilePicker.afterOpenCallback(this);
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
@ -8,15 +8,18 @@ const Cm = Components.manager;
|
|||
|
||||
const CONTRACT_ID = "@mozilla.org/content-permission/prompt;1";
|
||||
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
var oldClassID, oldFactory;
|
||||
var newClassID = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID();
|
||||
var newClassID = Cc["@mozilla.org/uuid-generator;1"]
|
||||
.getService(Ci.nsIUUIDGenerator)
|
||||
.generateUUID();
|
||||
var newFactory = {
|
||||
createInstance(aOuter, aIID) {
|
||||
if (aOuter)
|
||||
if (aOuter) {
|
||||
throw Cr.NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
return new MockPermissionPromptInstance().QueryInterface(aIID);
|
||||
},
|
||||
lockFactory(aLock) {
|
||||
|
@ -35,8 +38,10 @@ var MockPermissionPrompt = {
|
|||
} catch (ex) {
|
||||
oldClassID = "";
|
||||
oldFactory = null;
|
||||
dump("TEST-INFO | can't get permission prompt registered component, " +
|
||||
"assuming there is none");
|
||||
dump(
|
||||
"TEST-INFO | can't get permission prompt registered component, " +
|
||||
"assuming there is none"
|
||||
);
|
||||
}
|
||||
if (oldFactory) {
|
||||
registrar.unregisterFactory(oldClassID, oldFactory);
|
||||
|
@ -45,8 +50,7 @@ var MockPermissionPrompt = {
|
|||
}
|
||||
},
|
||||
|
||||
reset() {
|
||||
},
|
||||
reset() {},
|
||||
|
||||
cleanup() {
|
||||
this.reset();
|
||||
|
@ -57,7 +61,7 @@ var MockPermissionPrompt = {
|
|||
},
|
||||
};
|
||||
|
||||
function MockPermissionPromptInstance() { }
|
||||
function MockPermissionPromptInstance() {}
|
||||
MockPermissionPromptInstance.prototype = {
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIContentPermissionPrompt]),
|
||||
|
||||
|
@ -67,8 +71,12 @@ MockPermissionPromptInstance.prototype = {
|
|||
let perms = request.types.QueryInterface(Ci.nsIArray);
|
||||
for (let idx = 0; idx < perms.length; idx++) {
|
||||
let perm = perms.queryElementAt(idx, Ci.nsIContentPermissionType);
|
||||
if (Services.perms.testExactPermissionFromPrincipal(
|
||||
request.principal, perm.type) != Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
if (
|
||||
Services.perms.testExactPermissionFromPrincipal(
|
||||
request.principal,
|
||||
perm.type
|
||||
) != Ci.nsIPermissionManager.ALLOW_ACTION
|
||||
) {
|
||||
request.cancel();
|
||||
return;
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -6,8 +6,10 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["SpecialPowersAPIParent", "SpecialPowersError"];
|
||||
|
||||
var {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
var { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
ExtensionData: "resource://gre/modules/Extension.jsm",
|
||||
|
@ -27,28 +29,39 @@ function parseKeyValuePairs(text) {
|
|||
var lines = text.split("\n");
|
||||
var data = {};
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (lines[i] == "")
|
||||
if (lines[i] == "") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// can't just .split() because the value might contain = characters
|
||||
let eq = lines[i].indexOf("=");
|
||||
if (eq != -1) {
|
||||
let [key, value] = [lines[i].substring(0, eq),
|
||||
lines[i].substring(eq + 1)];
|
||||
if (key && value)
|
||||
let [key, value] = [
|
||||
lines[i].substring(0, eq),
|
||||
lines[i].substring(eq + 1),
|
||||
];
|
||||
if (key && value) {
|
||||
data[key] = value.replace(/\\n/g, "\n").replace(/\\\\/g, "\\");
|
||||
}
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function parseKeyValuePairsFromFile(file) {
|
||||
var fstream = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Ci.nsIFileInputStream);
|
||||
var fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(
|
||||
Ci.nsIFileInputStream
|
||||
);
|
||||
fstream.init(file, -1, 0, 0);
|
||||
var is = Cc["@mozilla.org/intl/converter-input-stream;1"].
|
||||
createInstance(Ci.nsIConverterInputStream);
|
||||
is.init(fstream, "UTF-8", 1024, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
|
||||
var is = Cc["@mozilla.org/intl/converter-input-stream;1"].createInstance(
|
||||
Ci.nsIConverterInputStream
|
||||
);
|
||||
is.init(
|
||||
fstream,
|
||||
"UTF-8",
|
||||
1024,
|
||||
Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER
|
||||
);
|
||||
var str = {};
|
||||
var contents = "";
|
||||
while (is.readString(4096, str) != 0) {
|
||||
|
@ -60,8 +73,7 @@ function parseKeyValuePairsFromFile(file) {
|
|||
}
|
||||
|
||||
function getTestPlugin(pluginName) {
|
||||
var ph = Cc["@mozilla.org/plugin/host;1"]
|
||||
.getService(Ci.nsIPluginHost);
|
||||
var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
|
||||
var tags = ph.getPluginTags();
|
||||
var name = pluginName || "Test Plug-in";
|
||||
for (var tag of tags) {
|
||||
|
@ -78,9 +90,9 @@ const PREF_TYPES = {
|
|||
[Ci.nsIPrefBranch.PREF_INT]: "INT",
|
||||
[Ci.nsIPrefBranch.PREF_BOOL]: "BOOL",
|
||||
[Ci.nsIPrefBranch.PREF_STRING]: "CHAR",
|
||||
"number": "INT",
|
||||
"boolean": "BOOL",
|
||||
"string": "CHAR",
|
||||
number: "INT",
|
||||
boolean: "BOOL",
|
||||
string: "CHAR",
|
||||
};
|
||||
|
||||
// We share a single preference environment stack between all
|
||||
|
@ -90,7 +102,9 @@ let inPrefEnvOp = false;
|
|||
|
||||
function doPrefEnvOp(fn) {
|
||||
if (inPrefEnvOp) {
|
||||
throw new Error("Reentrant preference environment operations not supported");
|
||||
throw new Error(
|
||||
"Reentrant preference environment operations not supported"
|
||||
);
|
||||
}
|
||||
inPrefEnvOp = true;
|
||||
try {
|
||||
|
@ -122,8 +136,8 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||
id = null;
|
||||
}
|
||||
if (id) {
|
||||
message.dumpIDs.push({id, extension: "dmp"});
|
||||
message.dumpIDs.push({id, extension: "extra"});
|
||||
message.dumpIDs.push({ id, extension: "dmp" });
|
||||
message.dumpIDs.push({ id, extension: "extra" });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,13 +152,17 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||
|
||||
let pluginID = aSubject.getPropertyAsAString("pluginDumpID");
|
||||
let extra = this._getExtraData(pluginID);
|
||||
if (extra && ("additional_minidumps" in extra)) {
|
||||
if (extra && "additional_minidumps" in extra) {
|
||||
let dumpNames = extra.additional_minidumps.split(",");
|
||||
for (let name of dumpNames) {
|
||||
message.dumpIDs.push({id: pluginID + "-" + name, extension: "dmp"});
|
||||
message.dumpIDs.push({
|
||||
id: pluginID + "-" + name,
|
||||
extension: "dmp",
|
||||
});
|
||||
}
|
||||
}
|
||||
} else { // ipc:content-shutdown
|
||||
} else {
|
||||
// ipc:content-shutdown
|
||||
if (!aSubject.hasKey("abnormal")) {
|
||||
return; // This is a normal shutdown, ignore it
|
||||
}
|
||||
|
@ -245,7 +263,9 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||
|
||||
let observers = [];
|
||||
|
||||
for (let {value: contractID} of Services.catMan.enumerateCategory(topic)) {
|
||||
for (let { value: contractID } of Services.catMan.enumerateCategory(
|
||||
topic
|
||||
)) {
|
||||
let factoryFunction;
|
||||
if (contractID.substring(0, serviceMarker.length) == serviceMarker) {
|
||||
contractID = contractID.substring(serviceMarker.length);
|
||||
|
@ -260,13 +280,12 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||
let observer = handler.QueryInterface(Ci.nsIObserver);
|
||||
observers.push(observer);
|
||||
}
|
||||
} catch (e) { }
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// Next enumerate the registered observers.
|
||||
for (let observer of Services.obs.enumerateObservers(topic)) {
|
||||
if (observer instanceof Ci.nsIObserver &&
|
||||
!observers.includes(observer)) {
|
||||
if (observer instanceof Ci.nsIObserver && !observers.includes(observer)) {
|
||||
observers.push(observer);
|
||||
}
|
||||
}
|
||||
|
@ -274,7 +293,7 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||
observers.forEach(function(observer) {
|
||||
try {
|
||||
observer.observe(subject, topic, data);
|
||||
} catch (e) { }
|
||||
} catch (e) {}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -335,11 +354,12 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||
value = pref[1];
|
||||
}
|
||||
|
||||
|
||||
/* If pref is not found or invalid it doesn't exist. */
|
||||
if (type !== "INVALID") {
|
||||
if ((Services.prefs.prefHasUserValue(name) && action == "clear") ||
|
||||
action == "set") {
|
||||
if (
|
||||
(Services.prefs.prefHasUserValue(name) && action == "clear") ||
|
||||
action == "set"
|
||||
) {
|
||||
originalValue = this._getPref(name, type);
|
||||
}
|
||||
} else if (action == "set") {
|
||||
|
@ -356,10 +376,10 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||
throw new Error("Unexpected preference type");
|
||||
}
|
||||
|
||||
pendingActions.push({action, type, name, value, iid});
|
||||
pendingActions.push({ action, type, name, value, iid });
|
||||
|
||||
/* Push original preference value or clear into cleanup array */
|
||||
var cleanupTodo = {type, name, value: originalValue, iid};
|
||||
var cleanupTodo = { type, name, value: originalValue, iid };
|
||||
if (originalValue == null) {
|
||||
cleanupTodo.action = "clear";
|
||||
} else {
|
||||
|
@ -432,7 +452,8 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||
* messageManager callback function
|
||||
* This will get requests from our API in the window and process them in chrome for it
|
||||
**/
|
||||
receiveMessage(aMessage) { // eslint-disable-line complexity
|
||||
receiveMessage(aMessage) {
|
||||
// eslint-disable-line complexity
|
||||
// We explicitly return values in the below code so that this function
|
||||
// doesn't trigger a flurry of warnings about "does not always return
|
||||
// a value".
|
||||
|
@ -452,21 +473,34 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||
let { prefName, prefValue, iid, defaultValue } = aMessage.json;
|
||||
|
||||
if (aMessage.json.op == "get") {
|
||||
if (!prefName || !prefType)
|
||||
throw new SpecialPowersError("Invalid parameters for get in SPPrefService");
|
||||
if (!prefName || !prefType) {
|
||||
throw new SpecialPowersError(
|
||||
"Invalid parameters for get in SPPrefService"
|
||||
);
|
||||
}
|
||||
|
||||
// return null if the pref doesn't exist
|
||||
if (defaultValue === undefined && prefs.getPrefType(prefName) == prefs.PREF_INVALID)
|
||||
if (
|
||||
defaultValue === undefined &&
|
||||
prefs.getPrefType(prefName) == prefs.PREF_INVALID
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
return this._getPref(prefName, prefType, defaultValue, iid);
|
||||
} else if (aMessage.json.op == "set") {
|
||||
if (!prefName || !prefType || prefValue === undefined)
|
||||
throw new SpecialPowersError("Invalid parameters for set in SPPrefService");
|
||||
if (!prefName || !prefType || prefValue === undefined) {
|
||||
throw new SpecialPowersError(
|
||||
"Invalid parameters for set in SPPrefService"
|
||||
);
|
||||
}
|
||||
|
||||
return this._setPref(prefName, prefType, prefValue, iid);
|
||||
} else if (aMessage.json.op == "clear") {
|
||||
if (!prefName)
|
||||
throw new SpecialPowersError("Invalid parameters for clear in SPPrefService");
|
||||
if (!prefName) {
|
||||
throw new SpecialPowersError(
|
||||
"Invalid parameters for clear in SPPrefService"
|
||||
);
|
||||
}
|
||||
|
||||
prefs.clearUserPref(prefName);
|
||||
} else {
|
||||
|
@ -487,17 +521,21 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||
case "delete-crash-dump-files":
|
||||
return this._deleteCrashDumpFiles(aMessage.json.filenames);
|
||||
case "find-crash-dump-files":
|
||||
return this._findCrashDumpFiles(aMessage.json.crashDumpFilesToIgnore);
|
||||
return this._findCrashDumpFiles(
|
||||
aMessage.json.crashDumpFilesToIgnore
|
||||
);
|
||||
case "delete-pending-crash-dump-files":
|
||||
return this._deletePendingCrashDumpFiles();
|
||||
default:
|
||||
throw new SpecialPowersError("Invalid operation for SPProcessCrashService");
|
||||
throw new SpecialPowersError(
|
||||
"Invalid operation for SPProcessCrashService"
|
||||
);
|
||||
}
|
||||
return undefined; // See comment at the beginning of this function.
|
||||
}
|
||||
|
||||
case "SPProcessCrashManagerWait": {
|
||||
let promises = aMessage.json.crashIds.map((crashId) => {
|
||||
let promises = aMessage.json.crashIds.map(crashId => {
|
||||
return Services.crashmanager.ensureCrashIsPresent(crashId);
|
||||
});
|
||||
return Promise.all(promises);
|
||||
|
@ -509,20 +547,33 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||
|
||||
switch (msg.op) {
|
||||
case "add":
|
||||
Services.perms.addFromPrincipal(principal, msg.type, msg.permission, msg.expireType, msg.expireTime);
|
||||
Services.perms.addFromPrincipal(
|
||||
principal,
|
||||
msg.type,
|
||||
msg.permission,
|
||||
msg.expireType,
|
||||
msg.expireTime
|
||||
);
|
||||
break;
|
||||
case "remove":
|
||||
Services.perms.removeFromPrincipal(principal, msg.type);
|
||||
break;
|
||||
case "has":
|
||||
let hasPerm = Services.perms.testPermissionFromPrincipal(principal, msg.type);
|
||||
let hasPerm = Services.perms.testPermissionFromPrincipal(
|
||||
principal,
|
||||
msg.type
|
||||
);
|
||||
return hasPerm == Ci.nsIPermissionManager.ALLOW_ACTION;
|
||||
case "test":
|
||||
let testPerm = Services.perms.testPermissionFromPrincipal(principal, msg.type);
|
||||
let testPerm = Services.perms.testPermissionFromPrincipal(
|
||||
principal,
|
||||
msg.type
|
||||
);
|
||||
return testPerm == msg.value;
|
||||
default:
|
||||
throw new SpecialPowersError(
|
||||
"Invalid operation for SPPermissionManager");
|
||||
"Invalid operation for SPPermissionManager"
|
||||
);
|
||||
}
|
||||
return undefined; // See comment at the beginning of this function.
|
||||
}
|
||||
|
@ -548,7 +599,9 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||
this._registerObservers._add(topic);
|
||||
break;
|
||||
default:
|
||||
throw new SpecialPowersError("Invalid operation for SPObserverervice");
|
||||
throw new SpecialPowersError(
|
||||
"Invalid operation for SPObserverervice"
|
||||
);
|
||||
}
|
||||
return undefined; // See comment at the beginning of this function.
|
||||
}
|
||||
|
@ -561,8 +614,9 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||
if (aMessage.json.url) {
|
||||
scriptName = aMessage.json.url;
|
||||
} else if (aMessage.json.function) {
|
||||
scriptName = aMessage.json.function.name
|
||||
|| "<loadChromeScript anonymous function>";
|
||||
scriptName =
|
||||
aMessage.json.function.name ||
|
||||
"<loadChromeScript anonymous function>";
|
||||
} else {
|
||||
throw new SpecialPowersError("SPLoadChromeScript: Invalid script");
|
||||
}
|
||||
|
@ -575,19 +629,25 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||
data => {
|
||||
this.sendAsyncMessage("Assert", data);
|
||||
},
|
||||
aMessage.data);
|
||||
aMessage.data
|
||||
);
|
||||
|
||||
Object.assign(sb.sandbox, {
|
||||
sendAsyncMessage: (name, message) => {
|
||||
this.sendAsyncMessage("SPChromeScriptMessage",
|
||||
{ id, name, message });
|
||||
this.sendAsyncMessage("SPChromeScriptMessage", {
|
||||
id,
|
||||
name,
|
||||
message,
|
||||
});
|
||||
},
|
||||
addMessageListener: (name, listener) => {
|
||||
this._chromeScriptListeners.push({ id, name, listener });
|
||||
},
|
||||
removeMessageListener: (name, listener) => {
|
||||
let index = this._chromeScriptListeners.findIndex(function(obj) {
|
||||
return obj.id == id && obj.name == name && obj.listener == listener;
|
||||
return (
|
||||
obj.id == id && obj.name == name && obj.listener == listener
|
||||
);
|
||||
});
|
||||
if (index >= 0) {
|
||||
this._chromeScriptListeners.splice(index, 1);
|
||||
|
@ -601,9 +661,15 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||
Cu.evalInSandbox(jsScript, sb.sandbox, "1.8", scriptName, 1);
|
||||
} catch (e) {
|
||||
throw new SpecialPowersError(
|
||||
"Error while executing chrome script '" + scriptName + "':\n" +
|
||||
e + "\n" +
|
||||
e.fileName + ":" + e.lineNumber);
|
||||
"Error while executing chrome script '" +
|
||||
scriptName +
|
||||
"':\n" +
|
||||
e +
|
||||
"\n" +
|
||||
e.fileName +
|
||||
":" +
|
||||
e.lineNumber
|
||||
);
|
||||
}
|
||||
return undefined; // See comment at the beginning of this function.
|
||||
}
|
||||
|
@ -636,8 +702,9 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||
let origin = aMessage.data.origin;
|
||||
let flags = aMessage.data.flags;
|
||||
let uri = Services.io.newURI(origin);
|
||||
let sss = Cc["@mozilla.org/ssservice;1"].
|
||||
getService(Ci.nsISiteSecurityService);
|
||||
let sss = Cc["@mozilla.org/ssservice;1"].getService(
|
||||
Ci.nsISiteSecurityService
|
||||
);
|
||||
sss.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, flags);
|
||||
return undefined;
|
||||
}
|
||||
|
@ -651,14 +718,18 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||
}
|
||||
|
||||
case "SPCheckServiceWorkers": {
|
||||
let swm = Cc["@mozilla.org/serviceworkers/manager;1"]
|
||||
.getService(Ci.nsIServiceWorkerManager);
|
||||
let swm = Cc["@mozilla.org/serviceworkers/manager;1"].getService(
|
||||
Ci.nsIServiceWorkerManager
|
||||
);
|
||||
let regs = swm.getAllRegistrations();
|
||||
|
||||
// XXX This code is shared with specialpowers.js.
|
||||
let workers = new Array(regs.length);
|
||||
for (let i = 0; i < regs.length; ++i) {
|
||||
let { scope, scriptSpec } = regs.queryElementAt(i, Ci.nsIServiceWorkerRegistrationInfo);
|
||||
let { scope, scriptSpec } = regs.queryElementAt(
|
||||
i,
|
||||
Ci.nsIServiceWorkerRegistrationInfo
|
||||
);
|
||||
workers[i] = { scope, scriptSpec };
|
||||
}
|
||||
return { workers };
|
||||
|
@ -670,12 +741,20 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||
let extension = ExtensionTestCommon.generate(ext);
|
||||
|
||||
let resultListener = (...args) => {
|
||||
this.sendAsyncMessage("SPExtensionMessage", {id, type: "testResult", args});
|
||||
this.sendAsyncMessage("SPExtensionMessage", {
|
||||
id,
|
||||
type: "testResult",
|
||||
args,
|
||||
});
|
||||
};
|
||||
|
||||
let messageListener = (...args) => {
|
||||
args.shift();
|
||||
this.sendAsyncMessage("SPExtensionMessage", {id, type: "testMessage", args});
|
||||
this.sendAsyncMessage("SPExtensionMessage", {
|
||||
id,
|
||||
type: "testMessage",
|
||||
args,
|
||||
});
|
||||
};
|
||||
|
||||
// Register pass/fail handlers.
|
||||
|
@ -703,38 +782,48 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||
}
|
||||
// ext is always the "real" Extension object, even when "extension"
|
||||
// is a MockExtension.
|
||||
this.sendAsyncMessage("SPExtensionMessage", {id, type: "extensionSetId", args: [ext.id, ext.uuid]});
|
||||
this.sendAsyncMessage("SPExtensionMessage", {
|
||||
id,
|
||||
type: "extensionSetId",
|
||||
args: [ext.id, ext.uuid],
|
||||
});
|
||||
});
|
||||
|
||||
// Make sure the extension passes the packaging checks when
|
||||
// they're run on a bare archive rather than a running instance,
|
||||
// as the add-on manager runs them.
|
||||
let extensionData = new ExtensionData(extension.rootURI);
|
||||
return extensionData.loadManifest().then(
|
||||
() => {
|
||||
return extensionData.initAllLocales().then(() => {
|
||||
if (extensionData.errors.length) {
|
||||
return Promise.reject("Extension contains packaging errors");
|
||||
return extensionData
|
||||
.loadManifest()
|
||||
.then(
|
||||
() => {
|
||||
return extensionData.initAllLocales().then(() => {
|
||||
if (extensionData.errors.length) {
|
||||
return Promise.reject("Extension contains packaging errors");
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
},
|
||||
() => {
|
||||
// loadManifest() will throw if we're loading an embedded
|
||||
// extension, so don't worry about locale errors in that
|
||||
// case.
|
||||
}
|
||||
)
|
||||
.then(async () => {
|
||||
// browser tests do not call startup in ExtensionXPCShellUtils or MockExtension,
|
||||
// in that case we have an ID here and we need to set the override.
|
||||
if (extension.id) {
|
||||
await ExtensionTestCommon.setIncognitoOverride(extension);
|
||||
}
|
||||
return extension.startup().then(
|
||||
() => {},
|
||||
e => {
|
||||
dump(`Extension startup failed: ${e}\n${e.stack}`);
|
||||
throw e;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
},
|
||||
() => {
|
||||
// loadManifest() will throw if we're loading an embedded
|
||||
// extension, so don't worry about locale errors in that
|
||||
// case.
|
||||
}
|
||||
).then(async () => {
|
||||
// browser tests do not call startup in ExtensionXPCShellUtils or MockExtension,
|
||||
// in that case we have an ID here and we need to set the override.
|
||||
if (extension.id) {
|
||||
await ExtensionTestCommon.setIncognitoOverride(extension);
|
||||
}
|
||||
return extension.startup().then(() => {}, e => {
|
||||
dump(`Extension startup failed: ${e}\n${e.stack}`);
|
||||
throw e;
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
case "SPExtensionMessage": {
|
||||
|
@ -754,20 +843,24 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||
}
|
||||
|
||||
case "Spawn": {
|
||||
let {browsingContext, task, args, caller} = aMessage.data;
|
||||
let { browsingContext, task, args, caller } = aMessage.data;
|
||||
|
||||
let spParent = browsingContext.currentWindowGlobal.getActor("SpecialPowers");
|
||||
let spParent = browsingContext.currentWindowGlobal.getActor(
|
||||
"SpecialPowers"
|
||||
);
|
||||
|
||||
let taskId = nextTaskID++;
|
||||
spParent._taskActors.set(taskId, this);
|
||||
|
||||
return spParent.sendQuery("Spawn", {task, args, caller, taskId}).finally(() => {
|
||||
spParent._taskActors.delete(taskId);
|
||||
});
|
||||
return spParent
|
||||
.sendQuery("Spawn", { task, args, caller, taskId })
|
||||
.finally(() => {
|
||||
spParent._taskActors.delete(taskId);
|
||||
});
|
||||
}
|
||||
|
||||
case "ProxiedAssert": {
|
||||
let {taskId, data} = aMessage.data;
|
||||
let { taskId, data } = aMessage.data;
|
||||
let actor = this._taskActors.get(taskId);
|
||||
|
||||
actor.sendAsyncMessage("Assert", data);
|
||||
|
@ -783,7 +876,9 @@ class SpecialPowersAPIParent extends JSWindowActorParent {
|
|||
}
|
||||
|
||||
default:
|
||||
throw new SpecialPowersError(`Unrecognized Special Powers API: ${aMessage.name}`);
|
||||
throw new SpecialPowersError(
|
||||
`Unrecognized Special Powers API: ${aMessage.name}`
|
||||
);
|
||||
}
|
||||
|
||||
// We throw an exception before reaching this explicit return because
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче