123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628 |
- /* 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/. */
- "use strict";
- const {utils: Cu} = Components;
- Cu.import("chrome://marionette/content/action.js");
- Cu.import("chrome://marionette/content/element.js");
- Cu.import("chrome://marionette/content/error.js");
- 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.");
- ok(new action.Action("id", "sometype", "sometype"));
- run_next_test();
- });
- add_test(function test_defaultPointerParameters() {
- 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 parametersData;
- for (let d of ["foo", "", "get", "Get"]) {
- 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});
- run_next_test();
- });
- add_test(function test_processPointerUpDownAction() {
- 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}`);
- }
- actionItem.button = 5;
- let act = action.Action.fromJson(actionSequence, actionItem);
- equal(act.button, actionItem.button);
- run_next_test();
- });
- add_test(function test_validateActionDurationAndCoordinates() {
- let actionItem = {};
- let actionSequence = {id: "some_id"};
- let check = function (type, subtype, message = undefined) {
- message = message || `duration: ${actionItem.duration}, subtype: ${subtype}`;
- actionItem.type = subtype;
- actionSequence.type = type;
- checkErrors(/Expected '.*' \(.*\) to be >= 0/,
- action.Action.fromJson, [actionSequence, actionItem], message);
- };
- for (let d of [-1, "a"]) {
- actionItem.duration = d;
- check("none", "pause");
- check("pointer", "pointerMove");
- }
- actionItem.duration = 5000;
- for (let name of ["x", "y"]) {
- 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`);
- }
- 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"}, []]) {
- actionItem.origin = d;
- checkErrors(/Expected \'origin\' to be a string or a web element reference/,
- 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"};
- for (let d of ["a", "", "get", "Get"]) {
- 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"};
- actionItem.origin = {[element.Key]: "something"};
- let a = action.Action.fromJson(actionSequence, actionItem);
- deepEqual(a.origin, actionItem.origin);
- run_next_test();
- });
- add_test(function test_processPointerMoveActionDefaultOrigin() {
- let actionSequence = {type: "pointer", id: "some_id"};
- // origin left undefined
- 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 actionItems = [
- {
- duration: 5000,
- type: "pointerMove",
- origin: undefined,
- x: undefined,
- y: undefined,
- },
- {
- duration: undefined,
- type: "pointerMove",
- origin: {[element.Key]: "id", [element.LegacyKey]: "id"},
- x: undefined,
- y: undefined,
- },
- {
- duration: 5000,
- type: "pointerMove",
- x: 0,
- y: undefined,
- origin: undefined,
- },
- {
- duration: 5000,
- type: "pointerMove",
- x: 1,
- y: 2,
- origin: undefined,
- },
- ];
- for (let expected of actionItems) {
- let actual = action.Action.fromJson(actionSequence, expected);
- ok(actual instanceof action.Action);
- equal(actual.duration, expected.duration);
- equal(actual.x, expected.x);
- equal(actual.y, expected.y);
- let origin = expected.origin;
- if (typeof origin == "undefined") {
- origin = action.PointerOrigin.Viewport;
- }
- deepEqual(actual.origin, origin);
- }
- run_next_test();
- });
- add_test(function test_computePointerDestinationViewport() {
- 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";
- inputState.y = "10";
- let target = action.computePointerDestination(act, inputState);
- equal(act.x, target.x);
- equal(act.y, target.y);
- run_next_test();
- });
- add_test(function test_computePointerDestinationPointer() {
- 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;
- let target = action.computePointerDestination(act, inputState);
- 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 inputState = new action.InputState.Pointer(action.PointerType.Mouse);
- 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.");
- Assert.throws(
- () => action.computePointerDestination(act, inputState, undefined),
- InvalidArgumentError,
- "Undefined element center coordinates.");
- run_next_test();
- });
- add_test(function test_processPointerAction() {
- let actionSequence = {
- type: "pointer",
- id: "some_id",
- parameters: {
- pointerType: "mouse" //TODO "touch"
- },
- };
- let actionItems = [
- {
- duration: 2000,
- type: "pause",
- },
- {
- type: "pointerMove",
- duration: 2000,
- },
- {
- type: "pointerUp",
- button: 1,
- }
- ];
- for (let expected of actionItems) {
- let actual = action.Action.fromJson(actionSequence, expected);
- equal(actual.type, actionSequence.type);
- equal(actual.subtype, expected.type);
- equal(actual.id, actionSequence.id);
- if (expected.type === "pointerUp") {
- equal(actual.button, expected.button);
- } else {
- equal(actual.duration, expected.duration);
- }
- if (expected.type !== "pause") {
- equal(actual.pointerType, actionSequence.parameters.pointerType);
- }
- }
- run_next_test();
- });
- add_test(function test_processPauseAction() {
- 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);
- ok(act instanceof action.Action);
- equal(act.type, type);
- equal(act.subtype, actionItem.type);
- equal(act.id, actionSequence.id);
- equal(act.duration, actionItem.duration);
- }
- actionItem.duration = undefined;
- let act = action.Action.fromJson(actionSequence, actionItem);
- equal(act.duration, actionItem.duration);
- run_next_test();
- });
- add_test(function test_processActionSubtypeValidation() {
- 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);
- };
- for (let type of ["none", "key", "pointer"]) {
- actionSequence.type = type;
- check(new RegExp(`Unknown subtype for ${type} action`));
- }
- run_next_test();
- });
- add_test(function test_processKeyActionUpDown() {
- let actionSequence = {type: "key", id: "some_id"};
- let actionItem = {type: "keyDown"};
- 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);
- }
- actionItem.value = "\uE004";
- let act = action.Action.fromJson(actionSequence, actionItem);
- ok(act instanceof action.Action);
- equal(act.type, actionSequence.type);
- equal(act.subtype, actionItem.type);
- equal(act.id, actionSequence.id);
- equal(act.value, actionItem.value);
- run_next_test();
- });
- add_test(function test_processInputSourceActionSequenceValidation() {
- 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/);
- action.inputStateMap.clear();
- actionSequence.id = undefined;
- 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/);
- action.inputStateMap.clear();
- run_next_test();
- });
- add_test(function test_processInputSourceActionSequence() {
- 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);
- expectedAction.duration = actionItem.duration;
- let actions = action.Sequence.fromJson(actionSequence);
- equal(actions.length, 1);
- deepEqual(actions[0], expectedAction);
- action.inputStateMap.clear();
- run_next_test();
- });
- add_test(function test_processInputSourceActionSequencePointer() {
- let actionItem = {type: "pointerDown", button: 1};
- let actionSequence = {
- type: "pointer",
- id: "9",
- actions: [actionItem],
- parameters: {
- pointerType: "mouse" // TODO "pen"
- },
- };
- let expectedAction = new action.Action(
- actionSequence.id, actionSequence.type, actionItem.type);
- expectedAction.pointerType = actionSequence.parameters.pointerType;
- expectedAction.button = actionItem.button;
- let actions = action.Sequence.fromJson(actionSequence);
- equal(actions.length, 1);
- deepEqual(actions[0], expectedAction);
- action.inputStateMap.clear();
- run_next_test();
- });
- add_test(function test_processInputSourceActionSequenceKey() {
- 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);
- expectedAction.value = actionItem.value;
- let actions = action.Sequence.fromJson(actionSequence);
- equal(actions.length, 1);
- deepEqual(actions[0], expectedAction);
- action.inputStateMap.clear();
- run_next_test();
- });
- add_test(function test_processInputSourceActionSequenceInputStateMap() {
- let id = "1";
- let actionItem = {type: "pause", duration: 5000};
- let actionSequence = {
- type: "key",
- id: id,
- actions: [actionItem],
- };
- 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}`);
- action.inputStateMap.clear();
- let rightInputState = new action.InputState.Key();
- action.inputStateMap.set(id, rightInputState);
- let acts = action.Sequence.fromJson(actionSequence);
- equal(acts.length, 1);
- action.inputStateMap.clear();
- run_next_test();
- });
- add_test(function test_processPointerActionInputStateMap() {
- let actionItem = {type: "pointerDown"};
- let id = "1";
- 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`);
- action.inputStateMap.clear();
- // TODO - uncomment once pen is supported
- //wrongInputState = new action.InputState.Pointer("pen");
- //action.inputStateMap.set(id, wrongInputState);
- //checkErrors(
- // /to be mapped to InputState whose subtype is/, action.processPointerAction,
- // [id, parameters, a],
- // `subtype ${parameters.pointerType} with ${wrongInputState.subtype} in inputState`);
- //action.inputStateMap.clear();
- let rightInputState = new action.InputState.Pointer("mouse");
- action.inputStateMap.set(id, rightInputState);
- action.processPointerAction(id, parameters, a);
- action.inputStateMap.clear();
- run_next_test();
- });
- add_test(function test_createInputState() {
- for (let kind in action.InputState) {
- let state;
- if (kind == "Pointer") {
- state = new action.InputState[kind]("mouse");
- } else {
- state = new action.InputState[kind]();
- }
- ok(state);
- if (kind === "Null") {
- equal(state.type, "none");
- } else {
- 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");
- 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);
- }
- run_next_test();
- });
- add_test(function test_extractActionChainEmpty() {
- deepEqual(action.Chain.fromJson([]), []);
- run_next_test();
- });
- add_test(function test_extractActionChain_oneTickOneInput() {
- 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);
- expectedAction.duration = actionItem.duration;
- let actionsByTick = action.Chain.fromJson([actionSequence]);
- equal(1, actionsByTick.length);
- equal(1, actionsByTick[0].length);
- deepEqual(actionsByTick, [[expectedAction]]);
- action.inputStateMap.clear();
- run_next_test();
- });
- add_test(function test_extractActionChain_twoAndThreeTicks() {
- let mouseActionItems = [
- {
- type: "pointerDown",
- button: 2,
- },
- {
- type: "pointerUp",
- button: 2,
- },
- ];
- let mouseActionSequence = {
- type: "pointer",
- id: "7",
- actions: mouseActionItems,
- parameters: {
- pointerType: "mouse" //TODO "touch"
- },
- };
- let keyActionItems = [
- {
- type: "keyDown",
- value: "a",
- },
- {
- type: "pause",
- duration: 4,
- },
- {
- type: "keyUp",
- value: "a",
- },
- ];
- let keyActionSequence = {
- type: "key",
- id: "1",
- actions: keyActionItems,
- };
- 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);
- 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: []}]);
- equal(keyActionItems.length, actionsByTick.length);
- equal(1, actionsByTick[0].length);
- action.inputStateMap.clear();
- run_next_test();
- });
- 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},
- // 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"},
- ];
- equal(expected, action.computeTickDuration(tickActions));
- run_next_test();
- });
- add_test(function test_computeTickDuration_empty() {
- equal(0, action.computeTickDuration([]));
- run_next_test();
- });
- 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},
- // undefined duration permitted
- {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);
- };
- function checkErrors(regex, func, args, message) {
- if (typeof message == "undefined") {
- message = `actionFunc: ${func.name}; args: ${args}`;
- }
- Assert.throws(() => func.apply(this, args), InvalidArgumentError, message);
- Assert.throws(() => func.apply(this, args), regex, message);
- };
|