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

Is it allowed to use an ID as a variable identifier?

One method I often use is assigning a variable with the same name as the id of an element, like this: randomDiv = document.getElementById("randomDiv"); randomDiv.onclick = function(){ /* Do something here; */ } randomDiv.property = "value"; This tech ...

Retrieve the dynamically generated element ID produced by a for loop and refresh the corresponding div

I am facing a challenge with my HTML page where I generate div IDs using a for loop. I want to be able to reload a specific div based on its generated ID without having to refresh the entire page. Here is a snippet of my HTML code: {% for list in metrics ...

The hyperlink and criteria provided are accurate, however, the webpage remains stagnant

My login page is supposed to redirect to the contact confirmation page when I receive a 200 response from the server, but it's not working. Can you help me find my mistake? const [form, setForm] = useState({}); async function checkLogin() { tr ...

Is there a Joomla extension available that can display or conceal content upon clicking?

Looking to enhance my Joomla site by installing a plugin that allows me to toggle the visibility of content with a click, similar to how FAQ sections work on many websites. Question 1 (click here for the answer) { Details for question 1 go here } Questi ...

Configuration file included in Node.js package for distribution

Someone recommended incorporating Continuous Integration for a pre-existing application (FrontEnd: Node.js - BackEnd: .Net API). At the moment, the API endpoints are hardwired in the .js files which become minified after being built using webpack. I plan ...

What is the best way to toggle dropdown menu items using jQuery?

Upon clicking on an li, the dropdown menu associated with it slides down. If another adjacent li is clicked, its drop down menu will slide down while the previous one slides back up. However, if I click on the same li to open and close it, the drop down m ...

What steps do I need to take to retrieve my paginated data from FaunaDB in a React frontend application?

I am facing a challenge when trying to access the data object that contains the keys (letter and extra) in my response from the faunadb database to the frontend react. Although I have used the map function in my frontend code, I have not been successful ...

Execute the assignment of exports.someFunction from within a callback function

My Express route is set up like this: app.get('/api/:type/:id', api.getItemById); The function api.getItemById resides in the api module within routes. However, inside the api module, I need to execute a function that connects to the database a ...

Navigating the route with quickness

Upon accessing the localhost, I encountered an issue with the code snippet below: When I try to access it, I receive an error message saying "Cannot GET /". var express = require('express'); var router = express.Router(); /* GET home page. */ r ...

'Error: The type is missing the 'previous' property - Combining TypeScript with ReactJS'

I am quite new to using reactjs and ts. While I understand the error that is occurring, I am unsure of the best solution to fix it. Currently working with reactjs, I have created an: interface interface IPropertyTax { annul: { current: number; p ...

Can Facebox's settings be adjusted during runtime? If so, how can this be done?

Can Facebox settings be accessed and customized? For instance, I am interested in setting the location of the loading image dynamically as shown on line 4: <script type="text/javascript" src="<?php echo base_url(); ?>media/facebox/facebox.js" > ...

When implementing afui and jQuery on PhoneGap, an error was encountered: "TypeError: Cannot read property 'touchLayer' of object function (selector, context)"

While working on deploying a web application using phonegap with afui (Intel Appframework UI) for Android, I encountered an issue when testing it in the android emulator. The debug console displayed the following error right after launching the app: Uncau ...

Vue.js The mp3 files have been successfully added to an array, yet the audio remains silent

While coding, I faced an issue that I resolved by doing some research online and tweaking the sample code. As I added more lines of code, I encountered sections that were a bit confusing to me, but I managed to make them work. My main objective is to devel ...

Determining the length and angle of a shadow using X and Y coordinates

I'm currently tackling the task of extracting data from a file generated by a software program that has the ability to add a shadow effect to text. The user interface allows you to specify an angle, length, and radius for this shadow. https://i.stack ...

Customizing Tabs in Material UI v5 - Give your Tabs a unique look

I am attempting to customize the MuiTabs style by targeting the flexContainer element (.MuiTabs-flexContainer). Could someone please clarify the significance of these ".css-heg063" prefixes in front of the selector? I never noticed them before upgrading my ...

Managing headers for localhost with Access-Control-Allow-Origin

I've run into a challenge with my React app. I'm making endpoint calls to different servers and have withCredentials set to true to include a token/cookie in the requests. The issue arises when trying to make this work seamlessly on localhost. S ...

What's the most effective method for implementing dynamic navigation in NextJS using Firebase integration?

Excited to begin building a web app using NextJS and Google's Firebase. This app will have both an admin panel and a public site, with the ability for the admin to edit the navigation of the public site. I'm debating whether it's wise to fet ...

Save picture in localStorage

Hello, I am currently working on a page where I need to retrieve an image from a JSON file and store it locally. Below is the code I have been using: <!DOCTYPE html> <html> <head> <script src="http://code.jquery.com/jquery-1.10.1.min. ...

Utilizing Conditional Styling for an Array of Objects within a Textarea in Angular 6

My array contains objects structured as follows: list =[ { name:"name1", value:true } { name:"name2", value:false } { name:"name3", value:true } { name:"name4", value:false ...