gpii-windows
Version:
Components of the GPII personalization infrastructure for use on Microsoft's "Windows" ™
629 lines (580 loc) • 18.7 kB
JavaScript
/*
* Tests for Application Zoom
*
* Copyright 2015 Raising the Floor - International
*
* Licensed under the New BSD license. You may not use this file except in
* compliance with this License.
*
* The research leading to these results has received funding from the European Union's
* Seventh Framework Programme (FP7/2007-2013)
* under grant agreement no. 289016.
*
* You may obtain a copy of the License at
* https://github.com/GPII/universal/blob/master/LICENSE.txt
*/
;
var fluid = require("gpii-universal");
var jqUnit = fluid.require("node-jqunit");
var gpii = fluid.registerNamespace("gpii");
var ffi = require("ffi-napi");
require("../src/appZoom.js");
require("../../../../tests/TestWithMocks.js");
fluid.registerNamespace("gpii.tests.windows.appZoom");
var teardowns = [];
jqUnit.module("gpii.tests.windows.appZoom", {
setup: function () {
},
teardown: function () {
while (teardowns.length) {
teardowns.pop()();
}
}
});
gpii.tests.windows.appZoom.user32 = ffi.Library("user32", {
// https://msdn.microsoft.com/library/ms646301
"GetKeyState": [
"short", ["int"]
]
});
gpii.tests.windows.appZoom.testConfigs = fluid.freezeRecursive([
{
id: "mouse wheel",
config: {
wheel: {}
}
},
{
id: "ctrl + mouse wheel",
config: {
wheel: {},
ctrl: true
}
},
{
id: "keyboard",
config: {
key: {
decrease: "-",
increase: "="
}
}
},
{
id: "ctrl + keyboard",
config: {
key: {
decrease: "A",
increase: "Z"
},
ctrl: true
}
},
{
id: "mouse wheel, getForegroundWindow",
config: {
wheel: {},
getForegroundWindow: true
}
}
]);
gpii.windows.messages.messagePumpDelay = 100;
jqUnit.asyncTest("Send zoom", function () {
var testData = gpii.tests.windows.appZoom.testConfigs;
var currentTest;
var currentTestPromise;
var testIndex = 0;
var gotKeyDown = false;
var appZoom;
// Expand the tests to test increase and decrease.
var allTests = [];
fluid.each(testData, function (test) {
allTests.push(Object.assign({direction: "increase"}, test));
allTests.push(Object.assign({direction: "decrease"}, test));
jqUnit.expect(6 * (test.config.key ? 2 : 1));
});
// Start the next test.
var nextTest = function () {
currentTest = allTests[testIndex++];
currentTestPromise = fluid.promise();
if (currentTest) {
fluid.log("test: " + currentTest.id);
gotKeyDown = false;
appZoom.currentWindow = {
hwnd: appZoom.getMessageWindow(),
config: currentTest.config
};
// Set control keys to a known state (depressed).
gpii.windows.user32.keybd_event(gpii.windows.API_constants.virtualKeyCodes.VK_CONTROL, 0, 2, 0);
gpii.windows.user32.keybd_event(gpii.windows.API_constants.virtualKeyCodes.VK_CONTROL, 0, 3, 0);
// Send the zoom command.
fluid.promise.sequence([
appZoom.sendZoom(currentTest.direction),
currentTestPromise
]).then(nextTest);
} else {
appZoom.destroy();
jqUnit.start();
}
};
appZoom = gpii.windows.appZoom({
listeners: {
// The message window is the recipient of the zoom messages.
"{gpii.windows.messages}.events.onMessage": function (hwnd, msg, wp) {
var handled = false;
switch (msg) {
case gpii.windows.API_constants.WM_MOUSEWHEEL:
jqUnit.assertTrue("WM_MOUSEWHEEL should only be received if testing the mouse wheel",
!!currentTest.config.wheel);
// Extract the scroll amount, and make it a signed short
var amount = gpii.windows.hiWord(wp);
if (amount & 0x8000) {
amount -= 0x10000;
}
var dir = amount && (amount > 0 ? "increase" : "decrease");
jqUnit.assertEquals("WM_MOUSEWHEEL scroll direction should match the test direction.",
currentTest.direction, dir);
handled = true;
break;
case gpii.windows.API_constants.WM_KEYDOWN:
jqUnit.assertTrue("WM_KEYDOWN should only be received if testing keys", !!currentTest.config.key);
var expectedChar = currentTest.config.key[currentTest.direction];
var charCode = gpii.windows.user32.MapVirtualKeyW(wp, gpii.windows.API_constants.MAPVK_VK_TO_CHAR);
var char = String.fromCharCode(charCode);
jqUnit.assertEquals("WM_KEYDOWN should be the correct key for the direction", expectedChar, char);
gotKeyDown = true;
handled = true;
break;
case gpii.windows.API_constants.WM_KEYUP:
jqUnit.assertTrue("WM_KEYUP should only be received if testing keys", !!currentTest.config.key);
jqUnit.assertTrue("WM_KEYUP should be received after WM_KEYDOWN", gotKeyDown);
handled = true;
break;
default:
// Ignore anything else.
break;
}
if (handled) {
var ctrlDown = !!(gpii.tests.windows.appZoom.user32.GetKeyState(
gpii.windows.API_constants.virtualKeyCodes.VK_CONTROL) & 0x8000);
jqUnit.assertEquals("Control key should only be down if configured",
!!currentTest.config.ctrl, ctrlDown);
if (msg !== gpii.windows.API_constants.WM_KEYDOWN) {
currentTestPromise.resolve();
}
}
}
}
});
nextTest();
});
jqUnit.test("Testing Invalid Zoom Direction", function () {
var appZoom = gpii.windows.appZoom({});
appZoom.currentWindow = {
hwnd: appZoom.getMessageWindow(),
config: {}
};
jqUnit.expectFrameworkDiagnostic("Should fail due to bad zoom direction", function () {
appZoom.sendZoom("InvalidDirection");
}, "sendZoom: direction should be either 'decrease' or 'increase'");
});
jqUnit.test("Testing Send Zoom on Min Window", function () {
var that = {
currentWindow: {
hwnd: "SimulatedWindow"
}
};
gpii.windows.tests.testWithMocks([{
"original": {
obj: gpii,
path: "windows.user32.IsIconic"
},
"mock": function () {
return true;
}
}], function () {
var promise = gpii.windows.appZoom.sendZoom(that, "decrease");
jqUnit.assertEquals("Promise should resolve", "resolve", promise.disposition);
}, function (e) {
jqUnit.fail("Error sending zoom with the following exception: " + e);
});
});
jqUnit.test("Testing Send Zoom with Child Window", function () {
var that = {
currentWindow: {
hwnd: "SimulatedWindow",
config: {
childWindow: "InvalidChildWindow"
}
}
};
var hwnd;
gpii.windows.tests.testWithMocks([{
"original": {
obj: gpii,
path: "windows.user32.IsIconic"
},
"mock": function () {
return false;
}
}, {
"original": {
obj: gpii,
path: "windows.appZoom.findChildWindow"
},
"mock": function () {
hwnd = 123;
return hwnd;
}
}], function () {
gpii.windows.appZoom.sendZoom(that, "decrease");
jqUnit.assertEquals("Window handle should equal mocked id", 123, hwnd);
}, function (e) {
jqUnit.fail("Error sending zoom with the following exception: " + e);
});
});
jqUnit.test("Testing Child Window Not Found", function () {
var currentWindow = {
hwnd: "Parent",
config: {
childWindow: "InvalidChildWindow"
}
};
var hwnd = gpii.windows.appZoom.findChildWindow(currentWindow, currentWindow.config);
jqUnit.assertNull("Child window should not be found", hwnd);
});
jqUnit.test("Testing Child Window Not Found (no Config)", function () {
var that = {
currentWindow: {
hwnd: "SimulatedWindow"
}
};
gpii.windows.tests.testWithMocks([{
"original": {
obj: gpii,
path: "windows.user32.IsIconic"
},
"mock": function () {
return false;
}
}], function () {
var promise = gpii.windows.appZoom.sendZoom(that, "decrease");
jqUnit.assertEquals("Promise should resolve", "reject", promise.disposition);
}, function (e) {
jqUnit.fail("Error sending zoom with the following exception: " + e);
});
});
jqUnit.test("Testing Active Window", function () {
var that = {
activeWindow: {
hwnd: "SimulatedWindow"
},
events: {
onApplicationActivated: {
fire: function (obj, currentWindow) {
activeWindow = currentWindow.currentWindow;
}
}
},
currentWindow: {
hwnd: "SimulatedWindow"
},
getConfig: function () {
return {
ignore: false,
getForegroundWindow: true
};
}
};
var activeWindow;
gpii.windows.tests.testWithMocks([{
"original": {
obj: gpii,
path: "windows.appZoom.getWindowInfo"
},
"mock": function () {
return {
pid: -1,
currentWindow: that.currentWindow
};
}
}], function () {
gpii.windows.appZoom.windowActivated(that, "SimulatedWindow");
jqUnit.assertEquals("Active Window Properly Identified", "SimulatedWindow", activeWindow.hwnd);
}, function (e) {
jqUnit.fail("Error detecting active window with the following exception: " + e);
});
});
jqUnit.test("Testing Send Wheel", function () {
var currentWindow = {
config: {
wheel: {
simulate: true
}
}
};
var currentPosition;
gpii.windows.tests.testWithMocks([{
"original": {
obj: gpii,
path: "windows.user32.SetCursorPos"
},
"mock": function (x, y) {
currentPosition = {x: x, y: y};
}
}], function () {
gpii.windows.appZoom.sendWheel("SimulatedWindow", -1, currentWindow);
jqUnit.assertNotNull("Simulates wheel as expected", currentPosition);
}, function (e) {
jqUnit.fail("Error simulating wheel with the following exception: " + e);
});
});
jqUnit.test("Testing Get Config", function () {
var that = {
getWindowInfo: function () {
return {};
},
options: {
configurations: {
generic: {
test: "data"
}
}
}
};
var config = gpii.windows.appZoom.getConfig(that, "SimulatedWindow");
jqUnit.assertDeepEq("Config as expected", config, {test: "data"});
});
jqUnit.test("Testing Get Window Info", function () {
gpii.windows.tests.testWithMocks([{
"original": {
obj: gpii,
path: "windows.getWindowProcessId"
},
"mock": function () {
return 1;
}
}], function () {
var windowInfo = gpii.windows.appZoom.getWindowInfo("SimulatedWindow");
jqUnit.assertDeepEq("Successfully got window info", windowInfo, {hwnd: "SimulatedWindow", pid: 1, exe: null});
}, function (e) {
jqUnit.fail("Error getting window info with the following exception: " + e);
});
});
jqUnit.test("Testing Set Control Key State (down)", function () {
var keyState;
gpii.windows.tests.testWithMocks([{
"original": {
obj: gpii,
path: "windows.user32.keybd_event"
},
"mock": function () {
keyState = arguments[2];
}
}], function () {
gpii.windows.appZoom.setControlKeyState(true);
jqUnit.assertEquals("Keyboard flags zero on down", 0, keyState);
}, function (e) {
jqUnit.fail("Error setting keyState with the following exception: " + e);
});
});
jqUnit.test("Testing Set Control Key State (up)", function () {
var keyState;
gpii.windows.tests.testWithMocks([{
"original": {
obj: gpii,
path: "windows.user32.keybd_event"
},
"mock": function () {
keyState = arguments[2];
}
}], function () {
gpii.windows.appZoom.setControlKeyState(false);
jqUnit.assertEquals("Keyboard flags 3 on up", 3, keyState);
}, function (e) {
jqUnit.fail("Error setting keyState with the following exception: " + e);
});
});
jqUnit.test("Testing Find Uncovered Point", function () {
gpii.windows.tests.testWithMocks([{
"original": {
obj: gpii,
path: "windows.getWindowRect"
},
"mock": function () {
return {
left: 20,
right: 20,
top: 20,
bottom: 20
};
}
}], function () {
var rect = {
left: 10,
right: 100,
top: 10,
bottom: 100
};
var centre = {
x: 100,
y: 100
};
var points = gpii.windows.appZoom.getOverlappingPoints(rect, centre, "windowOver");
jqUnit.assertDeepEq("Points should be properly populated", points, [
{x: 19, y: 100},
{x: 100, y: 19},
{x: 20, y: 100},
{x: 100, y: 20}
]);
}, function (e) {
jqUnit.fail("Error populating points with the following exception: " + e);
});
});
jqUnit.test("Testing Find Uncovered Point (single point)", function () {
gpii.windows.tests.testWithMocks([{
"original": {
obj: gpii,
path: "windows.getWindowRect"
},
"mock": function () {
return {
left: 20,
right: 20,
top: 20,
bottom: 20
};
}
}, {
"original": {
obj: gpii,
path: "windows.appZoom.getOverlappingPoints"
},
"mock": function () {
return [{x: 19, y: 100}];
}
}, {
"original": {
obj: gpii,
path: "windows.getWindowProcessId"
},
"mock": function () {
return 1;
}
}], function () {
var window = {
pid: 15
};
var points = gpii.windows.appZoom.findUncoveredPoint("SimulatedWindow", window);
jqUnit.assertDeepEq("Point should be properly populated", points, {
x: 19,
y: 100
});
}, function (e) {
jqUnit.fail("Error populating points with the following exception: " + e);
});
});
jqUnit.test("Testing Find Uncovered Point (single point)", function () {
gpii.windows.tests.testWithMocks([{
"original": {
obj: gpii,
path: "windows.getWindowRect"
},
"mock": function () {
return {
left: 20,
right: 20,
top: 20,
bottom: 20
};
}
}, {
"original": {
obj: gpii,
path: "windows.appZoom.getOverlappingPoints"
},
"mock": function () {
return [
{x: 19, y: 100},
{x: 100, y: 19},
{x: 20, y: 100},
{x: 100, y: 20}
];
}
}, {
"original": {
obj: gpii,
path: "windows.getWindowProcessId"
},
"mock": function () {
return 1;
}
}], function () {
var window = {
pid: 15
};
var points = gpii.windows.appZoom.findUncoveredPoint("SimulatedWindow", window);
jqUnit.assertDeepEq("Point should be properly populated", points, {
x: 19,
y: 100
});
}, function (e) {
jqUnit.fail("Error populating points with the following exception: " + e);
});
});
jqUnit.test("Testing Window Message", function () {
gpii.windows.tests.testWithMocks([{
"original": {
obj: process,
path: "nextTick"
},
"mock": function (callback, param) {
callback(param);
}
}], function () {
var debug;
var msg = gpii.windows.API_constants.WM_SHELLHOOK;
var lParam = {
address: function () {
return 456;
}
};
var that = {
windowActivated: function () {
debug = 123;
}
};
gpii.windows.appZoom.windowMessage(that, "SimulatedWindow", msg, 4, lParam);
jqUnit.assertEquals("Debug var should be set by callback", 123, debug);
}, function (e) {
jqUnit.fail("Error sending window message with the following exception: " + e);
});
});
jqUnit.test("Testing Window Message", function () {
gpii.windows.tests.testWithMocks([{
"original": {
obj: process,
path: "nextTick"
},
"mock": function (callback, param) {
callback(param);
}
}], function () {
var debug;
var msg = gpii.windows.API_constants.WM_SHELLHOOK;
var lParam = {
address: function () {
return 456;
}
};
var that = {
windowActivated: function () {
debug = 123;
}
};
gpii.windows.appZoom.windowMessage(that, "SimulatedWindow", msg, 0x8004, lParam);
jqUnit.assertEquals("Debug var should be set by callback", 123, debug);
}, function (e) {
jqUnit.fail("Error sending window message with the following exception: " + e);
});
});