<v-text-field
density="compact"
v-model="textMaterial"
:rules="textMaterialRules"
label="Text Material"
></v-text-field>
This is a simple example of how I am using v-text-field in a with a at the bottom of type submit which triggers the rule output to be displayed. The rules are defined as:
export default defineComponent({
data() {
return {
textMaterial: '',
textMaterialRules: [
(value: string | undefined) => {
if (value?.length != 0) return true
return 'An error message.'
}
]
}
}
This works fine when testing manually. But testing using vitest I am not able to find the element which displays the rule output. Its class seems to be .v-messages__message
.
it('displays error message', async () => {
const wrapper = mount(Page);
await wrapper.vm.$nextTick();
const submitButton = wrapper.find('v-btn[type="submit"]');
expect(submitButton.exists()).toBe(true);
await submitButton.trigger('click');
await wrapper.vm.$nextTick();
// TODO: not able to find v-messages__message elements
// expect(wrapper.find('.v-messages__message').text()).toContain('the error message above.');
});
Any help will be appreciated, I have been stuck on this for so long. I have tried getting v-form from wrapper.find() and figure out something but nothing good came out of it. wrapper.html() returns only html with v-form and v-text-field so I am thinking is there no way of getting this rules data from this wrapper and there is something else that I am not aware of to be done to make this text work.
Edit: There are 2 such v-text-fields that I am using on this component so I am using findAll generally. Use this to replicate: https://github.com/ksushant881/vue-testing-issue
The test will not actually render the Vuetify components unless you provide it with a Vuetify instance to resolve the components (Reference).
I modified the example that you provided:
// src/components/__tests__/HelloWorld.spec.ts
import { describe, it, expect } from 'vitest'
import { mount, config } from '@vue/test-utils'
import HelloWorld from '../HelloWorld.vue'
import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
// Create a vuetify instance with all available components
const vuetify = createVuetify({components, directives});
// This turns off stubs that hide some components
config.global.stubs.transition = false;
config.global.stubs['transition-group'] = false;
describe('HelloWorld', () => {
it('displays error message', async () => {
const wrapper = mount(HelloWorld, { global: { plugins: [vuetify] } });
// Notice the change from `v-btn` to `.v-btn`,
// since all vuetify components will now be rendered correctly
const submitButton = wrapper.find('.v-btn[type="submit"]');
expect(submitButton.exists()).toBe(true);
let messages = wrapper.find('.v-messages__message');
expect(messages.exists()).toBe(false);
// Triggering 'click' will not actually do anything,
// since the validation of the v-text-field is tied
// to the 'submit' event of the v-form
await submitButton.trigger('submit');
// It seems like `await wrapper.vm.$nextTick()` is not needed.
messages = wrapper.find('.v-messages__message');
expect(messages.exists()).toBe(true);
expect(messages.text()).toContain('error message');
});
})
The configuration needed to be adapted, too (Reference).
// vitest.config.js
// ...
export default mergeConfig(
// ...
defineConfig({
test: {
globals: true, // added
server: { deps: { inline: ['vuetify'] } }, // added
// ...
}
})
)