فصل نهم: تست و بهینه‌سازی

در این فصل، به بررسی تست و بهینه‌سازی اپلیکیشن مرکز اجاره کشتی‌های کروز با استفاده از ابزارهای مدرن Nuxt 3 می‌پردازیم. تست‌ها برای اطمینان از عملکرد صحیح کد و بهینه‌سازی‌ها برای بهبود سرعت و تجربه کاربری حیاتی هستند. این فصل شامل پیاده‌سازی تست‌های واحد (Unit Tests) با استفاده از Vitest و @nuxt/test-utils، بهینه‌سازی عملکرد با تکنیک‌هایی مانند هیدراتاسیون تنبل (Lazy Hydration)، و تقویت سئو با استفاده از متادیتای پویا است. هر بخش به‌طور کامل توضیح داده شده و کدهای مربوطه شرح داده می‌شوند.


تست‌های واحد (Unit Tests)

تست‌های واحد برای بررسی صحت عملکرد بخش‌های مختلف کد، مانند storeها، کامپوننت‌ها و توابع، استفاده می‌شوند. در این پروژه، از Vitest (یک فریم‌ورک تست سریع و مدرن) به همراه ماژول @nuxt/test-utils برای تست اپلیکیشن Nuxt استفاده می‌کنیم.

نصب وابستگی‌ها:

npm install -D vitest @nuxt/test-utils

توضیحات:

  • دستور npm install -D vitest @nuxt/test-utils: این دستور دو پکیج را نصب می‌کند:

  • vitest: یک فریم‌ورک تست که با Vite (موتور ساخت Nuxt 3) ادغام شده و تست‌های سریع و قابل اعتمادی ارائه می‌دهد.

  • @nuxt/test-utils: ابزارهای کمکی برای تست اپلیکیشن‌های Nuxt، از جمله شبیه‌سازی محیط Nuxt و پشتیبانی از تست‌های سمت سرور و کلاینت.
  • گام‌های بعدی برای تنظیم:

  • فایل تنظیمات Vitest (مانند vitest.config.ts) را ایجاد کنید:

    // vitest.config.ts
    import { defineVitestConfig } from '@nuxt/test-utils/config';

    export default defineVitestConfig({
      test: {
        environment: 'nuxt',
      },
    });
  • اسکریپت تست را به package.json اضافه کنید:
    "scripts": {
      "test": "vitest"
    }

نمونه تست برای useShipsStore:

// tests/shipsStore.test.ts
import { describe, it, expect } from 'vitest';
import { setActivePinia, createPinia } from 'pinia';
import { useShipsStore } from '~/stores/ships';

describe('Ships Store', () => {
  setActivePinia(createPinia());
  const store = useShipsStore();

  it('filters ships by search', () => {
    store.ships = [{ id: 1, name: 'Ocean Explorer', pricePerDay: 10000 }];
    store.setSearch('Ocean');
    expect(store.filteredShips.length).toBe(1);
  });
});

