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 keystrokeDelay configuration option #566

Closed
brian-mann opened this issue Jul 19, 2017 · 23 comments · Fixed by #15683
Closed

Add keystrokeDelay configuration option #566

brian-mann opened this issue Jul 19, 2017 · 23 comments · Fixed by #15683
Assignees
Labels
good first issue Good for newcomers pkg/driver This is due to an issue in the packages/driver directory type: enhancement Requested enhancement of existing feature type: feature New feature that does not currently exist

Comments

@brian-mann
Copy link
Member

Currently Cypress uses a setTimeout between keystrokes to mimic how a user would press each key.

Concern 1:

We should enable this property to be globally configurable such as keystrokeDelay.

Concern 2:

When set to false or 0, instead of making each key press be async, we should make it synchronous. This would be helpful to not only type faster but could make things easier for 3rd party JS frameworks such as react.

Currently as it stands since keypresses as async - its indeterminate whether or not your JS framework has finished 'processing' all of the keystrokes. For instance it may fire its change events while typing vs after all characters have been typed. See issue #534 for more detail.

Concern 3:

When typing very long sequences its often useful just to have it all "type at once" and not have to wait. Give developers the choice to decide.

Recommendation

  • set keystrokeDelay to true by default (which is the minimum setImmediate async between key presses)
  • if keystrokeDelay is set to false or 0 typing all characters synchronously
  • if keystrokeDelay is set to a number then use this as the setTimeout value

Passing the delay option to cy.type() will override anything globally set in config.

@brian-mann brian-mann added type: enhancement Requested enhancement of existing feature type: feature New feature that does not currently exist labels Jul 19, 2017
@brian-mann brian-mann self-assigned this Jul 19, 2017
@jennifer-shehane jennifer-shehane added the pkg/driver This is due to an issue in the packages/driver directory label Sep 25, 2017
@sompylasar
Copy link

We should enable this property to be globally configurable such as keystrokeDelay.

This would be convenient to configure globally.

For instance it may fire its change events while typing vs after all characters have been typed.

But in a real world with real users, that is how the app will actually behave, right? So why should it behave differently under the test?

@jennifer-shehane jennifer-shehane added the stage: ready for work The issue is reproducible and in scope label Apr 13, 2018
@Aaronius
Copy link

@sompylasar The way I'd answer that is that we sometimes take the trade-off of not testing a 100% accurate user experience if the benefit is faster test execution. We're already making some of these trade-offs already. For example, a user doesn't click a button immediately after a page loads; they would likely take some time reading text or scanning the UI and deciding their next course of action. But with end-to-end tests, we're doing all kinds of things super fast because mimicking the time it takes to read text and scan the UI is not worth the cost. Of course, simulating a regular typing speed is super important in some cases, so it's nice to have the flexibility.

@sompylasar
Copy link

@Aaronius

For example, a user doesn't click a button immediately after a page loads

At least there's a way to simulate that with a wait if the UI under test is time-sensitive.

But with end-to-end tests, we're doing all kinds of things super fast because mimicking the time it takes to read text and scan the UI is not worth the cost.

It's too bold of a decision for the authors of a test framework (Cypress) to estimate the cost for each use case that they might not know about. Provide a good API and good defaults, okay, but let the users make decisions.

@Foovanadil
Copy link

Foovanadil commented Oct 29, 2018

This would be helpful but maybe another way to accomplish this is by adding a secondary method that will fill out a field without delay and leave the "type" method intact as is.

This way, if you want to "type" into an input it works as expected. If you just want to fill the input you do something like

cy.get('#myInput').fill(value)

or something?

@techieshark
Copy link

The suggestion for fill() from @Foovanadil seems reasonable especially as it's possible real humans may sometimes copy/paste input and presumably fill() would mimic the same effect.

@on3al
Copy link

on3al commented Mar 1, 2019

Seriously need this feature. Those ci build minutes are expensive.

@crcatala
Copy link

Here's one custom command I've been using in the interim. If you're app sets up form input event listener's on either input and change events, this should cover most cases:

// in your commands file:
Cypress.Commands.add('fill', {
  prevSubject: 'element'
}, (subject, value) => {
  cy.wrap(subject).invoke('val', value).trigger('input').trigger('change')
});

// Usage in spec:
cy.get('[data-my-input-field]').fill('Hello');

@ls-chloe-schoreisz
Copy link

Having issues with this when dealing with Formik. I tried adding the events focus and blur but it doesn't seem to work, as soon as I go to the next field, the input is cleared. Ideas ?

@scaryguy
Copy link

scaryguy commented Aug 16, 2019

Here's one custom command I've been using in the interim. If you're app sets up form input event listener's on either input and change events, this should cover most cases:

// in your commands file:
Cypress.Commands.add('fill', {
  prevSubject: 'element'
}, (subject, value) => {
  cy.wrap(subject).invoke('val', value).trigger('input').trigger('change')
});

// Usage in spec:
cy.get('[data-my-input-field]').fill('Hello');

The problem with this solution is not having all necessary events triggered. I'm using react-final-form and because of the missing events, the field value is never changed if I use this solution. Does anyone have a solution to this? @crcatala maybe? @ls-chloe-schoreisz have you found a way to make it work in your case?

This feature is really important when you have to add a long text into a textarea... @brian-mann any plans on working on this feature any time soon?

@ls-chloe-schoreisz
Copy link

ls-chloe-schoreisz commented Aug 16, 2019

@scaryguy haven't found a workaround. I reduced the typing delay to its minimum, but my tests involve breaking string max boundaries (sometimes 255 char...) so an actual implementation of this feature would be much appreciated, I'd probably reduce the time of runs by 60%

@dRoskar
Copy link

dRoskar commented Dec 9, 2019

It seems that reducing the delay with cy.type("hello", {delay: 1}) doesn't do anything if you try to go below 10ms.

@GMchris
Copy link

GMchris commented Jan 23, 2020

I'm not saying this is ideal, however I've managed to finally get this working with React 16.8 with a textarea.

Cypress.Commands.add('fill', {
  prevSubject: 'element',
}, ($subject, value) => {
  const el = $subject[0];
  el.value = value;
  return cy.wrap($subject).type('t{backspace}');
});

Since cy.type actually manages to trigger React's events properly, writing on extra character then deleting it winds up triggered the change and the application responds to it. I'd prefer to write an empty string (Cypress blocks this) or at least spaces (doesn't appear to work), but it is what it is. I'm hoping for an official fill/paste command in the future.

@x-yuri
Copy link

x-yuri commented Mar 27, 2020

This might be not much of a difference, but still I like it more:

Cypress.Commands.add('fill', { prevSubject: 'element' }, ($subj, text) => {
    $subj.val(text);
    return cy.wrap($subj).type('{end}');
});

@slinden2
Copy link

I'm not saying this is ideal, however I've managed to finally get this working with React 16.8 with a textarea.

Cypress.Commands.add('fill', {
  prevSubject: 'element',
}, ($subject, value) => {
  const el = $subject[0];
  el.value = value;
  return cy.wrap($subject).type('t{backspace}');
});

Since cy.type actually manages to trigger React's events properly, writing on extra character then deleting it winds up triggered the change and the application responds to it. I'd prefer to write an empty string (Cypress blocks this) or at least spaces (doesn't appear to work), but it is what it is. I'm hoping for an official fill/paste command in the future.

Thanks. Works perfectly. We need an official solution though...

@AlanKrygowski
Copy link

Any updates on this?
Not sure why but I keep loosing the value when running the filling in a loop

@DanielFerrariR
Copy link

DanielFerrariR commented Aug 23, 2020

None of these solutions worked for me, so I created a npm package that is working on React with Material-UI in the lastest version:

cypress-fill-command

I used some info collected from all related posts, so, if you feel that you need to be tagged on it to give properly credit, contact me.

@x-yuri
Copy link

x-yuri commented Aug 24, 2020

Takes a regular expression?.. :)

@DanielFerrariR
Copy link

DanielFerrariR commented Aug 24, 2020

Ops, my mistake in the docs, it should only receive a simple string as a parameter. Already fix it.

@cypress-bot cypress-bot bot removed the stage: ready for work The issue is reproducible and in scope label Mar 28, 2021
@ric-rdrz
Copy link

I'm not saying this is ideal, however I've managed to finally get this working with React 16.8 with a textarea.

Cypress.Commands.add('fill', {
  prevSubject: 'element',
}, ($subject, value) => {
  const el = $subject[0];
  el.value = value;
  return cy.wrap($subject).type('t{backspace}');
});

Since cy.type actually manages to trigger React's events properly, writing on extra character then deleting it winds up triggered the change and the application responds to it. I'd prefer to write an empty string (Cypress blocks this) or at least spaces (doesn't appear to work), but it is what it is. I'm hoping for an official fill/paste command in the future.

Works perfectly. Thanks

@cypress-bot cypress-bot bot added stage: needs review The PR code is done & tested, needs review and removed stage: waiting labels Jun 1, 2021
@chrisbreiding chrisbreiding self-assigned this Jun 4, 2021
@cypress-bot cypress-bot bot added stage: work in progress stage: needs review The PR code is done & tested, needs review and removed stage: needs review The PR code is done & tested, needs review stage: work in progress labels Jun 9, 2021
@SymenTimmermans
Copy link

SymenTimmermans commented Jun 15, 2021

Instead of adding a random 't' and a backspace keypress, why not just split off the last character, and type it into the input?

Cypress.Commands.add('fill', {
    prevSubject: 'element',
}, ($subject, value) => {
    const el = $subject[0];
    el.value = value.substring(0, value.length - 1);
    var lastChar = value.substring(value.length - 1, value.length);
    return cy.wrap($subject).type(lastChar);
});

@x-yuri
Copy link

x-yuri commented Jun 15, 2021

Probably because with t{backspace} it works even if value.length == 1. To which you might reply that in that case one should use type() instead. But values we pass are not always fixed. In which case your version is a recipe for flaky tests.

UPD Okay, I jumped to conclusions. I somehow thought that with value.length == 1 it would trigger an error.

@cypress-bot
Copy link
Contributor

cypress-bot bot commented Jun 16, 2021

The code for this is done in cypress-io/cypress#15683, but has yet to be released.
We'll update this issue and reference the changelog when it's released.

@cypress-bot cypress-bot bot removed the stage: needs review The PR code is done & tested, needs review label Jun 16, 2021
@cypress-bot
Copy link
Contributor

cypress-bot bot commented Jun 23, 2021

Released in 7.6.0.

This comment thread has been locked. If you are still experiencing this issue after upgrading to
Cypress v7.6.0, please open a new issue.

@cypress-bot cypress-bot bot locked as resolved and limited conversation to collaborators Jun 23, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
good first issue Good for newcomers pkg/driver This is due to an issue in the packages/driver directory type: enhancement Requested enhancement of existing feature type: feature New feature that does not currently exist
Projects
None yet
Development

Successfully merging a pull request may close this issue.