Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access data model in VueJS with Cypress (application actions)

Tags:

vue.js

cypress

I recently came across this blog post: Stop using Page Objects and Start using App Actions. It describes an approach where the application exposes its model so that Cypress can access it in order to setup certain states for testing.

Example code from the link:

// app.jsx code
var model = new app.TodoModel('react-todos');

if (window.Cypress) {
  window.model = model
}

I'd like to try this approach in my VueJS application but I'm struggling with how to expose "the model".

I'm aware that it's possible to expose the Vuex store as described here: Exposing vuex store to Cypress but I'd need access to the component's data().

So, how could I expose e.g. HelloWorld.data.message for being accessible from Cypress?

Demo application on codesandbox.io

Would it be possible via Options/Data API?

like image 216
Robert Strauch Avatar asked Jun 10 '20 06:06

Robert Strauch


1 Answers

Vue is pretty good at providing it's internals for plugins, etc. Just console.log() to discover where the data sits at runtime.

For example, to read internal Vue data,

either from the app level (main.js)

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

then in the test

cy.window().then(win => {
  const message = win.Vue.$children[0].$children[0].message; 
}

or from the component level

mounted() {
  if (window.Cypress) {
    window.HelloWorld = this;
  }
}

then in the test

cy.window().then(win => {
  const message = win.HelloWorld.message; 
}

But actions in the referenced article implies setting data, and in Vue that means you should use Vue.set() to maintain observability.

Since Vue is exposed on this.$root,

cy.window().then(win => {
  const component = win.HelloWorld;
  const Vue = component.$root;
  Vue.$set(component, 'message', newValue);
}

P.S. The need to use Vue.set() may go away in v3, since they are implementing observability via proxies - you may just be able to assign the value.


Experimental App Action for Vue HelloWorld component.

You could expose a setter within the Vue component in the mounted hook

mounted() {
  this.$root.setHelloWorldMessage = this.setMessage;
},
methods: {
  setMessage: function (newValue) {
    this.message = newValue;
  }
}

But now we are looking at a situation where the Cypress test is looking like another component of the app that needs access to state of the HelloWorld.

In this case the Vuex approach you referenced seems the cleaner way to handle things.

like image 158
Richard Matsen Avatar answered Nov 10 '22 22:11

Richard Matsen