1 /*
   2  * Copyright (c) 2013, 2015, 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 
  26 package javafx.scene.control;
  27 
  28 import java.time.LocalDate;
  29 import java.time.chrono.*;
  30 import java.util.*;
  31 
  32 import com.sun.javafx.scene.control.infrastructure.KeyEventFirer;
  33 import com.sun.javafx.scene.control.infrastructure.KeyModifier;
  34 import com.sun.javafx.scene.control.infrastructure.StageLoader;
  35 import com.sun.javafx.tk.Toolkit;
  36 import javafx.beans.property.ObjectProperty;
  37 import javafx.beans.property.SimpleObjectProperty;
  38 import javafx.beans.property.SimpleStringProperty;
  39 import javafx.beans.property.StringProperty;
  40 import javafx.collections.FXCollections;
  41 import javafx.css.PseudoClass;
  42 import javafx.event.ActionEvent;
  43 import javafx.event.EventHandler;
  44 import javafx.scene.Node;
  45 import javafx.scene.Scene;
  46 import javafx.scene.input.KeyCode;
  47 import javafx.scene.layout.VBox;
  48 import javafx.util.Callback;
  49 import javafx.util.StringConverter;
  50 
  51 import static com.sun.javafx.scene.control.infrastructure.ControlTestUtils.assertStyleClassContains;
  52 
  53 import com.sun.javafx.scene.control.skin.DatePickerSkin;
  54 
  55 import org.junit.Before;
  56 import org.junit.Ignore;
  57 import org.junit.Test;
  58 
  59 import static org.junit.Assert.*;
  60 import static org.junit.Assert.assertEquals;
  61 
  62 public class DatePickerTest {
  63     private DatePicker datePicker;
  64     private final LocalDate today = LocalDate.now();
  65 
  66 
  67     /*********************************************************************
  68      *                                                                   *
  69      * Utility methods                                                   *
  70      *                                                                   *
  71      ********************************************************************/
  72 
  73     public Node getDisplayNode() {
  74         return ((DatePickerSkin)datePicker.getSkin()).getDisplayNode();
  75     }
  76 
  77 
  78 
  79     /*********************************************************************
  80      *                                                                   *
  81      * Setup                                                             *
  82      *                                                                   *
  83      ********************************************************************/
  84 
  85     @Before public void setup() {
  86         Locale.setDefault(Locale.forLanguageTag("en-US"));
  87         datePicker = new DatePicker();
  88     }
  89 
  90 
  91 
  92     /*********************************************************************
  93      *                                                                   *
  94      * Tests for the constructors                                        *
  95      *                                                                   *
  96      ********************************************************************/
  97 
  98     @Test public void noArgConstructorSetsTheStyleClass() {
  99         assertStyleClassContains(datePicker, "date-picker");
 100     }
 101 
 102     @Test public void noArgConstructor_valueIsNull() {
 103         assertNull(datePicker.getValue());
 104     }
 105 
 106     @Test public void noArgConstructor_editableIsTrue() {
 107         assertTrue(datePicker.isEditable());
 108     }
 109 
 110     @Test public void noArgConstructor_showingIsFalse() {
 111         assertFalse(datePicker.isShowing());
 112     }
 113 
 114     @Test public void noArgConstructor_promptTextIsEmptyString() {
 115         assertEquals("", datePicker.getPromptText());
 116     }
 117 
 118     @Test public void noArgConstructor_armedIsFalse() {
 119         assertFalse(datePicker.isArmed());
 120     }
 121 
 122     @Test public void noArgConstructor_converterIsNotNull() {
 123         assertNotNull(datePicker.getConverter());
 124     }
 125 
 126     @Test public void noArgConstructor_chronologyIsNotNull() {
 127         assertNotNull(datePicker.getChronology());
 128     }
 129 
 130     @Test public void noArgConstructor_dayCellFactoryIsNull() {
 131         assertNull(datePicker.getDayCellFactory());
 132     }
 133 
 134     @Test public void singleArgConstructorSetsTheStyleClass() {
 135         final DatePicker b2 = new DatePicker(today);
 136         assertStyleClassContains(b2, "date-picker");
 137     }
 138 
 139     @Test public void singleArgConstructor_valueIsArg() {
 140         final DatePicker b2 = new DatePicker(today);
 141         assertEquals(b2.getValue(), today);
 142     }
 143 
 144     @Test public void singleArgConstructor_editableIsTrue() {
 145         final DatePicker b2 = new DatePicker(today);
 146         assertTrue(b2.isEditable());
 147     }
 148 
 149     @Test public void singleArgConstructor_showingIsFalse() {
 150         final DatePicker b2 = new DatePicker(today);
 151         assertFalse(b2.isShowing());
 152     }
 153 
 154     @Test public void singleArgConstructor_promptTextIsEmptyString() {
 155         final DatePicker b2 = new DatePicker(today);
 156         assertEquals("", b2.getPromptText());
 157     }
 158 
 159     @Test public void singleArgConstructor_armedIsFalse() {
 160         final DatePicker b2 = new DatePicker(today);
 161         assertEquals(false, b2.isArmed());
 162     }
 163 
 164     @Test public void singleArgConstructor_converterIsNotNull() {
 165         final DatePicker b2 = new DatePicker(today);
 166         assertNotNull(b2.getConverter());
 167     }
 168 
 169     @Test public void singleArgConstructor_chronologyIsNotNull() {
 170         final DatePicker b2 = new DatePicker(today);
 171         assertNotNull(b2.getChronology());
 172     }
 173 
 174     @Test public void singleArgConstructor_dayCellFactoryIsNull() {
 175         final DatePicker b2 = new DatePicker(today);
 176         assertNull(b2.getDayCellFactory());
 177     }
 178 
 179 
 180     /*********************************************************************
 181      * Tests for default values                                         *
 182      ********************************************************************/
 183 
 184     @Test public void checkPromptTextPropertyName() {
 185         assertTrue(datePicker.promptTextProperty().getName().equals("promptText"));
 186     }
 187 
 188     @Test public void checkValuePropertyName() {
 189         assertTrue(datePicker.valueProperty().getName().equals("value"));
 190     }
 191 
 192     @Test public void checkConverterPropertyName() {
 193         assertTrue(datePicker.converterProperty().getName().equals("converter"));
 194     }
 195 
 196     @Test public void checkChronologyPropertyName() {
 197         assertTrue(datePicker.chronologyProperty().getName().equals("chronology"));
 198     }
 199 
 200     @Test public void checkOnActionPropertyName() {
 201         assertTrue(datePicker.onActionProperty().getName().equals("onAction"));
 202     }
 203 
 204     @Test public void checkArmedPropertyName() {
 205         assertTrue(datePicker.armedProperty().getName().equals("armed"));
 206     }
 207 
 208     @Test public void checkShowingPropertyName() {
 209         assertTrue(datePicker.showingProperty().getName().equals("showing"));
 210     }
 211 
 212     @Test public void checkEditablePropertyName() {
 213         assertTrue(datePicker.editableProperty().getName().equals("editable"));
 214     }
 215 
 216     @Test public void checkDayCellFactoryPropertyName() {
 217         assertTrue(datePicker.dayCellFactoryProperty().getName().equals("dayCellFactory"));
 218     }
 219 
 220     @Test public void defaultActionHandlerIsNotDefined() {
 221         assertNull(datePicker.getOnAction());
 222     }
 223 
 224     @Test public void defaultConverterCanHandleLocalDateValues() {
 225         StringConverter<LocalDate> sc = datePicker.getConverter();
 226         String todayStr = sc.toString(today);
 227         assertTrue(todayStr.length() > 0);
 228         assertEquals(today, sc.fromString(todayStr));
 229     }
 230 
 231     @Test public void defaultConverterCanHandleNullValues() {
 232         StringConverter<LocalDate> sc = datePicker.getConverter();
 233         String str = sc.toString(null);
 234 
 235         assertEquals(null, sc.fromString(null));
 236         assertEquals(null, sc.fromString(""));
 237         assertTrue(str == null || str.isEmpty());
 238     }
 239 
 240 
 241     /*********************************************************************
 242      * Tests for properties                                              *
 243      ********************************************************************/
 244 
 245     @Test public void ensureSettingNullChronologyRestoresDefault() {
 246         Chronology defaultChronology = datePicker.getChronology();
 247         Chronology otherChronology =
 248             (defaultChronology != IsoChronology.INSTANCE) ? IsoChronology.INSTANCE : JapaneseChronology.INSTANCE;
 249         datePicker.setChronology(otherChronology);
 250         assertEquals(otherChronology, datePicker.getChronology());
 251         datePicker.setChronology(null);
 252         assertEquals(defaultChronology, datePicker.getChronology());
 253     }
 254 
 255     @Test public void ensureSettingNullConverterRestoresDefault() {
 256         StringConverter<LocalDate> defaultConverter = datePicker.getConverter();
 257         datePicker.setConverter(new StringConverter<LocalDate>() {
 258             @Override public String toString(LocalDate t) { return t.toString(); }
 259             @Override public LocalDate fromString(String string) { return today; }
 260         });
 261         assertNotSame(defaultConverter, datePicker.getConverter());
 262         datePicker.setConverter(null);
 263         assertSame(defaultConverter, datePicker.getConverter());
 264     }
 265 
 266     @Test public void ensureCanSetNonNullDayCellFactory() {
 267         Callback<DatePicker, DateCell> cf = p -> null;
 268         datePicker.setDayCellFactory(cf);
 269         assertSame(cf, datePicker.getDayCellFactory());
 270     }
 271 
 272     @Test public void ensureEditorIsNonNullWhenComboBoxIsNotEditable() {
 273         assertNotNull(datePicker.getEditor());
 274     }
 275 
 276     @Test public void ensureEditorIsNonNullWhenComboBoxIsEditable() {
 277         datePicker.setEditable(true);
 278         assertNotNull(datePicker.getEditor());
 279     }
 280 
 281     @Test public void ensureEditorDoesNotChangeWhenEditableToggles() {
 282         datePicker.setEditable(true);
 283         assertNotNull(datePicker.getEditor());
 284         datePicker.setEditable(false);
 285         assertNotNull(datePicker.getEditor());
 286         datePicker.setEditable(true);
 287         assertNotNull(datePicker.getEditor());
 288     }
 289 
 290     @Test public void ensureCanSetValueToNonNullLocalDateAndBackAgain() {
 291         datePicker.setValue(today);
 292         assertEquals(today, datePicker.getValue());
 293         datePicker.setValue(null);
 294         assertNull(datePicker.getValue());
 295     }
 296 
 297     @Test public void ensureCanToggleEditable() {
 298         datePicker.setEditable(true);
 299         assertTrue(datePicker.isEditable());
 300         datePicker.setEditable(false);
 301         assertFalse(datePicker.isEditable());
 302     }
 303 
 304     @Test public void ensureCanToggleShowing() {
 305         datePicker.show();
 306         assertTrue(datePicker.isShowing());
 307         datePicker.hide();
 308         assertFalse(datePicker.isShowing());
 309     }
 310 
 311     @Test public void ensureCanNotToggleShowingWhenDisabled() {
 312         datePicker.setDisable(true);
 313         datePicker.show();
 314         assertFalse(datePicker.isShowing());
 315         datePicker.setDisable(false);
 316         datePicker.show();
 317         assertTrue(datePicker.isShowing());
 318     }
 319 
 320     @Test public void ensureCanSetPromptText() {
 321         datePicker.setPromptText("Test 1 2 3");
 322         assertEquals("Test 1 2 3", datePicker.getPromptText());
 323     }
 324 
 325     @Test public void ensureCanSetPromptTextToNull() {
 326         assertEquals("", datePicker.getPromptText());
 327         datePicker.setPromptText(null);
 328         assertEquals(null, datePicker.getPromptText());
 329     }
 330 
 331     @Test public void ensurePromptTextStripsNewlines() {
 332         datePicker.setPromptText("Test\n1\n2\n3");
 333         assertEquals("Test123", datePicker.getPromptText());
 334     }
 335 
 336     @Test public void ensureCanToggleArmed() {
 337         assertFalse(datePicker.isArmed());
 338         datePicker.arm();
 339         assertTrue(datePicker.isArmed());
 340         datePicker.disarm();
 341         assertFalse(datePicker.isArmed());
 342     }
 343 
 344     @Test public void ensureCanSetOnAction() {
 345         EventHandler<ActionEvent> onAction = t -> { };
 346         datePicker.setOnAction(onAction);
 347         assertEquals(onAction, datePicker.getOnAction());
 348     }
 349 
 350     @Test public void ensureOnActionPropertyReferencesBean() {
 351         assertEquals(datePicker, datePicker.onActionProperty().getBean());
 352     }
 353 
 354     /*********************************************************************
 355      * Tests for property binding                                        *
 356      ********************************************************************/
 357     @Test public void checkPromptTextPropertyBind() {
 358         StringProperty strPr = new SimpleStringProperty("value");
 359         datePicker.promptTextProperty().bind(strPr);
 360         assertTrue("PromptText cannot be bound", datePicker.getPromptText().equals("value"));
 361         strPr.setValue("newvalue");
 362         assertTrue("PromptText cannot be bound", datePicker.getPromptText().equals("newvalue"));
 363     }
 364 
 365     @Test public void checkValuePropertyBind() {
 366         ObjectProperty<LocalDate> objPr = new SimpleObjectProperty<LocalDate>(today);
 367         datePicker.valueProperty().bind(objPr);
 368         assertTrue("value cannot be bound", datePicker.getValue().equals(today));
 369         LocalDate tomorrow = today.plusDays(1);
 370         objPr.setValue(tomorrow);
 371         assertTrue("value cannot be bound", datePicker.getValue().equals(tomorrow));
 372     }
 373 
 374     @Test public void checkChronologyPropertyBind() {
 375         ObjectProperty<Chronology> objPr = new SimpleObjectProperty<Chronology>(IsoChronology.INSTANCE);
 376         datePicker.chronologyProperty().bind(objPr);
 377         assertTrue("Chronology cannot be bound", datePicker.getChronology().equals(IsoChronology.INSTANCE));
 378         objPr.setValue(JapaneseChronology.INSTANCE);
 379         assertTrue("Chronology cannot be bound", datePicker.getChronology().equals(JapaneseChronology.INSTANCE));
 380     }
 381 
 382 
 383     /*********************************************************************
 384      * Tests for bug reports                                             *
 385      ********************************************************************/
 386 
 387     @Test public void test_rt21186() {
 388         final DatePicker datePicker = new DatePicker();
 389 
 390         StageLoader sl = new StageLoader(datePicker);
 391 
 392         assertNull(datePicker.getTooltip());
 393         assertNull(datePicker.getEditor().getTooltip());
 394 
 395         Tooltip tooltip = new Tooltip("Tooltip");
 396         datePicker.setTooltip(tooltip);
 397         assertEquals(tooltip, datePicker.getTooltip());
 398         assertEquals(tooltip, datePicker.getEditor().getTooltip());
 399 
 400         datePicker.setTooltip(null);
 401         assertNull(datePicker.getTooltip());
 402         assertNull(datePicker.getEditor().getTooltip());
 403 
 404         sl.dispose();
 405     }
 406 
 407     @Test public void test_rt30549() {
 408         // Set a MinguoDate from a String
 409         datePicker.setChronology(MinguoChronology.INSTANCE);
 410         datePicker.getEditor().setText("5/22/0102 1");
 411         datePicker.setValue(datePicker.getConverter().fromString(datePicker.getEditor().getText()));
 412         assertEquals(MinguoChronology.INSTANCE.date(MinguoEra.ROC, 102, 5, 22),
 413                      MinguoDate.from(datePicker.getValue()));
 414         assertEquals("5/22/0102 1", datePicker.getEditor().getText());
 415 
 416         // Convert from MinguoDate to LocalDate (ISO)
 417         datePicker.setChronology(IsoChronology.INSTANCE);
 418         assertEquals(LocalDate.of(2013, 5, 22), datePicker.getValue());
 419         datePicker.getEditor().setText(datePicker.getConverter().toString(datePicker.getValue()));
 420         assertEquals("5/22/2013", datePicker.getEditor().getText());
 421     }
 422 
 423     private int test_rt35586_count = 0;
 424     @Test public void test_rt35586() {
 425         assertEquals(0, test_rt35586_count);
 426 
 427         final DatePicker dp = new DatePicker();
 428         dp.setOnAction(event -> {
 429             test_rt35586_count++;
 430             assertEquals("1/2/2015", dp.getEditor().getText());
 431         });
 432 
 433         StageLoader sl = new StageLoader(dp);
 434 
 435         dp.getEditor().requestFocus();
 436         dp.getEditor().setText("1/2/2015");
 437         KeyEventFirer keyboard = new KeyEventFirer(dp.getEditor());
 438         keyboard.doKeyPress(KeyCode.ENTER);
 439 
 440         assertEquals(1, test_rt35586_count);
 441 
 442         sl.dispose();
 443     }
 444 
 445     @Test public void test_rt35840() {
 446         final DatePicker dp = new DatePicker();
 447         dp.setEditable(true);
 448         StageLoader sl = new StageLoader(dp);
 449         dp.requestFocus();
 450 
 451         KeyEventFirer keyboard = new KeyEventFirer(dp);
 452         keyboard.doKeyTyped(KeyCode.DIGIT1);
 453         keyboard.doKeyTyped(KeyCode.SLASH);
 454         keyboard.doKeyTyped(KeyCode.DIGIT2);
 455         keyboard.doKeyTyped(KeyCode.SLASH);
 456         keyboard.doKeyTyped(KeyCode.DIGIT2);
 457         keyboard.doKeyTyped(KeyCode.DIGIT0);
 458         keyboard.doKeyTyped(KeyCode.DIGIT1);
 459         keyboard.doKeyTyped(KeyCode.DIGIT5);
 460         assertEquals("1/2/2015", dp.getEditor().getText());
 461 
 462         assertNull(dp.getValue());
 463         keyboard.doKeyPress(KeyCode.ENTER);
 464         assertEquals("2015-01-02", dp.getValue().toString());
 465 
 466         sl.dispose();
 467     }
 468 
 469     @Test public void test_rt36280_F4ShowsPopup() {
 470         final DatePicker dp = new DatePicker();
 471         StageLoader sl = new StageLoader(dp);
 472         KeyEventFirer dpKeyboard = new KeyEventFirer(dp);
 473 
 474         assertFalse(dp.isShowing());
 475         dpKeyboard.doKeyPress(KeyCode.F4);  // show the popup
 476         assertTrue(dp.isShowing());
 477 
 478         sl.dispose();
 479     }
 480 
 481     @Test public void test_rt36280_altUpShowsPopup() {
 482         final DatePicker dp = new DatePicker();
 483         StageLoader sl = new StageLoader(dp);
 484         KeyEventFirer dpKeyboard = new KeyEventFirer(dp);
 485 
 486         assertFalse(dp.isShowing());
 487         dpKeyboard.doKeyPress(KeyCode.UP, KeyModifier.ALT);  // show the popup
 488         assertTrue(dp.isShowing());
 489 
 490         sl.dispose();
 491     }
 492 
 493     @Test public void test_rt36280_altDownShowsPopup_onComboBox() {
 494         final DatePicker dp = new DatePicker();
 495         StageLoader sl = new StageLoader(dp);
 496         KeyEventFirer dpKeyboard = new KeyEventFirer(dp);
 497 
 498         assertFalse(dp.isShowing());
 499         assertTrue(dp.getEditor().getText().isEmpty());
 500         dpKeyboard.doKeyPress(KeyCode.DOWN, KeyModifier.ALT);  // show the popup
 501         assertTrue(dp.isShowing());
 502         assertTrue(dp.getEditor().getText().isEmpty());
 503 
 504         sl.dispose();
 505     }
 506 
 507     @Test public void test_rt36280_altDownShowsPopup_onTextField() {
 508         final DatePicker dp = new DatePicker();
 509         StageLoader sl = new StageLoader(dp);
 510 
 511         KeyEventFirer tfKeyboard = new KeyEventFirer(dp.getEditor());
 512         assertFalse(dp.isShowing());
 513         assertTrue(dp.getEditor().getText().isEmpty());
 514         tfKeyboard.doKeyPress(KeyCode.DOWN, KeyModifier.ALT);  // show the popup
 515         assertTrue(dp.isShowing());
 516         assertTrue(dp.getEditor().getText().isEmpty());
 517 
 518         sl.dispose();
 519     }
 520 
 521     @Test public void test_rt36280_F4HidesShowingPopup() {
 522         final DatePicker dp = new DatePicker();
 523         StageLoader sl = new StageLoader(dp);
 524         KeyEventFirer dpKeyboard = new KeyEventFirer(dp);
 525 
 526         assertFalse(dp.isShowing());
 527         dpKeyboard.doKeyPress(KeyCode.F4);  // show the popup
 528         assertTrue(dp.isShowing());
 529         dpKeyboard.doKeyPress(KeyCode.F4);  // hide the popup
 530         assertFalse(dp.isShowing());
 531 
 532         sl.dispose();
 533     }
 534 
 535     @Test public void test_rt36717() {
 536         final DatePicker dp = new DatePicker();
 537         StageLoader sl = new StageLoader(dp);
 538 
 539         // the stack overflow only occurs when a ComboBox changes from non-editable to editable
 540         dp.setEditable(false);
 541         dp.setEditable(true);
 542         assertNotNull(dp.getEditor());
 543         KeyEventFirer tfKeyboard = new KeyEventFirer(dp.getEditor());
 544         tfKeyboard.doKeyPress(KeyCode.ENTER);   // Stack overflow here
 545 
 546         sl.dispose();
 547     }
 548 
 549     @Test public void test_rt36902() {
 550         final DatePicker dp1 = new DatePicker() {
 551             @Override public String toString() {
 552                 return "dp1";
 553             }
 554         };
 555         final DatePicker dp2 = new DatePicker() {
 556             @Override public String toString() {
 557                 return "dp2";
 558             }
 559         };
 560         dp2.setEditable(true);
 561         VBox vbox = new VBox(dp1, dp2);
 562 
 563         // lame - I would rather have one keyboard here but I couldn't get it to
 564         // work, so watch out for which keyboard is used below
 565         KeyEventFirer dp1Keyboard = new KeyEventFirer(dp1);
 566         KeyEventFirer dp2Keyboard = new KeyEventFirer(dp2);
 567 
 568         StageLoader sl = new StageLoader(vbox);
 569         sl.getStage().requestFocus();
 570         dp1.requestFocus();
 571         Toolkit.getToolkit().firePulse();
 572         Scene scene = sl.getStage().getScene();
 573 
 574         assertTrue(dp1.isFocused());
 575         assertEquals(dp1, scene.getFocusOwner());
 576 
 577         // move focus forward to dp2
 578         dp1Keyboard.doKeyPress(KeyCode.TAB);
 579         assertTrue(dp2.isFocused());
 580         assertEquals(dp2, scene.getFocusOwner());
 581 
 582         // move focus forward again to dp1
 583         dp2Keyboard.doKeyPress(KeyCode.TAB);
 584         assertTrue(dp1.isFocused());
 585         assertEquals(dp1, scene.getFocusOwner());
 586 
 587         // now start going backwards with shift-tab.
 588         // The first half of the bug is here - when we shift-tab into dp2, we
 589         // actually go into the FakeFocusTextField subcomponent, so whilst the
 590         // dp2.isFocused() returns true as expected, the scene focus owner is
 591         // not the ComboBox, but the FakeFocusTextField inside it
 592         dp1Keyboard.doKeyPress(KeyCode.TAB, KeyModifier.SHIFT);
 593         assertTrue("Expect dp2 to be focused, but actual focus owner is: " + scene.getFocusOwner(),
 594                 dp2.isFocused());
 595         assertEquals("Expect dp2 TextField to be focused, but actual focus owner is: " + scene.getFocusOwner(),
 596                 dp2.getEditor(), scene.getFocusOwner());
 597 
 598         // This is where the second half of the bug appears, as we are stuck in
 599         // the FakeFocusTextField of dp2, we never make it to dp1
 600         dp2Keyboard.doKeyPress(KeyCode.TAB, KeyModifier.SHIFT);
 601         assertTrue(dp1.isFocused());
 602         assertEquals(dp1, scene.getFocusOwner());
 603 
 604         sl.dispose();
 605     }
 606 }