blob: 387feef495eb8a3c4727d86476bf0ade3676b49e [file] [log] [blame]
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.user.client.ui;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.EventTarget;
import com.google.gwt.dom.client.ImageElement;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.junit.DoNotRunWith;
import com.google.gwt.junit.Platform;
import com.google.gwt.junit.client.GWTTestCase;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
/**
* Tests for the native event triggering methods in {@link Event}.
*/
public class CreateEventTest extends GWTTestCase {
/**
* Listener for use with key[down up press].
*/
private static class KeyCodeEventListener extends BubbleAssertingEventListener {
public KeyCodeEventListener(String eventType) {
super(eventType, true);
}
@Override
public void onBrowserEvent(Event event) {
if (cancelled) {
return;
}
super.onBrowserEvent(event);
assertEquals(KEY_CODE, event.getKeyCode());
// shouldn't throw:
event.getCharCode();
}
}
/**
* Listener for use with key[down up press].
*/
private static class KeyPressEventListener extends BubbleAssertingEventListener {
public KeyPressEventListener() {
super("keypress", true);
}
@Override
public void onBrowserEvent(Event event) {
if (cancelled) {
return;
}
super.onBrowserEvent(event);
assertEquals(KEY_CODE, event.getCharCode());
// shouldn't throw:
event.getKeyCode();
}
}
/**
* Listener for use with mouse[down up move over out].
*/
private static class MouseEventListener extends BubbleAssertingEventListener {
public MouseEventListener(String eventType) {
super(eventType, true);
}
@Override
public void onBrowserEvent(Event event) {
if (cancelled) {
return;
}
super.onBrowserEvent(event);
assertMouseCoordinates(event);
assertEquals(Event.BUTTON_LEFT, event.getButton());
}
}
/**
* An event listener that asserts that the event is passed to child, then
* parent.
*/
private static class BubbleAssertingEventListener implements EventListener {
protected boolean cancelled = false;
private final String eventType;
private boolean expectedAlt = true;
private boolean expectedCtrl = true;
private boolean expectedMeta = true;
private boolean expectedShift = true;
private boolean parentReceived, childReceived;
private boolean supportsShiftKeys;
public BubbleAssertingEventListener(String eventType,
boolean supportsShiftKeys) {
this.eventType = eventType;
this.supportsShiftKeys = supportsShiftKeys;
}
public void assertReceived() {
if (cancelled) {
return;
}
assertTrue("Expected child to receive event", childReceived);
assertTrue("Expected parent to receive event", parentReceived);
childReceived = false;
parentReceived = false;
}
public void cancel() {
cancelled = true;
}
@Override
public void onBrowserEvent(Event event) {
if (cancelled) {
return;
}
assertEquals(eventType, event.getType());
if (supportsShiftKeys) {
assertAllShiftKeys(event, expectedCtrl, expectedAlt, expectedShift,
expectedMeta);
}
EventTarget target = event.getCurrentEventTarget();
if (Element.is(target)) {
if (Element.as(target) == child) {
assertFalse("Expecting child to receive the event only once",
childReceived);
assertFalse("Expecting child to receive the event before parent",
parentReceived);
childReceived = true;
} else if (Element.as(target) == parent) {
assertFalse("Expecting parent to receive the event only once",
parentReceived);
assertTrue("Expecting parent to receive the event after the child",
childReceived);
parentReceived = true;
}
}
}
/**
* Set the expected shift keys that should be on during the next event.
*/
public void setExpectedShiftKeys(boolean expectedCtrl, boolean expectedAlt,
boolean expectedShift, boolean expectedMeta) {
this.expectedCtrl = expectedCtrl;
this.expectedAlt = expectedAlt;
this.expectedShift = expectedShift;
this.expectedMeta = expectedMeta;
}
}
/**
* Used with {@link CreateEventTest#testGetCurrentEvent()}.
*/
private static class CurrentEventListener implements EventListener {
public boolean gotClick, gotKeyPress, gotFocus;
@Override
public void onBrowserEvent(Event event) {
switch (Event.getCurrentEvent().getTypeInt()) {
case Event.ONCLICK:
gotClick = true;
break;
case Event.ONKEYPRESS:
gotKeyPress = true;
break;
case Event.ONFOCUS:
gotFocus = true;
break;
}
}
}
/**
* An event listener that asserts that the event is passed only to child.
*/
private static class NonBubbleAssertingEventListener implements EventListener {
protected boolean cancelled = false;
private boolean childReceived;
private String eventType;
public NonBubbleAssertingEventListener(String eventType) {
this.eventType = eventType;
}
public void cancel() {
cancelled = true;
}
@Override
public void onBrowserEvent(Event event) {
if (cancelled) {
return;
}
assertEquals(eventType, event.getType());
if (event.getEventTarget().equals(child)) {
assertFalse("Expecting child to receive the event only once",
childReceived);
childReceived = true;
} else if (event.getEventTarget().equals(parent)) {
fail("Not expecting parent to receive the event");
}
}
}
/**
* Interface to create a new event for testing.
*/
private static interface EventCreator {
NativeEvent createEvent(boolean ctrlKey, boolean altKey, boolean shiftKey,
boolean metaKey);
}
/**
* An event listener that asserts that events are received properly for the
* img element.
*/
private static class ImgEventListener implements EventListener {
private final String eventType;
private boolean imgReceived;
public ImgEventListener(String eventType) {
this.eventType = eventType;
}
@Override
public void onBrowserEvent(Event event) {
if (event.getType().equals(eventType)) {
if (event.getEventTarget().equals(img)) {
assertFalse("Expecting img to receive the event only once",
imgReceived);
imgReceived = true;
} else if (event.getEventTarget().equals(parent)) {
fail("Not expecting parent to receive the event");
}
}
}
}
private static final int ALL_EVENTS = Event.MOUSEEVENTS | Event.KEYEVENTS
| Event.FOCUSEVENTS | Event.ONCHANGE | Event.ONCLICK | Event.ONDBLCLICK
| Event.ONCONTEXTMENU | Event.ONLOAD | Event.ONERROR | Event.ONSCROLL;
private static InputElement child;
private static final int CLIENT_X = 2;
private static final int CLIENT_Y = 3;
private static ImageElement img;
private static final int KEY_CODE = 'A';
private static final int MOUSE_DETAIL = 1;
private static DivElement parent;
private static final int SCREEN_X = 4;
private static final int SCREEN_Y = 5;
/**
* Assert that all shift keys are in the expected state.
*
* @param event the event that was triggered
*/
private static void assertAllShiftKeys(Event event, boolean expectedCtrl,
boolean expectedAlt, boolean expectedShift, boolean expectedMeta) {
assertEquals("Expecting ctrl = " + expectedCtrl, expectedCtrl,
event.getCtrlKey());
assertEquals("Expecting alt = " + expectedAlt, expectedAlt,
event.getAltKey());
assertEquals("Expecting shift = " + expectedShift, expectedShift,
event.getShiftKey());
assertEquals("Expecting meta = " + expectedMeta, expectedMeta,
event.getMetaKey());
}
private static void assertMouseCoordinates(Event event) {
assertEquals("clientX", CLIENT_X, event.getClientX());
assertEquals("clientY", CLIENT_Y, event.getClientY());
assertEquals("screenX", SCREEN_X, event.getScreenX());
assertEquals("screenY", SCREEN_Y, event.getScreenY());
}
@Override
public String getModuleName() {
return "com.google.gwt.user.UserTest";
}
/**
* Tests that {@link Event#getCurrentEvent()} returns the right value for
* synthesized events.
*/
public void testGetCurrentEvent() {
CurrentEventListener listener = new CurrentEventListener();
Event.setEventListener(child, listener);
// Test all three major event types.
child.dispatchEvent(Document.get().createClickEvent(0, 0, 0, 0, 0, false,
false, false, false));
child.dispatchEvent(Document.get().createKeyPressEvent(false, false, false,
false, 65));
child.dispatchEvent(Document.get().createFocusEvent());
assertTrue("Expecting click as current event", listener.gotClick);
assertTrue("Expecting keypress as current event", listener.gotKeyPress);
assertTrue("Expecting focus as current event", listener.gotFocus);
}
/**
* Tests NativeEvent.stopPropagation().
*/
public void testStopPropagation() {
NonBubbleAssertingEventListener listener = new NonBubbleAssertingEventListener(
"click") {
@Override
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
if (event.getCurrentEventTarget().equals(child)) {
event.stopPropagation();
}
}
};
Event.setEventListener(parent, listener);
Event.setEventListener(child, listener);
child.dispatchEvent(Document.get().createClickEvent(MOUSE_DETAIL, SCREEN_X,
SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true));
listener.cancel();
assertTrue("Expected child to receive event", listener.childReceived);
}
/**
* Tests createBlurEvent().
*/
public void testTriggerBlurEvent() {
NonBubbleAssertingEventListener listener = new NonBubbleAssertingEventListener(
"blur") {
@Override
public void onBrowserEvent(Event event) {
if (cancelled) {
return;
}
super.onBrowserEvent(event);
assertEquals("blur", event.getType());
}
};
Event.setEventListener(parent, listener);
Event.setEventListener(child, listener);
child.dispatchEvent(Document.get().createBlurEvent());
listener.cancel();
assertTrue("Expected child to receive event", listener.childReceived);
}
/**
* Tests createChangeEvent().
*/
public void testTriggerChangeEvent() {
BubbleAssertingEventListener listener = new BubbleAssertingEventListener(
"change", false);
Event.setEventListener(parent, listener);
Event.setEventListener(child, listener);
child.dispatchEvent(Document.get().createChangeEvent());
listener.cancel();
assertTrue("Expected child to receive event", listener.childReceived);
}
/**
* Tests createClickEvent().
*/
public void testTriggerClickEvent() {
BubbleAssertingEventListener listener = new BubbleAssertingEventListener(
"click", true) {
@Override
public void onBrowserEvent(Event event) {
if (cancelled) {
return;
}
super.onBrowserEvent(event);
assertMouseCoordinates(event);
}
};
Event.setEventListener(parent, listener);
Event.setEventListener(child, listener);
child.dispatchEvent(Document.get().createClickEvent(MOUSE_DETAIL, SCREEN_X,
SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true));
listener.cancel();
assertTrue("Expected child to receive event", listener.childReceived);
assertTrue("Expected parent to receive event", listener.parentReceived);
}
/**
* Tests createContextMenuEvent().
*/
public void testTriggerContextMenuEvent() {
BubbleAssertingEventListener listener = new BubbleAssertingEventListener(
"contextmenu", false);
Event.setEventListener(parent, listener);
Event.setEventListener(child, listener);
child.dispatchEvent(Document.get().createContextMenuEvent());
listener.cancel();
assertTrue("Expected child to receive event", listener.childReceived);
assertTrue("Expected parent to receive event", listener.parentReceived);
}
/**
* Tests createDblClickEvent().
*/
public void testTriggerDblClickEvent() {
BubbleAssertingEventListener listener = new BubbleAssertingEventListener(
"dblclick", true) {
@Override
public void onBrowserEvent(Event event) {
if (cancelled) {
return;
}
if (event.getTypeInt() == Event.ONCLICK) {
// Some browsers (IE, I'm looking at you) synthesize an extra click
// event when a double-click is triggered. This synthesized click
// will *not* have the same properties as the dblclick, so we will
// not try to assert them here.
return;
}
super.onBrowserEvent(event);
assertMouseCoordinates(event);
}
};
Event.setEventListener(parent, listener);
Event.setEventListener(child, listener);
child.dispatchEvent(Document.get().createDblClickEvent(MOUSE_DETAIL,
SCREEN_X, SCREEN_Y, CLIENT_X, CLIENT_Y, true, true, true, true));
listener.cancel();
assertTrue("Expected child to receive event", listener.childReceived);
assertTrue("Expected parent to receive event", listener.parentReceived);
}
public void testTriggerErrorEvent() {
ImgEventListener listener = new ImgEventListener("error");
Event.setEventListener(parent, listener);
Event.setEventListener(img, listener);
img.dispatchEvent(Document.get().createErrorEvent());
assertTrue("Expected child to receive event", listener.imgReceived);
}
/**
* Tests createFocusEvent().
*/
public void testTriggerFocusEvent() {
NonBubbleAssertingEventListener listener = new NonBubbleAssertingEventListener(
"focus") {
@Override
public void onBrowserEvent(Event event) {
if (cancelled) {
return;
}
super.onBrowserEvent(event);
assertEquals("focus", event.getType());
}
};
Event.setEventListener(parent, listener);
Event.setEventListener(child, listener);
child.dispatchEvent(Document.get().createFocusEvent());
listener.cancel();
assertTrue("Expected child to receive event", listener.childReceived);
}
/**
* Tests createKeyDownEvent().
*/
public void testTriggerKeyDownEvent() {
KeyCodeEventListener listener = new KeyCodeEventListener("keydown");
EventCreator creator = new EventCreator() {
@Override
public NativeEvent createEvent(boolean ctrlKey, boolean altKey,
boolean shiftKey, boolean metaKey) {
return Document.get().createKeyDownEvent(ctrlKey, altKey, shiftKey,
metaKey, KEY_CODE);
}
};
testTriggerEventWithShiftKeys(listener, creator);
listener.cancel();
}
/**
* Tests createKeyPressEvent().
*
* Failed in all modes due to HtmlUnit bug:
*/
@DoNotRunWith({Platform.HtmlUnitBug})
public void testTriggerKeyPressEvent() {
KeyPressEventListener listener = new KeyPressEventListener();
EventCreator creator = new EventCreator() {
@Override
public NativeEvent createEvent(boolean ctrlKey, boolean altKey,
boolean shiftKey, boolean metaKey) {
return Document.get().createKeyPressEvent(ctrlKey, altKey, shiftKey,
metaKey, KEY_CODE);
}
};
testTriggerEventWithShiftKeys(listener, creator);
listener.cancel();
}
/**
* Tests createKeyUpEvent().
*/
public void testTriggerKeyUpEvent() {
KeyCodeEventListener listener = new KeyCodeEventListener("keyup");
EventCreator creator = new EventCreator() {
@Override
public NativeEvent createEvent(boolean ctrlKey, boolean altKey,
boolean shiftKey, boolean metaKey) {
return Document.get().createKeyUpEvent(ctrlKey, altKey, shiftKey,
metaKey, KEY_CODE);
}
};
testTriggerEventWithShiftKeys(listener, creator);
listener.cancel();
}
/**
* Tests createLoadEvent().
*/
public void testTriggerLoadEvent() {
ImgEventListener listener = new ImgEventListener("load");
Event.setEventListener(parent, listener);
Event.setEventListener(img, listener);
img.dispatchEvent(Document.get().createLoadEvent());
assertTrue("Expected img to receive event", listener.imgReceived);
}
/**
* Tests createMouseDownEvent().
*/
public void testTriggerMouseDownEvent() {
MouseEventListener listener = new MouseEventListener("mousedown");
EventCreator creator = new EventCreator() {
@Override
public NativeEvent createEvent(boolean ctrlKey, boolean altKey,
boolean shiftKey, boolean metaKey) {
return Document.get().createMouseDownEvent(MOUSE_DETAIL, SCREEN_X,
SCREEN_Y, CLIENT_X, CLIENT_Y, ctrlKey, altKey, shiftKey, metaKey,
Event.BUTTON_LEFT);
}
};
testTriggerEventWithShiftKeys(listener, creator);
listener.cancel();
}
/**
* Tests createMouseMoveEvent().
*/
public void testTriggerMouseMoveEvent() {
MouseEventListener listener = new MouseEventListener("mousemove");
EventCreator creator = new EventCreator() {
@Override
public NativeEvent createEvent(boolean ctrlKey, boolean altKey,
boolean shiftKey, boolean metaKey) {
return Document.get().createMouseMoveEvent(MOUSE_DETAIL, SCREEN_X,
SCREEN_Y, CLIENT_X, CLIENT_Y, ctrlKey, altKey, shiftKey, metaKey,
Event.BUTTON_LEFT);
}
};
testTriggerEventWithShiftKeys(listener, creator);
listener.cancel();
}
/**
* Tests createMouseOutEvent().
*
* Failed in all modes due to HtmlUnit bug:
*/
@DoNotRunWith({Platform.HtmlUnitBug})
public void testTriggerMouseOutEvent() {
MouseEventListener listener = new MouseEventListener("mouseout") {
@Override
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
Element relatedTarget = event.getRelatedEventTarget().cast();
assertEquals("Expected relatedElement to be img", img, relatedTarget);
}
};
EventCreator creator = new EventCreator() {
@Override
public NativeEvent createEvent(boolean ctrlKey, boolean altKey,
boolean shiftKey, boolean metaKey) {
return Document.get().createMouseOutEvent(MOUSE_DETAIL, SCREEN_X,
SCREEN_Y, CLIENT_X, CLIENT_Y, ctrlKey, altKey, shiftKey, metaKey,
Event.BUTTON_LEFT, img);
}
};
testTriggerEventWithShiftKeys(listener, creator);
listener.cancel();
}
/**
* Tests createMouseOverEvent().
*
* Failed in all modes due to HtmlUnit bug:
*/
@DoNotRunWith({Platform.HtmlUnitBug})
public void testTriggerMouseOverEvent() {
MouseEventListener listener = new MouseEventListener("mouseover") {
@Override
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
Element relatedTarget = event.getRelatedEventTarget().cast();
assertEquals("Expected relatedElement to be img", img, relatedTarget);
}
};
EventCreator creator = new EventCreator() {
@Override
public NativeEvent createEvent(boolean ctrlKey, boolean altKey,
boolean shiftKey, boolean metaKey) {
return Document.get().createMouseOverEvent(MOUSE_DETAIL, SCREEN_X,
SCREEN_Y, CLIENT_X, CLIENT_Y, ctrlKey, altKey, shiftKey, metaKey,
Event.BUTTON_LEFT, img);
}
};
testTriggerEventWithShiftKeys(listener, creator);
listener.cancel();
}
/**
* Tests createMouseUpEvent().
*/
public void testTriggerMouseUpEvent() {
MouseEventListener listener = new MouseEventListener("mouseup");
EventCreator creator = new EventCreator() {
@Override
public NativeEvent createEvent(boolean ctrlKey, boolean altKey,
boolean shiftKey, boolean metaKey) {
return Document.get().createMouseUpEvent(MOUSE_DETAIL, SCREEN_X,
SCREEN_Y, CLIENT_X, CLIENT_Y, ctrlKey, altKey, shiftKey, metaKey,
Event.BUTTON_LEFT);
}
};
testTriggerEventWithShiftKeys(listener, creator);
listener.cancel();
}
public void testTriggerScrollEvent() {
NonBubbleAssertingEventListener listener = new NonBubbleAssertingEventListener(
"scroll") {
@Override
public void onBrowserEvent(Event event) {
if (cancelled) {
return;
}
super.onBrowserEvent(event);
assertEquals("scroll", event.getType());
}
};
Event.setEventListener(parent, listener);
Event.setEventListener(child, listener);
child.dispatchEvent(Document.get().createScrollEvent());
listener.cancel();
assertTrue("Expected child to receive event", listener.childReceived);
}
@Override
protected void gwtSetUp() throws Exception {
parent = Document.get().createDivElement();
child = Document.get().createTextInputElement();
img = Document.get().createImageElement();
Document.get().getBody().appendChild(parent);
parent.appendChild(child);
parent.appendChild(img);
Event.sinkEvents(parent, ALL_EVENTS);
Event.sinkEvents(child, ALL_EVENTS);
Event.sinkEvents(img, ALL_EVENTS);
}
/**
* Test an event that supports shift keys by testing each shift key
* individually.
*/
private void testTriggerEventWithShiftKeys(
BubbleAssertingEventListener listener, EventCreator creator) {
Event.setEventListener(parent, listener);
Event.setEventListener(child, listener);
listener.setExpectedShiftKeys(true, true, true, true);
child.dispatchEvent(creator.createEvent(true, true, true, true));
listener.assertReceived();
listener.setExpectedShiftKeys(true, false, false, false);
child.dispatchEvent(creator.createEvent(true, false, false, false));
listener.assertReceived();
listener.setExpectedShiftKeys(false, true, false, false);
child.dispatchEvent(creator.createEvent(false, true, false, false));
listener.assertReceived();
listener.setExpectedShiftKeys(false, false, true, false);
child.dispatchEvent(creator.createEvent(false, false, true, false));
listener.assertReceived();
listener.setExpectedShiftKeys(false, false, false, true);
child.dispatchEvent(creator.createEvent(false, false, false, true));
listener.assertReceived();
}
}