Emulate the selection process using element-ui and vue-test-utils

During my unit tests using Jest and Element-ui in Vue, I encountered an issue with a component containing a select element with 2 options. After selecting an option from the dropdown, I needed to verify that a specific action was called.

1) Everything worked perfectly with standard select and option HTML tags.

// Fruit.vue

<template lang="pug">
  select(
    v-model="fruit"
  )
    option(
      v-for="item in fruits"
      :label="item.label"
      :value="item.value"
    )
</template>
<script>
export default {
  data () {
    return {
      fruits: [
        {
          label: 'Banana',
          value: false
        },
        {
          label: 'Apple',
          value: false
        }
      ]
    }
  },
  computed: {
    fruit: {
      get () {
        return this.$store.state.fruit
      },
      set (fruit) {
        this.$store.dispatch('setSelectedFruit', { fruit })
      }
    }
  }
</script>

// DOM

<select>
  <option label="Banana" value="false"></option>
  <option label="Apple" value="false"></option>
</select>

// Fruit.spec.js

it('verifies the call to the "setSelectedFruit" action after selection', () => {
  const wrapper = mount(Fruit, { store, localVue })
  const options = wrapper.find('select').findAll('option')

  options.at(1).setSelected()
  expect(actions.setSelectedFruit).toHaveBeenCalled()
})

The challenge arose when using element-ui's el-select and el-option, which have different interaction patterns with the DOM.

2) Using el-select and el-option

// Fruit.vue

The code remains unchanged, except for replacing select with el-select and option with el-option.

// DOM

<div class="el-select-dropdown">
  <div class="el-select-dropdown__wrap">
    <ul class="el-select-dropdown__list">
      <li class="el-select-dropdown__item">
        <span>Banana</span>
      </li>
      <li class="el-select-dropdown__item">
        <span>Apple</span>
      </li>
    </ul>
  </div>
</div>

// Fruit.spec.js

a)

it('verifies the call to the "setSelectedFruit" action', () => {
  const wrapper = mount(Fruit, { store, localVue })
  const options = wrapper.find('.el-select-dropdown__list').findAll('el-select-dropdown__items')
  
  options.at(1).setSelected()
  expect(actions.setSelectedFruit).toHaveBeenCalled()
})

b) Since setSelected is just an alias as per the vue-test-utils documentation, I attempted a workaround:

it('verifies the call to the "setSelectedFruit" action', () => {
  const wrapper = mount(Fruit, { store, localVue })
  const options = wrapper.findAll('.el-select-dropdown__item')
  const select = wrapper.find('.el-select-dropdown__list')
  
  options.at(1).element.selected = false
  select.trigger('change')
  expect(actions.setSelectedFruit).toHaveBeenCalled()
})

While the second method successfully sets the chosen option as selected, the trigger on the select does not update the v-model.

Hence, if anyone has a solution to this problem or knows of another library (besides vue-test-utils) capable of simulating the functionality of element-ui's el-select, your insights would be highly appreciated.

Answer №1

Triggering a click event within the <el-dropdown> or <el-select> components to display the dropdown item can be quite challenging. However, after experimenting with mock elements, I was able to successfully achieve this functionality.

/mock/div.vue

<template>
  <div>
    <slot></slot>
    <slot name="dropdown"></slot>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({   
  inheritAttrs: true
})
</script>

jest.setup.js

import { config } from '@vue/test-utils'
import Div from './mock/div.vue'
config.global.components = {  
   ElDropdown: Div,
   ElDropdownItem: Div,
   ElDropdownMenu: Div
}

Answer №2

To make this work, I triggered a click on the dropdown item you want to simulate:

wrapper.findAll('.el-select-dropdown__item').at(1).trigger('click');
await Vue.nextTick();
expect(YourExpectStatement);

In my case, using Vue.nextTick() was necessary as it allows the DOM to update its cycle. You can find more information here. Also, remember to make your test function async like so:

