تست کامپوننتهای Vue مستقیم توی مرورگر
خلاصهٔ کاملتر
یه چالش آشنا برای خیلی از فرانتاندکاراست: چطور باید برای کدهای جاوااسکریپت فرانتاند تست نوشت، اون هم بدون Node یا Deno؟ نویسندهی این مقاله مدتهاست دنبال یه روش راحت برای این کار میگرده. قبلاً Playwright رو امتحان کرده بود، ولی کند و پیچیده بود و بازم به کد Node نیاز داشت. راهحلی که اینجا معرفی میشه سادهست: تستها رو مستقیم توی تب مرورگر اجرا کن!
ایدهی اصلی اینه که میشه کامپوننتهای Vue رو بدون هیچ build process یا toolchain سمت سرور، مستقیم توی یه صفحهی HTML لود کرد و رویشون تست نوشت. فریمورک تست انتخابشده QUnit هست که سبک، ساده و مستقل از Node کار میکنه. یه ویژگی مفید QUnit اینه که میشه تکتک تستها رو دوباره اجرا کرد که وقتی درخواستهای شبکه زیاده خیلی به کار میاد.
اولین قدم اینه که کامپوننتها رو توی یه آبجکت global قرار بدیم تا در محیط تست هم دسترسی بهشون وجود داشته باشه:
const components = { 'Feedback': FeedbackComponent, ... }
window._components = components;بعد یه تابع mountComponent میسازیم که کامپوننت مورد نظر رو توی یه div موقت و نامرئی خارج از صفحه رندر میکنه:
function mountComponent(template, data) {
const app = Vue.createApp({
template: template,
data: () => data,
})
for (const [c, v] of Object.entries(window._components)) {
app.component(c, v);
}
const div = document.getElementById('qunit-fixture')
.appendChild(document.createElement('div'));
return div;
}برای تستهای integration که به دادههای واقعی نیاز دارن، نویسنده یه endpoint روی dev server اضافه کرده که با یه POST ساده، دادههای تست رو توی دیتابیس reset میکنه. این کار باعث میشه هر تست از یه وضعیت مشخص و قابل پیشبینی شروع کنه.
یکی از مشکلات رایج توی این نوع تستها، درخواستهای شبکه و آپدیتهای async DOM هست. نویسنده یه تابع waitFor() نوشته که هر ۲۰ میلیثانیه یه بار چک میکنه آیا یه المان توی DOM ظاهر شده یا نه، و بعد از ۲ ثانیه timeout میده:
QUnit.test("click item", async function (assert) {
const {div} = mountComponent('<FeedbackList />', {});
const item = await waitFor(() => div.querySelector('.feedback-item'));
item.click();
// ادامهی تست...
})یه نکتهی جالب که نویسنده بهش رسیده اینه که وقتی پیدا کردن «چیز درست برای صبر کردن» سخته، احتمالاً مشکل از طراحی خود اپلیکیشنه. اگه یه المان توی DOM هست ولی هنوز آمادهی تعامل نیست، شاید اصلاً نباید نمایش داده بشه!
پر کردن فرمها هم یه ظرافت داره: فقط set کردن value کافی نیست، باید event مناسب هم dispatch بشه تا Vue متوجه تغییر بشه. برای textarea باید event از نوع input و برای checkbox از نوع change باشه:
textarea.value = 'banana banana banana';
textarea.dispatchEvent(new Event('input'));
checkbox.checked = true;
checkbox.dispatchEvent(new Event('change'));نویسنده همچنین اشاره میکنه که به جای استفاده از CSS class برای پیدا کردن المانها توی تست، بهتره از روشهایی مثل getByRole یا data-testid استفاده بشه که هم تستها رو قویتر میکنه و هم accessibility اپ رو بهتر.
نکات کلیدی:
- میشه کامپوننتهای Vue رو مستقیم توی مرورگر و بدون Node تست کرد
- QUnit یه فریمورک تست سبک و مستقله که برای این کار عالیه
- تابع mountComponent کامپوننت رو توی یه div موقت و نامرئی رندر میکنه
- برای مدیریت عملیات async باید از waitFor() به جای sleep() استفاده کرد
- پر کردن فرمها نیاز به dispatch کردن event داره تا Vue تغییرات رو بشناسه
- سختی در نوشتن تست اغلب نشونهای از مشکل در طراحی اپلیکیشنه




