001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.user.client.ui;
017:
018: import com.google.gwt.junit.client.GWTTestCase;
019: import com.google.gwt.user.client.Command;
020: import com.google.gwt.user.client.DOM;
021: import com.google.gwt.user.client.DeferredCommand;
022: import com.google.gwt.user.client.Element;
023: import com.google.gwt.user.client.Timer;
024:
025: /**
026: * Tests standard DOM operations in the {@link DOM} class.
027: */
028: public class DOMTest extends GWTTestCase {
029:
030: public static void assertEndsWith(String ending, String testStr) {
031: if (ending != testStr
032: && (testStr == null || !testStr.endsWith(ending))) {
033: fail("expected ending=" + ending + " actual=" + testStr);
034: }
035: }
036:
037: /**
038: * Helper method to return the denormalized child count of a DOM Element. For
039: * example, child nodes which have a nodeType of Text are included in the
040: * count, whereas <code>DOM.getChildCount(Element parent)</code> only counts
041: * the child nodes which have a nodeType of Element.
042: *
043: * @param elem the DOM element to check the child count for
044: * @return The number of child nodes
045: */
046: public static native int getDenormalizedChildCount(Element elem) /*-{
047: return (elem.childNodes.length);
048: }-*/;
049:
050: public String getModuleName() {
051: return "com.google.gwt.user.UserTest";
052: }
053:
054: /**
055: * Test DOM.get/set/removeElementAttribute() methods.
056: */
057: public void testElementAttribute() {
058: Element div = DOM.createDiv();
059: DOM.setElementAttribute(div, "class", "testClass");
060: String cssClass = DOM.getElementAttribute(div, "class");
061: assertEquals("testClass", cssClass);
062: DOM.removeElementAttribute(div, "class");
063: cssClass = DOM.getElementAttribute(div, "class");
064: assertNull(cssClass);
065: }
066:
067: /**
068: * Tests {@link DOM#getAbsoluteLeft(Element)} and
069: * {@link DOM#getAbsoluteTop(Element)}.
070: */
071: public void testGetAbsolutePosition() {
072: final int border = 8;
073: final int margin = 9;
074: final int padding = 10;
075:
076: final int top = 15;
077: final int left = 14;
078:
079: final Element elem = DOM.createDiv();
080: DOM.appendChild(RootPanel.getBodyElement(), elem);
081:
082: DOM.setStyleAttribute(elem, "position", "absolute");
083: DOM.setStyleAttribute(elem, "border", border + "px solid #000");
084: DOM.setStyleAttribute(elem, "padding", padding + "px");
085: DOM.setStyleAttribute(elem, "margin", margin + "px");
086:
087: DOM.setStyleAttribute(elem, "top", top + "px");
088: DOM.setStyleAttribute(elem, "left", left + "px");
089:
090: delayTestFinish(1000);
091: DeferredCommand.addCommand(new Command() {
092: public void execute() {
093: assertEquals(top + margin, DOM.getAbsoluteTop(elem));
094: assertEquals(left + margin, DOM.getAbsoluteLeft(elem));
095: finishTest();
096: }
097: });
098: }
099:
100: /**
101: * Tests {@link DOM#getAbsoluteTop(Element)} and
102: * {@link DOM#getAbsoluteLeft(Element)} for consistency when the element
103: * contains children and has scrollbars. See issue #1093 for more details.
104: *
105: */
106: public void testGetAbsolutePositionWhenScrolled() {
107: final Element outer = DOM.createDiv();
108: final Element inner = DOM.createDiv();
109:
110: DOM.setStyleAttribute(outer, "position", "absolute");
111: DOM.setStyleAttribute(outer, "top", "0px");
112: DOM.setStyleAttribute(outer, "left", "0px");
113: DOM.setStyleAttribute(outer, "overflow", "auto");
114: DOM.setStyleAttribute(outer, "width", "200px");
115: DOM.setStyleAttribute(outer, "height", "200px");
116:
117: DOM.setStyleAttribute(inner, "marginTop", "800px");
118: DOM.setStyleAttribute(inner, "marginLeft", "800px");
119:
120: DOM.appendChild(outer, inner);
121: DOM.appendChild(RootPanel.getBodyElement(), outer);
122: DOM.setInnerText(inner, ":-)");
123: DOM.scrollIntoView(inner);
124:
125: // Ensure that we are scrolled.
126: assertTrue(DOM.getElementPropertyInt(outer, "scrollTop") > 0);
127: assertTrue(DOM.getElementPropertyInt(outer, "scrollLeft") > 0);
128:
129: assertEquals(0, DOM.getAbsoluteTop(outer));
130: assertEquals(0, DOM.getAbsoluteLeft(outer));
131: }
132:
133: /**
134: * Tests the ability to do a parent-ward walk in the DOM.
135: */
136: public void testGetParent() {
137: Element element = RootPanel.get().getElement();
138: int i = 0;
139: while (i < 10 && element != null) {
140: element = DOM.getParent(element);
141: i++;
142: }
143: // If we got here we looped "forever" or passed, as no exception was thrown.
144: if (i == 10) {
145: fail("Cyclic parent structure detected.");
146: }
147: // If we get here, we pass, because we encountered no errors going to the
148: // top of the parent hierarchy.
149: }
150:
151: /**
152: * Tests {@link DOM#insertChild(Element, Element, int)}.
153: *
154: */
155: public void testInsertChild() {
156: Element parent = RootPanel.get().getElement();
157: Element div = DOM.createDiv();
158: DOM.insertChild(parent, div, Integer.MAX_VALUE);
159: Element child = DOM.getChild(RootPanel.get().getElement(), DOM
160: .getChildCount(parent) - 1);
161: assertEquals(div, child);
162: }
163:
164: /**
165: * Tests that {@link DOM#isOrHasChild(Element, Element)} works consistently
166: * across browsers.
167: */
168: public void testIsOrHasChild() {
169: Element div = DOM.createDiv();
170: Element childDiv = DOM.createDiv();
171: assertFalse(DOM.isOrHasChild(div, childDiv));
172: DOM.appendChild(div, childDiv);
173: assertTrue(DOM.isOrHasChild(div, childDiv));
174: assertFalse(DOM.isOrHasChild(childDiv, div));
175: }
176:
177: /**
178: * Tests that {@link DOM#setInnerText(Element, String)} works consistently
179: * across browsers.
180: */
181: public void testSetInnerText() {
182: Element tableElem = DOM.createTable();
183:
184: Element trElem = DOM.createTR();
185:
186: Element tdElem = DOM.createTD();
187: DOM.setInnerText(tdElem, "Some Table Heading Data");
188:
189: // Add a <em> element as a child to the td element
190: Element emElem = DOM.createElement("em");
191: DOM.setInnerText(emElem, "Some emphasized text");
192: DOM.appendChild(tdElem, emElem);
193:
194: DOM.appendChild(trElem, tdElem);
195:
196: DOM.appendChild(tableElem, trElem);
197:
198: DOM.appendChild(RootPanel.getBodyElement(), tableElem);
199:
200: DOM.setInnerText(tdElem, null);
201:
202: // Once we set the inner text on an element to null, all of the element's
203: // child nodes
204: // should be deleted, including any text nodes, for all supported browsers.
205: assertTrue(getDenormalizedChildCount(tdElem) == 0);
206: }
207:
208: /**
209: * Tests the correctness of setting the <code>src</code> attribute on
210: * images. The reason for these complicated tests is that DOMImplIE6 has a
211: * complex delay-load strategy to address the fact that loading multiple
212: * images of the same type on IE6 can cause multiple redundant requests when
213: * the image is not already cached.
214: *
215: * This tests the following transformation, where letters refer to URLs and
216: * number refer to indexes.
217: *
218: * <pre>
219: * 0:A -> 0:B
220: * <pre>
221: */
222: public void testSetSrc0() {
223: final Element image = DOM.createImg();
224: DOM.setImgSrc(image, "a0.gif");
225: assertEndsWith("a0.gif", DOM.getImgSrc(image));
226: DOM.setImgSrc(image, "b0.gif");
227: assertEndsWith("b0.gif", DOM.getImgSrc(image));
228: delayTestFinish(2000);
229: new Timer() {
230: public void run() {
231: assertEndsWith("b0.gif", DOM.getElementProperty(image,
232: "src"));
233: finishTest();
234: }
235: }.schedule(1000);
236: }
237:
238: /**
239: * Tests the correctness of setting the <code>src</code> attribute on
240: * images. The reason for these complicated tests is that DOMImplIE6 has a
241: * complex delay-load strategy to address the fact that loading multiple
242: * images of the same type on IE6 can cause multiple redundant requests when
243: * the image is not already cached.
244: *
245: * This tests the following transformation, where letters refer to URLs and
246: * number refer to indexes.
247: *
248: * <pre>
249: * 0:A -> 0:A 1:B
250: * | |
251: * |---| |
252: * 1:A 2:A 2:A
253: * <pre>
254: */
255: public void testSetSrc1() {
256: final Element[] images = new Element[] { DOM.createImg(),
257: DOM.createImg(), DOM.createImg() };
258: DOM.setImgSrc(images[0], "a1.gif");
259: DOM.setImgSrc(images[1], "a1.gif");
260: DOM.setImgSrc(images[2], "a1.gif");
261: assertEndsWith("a1.gif", DOM.getImgSrc(images[0]));
262: assertEndsWith("a1.gif", DOM.getImgSrc(images[1]));
263: assertEndsWith("a1.gif", DOM.getImgSrc(images[2]));
264: DOM.setImgSrc(images[1], "b1.gif");
265: assertEndsWith("a1.gif", DOM.getImgSrc(images[0]));
266: assertEndsWith("b1.gif", DOM.getImgSrc(images[1]));
267: assertEndsWith("a1.gif", DOM.getImgSrc(images[2]));
268: delayTestFinish(2000);
269: new Timer() {
270: public void run() {
271: assertEndsWith("a1.gif", DOM.getElementProperty(
272: images[0], "src"));
273: assertEndsWith("b1.gif", DOM.getElementProperty(
274: images[1], "src"));
275: assertEndsWith("a1.gif", DOM.getElementProperty(
276: images[2], "src"));
277: finishTest();
278: }
279: }.schedule(1000);
280: }
281:
282: /**
283: * Tests the correctness of setting the <code>src</code> attribute on
284: * images. The reason for these complicated tests is that DOMImplIE6 has a
285: * complex delay-load strategy to address the fact that loading multiple
286: * images of the same type on IE6 can cause multiple redundant requests when
287: * the image is not already cached.
288: *
289: * This tests the following transformation, where letters refer to URLs and
290: * number refer to indexes.
291: *
292: * <pre>
293: * 0:A -> 1:A 0:B
294: * | |
295: * |---| |
296: * 1:A 2:A 2:A
297: * <pre>
298: */
299: public void testSetSrc2() {
300: final Element[] images = new Element[] { DOM.createImg(),
301: DOM.createImg(), DOM.createImg() };
302: DOM.setImgSrc(images[0], "a2.gif");
303: DOM.setImgSrc(images[1], "a2.gif");
304: DOM.setImgSrc(images[2], "a2.gif");
305: assertEndsWith("a2.gif", DOM.getImgSrc(images[0]));
306: assertEndsWith("a2.gif", DOM.getImgSrc(images[1]));
307: assertEndsWith("a2.gif", DOM.getImgSrc(images[2]));
308: DOM.setImgSrc(images[0], "b2.gif");
309: assertEndsWith("b2.gif", DOM.getImgSrc(images[0]));
310: assertEndsWith("a2.gif", DOM.getImgSrc(images[1]));
311: assertEndsWith("a2.gif", DOM.getImgSrc(images[2]));
312: delayTestFinish(2000);
313: new Timer() {
314: public void run() {
315: assertEndsWith("b2.gif", DOM.getElementProperty(
316: images[0], "src"));
317: assertEndsWith("a2.gif", DOM.getElementProperty(
318: images[1], "src"));
319: assertEndsWith("a2.gif", DOM.getElementProperty(
320: images[2], "src"));
321: finishTest();
322: }
323: }.schedule(1000);
324: }
325:
326: /**
327: * Tests the correctness of setting the <code>src</code> attribute on
328: * images. The reason for these complicated tests is that DOMImplIE6 has a
329: * complex delay-load strategy to address the fact that loading multiple
330: * images of the same type on IE6 can cause multiple redundant requests when
331: * the image is not already cached.
332: *
333: * This tests the following transformation, where letters refer to URLs and
334: * number refer to indexes.
335: *
336: * <pre>
337: * 0:A 3:B -> 1:A 3:B
338: * | | |
339: * |---| | |
340: * 1:A 2:A 2:A 0:B
341: * <pre>
342: */
343: public void testSetSrc3() {
344: final Element[] images = new Element[] { DOM.createImg(),
345: DOM.createImg(), DOM.createImg(), DOM.createImg() };
346: DOM.setImgSrc(images[0], "a3.gif");
347: DOM.setImgSrc(images[1], "a3.gif");
348: DOM.setImgSrc(images[2], "a3.gif");
349: DOM.setImgSrc(images[3], "b3.gif");
350: assertEndsWith("a3.gif", DOM.getImgSrc(images[0]));
351: assertEndsWith("a3.gif", DOM.getImgSrc(images[1]));
352: assertEndsWith("a3.gif", DOM.getImgSrc(images[2]));
353: assertEndsWith("b3.gif", DOM.getImgSrc(images[3]));
354: DOM.setImgSrc(images[0], "b3.gif");
355: assertEndsWith("b3.gif", DOM.getImgSrc(images[0]));
356: assertEndsWith("a3.gif", DOM.getImgSrc(images[1]));
357: assertEndsWith("a3.gif", DOM.getImgSrc(images[2]));
358: assertEndsWith("b3.gif", DOM.getImgSrc(images[3]));
359: delayTestFinish(2000);
360: new Timer() {
361: public void run() {
362: assertEndsWith("b3.gif", DOM.getElementProperty(
363: images[0], "src"));
364: assertEndsWith("a3.gif", DOM.getElementProperty(
365: images[1], "src"));
366: assertEndsWith("a3.gif", DOM.getElementProperty(
367: images[2], "src"));
368: assertEndsWith("b3.gif", DOM.getElementProperty(
369: images[3], "src"));
370: finishTest();
371: }
372: }.schedule(1000);
373: }
374:
375: /**
376: * Tests the correctness of setting the <code>src</code> attribute on
377: * images. The reason for these complicated tests is that DOMImplIE6 has a
378: * complex delay-load strategy to address the fact that loading multiple
379: * images of the same type on IE6 can cause multiple redundant requests when
380: * the image is not already cached.
381: *
382: * This tests the following transformation, where letters refer to URLs and
383: * number refer to indexes.
384: *
385: * <pre>
386: * 0:A 3:B -> 0:A 3:B
387: * | | | |
388: * |---| | | |---|
389: * 1:A 2:A 4:B 1:A 4:B 2:B
390: * <pre>
391: */
392: public void testSetSrc4() {
393: final Element[] images = new Element[] { DOM.createImg(),
394: DOM.createImg(), DOM.createImg(), DOM.createImg(),
395: DOM.createImg() };
396: DOM.setImgSrc(images[0], "a4.gif");
397: DOM.setImgSrc(images[1], "a4.gif");
398: DOM.setImgSrc(images[2], "a4.gif");
399: DOM.setImgSrc(images[3], "b4.gif");
400: DOM.setImgSrc(images[4], "b4.gif");
401: assertEndsWith("a4.gif", DOM.getImgSrc(images[0]));
402: assertEndsWith("a4.gif", DOM.getImgSrc(images[1]));
403: assertEndsWith("a4.gif", DOM.getImgSrc(images[2]));
404: assertEndsWith("b4.gif", DOM.getImgSrc(images[3]));
405: assertEndsWith("b4.gif", DOM.getImgSrc(images[4]));
406: DOM.setImgSrc(images[2], "b4.gif");
407: assertEndsWith("a4.gif", DOM.getImgSrc(images[0]));
408: assertEndsWith("a4.gif", DOM.getImgSrc(images[1]));
409: assertEndsWith("b4.gif", DOM.getImgSrc(images[2]));
410: assertEndsWith("b4.gif", DOM.getImgSrc(images[3]));
411: assertEndsWith("b4.gif", DOM.getImgSrc(images[4]));
412: delayTestFinish(2000);
413: new Timer() {
414: public void run() {
415: assertEndsWith("a4.gif", DOM.getElementProperty(
416: images[0], "src"));
417: assertEndsWith("a4.gif", DOM.getElementProperty(
418: images[1], "src"));
419: assertEndsWith("b4.gif", DOM.getElementProperty(
420: images[2], "src"));
421: assertEndsWith("b4.gif", DOM.getElementProperty(
422: images[3], "src"));
423: assertEndsWith("b4.gif", DOM.getElementProperty(
424: images[4], "src"));
425: finishTest();
426: }
427: }.schedule(1000);
428: }
429:
430: /**
431: * Tests {@link DOM#toString(Element)} against likely failure points.
432: */
433: public void testToString() {
434: Button b = new Button("abcdef");
435: assertTrue(b.toString().indexOf("abcdef") != -1);
436: assertTrue(b.toString().toLowerCase().indexOf("button") != -1);
437:
438: // Test <img src="http://.../logo.gif" />
439: Element image = DOM.createImg();
440: String imageUrl = "http://www.google.com/images/logo.gif";
441: DOM.setImgSrc(image, imageUrl);
442: String imageToString = DOM.toString(image).trim().toLowerCase();
443: assertTrue(imageToString.startsWith("<img"));
444: assertTrue(imageToString.indexOf(imageUrl) != -1);
445:
446: // Test <input name="flinks" />
447: Element input = DOM.createInputText();
448: DOM.setElementProperty(input, "name", "flinks");
449: final String inputToString = DOM.toString(input).trim()
450: .toLowerCase();
451: assertTrue(inputToString.startsWith("<input"));
452:
453: // Test <select><option>....</select>
454: Element select = DOM.createSelect();
455: for (int i = 0; i < 10; i++) {
456: final Element option = DOM.createElement("option");
457: DOM.appendChild(select, option);
458: DOM.setInnerText(option, "item #" + i);
459: }
460: String selectToString = DOM.toString(select).trim()
461: .toLowerCase();
462: assertTrue(selectToString.startsWith("<select"));
463: for (int i = 0; i < 10; i++) {
464: assertTrue(selectToString.indexOf("item #" + i) != -1);
465: }
466:
467: // Test <meta name="robots" />
468: Element meta = DOM.createElement("meta");
469: DOM.setElementProperty(meta, "name", "robots");
470: String metaToString = DOM.toString(meta).trim().toLowerCase();
471: assertTrue(metaToString.startsWith("<meta"));
472: }
473: }
|