پرش به محتوای اصلی

Vue.js

Vue.js یک فریم‌ورک قابل دسترس، کارآمد و چندمنظوره برای ساخت رابط‌های کاربری وب است. شما می‌توانید کامپوننت‌های Vue.js را مستقیماً در یک مرورگر واقعی با استفاده از WebdriverIO و browser runner آن تست کنید.

راه‌اندازی

برای راه‌اندازی WebdriverIO در پروژه Vue.js خود، دستورالعمل‌ها را در مستندات تست کامپوننت ما دنبال کنید. اطمینان حاصل کنید که vue را به عنوان پیش‌تنظیم در گزینه‌های runner خود انتخاب کرده‌اید، مثلاً:

// wdio.conf.js
export const config = {
// ...
runner: ['browser', {
preset: 'vue'
}],
// ...
}
اطلاعات

اگر شما از قبل از Vite به عنوان سرور توسعه استفاده می‌کنید، می‌توانید به سادگی پیکربندی خود را در vite.config.ts در پیکربندی WebdriverIO خود مجدداً استفاده کنید. برای اطلاعات بیشتر، به viteConfig در گزینه‌های runner مراجعه کنید.

پیش‌تنظیم Vue نیاز به نصب @vitejs/plugin-vue دارد. همچنین ما استفاده از Testing Library را برای رندر کردن کامپوننت در صفحه تست توصیه می‌کنیم. بنابراین شما باید وابستگی‌های اضافی زیر را نصب کنید:

npm install --save-dev @testing-library/vue @vitejs/plugin-vue

سپس می‌توانید تست‌ها را با اجرای دستور زیر شروع کنید:

npx wdio run ./wdio.conf.js

نوشتن تست‌ها

با فرض اینکه شما کامپوننت Vue.js زیر را دارید:

./components/Component.vue
<template>
<div>
<p>Times clicked: {{ count }}</p>
<button @click="increment">increment</button>
</div>
</template>

<script>
export default {
data: () => ({
count: 0,
}),

methods: {
increment() {
this.count++
},
},
}
</script>

در تست خود، کامپوننت را در DOM رندر کنید و بررسی‌های خود را روی آن انجام دهید. ما توصیه می‌کنیم از @vue/test-utils یا @testing-library/vue برای اتصال کامپوننت به صفحه تست استفاده کنید. برای تعامل با کامپوننت، از دستورات WebdriverIO استفاده کنید زیرا رفتار آنها به تعاملات واقعی کاربر نزدیک‌تر است، مثلاً:

vue.test.js
import { $, expect } from '@wdio/globals'
import { mount } from '@vue/test-utils'
import Component from './components/Component.vue'

describe('Vue Component Testing', () => {
it('increments value on click', async () => {
// The render method returns a collection of utilities to query your component.
const wrapper = mount(Component, { attachTo: document.body })
expect(wrapper.text()).toContain('Times clicked: 0')

const button = await $('aria/increment')

// Dispatch a native click event to our button element.
await button.click()
await button.click()

expect(wrapper.text()).toContain('Times clicked: 2')
await expect($('p=Times clicked: 2')).toExist() // same assertion with WebdriverIO
})
})

شما می‌توانید یک نمونه کامل از مجموعه تست کامپوننت WebdriverIO برای Vue.js را در مخزن نمونه ما پیدا کنید.

تست کامپوننت‌های ناهمگام در Vue3

اگر از Vue نسخه 3 استفاده می‌کنید و در حال تست کامپوننت‌های ناهمگام مانند زیر هستید:

<script setup>
const res = await fetch(...)
const posts = await res.json()
</script>

<template>
{{ posts }}
</template>

ما توصیه می‌کنیم از @vue/test-utils و یک wrapper suspense کوچک برای رندر کردن کامپوننت استفاده کنید. متأسفانه @testing-library/vue هنوز از این پشتیبانی نمی‌کند. یک فایل helper.ts با محتوای زیر ایجاد کنید:

import { mount, type VueWrapper as VueWrapperImport } from '@vue/test-utils'
import { Suspense } from 'vue'

export type VueWrapper = VueWrapperImport<any>
const scheduler = typeof setImmediate === 'function' ? setImmediate : setTimeout

export function flushPromises(): Promise<void> {
return new Promise((resolve) => {
scheduler(resolve, 0)
})
}

