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