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

After type, framework's internal state doesn't have time to update #984

Closed
bahmutov opened this issue Nov 30, 2017 · 5 comments
Closed

After type, framework's internal state doesn't have time to update #984

bahmutov opened this issue Nov 30, 2017 · 5 comments
Labels
stage: wontfix Cypress does not regard this as an issue or will not implement this feature

Comments

@bahmutov
Copy link
Contributor

  • Operating System: Linux
  • Cypress Version: 1.1.2
  • Browser Version: Electron

Is this a Feature or Bug?

bug

Current behavior:

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"

Desired behavior:

  • Have the expected text in the input box.
  • Give better error message. In this case we are comparing the central data store object, but we have to guess what happens. It would be nice if the error message actually showed values in the STDERR of the application.

Instead of

How to reproduce:

Test code:

Additional Info (images, stack traces, etc)

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

Test: https://github.com/cypress-io/cypress-example-recipes/blob/master/examples/blogs__vue-vuex-rest/cypress/integration/store-spec.js#L160

  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
    })
  })

test-input

What I think happens

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.

  • user could wait for Vue component refresh, for example using cy.input... should be empty assertion
  • Cypress test runner could watch the input element and detect "stray" changes that were triggered by the outside code. Then it would know that something else just created a race condition. Consider example
cy.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 ;)

@bahmutov
Copy link
Contributor Author

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

typing after delay

@brian-mann
Copy link
Member

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: #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.

@bahmutov
Copy link
Contributor Author

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

@brian-mann
Copy link
Member

brian-mann commented Nov 30, 2017 via email

@kuceb
Copy link
Contributor

kuceb commented Jun 29, 2018

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

@kuceb kuceb added this to the 3.0.3 milestone Jun 29, 2018
@kuceb kuceb self-assigned this Jun 29, 2018
@kuceb kuceb removed their assignment Jul 16, 2018
@kuceb kuceb removed this from the 3.0.3 milestone Jul 16, 2018
@kuceb kuceb added stage: wontfix Cypress does not regard this as an issue or will not implement this feature and removed stage: wontfix Cypress does not regard this as an issue or will not implement this feature type: bug stage: in progress labels Jul 16, 2018
@kuceb kuceb changed the title Scrambled text input After type, framework's internal state doesn't have time to update Jul 17, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stage: wontfix Cypress does not regard this as an issue or will not implement this feature
Projects
None yet
Development

No branches or pull requests

4 participants