Target window for write() in 4.x Alpha

109 views
Skip to first unread message

Bernhard

unread,
Dec 3, 2015, 8:38:17 AM12/3/15
to TestFX
Hello,

in a unit test a new window is created (via FXML). When calling write("something") the text is not written into the textfield in new window but to the previous window.

When doing the same thing in the real application this is working (and I think to remember that this also worked in 3.x). Before showing the stage an explicit call to Stage.requestFocus() is made.

After setting the new window via target() the text is written into the correct window/textfield. But is there an easier approach that the target() is already set correctly?

Bernhard

Benjamin Gudehus

unread,
Dec 4, 2015, 3:58:25 AM12/4/15
to Bernhard, TestFX
>Before showing the stage an explicit call to Stage.requestFocus() is made.

So, JavaFX calls this method?

I'm currently not aware of any way to listen globally to focus requests and new created windows.

For a login dialog I would use

clickOn("#firstname").write("scott");
clickOn("#lastname").write("tiger");

instead of

write("scott");
clickOn("#lastname").write("tiger");

This is also more explicit.

For dialogs with only one textfield, I would use

clickOn(".text-field").write("new filename.text")

--Benjamin






Bernhard

--
You received this message because you are subscribed to the Google Groups "TestFX" group.
To unsubscribe from this group and stop receiving emails from it, send an email to testfx-discus...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Bernhard

unread,
Dec 4, 2015, 5:52:39 AM12/4/15
to TestFX
Hi Benjamin,

the "problem" is that I have to verify that the text is written into the correct textfield even without clicking anywhere.

That is, the target for the text should be the same as it would be when running "live".

Of course I could set the target manually or via clickOn(), but then I am not testing the scenario I want to.

We call Stage.requestFocus() manually, but tests have shown this is not really necessary.

+Bernhard

Benjamin Gudehus

unread,
Dec 4, 2015, 7:21:40 AM12/4/15
to Bernhard, TestFX
Ahh, I see.

For the test that tests the Stage.requestFocus() you can use type()
instead of write().

// given:
interact(() -> secondStage.requestFocus());

// when:
type(KeyCode.X, 5);

// then:
verifyThat("#first-textfield-in-second-stage", hasText("xxxxx"));

worked for me.

In your use case requestFocus() would be somewhere in your application code.

P.S.: I'm thinking about new matcher methods to verify e.g.
Stage::isFocused(), and Stage::isFullScreen(), and Node::isFocused. It
is also a bit cumbersome to lookup windows/stages using FxRobot.

Bernhard

unread,
Dec 4, 2015, 9:09:59 AM12/4/15
to TestFX
Hi Benjamin,

I extended the API and implemented a type(String) method that uses type(KeyCode) internally (supports alpha-numeric characters, could be extended to suppert e.g. whitespace etc.). Then it works as expected for me (without the need to call requestFocus()).

Will send you a Pull Request for this.

Cheers,
Bernhard

Benjamin Gudehus

unread,
Dec 4, 2015, 9:21:35 AM12/4/15
to Bernhard, TestFX
Hey,

we had some issues with french and spanish keyboard layouts. AFAIR one
needs to press shift-1 in order to write 1 on the "FR_fr" layout.

I'd like to have an API like `type(KeyCodeUtils.asKeyCodes("hello
world!", KeyLayout.FRENCH))` (one could statically import this
method), and we should have `type()` only for KeyCodes and `write()`
only for Strings, to prevent the issues with different keyboard
layouts; this caused some trouble in TestFX 3.

--Benjamin




On 12/4/15, Bernhard <bernhard...@gmail.com> wrote:

Benjamin Gudehus

unread,
Dec 4, 2015, 9:32:12 AM12/4/15
to Bernhard, TestFX
I remember I wrote a simulator that iterates over all all KeyCodes,
type()s them, maps the KeyCodes to the text of a TextField, and
outputs everything into a text file. This was before I found out, that
we can use the JavaFX robot to output Unicode characters. The approach
with the keyboard layout text file mappings was a bit overkill,
especially for CJK layouts, e.g. a korean/hangul character/block can
consist of three typed keys. I also tried to reuse the keyboard
mapping files from Android, but somehow this didn't work good.

Benjamin Gudehus

unread,
Dec 4, 2015, 10:03:52 AM12/4/15
to Bernhard, TestFX
The main question I tinkered about when restructuring the API for
keyboard inputs was, how can we change the imperative key typing into
a declarative way, i.e. is it possible to use a DSL and data
structures for keyboard input.

Here is the current API:

~~~
push(KeyCode... combination); // Pushes a given key combination.
push(KeyCodeCombination combination); // Pushes a given key combination.
type(KeyCode... keys); // Types given keys one after the other.
type(KeyCode key, int times); // Types a given key multiple times.
~~~

And code examples:

push(CTRL, ALT, DEL);
push(CTRL, F4);
type(O, K, ENTER);

So `push()` is for a single key combination and `type()` is for typing
keys one after the other.

`push(CTRL, ALT, DEL)` translates roughly to
`pressNoWait(CTRL).pressNoWait(ALT).pressNoWait(DEL).releaseNoWait(DEL).releaseNoWait(ALT).release(CTRL)`
whereas `type(O, K, ENTER)` translates to roughly
`pressNoWait(O).release(O).pressNoWait(K).release(K).pressNoWait(ENTER).release(ENTER)`.
What makes this complicated is, that we have to wait after each key
stroke; TestFX synchronizes a lot in background with the JavaFX
application thread.

Now the problem is, we can't input uppercase letters with `type()`. We
have use `push()`, e.g. `push(SHIFT, O).push(SHIFT, K).push(ENTER)`.
We can't simulate typing uppercase letter with a single KeyCode, we
either have to use multiple KeyCode or a KeyCodeCombination.

So we have some small open API issues here. I also tried to implement
something like `hold(SHIFT).type(O, K).unhold()` or
`type(whileHolding(SHIFT), O, K)`. But is was not very elegant, and
introduced some global state.

Benjamin Gudehus

unread,
Dec 4, 2015, 10:11:40 AM12/4/15
to Bernhard, TestFX
Hmm, so typing "OK(ENTER)" is possible with `press(SHIFT).type(O,
K).release(SHIFT).push(ENTER)`. `type("OK").push(ENTER)` might be
simpler, but we really have to explicitly declare the keyboard layout
for instance with `type("OK", KeyLayout.FRENCH).push(ENTER)`.

Benjamin Gudehus

unread,
Dec 4, 2015, 9:40:29 PM12/4/15
to Bernhard, TestFX
Fixed the issue with `write()` in PR #239.

#239: (fix) `WriteRobot::write()` to prefer the `Scene` of the focused
window., https://github.com/TestFX/TestFX/pull/239
Reply all
Reply to author
Forward
0 new messages