توضیحات:

  1. وارد کردن وابستگی‌ها:

  2. describe, it, expect: توابع اصلی Vitest برای تعریف گروه تست‌ها، تست‌های جداگانه و بررسی انتظارات.

  3. setActivePinia, createPinia: توابعی از Pinia برای تنظیم محیط تست storeها.
  4. useShipsStore: store کشتی‌ها که می‌خواهیم تست کنیم.

  5. تنظیم محیط تست:

  6. setActivePinia(createPinia()): یک نمونه Pinia ایجاد کرده و آن را به‌عنوان محیط فعال تنظیم می‌کند.

  7. const store = useShipsStore(): نمونه‌ای از store کشتی‌ها برای تست ایجاد می‌شود.

  8. تست فیلتر جستجو:

  9. تست با نام "filters ships by search" بررسی می‌کند که آیا store می‌تواند کشتی‌ها را بر اساس جستجوی نام فیلتر کند.

  10. مراحل تست:
    • یک کشتی نمونه با نام "Ocean Explorer" به آرایه ships اضافه می‌شود.
    • متد setSearch('Ocean') فراخوانی می‌شود تا فیلتر جستجو اعمال شود.
    • با استفاده از expect(store.filteredShips.length).toBe(1) بررسی می‌شود که آرایه filteredShips دقیقاً یک کشتی را برگرداند.
  11. نتیجه: اگر تست موفق باشد، نشان می‌دهد که قابلیت فیلتر جستجو در store به‌درستی کار می‌کند.

  12. کاربرد:

  13. این تست اطمینان می‌دهد که منطق فیلتر کردن کشتی‌ها در store به‌درستی عمل می‌کند.

  14. می‌توان تست‌های بیشتری برای بررسی سایر getters (مانند getShipById) یا actions (مانند fetchShips) اضافه کرد.

  15. مزایا:

  16. اطمینان از صحت کد: تست‌های واحد خطاها را زودتر شناسایی می‌کنند.

  17. توسعه پایدار: با افزودن قابلیت‌های جدید، تست‌ها تضمین می‌کنند که تغییرات کد قبلی را خراب نمی‌کنند.
  18. ادغام با Nuxt: @nuxt/test-utils تست‌های سمت سرور و کلاینت را ساده می‌کند.

  19. گسترش تست‌ها:

  20. می‌توان تست‌هایی برای کامپوننت‌ها (مانند ShipCard.vue) یا مسیرهای سرور (/api/ships) با استفاده از @nuxt/test-utils نوشت.

  21. برای مثال، تست کامپوننت:
     import { mount } from '@vue/test-utils';
     import ShipCard from '~/components/ShipCard.vue';

     it('renders ship name', () => {
       const wrapper = mount(ShipCard, {
         props: { ship: { id: 1, name: 'Ocean Explorer', capacity: 500, pricePerDay: 10000, amenities: [], image: '' } },
       });
       expect(wrapper.find('h2').text()).toBe('Ocean Explorer');
     });

بهینه‌سازی عملکرد

بهینه‌سازی عملکرد برای ارائه تجربه کاربری سریع و روان حیاتی است. در این پروژه، از تکنیک هیدراتاسیون تنبل (Lazy Hydration) برای بهبود سرعت بارگذاری صفحات استفاده می‌کنیم.

توضیحات:

  • هیدراتاسیون تنبل (Lazy Hydration):

  • هیدراتاسیون فرآیند تبدیل HTML رندرشده سمت سرور به یک اپلیکیشن تعاملی Vue در سمت کلاینت است.

  • برای کامپوننت‌های سنگین (مانند گریدهای بزرگ یا کامپوننت‌هایی با منطق پیچیده)، می‌توان هیدراتاسیون را به تأخیر انداخت تا فقط زمانی انجام شود که کامپوننت در viewport کاربر قرار گیرد.
  • روش‌های پیاده‌سازی:
    • استفاده از تگ <ClientOnly>: این تگ اطمینان می‌دهد که کامپوننت فقط در سمت کلاینت رندر می‌شود.
      <ClientOnly>
        <HeavyComponent />
      </ClientOnly>
- استفاده از `v-if`: می‌توان از یک شرط برای بارگذاری تنبل کامپوننت استفاده کرد:
      <HeavyComponent v-if="isVisible" />
      <script setup>
      const isVisible = ref(false);
      onMounted(() => {
        isVisible.value = true; // یا منطق مبتنی بر IntersectionObserver
      });
      </script>
  • کاربرد در پروژه:

    • در صفحه لیست کشتی‌ها (pages/ships/index.vue)، می‌توان کامپوننت ShipCard را با <ClientOnly> یا v-if لود کرد تا هیدراتاسیون فقط برای کارت‌های قابل مشاهده انجام شود.
    • این کار باعث کاهش بار اولیه JavaScript و بهبود زمان بارگذاری صفحه می‌شود.
  • مزایا:

  • کاهش زمان بارگذاری: با به تأخیر انداختن هیدراتاسیون کامپوننت‌های غیرضروری، منابع کمتری در بارگذاری اولیه مصرف می‌شود.

  • تجربه کاربری بهتر: صفحات سریع‌تر رندر می‌شوند، به‌ویژه در دستگاه‌های با منابع محدود.
  • انعطاف‌پذیری: می‌توان هیدراتاسیون تنبل را به‌صورت انتخابی برای کامپوننت‌های خاص اعمال کرد.

  • یادداشت برای پروژه:

  • در این اپلیکیشن، ShipCard در گرید لیست کشتی‌ها می‌تواند با <ClientOnly> یا یک IntersectionObserver لود شود تا فقط کارت‌های داخل viewport هیدراته شوند.

  • برای مثال:
    <ClientOnly>
      <ShipCard v-for="ship in filteredShips" :key="ship.id" :ship="ship" />
    </ClientOnly>

