'Cypress using actions from Pinia Vue3

I was learning some cypress from this video: https://www.youtube.com/watch?v=03kG2rdJYtc I'm interested with he's saying at 29:33: "programatic login" But he's using vue2 and Vuex.

My project is created with Vite and the state management is Pinia. So how can I do a programatic login using the pinia action?

For example the welcome logged in user should see dashboard:

describe('Welcome', () => {
  it('logged in user should visit dashboard', () => {
    // login
    cy.visit('/')
    cy.url().should('contain', '/dashboard')
  })
})

And my userStore:

export const useUserStore = defineStore({
  id: 'user',
  state: () => ({
    username: ref(useLocalStorage('username', null)),
  }),
  getters: {
    isLoggedIn: (state) => state.username !== null,
  },
  actions: {
    login(username, password) {
      return useAuthLoginService(username, password)
        .then((response) => {
          this.username = response.username
        })
        .catch((error) => {
          return Promise.reject(new Error(error))
        })
    },
  },
})

How can I call the login action on the cypress test? For now as a workaround I'm writing on a localstorage like:

localStorage.setItem('username', 'user')

And it works fine, because userStore catch this item from localstorage and passes like it's logged in... But I don't like this solution, seems fragile, and I'd like to use the action which is made for login users.

Another thing I tried is adding the app variable inside window but it doesn't work for me... don't understand why...

on main.js

The video shows that code:

const vue = new Vue({...})
if(window.Cypress){
  window.app = app
}

In my case it's:

const app = createApp(App)
if(window.Cypress){
  window.app = app
}

But in cypress tests the window.app it's undefined... I don't know how I would access to userStore using this... like it was vuex.



Solution 1:[1]

It probably depends on the way the store is set up.

In the Pinia demo app, the store is initialized in App.vue, so this is where I add the reference for Cypress to use

export default defineComponent({
  components: { Layout, PiniaLogo },

  setup() {
    const user = useUserStore()
    const cart = useCartStore()
    if (window.Cypress) {
      window.store = {user, cart)
    }
    ...

Then in the test (using the supplied main.spec.js)

let store;

describe('Pinia demo with counters', () => {
  beforeEach(() => {
    cy.viewport(1000, 1000)
    cy.visit(`http://localhost:${PORT}`).then(win => store = win.store)
  })

  it('works', () => {
    cy.wait(500) // wait for the JS to load
      .then(() => store.cart.addItem('Cypress test item'))  // invoke action
      .then(() => {
        const item1 = store.cart.items[0]                   // invoke getter
        cy.wrap(item1)
          .should('have.property', 'name', 'Cypress test item')  // passes
      })

The login action is asynchronous, so I guess to use it you might need to return the promise to allow Cypress to wait.

// user.js

async login(user, password) {
  const userData = await apiLogin(user, password)

  this.$patch({
    name: user,
    ...userData,
  })
  return userData   // this returns a promise which can awaited
},
// main.spec.js

describe('Pinia demo with counters', () => {
  beforeEach(() => {
    cy.viewport(1000, 1000)
    cy.visit(`http://localhost:${PORT}`).then(win => {
      store = win.store

      // default name in store before login
      cy.wrap(store.user.name).should('eq', 'Eduardo')

      // logging in
      store.user.login('ed', 'ed').then(() => {
        cy.wrap(store.user.name).should('eq', 'ed')
      })
    })
  })

Alternatively, wait for the name to change on the page

// main.spec.js

cy.visit(`http://localhost:${PORT}`).then(win => {
  store = win.store

  // default name in store
  cy.wrap(store.user.name).should('eq', 'Eduardo')

  // loggin on
  store.user.login('ed', 'ed')  
  cy.contains('Hello ed')              // waits for name on page to change
    .then(() => {          
      cy.wrap(store.user.name).should('eq', 'ed')
    })
})

Note that store commands run before Cypress commands in the same block, so that may trip you up in places.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1