Testing child components in Vue 3 with Vitest and Testing Library
I am implementing a small Vue3 app that guides the user through several steps by clicking next/previous button. I want to add tests that verify that the correct view/component is showing up after clicking on next/previous button.
- There is no vue-router
- I am using a Pinia store
At the moment I am using Vitest, vue-testing-libary and jest-dom to write the tests. I'm not sure if it is possible to accomplish my issue with these tools. If possible I don't want to use vue-test-utils because vue-testing-libary is build on top of it and seems to be the newer solution. Maybe I need to use Cypress?
<template>
<div v-if="store.myCondition.length > 0">
<FirstView v-if="store.step === 1"/>
<SecondView v-if="store.step === 2"/>
<ThirdView v-if="store.step === 3"/>
</div>
<div v-else>Loading ...</div>
</template>
Here is a dummy test that does nothing but printing the rendered HTML. In the rendered HTML there is no view rendered at all.
test('debug test', () => {
screen.debug()
})
do you know?
how many words do you know
See also questions close to this topic
-
How do I instrument `.vue` files using the istanbul/nyc command line
Ultimately, I am trying to instrument my Vue 3 app so that I can get code coverage that includes my
.js
and.vue
files using the below command:nyc instrument --compact=false src instrumented
I see that my
.vue
files are getting duplicated and included in myinstrumented
folder thanks to my.nycrc
configuration.{ "extension": [".js", ".vue"] }
But they are not getting instrumented.
They are simply copies.
What else do I need to do to get these files properly instrumented so that they can be included in my coverage report?
-
vuetify v-select: 'item-text' override does not work
Vuetify (v3) v-select does not work when passing in an array. I'm wondering if anyone can suggest a work around?
Even the example on their website does not work: https://next.vuetifyjs.com/en/components/selects/
I've read any/every article remotely related with no luck, any assistance is greatly appreciated.
-
vitest test await async completion of onMounted callback in vue3 component
I'm playing around with Vitest and want to wait for the completion of a couple mocked fetches in the onMounted lifecycle hook in my component:
My test:
import { mount } from '@vue/test-utils'; import HelloWorld from './HelloWorld.vue'; import { mockGet } from 'vi-fetch'; import 'vi-fetch/setup'; mockGet('api/welcome-message').willResolve('Welcome message from vitest'); mockGet('api/players').willResolve(['Mario', 'Luigi']); test('the players have been rendered', async () => { const wrapper = mount(HelloWorld); const lastPlayer = await wrapper.findAll('.player'); expect(lastPlayer).toHaveLength(2); });
My component script:
<script setup lang="ts"> import { onMounted, ref } from 'vue'; const apiMessage = ref(''); const players = ref<string[]>([]); onMounted(async () => { const fetchMessage = fetch('api/welcome-message') .then((res) => res.text()) .then((message: string) => (apiMessage.value = message)); const fetchPlayers = fetch('api/players') .then((res) => res.json()) .then((playersRes: string[]) => (players.value = playersRes)); }); </script>
The test fails because, I assume, the code running in onMounted doesn't have time to complete before the test looks for all
.player
<li>
elements (rendered with a v-for) off of theplayers
ref. How can I ask vitest to wait for the responses from each of these fetches before calling the test a failure.Thanks.
-
Jwt, VueRouter and Vue Component
Just a quick question regarding the mentioned technologies.
I have a vue project that connects to a flask backend for authentication, I return a JWT that has a custom payload with role, name, and etc.
How would you store the JWT, so, that for example the navbar could update once logged in with welcome “name”.
Local storage, Pinia, Vuex or another method ? Please explain your reasoning as I’m learning and have never done this before
Thank you
-
Uncaught SyntaxError: The requested module '/node_modules/.vite/vue.js?v=31b05063' does not provide an export named 'default'
I don't know how to solve this problem. When I started project vue3.js , console show me this error. This import in pinia store. I tryied change first line with import to "import Vue from 'vue';" (without curcy braces), but error don't disappear.
import { Vue } from 'vue'; import { defineStore } from 'pinia'; import moment from 'moment'; import _ from 'lodash'; import router from '@/router';
-
jest-dom eslint rule violation not breaking test
I'm using Reactjs with CRA. I have a test like this;
I'm deliberately forcing jest-dom to produce this
prefer-to-have-text-content
warning. My test still runs OK and the result is success. Now, I want my test to fail. My.eslintrc
file is like;{ "plugins": ["testing-library", "jest-dom"], "extends": [ "react-app", "react-app/jest", "plugin:testing-library/react", "plugin:jest-dom/recommended" ], "rules": { "jest-dom/prefer-to-have-text-content": "error" } }
However, my test still succeds! How can I make my test fail in case of such jest-dom issues?
-
Error in test files: It should match the snapshot Objects are not valid as a React child
I am running into this same error across 7 different test files in our React App. This started to happen after I went through entire app to upgrade a library.
it should match the snapshot Objects are not valid as a React child (found: object with keys {id, label, subtext, value, checked}). If you meant to render a collection of children, use an array instead.
I think if I can figure out how to re-render the snapshot files this may or may not solve my problem.
I did try the following solution:
npm install jest -g jest --updateSnapshot
^^ That did not work at all and ended up with errors in every single test file
I also went through the list of answers on this page (but none are in relation to this type of error and didn't work) = STACKOVERFLOW_ANSWERS
Here is my code: FiberReportForm.test.tsx
import React from 'react'; import { render } from '@testing-library/react'; import '@testing-library/jest-dom/extend-expect'; import { IFiberDetailsLocation } from '../../../../types/types.generated'; import FiberReportForm from './FiberReportForm'; const testData = { id: '6e81a4d4-596e-4146-a9ff-819eb9e9157d', address: { friendlyName: 'Pfannerstill Gateway', street: '213 Winfield Walk', city: 'Lake Vivianshire', state: 'MA', }, circuit: { id: '56..T12227.VA.TWCC', bandwidth: '10 Mbps', }, }; describe('FiberReportForm Component', () => { test('it should match the snapshot', () => { const { asFragment } = render( <FiberReportForm data={testData as unknown as IFiberDetailsLocation} onSubmit={(formData) => console.log(formData)} /> ); expect(asFragment()).toMatchSnapshot(); }); });
FiberReportForm.test.tsx.snap
// Jest Snapshot v1 exports[`FiberReportForm Component it should match the snapshot 1`] = ` <DocumentFragment> <div class="report-form" > <div class="report-form__upper" > <h1> Create Fiber Report </h1> <span> Please select the data you want in your report. </span> </div> <div class="kite-card report-form__card" > <h2> 1. Location </h2> <div class="report-form__card-content" > <dl> <dt class="report-form__card-content-label" > Location Name: </dt> <dd> Pfannerstill Gateway </dd> </dl> <dl> <dt class="report-form__card-content-label" > Address: </dt> <dd> 213 Winfield Walk, Lake Vivianshire, MA </dd> </dl> <dl> <dt class="report-form__card-content-label" > Circuit ID: </dt> <dd> 56..T12227.VA.TWCC </dd> </dl> </div> </div> <div class="kite-card report-form__card" > <h2> 2. Time Increment </h2> <div class="report-form__card-content" > <div aria-labelledby="timeSelect" class="kite-radio kite-form-group " role="group" > <div class="kite-radio__button-container" > <label class="kite-custom-control kite-custom-radio kite-radio__button" for="day" > <input aria-checked="true" checked="" class="kite-custom-control-input" id="day" name="timeSelect" tabindex="0" type="radio" value="day" /> <div class="kite-custom-control-indicator" /> <span class="kite-custom-control-description" > Day <p aria-hidden="true" class="kite-radio__subtext" > Data is available for the past 365 days. </p> </span> </label> <label class="kite-custom-control kite-custom-radio kite-radio__button" for="hour" > <input aria-checked="false" class="kite-custom-control-input" id="hour" name="timeSelect" tabindex="-1" type="radio" value="hour" /> <div class="kite-custom-control-indicator" /> <span class="kite-custom-control-description" > Hour <p aria-hidden="true" class="kite-radio__subtext" > Data is available for the past 90 days. Maximum date range is 31 days. </p> </span> </label> <label class="kite-custom-control kite-custom-radio kite-radio__button" for="fifteen" > <input aria-checked="false" class="kite-custom-control-input" id="fifteen" name="timeSelect" tabindex="-1" type="radio" value="fifteen" /> <div class="kite-custom-control-indicator" /> <span class="kite-custom-control-description" > 15 Minutes <p aria-hidden="true" class="kite-radio__subtext" > Data is available for the past 31 days. Maximum date range is 31 days. </p> </span> </label> </div> </div> </div> <span class="report-form__card-footer" > Times in UTC timezone </span> </div> <div class="kite-card report-form__card" > <h2> 3. Date Range </h2> <div class="report-form__card-content--column" > <div class="report-form__card-content--daterange" > <div class="rkp-date-range rkp-date-range--with-label rkp-date-range--with-options" > <span class="rkp-date-range__label" > Date Range </span> <div class="rkp-date-range__toggle" > <button class="rkp-date-range__toggle-button" > <span class="kite-icon " style="height: 18px; width: 18px;" > <svg aria-hidden="true" aria-label="" class="ki icon-calendar " role="" style="height: 100%; width: 100%; background-color: transparent;" > <use xlink:href="/assets/kite-icons.svg#ki-calendar" /> </svg> </span> </button> <div class="rkp-date-range__toggle-date-container" > <input class="rkp-date-range__toggle-date" id="startDisplay" max="2022-03-17" min="2021-03-17" step="1" type="date" value="2022-03-11" /> <span> - </span> <input class="rkp-date-range__toggle-date" id="endDisplay" max="2022-03-17" min="2022-03-11" step="1" type="date" value="2022-03-17" /> </div> </div> </div> </div> </div> </div> <div class="report-form__submit-container" > <button class="kite-btn kite-btn-lg" style="display: flex;" type="button" > <span class="kite-btn__content kite-btn-outline-primary" tabindex="-1" > Cancel </span> </button> <button class="kite-btn kite-btn-lg" style="display: flex;" type="submit" > <span class="kite-btn__content kite-btn-primary" tabindex="-1" > Submit </span> </button> </div> </div> </DocumentFragment> `;
-
Adding Props to found components throw the mounted wrapper
I have a form that contains a selector reusable component like this
<template> <div class="channelDetail" data-test="channelDetail"> <div class="row"> <BaseTypography class="label">{{ t('channel.detail.service') }}</BaseTypography> <BaseSelector v-model="serviceId" data-test="serviceInput" class="content" :option="servicePicker.data?.data" :class="serviceIdErrorMessage && 'input-error'" /> </div> <div class="row"> <BaseTypography class="label">{{ t('channel.detail.title') }}</BaseTypography> <BaseInput v-model="title" data-test="titleInput" class="content" :class="titleErrorMessage && 'input-error'" /> </div> </div> </template>
I'm going to test this form by using vue-test-utils and vitest. I need to set option props from the script to the selector. In my thought, this should be worked but not
it('test', async () => { const wrapper=mount(MyForm,{}) wrapper.findComponent(BaseSelector).setProps({option:[...some options]}) ---or wrapper.find('[data-test="serviceInput"]').setProps({option:[...some options]}) ---or ??? });
Could anyone help me to set the props into components in the mounted wrapper component?
-
vue 2 jest coverage is incorrect
I have setup unit testing using installation instructions from https://v1.test-utils.vuejs.org/
Tests are running properly. But the coverage is coming incorrectly.
In the report it is showing it has only 1 statement, 1 function, 2 branches for some reason.
It's not showing coverage for all the lines. It shows coverage in the first line and doesn't show coverage anywhere else. Don't know what's the issue is here.
I'm using Bootstrap-vue to render components. Can this create an issue with coverage? I'm asking this because the example.spec.js that came for the helloworld component is showing coverage correctly.
my dev dependencies
"devDependencies": { "@babel/core": "^7.12.16", "@babel/eslint-parser": "^7.12.16", "@vue/cli-plugin-babel": "~5.0.0", "@vue/cli-plugin-eslint": "~5.0.0", "@vue/cli-plugin-unit-jest": "^5.0.4", "@vue/cli-service": "~5.0.0", "@vue/test-utils": "^1.3.0", "@vue/vue2-jest": "^27.0.0-alpha.2", "babel-jest": "^27.0.6", "eslint": "^7.32.0", "eslint-plugin-vue": "^8.0.3", "flush-promises": "^1.0.2", "jest": "^27.0.5", "node-sass": "^7.0.1", "sass-loader": "^12.6.0", "vue-template-compiler": "^2.6.14" },
-
Vitest defineConfig, 'test' does not exist in type 'UserConfigExport'
Trying to setup vitest on an already existing vite (vue 3, typescript) project.
My vite.config.ts looks like this:
import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; export default defineConfig({ test: { globals: true, environment: 'jsdom', }, plugins: [vue()], });
But in VS code it complains:
On hover I see:
Argument of type '{ test: { globals: boolean; environment: string; }; plugins: Plugin[]; }' is not assignable to parameter of type 'UserConfigExport'. Object literal may only specify known properties, and 'test' does not exist in type 'UserConfigExport'.ts(2345)
I can make it go away if I change this line:
import { defineConfig } from 'vite';
To:
import { defineConfig } from 'vitest/config';
But why? What's up with this? Why should I have to import defineConfig from vitest in order to get it to support the test property?