بهینه‌سازی سئو (SEO)

بهینه‌سازی برای موتورهای جستجو (SEO) در اپلیکیشن‌های وب مدرن حیاتی است. Nuxt 3 ابزارهای قدرتمندی مانند useSeoMeta و useHead برای مدیریت متادیتای پویا ارائه می‌دهد، که در صفحات این پروژه (مانند صفحه اصلی، لیست کشتی‌ها، و جزئیات کشتی) پیاده‌سازی شده‌اند.

توضیحات:

  • استفاده از useSeoMeta و useHead:

  • این توابع در صفحات پروژه برای تنظیم عنوان (title)، توضیحات (description)، و متادیتای Open Graph استفاده شده‌اند. برای مثال:

    • در pages/index.vue:
      useSeoMeta({
        title: 'Cruise Ship Rental Center | Luxury Cruises 2025',
        description: 'Rent premium cruise ships for your next adventure. Explore our fleet and book today!',
        ogImage: '/og-image.jpg',
      });
- در `pages/ships/[id].vue`:
      useSeoMeta({
        title: () => ship.value ? `${ship.value.name} | Cruise Rental 2025` : 'Ship Details',
        description: () => ship.value ? `Book ${ship.value.name} for your next adventure!` : 'View cruise ship details.',
      });
  • کاربرد:
    • useSeoMeta: متادیتای استاندارد مانند title و description را تنظیم می‌کند که برای رتبه‌بندی در موتورهای جستجو مهم هستند.
    • useHead: امکان تنظیم متادیتای پیشرفته‌تر (مانند متا تگ‌های سفارشی یا اسکریپت‌ها) را فراهم می‌کند.
    • متادیتای پویا (مانند استفاده از نام کشتی در عنوان) باعث می‌شود هر صفحه محتوای منحصربه‌فردی برای سئو داشته باشد.
  • مزایا:

    • بهبود رتبه‌بندی: متادیتای دقیق و پویا شانس نمایش در نتایج جستجو را افزایش می‌دهد.
    • شبکه‌های اجتماعی: متادیتای Open Graph (مانند ogImage) باعث نمایش بهتر صفحات در پلتفرم‌هایی مانند فیسبوک یا توییتر می‌شود.
    • ادغام با SSR: متادیتا در سمت سرور رندر می‌شود، که برای خزنده‌های موتور جستجو ایده‌آل است.
  • یادداشت برای پروژه:

  • متادیتا در تمام صفحات اصلی پروژه (صفحه اصلی، لیست کشتی‌ها، جزئیات کشتی، و داشبورد رزروها) پیاده‌سازی شده است.

  • برای بهبود بیشتر، می‌توان متا تگ‌های اضافی مانند keywords یا ساختارهای Schema.org (مانند JSON-LD) اضافه کرد:
    useHead({
      script: [
        {
          type: 'application/ld+json',
          innerHTML: JSON.stringify({
            '@context': 'https://schema.org',
            '@type': 'Product',
            name: ship.value?.name,
            description: ship.value?.description,
          }),
        },
      ],
    });

جمع‌بندی فصل نهم

در این فصل، به جنبه‌های کلیدی تست و بهینه‌سازی اپلیکیشن مرکز اجاره کشتی‌های کروز پرداختیم:

  • تست‌های واحد: با استفاده از Vitest و @nuxt/test-utils، یک تست نمونه برای store کشتی‌ها پیاده‌سازی کردیم که قابلیت فیلتر جستجو را بررسی می‌کند.
  • بهینه‌سازی عملکرد: با استفاده از هیدراتاسیون تنبل (<ClientOnly> یا v-if)، بار اولیه JavaScript را کاهش دادیم.
  • بهینه‌سازی سئو: با استفاده از useSeoMeta و useHead، متادیتای پویا را برای بهبود رتبه‌بندی در موتورهای جستجو پیاده‌سازی کردیم.

این تکنیک‌ها اپلیکیشن را پایدارتر، سریع‌تر و قابل کشف‌تر می‌کنند. در فصل‌های بعدی، به استقرار و گسترش اپلیکیشن خواهیم پرداخت.