1 /*
   2  * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  */
   5 package javafx.scene.control.test.richtexteditor;
   6 
   7 import client.test.Keywords;
   8 import client.test.ScreenshotCheck;
   9 import client.test.Smoke;
  10 import java.awt.Toolkit;
  11 import java.io.*;
  12 import java.net.URL;
  13 import java.util.*;
  14 import java.util.Map.Entry;
  15 import javafx.beans.property.SimpleStringProperty;
  16 import javafx.scene.Node;
  17 import javafx.scene.Scene;
  18 import javafx.scene.control.*;
  19 import javafx.scene.control.test.ControlsTestBase;
  20 import javafx.scene.control.test.MenuApp;
  21 import javafx.scene.control.test.RichTextEditorApp;
  22 import javafx.scene.input.Clipboard;
  23 import javafx.scene.web.HTMLEditor;
  24 import javafx.scene.web.WebView;
  25 import javafx.stage.PopupWindow;
  26 import org.jemmy.action.GetAction;
  27 import org.jemmy.control.Wrap;
  28 import org.jemmy.env.Timeout;
  29 import org.jemmy.fx.ByID;
  30 import org.jemmy.fx.ByWindowType;
  31 import org.jemmy.fx.Root;
  32 import org.jemmy.fx.control.TextControlWrap;
  33 import org.jemmy.fx.control.ThemeDriverFactory;
  34 import org.jemmy.fx.control.caspian.CaspianDriverFactory;
  35 import org.jemmy.interfaces.Keyboard.KeyboardButton;
  36 import org.jemmy.interfaces.Keyboard.KeyboardButtons;
  37 import org.jemmy.interfaces.Keyboard.KeyboardModifiers;
  38 import org.jemmy.interfaces.Parent;
  39 import org.jemmy.interfaces.Selectable;
  40 import org.jemmy.lookup.Lookup;
  41 import org.jemmy.lookup.LookupCriteria;
  42 import org.jemmy.timing.State;
  43 import static org.junit.Assert.*;
  44 import org.junit.*;
  45 import org.junit.runner.RunWith;
  46 import test.javaclient.shared.FilteredTestRunner;
  47 import test.javaclient.shared.JemmyUtils;
  48 import test.javaclient.shared.Utils;
  49 import test.javaclient.shared.screenshots.ImagesManager;
  50 import test.javaclient.shared.screenshots.ScreenshotUtils;
  51 
  52 @RunWith(FilteredTestRunner.class)
  53 public class RichTextEditorTest extends ControlsTestBase {
  54 
  55     public RichTextEditorTest() {
  56     }
  57     static Wrap<? extends Scene> scene = null;
  58     static Parent<Node> parent = null;
  59     static Wrap resetBtn;
  60     static Wrap contentPane = null;
  61     Wrap<? extends WebView> webView = null;
  62     Wrap cut = null;
  63     Wrap copy = null;
  64     Wrap paste = null;
  65     Wrap undo = null;
  66     Wrap redo = null;
  67     Wrap separator = null;
  68     Wrap left = null;
  69     Wrap center = null;
  70     Wrap right = null;
  71     Wrap adjust = null;
  72     Wrap bullets = null;
  73     Wrap numbers = null;
  74     Wrap indent = null;
  75     Wrap removeIndent = null;
  76     Wrap<? extends ComboBox> paragraph = null;
  77     Wrap<? extends ComboBox> fontStyle = null;
  78     Wrap<? extends ComboBox> fontSize = null;
  79     Wrap<? extends ToggleButton> bold = null;
  80     Wrap<? extends ToggleButton> italic = null;
  81     Wrap<? extends ToggleButton> underline = null;
  82     Wrap<? extends ToggleButton> crossed = null;
  83     Wrap foreground = null;
  84     Wrap background = null;
  85     Wrap<? extends HTMLEditor> htmlEditor = null;
  86     Parent htmlEditorAsParent;
  87     protected static KeyboardModifiers CTRL_DOWN_MASK_OS;
  88     public static String DEFAULT_TEXT_STYLE = "ArialW7";
  89     public static String PLATFORM_TAG;
  90 
  91     static {
  92         if (Utils.isMacOS()) {
  93             CTRL_DOWN_MASK_OS = KeyboardModifiers.META_DOWN_MASK;
  94             PLATFORM_TAG = "mac_";
  95         } else {
  96             CTRL_DOWN_MASK_OS = KeyboardModifiers.CTRL_DOWN_MASK;
  97             if (Utils.isWindows8()) {
  98                 PLATFORM_TAG = "win8_";
  99             } else if (Utils.isWindows()) {
 100                 PLATFORM_TAG = "win_";
 101             } else {
 102                 PLATFORM_TAG = "lin_";
 103             }
 104         }
 105     }
 106 
 107     @BeforeClass
 108     public static void setUpClass() throws Exception {
 109         RichTextEditorApp.main(null);
 110         scene = Root.ROOT.lookup().wrap();
 111         parent = scene.as(Parent.class, Node.class);
 112         resetBtn = parent.lookup(new ByID(RichTextEditorApp.RESET_BUTTON_ID)).wrap();
 113         contentPane = parent.lookup(new ByID<Node>(RichTextEditorApp.TEST_PANE_ID)).wrap();
 114     }
 115 
 116     @AfterClass
 117     public static void tearDownClass() throws Exception {
 118     }
 119 
 120     @Before
 121     public void setUp() {
 122         JemmyUtils.comparatorDistance = 0.01f;
 123         reset();
 124         if (!Utils.isLinux() && !Utils.isMacOS()) //Temporary. Need to be explored, why it generates exception on linux.
 125         {
 126             Toolkit.getDefaultToolkit().setLockingKeyState(java.awt.event.KeyEvent.VK_NUM_LOCK, false);
 127         }
 128     }
 129 
 130     @After
 131     public void tearDown() {
 132     }
 133 
 134 //     @ScreenshotCheck
 135 //     @Test(timeout=300000) //platform specific
 136 //     public void fontStylesTest() throws InterruptedException, IOException, Throwable {
 137 //        final Parent<RadioMenuItem> attributes = fontStyle.as(Parent.class, RadioMenuItem.class);
 138 //        for (int i = 0; i < attributes.lookup().size(); i++) {
 139 //            Wrap<? extends RadioMenuItem> attribute = attributes.lookup().wrap(i);
 140 //            attribute.mouse().click();
 141 //            typeText(getAttributeText("paragraph", attribute.getControl().getText()) + "\n");
 142 //        }
 143 //        check("");
 144 //    }
 145     @ScreenshotCheck
 146     @Test(timeout = 300000)
 147     @Keywords(keywords="webkit")
 148     public void textSelectionTest() throws InterruptedException, IOException, Throwable {
 149         int someRandomColor = 19;
 150         typeText(SOME_TEXT);
 151         webView.keyboard().pushKey(KeyboardButtons.ENTER);
 152         typeText(SOME_OTHER_TEXT);
 153         for (int i = 0; i < SOME_OTHER_TEXT.length() + 1; i++) {
 154             webView.keyboard().pushKey(KeyboardButtons.LEFT);
 155         }
 156         webView.keyboard().pressKey(KeyboardButtons.SHIFT);
 157         try {
 158             for (int i = 0; i < SOME_OTHER_TEXT.length() + 1; i++) {
 159                 webView.keyboard().pushKey(KeyboardButtons.LEFT);
 160             }
 161         } finally {
 162             webView.keyboard().releaseKey(KeyboardButtons.SHIFT);
 163         }        
 164         color(background, "background", someRandomColor);
 165         webView.keyboard().pushKey(KeyboardButtons.A, CTRL_DOWN_MASK_OS);
 166         webView.keyboard().pushKey(KeyboardButtons.RIGHT);
 167         ScreenshotUtils.checkScreenshot("RichTextEditor-textSelection", webView);
 168         throwScreenshotError();
 169     }
 170 
 171     @ScreenshotCheck
 172     @Test(timeout = 300000)
 173     @Keywords(keywords="webkit")
 174     public void textStyleReflectionTest() throws InterruptedException, IOException, Throwable {
 175         typeText(HELLO_WORLD);
 176         webView.keyboard().pushKey(KeyboardButtons.ENTER);
 177         setParagraph(HEADING1);
 178         typeText(SOME_TEXT);
 179         ScreenshotUtils.checkScreenshot("RichTextEditor-textStyleReflection1", contentPane);
 180         webView.keyboard().pushKey(KeyboardButtons.ENTER);
 181         setParagraph(HEADING2);
 182         typeText(SOME_OTHER_TEXT);
 183         ScreenshotUtils.checkScreenshot("RichTextEditor-textStyleReflection2", contentPane);
 184         throwScreenshotError();
 185     }
 186 
 187     @ScreenshotCheck
 188     @Test(timeout = 300000)
 189     @Keywords(keywords="webkit")
 190     public void headingIssueTest() throws InterruptedException, IOException, Throwable {
 191         setParagraph(HEADING1);
 192         typeText(SOME_TEXT);
 193         webView.keyboard().pushKey(KeyboardButtons.ENTER);
 194         setParagraph(HEADING2);
 195         typeText(SOME_OTHER_TEXT);
 196         for (int i = 0; i < SOME_OTHER_TEXT.length(); i++) {
 197             webView.keyboard().pushKey(KeyboardButtons.LEFT);
 198         }
 199         webView.keyboard().pushKey(KeyboardButtons.BACK_SPACE);
 200         ScreenshotUtils.checkScreenshot("RichTextEditor-headingIssue", webView);
 201         check("heading_issue");
 202         throwScreenshotError();
 203     }
 204 
 205     @Smoke
 206     @Test(timeout = 300000)
 207     @Keywords(keywords="webkit")
 208     public void setHtmlTest() throws InterruptedException, IOException {
 209         SimpleStringProperty ssp = new SimpleStringProperty();
 210         ssp.set(LIST);
 211         setHTML(HTML_SAMPLE_TEXT);
 212         String res = getHTML();
 213         assertEquals(HTML_SAMPLE_TEXT, res);
 214     }
 215 
 216     @ScreenshotCheck
 217     @Test(timeout = 300000)
 218     @Keywords(keywords="webkit")
 219     public void checkStylesTest() throws Throwable {
 220         setParagraph(HEADING1);
 221         typeText(SOME_TEXT);
 222         setFontSize(XX_LARGE_FONT_SIZE);
 223         typeText(SOME_OTHER_TEXT);
 224         setParagraph(HEADING6);
 225         ScreenshotUtils.checkScreenshot("RichTextEditor-styles", webView);
 226         throwScreenshotError();
 227     }
 228 
 229     @ScreenshotCheck
 230     @Smoke
 231     @Test(timeout = 300000)
 232     @Keywords(keywords="webkit")
 233     public void initialStateTest() throws InterruptedException {
 234         ScreenshotUtils.checkScreenshot("RichTextEditor-initialState", contentPane);
 235     }
 236 
 237     @Smoke
 238     @Test(timeout = 300000)
 239     @Keywords(keywords="webkit")
 240     public void deletingEmptyStringTest() throws InterruptedException, IOException, Throwable {
 241         webView.keyboard().pushKey(KeyboardButtons.ENTER);
 242         webView.keyboard().pushKey(KeyboardButtons.ENTER);
 243         webView.keyboard().pushKey(KeyboardButtons.UP);
 244         webView.keyboard().pushKey(KeyboardButtons.UP);
 245         webView.keyboard().pushKey(KeyboardButtons.DELETE);
 246         webView.keyboard().pushKey(KeyboardButtons.DOWN);
 247         webView.keyboard().pushKey(KeyboardButtons.DOWN);
 248         webView.keyboard().pushKey(KeyboardButtons.BACK_SPACE);
 249         assertTrue(getHTML().equals(readResource("deleting_empty_string_test.html")));
 250     }
 251 
 252     @ScreenshotCheck
 253     @Test(timeout = 300000) //rt-20500 -- html when possible
 254     @Keywords(keywords="webkit")
 255     public void unexpectedlyTextSelectionTest() throws InterruptedException, IOException, Throwable {
 256         final String hw = "Hello, World!";
 257         typeText(hw);
 258         for (int i = 0; i < hw.length(); i++) {
 259             webView.keyboard().pushKey(KeyboardButtons.LEFT);
 260         }
 261         webView.keyboard().pushKey(KeyboardButtons.Q);
 262         webView.keyboard().pushKey(KeyboardButtons.W);
 263         webView.keyboard().pushKey(KeyboardButtons.E);
 264         webView.keyboard().pushKey(KeyboardButtons.R);
 265         webView.keyboard().pushKey(KeyboardButtons.T);
 266         webView.keyboard().pushKey(KeyboardButtons.Y);
 267         checkScreenshot("RichTextEditor-unexpectedly-text-selection", webView);
 268         throwScreenshotError();
 269     }
 270 
 271     @ScreenshotCheck
 272     @Test(timeout = 300000)
 273     @Keywords(keywords="webkit")
 274     public void separatorTest() throws InterruptedException, IOException {
 275         webView.mouse().click();
 276         separator.mouse().click();
 277         check("separator");
 278         ScreenshotUtils.checkScreenshot("RichTextEditor-separator", webView);
 279     }
 280 
 281     @ScreenshotCheck
 282     @Test(timeout = 300000)
 283     @Keywords(keywords="webkit")
 284     public void alignmentTest() throws InterruptedException, IOException, Throwable {
 285         typeText(ALIGNMENT_TEXT);
 286         webView.keyboard().pushKey(KeyboardButtons.A, CTRL_DOWN_MASK_OS);
 287         alignment(left, "left");
 288         alignment(right, "right");
 289         alignment(center, "center");
 290         alignment(adjust, "adjust");
 291 
 292         kbdClear();
 293 
 294         Map<Wrap<? extends ToggleButton>, String> map = new LinkedHashMap<Wrap<? extends ToggleButton>, String>();
 295         map.put(left, "left");
 296         map.put(right, "right");
 297         map.put(center, "center");
 298         map.put(adjust, "adjust");
 299 
 300         for (int j = 0; j < map.size(); j++) {
 301             Entry<Wrap<? extends ToggleButton>, String> param = (Entry<Wrap<? extends ToggleButton>, String>) map.entrySet().toArray()[j];
 302             param.getKey().as(Selectable.class, Boolean.class).selector().select(true);
 303             typeText(param.getValue() + "\n");
 304         }
 305 
 306         moveToTextBegin();
 307 
 308         for (int j = 0; j < map.size(); j++) {
 309             Entry<Wrap<? extends ToggleButton>, String> param = (Entry<Wrap<? extends ToggleButton>, String>) map.entrySet().toArray()[j];
 310             param.getKey().waitProperty(TextControlWrap.SELECTED_PROP_NAME, true);
 311             webView.keyboard().pushKey(KeyboardButtons.END);
 312             param.getKey().waitProperty(TextControlWrap.SELECTED_PROP_NAME, true);
 313             pushKey(KeyboardButtons.DOWN, 1);
 314         }
 315 
 316         throwScreenshotError();
 317     }
 318 
 319     @ScreenshotCheck
 320     @Test(timeout = 300000)
 321     @Keywords(keywords = "webkit")
 322     public void fontSizeTest() throws InterruptedException, IOException, Throwable {
 323         //We need to change step of scrolling, because list view behavior doesn't allow to select the last item.
 324         final int val = Math.round(((CaspianDriverFactory) ThemeDriverFactory.getThemeFactory()).getDragDelta());
 325         ((CaspianDriverFactory) ThemeDriverFactory.getThemeFactory()).setDragDelta(20);
 326         attributes(fontSize, "size");
 327         ((CaspianDriverFactory) ThemeDriverFactory.getThemeFactory()).setDragDelta(val);
 328         reset();
 329     }
 330 
 331     @ScreenshotCheck
 332     @Test(timeout = 300000)
 333     @Keywords(keywords="webkit")
 334     public void fontStyleTest() throws InterruptedException, IOException, Throwable {
 335         attributes(fontStyle, "style", 4);
 336     }
 337 
 338     @ScreenshotCheck
 339     @Test(timeout = 300000) //rt -- 20500 update when possible
 340     @Keywords(keywords="webkit")
 341     public void paragraphTest() throws InterruptedException, IOException, Throwable {
 342         final Parent<RadioMenuItem> attributes = paragraph.as(Parent.class, RadioMenuItem.class);
 343         for (int i = 0; i < attributes.lookup().size(); i++) {
 344             Wrap<? extends RadioMenuItem> attribute = attributes.lookup().wrap(i);
 345             attribute.mouse().click();
 346             typeText(getAttributeText("paragraph", attribute.getControl().getText()) + "\n");
 347         }
 348 
 349         moveToTextBegin();
 350 
 351         paragraph.waitProperty(Wrap.TEXT_PROP_NAME, attributes.lookup().wrap(0).getControl().getText());
 352         for (int i = 0; i < attributes.lookup().size(); i++) {
 353             Wrap<? extends RadioMenuItem> attribute = attributes.lookup().wrap(i);
 354             paragraph.waitProperty(Wrap.TEXT_PROP_NAME, attribute.getControl().getText());
 355             pushKey(KeyboardButtons.DOWN, 1);
 356         }
 357 
 358         check("paragraph");
 359 
 360         checkScreenshot("RichTextEditor-font-paragraph", webView);
 361 
 362         webView.keyboard().pushKey(KeyboardButtons.A, CTRL_DOWN_MASK_OS);
 363         checkScreenshot("RichTextEditor-font-paragraph-selected", webView);
 364 
 365         throwScreenshotError();
 366     }
 367 
 368     @ScreenshotCheck
 369     @Test(timeout = 300000)
 370     public void typefaceTest() throws InterruptedException, IOException, Throwable {
 371         Map<Wrap<? extends ToggleButton>, String> map = new LinkedHashMap<Wrap<? extends ToggleButton>, String>();
 372         map.put(bold, "bold");
 373         map.put(italic, "italic");
 374         map.put(underline, "underline");
 375         map.put(crossed, "crossed");
 376 
 377         for (Integer i = 0; i < (1 << map.size()); i++) {
 378             String text = new String();
 379             for (int j = 0; j < map.size(); j++) {
 380                 Entry<Wrap<? extends ToggleButton>, String> param = (Entry<Wrap<? extends ToggleButton>, String>) map.entrySet().toArray()[j];
 381                 Boolean selected = ((i >> j) & 1) > 0;
 382                 param.getKey().as(Selectable.class, Boolean.class).selector().select(selected);
 383                 text += (selected ? "" : "not ") + param.getValue() + " ";
 384             }
 385             typeText(text);
 386         }
 387 
 388         moveToTextBegin();
 389 
 390         for (int j = 0; j < map.size(); j++) {
 391             Wrap<? extends ToggleButton> wrap = (Wrap<? extends ToggleButton>) map.keySet().toArray()[j];
 392             wrap.waitProperty(TextControlWrap.SELECTED_PROP_NAME, false);
 393         }
 394         pushKey(KeyboardButtons.RIGHT, 1);
 395         for (Integer i = 0; i < (1 << map.size()); i++) {
 396             String text = new String();
 397             for (int j = 0; j < map.size(); j++) {
 398                 Entry<Wrap<? extends ToggleButton>, String> param = (Entry<Wrap<? extends ToggleButton>, String>) map.entrySet().toArray()[j];
 399                 Boolean selected = ((i >> j) & 1) > 0;
 400                 param.getKey().waitProperty(TextControlWrap.SELECTED_PROP_NAME, selected);
 401                 text += (selected ? "" : "not ") + param.getValue() + " ";
 402             }
 403             pushKey(KeyboardButtons.RIGHT, text.length());
 404         }
 405 
 406         checkScreenshot("RichTextEditor-typeface", webView);
 407 
 408         webView.keyboard().pushKey(KeyboardButtons.A, CTRL_DOWN_MASK_OS);
 409         checkScreenshot("RichTextEditor-typeface-selected", webView);
 410 
 411         throwScreenshotError();
 412     }
 413 
 414     @ScreenshotCheck
 415     @Test(timeout = 300000)
 416     @Keywords(keywords="webkit")
 417     public void colorTest() throws InterruptedException, IOException, Throwable {
 418         for (int i = 0; i < 3; i++) {
 419             String fore = color(foreground, "foreground", i);
 420             for (int j = 3; j < 6; j++) {
 421                 String back = color(background, "background", j);
 422                 typeText("[" + fore + "; " + back + "] ");
 423             }
 424         }
 425         check("color");
 426 
 427         checkScreenshot("RichTextEditor-colors", webView);
 428 
 429         webView.keyboard().pushKey(KeyboardButtons.A, CTRL_DOWN_MASK_OS);
 430         checkScreenshot("RichTextEditor-colors-selected", webView);
 431 
 432         throwScreenshotError();
 433     }
 434 
 435     @ScreenshotCheck
 436     @Test(timeout = 300000)
 437     @Keywords(keywords="webkit")
 438     public void resetTest() throws InterruptedException, IOException, Throwable {
 439         for (int i = 0; i < 30; ++i) {
 440             reset();
 441         }
 442         checkScreenshot("RichTextEditor-reset", scene);
 443         throwScreenshotError();
 444     }
 445 
 446     @ScreenshotCheck
 447     @Test(timeout = 300000)
 448     @Keywords(keywords="webkit")
 449     public void countTest() throws InterruptedException, IOException, Throwable {
 450         countSequential(numbers, "number");
 451         Thread.sleep(500);
 452         countSequential(bullets, "bullet");
 453         check("count");
 454         checkScreenshot("RichTextEditor-count-sequential", webView);
 455         kbdClear();
 456         check("empty-count");
 457         checkScreenshot("RichTextEditor-count-clear", webView);
 458         throwScreenshotError();
 459     }
 460 
 461     @ScreenshotCheck
 462     @Test(timeout = 300000)
 463     @Keywords(keywords="webkit")
 464     public void countChangeTypeTest() throws InterruptedException, IOException, Throwable {
 465         countSequential(numbers, "number");
 466         check("count_numbers");
 467         webView.keyboard().pushKey(KeyboardButtons.A, CTRL_DOWN_MASK_OS);
 468         bullets.mouse().click();
 469         check("count_bullets");
 470         webView.keyboard().pushKey(KeyboardButtons.A, CTRL_DOWN_MASK_OS);
 471         numbers.mouse().click();
 472         check("count_numbers2");
 473         checkScreenshot("RichTextEditor-count-change-type", webView);
 474         throwScreenshotError();
 475     }
 476 
 477     @ScreenshotCheck
 478     @Test(timeout = 300000)
 479     @Keywords(keywords="webkit")
 480     public void countRemoveIndentTest() throws InterruptedException, IOException, Throwable {
 481         countSimple(numbers, "number");
 482         moveToTextBegin();
 483         removeIndent.mouse().click();
 484         check("count_numbers_remove_indent");
 485         checkScreenshot("RichTextEditor-indent-remove", webView);
 486         throwScreenshotError();
 487     }
 488 
 489     @ScreenshotCheck
 490     @Test(timeout = 300000)
 491     @Keywords(keywords="webkit")
 492     public void countIndentTest() throws InterruptedException, IOException, Throwable {
 493         countSimple(numbers, "number");
 494         check("simple_numbers");
 495         moveToTextBegin();
 496         for (int i = 0; i < SHORT_LIST_LENTGTH; i++) {
 497             indent.mouse().click();
 498             check("count_numbers_indent_" + i + "");
 499             checkScreenshot("RichTextEditor-indent-" + i, webView);
 500             removeIndent.mouse().click();
 501             //check("simple_numbers");
 502             webView.keyboard().pushKey(KeyboardButtons.DOWN);
 503         }
 504         throwScreenshotError();
 505     }
 506 
 507     @ScreenshotCheck
 508     @Test(timeout = 300000) //platform specific OK except bug 20500
 509     @Keywords(keywords="webkit")
 510     public void compositeTest() throws InterruptedException, IOException, Throwable {
 511         HashMap<Wrap, Integer> map = getAttributesMap();
 512         typeText(LINE);
 513 
 514         final int SHIFT = 4;
 515         final int RANGE = SHIFT * (map.size() + 1);
 516         assertTrue(2 * map.size() * SHIFT < LINE.length());
 517         for (int i = 0; i < map.size(); i++) {
 518             int start = i * SHIFT;
 519             selectRange(start, start + RANGE);
 520             Entry<Wrap, Integer> param = (Entry<Wrap, Integer>) map.entrySet().toArray()[i];
 521             int index = param.getValue();
 522             Wrap wrap = param.getKey();
 523             if (index == -1) {
 524                 wrap.mouse().click();
 525             } else {
 526                 if (ColorPicker.class.isAssignableFrom(wrap.getControl().getClass())) {
 527                     color(wrap, "", index);
 528                 } else {
 529                     selectAttribute(wrap, index);
 530                 }
 531             }
 532         }
 533         selectRange(0, 0);
 534         check("composite");
 535         checkScreenshot("RichTextEditor-composite", webView);
 536         throwScreenshotError();
 537     }
 538 
 539     @Smoke
 540     @Test(timeout = 300000) //http://javafx-jira.kenai.com/browse/RT-20554
 541     @Keywords(keywords="webkit")
 542     public void copyTest() throws InterruptedException, IOException, Throwable {
 543         clipboard(copy, "copy");
 544     }
 545 
 546     @Smoke
 547     @Test(timeout = 300000) //http://javafx-jira.kenai.com/browse/RT-20554
 548     @Keywords(keywords="webkit")
 549     public void cutTest() throws InterruptedException, IOException, Throwable {
 550         clipboard(cut, "cut");
 551     }
 552 
 553     @Smoke
 554     @Test(timeout = 300000)  //http://javafx-jira.kenai.com/browse/RT-20554
 555     @Keywords(keywords="webkit")
 556     public void pasteTest() throws InterruptedException, IOException, Throwable {
 557         typeText(ALIGNMENT_TEXT);
 558         webView.keyboard().pushKey(KeyboardButtons.A, CTRL_DOWN_MASK_OS);
 559         copy.mouse().click();
 560         webView.keyboard().pushKey(KeyboardButtons.DELETE);
 561         paste.mouse().click();
 562         System.out.println(getHTML());
 563         check("paste");
 564     }
 565 
 566 //    @ScreenshotCheck
 567 //    @Test(timeout=300000)
 568 //    public void undoRedoTest() throws InterruptedException, IOException, Throwable {
 569 //        typeText(SHORT_LIST);
 570 //        String html = htmlEditor.getControl().getHtmlText();
 571 //        undo.mouse().click();
 572 //        check("empty");
 573 //        redo.mouse().click();
 574 //        htmlEditor.waitState(new State<String>() {
 575 //            public String reached() {
 576 //                return htmlEditor.getControl().getHtmlText();
 577 //            }
 578 //        }, html);
 579 //    }
 580     protected void setParagraph(int num) throws InterruptedException {
 581         paragraph.mouse().click();
 582         final Parent<Node> attributes = (Parent<Node>) getPopupWrap().as(Parent.class, Node.class).lookup(ListView.class).wrap(0).as(Parent.class, Node.class);
 583         if (num < 0 || num > attributes.lookup(ListCell.class).size()) {
 584             num = 0;
 585         }
 586         attributes.lookup(ListCell.class).wrap(num).mouse().click();
 587         setDefaultFont();
 588     }
 589 
 590     protected void setFontSize(int num) throws InterruptedException {
 591         fontSize.mouse().click();
 592         final Parent<Node> attributes = (Parent<Node>) getPopupWrap().as(Parent.class, Node.class).lookup(ListView.class).wrap(0).as(Parent.class, Node.class);
 593         if (num < 0 || num > attributes.lookup(ListCell.class).size()) {
 594             num = 0;
 595         }
 596         attributes.lookup(ListCell.class).wrap(num).mouse().click();
 597     }
 598 
 599     protected void setFont(int num) throws InterruptedException {
 600         fontStyle.mouse().click();
 601         final Parent<Node> attributes = (Parent<Node>) getPopupWrap().as(Parent.class, Node.class).lookup(ListView.class).wrap(0).as(Parent.class, Node.class);
 602         if (num < 0 || num > attributes.lookup(ListCell.class).size()) {
 603             num = 0;
 604         }
 605         attributes.lookup(ListCell.class).wrap(num).mouse().click();
 606     }
 607 
 608     protected HashMap<Wrap, Integer> getAttributesMap() {
 609         HashMap<Wrap, Integer> map = new LinkedHashMap<Wrap, Integer>();
 610         map.put(fontSize, 4);
 611         map.put(fontStyle, 3);
 612         //map.put(paragraph, 2);
 613         map.put(bold, -1);
 614         map.put(italic, -1);
 615         map.put(underline, -1);
 616         map.put(crossed, -1);
 617         map.put(foreground, 3);
 618         map.put(background, 4);
 619         return map;
 620     }
 621 
 622     protected void clipboard(final Wrap<? extends Node> wrap, String html) throws IOException {
 623         typeText(ALIGNMENT_TEXT);
 624         webView.keyboard().pushKey(KeyboardButtons.A, CTRL_DOWN_MASK_OS);
 625         wrap.waitState(new State<Boolean>() {
 626 
 627             public Boolean reached() {
 628                 return new GetAction<Boolean>() {
 629 
 630                     @Override
 631                     public void run(Object... parameters) {
 632                         setResult(wrap.getControl().isDisabled());
 633                     }
 634                 }.dispatch(Root.ROOT.getEnvironment());
 635             }
 636         }, false);
 637         wrap.mouse().click();
 638         checkClipboard(html);
 639     }
 640 
 641     protected void selectAttribute(Wrap<? extends MenuButton> wrap, int index) {
 642         final Parent<RadioMenuItem> attributes = wrap.as(Parent.class, RadioMenuItem.class);
 643         Wrap<? extends RadioMenuItem> attribute = attributes.lookup().wrap(index);
 644         attribute.mouse().click();
 645     }
 646 
 647     protected void selectRange(int min, int max) {
 648         setPos(min);
 649         setPos(max, KeyboardModifiers.SHIFT_DOWN_MASK);
 650     }
 651     int current_pos = -1;
 652 
 653     protected void setPos(int pos, KeyboardModifiers... mdfs) {
 654         if (current_pos == -1 || mdfs.length == 0) {
 655             moveToTextBegin();
 656             current_pos = 0;
 657         }
 658         if (current_pos < pos) {
 659             pushKey(KeyboardButtons.RIGHT, pos - current_pos, mdfs);
 660         } else {
 661             pushKey(KeyboardButtons.LEFT, current_pos - pos, mdfs);
 662         }
 663         current_pos = pos;
 664     }
 665 
 666     public void countSequential(Wrap wrap, String name) throws InterruptedException, IOException, Throwable {
 667         wrap.mouse().click();
 668         typeText(SHORT_LIST);
 669         typeText("\n");
 670         wrap.mouse().click();
 671         typeText(SHORT_LIST);
 672         typeText("\n\n");
 673         wrap.mouse().click();
 674         typeText(SHORT_LIST);
 675     }
 676 
 677     public void countSimple(Wrap wrap, String name) throws InterruptedException, IOException, Throwable {
 678         wrap.mouse().click();
 679         setDefaultFont();
 680         typeText(SHORT_LIST);
 681         typeText("\n");
 682     }
 683 
 684     /**
 685      * Selects color from dropdown.
 686      * @param control - part of color picker visible on a panel.
 687      * @param name - just a name
 688      * @param num - index of the color
 689      * @return
 690      * @throws InterruptedException
 691      * @throws IOException
 692      * @throws Throwable 
 693      */
 694     protected String color(Wrap control, String name, int num) throws InterruptedException, IOException, Throwable {
 695         control.mouse().click();
 696         Wrap<? extends Scene> drop_scene = Root.ROOT.lookup(new LookupCriteria<Scene>() {
 697 
 698             public boolean check(Scene sc) {
 699                 return sc != scene.getControl() && sc.getWindow().isShowing();
 700             }
 701         }).wrap();
 702         Parent<Node> drop_scene_parent = drop_scene.as(Parent.class, Node.class);
 703         Lookup<Node> color_lookup = drop_scene_parent.lookup(new LookupCriteria<Node>() {
 704 
 705             public boolean check(Node cntrl) {
 706                 return cntrl.getStyleClass().contains("color-square") || cntrl.getStyleClass().contains("color-square-selected");
 707             }
 708         });
 709 
 710         Wrap wrap = color_lookup.wrap(num);
 711         double[] colors = getColors(wrap.getScreenImage());
 712         wrap.mouse().click();
 713         return name + ": (" + colors[0] + ", " + colors[1] + ", " + colors[2] + ")";
 714     }
 715 
 716     public void attributes(Wrap<? extends ComboBox> wrap, String name, int... counter) throws InterruptedException, IOException, Throwable {
 717         int c = 0;
 718         for (int i = 0; i < wrap.as(Selectable.class).getStates().size(); i++) {
 719             if (counter.length > 0) {
 720                 if (c++ >= counter[0]) {
 721                     break;
 722                 }
 723             }
 724             wrap.as(Selectable.class).selector().select(wrap.as(Selectable.class).getStates().get(i));
 725             typeText(getAttributeText(name, wrap.as(Selectable.class).getStates().get(i).toString()));
 726         }
 727 
 728         moveToTextBegin();
 729         checkComboBoxValue(wrap, wrap.as(Selectable.class).getStates().get(0).toString());
 730         pushKey(KeyboardButtons.RIGHT, 1);
 731         c = 0;
 732         for (int i = 0; i < wrap.as(Selectable.class).getStates().size(); i++) {
 733             if (counter.length > 0) {
 734                 if (c++ >= counter[0]) {
 735                     break;
 736                 }
 737             }
 738             checkComboBoxValue(wrap, wrap.as(Selectable.class).getStates().get(i).toString());
 739             pushKey(KeyboardButtons.RIGHT, getAttributeText(name, wrap.as(Selectable.class).getStates().get(i).toString()).length());
 740         }
 741 
 742         check(name);
 743 
 744         checkScreenshot("RichTextEditor-font-" + name, webView);
 745 
 746         webView.keyboard().pushKey(KeyboardButtons.A, CTRL_DOWN_MASK_OS);
 747         checkScreenshot("RichTextEditor-font-" + name + "-selected", webView);
 748 
 749         throwScreenshotError();
 750     }
 751 
 752     protected void checkComboBoxValue(final Wrap<? extends ComboBox> wrap, String expectedValue) {
 753         wrap.waitState(new State<String>() {
 754             public String reached() {
 755                 return new GetAction<String>() {
 756                     @Override
 757                     public void run(Object... os) throws Exception {
 758                         setResult(wrap.getControl().getValue().toString());
 759                     }
 760                 }.dispatch(Root.ROOT.getEnvironment());
 761             }
 762         }, expectedValue);
 763     }
 764 
 765     protected void alignment(Wrap wrap, String name) throws InterruptedException, IOException, Throwable {
 766         wrap.mouse().click();
 767         check(name + "_alignment");
 768         checkScreenshot("RichTextEditor-alignment-" + name, webView);
 769     }
 770 
 771     private List<MenuItem> getFonts() {
 772         return new GetAction<List<MenuItem>>() {
 773 
 774             @Override
 775             public void run(Object... os) throws Exception {
 776                 ArrayList res = new ArrayList();
 777                 int size = fontStyle.as(Parent.class, MenuItem.class).lookup().size();
 778                 for (int i = 0; i < size; i++) {
 779                     res.add(fontStyle.as(Parent.class, MenuItem.class).lookup().get(i));
 780                 }
 781                 setResult(res);
 782 
 783                 //setResult(((MenuButton)fontStyle.getControl()).getItems().listIterator());
 784             }
 785         }.dispatch(htmlEditor.getEnvironment());
 786     }
 787 
 788     protected void setFont(String name) {
 789         fontStyle.as(Selectable.class).selector().select(name);
 790 //       ListIterator<MenuItem> li = getFonts().listIterator();
 791 //       MenuItem mi;
 792 //       int i = 0;
 793 //       do {
 794 //        mi = li.next();
 795 //        i++;
 796 //       } while (!mi.getText().equals(name));
 797 //       setFont(--i);
 798     }
 799 
 800     private void setDefaultFont() {
 801         setFont(DEFAULT_TEXT_STYLE);
 802     }
 803 
 804     void reset() {
 805         resetBtn.mouse().click();
 806 
 807         webView = parent.lookup(WebView.class).wrap();
 808         webView.mouse().click();
 809 
 810         htmlEditor = parent.lookup(HTMLEditor.class).wrap();
 811         htmlEditorAsParent = htmlEditor.as(Parent.class, Node.class);
 812 
 813         cut = parent.lookup(Button.class).wrap(0);
 814         copy = parent.lookup(Button.class).wrap(1);
 815         paste = parent.lookup(Button.class).wrap(2);
 816 //        undo = parent.lookup(Button.class).wrap(3);
 817 //        redo = parent.lookup(Button.class).wrap(4);
 818         left = parent.lookup(ToggleButton.class).wrap(0);
 819         center = parent.lookup(ToggleButton.class).wrap(1);
 820         right = parent.lookup(ToggleButton.class).wrap(2);
 821         adjust = parent.lookup(ToggleButton.class).wrap(3);
 822         bullets = parent.lookup(ToggleButton.class).wrap(4);
 823         numbers = parent.lookup(ToggleButton.class).wrap(5);
 824         indent = parent.lookup(Button.class).wrap(3);
 825         removeIndent = parent.lookup(Button.class).wrap(4);
 826         separator = parent.lookup(Button.class).wrap(5);
 827 
 828         paragraph = parent.lookup(ComboBox.class).wrap(0);
 829         fontStyle = parent.lookup(ComboBox.class).wrap(1);
 830         fontSize = parent.lookup(ComboBox.class).wrap(2);
 831 
 832         bold = parent.lookup(ToggleButton.class).wrap(6);
 833         italic = parent.lookup(ToggleButton.class).wrap(7);
 834         underline = parent.lookup(ToggleButton.class).wrap(8);
 835         crossed = parent.lookup(ToggleButton.class).wrap(9);
 836 
 837         foreground = parent.lookup(ColorPicker.class).wrap(0);
 838         background = parent.lookup(ColorPicker.class).wrap(1);
 839         setDefaultFont();
 840     }
 841 
 842     private String getHTMLName(String name) {
 843         String plsSpecName = PLATFORM_TAG + name;
 844         File plSpec;
 845         URL url = getClass().getResource(plsSpecName + ".html");
 846         if (url != null) {
 847             plSpec = new File(url.getFile());
 848             if (plSpec != null && plSpec.exists()) {
 849                 return plsSpecName;
 850             }
 851         }
 852         //If no win8, use other win.
 853         if (PLATFORM_TAG.contains("win8_") && url == null) {
 854             plsSpecName = "win_" + name;
 855             url = getClass().getResource(plsSpecName + ".html");
 856             if (url != null) {
 857                 plSpec = new File(url.getFile());
 858                 if (plSpec != null && plSpec.exists()) {
 859                     return plsSpecName;
 860                 }
 861             }
 862         }
 863         
 864         System.out.println("there is no platform specific html for name <" + name + ">.");
 865         return name;
 866     }
 867 
 868     protected void check(final String html) throws IOException, FileNotFoundException {
 869         System.out.println(readResource(getHTMLName(html) + ".html"));
 870         try {
 871             htmlEditor.waitState(new State<String>() {
 872 
 873                 public String reached() {
 874                     System.out.println(htmlEditor.getControl().getHtmlText());
 875                     return htmlEditor.getControl().getHtmlText();
 876                 }
 877             }, readResource(getHTMLName(html) + ".html"));
 878         } finally {
 879             Writer out = new OutputStreamWriter(new FileOutputStream(ImagesManager.getInstance().getHTMLPath(html)));
 880             try {
 881                 out.write("Found : " + htmlEditor.getControl().getHtmlText() + "\n");
 882                 out.write("Expected : " + readResource(getHTMLName(html) + ".html") + "\n");
 883             } finally {
 884                 out.close();
 885             }
 886         }
 887     }
 888 
 889     protected void checkClipboard(String html) throws IOException {
 890         try {
 891             htmlEditor.waitState(new State<String>() {
 892 
 893                 public String reached() {
 894                     return getClipboardHTML();
 895                 }
 896             }, readResource(getHTMLName(html) + ".html"));
 897         } finally {
 898             Writer out = new OutputStreamWriter(new FileOutputStream(ImagesManager.getInstance().getHTMLPath(html)));
 899             try {
 900                 out.write(getClipboardHTML());
 901             } finally {
 902                 out.close();
 903             }
 904         }
 905     }
 906 
 907     protected void typeText(String text) {
 908         for (int i = 0; i < text.length(); i++) {
 909             char c = text.charAt(i);
 910             if (c == '\n') {
 911                 webView.keyboard().pushKey(KeyboardButtons.ENTER);
 912             } else {
 913                 webView.keyboard().typeChar(text.charAt(i), ZERO_TIMEOUT);
 914             }
 915         }
 916     }
 917 
 918     protected String readResource(String name) throws IOException {
 919         URL url = RichTextEditorTest.class.getResource(name);
 920         assertNotNull(url);
 921         BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
 922         StringBuilder result = new StringBuilder();
 923         while (true) {
 924             int c = reader.read();
 925             if (c == -1) {
 926                 break;
 927             }
 928             result.append((char) c);
 929         }
 930         return result.toString();
 931     }
 932 
 933     protected String getClipboardHTML() {
 934         return new GetAction<String>() {
 935 
 936             @Override
 937             public void run(Object... os) throws Exception {
 938                 setResult(Clipboard.getSystemClipboard().getHtml());
 939             }
 940         }.dispatch(htmlEditor.getEnvironment());
 941     }
 942 
 943     protected String getHTML() {
 944         return new GetAction<String>() {
 945 
 946             @Override
 947             public void run(Object... parameters) {
 948                 setResult(htmlEditor.getControl().getHtmlText());
 949             }
 950         }.dispatch(Root.ROOT.getEnvironment());
 951     }
 952 
 953     protected void setHTML(final String html) {
 954         new GetAction() {
 955 
 956             @Override
 957             public void run(Object... parameters) {
 958                 htmlEditor.getControl().setHtmlText(html);
 959             }
 960         }.dispatch(Root.ROOT.getEnvironment());
 961     }
 962 
 963     protected String getAttributeText(String attribute, String value) {
 964         return attribute + " " + value + " ";
 965     }
 966 
 967     protected void pushKey(KeyboardButton kb, int count, KeyboardModifiers... mods) {
 968         for (int k = 0; k < count; k++) {
 969             webView.keyboard().pushKey(ZERO_TIMEOUT, kb, mods);
 970         }
 971     }
 972 
 973     protected void kbdClear() {
 974         webView.keyboard().pushKey(KeyboardButtons.A, CTRL_DOWN_MASK_OS);
 975         webView.keyboard().pushKey(KeyboardButtons.DELETE);
 976     }
 977 
 978     protected void moveToTextBegin() {
 979         if (Utils.isMacOS()) {
 980             webView.keyboard().pushKey(KeyboardButtons.UP, KeyboardModifiers.META_DOWN_MASK);
 981         } else {
 982             webView.keyboard().pushKey(KeyboardButtons.HOME, KeyboardModifiers.CTRL_DOWN_MASK);
 983         }
 984     }
 985 
 986     private Wrap<? extends Scene> getPopupWrap() throws InterruptedException {
 987         Wrap<? extends Scene> temp;
 988         try {
 989             temp = Root.ROOT.lookup(new ByWindowType(PopupWindow.class)).lookup(Scene.class).wrap(0);
 990         } catch (Exception e) {
 991             return null;
 992         }
 993         return temp;
 994     }
 995     final static String SOME_TEXT = "some text";
 996     final static String HELLO_WORLD = "Hello, World!";
 997     final static String SOME_OTHER_TEXT = "some more text";
 998     final static String HTML_SAMPLE_TEXT = "<html><head></head><body contenteditable=\"true\"><div style=\"text-align: left;\"><div style=\"text-align: left;\">\"<b>Sing, O goddess, the anger of<i> </i></b><i>Achilles <u>son </u></i><u>of Pele<strike>us, that brou</strike></u>ght&nbsp;</div><hr><h5>c<font class=\"Apple-style-span\" face=\"CordiaUPC\">ountless ills up</font>o<font class=\"Apple-style-span\" size=\"4\">n the Achaeans. Many<font class=\"Apple-style-span\" face=\"'Comic Sans MS'\"> </font></font><font class=\"Apple-style-span\" face=\"'Comic Sans MS'\">a brave sou</font><font class=\"Apple-style-span\" face=\"David\">l <font class=\"Apple-style-span\" size=\"4\">di</font></font><font class=\"Apple-style-span\" face=\"David\" style=\"font-size: large; \">d it send hurrying down to Hades, and many a hero did it yield a prey to dogs and </font><font class=\"Apple-style-span\" face=\"'DejaVu Sans Mono'\" style=\"font-size: large; \">vultures, for so</font><font class=\"Apple-style-span\" size=\"4\"> were the counsels of Jove fulfilled from the day on which the son of Atr</font><font class=\"Apple-style-span\" face=\"BrowalliaUPC\" size=\"3\">eus, king of men, and great A</font><font class=\"Apple-style-span\" size=\"4\">chilles, first fell out with one another.\";</font></h5><p><br></p></div></body></html>";
 999     final static Timeout ZERO_TIMEOUT = new Timeout("KbdType", 0);
1000     final static String ALIGNMENT_TEXT = "Line 1 line 1 line 1 line 1 line 1 line 1 line 1 line 1 line 1\n"
1001             + "Line 2 line 2 line 2 line 2 line 2 line 2 line 2 line 2\n"
1002             + "Line 3 line 3 line 3 line 3 line 3 line 3 line 3\n"
1003             + "Line 4 line 4 line 4 line 4 line 4 line 4\n"
1004             + "Line 5 line 5 line 5 line 5 line 5\n"
1005             + "Line 6 line 6 line 6 line 6\n"
1006             + "Sing, O goddess, the anger of Achilles son of Peleus, that brought countless ills upon the Achaeans. Many a brave soul did it send hurrying down to Hades, and many a hero did it yield a prey to dogs and vultures, for so were the counsels of Jove fulfilled from the day on which the son of Atreus, king of men, and great Achilles, first fell out with one another.";
1007     final static String LIST = "Line 1 line 1 line 1 line 1 line 1 line 1 line 1 line 1 line 1 line 1 line 1 line 1 line 1 line 1\n"
1008             + "Line 2 line 2 line 2 line 2 line 2 line 2 line 2 line 2 line 2 line 2 line 2 line 2 line 2 line 2\n"
1009             + "Line 3 line 3 line 3 line 3 line 3 line 3 line 3 line 3 line 3 line 3 line 3 line 3 line 3 line 3\n"
1010             + "Line 4 line 4 line 4 line 4 line 4 line 4 line 4 line 4 line 4 line 4 line 4 line 4 line 4 line 4\n"
1011             + "Line 5 line 5 line 5 line 5 line 5 line 5 line 5 line 5 line 5 line 5 line 5 line 5 line 5 line 5\n"
1012             + "Line 6 line 6 line 6 line 6 line 6 line 6 line 6 line 6 line 6 line 6 line 6 line 6 line 6 line 6\n";
1013     final static int SHORT_LIST_LENTGTH = 4;
1014     final static int HEADING1 = 1;
1015     final static int HEADING2 = 2;
1016     final static int HEADING6 = 6;
1017     final static int XX_LARGE_FONT_SIZE = 6;
1018     final static String SHORT_LIST = "Line 1\n"
1019             + "Line 2\n"
1020             + "Line 3\n"
1021             + "Line 4\n";
1022     final static String LINE = "Item 01 item 02 item 03 item 04 item 05 item 06 item 07 item 08 item 09 item 10 item 11";
1023 }