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:
Victor Porof 2019-07-05 11:01:24 +02:00
Родитель 4998c97d04
Коммит 2b036e45c5
194 изменённых файлов: 10107 добавлений и 5510 удалений

Просмотреть файл

@ -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"}, "&#160;"),
TD({style: spacer},
A({href: link}, link)));
if (value instanceof Object && !("test" in value)) {
response += TR(
{ class: "dir", id: "tr-" + link },
TD({ colspan: "3" }, "&#160;"),
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

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше