blob: 085a91d0a936f4e2d11be9f21953aec8eccffd12 [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;
import com.google.gwt.core.client.JavaScriptException;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.http.client.UrlBuilder;
import com.google.gwt.http.client.URL;
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.Window.Location;
import com.google.gwt.user.client.Window.Navigator;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Test Case for {@link Window}.
*/
public class WindowTest extends GWTTestCase {
private static native String getNodeName(Element elem) /*-{
return (elem.nodeName || "").toLowerCase();
}-*/;
/**
* Removes all elements in the body, except scripts and iframes.
*/
private static void clearBodyContent() {
Element bodyElem = RootPanel.getBodyElement();
List<Element> toRemove = new ArrayList<Element>();
for (int i = 0, n = DOM.getChildCount(bodyElem); i < n; ++i) {
Element elem = DOM.getChild(bodyElem, i);
String nodeName = getNodeName(elem);
if (!"script".equals(nodeName) && !"iframe".equals(nodeName)) {
toRemove.add(elem);
}
}
for (int i = 0, n = toRemove.size(); i < n; ++i) {
DOM.removeChild(bodyElem, toRemove.get(i));
}
}
@Override
public String getModuleName() {
return "com.google.gwt.user.User";
}
public void testLocation() {
// testing reload, replace, and assign seemed to hang our junit harness.
// Therefore only testing subset of Location that is testable.
// Use History to get the #hash part of the url into a known state (if the
// url has somehow been set to http://host/#, location.hash returns the
// empty string, but location.href includes the trailing hash).
History.newItem("foo bar");
// As we have no control over these values we cannot assert much about them.
String hash = Window.Location.getHash();
String host = Window.Location.getHost();
String hostName = Window.Location.getHostName();
String href = Window.Location.getHref();
assertNull(Window.Location.getParameter("fuzzy bunny"));
String path = Window.Location.getPath();
String port = Window.Location.getPort();
String protocol = Window.Location.getProtocol();
String query = Window.Location.getQueryString();
// Check that the sum is equal to its parts.
assertEquals(host, hostName + ":" + port);
assertEquals(href, protocol + "//" + host + path + query + hash);
}
public void testLocationCreateUrlBuilder() {
History.newItem("theHash");
String expected = Location.getHref();
// Build the string with the builder.
UrlBuilder builder = Location.createUrlBuilder();
String actual = builder.buildString();
// Check the hash.
{
String[] expectedParts = expected.split("#");
String[] actualParts = actual.split("#");
assertEquals(2, actualParts.length);
assertEquals(expectedParts[1], actualParts[1]);
expected = expectedParts[0];
actual = actualParts[0];
}
// Check the query parameters.
{
String[] expectedParts = expected.split("[?]");
String[] actualParts = actual.split("[?]");
if (expectedParts.length > 1) {
assertEquals(2, actualParts.length);
String[] expectedPairs = expectedParts[1].split("&");
String[] actualPairs = actualParts[1].split("&");
assertEquals(expectedPairs.length, actualPairs.length);
for (String actualPair : actualPairs) {
String[] kv = actualPair.split("=");
assertEquals(Location.getParameter(kv[0]),
// has a URL encoded ':' in a parameter
kv.length > 1 ? URL.decodeQueryString(kv[1]) : "");
}
}
expected = expectedParts[0];
actual = actualParts[0];
}
// Check everything but the query params and hash/
assertEquals(expected, actual);
}
public void testLocationParsing() {
Map<String, List<String>> map;
// typical case
map = Window.Location.buildListParamMap("?fuzzy=bunnies&foo=bar&num=42");
assertEquals(map.size(), 3);
assertEquals(map.get("foo").get(0), "bar");
assertEquals(map.get("fuzzy").get(0), "bunnies");
// multiple values for the same parameter
map = Window.Location.buildListParamMap(
"?fuzzy=bunnies&foo=bar&num=42&foo=baz");
assertEquals(map.size(), 3);
assertEquals(map.get("foo").get(0), "bar");
assertEquals(map.get("foo").get(1), "baz");
// no query parameters.
map = Window.Location.buildListParamMap("");
assertEquals(map.size(), 0);
// blank keys should be ignored, but blank values are OK. Also,
// keys can contain whitespace. (but the browser may give whitespace
// back as escaped).
map = Window.Location.buildListParamMap("?&& &a&b=&c=c&d=d=d&=e&f=2&f=1&");
assertEquals(map.size(), 6);
assertEquals(map.get(" ").get(0), "");
assertEquals(map.get("a").get(0), "");
assertEquals(map.get("b").get(0), "");
assertEquals(map.get("c").get(0), "c");
assertEquals(map.get("d").get(0), "d=d");
assertEquals(map.get("f").get(0), "2");
assertEquals(map.get("f").get(1), "1");
// Values escaped with hex codes should work too.
map = Window.Location.buildListParamMap("?foo=bar%20baz%3aqux");
assertEquals(map.get("foo").get(0), "bar baz:qux");
}
public void testNavigator() {
assertNotNull(Navigator.getAppCodeName());
assertNotNull(Navigator.getAppName());
assertNotNull(Navigator.getAppVersion());
assertNotNull(Navigator.getPlatform());
assertNotNull(Navigator.getUserAgent());
assertTrue(Navigator.isCookieEnabled());
// We don't care if Java is enabled, but need to make sure this call does
// not throw. The try/catch block keeps the compiled code from being
// optimized away.
try {
Navigator.isJavaEnabled();
} catch (JavaScriptException e) {
throw e;
}
}
/**
* Tests the ability of the Window to get the client size correctly with and
* without visible scroll bars.
* Failed in all modes due to HtmlUnit bug:
* https://sourceforge.net/tracker/?func=detail&aid=2944261&group_id=47038&atid=448266
*/
@DoNotRunWith(Platform.HtmlUnitBug)
public void testGetClientSize() {
// NOTE: We must clear the DOM here so that previous tests do not pollute
// our results.
clearBodyContent();
// Get the dimensions without any scroll bars
Window.enableScrolling(false);
final int oldClientHeight = Window.getClientHeight();
final int oldClientWidth = Window.getClientWidth();
assertTrue("Expect positive oldClientHeight. "
+ "This will fail in WebKit if run headless", oldClientHeight > 0);
assertTrue(oldClientWidth > 0);
// Firefox hides scrollbar if clientHeight < 49 even when it should show.
// If we are in this case, simply return.
if (oldClientHeight < 49 && Navigator.getUserAgent().contains("Firefox")) {
return;
}
// Compare to the dimensions with scroll bars
Window.enableScrolling(true);
final Label largeDOM = new Label();
largeDOM.setPixelSize(oldClientWidth + 100, oldClientHeight + 100);
RootPanel.get().add(largeDOM);
delayTestFinish(1000);
DeferredCommand.addCommand(new Command() {
public void execute() {
int newClientHeight = Window.getClientHeight();
int newClientWidth = Window.getClientWidth();
assertTrue(newClientHeight < oldClientHeight);
assertTrue(newClientWidth < oldClientWidth);
RootPanel.get().remove(largeDOM);
finishTest();
}
});
}
/**
* Calculates the sizes for Window extras such as border, menu, tool bar, and
* stores the original sizes to restore at the end of test.
*/
public static final class ResizeHelper {
private static int clientHeight;
private static int clientWidth;
private static int extraWidth;
private static int extraHeight;
private static boolean initialized;
public static int getExtraHeight() {
ensureInitialized();
return extraHeight;
}
public static int getExtraWidth() {
ensureInitialized();
return extraWidth;
}
/**
* Wraps {@code Window#resizeBy(int, int)} to ensure initialized. This may
* be a no-op in Chrome.
*
* @param width
* @param height
* @return Whether this operation is done
*/
public static boolean resizeBy(int width, int height) {
if (ensureInitialized()) {
Window.resizeBy(width, height);
}
return initialized;
}
/**
* Wraps {@code Window#resizeTo(int, int)} to ensure initialized. This may
* be a no-op in Chrome.
*
* @param width
* @param height
* @return Whether this operation is done
*/
public static boolean resizeTo(int width, int height) {
if (ensureInitialized()) {
Window.resizeTo(width, height);
}
return initialized;
}
public static void restoreSize() {
// Ignore if not initialized
if (initialized) {
Window.resizeTo(clientWidth + extraWidth, clientHeight + extraHeight);
}
}
private static synchronized boolean ensureInitialized() {
if (!initialized) {
init();
}
return initialized;
}
private static void init() {
// resizeTo works in Chrome if the window is opened by Window.open(),
// which is the case when testing with Selenium and the server is started
// with -multiWin. However, the size change is deferred. The test would
// involve many nested DeferredCommand.
if (Navigator.getUserAgent().toLowerCase().contains("chrome")) {
return;
}
// FF4 on win can start in 'almost' fullscreen when the window title bar
// is hidden but accounted incorrectly, so, move the window and resize to
// smaller size first, to take it out of 'full screen mode'.
Window.moveTo(10,10);
Window.resizeTo(700, 500);
// store the original size (to be used in restoreSize)
clientHeight = Window.getClientHeight();
clientWidth = Window.getClientWidth();
// IE cannot resize window out of the screen, so we need to move the
// window such that it can be resized to below size.
// We do not have method to return the window coordinates (screenLeft,
// screenTop), so this move is not undone.
Window.moveTo(0,0);
// clientWidth is innerWidth, resizeTo specifies outerWidth
// Let's find out the delta for extras such as border, menu, tool bar.
// If the sizes are too small to show the extras, resizeTo may not set the
// sizes as requested.
// If the sizes are too big, for example, height > screen.availHeight + 40
// on FF, resizeTo silently sets the height to screen.availHeight + 40.
// Some test machines are configured at this time as 800x600, reduce the size
// to give some 'buffer'
Window.resizeTo(750, 550);
extraWidth = 750 - Window.getClientWidth();
extraHeight = 550 - Window.getClientHeight();
initialized = true;
restoreSize();
}
}
private static final class TestResizeHandler implements ResizeHandler {
private int height;
private int width;
public void onResize(ResizeEvent event) {
width = event.getWidth();
height = event.getHeight();
}
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
}
/**
* Tests the ability of resize the Window and catch resize events.
*/
@DoNotRunWith({Platform.HtmlUnitLayout})
public void testResizing() {
clearBodyContent();
// Handler for resize events
final TestResizeHandler resizeHandler = new TestResizeHandler();
final HandlerRegistration handlerRegistration = Window.addResizeHandler(resizeHandler);
delayTestFinish(2000);
DeferredCommand.addCommand(new Command() {
public void execute() {
// Sizes must be appropriate, otherwise browsers may not resize as
// requested. See comments in ResizeHelper.
int width = 600;
int height = 500;
// ensureInitialized could fail on Chrome
if (!ResizeHelper.resizeTo(width, height)) {
handlerRegistration.removeHandler();
finishTest(); // nothing we can test
}
assertEquals(width, Window.getClientWidth() + ResizeHelper.getExtraWidth());
assertEquals(height, Window.getClientHeight() + ResizeHelper.getExtraHeight());
// TODO: TestResizeHandler.getWidth() returns 0 -- need to investigate
// assertEquals(resizeHandler.getWidth(), Window.getClientWidth());
// assertEquals(resizeHandler.getHeight(), Window.getClientHeight());
ResizeHelper.resizeBy(10, 20);
assertEquals(width + 10, Window.getClientWidth() + ResizeHelper.getExtraWidth());
assertEquals(height + 20, Window.getClientHeight() + ResizeHelper.getExtraHeight());
// assertEquals(resizeHandler.getWidth(), Window.getClientWidth());
// assertEquals(resizeHandler.getHeight(), Window.getClientHeight());
// Cleanup the window
handlerRegistration.removeHandler();
ResizeHelper.restoreSize();
finishTest();
}
});
}
/**
* Tests the ability of scroll the Window and catch scroll events.
* Failed in all modes due to HtmlUnit bug:
* https://sourceforge.net/tracker/?func=detail&aid=2897457&group_id=47038&atid=448266
* <p>
* TODO(flin): it is marked fixed, but is still not fixed.
*/
@DoNotRunWith(Platform.HtmlUnitBug)
public void testScrolling() {
// Force scroll bars to appear
Window.enableScrolling(true);
int clientHeight = Window.getClientHeight();
int clientWidth = Window.getClientWidth();
final Label largeDOM = new Label();
largeDOM.setPixelSize(clientWidth + 500, clientHeight + 500);
RootPanel.get().add(largeDOM);
// Listener for scroll events
Window.scrollTo(100, 200);
assertEquals(100, Window.getScrollLeft());
assertEquals(200, Window.getScrollTop());
Window.scrollTo(0, 0);
assertEquals(0, Window.getScrollLeft());
assertEquals(0, Window.getScrollTop());
// Cleanup the window
RootPanel.get().remove(largeDOM);
}
@SuppressWarnings("deprecation")
static class ListenerTester implements WindowResizeListener {
static int resize = 0;
public void onWindowResized(int width, int height) {
++resize;
}
public static void fire() {
resize = 0;
ResizeEvent.fire(Window.handlers, 0, 0);
}
}
@SuppressWarnings("deprecation")
public void testListenerRemoval() {
WindowResizeListener r1 = new ListenerTester();
WindowResizeListener r2 = new ListenerTester();
Window.addWindowResizeListener(r1);
Window.addWindowResizeListener(r2);
ListenerTester.fire();
assertEquals(ListenerTester.resize, 2);
Window.removeWindowResizeListener(r1);
ListenerTester.fire();
assertEquals(ListenerTester.resize, 1);
Window.removeWindowResizeListener(r2);
ListenerTester.fire();
assertEquals(ListenerTester.resize, 0);
}
}