it('Name of Async Test', async () => {

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Steps to Remove the Displayed Image upon Click

I have a collection of images such as {A:[img1,img2], B:[img1]}. My goal is to remove the array values that correspond to previewed images upon clicking the delete button. Each image is equipped with its own delete button for this purpose. This snippet ...

Creating a loop to iterate through JSON data being received

I successfully used JSON to display data, but I am now wondering how I can print all the database entries into a div or table. JavaScript $(document).ready(function() { $.ajax({ type : 'POST', url : 'server.php', dataTyp ...

Incorporating a delete button onto an image using JavaScript

I am currently developing a BlogApp and facing difficulty in attempting to include a button on an image. The image is being retrieved from the Django database in JavaScript (HTML). My goal is to have a clickable button overlaid on the image. views.py def ...

Encountering challenges with implementing debouncing functionality in React programming

import React,{useState} from 'react'; const app = () => { const [inputValue, setInputValue] = useState(); const handleChange = (e) => { setInputValue(e.target.value); console.log(inputValue); } const d ...

Is there a method to refresh the entire DOM-based location without having to reload the browser window?

Is it possible to achieve smooth asynchronous page transitions without breaking existing JavaScript animations in a system like Webflow? I'm struggling to find a way to present new elements to the DOM without disrupting the animations that are already ...

When coding in JavaScript, the value of "this" becomes undefined within a class function

I'm facing an issue with my TypeScript class that contains all my Express page functions. When I try to access the class member variable using this, I get an 'undefined' error: class CPages { private Version: string; constructor(ver ...

When the Ajax "GET" request is made to the intra-service, the CMS service worker will respond with an "OK" even when offline

Hello there, We are currently utilizing an open-source CMS that recently received an upgrade with a new feature - a javascript serviceworker implementation to manage all requests. This CMS includes workflow forms where users engage (created by us). Durin ...

Having trouble with Postgres not establishing a connection with Heroku

My website is hosted on Heroku, but I keep encountering the same error message: 2018-05-06T19:28:52.212104+00:00 app[web.1]:AssertionError [ERR_ASSERTION]: false == true 2018-05-06T19:28:52.212106+00:00 app[web.1]:at Object.exports.connect (_tls_wrap.js:1 ...

Image not yet clicked on the first try

I am encountering an issue with my image gallery. Currently, when I click on a thumbnail, the large image is displayed. However, I would like the first image to show up without requiring the user to click on its thumbnail. How can I address this problem? B ...

How come I'm not receiving an error message when I enter an incorrect email or password?

Whenever I try to log in with the wrong password and email, no error message is displayed. Instead, it simply logs me in and takes me to the main page. Can someone please assist me in implementing an error message display for incorrect login details? imp ...

What are some efficient ways to reduce the size of the vendor.js file generated by webpack

After running Google LightHouse on my development site, I received a warning advising to "Remove unused JavaScript". The site is built using Vue.js and webpack. It seems that the vendor.js file is being generated from the node_modules directory. I am wond ...

Issue with JavaScript Date.parse function not functioning as expected

I have implemented a date validation method in my application to check if a given date is valid or not. myApp.isValidDate = function(date) { var timestamp; timestamp = Date.parse(date); if (isNaN(timestamp) === false) { return true; } return ...

Encountered an Xpath error while attempting to create a random email generator using Selenium IDE

While attempting to execute a script, I encountered an "element not found" error with Selenium failing to detect the xpath. My goal is to randomly generate email addresses. Every time there is an error message stating: [error] Element .//[@id='GmailA ...

Dealing with numerous Ajax calls within a single Ajax request

I am utilizing the $http method in angularjs to retrieve multiple "parent" elements. Within the success method of these Ajax calls, I need to loop through the parent elements and make another Ajax call for each parent element to fetch its corresponding chi ...

EmberJS: Learning how to create a record with a belongsTo relationship

My issue involves using Posts and Comments to explain my problem. In my post_controller, I am trying to create a new record for a comment related to the current post. What is the recommended way to achieve this in Ember? The relationship between Post and ...

Issue with Bootstrap Navbar dropdown functionality not functioning correctly in browsers, but working fine on Codepen

I'm encountering an issue with a dropdown menu in the navbar of my document. The dropdown menu works fine in my codepen but not in my text editor (Sublime). I've tried various solutions and couldn't find a fix, so I'm reaching out here ...

What is the best way to style output in jQuery for a specific div?

I have developed a tool for creating forms, but I am struggling to format the output neatly like pretty print. I have tried using \n and pre tags as well. allCont += "<label>"+insCleaned+"</label><input type='text' name= ...

How can I transfer Gmail message using express rendering parameters?

Using passport-google-oauth for authentication and the node-gmail-api for fetching gmail, I aim to display gmail message after authentication. In order to achieve this, I have written the following code in routes.js: app.get('/profile', isLogged ...

Updating the JSON format output from snake case to camel case in a React web application

Modifying JSON output in a React Web app to change keys from snake case to camel case Currently, the API endpoint response is structured like this: [ { "id": 1, "goals_for": 0, "goals_against": 0, "points": 0 } ] ...

Is there a Node Package available for storing data indefinitely?

When I execute my code, I need to store a variable permanently. Is there a node package or another method to achieve this? I want to ensure that I can access the stored data even after restarting my server. For instance, in my file named "runMe.js": var ...