Techniques for handling Vuetify with Cypress

DevOps

I am implementing the front end of a web application using Nuxt and Vuetify at work. I have been manually checking the behavior of each release, and it is tedious each time, so I introduced Cypress (E2E testing) to automate the behavior check and save time.

I would like to share with you some of the difficulties I encountered when introducing Cypress to a project that uses Nuxt and Vuetify.

Environment

The main libraries and versions used are listed below.

LibraryVersion
Nuxt2.15.8
Vue2.7.8
Vuetify2.6.8
Cypress10.4.0

Creating a test project

Create a test project using the npx create-nuxt-app command. The settings are as follows, but be sure to select Vuetify.js in the UI framework, as you will use later.

$ npx create-nuxt-app nuxt-cypress-app

create-nuxt-app v4.0.0
✨  Generating Nuxt.js project in nuxt-cypress-app
? Project name: nuxt-cypress-app
? Programming language: JavaScript
? Package manager: Yarn
? UI framework: Vuetify.js
? Nuxt.js modules: (Press <space> to select, <a> to toggle all, <i> to invert selection)
? Linting tools: ESLint, Prettier
? Testing framework: Jest
? Rendering mode: Single Page App
? Deployment target: Static (Static/Jamstack hosting)
? Development tools: jsconfig.json (Recommended for VS Code if you're not using typescript), Dependabot (For auto-updating dependencies, GitHub only)
? Continuous integration: GitHub Actions (GitHub only)
? What is your GitHub username? yamada
? Version control system: Git

Install cypress.

$ cd nuxt-cypress-app
$ yarn add -D cypress

Create a cypress directory under the project, create the following cypress configuration file (cypress.config.js), and store test files (tests).

nuxt-cypress-app
└── cypress
    └── cypress.config.js

Write the following in cypress.config.js.

const { defineConfig } = require('cypress')

module.exports = defineConfig({
  e2e: {
    baseUrl: 'http://localhost:3000',
    specPattern: "**/tests/*.spec.js",
    supportFile: false,
    video: true,
    videoUploadOnPasses: false,
    defaultCommandTimeout: 10000
  }
})

Add “e2e”: “cypress run –config-file=cypress/cypress.config.js –browser chrome” to the scripts in package.json directly under the project to quickly run E2E tests. Run npm run e2e to run the E2E test.

Create the file to be tested. This time, we will create a form to input name, date of birth, etc., and a completion page.

input form

<template>
  <v-container fluid>
    <v-text-field
      ref="name"
      :value="name"
      label=""
      maxlength="50"
      outlined
      data-cy="name"
      @change="(value) => (name = value)"
    >
      <template #prepend>Name</template>
    </v-text-field>

    <v-menu
      v-model="menu"
      :close-on-content-click="false"
      :nudge-right="40"
      transition="scale-transition"
      offset-y
      hide-details
      min-width="auto"
    >
      <template #activator="{ on, attrs }">
        <v-text-field
          id="birthday"
          ref="birthday"
          v-model="birthday"
          label=""
          outlined
          readonly
          clearable
          data-cy="birthday-text-field"
          v-bind="attrs"
          v-on="on"
          @click:clear="birthday = null"
        >
          <template #prepend>Birthday</template>
        </v-text-field>
      </template>
      <v-date-picker
        v-model="birthday"
        year-icon="mdi-calendar-edit"
        prev-icon="mdi-skip-previous"
        next-icon="mdi-skip-next"
        data-cy="birthday-date-picker"
        :day-format="(date) => new Date(date).getDate()"
        @input="menu = false"
      ></v-date-picker>
    </v-menu>

    <v-radio-group
      ref="sex"
      v-model="sex"
      row
      class="mt-0 mb-0"
    >
      <template #prepend>Sex</template>
      <v-radio
        id="male"
        value="male"
        label="male"
        data-cy="sex-male"
      ></v-radio>
      <v-radio
        id="female"
        value="female"
        label="female"
        data-cy="sex-female"
      ></v-radio>
    </v-radio-group>

    <v-row class="my-5">
      <v-col cols="10">
        <v-checkbox
          v-model="agreedWithEula"
          :label="`I agree`"
          color="primary"
          data-cy="agreed-with-eula"
        >
        </v-checkbox>
      </v-col>
    </v-row>

    <v-btn
      class="mx-0"
      cols="12"
      large
      block
      color="primary"
      nuxt
      data-cy="next-btn"
      @click="register"
    >
      register
    </v-btn>

  </v-container>
</template>

<script>
export default {
  name: 'RegisterIndex',
  data() {
    return {
      menu: false,
      name: '',
      birthday: '',
      sex: '',
      agreedWithEula: false
    }
  },
  methods: {
    register() {
      this.$router.push(
          `/register/complete/`
        )
    }
  }
}
</script>

<style scoped>
</style>

completion page

<template>
  <v-container fluid>
    Your registration is complete.
  </v-container>
</template>

<script>
export default {
  name: 'RegisterComplete'
}
</script>

<style scoped>
</style>

Implement E2E testing

Implement an E2E test. In the following scenario, you will create a test file.

①Fill in each item on the input form(Select the 8th day of the month 18 months before the present as your birthday).
②When you have completed the input items, click the “Register” button.
③Move to the completion page and verify that the text “Your registration is complete.

Create a test file named register.spec.js in the cypress test directory.

describe('test register page', () => {
  it('should register', () => {
    cy.visit('/register/')
    cy.get('[data-cy=name]').type('John')
    cy.get('[data-cy=birthday-text-field]').click()
    const datePicker = cy.get('[data-cy=birthday-date-picker]')
    for (let i = 0; i < 18; i++) {
      datePicker.get('[aria-label="Previous month"]').click()
    }
    cy.get('[data-cy=birthday-date-picker]').within(() => {
      cy.wait(1000)
      cy.get('div').contains('8').click()
    })

    cy.get('[data-cy=sex-female]').parent().click()
    cy.get('[data-cy=agreed-with-eula]').parent().click()
    cy.wait(1000)
    cy.get('[data-cy=next-btn]').click()
    cy.wait(1000)

    cy.contains(
      'Your registration is complete.'
    ).should('exist')
  })
})

If you run Cypress with npm run e2e, you can run the E2E test and take a video, as shown below.

Troubleshooting

Unable to check with v-radio or v-checkbox

It was not checked by simply calling the click method with cy.get(‘[data-cy=agreed-with-eula]’).click().
I need to call the parent method like cy.get(‘[data-cy=agreed-with-eula]’).parent().click() (I have also looked into the reason but have not figured it out yet).

I want to select a specific date with v-date-picker

// Get the date picker component
const datePicker = cy.get('[data-cy=birthday-date-picker]')

// You need to select 18 months forward from the current date in the project, so press the "Back to previous month" icon 18 times.
for (let i = 0; i < 18; i++) {
  datePicker.get('[aria-label="Previous month"]').click()
}

cy.get('[data-cy=birthday-date-picker]').within(() => {
  // Wait 1 second for browser rendering so the test can retrieve the date DOM.
  cy.wait(1000)
  // Click on 8th
  cy.get('div').contains('8').click()
})

Finally

I have uploaded the above test project to Github, so please clone it and try it out yourself.

コメント

タイトルとURLをコピーしました