Mastering Vue Unit Testing with Vue Test Utils
This challenge focuses on building a robust testing suite for a Vue.js application using Vue Test Utils. You will learn to effectively mount Vue components, interact with them, and assert their behavior, which is crucial for ensuring the stability and maintainability of your Vue applications.
Problem Description
Your task is to write unit tests for a simple Vue.js component using TypeScript and Vue Test Utils. The component, UserProfile.vue, displays a user's name and email, and has a button to toggle the visibility of the user's email.
Component: UserProfile.vue
<template>
<div>
<h2>User Profile</h2>
<p>Name: {{ name }}</p>
<button @click="toggleEmailVisibility">
{{ emailVisible ? 'Hide Email' : 'Show Email' }}
</button>
<p v-if="emailVisible">Email: {{ email }}</p>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
name: 'UserProfile',
props: {
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
},
setup(props) {
const emailVisible = ref(false);
const toggleEmailVisibility = () => {
emailVisible.value = !emailVisible.value;
};
return {
emailVisible,
toggleEmailVisibility,
};
},
});
</script>
What needs to be achieved:
You need to create a test file (e.g., UserProfile.spec.ts) that contains the following unit tests:
- Initial Render Test: Verify that the component renders correctly with the provided
nameprop. The email should not be visible initially. - Email Visibility Toggle Test:
- Click the "Show Email" button. Assert that the email is now visible and the button text changes to "Hide Email".
- Click the "Hide Email" button. Assert that the email is no longer visible and the button text changes back to "Show Email".
- Prop Rendering Test: Ensure that both the
nameandemailprops are correctly rendered when the email is visible.
Key requirements:
- Use
vue-test-utilsfor mounting and interacting with the component. - Write tests in TypeScript.
- Mock any necessary dependencies if the component were more complex (though for this simple component, direct prop passing is sufficient).
Expected behavior:
- When the component is mounted with
name="John Doe"andemail="john.doe@example.com", it should display "Name: John Doe" and a button with the text "Show Email". The email itself should not be displayed. - Clicking the "Show Email" button should display "Email: john.doe@example.com" and change the button text to "Hide Email".
- Clicking the "Hide Email" button should hide the email again and change the button text back to "Show Email".
Edge cases to consider:
- What happens if the
nameoremailprops are empty strings? (For this challenge, assume valid string inputs as perrequired: true.)
Examples
Example 1: Initial Render
// Assuming UserProfile.vue is imported and mounted correctly
const wrapper = mount(UserProfile, {
props: {
name: 'Jane Smith',
email: 'jane.smith@example.com',
},
});
// Assertions:
expect(wrapper.find('h2').text()).toBe('User Profile');
expect(wrapper.find('p:first-of-type').text()).toBe('Name: Jane Smith');
expect(wrapper.find('button').text()).toBe('Show Email');
expect(wrapper.find('p:last-of-type').exists()).toBe(false); // Email should not be visible
Example 2: Toggling Email Visibility
// Assuming component is mounted as in Example 1
// Click to show email
await wrapper.find('button').trigger('click');
// Assertions after showing
expect(wrapper.find('button').text()).toBe('Hide Email');
expect(wrapper.find('p:last-of-type').text()).toBe('Email: jane.smith@example.com');
expect(wrapper.find('p:last-of-type').exists()).toBe(true);
// Click to hide email
await wrapper.find('button').trigger('click');
// Assertions after hiding
expect(wrapper.find('button').text()).toBe('Show Email');
expect(wrapper.find('p:last-of-type').exists()).toBe(false);
Constraints
- All tests must be written in TypeScript.
- You must use the
vue-test-utilslibrary. - The tests should be self-contained and runnable with a standard Vue testing setup (e.g., using Vitest or Jest).
- Assume the component's internal logic (
setupfunction) remains as provided.
Notes
- You'll need to install
vue-test-utilsand any necessary testing framework (like Vitest or Jest) and their TypeScript types. - Consider using
awaitwhen triggering events, as DOM updates might be asynchronous. - Familiarize yourself with
vue-test-utils'smountfunction and the methods available on thewrapperobject (e.g.,find,text,trigger,exists). - The
nameandemailprops are crucial for testing the initial state and verifying content. - The button's text dynamically changes, which is a good indicator to test the state change.