bug
Test is adding one todo to the list, then types long text into the input box. But the input box somehow only shows last part of the long text (see image). The text typed into the box is supposed to be "Learn how to test with Cypress.io". The box has only "h Cypress.io"
Instead of
Repo: https://github.com/cypress-io/cypress-example-recipes folder examples/blogs__vue-vuex-rest
Dashboard result: https://dashboard.cypress.io/#/projects/6p53jw/runs/feffade1-893c-4327-8059-6c53920bcc32/screenshots
it('can add a todo, type and compare entire store', () => {
const title = 'a random todo'
enterTodo(title)
const text = 'learn how to test with Cypress.io'
cy
.get('.todoapp')
.find('.new-todo')
.type(text)
.trigger('change')
getStore().should('deep.equal', {
loading: false,
todos: [
{
title,
completed: false,
id: '1'
}
],
newTodo: text
})
})

The test first adds a Todo object that goes to the server, then Vue component refreshes. I think the typing does NOT WAIT for the vue component refresh. Thus when the Vue component refreshes it deletes part of the text cy.type(text) entered.
cy.input... should be empty assertioncy.get('input').type('a very very very long string', {delay: 100})
setTimeout(function setInput () {
document.querySelector('input').value = 'foo'
}, 500)
Im this case we will start typing a very ... with 100ms delay after each letter, but 500ms after the input will be set to foo by the timer. Cypress should catch this problem - I think this might be a reason for flake in many web apps - Cypress moves to the next step faster than the web apps update themselves ;)
Confirmed. Added a test that delays the response from the server, so the web component updates while we are slowly typing into the input box.
it('starts typing after delayed server response', () => {
// this will force new todo item to be added only after a delay
cy.server()
cy.route({
method: 'POST',
url: '/todos',
delay: 3000,
response: {}
})
const title = 'first todo'
enterTodo(title)
const newTitleText = 'this is a second todo title, slowly typed'
cy
.get('.todoapp')
.find('.new-todo')
.type(newTitleText, { delay: 100 })
.trigger('change')
cy.screenshot('typing after delay')
})
Result - only last part of the new text

Yes this is possibly "part" of the problem. There are situations where cy.type does not respect changes to selectionStart and selectionEnd which is covered by another issue.
I had opened another issue awhile ago which would be a breaking change here: https://github.com/cypress-io/cypress/issues/566
What that describes is that we should change cy.type to synchronously type all of the characters. It would make async digests impossible to fuss with the typed text and remove all race conditions. It wouldn't match "reality" but it would remove these kinds of hard to understand problems.
My guess here though is that you should be able to reproduce this by banging on the keyboard as fast as possible since Cypress types at approximately 120wpm.
If you can't repro that way, then there may be a somewhere where we're not respecting changes.
yeah, it is the problem in this particular repo, I bet I could recreate the problem by banging on the keyboard quickly when using a remote server with noticeable lag. For now I added assertion to make sure new todo updates the DOM before proceeding
export const getNewTodoInput = () => getTodoApp().find('.new-todo')
export const enterTodo = (text = 'example todo') => {
getNewTodoInput().type(`${text}{enter}`)
// we need to make sure the store and the vue component
// get updated and the DOM is updated.
// quick check - the new text appears at the last position
getTodoItems().last().should('contain', text)
}
But in general, I think we should detect input update and treat it as an error, same way we do with "detached DOM element" error
Right, we could automatically wait that the input has the value we expect
it to after typing - but the problem here are text masks.
The value could be mutated on each keystroke to align itself to something
like a formatted date or a formatted phone number.
We could add in an optional param that says like: "synchronize" and then
it'll wait until the value matches... but... yeah it's tough.
I think the problem really is that the value of the <input> WILL be
changing correctly, but the "component" registering it is lagging behind
due to its own internal digest cycle.
On Thu, Nov 30, 2017 at 10:55 AM, Gleb Bahmutov notifications@github.com
wrote:
yeah, it is the problem in this particular repo, I bet I could recreate
the problem by banging on the keyboard quickly when using a remote server
with noticeable lag. For now I added assertion to make sure new todo
updates the DOM before proceedingexport const getNewTodoInput = () => getTodoApp().find('.new-todo')
export const enterTodo = (text = 'example todo') => {
getNewTodoInput().type(${text}{enter})
// we need to make sure the store and the vue component
// get updated and the DOM is updated.
// quick check - the new text appears at the last position
getTodoItems().last().should('contain', text)
}But in general, I think we should detect input update and treat it as an
error, same way we do with "detached DOM element" error—
You are receiving this because you were assigned.
Reply to this email directly, view it on GitHub
https://github.com/cypress-io/cypress/issues/984#issuecomment-348231152,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABNc8JJLQbGVMiGen8WTG3KwL5FNXZQmks5s7tAEgaJpZM4Qwsv8
.
it's unlikely there is a good way to fix this since we shouldn't error on unexpected changes to the input value, and we also don't know exactly how long to wait for a framework's internal state to settle. I'm going to label this with wont fix