@vue/test-utils, enzyme, and react-testing-library are utility libraries designed to simplify component testing in modern web applications, but they serve different frameworks and philosophies. @vue/test-utils is the official testing library for Vue.js, providing deep access to Vue component instances and lifecycle hooks. enzyme was the standard for React testing for years, offering shallow rendering and detailed DOM traversal, but it is now in maintenance mode. react-testing-library (now @testing-library/react) focuses on testing React components from the user's perspective, encouraging tests that resemble how users interact with the app rather than how components are implemented.
These tools help you test UI components, but they belong to different frameworks. @vue/test-utils is for Vue. enzyme and react-testing-library are for React. Choosing the right one depends on your framework and testing philosophy. Let's break down how they handle common testing tasks.
@vue/test-utils is built specifically for Vue.
// @vue/test-utils: Vue specific
import { mount } from '@vue/test-utils';
import MyComponent from './MyComponent.vue';
const wrapper = mount(MyComponent);
enzyme is built specifically for React.
// enzyme: React specific
import { shallow } from 'enzyme';
import MyComponent from './MyComponent.jsx';
const wrapper = shallow(<MyComponent />);
react-testing-library is built specifically for React.
// react-testing-library: React specific
import { render } from 'react-testing-library';
import MyComponent from './MyComponent.jsx';
render(<MyComponent />);
@vue/test-utils allows querying by CSS selectors or component references.
// @vue/test-utils: Query by selector
const wrapper = mount(MyComponent);
const button = wrapper.find('.submit-btn');
enzyme also relies heavily on CSS selectors and component types.
// enzyme: Query by selector
const wrapper = shallow(<MyComponent />);
const button = wrapper.find('.submit-btn');
react-testing-library encourages querying by role or text.
// react-testing-library: Query by role
import { screen } from 'react-testing-library';
const button = screen.getByRole('button', { name: /submit/i });
@vue/test-utils provides a trigger method on the wrapper.
// @vue/test-utils: Trigger event
const wrapper = mount(MyComponent);
await wrapper.find('button').trigger('click');
enzyme uses a simulate method on the wrapper node.
// enzyme: Simulate event
const wrapper = shallow(<MyComponent />);
wrapper.find('button').simulate('click');
react-testing-library uses fireEvent or user-event.
// react-testing-library: Fire event
import { fireEvent } from 'react-testing-library';
const button = screen.getByRole('button');
fireEvent.click(button);
@vue/test-utils is actively maintained by the Vue team.
// @vue/test-utils: Current Version Support
// Supports Vue 3.x fully
import { mount } from '@vue/test-utils';
enzyme is in maintenance mode and effectively deprecated for new work.
// enzyme: Deprecation Warning
// Not recommended for React 18+
import { shallow } from 'enzyme';
react-testing-library is active but renamed to @testing-library/react.
// react-testing-library: Package Rename
// Use @testing-library/react for new projects
import { render } from '@testing-library/react';
While the frameworks differ, these libraries share some core testing concepts.
// @vue/test-utils
mount(Component);
// enzyme
shallow(<Component />);
// react-testing-library
render(<Component />);
// @vue/test-utils
expect(wrapper.text()).toContain('Hello');
// enzyme
expect(wrapper.text()).toContain('Hello');
// react-testing-library
expect(screen.getByText('Hello')).toBeInTheDocument();
// @vue/test-utils
await wrapper.vm.$nextTick();
// enzyme
await wrapper.update();
// react-testing-library
await waitFor(() => screen.getByText('Loaded'));
| Feature | @vue/test-utils | enzyme | react-testing-library |
|---|---|---|---|
| Framework | 🟢 Vue.js | 🔴 React | 🔴 React |
| Query Style | 🔍 CSS Selectors | 🔍 CSS Selectors | ♿ Roles & Text |
| Event Handling | ⚡ trigger | ⚡ simulate | 🖱️ fireEvent |
| Maintenance | ✅ Active | ⚠️ Legacy / Maintenance | ✅ Active (renamed) |
| Philosophy | 🛠️ Implementation Access | 🛠️ Implementation Access | 🧑 User Behavior |
@vue/test-utils is the standard tool 🧰 for Vue developers. It gives you deep access to the component instance, which is useful for testing Vue-specific logic. Use it for any Vue 2 or Vue 3 project.
enzyme is a legacy tool 🕰️ for React. It was popular for shallow rendering but now holds back adoption of modern React features. Avoid it for new work — migrate to React Testing Library instead.
react-testing-library is the modern standard 📚 for React. It pushes you to write tests that verify user experience rather than internal state. Note that the package is now @testing-library/react, but the philosophy remains the same.
Final Thought: Your framework choice dictates your testing library. For Vue, use @vue/test-utils. For React, use @testing-library/react and leave enzyme in the past.
Choose @vue/test-utils if you are building applications with Vue.js 2 or Vue 3. It is the officially maintained library by the Vue team and provides the best integration with Vue's reactivity system and lifecycle methods. It is the only viable option among these three for Vue projects.
Do not choose enzyme for new React projects. It is in maintenance mode and does not fully support React 18+ concurrent features. Only consider it if you are maintaining a legacy React 16/17 codebase that already relies heavily on its shallow rendering API.
Choose react-testing-library (or its successor @testing-library/react) for new React projects. It encourages best practices by focusing on user behavior rather than implementation details. It is the industry standard for React testing and receives active updates to support modern React features.
Component testing utils for Vue 3.
🇫🇷 French version of this README.md
yarn add @vue/test-utils --devnpm install @vue/test-utils --save-devGet started with the documentation.
Check the migration guide. It's still a work in progress. If you find a problem or something that doesn't work that previously did in Vue Test Utils v1, please open an issue.
See the docs.
Get started by running pnpm install. You can run the tests with pnpm test. That's it!
Releases are published to npm from GitHub Actions using npm trusted publishing. Publishing with npm tokens is disabled, so a release requires:
vuejs/test-utils repositorymainpackage.json to contain the version being releasednpm-publish GitHub environmentTo cut a release, push a version tag from main:
git checkout main
git pull
git tag v2.x.y
git push origin v2.x.y
Pushing a v* tag starts the release workflow.
The workflow builds the package, pauses for approval in the npm-publish environment,
then publishes @vue/test-utils to npm after approval.
The person who pushed the tag cannot self-approve the publish step.
All the documentation files can be found in docs. It contains the English markdown files while translation(s) are stored in their corresponding <lang> sub-folder(s):
fr: French translation.Besides that, the .vitepress sub-folder contains the config and theme, including the i18n information.
pnpm docs:dev: Start the docs dev server.pnpm docs:build: Build the docs.To add or maintain the translations, we follow the Vue Ecosystem Translation Guidelines.
pnpm docs:translation:status [<lang>]: Show the translation status for your language. If you don't specify a language, it will show the status for all languages.pnpm docs:translation:compare <lang>: Compare the docs with the latest checkpoint for your language.pnpm docs:translation:update <lang> [<commit>]: Update the checkpoint for your language. The checkpoint will be set by the latest commit hash. However, you can also specify a commit hash manually.