Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add typeIn helper to trigger keyup, keypress and keyup events when filling inputs #397

Merged

Conversation

mfeckie
Copy link
Contributor

@mfeckie mfeckie commented Jul 14, 2018

The current implementation of fillIn does not trigger keydown, keypress and keyup events.

I've recently been working on some stuff that uses these events. One example being a formatted text input for bank account numbers that only allow certain characters.

I'm not sure if other folks would find this helpful so submitting as a PR for consideration / discussion.

@mfeckie mfeckie force-pushed the feature/add-fill-in-with-keyboard-events branch from 3e32044 to 7119b82 Compare July 14, 2018 09:13
Copy link
Contributor

@cibernox cibernox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally oppose to this change. I do think it's valuable but it should be, at least at first, a different helper.

Also if we want to do it right, it should modify the value char by char triggering the full sequence of events for each.

Ideally it should also allow to specify a delay between keystrokes to simulate slow typing for scenarios with debouncing.

@mfeckie
Copy link
Contributor Author

mfeckie commented Jul 14, 2018

Consider it a proof of concept. I'm happy to make it a seperate helper. What would it be called?

Also happy to update the input char by char and allow delays

@mfeckie
Copy link
Contributor Author

mfeckie commented Jul 14, 2018

How about fillUsingKeyEvents ?

@cibernox
Copy link
Contributor

My preference is "typeIn"

@mfeckie
Copy link
Contributor Author

mfeckie commented Jul 14, 2018

❤️ Less verbose and says what it does :) will use

@mfeckie
Copy link
Contributor Author

mfeckie commented Jul 14, 2018

Looking at the codebase, it seems that async/await is explicitly disabled, which would make cleanly implementing a delay between each key input difficult. Suggestions welcome.

@Turbo87
Copy link
Member

Turbo87 commented Jul 14, 2018

@mfeckie you can use promise chains instead

@mfeckie mfeckie force-pushed the feature/add-fill-in-with-keyboard-events branch from 7119b82 to f62242f Compare July 14, 2018 13:09
@mfeckie
Copy link
Contributor Author

mfeckie commented Jul 14, 2018

OK folks, I've updated the PR to address all the feedback and suggestions so far.

I've also updated the documentation to go along with it.

@mfeckie
Copy link
Contributor Author

mfeckie commented Jul 19, 2018

Any updates on the this folks?

@Turbo87 Turbo87 changed the title Allow fillIn to trigger keyup, keypress and keyup events as well Add typeIn helper to trigger keyup, keypress and keyup events when filling inputs Jul 19, 2018
import hasEmberVersion from 'ember-test-helpers/has-ember-version';

let expectedEvents = [
'focus',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After some investigation, I think the order of the events may be wrong. Check this jsbin: https://jsbin.com/zitazuxabe/edit?html,js,console,output

Seems that the sequence when typing "abc" is:

keydown | e.target.value is ""
keypress | e.target.value is ""
input | e.target.value is "a"
keyup | e.target.value is "a"
keydown | e.target.value is " a"
keypress | e.target.value is "a"
input | e.target.value is "ab"
keyup | e.target.value is "ab"
keydown | e.target.value is " ab"
keypress | e.target.value is "ab"
input | e.target.value is "abc"
keyup | e.target.value is "abc"
change | e.target.value is "abc"

Changes I request:

  • input fires before keyup
  • It's important that keydown and keypress are fired before the input gets the new value, and the rest are fired after
  • The change event should only be fired once at the end.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add this JSBin as an inline comment? It sure will make "reality" testing easier over time...

@cibernox
Copy link
Contributor

@rwjblue how do you feel about this helper once it has been polished?

@cibernox
Copy link
Contributor

Code-wise, I think this is good. I'll defer to @rwjblue to decide wether we want this helper in this repo or in another one, but sounds good.

@rwjblue
Copy link
Member

rwjblue commented Jul 19, 2018

Conceptually, I think it is a good helper to have. I haven't had much time to dig into the implementation just yet though (sorry).

@mfeckie
Copy link
Contributor Author

mfeckie commented Jul 31, 2018

Anything I can do to help progress this good humans?

Copy link
Member

@rwjblue rwjblue left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good, only a few suggested tweaks/changes...

API.md Outdated
@@ -3,14 +3,15 @@
### Table of Contents

- [DOM Interaction Helpers](#dom-interaction-helpers)
- [blur](#blur)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you reset the changes here to API.md? I'll regenerate it before publishing (this way the API.md on master roughly continues to match what actual users are using)...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

* @param {number} millisecondDelay number of millisecons to wait per keypress
* @return {Promise<void>} resolves when the application is settled
*/
export default function typeIn(target, text, millisecondDelay = 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets go with an { delay: 50 } for the third arg

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


// eslint-disable-next-line require-jsdoc
function fillOut(element, text, delay) {
return new Promise(resolve => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this promise nesting

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason for the promise nesting is because fillOut takes each step and executes keyDown, keyPress, input and keyUp events for each character in the input string.

We need to ensure that each promise is triggered in order.

Without this, everything essentially happens without delay.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I don’t think that I see what you mean. It seems that executeEvents does all of that and fillOut just wraps another promise around the promise returned by executeEvents without doing anything else.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, your right. Have removed. Sorry for misunderstanding the original question!


__focus__(element);

return fillOut(element, text, millisecondDelay)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason we can't use executeEvents directly here? I don't see what fillOut provides us...

return executeEvents(element, text, delay).then(() => fireEvent(element, 'change'))

Copy link
Contributor Author

@mfeckie mfeckie Aug 1, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fillOut packages up the promise tree.

throw new Error('Must provide `text` when calling `typeIn`.');
}

__focus__(element);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does __focus__ return a promise that we need to chain?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is exactly the same as I found it in fill-in.js so I kept for consistency

import hasEmberVersion from 'ember-test-helpers/has-ember-version';

let expectedEvents = [
'focus',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add this JSBin as an inline comment? It sure will make "reality" testing easier over time...

@mfeckie mfeckie force-pushed the feature/add-fill-in-with-keyboard-events branch from 5d098b0 to 3478211 Compare August 1, 2018 09:42
@makepanic
Copy link

makepanic commented Aug 7, 2018

fillIn supports contenteditable as target elements.
Is it possible to add this to the typeIn helper too?

In its current state, one can't use typeIn for contenteditable elements.

@mfeckie
Copy link
Contributor Author

mfeckie commented Aug 7, 2018

I specifically excluded contenteditable as I don't believe it follows the same event pattern as native inputs.

Perhaps you could take a look after / if this PR gets merged?

@mfeckie
Copy link
Contributor Author

mfeckie commented Aug 9, 2018

@rwjblue I think I've addressed all your feedback? Anything outstanding?

@mfeckie
Copy link
Contributor Author

mfeckie commented Aug 25, 2018

Bump

Copy link
Member

@rwjblue rwjblue left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for letting this sit so long @mfeckie.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants