The problem
Someone in the Cypress Discord faced an issue where cy.type()
wouldn't enter the full desired string in a form field, resulting in only a partial string value showing up in the UI (and their test not working as expected). This has happened to me before, and if you work with Cypress long enough, it'll probably happen to you at least once.
This tester's easiest fix was just to insert a hard cy.wait()
to ensure that the field was ready for text entry, but we prefer to try to avoid those. There are a few little tricks I use to deal with this issue when it arises, and I use them each in turn depending on the context. Hopefully something here will help you get unstuck if you ever face issues typing text with Cypress.
Example
Here's an example where I'm using all the tricks at once, and I'll break down each one, line by line.
cy.get('field')
.should('be.visible')
.clear()
.type('string', { delay: 0 })
.should('contain', 'string');
cy.get('field')
No real trick here, but I'll emphasize the importance of selecting the correct element, generally an <input>
- though not always guaranteed.
.should('be.visible')
Cypress is much faster than a human. A form field can receive input as soon as it exists in the DOM, but by waiting until it is visible, we have a better chance of waiting long enough for the .type()
action to actually take place and have effects like filling the field. In modern apps, there's a lot more stuff being done by Javascript and it's important to be able to wait for element availability as close as possible to their "ready" state. Waiting for visibility (page has been painted) is the first good nudge toward knowing when that "ready" state occurs.
.clear()
Sometimes form fields contain default text that clears based on a click
or focus
action. If the page's Javascript is still hydrating the page, I've seen this break and newly entered text will sometimes append the placeholder text. It's generally just a good idea to clear
the field, unless of course you actually want to append text (as in a "Notes" field).
.type('string', { delay: 0 })
Using { delay: 0 }
is open to debate. This option enters the full input string as a chunk, rather than by typing each key individually. This is less like a "real user" would type text into a field, but it can lead to more reliable test automation, if you feel comfortable with the trade-off. It's comparable to a user pasting directly into the field.
.should('contain', 'string');
It's good to check the state of any elements you modify. This command will let us confirm that the field is in the correct state, and we can move on with the rest of our test.
Other options
In my example, I assumed that the field would accept direct text entry, however that's not always the case. You might find that you need to use .click()
on the element before you begin typing. You might also want to use .focus() to set your cursor into the field. I didn't include these in my happy-path example, because this post was really just about the .type()
command.
A plugin option
If you're using the cypress-real-events plugin, you might choose to use cy.realType()
in combination with cy.get().focus()
. This command types in each character, just like from a physical keyboard, so this method may be the most "realistic" option, if that is a priority for your testing goals.
I hope this helps
If any of these helped you write more reliable, stable tests - let me know on Twitter, Mastodon, or Bluesky.
Top comments (6)
Great write-up, thank you @samelawrence .
Glad you found it helpful!
Very good tips, when I start with Cypress I find many difficult with cy.type().
Thank you! It took me a long time to get comfortable with Cypress and years later, I'm still constantly learning new things about how to use it properly. Just keep practicing and using it!
What about adding a
{force: true}
to type? That has helped me solve this problem even though I don't fully understand why.Using
{force: true}
is usually a code smell, but I do have to resort to it as needed. It's nice to know it's an option, for sure!