Skip to content

Latest commit

 

History

History
240 lines (171 loc) · 5.24 KB

File metadata and controls

240 lines (171 loc) · 5.24 KB

☀️ Part 6: Application data store

📚 You will learn

  • how to access the running application from test code
  • how to stub a method in the application
  • how to drive application by dispatching actions

+++

  • keep todomvc app running
  • open cypress/integration/06-app-data-store/spec.js
  • test that Vuex data store is working correctly

The application object

// todomvc/app.js
// if you want to expose "app" globally only
// during end-to-end tests you can guard it using "window.Cypress" flag
// if (window.Cypress) {
window.app = app
// }

+++

Todo: confirm window.app

// cypress/integration/06-app-data-store/spec.js
it('has window.app property', () => {
  // get its "app" property
  // and confirm it is an object
  // see https://on.cypress.io/its
  cy.window()
})

Todo: confirm window.app.$store

// cypress/integration/06-app-data-store/spec.js
it('has window.app property', () => {
  // get the app.$store property
  // and confirm it has expected Vuex properties
  // see https://on.cypress.io/its
  cy.window()
})

Todo: the initial Vuex state

it('starts with an empty store', () => {
  // the list of todos in the Vuex store should be empty
  cy.window()
})

Todo: check Vuex state

Let's add two items via the page, then confirm the Vuex store has them

// cypress/integration/06-app-data-store/spec.js
const addItem = (text) => {
  cy.get('.new-todo').type(`${text}{enter}`)
}
it('adds items to store', () => {
  addItem('something')
  addItem('something else')
  // get application's window
  // then get app, $store, state, todos
  // it should have 2 items
})

Question

Why can't we confirm both items using should('deep.equal', [...])?

cy.window()
  .its('app.$store.state.todos')
  .should('deep.equal', [
    { title: 'something', completed: false, id: '1' },
    { title: 'else', completed: false, id: '2' }
  ])

+++

Random id


Non-determinism

+++

Questions

  • how does a new item get its id?
  • can you override random id generator from DevTools?

+++

Iframed contexts

Contexts

+++

Application under test

Application under test


Stub application's random generator

  • test "creates an item with id 1" in 06-app-data-store/spec.js
  • get the application's context using cy.window
  • get application's window.Math object
  • can you stub application's random generator?
    • hint use cy.stub

+++

Confirm spy's behavior

  • test "creates an item with id using a stub"
  • write a test that adds 1 item
  • name spy with an alias cy.spy(...).as('name')
  • get the spy using the alias and confirm it was called once

Abstract common actions

The tests can repeat common actions (like creating items) by always going through the DOM, called page objects

The tests can access the app and call method bypassing the DOM, called "app actions"

The tests can be a combination of DOM and App actions.

+++

Practice

Write a test that:

  • dispatches actions to the store to add items
  • confirms new items are added to the DOM

(see next slide) +++

it('adds todos via app', () => {
  // bypass the UI and call app's actions directly from the test
  // using https://on.cypress.io/invoke
  // app.$store.dispatch('setNewTodo', <desired text>)
  // app.$store.dispatch('addTodo')
  // and then check the UI
})

+++

Todo: test edge data case

it('handles todos with blank title', () => {
  // add todo that the user cannot add via UI
  cy.window()
    .its('app.$store')
    .invoke('dispatch', 'setNewTodo', '  ')
  // app.$store.dispatch('addTodo')
  // confirm the UI
})

+++

⚠️ Watch out for stale data

Note that the web application might NOT have updated the data right away. For example:

getStore().then(store => {
  store.dispatch('setNewTodo', 'a new todo')
  store.dispatch('addTodo')
  store.dispatch('clearNewTodo')
})
// not necessarily has the new item right away
getStore().its('state')

Note: In a flaky test cypress-io/cypress-example-recipes#246 the above code was calling getStore().its('state').snapshot() sometimes before and sometimes after updating the list of todos.

+++

⚠️ Watch out for stale data

Solution: confirm the data is ready before using it.

// add new todo using dispatch
// retry until new item is in the list
getStore()
  .its('state.todos')
  .should('have.length', 1)
// do other checks

🏁 App Access

  • when needed, you can access the application directly from the test

Read also: https://www.cypress.io/blog/2018/11/14/testing-redux-store/, https://glebbahmutov.com/blog/stub-navigator-api/

➡️ Pick the next section