בדיקת רכיבי Vue עם Vue Test Utils
עדכנת את רכיב העגלה, אבל בייצור יש שגיאה: מספר הפריטים לא מתעדכן. ללא בדיקות יחידה, אתה לומד על באגים מהמשתמשים, ומציאת הגורם לבעיה לוקחת שעות. Vue Test Utils — הספרייה הרשמית לבדיקת רכיבי Vue 3 — פותרת זאת: הרכבה מבודדת, סימולציית אירועים, בדיקות ריאקטיביות ללא הרצת האפליקציה המלאה. אנחנו, הצוות שלנו, מקימים את מחזור הבדיקות המלא turnkey: מבחירת מחסנית ועד צינור CI. אנו מבטיחים כיסוי של תרחישים מרכזיים והכשרת צוות, בהסתמך על ניסיון של 5+ שנים עם אקוסיסטם Vue ולמעלה מ-50 פרויקטים מיושמים.
צור קשר כדי להעריך את הכיסוי הנוכחי שלך ולבחור אסטרטגיית בדיקות.
למה להפוך את בדיקות רכיבי Vue לאוטומטיות?
בדיקה ידנית של כל רכיב לפני שחרור היא איטית ולא אמינה. בדיקות יחידה הופכות את האימות לאוטומטי: רינדור, emits, מצב, מקרי קצה. לפי התיעוד הרשמי של Vue Test Utils, הספרייה נועדה לבדיקת רכיבים מבודדת. Vue Test Utils בשילוב עם Vitest רץ פי 5 מהר יותר מ-Cypress Component Test Runner לתרחישים פשוטים — אין צורך בדפדפן. בדיקות רצות מקומית וב-CI, ומספקות משוב מהיר למפתחים. בדיקות רגרסיה מואצות ב-80%, וזמן חיפוש הבאגים מצטמצם ב-30% — מאושר על ידי ניסיון הפרויקטים שלנו. בפרויקט אחד, קיצרנו את זמן ריצת הרגרסיה מ-3 שעות ל-30 דקות (שיפור פי 6).
איך להקים בדיקות Vue 3 עם Vue Test Utils?
הוראות התקנה שלב אחר שלב
-
התקן תלויות:
npm install -D @vue/test-utils vitest jsdom. - צור vitest.config.ts עם התצורה המוצעת:
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [vue()],
test: {
environment: 'jsdom',
globals: true,
},
});
- כתוב את הבדיקה הראשונה שלך. דוגמה לבדיקת רינדור ו-emit:
import { mount } from '@vue/test-utils';
import UserCard from './UserCard.vue';
describe('UserCard', () => {
it('renders user name', () => {
const wrapper = mount(UserCard, {
props: {
user: {
name: 'Иван Петров',
email: '[email protected]'
}
},
});
expect(wrapper.text()).toContain('Иван Петров');
});
it('emits delete event with user id', async () => {
const wrapper = mount(UserCard, {
props: {
user: {
id: 42,
name: 'Иван'
}
},
});
await wrapper.find('[data-testid="delete-btn"]').trigger('click');
expect(wrapper.emitted('delete')).toBeTruthy();
expect(wrapper.emitted('delete')![0]).toEqual([42]);
});
});
- הרץ בדיקות:
import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; export default defineConfig({ plugins: [vue()], test: { environment: 'jsdom', globals: true, }, });.
אילו תרחישים בדיקות יחידה מכסות?
בדיקת אינטראקציה עם חנות. אם רכיב תלוי ב-Pinia, אתחל את החנות לפני כל בדיקה:
import { setActivePinia, createPinia } from 'pinia';
import { useCartStore } from '@/stores/cart';
describe('CartButton', () => {
beforeEach(() => setActivePinia(createPinia()));
it('adds item to cart', async () => {
const wrapper = mount(CartButton, {
props: { productId: 1 },
global: {
plugins: [createPinia()],
},
});
const store = useCartStore();
await wrapper.find('button').trigger('click');
expect(store.items).toHaveLength(1);
});
});טעינת נתונים אסינכרונית. השתמש ב-import { mount } from '@vue/test-utils'; import UserCard from './UserCard.vue'; describe('UserCard', () => { it('renders user name', () => { const wrapper = mount(UserCard, { props: { user: { name: 'Иван Петров', email: '[email protected]' } }, }); expect(wrapper.text()).toContain('Иван Петров'); }); it('emits delete event with user id', async () => { const wrapper = mount(UserCard, { props: { user: { id: 42, name: 'Иван' } }, }); await wrapper.find('[data-testid="delete-btn"]').trigger('click'); expect(wrapper.emitted('delete')).toBeTruthy(); expect(wrapper.emitted('delete')![0]).toEqual([42]); }); }); ו-npx vitest כדי ליצור mock ל-API:
it('loads data after API call', async () => {
vi.mock('@/api', () => ({
fetchUser: vi.fn().mockResolvedValue({ name: 'Мария' }),
}));
const wrapper = mount(UserProfile, {
props: { userId: 1 },
});
expect(wrapper.find('[data-testid="loading"]').exists()).toBe(true);
await flushPromises();
expect(wrapper.text()).toContain('Мария');
});Slots ו-stubs. ודא רינדור של slots ובודד רכיבי ילדים באמצעות import { setActivePinia, createPinia } from 'pinia'; import { useCartStore } from '@/stores/cart'; describe('CartButton', () => { beforeEach(() => setActivePinia(createPinia())); it('adds item to cart', async () => { const wrapper = mount(CartButton, { props: { productId: 1 }, global: { plugins: [createPinia()] }, }); const store = useCartStore(); await wrapper.find('button').trigger('click'); expect(store.items).toHaveLength(1); }); }); :
it('renders default slot', () => {
const wrapper = mount(Card, {
slots: {
default: '<p data-testid="slotted">Содержимое</p>',
},
});
expect(wrapper.find('[data-testid="slotted"]').exists()).toBe(true);
});
it('uses shallowMount to stub children', () => {
const wrapper = shallowMount(ParentComponent);
// дочерние компоненты автоматически стабируются
});Composables נבדקים ללא הרכבה — פשוט קרא לפונקציה ובדוק את התוצאה. לדוגמה, hook לאימות טופס: העבר שדות, קרא ל-vi.mock(), ובדוק שגיאות.
איך להימנע מטעויות נפוצות בכתיבת בדיקות?
- אל תשכח לאפס את מצב Pinia ב-
flushPromises():it('loads data after API call', async () => { vi.mock('@/api', () => ({ fetchUser: vi.fn().mockResolvedValue({ name: 'Мария' }), })); const wrapper = mount(UserProfile, { props: { userId: 1 } }); expect(wrapper.find('[data-testid="loading"]').exists()).toBe(true); await flushPromises(); expect(wrapper.text()).toContain('Мария'); });. אחרת בדיקות ישפיעו זו על זו. - לפעולות אסינכרוניות, השתמש תמיד ב-
shallowMountאחרי יצירת mock, אחרת הבדיקה עלולה להסתיים לפני הביצוע. - השתמש במאפיינים מסוג
it('renders default slot', () => { const wrapper = mount(Card, { slots: { default: '<p data-testid="slotted">Содержимое</p>' }, }); expect(wrapper.find('[data-testid="slotted"]').exists()).toBe(true); }); it('uses shallowMount to stub children', () => { const wrapper = shallowMount(ParentComponent); // дочерние компоненты автоматически стабируются });לבחירת אלמנטים — הם יציבים יותר ממחלקות CSS או טקסט. - בבדיקת slots, זכור להעביר תוכן דרך
validate().
רשימת בדיקה להקמת סביבה
- @vue/test-utils, vitest, jsdom מותקנים
- תצורת vitest כוללת jsdom ו-globals
- נכתבה לפחות בדיקה אחת לאימות ההתקנה
- בדיקות רצות מקומית עם
beforeEach - בדיקות משולבות ב-CI (לדוגמה, GitHub Actions)
הקמת בדיקות Turnkey: מה כלול
- ניתוח הפרויקט הנוכחי ובחירת מחסנית (Vitest + Vue Test Utils או Jest).
- הקמת סביבה וירטואלית (jsdom) ותצורת vitest.
- כתיבת בדיקות ל-20–30 רכיבים מרכזיים: הרכבה, אירועים, מצב, פעולות אסינכרוניות.
- יצירת mocks ל-API ולחנויות.
- אינטגרציית CI (GitLab CI / GitHub Actions / Bitbucket Pipelines).
- תיעוד לכתיבת בדיקות חדשות ומדדי כיסוי.
- הכשרת צוות: סדנה של שעתיים בכתיבת בדיקות יחידה.
השוואת שיטות בדיקת רכיבי Vue
| שיטה | מהירות | בידוד | בדיקת UI | משאבים |
|---|---|---|---|---|
| יחידה (Vue Test Utils) | גבוהה | מלא | לוגית | נמוכים |
| רכיב (Cypress) | בינונית | חלקי | ויזואלית | גבוהים |
| E2E (Playwright) | נמוכה | אין | מלאה | גבוהים מאוד |
שלבי הקמת בדיקות Turnkey
| שלב | משך | תוצאה |
|---|---|---|
| ניתוח ובחירת מחסנית | יום אחד | תוכנית בדיקות |
| הקמת סביבה | יום אחד | vitest + jsdom עובדים |
| כתיבת בדיקות (20–30 רכיבים) | 2–4 ימים | ערכת בדיקות עם כיסוי |
| אינטגרציית CI | יום אחד | ריצה אוטומטית ב-push |
| תיעוד והכשרה | יום אחד | מדריך וסדנה |
ציר זמן
הקמת סביבה, כתיבת בדיקות ואינטגרציית CI לפרויקט Vue טיפוסי אורכים בין 4 ל-7 ימים. ההערכה המדויקת תלויה במורכבות הרכיבים ובכמות הקוד ה-legacy.
קבל ייעוץ לבדיקת פרויקט ה-Vue שלך — נעריך את הכיסוי הנוכחי, נעזור לבחור אסטרטגיה, ונקים צינור מהיר. 5+ שנות ניסיון ב-Vue, עשרות פרויקטים מורכבים. אנו מבטיחים איכות ושקיפות בתהליך. צור קשר כדי לדון בפרטים.







