1 /*
   2  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation. Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package javafx.scene.control.test.cell;
  26 
  27 import client.test.Smoke;
  28 import com.sun.glass.ui.Application;
  29 import com.sun.javafx.scene.control.LabeledText;
  30 import java.util.ArrayList;
  31 import java.util.List;
  32 import javafx.collections.ObservableList;
  33 import javafx.scene.Node;
  34 import javafx.scene.Scene;
  35 import javafx.scene.control.*;
  36 import javafx.scene.control.test.ControlsTestBase;
  37 import javafx.scene.control.test.cellapps.CellCustomStringConverter;
  38 import javafx.scene.control.test.cellapps.CellsApp;
  39 import static javafx.scene.control.test.cellapps.CellsApp.*;
  40 import javafx.scene.control.test.cellapps.CellsApp.CellType;
  41 import javafx.scene.control.test.cellapps.CellsApp.DataItem;
  42 import org.jemmy.action.GetAction;
  43 import org.jemmy.control.Wrap;
  44 import org.jemmy.fx.ByID;
  45 import org.jemmy.fx.ByText;
  46 import org.jemmy.fx.Root;
  47 import org.jemmy.interfaces.Keyboard.KeyboardButtons;
  48 import org.jemmy.interfaces.Keyboard.KeyboardModifiers;
  49 import org.jemmy.interfaces.Parent;
  50 import org.jemmy.interfaces.Selectable;
  51 import org.jemmy.interfaces.Text;
  52 import org.jemmy.lookup.Lookup;
  53 import org.jemmy.lookup.LookupCriteria;
  54 import org.jemmy.timing.State;
  55 import org.junit.After;
  56 import static org.junit.Assert.assertEquals;
  57 import org.junit.Test;
  58 import org.junit.runner.RunWith;
  59 import test.javaclient.shared.FilteredTestRunner;
  60 import test.javaclient.shared.Utils;
  61 
  62 @RunWith(FilteredTestRunner.class)
  63 public abstract class CellsTestBase extends ControlsTestBase {
  64 
  65     protected static Wrap<? extends Scene> scene = null;
  66     protected static Parent<Node> parent = null;
  67     protected static String cellID = null;
  68     protected static String choiceID = null;
  69     protected static Wrap<? extends Control> testedControl = null;
  70 
  71     protected static void updateWraps() {
  72         scene = Root.ROOT.lookup().wrap();
  73         parent = scene.as(Parent.class, Node.class);
  74     }
  75 
  76     protected abstract Wrap select(String data);
  77 
  78     protected abstract ObservableList<DataItem> getCurrentProgramValues();
  79 
  80     @After
  81     public void tearDown() throws InterruptedException {
  82         Wrap error = parent.lookup(Label.class, new ByID<Label>(ERROR_LABEL_ID)).wrap();
  83         assertEquals("", error.getProperty(Wrap.TEXT_PROP_NAME));
  84         new GetAction() {
  85             @Override
  86             public void run(Object... os) throws Exception {
  87                 ((Button) os[0]).getOnAction().handle(null);
  88             }
  89         }.dispatch(Root.ROOT.getEnvironment(), parent.lookup(Button.class, new ByID(RESET_SCENE_BTN_ID)).wrap().getControl());
  90     }
  91 
  92     @Smoke
  93     @Test(timeout = 300000)
  94     public void enterTextTest() throws InterruptedException {
  95         doFactoryChange(CellType.CustomCell);
  96         startEditingByMouse("Data item 0");
  97 
  98         String newData = "New data";
  99         Wrap<? extends TextField> edit_wrap = parent.lookup(TextField.class, new ByID<TextField>(cellID)).wrap();
 100         edit_wrap.keyboard().pushKey(KeyboardButtons.A, Utils.isMacOS() ? KeyboardModifiers.META_DOWN_MASK : KeyboardModifiers.CTRL_DOWN_MASK);
 101         edit_wrap.as(Text.class).type(newData);
 102         commitEditing(newData);
 103         select(newData);
 104     }
 105 
 106     @Smoke
 107     @Test(timeout = 300000)
 108     public void escapeEditingTest() throws Exception {
 109         doFactoryChange(CellType.CustomCell);
 110         startEditingByMouse("Data item 3");
 111 
 112         String newData = "New data";
 113         Wrap<? extends TextField> edit_wrap = parent.lookup(TextField.class, new ByID<TextField>(cellID)).wrap();
 114         edit_wrap.mouse().click();
 115         edit_wrap.keyboard().pushKey(KeyboardButtons.A, Utils.isMacOS() ? KeyboardModifiers.META_DOWN_MASK : KeyboardModifiers.CTRL_DOWN_MASK);
 116         edit_wrap.as(Text.class).type(newData);
 117         escapeEditing(newData);
 118 
 119         try {
 120             select(newData);
 121         } catch (Exception ex) {
 122             ex.printStackTrace();
 123             return;
 124         }
 125 
 126         throw new Exception("Test fails, because we've found item, which should be, because editing was escaped");
 127     }
 128 
 129     @Smoke
 130     @Test(timeout = 300000)
 131     public void editInnerSelectionTest() throws InterruptedException {
 132         doFactoryChange(CellType.CustomCell);
 133         Wrap<String> item_wrap = startEditingByMouse("Data item 3");
 134         item_wrap.mouse().click();
 135         testedControl.as(Parent.class, Node.class).lookup(TextField.class, new ByID<TextField>(cellID)).wait(1);
 136     }
 137 
 138     @Smoke
 139     @Test(timeout = 300000)
 140     public void editFocusTest() throws InterruptedException {
 141         doFactoryChange(CellType.CustomCell);
 142         startEditingByMouse("Data item 3");
 143         scene.keyboard().pushKey(KeyboardButtons.TAB);
 144         testedControl.as(Parent.class, Node.class).lookup(TextField.class, new ByID<TextField>(cellID)).wait(1);
 145     }
 146 
 147     @Smoke
 148     @Test(timeout = 300000)
 149     public void clickOtherItemTest() throws InterruptedException {
 150         doFactoryChange(CellType.CustomCell);
 151         startEditingByMouse("Data item 3");
 152         select("Data item 2");
 153         scene.waitState(new State<Integer>() {
 154             public Integer reached() {
 155                 return parent.lookup(TextField.class, new ByID<TextField>(cellID)).size();
 156             }
 157         }, 0);
 158     }
 159 
 160     @Smoke
 161     @Test(timeout = 300000)
 162     public void editOtherItemTest() throws InterruptedException {
 163         doFactoryChange(CellType.CustomCell);
 164         select("Data item 5");
 165         startEditingByMouse("Data item 3");
 166         startEditingByMouse("Data item 2");
 167         parent.lookup(TextField.class, new ByID<TextField>(cellID)).wait(1);
 168     }
 169 
 170     @Smoke
 171     @Test(timeout = 300000)
 172     public void commonCheckBoxFactoryWithMouseTest() {
 173         doCommonCheckOfChanger(CellType.CheckBox, Boolean.FALSE, Boolean.TRUE, Boolean.TRUE, null, WayOfEditing.ByMouse);
 174     }
 175 
 176     @Smoke
 177     @Test(timeout = 300000)
 178     public void commonCheckBoxFactoryWithKeyboardTest() {
 179         doCommonCheckOfChanger(CellType.CheckBox, Boolean.FALSE, Boolean.TRUE, Boolean.TRUE, null, WayOfEditing.ByKeyboard);
 180     }
 181 
 182     @Smoke
 183     @Test(timeout = 300000)
 184     public void commonChoiceBoxFacoryWithMouseTest() {
 185         doCommonCheckOfChanger(CellType.ChoiceBox, data.get(5), someValues.get(1), someValues.get(1), new CellCustomStringConverter().toString(someValues.get(1).toString()), WayOfEditing.ByMouse);
 186     }
 187 
 188     @Smoke
 189     @Test(timeout = 300000)
 190     public void commonChoiceBoxFacoryWithKeyboardTest() {
 191         doCommonCheckOfChanger(CellType.ChoiceBox, data.get(3), someValues.get(2), someValues.get(2), new CellCustomStringConverter().toString(someValues.get(2).toString()), WayOfEditing.ByKeyboard);
 192     }
 193 
 194     @Smoke
 195     @Test(timeout = 300000)
 196     public void commonComboBoxFacoryWithMouseTest() {
 197         doCommonCheckOfChanger(CellType.ComboBox, data.get(8), someValues.get(2), someValues.get(2), new CellCustomStringConverter().toString(someValues.get(2).toString()), WayOfEditing.ByMouse);
 198     }
 199 
 200     @Smoke
 201     @Test(timeout = 300000)
 202     public void commonComboBoxFacoryWithKeyboardTest() {
 203         doCommonCheckOfChanger(CellType.ComboBox, data.get(4), someValues.get(0), someValues.get(0), new CellCustomStringConverter().toString(someValues.get(0).toString()), WayOfEditing.ByKeyboard);
 204     }
 205 
 206     @Smoke
 207     @Test(timeout = 300000)
 208     public void commonTextFieldFacoryWithMouseTest() {
 209         doCommonCheckOfChanger(CellType.TextField, data.get(7), someValues.get(0), new CellCustomStringConverter().fromString(someValues.get(0).toString()),
 210                 new CellCustomStringConverter().toString(new CellCustomStringConverter().fromString(someValues.get(0).toString())), WayOfEditing.ByMouse);
 211     }
 212 
 213     @Smoke
 214     @Test(timeout = 300000)
 215     public void commonTextFieldFacoryWithKeyboardTest() {
 216         doCommonCheckOfChanger(CellType.TextField, data.get(2), someValues.get(1), new CellCustomStringConverter().fromString(someValues.get(1).toString()),
 217                 new CellCustomStringConverter().toString(new CellCustomStringConverter().fromString(someValues.get(1).toString())), WayOfEditing.ByKeyboard);
 218     }
 219 
 220     @Smoke
 221     @Test(timeout = 300000)
 222     public void commonCustomTextFieldFacoryWithMouseTest() {
 223         doCommonCheckOfChanger(CellType.CustomCell, data.get(7), someValues.get(0), new CellCustomStringConverter().fromString(someValues.get(0).toString()),
 224                 new CellCustomStringConverter().toString(new CellCustomStringConverter().fromString(someValues.get(0).toString())), WayOfEditing.ByMouse);
 225     }
 226 
 227     @Smoke
 228     @Test(timeout = 300000)
 229     public void commonCustomTextFieldFacoryWithKeyboardTest() {
 230         doCommonCheckOfChanger(CellType.CustomCell, data.get(2), someValues.get(1), new CellCustomStringConverter().fromString(someValues.get(1).toString()),
 231                 new CellCustomStringConverter().toString(new CellCustomStringConverter().fromString(someValues.get(1).toString())), WayOfEditing.ByKeyboard);
 232     }
 233 
 234     protected Wrap startEditingByMouse(String data) {
 235         Wrap<? extends DataItem> wrap = select(data);
 236         wrap.mouse().click();
 237         return wrap;
 238     }
 239 
 240     protected Wrap startEditingByKeyboard(String data) {
 241         Wrap<? extends DataItem> wrap = select(data);
 242         wrap.keyboard().pushKey(KeyboardButtons.F2);
 243         return wrap;
 244     }
 245 
 246     protected void escapeEditing(String data) {
 247         parent.lookup(TextField.class, new ByText<TextField>(data)).wrap().keyboard().pushKey(KeyboardButtons.ESCAPE);
 248     }
 249 
 250     protected void commitEditing(String data) {
 251         parent.lookup(TextField.class, new ByText<TextField>(data)).wrap().keyboard().pushKey(KeyboardButtons.ENTER);
 252     }
 253 
 254     protected void doCommonCheckOfChanger(CellsApp.CellType cellType, Object editableValue, Object newValue, Object expectedValue, String expectedValueRepresentation, WayOfEditing way) {
 255         doFactoryChange(cellType);
 256         checkShowingChangeAfterTypeOfFactoryChanging(cellType);
 257         changeValue(cellType, way, editableValue, newValue);
 258         checkValueChangingProgrammly(expectedValue, cellType.equals(CellType.CheckBox) ? ValueType.Bool : ValueType.Str);
 259         checkValueChangingByShowing(expectedValueRepresentation, cellType);
 260     }
 261 
 262     protected void doFactoryChange(final CellsApp.CellType cellType) {
 263         final Wrap<? extends ComboBox<CellType>> comboBox = parent.lookup(ComboBox.class, new ByID(choiceID)).wrap();
 264         Application.invokeAndWait(new Runnable() {
 265 
 266             @Override
 267             public void run() {
 268                 try {
 269                     comboBox.getControl().getSelectionModel().select(cellType);
 270                 } catch (Throwable ex) {
 271                     ex.printStackTrace();
 272                 }
 273             }
 274         });
 275     }
 276 
 277     protected void changeValue(CellsApp.CellType cellType, WayOfEditing way, Object editableValue, final Object newValue) {
 278         if (!cellType.equals(CellType.CheckBox)) {
 279             switch (way) {
 280                 case ByKeyboard:
 281                     startEditingByKeyboard(editableValue.toString());
 282                     break;
 283                 case ByMouse:
 284                     startEditingByMouse(editableValue.toString());
 285             }
 286         }
 287 
 288         switch (cellType) {
 289             case CheckBox:
 290                 Lookup lookup = testedControl.as(Parent.class, Node.class).lookup(CheckBox.class);
 291                 int size = lookup.size();
 292                 assertEquals(size, dataItemsSize + (testedControl.getControl() instanceof TreeView ? 1 : 0), 0);
 293                 for (int i = 0; i < size; i++) {
 294                     if (way == WayOfEditing.ByMouse) {
 295                         lookup.wrap(i).mouse().click();
 296                     } else {
 297                         new GetAction() {
 298                             @Override
 299                             public void run(Object... os) throws Exception {
 300                                 ((Control) os[0]).requestFocus();
 301                             }
 302                         }.dispatch(Root.ROOT.getEnvironment(), (Control) lookup.wrap(i).getControl());//Otherwise it use mouse click to get focus and make "selected" value changed.
 303                         lookup.wrap(i).keyboard().pushKey(KeyboardButtons.SPACE);
 304                     }
 305                 }
 306                 break;
 307             case ChoiceBox:
 308                 Lookup lookupChoiceBox = testedControl.as(Parent.class, Node.class).lookup(ChoiceBox.class);
 309                 final Wrap<? extends ChoiceBox> choiceBox = lookupChoiceBox.wrap();
 310                 choiceBox.waitState(new State<Boolean>() {
 311                     public Boolean reached() {
 312                         return choiceBox.getControl().isVisible();
 313                     }
 314                 }, true);
 315                 assertEquals(lookupChoiceBox.size(), 1, 0);
 316                 if (way == WayOfEditing.ByMouse) {
 317                     choiceBox.as(Selectable.class).selector().select(converter.toString(newValue));
 318                     choiceBox.waitState(new State<Boolean>() {
 319                         public Boolean reached() {
 320                             return choiceBox.getControl().getSelectionModel().getSelectedItem().equals(newValue);
 321                         }
 322                     }, true);
 323                 } else { //by keyboard
 324                     //choiceBox.keyboard().pushKey(KeyboardButtons.SPACE);
 325                     for (int i = 0; i < getIndexOfValueInChoiceBox(choiceBox, newValue) + 1; i++) {
 326                         choiceBox.keyboard().pushKey(KeyboardButtons.DOWN);
 327                     }
 328                     choiceBox.keyboard().pushKey(KeyboardButtons.ENTER);
 329                 }
 330                 break;
 331             case ComboBox:
 332                 Lookup lookupComboBox = testedControl.as(Parent.class, Node.class).lookup(ComboBox.class);
 333                 assertEquals(lookupComboBox.size(), 1, 0);
 334                 Wrap<? extends ComboBox> comboBox = lookupComboBox.wrap();
 335                 if (way == WayOfEditing.ByMouse) {
 336                     comboBox.as(Selectable.class).selector().select(newValue);
 337                 } else { //by keyboard
 338                     comboBox.keyboard().pushKey(KeyboardButtons.SPACE);
 339                     for (int i = 0; i < getIndexOfValueInComboBox(comboBox, newValue) + 1; i++) {
 340                         comboBox.keyboard().pushKey(KeyboardButtons.DOWN);
 341                     }
 342                     comboBox.keyboard().pushKey(KeyboardButtons.ENTER);
 343                 }
 344                 break;
 345             case TextField:
 346             case CustomCell:
 347                 Lookup lookupTextField = testedControl.as(Parent.class, Node.class).lookup(TextField.class);
 348                 assertEquals(lookupTextField.size(), 1, 0);
 349                 final Wrap<? extends TextField> textField = lookupTextField.wrap();
 350                 new GetAction() {
 351                     @Override
 352                     public void run(Object... os) throws Exception {
 353                         textField.getControl().requestFocus();
 354                     }
 355                 }.dispatch(Root.ROOT.getEnvironment());
 356                 textField.keyboard().pushKey(KeyboardButtons.HOME);
 357                 textField.keyboard().pushKey(KeyboardButtons.END, KeyboardModifiers.SHIFT_DOWN_MASK);
 358                 textField.keyboard().pushKey(KeyboardButtons.DELETE);
 359                 textField.as(Text.class).type(newValue.toString());
 360                 textField.keyboard().pushKey(KeyboardButtons.ENTER);
 361                 break;
 362             default:
 363                 throw new IllegalStateException("Unknown version");
 364         }
 365     }
 366 
 367     protected int getIndexOfValueInChoiceBox(final Wrap< ? extends ChoiceBox> choiceBox, final Object newValue) {
 368         return new GetAction<Integer>() {
 369             @Override
 370             public void run(Object... os) throws Exception {
 371                 setResult(choiceBox.getControl().getItems().indexOf(newValue));
 372             }
 373         }.dispatch(Root.ROOT.getEnvironment());
 374     }
 375 
 376     protected int getIndexOfValueInComboBox(final Wrap< ? extends ComboBox> comboBox, final Object newValue) {
 377         return new GetAction<Integer>() {
 378             @Override
 379             public void run(Object... os) throws Exception {
 380                 setResult(comboBox.getControl().getItems().indexOf(newValue));
 381             }
 382         }.dispatch(Root.ROOT.getEnvironment());
 383     }
 384 
 385     protected void checkValueChangingByShowing(final String expectedValue, CellType cellType) {
 386         if (!cellType.equals(CellType.CheckBox)) {
 387             final int size = testedControl.as(Parent.class, Node.class).lookup(new LookupCriteria<Node>() {
 388                 public boolean check(Node cntrl) {
 389                     return (cntrl instanceof LabeledText)
 390                             && ((LabeledText) cntrl).getText().equals(expectedValue)
 391                             && cntrl.isVisible();
 392                 }
 393             }).lookup().size();
 394             assertEquals("Failed to lookup visible labeled with text [" + expectedValue + "]", size, 1, 0);
 395         }
 396     }
 397 
 398     protected void checkShowingChangeAfterTypeOfFactoryChanging(CellType cellType) {
 399         testedControl.waitState(() -> {
 400             List<String> shownValues = new ArrayList<>();
 401             Lookup lookup = testedControl.as(Parent.class, Node.class).lookup(new LookupCriteria<Node>() {
 402                 @Override
 403                 public boolean check(final Node cntrl) {
 404                     if (cntrl instanceof LabeledText) {
 405                         boolean isVisible = new GetAction<Boolean>() {
 406 
 407                             @Override
 408                             public void run(Object... os) throws Exception {
 409                                 setResult(cntrl.isVisible());
 410                             }
 411                         }.dispatch(Root.ROOT.getEnvironment());
 412                         if (isVisible) {
 413                             return true;
 414                         }
 415                     }
 416                     return false;
 417                 }
 418             }).lookup();
 419             int size = lookup.size();
 420             for (int i = 0; i < size; i++) {
 421                 shownValues.add(new GetAction<String>() {
 422                     @Override
 423                     public void run(Object... os) throws Exception {
 424                         setResult(((LabeledText) os[0]).getText());
 425                     }
 426                 }.dispatch(Root.ROOT.getEnvironment(), (LabeledText) lookup.wrap(i).getControl()));
 427             }
 428 
 429             List<DataItem> failedAttemps = new ArrayList<>();
 430             for (DataItem item : data) {
 431                 int counter = 0;
 432                 for (String str : shownValues) {
 433                     if (str.contains(CellCustomStringConverter.TO_STRING_PREFIX) && str.contains(item.toString())) {
 434                         counter++;
 435                     }
 436                 }
 437                 if (counter != 1) {
 438                     System.out.println("For data item <" + item + "> cannot find proper representation.");
 439                     failedAttemps.add(item);
 440                 }
 441             }
 442             if (failedAttemps.isEmpty()) {
 443                 return true;
 444             } else {
 445                 return null;
 446             }
 447         });
 448     }
 449 
 450     protected void checkValueChangingProgrammly(Object expectedValue, ValueType type) {
 451         switch (type) {
 452             case Bool:
 453                 for (DataItem item : getCurrentProgramValues()) {
 454                     assertEquals((Boolean) expectedValue, item.choiceBoxChecker.getValue());
 455                 }
 456                 break;
 457             case Str:
 458                 int counter = 0;
 459                 for (DataItem item : getCurrentProgramValues()) {
 460                     if (item.toString().equals(expectedValue.toString())) {
 461                         counter++;
 462                     }
 463                 }
 464                 assertEquals(counter, 1, 0);
 465                 break;
 466             default:
 467                 throw new IllegalStateException("Unknown option");
 468         }
 469     }
 470 
 471     protected enum ValueType {
 472 
 473         Bool, Str
 474     };
 475 
 476     protected enum WayOfEditing {
 477 
 478         ByMouse, ByKeyboard
 479     };
 480 }