| /* |
| * 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.core.client.GWT; |
| import com.google.gwt.dom.client.Document; |
| import com.google.gwt.dom.client.NativeEvent; |
| import com.google.gwt.event.dom.client.ClickEvent; |
| import com.google.gwt.event.dom.client.ClickHandler; |
| import com.google.gwt.event.dom.client.FocusEvent; |
| import com.google.gwt.event.dom.client.FocusHandler; |
| import com.google.gwt.event.logical.shared.InitializeEvent; |
| import com.google.gwt.event.logical.shared.InitializeHandler; |
| import com.google.gwt.junit.DoNotRunWith; |
| import com.google.gwt.junit.Platform; |
| import com.google.gwt.junit.client.GWTTestCase; |
| import com.google.gwt.safehtml.shared.SafeHtmlUtils; |
| import com.google.gwt.user.client.Element; |
| import com.google.gwt.user.client.Event; |
| import com.google.gwt.user.client.Timer; |
| import com.google.gwt.user.client.ui.RichTextArea.BasicFormatter; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * Tests the {@link RichTextArea} widget. |
| */ |
| public class RichTextAreaTest extends GWTTestCase { |
| static final int RICH_TEXT_ASYNC_DELAY = 3000; |
| private static final String html = "<b>hello</b><i>world</i>"; |
| |
| @Override |
| public String getModuleName() { |
| return "com.google.gwt.user.User"; |
| } |
| |
| /** |
| * Test that removing and re-adding an RTA doesn't destroy its contents (Only |
| * IE actually preserves dynamically-created iframe contents across DOM |
| * removal/re-adding). |
| */ |
| @DoNotRunWith(Platform.HtmlUnitUnknown) |
| public void testAddEditRemoveAdd() { |
| final RichTextArea area = new RichTextArea(); |
| delayTestFinish(RICH_TEXT_ASYNC_DELAY); |
| area.addInitializeHandler(new InitializeHandler() { |
| public void onInitialize(InitializeEvent event) { |
| RootPanel.get().remove(area); |
| RootPanel.get().add(area); |
| |
| // It's ok (and important) to check the HTML immediately after re-adding |
| // the rta. |
| assertEquals("foo", area.getHTML()); |
| finishTest(); |
| } |
| }); |
| RootPanel.get().add(area); |
| area.setHTML("foo"); |
| } |
| |
| public void testBlurAfterAttach() { |
| final RichTextArea rta = new RichTextArea(); |
| final List<String> actual = new ArrayList<String>(); |
| rta.addFocusHandler(new FocusHandler() { |
| public void onFocus(FocusEvent event) { |
| actual.add("test"); |
| } |
| }); |
| RootPanel.get().add(rta); |
| rta.setFocus(true); |
| rta.setFocus(false); |
| |
| // This has to be done on a timer because the rta can take some time to |
| // finish initializing (on some browsers). |
| this.delayTestFinish(3000); |
| new Timer() { |
| @Override |
| public void run() { |
| assertEquals(0, actual.size()); |
| RootPanel.get().remove(rta); |
| finishTest(); |
| } |
| }.schedule(2000); |
| } |
| |
| public void testFocusAfterAttach() { |
| final RichTextArea rta = new RichTextArea(); |
| final List<String> actual = new ArrayList<String>(); |
| rta.addFocusHandler(new FocusHandler() { |
| public void onFocus(FocusEvent event) { |
| actual.add("test"); |
| } |
| }); |
| RootPanel.get().add(rta); |
| rta.setFocus(true); |
| |
| // Webkit based browsers will not fire a focus event if the browser window |
| // is behind another window, so we can only test that this doesn't cause |
| // an error. |
| } |
| |
| /** |
| * Test that adding and removing an RTA before initialization completes |
| * doesn't throw an exception. |
| */ |
| public void testAddRemoveBeforeInit() { |
| final RichTextArea richTextArea = new RichTextArea(); |
| RootPanel.get().add(richTextArea); |
| RootPanel.get().remove(richTextArea); |
| } |
| |
| public void testFormatAfterAttach() { |
| final RichTextArea area = new RichTextArea(); |
| BasicFormatter formatter = area.getBasicFormatter(); |
| RootPanel.get().add(area); |
| if (formatter != null) { |
| try { |
| formatter.toggleBold(); |
| if (!GWT.isScript()) { |
| fail("Expected AssertionError"); |
| } |
| } catch (AssertionError e) { |
| // Expected because the iframe is not initialized |
| return; |
| } |
| if (!GWT.isScript()) { |
| fail("Expected AssertionError"); |
| } |
| } |
| } |
| |
| @DoNotRunWith(Platform.HtmlUnitUnknown) |
| public void testFormatAfterInitialize() { |
| final RichTextArea area = new RichTextArea(); |
| |
| delayTestFinish(RICH_TEXT_ASYNC_DELAY); |
| area.addInitializeHandler(new InitializeHandler() { |
| public void onInitialize(InitializeEvent event) { |
| BasicFormatter formatter = area.getBasicFormatter(); |
| if (formatter != null) { |
| formatter.toggleBold(); |
| } |
| RootPanel.get().remove(area); |
| finishTest(); |
| } |
| }); |
| RootPanel.get().add(area); |
| } |
| |
| public void testFormatBeforeAttach() { |
| final RichTextArea area = new RichTextArea(); |
| BasicFormatter formatter = area.getBasicFormatter(); |
| if (formatter != null) { |
| try { |
| formatter.toggleBold(); |
| if (!GWT.isScript()) { |
| fail("Expected AssertionError"); |
| } |
| } catch (AssertionError e) { |
| // expected |
| return; |
| } |
| if (!GWT.isScript()) { |
| fail("Expected AssertionError"); |
| } |
| } |
| } |
| |
| @DoNotRunWith(Platform.HtmlUnitUnknown) |
| public void testFormatWhenHidden() { |
| final RichTextArea area = new RichTextArea(); |
| delayTestFinish(RICH_TEXT_ASYNC_DELAY); |
| area.addInitializeHandler(new InitializeHandler() { |
| public void onInitialize(InitializeEvent event) { |
| area.setVisible(false); |
| BasicFormatter formatter = area.getBasicFormatter(); |
| if (formatter != null) { |
| // This won't work on some browsers, but it should return quietly. |
| formatter.toggleBold(); |
| } |
| RootPanel.get().remove(area); |
| finishTest(); |
| } |
| }); |
| RootPanel.get().add(area); |
| } |
| |
| /** |
| * See that the custom InitializeEvent fires. |
| */ |
| @DoNotRunWith({Platform.HtmlUnitUnknown}) |
| public void testRichTextInitializeEvent() { |
| delayTestFinish(RICH_TEXT_ASYNC_DELAY); |
| final RichTextArea richTextArea = new RichTextArea(); |
| richTextArea.addInitializeHandler(new InitializeHandler() { |
| public void onInitialize(InitializeEvent event) { |
| finishTest(); |
| } |
| }); |
| RootPanel.get().add(richTextArea); |
| } |
| |
| /** |
| * Test that a delayed call to setEnable is reflected. |
| */ |
| @DoNotRunWith(Platform.HtmlUnitUnknown) |
| public void testSetEnabledAfterInit() { |
| final RichTextArea richTextArea = new RichTextArea(); |
| delayTestFinish(RICH_TEXT_ASYNC_DELAY); |
| richTextArea.addInitializeHandler(new InitializeHandler() { |
| public void onInitialize(InitializeEvent event) { |
| richTextArea.setEnabled(false); |
| assertEquals(false, richTextArea.isEnabled()); |
| richTextArea.setEnabled(true); |
| assertEquals(true, richTextArea.isEnabled()); |
| finishTest(); |
| } |
| }); |
| RootPanel.get().add(richTextArea); |
| } |
| |
| /** |
| * Test that a call to setEnable is reflected immediately, and after the area |
| * loads. |
| */ |
| @DoNotRunWith(Platform.HtmlUnitUnknown) |
| public void testSetEnabledBeforeInit() { |
| final RichTextArea richTextArea = new RichTextArea(); |
| richTextArea.setEnabled(false); |
| assertEquals(false, richTextArea.isEnabled()); |
| delayTestFinish(RICH_TEXT_ASYNC_DELAY); |
| richTextArea.addInitializeHandler(new InitializeHandler() { |
| public void onInitialize(InitializeEvent event) { |
| assertEquals(false, richTextArea.isEnabled()); |
| finishTest(); |
| } |
| }); |
| RootPanel.get().add(richTextArea); |
| assertEquals(false, richTextArea.isEnabled()); |
| } |
| |
| /** |
| * Test that events are dispatched correctly to handlers. |
| */ |
| @DoNotRunWith(Platform.HtmlUnitUnknown) |
| public void testEventDispatch() { |
| final RichTextArea rta = new RichTextArea(); |
| RootPanel.get().add(rta); |
| |
| final List<String> actual = new ArrayList<String>(); |
| rta.addClickHandler(new ClickHandler() { |
| public void onClick(ClickEvent event) { |
| assertNotNull(Event.getCurrentEvent()); |
| actual.add("test"); |
| } |
| }); |
| |
| // Fire a click event after the iframe is available |
| delayTestFinish(1000); |
| new Timer() { |
| @Override |
| public void run() { |
| assertEquals(0, actual.size()); |
| NativeEvent event = getDocument(rta).createClickEvent(0, 0, 0, 0, 0, |
| false, false, false, false); |
| getBodyElement(rta).dispatchEvent(event); |
| assertEquals(1, actual.size()); |
| RootPanel.get().remove(rta); |
| finishTest(); |
| } |
| }.schedule(500); |
| } |
| |
| /** |
| * Test that a delayed set of HTML is reflected. Some platforms have timing |
| * subtleties that need to be tested. |
| */ |
| @DoNotRunWith(Platform.HtmlUnitUnknown) |
| public void testSetHTMLAfterInit() { |
| final RichTextArea richTextArea = new RichTextArea(); |
| delayTestFinish(RICH_TEXT_ASYNC_DELAY); |
| richTextArea.addInitializeHandler(new InitializeHandler() { |
| public void onInitialize(InitializeEvent event) { |
| richTextArea.setHTML("<b>foo</b>"); |
| assertEquals("<b>foo</b>", richTextArea.getHTML().toLowerCase()); |
| finishTest(); |
| } |
| }); |
| RootPanel.get().add(richTextArea); |
| } |
| |
| /** |
| * Test that an immediate set of HTML is reflected immediately and after the |
| * area loads. Some platforms have timing subtleties that need to be tested. |
| */ |
| @DoNotRunWith(Platform.HtmlUnitUnknown) |
| public void testSetHTMLBeforeInit() { |
| final RichTextArea richTextArea = new RichTextArea(); |
| delayTestFinish(RICH_TEXT_ASYNC_DELAY); |
| richTextArea.addInitializeHandler(new InitializeHandler() { |
| public void onInitialize(InitializeEvent event) { |
| new Timer() { |
| @Override |
| public void run() { |
| assertEquals("<b>foo</b>", richTextArea.getHTML().toLowerCase()); |
| finishTest(); |
| } |
| }.schedule(100); |
| } |
| }); |
| richTextArea.setHTML("<b>foo</b>"); |
| RootPanel.get().add(richTextArea); |
| assertEquals("<b>foo</b>", richTextArea.getHTML().toLowerCase()); |
| } |
| |
| /** |
| * Test that a delayed set of safe html is reflected. Some platforms have |
| * timing subtleties that need to be tested. |
| */ |
| @DoNotRunWith(Platform.HtmlUnitUnknown) |
| public void testSetSafeHtmlAfterInit() { |
| final RichTextArea richTextArea = new RichTextArea(); |
| delayTestFinish(RICH_TEXT_ASYNC_DELAY); |
| richTextArea.addInitializeHandler(new InitializeHandler() { |
| public void onInitialize(InitializeEvent event) { |
| richTextArea.setHTML(SafeHtmlUtils.fromSafeConstant(html)); |
| assertEquals(html, richTextArea.getHTML().toLowerCase()); |
| finishTest(); |
| } |
| }); |
| RootPanel.get().add(richTextArea); |
| } |
| |
| /** |
| * Test that an immediate set of safe html is reflected immediately and after |
| * the area loads. Some platforms have timing subtleties that need to be |
| * tested. |
| */ |
| @DoNotRunWith(Platform.HtmlUnitUnknown) |
| public void testSetSafeHtmlBeforeInit() { |
| final RichTextArea richTextArea = new RichTextArea(); |
| delayTestFinish(RICH_TEXT_ASYNC_DELAY); |
| richTextArea.addInitializeHandler(new InitializeHandler() { |
| public void onInitialize(InitializeEvent event) { |
| new Timer() { |
| @Override |
| public void run() { |
| assertEquals(html, richTextArea.getHTML().toLowerCase()); |
| finishTest(); |
| } |
| }.schedule(100); |
| } |
| }); |
| richTextArea.setHTML(SafeHtmlUtils.fromSafeConstant(html)); |
| RootPanel.get().add(richTextArea); |
| assertEquals(html, richTextArea.getHTML().toLowerCase()); |
| } |
| |
| /** |
| * Test that delayed set of text is reflected. Some platforms have timing |
| * subtleties that need to be tested. |
| */ |
| @DoNotRunWith(Platform.HtmlUnitUnknown) |
| public void testSetTextAfterInit() { |
| final RichTextArea richTextArea = new RichTextArea(); |
| delayTestFinish(RICH_TEXT_ASYNC_DELAY); |
| richTextArea.addInitializeHandler(new InitializeHandler() { |
| public void onInitialize(InitializeEvent event) { |
| richTextArea.setText("foo"); |
| assertEquals("foo", richTextArea.getText()); |
| finishTest(); |
| } |
| }); |
| RootPanel.get().add(richTextArea); |
| } |
| |
| /** |
| * Test that an immediate set of text is reflected immediately and after the |
| * area loads. Some platforms have timing subtleties that need to be tested. |
| */ |
| @DoNotRunWith(Platform.HtmlUnitUnknown) |
| public void testSetTextBeforeInit() { |
| final RichTextArea richTextArea = new RichTextArea(); |
| richTextArea.setText("foo"); |
| delayTestFinish(RICH_TEXT_ASYNC_DELAY); |
| richTextArea.addInitializeHandler(new InitializeHandler() { |
| public void onInitialize(InitializeEvent event) { |
| assertEquals("foo", richTextArea.getText()); |
| finishTest(); |
| } |
| }); |
| RootPanel.get().add(richTextArea); |
| assertEquals("foo", richTextArea.getText()); |
| } |
| |
| /** |
| * Get the body element from a RichTextArea. |
| * |
| * @param rta the {@link RichTextArea} |
| * @return the body element |
| */ |
| private Element getBodyElement(RichTextArea rta) { |
| return getDocument(rta).getBody().cast(); |
| } |
| |
| /** |
| * Get the iframe's Document. This is useful for creating events, which must |
| * be created in the iframe's document to work correctly. |
| * |
| * @param rta the {@link RichTextArea} |
| * @return the document element |
| */ |
| private Document getDocument(RichTextArea rta) { |
| return getDocumentImpl(rta.getElement()); |
| } |
| |
| private native Document getDocumentImpl(Element iframe) /*-{ |
| return iframe.contentWindow.document; |
| }-*/; |
| } |