blob: cfc8469451b2ce120f1d699216e859ed942c7631 [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<title>mouse_test</title>
<script src="test_bootstrap.js"></script>
<script type="text/javascript">
goog.require('bot.Mouse');
goog.require('bot.action');
goog.require('bot.userAgent');
goog.require('goog.Promise');
goog.require('goog.array');
goog.require('goog.dom');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.math.Coordinate');
goog.require('goog.style');
goog.require('goog.testing.jsunit');
goog.require('goog.userAgent');
</script>
<body>
<div id="green" style="background-color:green; width:100px; height:50px">
<div id="red" style="background-color:red; width:50px; height:25px;
position: relative; top:25px;">Red</div>
</div>
<div id="capture" style="background-color:blue; width:100px; height:50px">
<div id="innerCapture" style="background-color:cyan;
width:50px;
height:25px;">
</div>
</div>
<script type="text/javascript">
// The goog.events.EventType enum is missing mouse scrolling event types.
// This a little hacky but gives us some stylistic consistency :).
goog.events.EventType.MOUSEWHEEL =
goog.userAgent.GECKO ? 'DOMMouseScroll' : 'mousewheel';
goog.events.EventType.MOUSEPIXELSCROLL = 'MozMousePixelScroll';
var events = [];
var greenDiv, redDiv, captureDiv, innerCaptureDiv;
var MOUSE_EVENTS = [
goog.events.EventType.MOUSEOUT,
goog.events.EventType.MOUSEOVER,
goog.events.EventType.MOUSEMOVE,
goog.events.EventType.MOUSEDOWN,
goog.events.EventType.MOUSEUP,
goog.events.EventType.MOUSEWHEEL,
goog.events.EventType.MOUSEPIXELSCROLL,
goog.events.EventType.CLICK,
goog.events.EventType.CONTEXTMENU,
goog.events.EventType.DBLCLICK,
goog.events.EventType.MSPOINTERDOWN,
goog.events.EventType.MSPOINTERMOVE,
goog.events.EventType.MSPOINTEROVER,
goog.events.EventType.MSPOINTEROUT,
goog.events.EventType.MSPOINTERUP
];
function setUpPage() {
greenDiv = bot.locators.findElement({id: 'green'});
redDiv = bot.locators.findElement({id: 'red'});
captureDiv = bot.locators.findElement({id: 'capture'});
innerCaptureDiv = bot.locators.findElement({id: 'innerCapture'});
goog.testing.TestCase.getActiveTestCase().promiseTimeout = 30000; // 30s
}
function setUp() {
bot.getDocument().documentElement.focus();
events = [];
goog.events.removeAll(greenDiv);
goog.events.removeAll(redDiv);
goog.events.removeAll(captureDiv);
goog.events.removeAll(innerCaptureDiv);
goog.events.listen(greenDiv, MOUSE_EVENTS, function(e) {
events.push(e.type);
events.push(e.target);
events.push(e.button);
});
goog.events.listen(captureDiv, MOUSE_EVENTS, function(e) {
events.push(e.type);
events.push(e.target);
events.push(e.button);
if (e.type == goog.events.EventType.MSPOINTERDOWN) {
captureDiv.msSetPointerCapture(e.getBrowserEvent().pointerId);
}
});
}
/**
* Returns the button value in the object depending on the current useragent.
* Returns the 'wk' property for WebKit and IE9 in standards mode, the 'ie'
* property for IE, and the 'ff' property for Firefox.
*/
function b(button) {
return bot.userAgent.IE_DOC_9 || goog.userAgent.WEBKIT ? button['wk'] :
(goog.userAgent.IE ? button['ie'] :
button['ff']); // Firefox
}
function assertEvents(var_args) {
var expectedEvents = goog.array.concat.apply(null, arguments);
assertArrayEquals(expectedEvents, events);
events = [];
}
function mousedownEvents(elem, button) {
var events = [goog.events.EventType.MOUSEDOWN, elem, button];
return !bot.userAgent.IE_DOC_10 ? events :
[goog.events.EventType.MSPOINTERDOWN, elem, button].concat(events);
}
function mousemoveEvents(elem, button) {
var events = [goog.events.EventType.MOUSEMOVE, elem, button];
return bot.userAgent.IE_DOC_10 ?
[goog.events.EventType.MSPOINTERMOVE, elem, -1].concat(events) :
events;
}
function mouseoutEvents(elem, button) {
var events = [goog.events.EventType.MOUSEOUT, elem, button];
return bot.userAgent.IE_DOC_10 ?
[goog.events.EventType.MSPOINTEROUT, elem, -1].concat(events) :
events;
}
function mouseupEvents(elem, button) {
var events = [goog.events.EventType.MOUSEUP, elem, button];
return bot.userAgent.IE_DOC_10 ?
[goog.events.EventType.MSPOINTERUP, elem, button].concat(events) :
events;
}
function mouseoverAndMoveEvents(elem, button) {
function mouseoverEvents(elem, button) {
var events = [goog.events.EventType.MOUSEOVER, elem, button];
return bot.userAgent.IE_DOC_10 ?
[goog.events.EventType.MSPOINTEROVER, elem, -1].concat(events) :
events;
}
// IE fires the movemove *before* the mouseover event, and
// IE < 9 always supplies a mouseover button value of 0.
return goog.userAgent.IE ?
mousemoveEvents(elem, button).concat(
mouseoverEvents(elem, bot.userAgent.IE_DOC_9 ? button : 0)) :
mouseoverEvents(elem, button).concat(mousemoveEvents(elem, button));
}
function testNoClickWhenPressHiddenElement() {
var coords = new goog.math.Coordinate(5, 5);
var mouse = new bot.Mouse();
mouse.move(greenDiv, coords);
goog.style.showElement(greenDiv, false);
mouse.pressButton(bot.Mouse.Button.LEFT);
mouse.releaseButton();
assertEvents(mouseoverAndMoveEvents(greenDiv, 0));
goog.style.showElement(greenDiv, true);
}
function testLeftClick() {
var coords = new goog.math.Coordinate(5, 5);
var mouse = new bot.Mouse();
mouse.move(redDiv, coords);
mouse.pressButton(bot.Mouse.Button.LEFT);
mouse.releaseButton();
assertEvents(
mouseoverAndMoveEvents(redDiv, 0),
mousedownEvents(redDiv, b({ie: 1, wk: 0, ff: 0})),
mouseupEvents(redDiv, b({ie: 1, wk: 0, ff: 0})),
goog.events.EventType.CLICK, redDiv, 0
);
}
function testNoLeftClickWhenReleasedOverOtherElement() {
var coords = new goog.math.Coordinate(5, 5);
var mouse = new bot.Mouse();
mouse.move(greenDiv, coords);
mouse.pressButton(bot.Mouse.Button.LEFT);
mouse.move(redDiv, coords);
mouse.releaseButton();
// No click if we released on another element.
assertEvents(
mouseoverAndMoveEvents(greenDiv, 0),
mousedownEvents(greenDiv, b({ie: 1, wk: 0, ff: 0})),
mouseoutEvents(greenDiv, 0),
mouseoverAndMoveEvents(redDiv, b({ie: 1, wk: 0, ff: 0})),
mouseupEvents(redDiv, b({ie: 1, wk: 0, ff: 0}))
);
}
function testRightClick() {
var coords = new goog.math.Coordinate(5, 5);
var mouse = new bot.Mouse();
mouse.move(greenDiv, coords);
mouse.pressButton(bot.Mouse.Button.RIGHT);
mouse.move(redDiv, coords);
mouse.releaseButton();
// In https://chromium.googlesource.com/chromium/src/+/bafc23e1920cc799c03159c39e29878e26071db0
// Chrome adopted the same values as IE and FF.
var expectUninitializedButtons =
goog.userAgent.product.CHROME && goog.userAgent.product.isVersion(60);
var wkButtonData;
if (expectUninitializedButtons) {
wkButtonData = 0;
} else {
wkButtonData = 2;
}
// Right click triggers contextmenu even when released over another element.
assertEvents(
mouseoverAndMoveEvents(greenDiv, 0),
mousedownEvents(greenDiv, 2),
mouseoutEvents(greenDiv, b({ie: 2, wk: wkButtonData, ff: 0})),
mouseoverAndMoveEvents(redDiv, b({ie: 2, wk: wkButtonData, ff: 0})),
mouseupEvents(redDiv, 2),
goog.events.EventType.CONTEXTMENU, redDiv, b({ie: 0, wk: 2, ff: 2})
);
}
function testDoubleClick() {
var coords = new goog.math.Coordinate(5, 5);
var mouse = new bot.Mouse();
mouse.move(redDiv, coords);
mouse.pressButton(bot.Mouse.Button.LEFT);
mouse.releaseButton();
mouse.pressButton(bot.Mouse.Button.LEFT);
mouse.releaseButton();
assertEvents(
mouseoverAndMoveEvents(redDiv, 0),
mousedownEvents(redDiv, b({ie: 1, wk: 0, ff: 0})),
mouseupEvents(redDiv, b({ie: 1, wk: 0, ff: 0})),
goog.events.EventType.CLICK, redDiv, 0,
mousedownEvents(redDiv, b({ie: 1, wk: 0, ff: 0})),
mouseupEvents(redDiv, b({ie: 1, wk: 0, ff: 0})),
goog.events.EventType.CLICK, redDiv, 0,
goog.events.EventType.DBLCLICK, redDiv, 0
);
}
function testNoDoubleClickWhenTheMouseMovesBetweenClicks() {
var coords = new goog.math.Coordinate(5, 5);
var mouse = new bot.Mouse();
mouse.move(greenDiv, coords);
mouse.pressButton(bot.Mouse.Button.LEFT);
mouse.releaseButton();
mouse.move(redDiv, coords);
mouse.pressButton(bot.Mouse.Button.LEFT);
mouse.releaseButton();
assertEvents(
mouseoverAndMoveEvents(greenDiv, 0),
mousedownEvents(greenDiv, b({ie: 1, wk: 0, ff: 0})),
mouseupEvents(greenDiv, b({ie: 1, wk: 0, ff: 0})),
goog.events.EventType.CLICK, greenDiv, 0,
mouseoutEvents(greenDiv, 0),
mouseoverAndMoveEvents(redDiv, 0),
mousedownEvents(redDiv, b({ie: 1, wk: 0, ff: 0})),
mouseupEvents(redDiv, b({ie: 1, wk: 0, ff: 0})),
goog.events.EventType.CLICK, redDiv, 0
);
}
function testMoveOnSameElement() {
var coords1 = new goog.math.Coordinate(5, 5);
var coords2 = new goog.math.Coordinate(10, 5);
var mouse = new bot.Mouse();
mouse.move(greenDiv, coords1);
mouse.move(greenDiv, coords2);
assertEvents(
mouseoverAndMoveEvents(greenDiv, 0),
mousemoveEvents(greenDiv, 0)
);
}
function testMoveToAnotherElement() {
var coords = new goog.math.Coordinate(5, 5);
var mouse = new bot.Mouse();
mouse.move(greenDiv, coords);
mouse.move(redDiv, coords);
assertEvents(
mouseoverAndMoveEvents(greenDiv, 0),
mouseoutEvents(greenDiv, 0),
mouseoverAndMoveEvents(redDiv, 0)
);
}
function testFirstMoveHasNullRelated() {
var mouse = new bot.Mouse();
var fired = 0;
goog.events.listenOnce(greenDiv, goog.events.EventType.MOUSEOVER,
function(e) {
fired++;
// Even though bot.events.fire explicitly sets relatedTarget to null,
// it sometimes becomes undefined in Firefox.
assertEvaluatesToFalse(e.relatedTarget);
});
mouse.move(greenDiv, new goog.math.Coordinate(5, 5));
assertEquals(1, fired);
}
function testSecondMoveHasRelatedSet() {
var mouse = new bot.Mouse();
mouse.move(greenDiv, new goog.math.Coordinate(5, 5));
var fired = 0;
var relatedTarget;
goog.events.listen(redDiv, goog.events.EventType.MOUSEOVER,
function(e) {
fired++;
// Catch the relatedTarget here, but check it below so any errors are
// handled correctly in IE.
relatedTarget = e.relatedTarget;
});
mouse.move(redDiv, new goog.math.Coordinate(5, 5));
assertEquals('mouseover event not fired', 1, fired);
assertNotNull(relatedTarget);
assertNotEquals(redDiv, relatedTarget);
}
function testMoveMouseFromClosedWindowDoesNotError() {
var mouse = new bot.Mouse();
var coord = new goog.math.Coordinate(0, 0);
var iframe = document.createElement('iframe');
return new goog.Promise(function(loaded) {
goog.events.listenOnce(iframe, 'load', loaded);
iframe.src = 'testdata/blank_page.html';
document.body.appendChild(iframe);
}).then(function() {
mouse.move(iframe.contentWindow.document.body, coord);
return new goog.Promise(function(loaded) {
goog.events.listenOnce(iframe, 'load', loaded);
iframe.src = 'testdata/iframe_page.html';
});
}).then(function() {
mouse.move(iframe.contentWindow.document.body, coord);
document.body.removeChild(iframe);
});
}
function testMoveMouseFiresAllEventsOnElementHiddenMidSequence() {
var coords = new goog.math.Coordinate(5, 5);
var mouse = new bot.Mouse();
mouse.move(greenDiv, coords);
goog.events.listen(greenDiv, 'mouseout', function() {
goog.style.showElement(redDiv, false);
});
mouse.move(redDiv, coords);
goog.style.showElement(redDiv, true);
assertEvents(
mouseoverAndMoveEvents(greenDiv, 0),
mouseoutEvents(greenDiv, 0),
mouseoverAndMoveEvents(redDiv, 0)
);
}
function testScrollMouseZeroTicksThrowsError() {
var mouse = new bot.Mouse();
mouse.move(greenDiv, new goog.math.Coordinate(5, 5));
assertThrows(function() {
mouse.scroll(0);
});
}
function testScrollMouseDown() {
var mouse = new bot.Mouse();
mouse.move(greenDiv, new goog.math.Coordinate(5, 5));
mouse.scroll(1);
if (goog.userAgent.GECKO) {
assertEvents(
mouseoverAndMoveEvents(greenDiv, 0),
goog.events.EventType.MOUSEWHEEL, greenDiv, 0,
goog.events.EventType.MOUSEPIXELSCROLL, greenDiv, 0
);
} else {
assertEvents(
mouseoverAndMoveEvents(greenDiv, 0),
goog.events.EventType.MOUSEWHEEL, greenDiv, 0
);
}
}
function testScrollMouseUp() {
var mouse = new bot.Mouse();
mouse.move(greenDiv, new goog.math.Coordinate(5, 5));
mouse.scroll(-2);
if (goog.userAgent.GECKO) {
assertEvents(
mouseoverAndMoveEvents(greenDiv, 0),
goog.events.EventType.MOUSEWHEEL, greenDiv, 0,
goog.events.EventType.MOUSEPIXELSCROLL, greenDiv, 0,
goog.events.EventType.MOUSEWHEEL, greenDiv, 0,
goog.events.EventType.MOUSEPIXELSCROLL, greenDiv, 0
);
} else {
assertEvents(
mouseoverAndMoveEvents(greenDiv, 0),
goog.events.EventType.MOUSEWHEEL, greenDiv, 0,
goog.events.EventType.MOUSEWHEEL, greenDiv, 0
);
}
}
function testMsSetPointerCapture() {
if (!bot.userAgent.IE_DOC_10) {
return;
}
var coords = new goog.math.Coordinate(75, 5);
var mouse = new bot.Mouse();
mouse.move(captureDiv, coords);
mouse.pressButton(bot.Mouse.Button.LEFT);
mouse.move(greenDiv, coords);
mouse.releaseButton();
// The captureDiv will call msSetPointerCapture on MSPointerDown and as a
// result, subsequent events should be fired on captureDiv instead of
// greenDiv.
assertEvents(
mouseoverAndMoveEvents(captureDiv, 0),
mousedownEvents(captureDiv, 0),
mouseoutEvents(captureDiv, 0),
mouseoverAndMoveEvents(captureDiv, 0),
mouseupEvents(captureDiv, 0)
);
}
function testClickDoesNotFireOnCapturedPointer() {
if (!bot.userAgent.IE_DOC_10) {
return;
}
var mouse = new bot.Mouse();
mouse.move(innerCaptureDiv, new goog.math.Coordinate(5, 5));
mouse.pressButton(bot.Mouse.Button.LEFT);
mouse.move(innerCaptureDiv, new goog.math.Coordinate(6, 6));
mouse.releaseButton();
// The MSPointerDown event on innerCaptureDiv bubbles up to the
// captureDiv element which calls msSetPointerCapture, so subsequent
// events should fire on captureTarget except for the click event.
assertEvents(
mouseoverAndMoveEvents(innerCaptureDiv, 0),
mousedownEvents(innerCaptureDiv, 0),
mousemoveEvents(captureDiv, 0),
mouseupEvents(captureDiv, 0),
goog.events.EventType.CLICK, innerCaptureDiv, 0
);
}
</script>
</body>
</html>