export function wrapInSuspense(
component: ReturnType<typeof defineComponent>,
{ props }: { props: object },
): ReturnType<typeof defineComponent> {
return defineComponent({
render() {
return h(
'div',
{ id: 'root' },
h(Suspense, null, {
default() {
return h(component, props)
},
fallback: h('div', 'fallback'),
}),
)
},
})
}

export function renderAsyncComponent(vueComponent: ReturnType<typeof defineComponent>, props: object): VueWrapper{
const component = wrapInSuspense(vueComponent, { props })
return mount(component, { attachTo: document.body })
}

سپس کامپوننت را به صورت زیر وارد و تست کنید:

import { $, expect } from '@wdio/globals'

import { renderAsyncComponent, flushPromises, type VueWrapper } from './helpers.js'
import AsyncComponent from '/components/SomeAsyncComponent.vue'

describe('Testing Async Components', () => {
let wrapper: VueWrapper

it('should display component correctly', async () => {
const props = {}
wrapper = renderAsyncComponent(AsyncComponent, { props })
await flushPromises()
await expect($('...')).toBePresent()
})

afterEach(() => {
wrapper.unmount()
})
})

تست کامپوننت‌های Vue در Nuxt

اگر از فریم‌ورک وب Nuxt استفاده می‌کنید، WebdriverIO به طور خودکار ویژگی auto-import را فعال می‌کند و تست کامپوننت‌های Vue و صفحات Nuxt را آسان می‌سازد. با این حال، هر ماژول Nuxt که ممکن است در پیکربندی خود تعریف کنید و به زمینه برنامه Nuxt نیاز داشته باشد، نمی‌تواند پشتیبانی شود.

دلایل این امر عبارتند از:

  • WebdriverIO نمی‌تواند یک برنامه Nuxt را فقط در محیط مرورگر راه‌اندازی کند
  • وابستگی بیش از حد تست‌های کامپوننت به محیط Nuxt پیچیدگی ایجاد می‌کند و ما توصیه می‌کنیم این تست‌ها را به عنوان تست‌های e2e اجرا کنید
اطلاعات

WebdriverIO همچنین سرویسی برای اجرای تست‌های e2e روی برنامه‌های Nuxt ارائه می‌دهد، برای اطلاعات بیشتر به webdriverio-community/wdio-nuxt-service مراجعه کنید.

شبیه‌سازی composables داخلی

در صورتی که کامپوننت شما از یک composable بومی Nuxt استفاده می‌کند، مثلاً useNuxtData، WebdriverIO به طور خودکار این توابع را شبیه‌سازی می‌کند و به شما امکان می‌دهد رفتار آنها را تغییر دهید یا آنها را بررسی کنید، مثلاً:

import { mocked } from '@wdio/browser-runner'

// e.g. your component uses calls `useNuxtData` the following way
// `const { data: posts } = useNuxtData('posts')`
// in your test you can assert against it
expect(useNuxtData).toBeCalledWith('posts')
// and change their behavior
mocked(useNuxtData).mockReturnValue({
data: [...]
})

مدیریت composables شخص ثالث

تمام ماژول‌های شخص ثالث که می‌توانند پروژه Nuxt شما را تقویت کنند، نمی‌توانند به طور خودکار شبیه‌سازی شوند. در این موارد، شما باید آنها را به صورت دستی شبیه‌سازی کنید. به عنوان مثال، با فرض اینکه برنامه شما از ماژول پلاگین Supabase استفاده می‌کند:

export default defineNuxtConfig({
modules: [
"@nuxtjs/supabase",
// ...
],
// ...
});

و شما در جایی در composables خود یک نمونه از Supabase ایجاد می‌کنید، مثلاً:

const superbase = useSupabaseClient()

تست به دلیل زیر با شکست مواجه می‌شود:

ReferenceError: useSupabaseClient is not defined

در اینجا، ما توصیه می‌کنیم یا کل ماژولی که از تابع useSupabaseClient استفاده می‌کند را شبیه‌سازی کنید یا یک متغیر جهانی ایجاد کنید که این تابع را شبیه‌سازی می‌کند، مثلاً:

import { fn } from '@wdio/browser-runner'
globalThis.useSupabaseClient = fn().mockReturnValue({})

Welcome! How can I help?

WebdriverIO AI Copilot