آموزش کامل تست End-to-End با Playwright و هوش مصنوعی؛ از تولید تست تا تحلیل خطا با API درواره

در این راهنمای عملی، تست End-to-End با Playwright را از صفر پیاده‌سازی می‌کنیم و با اتصال API درواره، تولید سناریو، ساخت تست و تحلیل هوشمند خطاهای CI را خودکار می‌کنیم.

Share
آموزش کامل تست End-to-End با Playwright و هوش مصنوعی؛ از تولید تست تا تحلیل خطا با API درواره

یک برنامه ممکن است صدها Unit Test موفق داشته باشد، APIهای آن جداگانه درست کار کنند و تمام کامپوننت‌های رابط کاربری نیز بدون خطا رندر شوند؛ اما کاربر هنگام ورود، ثبت سفارش یا پرداخت با خطا مواجه شود.

دلیل آن ساده است: تست‌های واحد معمولاً اجزای نرم‌افزار را جدا از یکدیگر بررسی می‌کنند، درحالی‌که کاربر با کل سیستم تعامل دارد.

تست End-to-End یا E2E دقیقاً همین تجربه کامل را آزمایش می‌کند. در این نوع تست، یک مرورگر واقعی باز می‌شود و همان مراحلی را انجام می‌دهد که کاربر انجام می‌دهد:

  • وارد سایت می‌شود.
  • فرم ورود را تکمیل می‌کند.
  • محصولی را جست‌وجو می‌کند.
  • آن را به سبد خرید اضافه می‌کند.
  • سفارش را ثبت می‌کند.
  • نتیجه نهایی را بررسی می‌کند.

Playwright یکی از مهم‌ترین ابزارهای امروزی برای اجرای این تست‌ها است. ترکیب Playwright با هوش مصنوعی می‌تواند تولید سناریو، نوشتن نسخه اولیه تست، نگهداری تست‌ها و تحلیل خطاهای CI را سریع‌تر کند.

اما یک اصل مهم باید از ابتدا رعایت شود:

هوش مصنوعی می‌تواند تست را پیشنهاد دهد و خطا را تحلیل کند، اما نتیجه موفق یا ناموفق بودن تست باید توسط Assertionهای قطعی Playwright تعیین شود.

در این مقاله، یک پروژه عملی با Playwright، TypeScript و API هوش مصنوعی درواره می‌سازیم که قابلیت‌های زیر را دارد:

  • اجرای تست E2E در مرورگر واقعی
  • تست ورود و مسیر خرید
  • استفاده از Locatorهای پایدار
  • مدیریت وضعیت احراز هویت
  • Mock کردن سرویس‌های خارجی
  • تولید تست از روی مشخصات محصول با AI
  • تحلیل هوشمند خطاهای Playwright
  • ذخیره Screenshot، Video و Trace
  • اجرای تست در GitHub Actions
  • جلوگیری از تست‌های Flaky
  • کنترل هزینه استفاده از مدل‌های هوش مصنوعی

Playwright چیست؟

Playwright یک فریم‌ورک تست End-to-End برای برنامه‌های وب مدرن است. این ابزار امکان کنترل مرورگرهای مختلف را از طریق یک API یکپارچه فراهم می‌کند.

Playwright از موتورهای مرورگر زیر پشتیبانی می‌کند:

  • Chromium برای مرورگرهایی مانند Chrome و Edge
  • Firefox
  • WebKit برای شبیه‌سازی رفتار Safari

Playwright Test علاوه بر کنترل مرورگر، قابلیت‌های مهم دیگری نیز دارد:

  • Test Runner داخلی
  • اجرای موازی تست‌ها
  • Assertionهای مخصوص وب
  • Auto-waiting
  • Retry
  • Screenshot و Video
  • Trace Viewer
  • اجرای Headless و Headed
  • شبیه‌سازی موبایل
  • تست API
  • Mock کردن درخواست‌های شبکه
  • مدیریت وضعیت ورود کاربران
  • اجرای تست در CI/CD

براساس مستندات رسمی Playwright، این ابزار روی Windows، macOS و Linux اجرا می‌شود و می‌تواند تست‌ها را به‌صورت محلی یا در محیط CI اجرا کند.

تست End-to-End چیست؟

تست End-to-End یک مسیر واقعی کاربر را از ابتدا تا انتها بررسی می‌کند.

برای مثال، در یک فروشگاه اینترنتی ممکن است مسیر زیر آزمایش شود:

  1. کاربر صفحه ورود را باز می‌کند.
  2. شماره موبایل یا ایمیل خود را وارد می‌کند.
  3. وارد حساب کاربری می‌شود.
  4. یک محصول را انتخاب می‌کند.
  5. محصول را به سبد خرید اضافه می‌کند.
  6. آدرس ارسال را تعیین می‌کند.
  7. سفارش را نهایی می‌کند.
  8. صفحه تأیید سفارش نمایش داده می‌شود.

در این مسیر، چند بخش مختلف هم‌زمان درگیر هستند:

  • رابط کاربری
  • API
  • احراز هویت
  • پایگاه داده
  • مدیریت Session
  • منطق سبد خرید
  • وضعیت سفارش

به همین دلیل، تست E2E می‌تواند خطاهایی را پیدا کند که در Unit Test یا Integration Test دیده نمی‌شوند.

تفاوت Unit Test، Integration Test و E2E Test

Unit Test

یک تابع، کلاس یا کامپوننت کوچک را به‌صورت مستقل آزمایش می‌کند.

نمونه:

expect(calculateTotal([100, 200])).toBe(300);

این تست سریع و ارزان است، اما نمی‌گوید آیا کاربر واقعاً می‌تواند خرید خود را کامل کند یا نه.

Integration Test

ارتباط میان چند بخش را بررسی می‌کند؛ برای مثال ارتباط یک API با پایگاه داده.

End-to-End Test

کل جریان نرم‌افزار را از دید کاربر آزمایش می‌کند. این تست از دو مورد قبلی کندتر است، اما اطمینان بیشتری درباره عملکرد مسیرهای حیاتی ایجاد می‌کند.

یک راهبرد منطقی این است:

  • تعداد زیادی Unit Test
  • تعدادی Integration Test
  • تعداد محدود اما بسیار مهم E2E Test

قرار نیست تمام جزئیات برنامه با Playwright آزمایش شوند. بهتر است مسیرهای حیاتی کسب‌وکار را به تست E2E تبدیل کنید.

هوش مصنوعی در تست Playwright چه کاربردی دارد؟

هوش مصنوعی می‌تواند در چند مرحله به تیم توسعه کمک کند.

استخراج سناریو از User Story

فرض کنید مدیر محصول چنین نیازی نوشته است:

کاربر واردشده باید بتواند یک محصول موجود را به سبد خرید اضافه کند و تعداد آن را تغییر دهد.

مدل هوش مصنوعی می‌تواند این متن را به سناریوهای دقیق‌تر تبدیل کند:

  • افزودن یک محصول به سبد
  • افزایش تعداد محصول
  • کاهش تعداد محصول
  • حذف محصول
  • بررسی محاسبه مبلغ
  • جلوگیری از انتخاب تعداد بیشتر از موجودی
  • حفظ سبد بعد از Refresh
  • نمایش سبد در موبایل

تولید نسخه اولیه تست

مدل می‌تواند براساس قرارداد رابط کاربری، Routeها و Locatorهای مجاز، یک فایل Playwright تولید کند.

شناسایی حالت‌های مرزی

توسعه‌دهنده معمولاً Happy Path را به‌خوبی می‌شناسد، اما هوش مصنوعی می‌تواند Edge Caseهایی مانند این موارد را پیشنهاد دهد:

  • پاسخ دیرهنگام API
  • خالی بودن داده
  • قطع شدن درخواست
  • انقضای Session
  • دوبار کلیک روی دکمه
  • Refresh در میانه فرایند
  • نمایش خطای اعتبارسنجی
  • تفاوت نقش‌های کاربری

تحلیل خطاهای CI

خروجی تست Playwright ممکن است شامل Stack Trace، خطای Locator، درخواست‌های ناموفق و Timeout باشد. مدل می‌تواند این داده‌ها را خلاصه و علت‌های محتمل را اولویت‌بندی کند.

کمک به نگهداری تست‌ها

وقتی رابط کاربری تغییر می‌کند، AI می‌تواند تست قدیمی و قرارداد جدید UI را مقایسه و اصلاحات احتمالی را پیشنهاد کند.

معماری درست Playwright و هوش مصنوعی

معماری پیشنهادی شامل سه لایه است.

لایه اول: قرارداد محصول

در این لایه اطلاعات قطعی برنامه نگهداری می‌شود:

  • مسیر صفحات
  • نقش کاربران
  • نام فیلدها
  • رفتار مورد انتظار
  • Locatorهای مجاز
  • داده‌های تست
  • پیش‌شرط‌ها
  • نتیجه مورد انتظار

لایه دوم: هوش مصنوعی

مدل هوش مصنوعی وظایف احتمالی و تفسیری را انجام می‌دهد:

  • پیشنهاد سناریو
  • تولید پیش‌نویس تست
  • تحلیل گزارش خطا
  • پیشنهاد علت ریشه‌ای
  • پیشنهاد تست Regression

لایه سوم: Playwright

Playwright مسئول اجرای قطعی است:

  • باز کردن مرورگر
  • انجام عملیات
  • انتظار برای وضعیت مناسب
  • اجرای Assertion
  • تعیین Passed یا Failed
  • ثبت Screenshot و Trace

مدل نباید تصمیم بگیرد که یک تست موفق بوده است. برای مثال، این رویکرد اشتباه است:

تصویر صفحه را به مدل بده و از آن بپرس آیا خرید موفق بوده است؟

رویکرد درست این است:

await expect(
  page.getByRole('heading', { name: 'سفارش شما ثبت شد' })
).toBeVisible();

هوش مصنوعی می‌تواند این Assertion را پیشنهاد دهد، اما اجرای آن بر عهده Playwright است.

پیش‌نیازهای پروژه

برای اجرای آموزش به موارد زیر نیاز دارید:

  • Node.js با نسخه فعال LTS
  • npm یا pnpm
  • یک پروژه وب قابل اجرا
  • حساب درواره
  • کلید API درواره
  • یک مدل متنی مناسب برنامه‌نویسی
  • آشنایی مقدماتی با TypeScript

برای دریافت کلید API وارد درواره شوید و پس از ساخت حساب، از بخش کلیدهای API یک کلید جدید ایجاد کنید.

کلید API را فقط در Backend، اسکریپت‌های محلی یا Secretهای CI نگهداری کنید. این کلید نباید در کد Frontend، فایل عمومی یا Repository قرار بگیرد.

نصب Playwright

در ریشه پروژه دستور زیر را اجرا کنید:

npm init playwright@latest

هنگام نصب، گزینه‌های زیر نمایش داده می‌شوند:

  • TypeScript یا JavaScript
  • مسیر پوشه تست‌ها
  • ساخت Workflow مربوط به GitHub Actions
  • نصب مرورگرها

برای این آموزش TypeScript را انتخاب می‌کنیم.

اگر Playwright از قبل در پروژه نصب شده است، برای نصب یا به‌روزرسانی آن می‌توانید از دستورهای زیر استفاده کنید:

npm install -D @playwright/test@latest
npx playwright install --with-deps

بررسی نسخه نصب‌شده:

npx playwright --version

اجرای اولین تست:

npx playwright test

اجرای تست در مرورگر قابل مشاهده:

npx playwright test --headed

باز کردن محیط گرافیکی Playwright:

npx playwright test --ui

اجرای تست در حالت Debug:

npx playwright test --debug

مشاهده گزارش HTML:

npx playwright show-report

ساختار پیشنهادی پروژه

برای یک پروژه متوسط می‌توانیم از ساختار زیر استفاده کنیم:

project/
├── ai/
│   ├── analyze-failure.ts
│   ├── generate-test.ts
│   └── prompts/
│       ├── test-generator.md
│       └── failure-analyzer.md
├── contracts/
│   └── application.md
├── pages/
│   ├── LoginPage.ts
│   ├── ProductsPage.ts
│   └── CheckoutPage.ts
├── playwright/
│   └── .auth/
├── test-results/
├── tests/
│   ├── auth.setup.ts
│   ├── login.spec.ts
│   └── checkout.spec.ts
├── .env
├── .gitignore
├── package.json
└── playwright.config.ts

این ساختار کد تست، Page Objectها، پرامپت‌ها و ابزارهای AI را از یکدیگر جدا می‌کند.

تنظیم فایل playwright.config.ts

فایل playwright.config.ts را به‌شکل زیر تنظیم کنید:

import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',

  fullyParallel: true,

  forbidOnly: Boolean(process.env.CI),

  retries: process.env.CI ? 2 : 0,

  workers: process.env.CI ? 1 : undefined,

  reporter: [
    ['html', { open: 'never' }],
    ['json', { outputFile: 'test-results/results.json' }],
  ],

  use: {
    baseURL: process.env.APP_BASE_URL || 'http://localhost:3000',

    trace: 'on-first-retry',

    screenshot: 'only-on-failure',

    video: 'retain-on-failure',
  },

  projects: [
    {
      name: 'chromium',
      use: {
        ...devices['Desktop Chrome'],
      },
    },
    {
      name: 'firefox',
      use: {
        ...devices['Desktop Firefox'],
      },
    },
    {
      name: 'webkit',
      use: {
        ...devices['Desktop Safari'],
      },
    },
    {
      name: 'mobile-chrome',
      use: {
        ...devices['Pixel 7'],
      },
    },
  ],

  webServer: {
    command: 'npm run dev',
    url: 'http://localhost:3000',
    reuseExistingServer: !process.env.CI,
  },
});

چند نکته مهم در این تنظیمات وجود دارد:

  • در محیط CI، تست شکست‌خورده دوباره اجرا می‌شود.
  • در اولین Retry، فایل Trace ساخته می‌شود.
  • Screenshot فقط هنگام شکست ذخیره می‌شود.
  • Video فقط برای تست ناموفق نگهداری می‌شود.
  • تست‌ها روی چند موتور مرورگر و یک نمای موبایل اجرا می‌شوند.
  • گزارش HTML و JSON تولید می‌شود.
  • در CI فقط یک Worker فعال است تا شروع کار پایدارتر باشد؛ بعداً می‌توانید آن را افزایش دهید.

نوشتن اولین تست Playwright

فرض کنیم برنامه یک صفحه ورود دارد.

فایل tests/login.spec.ts را بسازید:

import { test, expect } from '@playwright/test';

test.describe('ورود کاربر', () => {
  test('کاربر با اطلاعات معتبر وارد حساب می‌شود', async ({ page }) => {
    await page.goto('/login');

    await page.getByLabel('ایمیل').fill('test@example.com');
    await page.getByLabel('رمز عبور').fill('TestPassword123');

    await page.getByRole('button', { name: 'ورود' }).click();

    await expect(page).toHaveURL(/dashboard/);

    await expect(
      page.getByRole('heading', { name: 'داشبورد' })
    ).toBeVisible();
  });

  test('برای رمز عبور اشتباه پیام خطا نمایش داده می‌شود', async ({
    page,
  }) => {
    await page.goto('/login');

    await page.getByLabel('ایمیل').fill('test@example.com');
    await page.getByLabel('رمز عبور').fill('WrongPassword');

    await page.getByRole('button', { name: 'ورود' }).click();

    await expect(
      page.getByRole('alert')
    ).toContainText('اطلاعات ورود صحیح نیست');
  });
});

این مثال باید براساس متن‌ها و رفتار واقعی برنامه شما اصلاح شود.

انتخاب Locator مناسب

Locator مشخص می‌کند Playwright با کدام عنصر صفحه تعامل داشته باشد.

براساس راهنمای رسمی Locatorهای Playwright، بهتر است Locatorهایی را انتخاب کنید که به تجربه کاربر یا یک قرارداد مشخص تست نزدیک باشند.

ترتیب پیشنهادی معمولاً به این شکل است:

  1. getByRole
  2. getByLabel
  3. getByPlaceholder
  4. getByText
  5. getByTestId
  6. CSS Selector فقط در صورت ضرورت
  7. XPath فقط در شرایط بسیار خاص

نمونه مناسب:

await page.getByRole('button', { name: 'ثبت سفارش' }).click();

نمونه شکننده:

await page
  .locator('#app > div:nth-child(2) > div > button.primary')
  .click();

اگر کلاس CSS یا ساختار DOM تغییر کند، نمونه دوم از کار می‌افتد؛ حتی اگر دکمه همچنان برای کاربر قابل مشاهده و قابل استفاده باشد.

استفاده از data-testid

گاهی یک عنصر نام یا Role مناسبی ندارد. در این شرایط می‌توانید یک قرارداد صریح تست تعریف کنید:

<button data-testid="checkout-submit">
  ثبت سفارش
</button>

سپس در تست بنویسید:

await page.getByTestId('checkout-submit').click();

نام data-testid باید براساس مفهوم پایدار عنصر انتخاب شود، نه رنگ یا محل نمایش آن.

مناسب:

checkout-submit
cart-total
profile-menu

نامناسب:

blue-button
left-item
second-div

چرا نباید از waitForTimeout استفاده کنیم؟

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

await page.waitForTimeout(5000);

این کار دو مشکل ایجاد می‌کند:

  • اگر صفحه در یک ثانیه آماده شود، چهار ثانیه وقت تلف می‌شود.
  • اگر صفحه بیش از پنج ثانیه زمان نیاز داشته باشد، تست شکست می‌خورد.

Playwright برای بسیاری از عملیات از Auto-waiting استفاده می‌کند. برای مثال، قبل از کلیک بررسی می‌کند که عنصر قابل مشاهده، پایدار، فعال و قابل دریافت رویداد باشد. جزئیات این رفتار در مستندات Auto-waiting آمده است.

به‌جای انتظار ثابت، منتظر یک وضعیت واقعی بمانید:

await expect(
  page.getByRole('heading', { name: 'سفارش ثبت شد' })
).toBeVisible();

یا:

await page.waitForURL(/orders\/\d+/);

استفاده از Web-first Assertions

نمونه نامناسب:

const visible = await page.getByText('خوش آمدید').isVisible();
expect(visible).toBe(true);

این روش وضعیت را فقط در همان لحظه بررسی می‌کند.

نمونه بهتر:

await expect(
  page.getByText('خوش آمدید')
).toBeVisible();

Assertionهای Web-first تا زمان رسیدن به نتیجه یا پایان Timeout دوباره وضعیت را بررسی می‌کنند.

ساخت یک تست واقعی برای فرایند خرید

فایل tests/checkout.spec.ts:

import { test, expect } from '@playwright/test';

test.describe('فرایند خرید', () => {
  test('کاربر می‌تواند محصول موجود را سفارش دهد', async ({ page }) => {
    await page.goto('/products');

    const product = page
      .getByRole('listitem')
      .filter({ hasText: 'هدفون بی‌سیم' });

    await product
      .getByRole('button', { name: 'افزودن به سبد' })
      .click();

    await expect(
      page.getByTestId('cart-count')
    ).toHaveText('1');

    await page.getByRole('link', { name: 'سبد خرید' }).click();

    await expect(
      page.getByRole('heading', { name: 'سبد خرید' })
    ).toBeVisible();

    await expect(
      page.getByTestId('cart-item')
    ).toContainText('هدفون بی‌سیم');

    await page
      .getByRole('button', { name: 'ادامه فرایند خرید' })
      .click();

    await page.getByLabel('نام تحویل‌گیرنده').fill('کاربر تست');
    await page.getByLabel('کد پستی').fill('1234567890');
    await page.getByLabel('آدرس').fill('آدرس مخصوص محیط تست');

    await page
      .getByRole('button', { name: 'ثبت سفارش' })
      .click();

    await expect(page).toHaveURL(/orders\/confirmation/);

    await expect(
      page.getByRole('heading', { name: 'سفارش شما ثبت شد' })
    ).toBeVisible();

    await expect(
      page.getByTestId('order-number')
    ).not.toBeEmpty();
  });
});

این تست یک نتیجه کسب‌وکاری را بررسی می‌کند، نه صرفاً کلیک شدن چند دکمه را.

استفاده از Page Object Model

با بزرگ شدن پروژه، تکرار Locatorها نگهداری تست‌ها را دشوار می‌کند. Page Object Model یا POM عملیات هر صفحه را در یک کلاس جداگانه قرار می‌دهد.

فایل pages/LoginPage.ts:

import { expect, type Locator, type Page } from '@playwright/test';

export class LoginPage {
  readonly page: Page;
  readonly emailInput: Locator;
  readonly passwordInput: Locator;
  readonly submitButton: Locator;
  readonly errorAlert: Locator;

  constructor(page: Page) {
    this.page = page;

    this.emailInput = page.getByLabel('ایمیل');
    this.passwordInput = page.getByLabel('رمز عبور');
    this.submitButton = page.getByRole('button', {
      name: 'ورود',
    });
    this.errorAlert = page.getByRole('alert');
  }

  async open() {
    await this.page.goto('/login');
  }

  async login(email: string, password: string) {
    await this.emailInput.fill(email);
    await this.passwordInput.fill(password);
    await this.submitButton.click();
  }

  async expectInvalidCredentials() {
    await expect(this.errorAlert).toContainText(
      'اطلاعات ورود صحیح نیست'
    );
  }
}

تست نهایی ساده‌تر می‌شود:

import { test, expect } from '@playwright/test';
import { LoginPage } from '../pages/LoginPage';

test('ورود موفق کاربر', async ({ page }) => {
  const loginPage = new LoginPage(page);

  await loginPage.open();

  await loginPage.login(
    'test@example.com',
    'TestPassword123'
  );

  await expect(page).toHaveURL(/dashboard/);
});

POM در پروژه‌های بزرگ مفید است، اما نباید تمام Assertionها و منطق تست را در کلاس‌ها پنهان کنید. تست باید همچنان خوانا باشد و هدف کسب‌وکاری آن مشخص بماند.

ذخیره وضعیت ورود کاربر

ورود از طریق رابط کاربری در ابتدای تمام تست‌ها باعث کند شدن مجموعه تست می‌شود. Playwright می‌تواند وضعیت مرورگر را ذخیره و در تست‌های بعدی استفاده کند.

ابتدا مسیر زیر را به .gitignore اضافه کنید:

playwright/.auth
.env
test-results
playwright-report

فایل وضعیت ورود ممکن است Cookie، Header یا Token حساس داشته باشد؛ بنابراین نباید در Git ثبت شود. مستندات احراز هویت Playwright نیز نگهداری فایل‌های Auth خارج از Repository را توصیه می‌کند.

فایل tests/auth.setup.ts:

import { test as setup, expect } from '@playwright/test';

const authFile = 'playwright/.auth/user.json';

setup('authenticate', async ({ page }) => {
  await page.goto('/login');

  await page
    .getByLabel('ایمیل')
    .fill(process.env.E2E_USER_EMAIL!);

  await page
    .getByLabel('رمز عبور')
    .fill(process.env.E2E_USER_PASSWORD!);

  await page
    .getByRole('button', { name: 'ورود' })
    .click();

  await expect(page).toHaveURL(/dashboard/);

  await page.context().storageState({
    path: authFile,
  });
});

سپس پروژه Setup و پروژه Chromium را در تنظیمات تعریف کنید:

projects: [
  {
    name: 'setup',
    testMatch: /.*\.setup\.ts/,
  },
  {
    name: 'chromium',
    use: {
      ...devices['Desktop Chrome'],
      storageState: 'playwright/.auth/user.json',
    },
    dependencies: ['setup'],
  },
],

اگر تست‌ها داده مشترک را تغییر می‌دهند، استفاده هم‌زمان از یک حساب می‌تواند باعث تداخل شود. در این شرایط برای هر Worker یک حساب تست مستقل در نظر بگیرید.

Mock کردن APIهای خارجی

تست End-to-End نباید بی‌دلیل به سرویس خارجی وابسته باشد. تغییر رفتار یا اختلال سرویس شخص ثالث می‌تواند تست شما را ناموفق کند، درحالی‌که برنامه خودتان مشکلی ندارد.

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

import { test, expect } from '@playwright/test';

test('هزینه ارسال در خلاصه سفارش نمایش داده می‌شود', async ({
  page,
}) => {
  await page.route('**/api/shipping/quote', async (route) => {
    await route.fulfill({
      status: 200,
      contentType: 'application/json',
      body: JSON.stringify({
        price: 85000,
        currency: 'IRR',
        estimatedDays: 2,
      }),
    });
  });

  await page.goto('/checkout');

  await expect(
    page.getByTestId('shipping-price')
  ).toContainText('۸۵٬۰۰۰');
});

همچنین می‌توانید وضعیت خطا را آزمایش کنید:

await page.route('**/api/shipping/quote', async (route) => {
  await route.fulfill({
    status: 503,
    contentType: 'application/json',
    body: JSON.stringify({
      message: 'Service unavailable',
    }),
  });
});

سپس بررسی کنید که برنامه پیام مناسبی نمایش می‌دهد:

await expect(
  page.getByRole('alert')
).toContainText('محاسبه هزینه ارسال موقتاً در دسترس نیست');

اتصال Playwright به API هوش مصنوعی درواره

اکنون قابلیت AI را به پروژه اضافه می‌کنیم.

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

npm install openai dotenv
npm install -D tsx

فایل .env:

DARVAREH_API_KEY=YOUR_DARVAREH_API_KEY
DARVAREH_MODEL_ID=MODEL_ID_DARVAREH
APP_BASE_URL=http://localhost:3000

برای مشاهده مدل‌های در دسترس و قیمت به‌روز آن‌ها، صفحه مدل‌های درواره را مشاهده کنید.

کلید .env را در Git ثبت نکنید.

ساخت قرارداد برنامه برای مدل هوش مصنوعی

مدل بدون شناخت برنامه شما ممکن است Route، متن دکمه یا data-testid غیرواقعی تولید کند. برای کاهش این خطا، یک فایل قرارداد بسازید.

فایل contracts/application.md:

# Application contract

## Product
Persian RTL e-commerce application

## Base URL
Read from APP_BASE_URL

## Routes
- /login
- /dashboard
- /products
- /cart
- /checkout
- /orders/confirmation

## Authentication
- Email field label: ایمیل
- Password field label: رمز عبور
- Submit button accessible name: ورود
- Successful login URL contains: /dashboard

## Products page
- Products are rendered as listitem
- Add button accessible name: افزودن به سبد
- Cart count test id: cart-count

## Checkout
- Receiver label: نام تحویل‌گیرنده
- Postal code label: کد پستی
- Address label: آدرس
- Submit accessible name: ثبت سفارش
- Confirmation heading: سفارش شما ثبت شد
- Order number test id: order-number

## Testing rules
- Use getByRole and getByLabel whenever possible
- Use getByTestId only for documented test ids
- Do not invent routes, labels, roles or test ids
- Do not use XPath
- Do not use long CSS selectors
- Do not use waitForTimeout
- Use web-first assertions
- Every test must be independent
- Do not include real credentials

هرچه این قرارداد دقیق‌تر باشد، تست تولیدشده قابل‌اعتمادتر خواهد بود.

تولید تست Playwright با API درواره

فایل ai/generate-test.ts را ایجاد کنید:

import 'dotenv/config';
import OpenAI from 'openai';
import { readFile, writeFile } from 'node:fs/promises';

const apiKey = process.env.DARVAREH_API_KEY;
const model = process.env.DARVAREH_MODEL_ID;

if (!apiKey) {
  throw new Error('DARVAREH_API_KEY is required');
}

if (!model) {
  throw new Error('DARVAREH_MODEL_ID is required');
}

const client = new OpenAI({
  apiKey,
  baseURL: 'https://api.darvareh.ir/v1',
});

function removeMarkdownFence(content: string): string {
  return content
    .replace(/^```(?:typescript|ts)?\s*/i, '')
    .replace(/\s*```$/, '')
    .trim();
}

async function main() {
  const contract = await readFile(
    'contracts/application.md',
    'utf8'
  );

  const userStory = `
کاربر واردشده باید بتواند یک محصول موجود را به سبد خرید
اضافه کند، وارد صفحه سبد شود و مبلغ و تعداد محصول را ببیند.
  `.trim();

  const response = await client.chat.completions.create({
    model,
    temperature: 0.1,
    messages: [
      {
        role: 'system',
        content: `
شما یک مهندس ارشد تست نرم‌افزار هستید.
یک فایل Playwright Test معتبر با TypeScript تولید کنید.

قوانین:
- فقط کد TypeScript برگردانید.
- هیچ توضیح یا Markdown برنگردانید.
- فقط از اطلاعات قرارداد استفاده کنید.
- Route، Locator یا data-testid جدید نسازید.
- از waitForTimeout استفاده نکنید.
- از XPath و CSS Selector طولانی استفاده نکنید.
- از Web-first Assertion استفاده کنید.
- تست باید مستقل و قابل تکرار باشد.
- اطلاعات ورود را از Environment Variable بخوانید.
- نتیجه تست را با Assertion قطعی مشخص کنید.
        `.trim(),
      },
      {
        role: 'user',
        content: `
قرارداد برنامه:

${contract}

User Story:

${userStory}

یک تست Happy Path و حداقل دو حالت مرزی تولید کن.
        `.trim(),
      },
    ],
  });

  const content = response.choices[0]?.message?.content;

  if (!content) {
    throw new Error('Model returned an empty response');
  }

  const code = removeMarkdownFence(content);

  if (
    code.includes('waitForTimeout') ||
    code.includes('xpath=') ||
    code.includes('page.$(')
  ) {
    throw new Error(
      'Generated test violates the project testing rules'
    );
  }

  await writeFile(
    'tests/generated-cart.spec.ts',
    code,
    'utf8'
  );

  console.log(
    'Generated tests/generated-cart.spec.ts'
  );
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});

اسکریپت را اجرا کنید:

npx tsx ai/generate-test.ts

سپس فایل تولیدشده را فرمت و بررسی کنید:

npx prettier --write tests/generated-cart.spec.ts
npx playwright test tests/generated-cart.spec.ts

آیا باید کد تولیدشده مستقیماً اجرا شود؟

در محیط توسعه می‌توانید فایل را تولید و سپس بازبینی کنید. اما بهتر است کد تولیدشده بدون کنترل وارد Branch اصلی نشود.

فرایند پیشنهادی:

  1. توسعه‌دهنده User Story را مشخص می‌کند.
  2. مدل پیش‌نویس تست را می‌سازد.
  3. Linter و TypeScript کد را بررسی می‌کنند.
  4. توسعه‌دهنده Locatorها و Assertionها را بازبینی می‌کند.
  5. تست در محیط محلی اجرا می‌شود.
  6. تغییرات از طریق Pull Request وارد Repository می‌شوند.
  7. CI تست را دوباره اجرا می‌کند.

مدل ممکن است کدی از نظر Syntax صحیح اما از نظر رفتار محصول اشتباه تولید کند. بنابراین بازبینی انسانی همچنان ضروری است.

پرامپت مناسب برای تولید تست Playwright

یک پرامپت خوب باید این اطلاعات را در اختیار مدل قرار دهد:

  • هدف کسب‌وکاری تست
  • پیش‌شرط‌ها
  • Routeهای معتبر
  • Locatorهای واقعی
  • داده‌های تست
  • نتیجه مورد انتظار
  • رفتار API
  • محدودیت‌های فنی
  • موارد ممنوع
  • قالب خروجی

نمونه:

برای User Story زیر یک تست Playwright با TypeScript بنویس.

هدف:
کاربر بتواند یک محصول موجود را به سبد خرید اضافه کند.

پیش‌شرط:
کاربر از قبل وارد شده است.

Locatorهای مجاز:
- product list: role=listitem
- add button: role=button, name=افزودن به سبد
- cart counter: testId=cart-count
- cart link: role=link, name=سبد خرید

نتیجه مورد انتظار:
- شمارنده سبد برابر 1 شود.
- نام محصول در صفحه سبد نمایش داده شود.

محدودیت‌ها:
- از waitForTimeout استفاده نکن.
- Locator جدید اختراع نکن.
- از CSS و XPath استفاده نکن.
- از Web-first Assertions استفاده کن.
- تست مستقل باشد.
- فقط کد TypeScript برگردان.

تحلیل خطای Playwright با هوش مصنوعی

Playwright گزارش JSON تولید می‌کند. می‌توانیم بخش‌های مرتبط گزارش را پس از حذف داده‌های حساس برای مدل ارسال کنیم.

فایل ai/analyze-failure.ts:

import 'dotenv/config';
import OpenAI from 'openai';
import { readFile, writeFile } from 'node:fs/promises';

const apiKey = process.env.DARVAREH_API_KEY;
const model = process.env.DARVAREH_MODEL_ID;

if (!apiKey || !model) {
  throw new Error(
    'DARVAREH_API_KEY and DARVAREH_MODEL_ID are required'
  );
}

const client = new OpenAI({
  apiKey,
  baseURL: 'https://api.darvareh.ir/v1',
});

function sanitize(value: string): string {
  return value
    .replace(
      /Bearer\s+[A-Za-z0-9._-]+/gi,
      'Bearer [REDACTED]'
    )
    .replace(
      /sk-[A-Za-z0-9_-]+/g,
      '[REDACTED_API_KEY]'
    )
    .replace(
      /[\w.+-]+@[\w.-]+\.[A-Za-z]{2,}/g,
      '[REDACTED_EMAIL]'
    )
    .replace(
      /"password"\s*:\s*"[^"]+"/gi,
      '"password":"[REDACTED]"'
    );
}

async function main() {
  const rawReport = await readFile(
    'test-results/results.json',
    'utf8'
  );

  const safeReport = sanitize(rawReport).slice(0, 50000);

  const response = await client.chat.completions.create({
    model,
    temperature: 0.1,
    messages: [
      {
        role: 'system',
        content: `
شما مهندس ارشد QA و متخصص Playwright هستید.
گزارش تست را تحلیل کنید.

پاسخ را به فارسی و با ساختار زیر ارائه دهید:
1. خلاصه خطا
2. محتمل‌ترین علت ریشه‌ای
3. شواهد موجود در گزارش
4. تشخیص نوع خطا
5. مراحل بازتولید
6. پیشنهاد اصلاح کد برنامه
7. پیشنهاد اصلاح تست
8. تست Regression پیشنهادی
9. میزان اطمینان از تحلیل از صفر تا صد

اگر شواهد کافی وجود ندارد، صریحاً اعلام کنید.
موفق یا ناموفق بودن تست را تغییر ندهید.
        `.trim(),
      },
      {
        role: 'user',
        content: safeReport,
      },
    ],
  });

  const analysis =
    response.choices[0]?.message?.content ||
    'No analysis generated';

  await writeFile(
    'test-results/ai-analysis.md',
    analysis,
    'utf8'
  );

  console.log(analysis);
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});

اجرای تحلیل:

npx tsx ai/analyze-failure.ts

این اسکریپت فقط گزارش متنی را تحلیل می‌کند. در پروژه پیشرفته‌تر می‌توانید اطلاعات انتخابی زیر را نیز اضافه کنید:

  • خطاهای Console
  • درخواست‌های HTTP ناموفق
  • URL صفحه هنگام شکست
  • نام پروژه مرورگر
  • مدت زمان تست
  • مرحله‌ای که شکست رخ داده است
  • Screenshot پالایش‌شده
  • تغییرات اخیر Pull Request

قبل از ارسال هر داده‌ای مطمئن شوید اطلاعات محرمانه، Cookie، Token، اطلاعات مشتری یا داده واقعی کاربران در آن وجود ندارد.

تحلیل Trace با Playwright Trace Viewer

Trace یکی از مفیدترین ابزارهای Playwright برای بررسی خطا است. Trace می‌تواند اطلاعات زیر را ثبت کند:

  • Timeline اجرای تست
  • عملیات انجام‌شده
  • DOM Snapshot
  • درخواست‌های شبکه
  • Console
  • Locator استفاده‌شده
  • وضعیت صفحه قبل و بعد از عملیات
  • Screenshotهای هر مرحله

برای تولید Trace:

npx playwright test --trace on

برای مشاهده گزارش:

npx playwright show-report

در محیط CI بهتر است Trace فقط هنگام Retry یا شکست ذخیره شود؛ زیرا ثبت Trace برای تمام تست‌ها می‌تواند زمان و فضای ذخیره‌سازی بیشتری مصرف کند. راهنمای رسمی Trace Viewer جزئیات مشاهده و بررسی Trace را توضیح می‌دهد.

ثبت خطاهای Console و Network

می‌توانیم یک Fixture بسازیم که خطاهای مرورگر و درخواست‌های ناموفق را ثبت کند.

فایل tests/fixtures.ts:

import { test as base } from '@playwright/test';

type Diagnostics = {
  browserErrors: string[];
  failedRequests: string[];
};

export const test = base.extend<Diagnostics>({
  browserErrors: async ({ page }, use) => {
    const errors: string[] = [];

    page.on('console', (message) => {
      if (message.type() === 'error') {
        errors.push(message.text());
      }
    });

    page.on('pageerror', (error) => {
      errors.push(error.message);
    });

    await use(errors);

    if (errors.length > 0) {
      await test.info().attach('browser-errors', {
        body: Buffer.from(
          JSON.stringify(errors, null, 2)
        ),
        contentType: 'application/json',
      });
    }
  },

  failedRequests: async ({ page }, use) => {
    const failures: string[] = [];

    page.on('response', (response) => {
      if (response.status() >= 400) {
        failures.push(
          `${response.status()} ${response.request().method()} ${response.url()}`
        );
      }
    });

    page.on('requestfailed', (request) => {
      failures.push(
        `${request.method()} ${request.url()} ${
          request.failure()?.errorText || 'unknown'
        }`
      );
    });

    await use(failures);

    if (failures.length > 0) {
      await test.info().attach('failed-requests', {
        body: Buffer.from(
          JSON.stringify(failures, null, 2)
        ),
        contentType: 'application/json',
      });
    }
  },
});

export { expect } from '@playwright/test';

در تست‌ها از Fixture جدید استفاده کنید:

import { test, expect } from './fixtures';

test('داشبورد بدون خطای بحرانی باز می‌شود', async ({
  page,
  browserErrors,
  failedRequests,
}) => {
  await page.goto('/dashboard');

  await expect(
    page.getByRole('heading', { name: 'داشبورد' })
  ).toBeVisible();

  expect(browserErrors).toEqual([]);
  expect(failedRequests).toEqual([]);
});

در بعضی برنامه‌ها تعدادی درخواست 404 یا خطای Console شناخته‌شده وجود دارد. بهتر است به‌جای نادیده گرفتن تمام خطاها، Allowlist محدود و مستند بسازید.

اجرای تست Playwright در GitHub Actions

فایل .github/workflows/playwright.yml:

name: Playwright Tests

on:
  push:
    branches:
      - main

  pull_request:
    branches:
      - main

jobs:
  e2e:
    runs-on: ubuntu-latest
    timeout-minutes: 30

    env:
      APP_BASE_URL: ${{ secrets.E2E_APP_BASE_URL }}
      E2E_USER_EMAIL: ${{ secrets.E2E_USER_EMAIL }}
      E2E_USER_PASSWORD: ${{ secrets.E2E_USER_PASSWORD }}

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Install Playwright browsers
        run: npx playwright install --with-deps

      - name: Run Playwright tests
        id: playwright
        continue-on-error: true
        run: npx playwright test

      - name: Analyze failed tests with AI
        if: steps.playwright.outcome == 'failure'
        env:
          DARVAREH_API_KEY: ${{ secrets.DARVAREH_API_KEY }}
          DARVAREH_MODEL_ID: ${{ secrets.DARVAREH_MODEL_ID }}
        run: npx tsx ai/analyze-failure.ts

      - name: Upload Playwright artifacts
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: playwright-report
          path: |
            playwright-report/
            test-results/
          retention-days: 7

      - name: Mark workflow as failed
        if: steps.playwright.outcome == 'failure'
        run: exit 1

در این Workflow:

  • تست‌ها در Push و Pull Request اجرا می‌شوند.
  • مرورگرهای موردنیاز نصب می‌شوند.
  • در صورت شکست تست، تحلیل AI اجرا می‌شود.
  • گزارش، Trace و تحلیل هوش مصنوعی ذخیره می‌شوند.
  • نتیجه نهایی Pipeline همچنان ناموفق باقی می‌ماند.

AI نباید یک تست ناموفق را به موفق تبدیل کند یا خطای آن را پنهان کند.

افزودن دستورها به package.json

{
  "scripts": {
    "test:e2e": "playwright test",
    "test:e2e:ui": "playwright test --ui",
    "test:e2e:debug": "playwright test --debug",
    "test:e2e:report": "playwright show-report",
    "test:e2e:generate": "tsx ai/generate-test.ts",
    "test:e2e:analyze": "tsx ai/analyze-failure.ts"
  }
}

اکنون اعضای تیم می‌توانند از دستورهای یکسان استفاده کنند:

npm run test:e2e
npm run test:e2e:ui
npm run test:e2e:generate
npm run test:e2e:analyze

تست تصویری با Playwright

Playwright امکان مقایسه Screenshot را نیز فراهم می‌کند:

import { test, expect } from '@playwright/test';

test('صفحه اصلی از نظر بصری تغییر ناخواسته ندارد', async ({
  page,
}) => {
  await page.goto('/');

  await expect(page).toHaveScreenshot(
    'homepage-desktop.png',
    {
      fullPage: true,
      animations: 'disabled',
    }
  );
});

اولین اجرا تصویر مرجع را ایجاد می‌کند:

npx playwright test --update-snapshots

در اجراهای بعدی، تصویر فعلی با Snapshot مرجع مقایسه می‌شود.

برای کاهش خطاهای کاذب تست تصویری:

  • نسخه مرورگر و سیستم‌عامل را ثابت نگه دارید.
  • Animationها را غیرفعال کنید.
  • زمان و تاریخ پویا را ثابت کنید.
  • داده‌های تصادفی را حذف کنید.
  • تصاویر خارجی را Mock کنید.
  • محیط CI مشخص و تکرارپذیر داشته باشید.
  • نواحی کاملاً پویا را Mask کنید.

نمونه Mask کردن:

await expect(page).toHaveScreenshot('dashboard.png', {
  mask: [
    page.getByTestId('current-time'),
    page.getByTestId('dynamic-chart'),
  ],
});

تست API با Playwright

Playwright فقط برای رابط کاربری نیست. می‌توانید API را نیز آزمایش کنید.

import { test, expect } from '@playwright/test';

test('API فهرست محصولات پاسخ معتبر می‌دهد', async ({
  request,
}) => {
  const response = await request.get('/api/products');

  expect(response.ok()).toBeTruthy();

  const body = await response.json();

  expect(Array.isArray(body.items)).toBe(true);
  expect(body.items.length).toBeGreaterThan(0);

  expect(body.items[0]).toEqual(
    expect.objectContaining({
      id: expect.any(String),
      title: expect.any(String),
      price: expect.any(Number),
    })
  );
});

تست API می‌تواند برای آماده‌سازی داده نیز استفاده شود. برای مثال، به‌جای ساخت محصول از پنل مدیریت، قبل از تست آن را با API ایجاد کنید و پس از تست حذف کنید.

تشخیص تست Flaky

تست Flaky تستی است که بدون تغییر کد، گاهی موفق و گاهی ناموفق می‌شود.

دلایل رایج:

  • استفاده از waitForTimeout
  • وابستگی تست‌ها به یکدیگر
  • داده مشترک بین تست‌های موازی
  • Selector شکننده
  • وابستگی به سرویس خارجی
  • Animation
  • زمان و تاریخ متغیر
  • وضعیت نامشخص پایگاه داده
  • درخواست شبکه‌ای کند
  • اشتراک یک حساب بین تست‌های تغییردهنده
  • نادیده گرفتن Promiseها
  • استفاده نادرست از Retry

در Playwright، تستی که ابتدا شکست بخورد و در Retry موفق شود، Flaky شناخته می‌شود. Retry برای جمع‌آوری اطلاعات و کاهش اختلال موقت مفید است، اما نباید جایگزین رفع علت اصلی شود.

برای تکرار یک تست و پیدا کردن ناپایداری:

npx playwright test tests/checkout.spec.ts --repeat-each=20

اجرای یک تست روی Chromium:

npx playwright test tests/checkout.spec.ts --project=chromium

اجرای یک تست مشخص:

npx playwright test -g "کاربر می‌تواند محصول موجود را سفارش دهد"

استفاده درست از هوش مصنوعی برای رفع تست Flaky

برای تحلیل مناسب، این داده‌ها را به مدل بدهید:

  • نام تست
  • تعداد دفعات شکست
  • مرورگر
  • مدت اجرای موفق و ناموفق
  • Error Message
  • Call Log
  • Locator مربوطه
  • درخواست‌های شبکه ناموفق
  • Console Errorها
  • تغییرات اخیر
  • بخش مرتبط از Trace

از مدل بخواهید علت‌ها را در دسته‌های مشخص قرار دهد:

  • مشکل واقعی محصول
  • Locator نامناسب
  • داده تست
  • Race Condition
  • محیط CI
  • سرویس خارجی
  • تنظیمات Playwright
  • Timeout نامناسب
  • اطلاعات ناکافی

نمونه پرامپت:

این تست Playwright در 3 اجرا از 20 اجرا ناموفق شده است.

وظیفه:
- علت‌های محتمل را اولویت‌بندی کن.
- شواهد هر علت را مشخص کن.
- میان مشکل محصول و مشکل تست تفاوت بگذار.
- راه‌حل مبتنی بر waitForTimeout پیشنهاد نده.
- اگر شواهد کافی نیست، داده لازم را مشخص کن.
- در پایان یک تست Regression پیشنهاد بده.

چه تست‌هایی را ابتدا خودکار کنیم؟

همه تست‌ها ارزش یکسانی ندارند. ابتدا مسیرهایی را خودکار کنید که در صورت خرابی بیشترین اثر را دارند.

اولویت مناسب برای بسیاری از محصولات:

  1. ثبت‌نام
  2. ورود و خروج
  3. بازیابی دسترسی
  4. خرید یا ثبت سفارش
  5. پرداخت آزمایشی یا Callback شبیه‌سازی‌شده
  6. عملیات اصلی محصول
  7. مدیریت نقش‌ها
  8. ذخیره و بازیابی داده
  9. تغییر تنظیمات مهم
  10. مسیرهای حیاتی موبایل

برای انتخاب سناریو می‌توانید از امتیازدهی ساده استفاده کنید:

اولویت تست = اثر کسب‌وکاری × احتمال خرابی × فراوانی استفاده

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

اشتباهات رایج در استفاده از AI برای Playwright

دادن URL و درخواست «همه تست‌ها را بنویس»

مدل بدون شناخت دقیق رفتار محصول نمی‌تواند نتیجه مورد انتظار را تشخیص دهد.

راه‌حل: Routeها، User Story، Locatorها، نقش‌ها و Acceptance Criteria را در اختیار مدل قرار دهید.

قبول کردن Locatorهای اختراعی

مدل ممکن است data-testid تولید کند که در برنامه وجود ندارد.

راه‌حل: قرارداد Locatorهای مجاز تعریف کنید و خروجی را اعتبارسنجی کنید.

تولید تست بدون Assertion واقعی

این تست ناقص است:

await page.goto('/checkout');
await page.getByRole('button', { name: 'ثبت سفارش' }).click();

فقط انجام عملیات کافی نیست. باید نتیجه بررسی شود:

await expect(
  page.getByRole('heading', { name: 'سفارش شما ثبت شد' })
).toBeVisible();

استفاده زیاد از Retry

Retry می‌تواند تست Flaky را پنهان کند. هر تستی که در اجرای اول شکست خورده و در Retry موفق شده باید بررسی شود.

ارسال تمام Trace بدون پالایش

Trace ممکن است داده‌های حساس داشته باشد. فقط اطلاعات موردنیاز را پس از حذف Cookie، Token، Header و داده واقعی کاربران ارسال کنید.

تغییر خودکار تست پس از شکست

اگر یک Agent بعد از هر شکست Assertion را ضعیف‌تر کند، تست‌ها به‌تدریج بی‌ارزش می‌شوند.

این تغییر خطرناک است:

await expect(total).toHaveText('۱۰۰٬۰۰۰');

تبدیل خودکار آن به این Assertion مشکل را پنهان می‌کند:

await expect(total).toBeVisible();

تست هنوز اجرا می‌شود، اما دیگر مبلغ صحیح را بررسی نمی‌کند.

الگوی امن برای Agent تست‌نویس

اگر قصد ساخت یک AI Agent برای نگهداری تست‌ها را دارید، سطح دسترسی آن را محدود کنید.

Agent می‌تواند:

  • سناریوی جدید پیشنهاد دهد.
  • فایل تست جدید در Branch جداگانه بسازد.
  • خطا را خلاصه کند.
  • Locator نامعتبر را گزارش دهد.
  • Regression Test پیشنهاد کند.
  • Draft Pull Request آماده کند.

Agent نباید بدون تأیید:

  • تست شکست‌خورده را Skip کند.
  • Assertion را حذف کند.
  • Timeout را به مقدار بسیار بزرگ افزایش دهد.
  • Retry را بی‌دلیل زیاد کند.
  • Snapshot مرجع را به‌روزرسانی کند.
  • فایل Auth را بخواند.
  • Secretها را در خروجی قرار دهد.
  • Branch اصلی را تغییر دهد.

کاهش هزینه استفاده از AI در تست نرم‌افزار

قرار نیست برای هر کلیک مرورگر یک درخواست AI ارسال شود. این کار هم هزینه را افزایش می‌دهد و هم تست را غیرقطعی می‌کند.

الگوی مناسب:

  • اجرای مرورگر کاملاً قطعی و محلی باشد.
  • تولید تست فقط هنگام ایجاد سناریوی جدید انجام شود.
  • تحلیل AI فقط برای تست‌های شکست‌خورده اجرا شود.
  • خطاهای تکراری Cache شوند.
  • فقط قسمت مرتبط گزارش به مدل ارسال شود.
  • برای خلاصه‌سازی اولیه از مدل اقتصادی‌تر استفاده شود.
  • برای خطاهای پیچیده از مدل قوی‌تر استفاده شود.
  • حداکثر طول ورودی کنترل شود.
  • تحلیل‌های مشابه دسته‌بندی شوند.

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

معیارهای ارزیابی کیفیت مجموعه تست

صرفاً زیاد بودن تعداد تست‌ها نشانه کیفیت نیست. این شاخص‌ها را اندازه‌گیری کنید:

  • نرخ موفقیت در اجرای اول
  • تعداد تست‌های Flaky
  • میانگین زمان اجرا
  • تعداد خطاهای واقعی کشف‌شده
  • تعداد شکست‌های کاذب
  • مدت زمان تشخیص علت خطا
  • درصد مسیرهای حیاتی پوشش‌داده‌شده
  • تعداد تست‌های وابسته به Selector شکننده
  • هزینه نگهداری تست‌ها
  • نرخ پذیرش تست‌های تولیدشده با AI
  • درصد خروجی AI که نیازمند اصلاح اساسی است

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

برنامه پیشنهادی پیاده‌سازی در تیم

مرحله اول: راه‌اندازی پایه

  • نصب Playwright
  • انتخاب Chromium
  • ساخت پنج تست حیاتی
  • فعال کردن گزارش HTML
  • ذخیره Screenshot هنگام شکست

مرحله دوم: پایدارسازی

  • حذف waitForTimeout
  • جایگزینی Selectorهای شکننده
  • مستقل کردن داده تست‌ها
  • Mock کردن سرویس‌های خارجی
  • ساخت Auth Setup
  • فعال کردن Trace در Retry

مرحله سوم: CI

  • اجرای تست در Pull Request
  • ذخیره Artifact
  • جلوگیری از Merge هنگام شکست مسیر حیاتی
  • تفکیک Smoke Test از Full Regression

مرحله چهارم: افزودن هوش مصنوعی

  • ساخت قرارداد برنامه
  • تولید پیش‌نویس تست از User Story
  • تحلیل گزارش‌های شکست‌خورده
  • تولید پیشنهاد Regression
  • اندازه‌گیری نرخ پذیرش پیشنهادهای مدل

مرحله پنجم: مقیاس‌پذیری

  • اجرای موازی
  • Sharding
  • تفکیک پروژه‌های مرورگر
  • ساخت Test Data Factory
  • داشبورد Flakiness
  • تحلیل روند خطاها
  • استفاده کنترل‌شده از Agent

چک‌لیست نهایی تست Playwright

پیش از Merge کردن یک تست جدید بررسی کنید:

  • آیا تست یک رفتار واقعی کاربر را بررسی می‌کند؟
  • آیا نتیجه مورد انتظار با Assertion قطعی مشخص شده است؟
  • آیا تست مستقل اجرا می‌شود؟
  • آیا به ترتیب اجرای سایر تست‌ها وابسته نیست؟
  • آیا از getByRole و getByLabel استفاده شده است؟
  • آیا waitForTimeout حذف شده است؟
  • آیا داده تست کنترل‌شده است؟
  • آیا سرویس خارجی غیرضروری Mock شده است؟
  • آیا اطلاعات ورود از Environment Variable خوانده می‌شود؟
  • آیا تست در CI قابل اجرا است؟
  • آیا Screenshot و Trace فقط در زمان مناسب ذخیره می‌شوند؟
  • آیا خروجی AI توسط توسعه‌دهنده بازبینی شده است؟
  • آیا مدل هیچ Route یا Locator غیرواقعی ایجاد نکرده است؟
  • آیا شکست تست همچنان باعث شکست CI می‌شود؟
  • آیا داده ارسالی برای تحلیل AI پالایش شده است؟

پرسش‌های متداول

Playwright چیست؟

Playwright یک فریم‌ورک تست خودکار برای برنامه‌های وب است که امکان اجرای تست روی Chromium، Firefox و WebKit را فراهم می‌کند. این ابزار دارای Test Runner، Auto-waiting، Assertion، Trace Viewer و امکانات CI است.

آیا Playwright فقط برای JavaScript است؟

خیر. Playwright برای JavaScript و TypeScript، پایتون (Python)، جاوا و دات‌نت API ارائه می‌دهد. Playwright Test در اکوسیستم Node.js تجربه یکپارچه‌ای برای Test Runner و Assertion فراهم می‌کند.

Playwright بهتر است یا Selenium؟

پاسخ به نیاز پروژه بستگی دارد. Playwright برای برنامه‌های وب مدرن، Auto-waiting، Browser Context، Trace و API یکپارچه‌ای ارائه می‌کند. Selenium نیز اکوسیستم قدیمی‌تر و پشتیبانی گسترده‌ای دارد. برای پروژه جدید وب، Playwright یکی از گزینه‌های جدی است.

آیا هوش مصنوعی می‌تواند تمام تست‌های Playwright را خودکار تولید کند؟

می‌تواند پیش‌نویس مناسبی تولید کند، اما بدون قرارداد محصول و بازبینی انسانی ممکن است Locator، Route یا انتظار غیرواقعی ایجاد کند. بهتر است AI دستیار تست‌نویسی باشد، نه مرجع نهایی رفتار محصول.

آیا باید در زمان اجرای هر تست از API هوش مصنوعی استفاده کنیم؟

معمولاً خیر. اجرای تست باید سریع، قطعی و قابل تکرار باشد. AI را برای تولید سناریو، تولید پیش‌نویس کد و تحلیل شکست‌ها استفاده کنید.

چگونه از تست‌های Flaky جلوگیری کنیم؟

از Locatorهای پایدار، Web-first Assertion، داده مستقل، Mock سرویس‌های خارجی و وضعیت کنترل‌شده استفاده کنید. از waitForTimeout و وابستگی تست‌ها به یکدیگر اجتناب کنید.

آیا می‌توان Playwright را در GitHub Actions اجرا کرد؟

بله. مرورگرها و وابستگی‌های سیستم نصب می‌شوند و سپس فرمان npx playwright test اجرا می‌شود. گزارش، Screenshot و Trace نیز می‌توانند به‌عنوان Artifact ذخیره شوند.

آیا می‌توان تست‌ها را روی موبایل اجرا کرد؟

Playwright قابلیت شبیه‌سازی دستگاه، Viewport، User Agent و رفتار مرورگر موبایل را دارد. بااین‌حال این شبیه‌سازی جای تست محدود روی دستگاه واقعی را به‌طور کامل نمی‌گیرد.

آیا API درواره با کتابخانه OpenAI سازگار است؟

بله، برای ابزارهایی که امکان تعیین Base URL دارند می‌توانید از آدرس زیر استفاده کنید:

https://api.darvareh.ir/v1

در نمونه این مقاله، کتابخانه OpenAI فقط به‌عنوان Client سازگار با API درواره استفاده شده است.

از کدام مدل برای تولید تست استفاده کنیم؟

مدلی انتخاب کنید که در Coding، دنبال کردن دستور، تولید TypeScript و تحلیل خطا عملکرد مناسبی داشته باشد. چون مدل‌ها و قیمت‌ها تغییر می‌کنند، انتخاب خود را براساس فهرست و قیمت مدل‌های درواره انجام دهید.

جمع‌بندی

ترکیب Playwright و هوش مصنوعی می‌تواند فرایند تست نرم‌افزار را سریع‌تر و منظم‌تر کند، اما موفقیت این معماری به تفکیک درست مسئولیت‌ها بستگی دارد.

Playwright باید مسئول اجرای قطعی تست، تعامل با مرورگر و ارزیابی Assertionها باشد. هوش مصنوعی نیز می‌تواند در تولید سناریو، نوشتن پیش‌نویس تست، کشف حالت‌های مرزی و تحلیل خطاها کمک کند.

بهترین نقطه شروع این است:

  1. پنج مسیر حیاتی محصول را انتخاب کنید.
  2. برای آن‌ها تست Playwright پایدار بنویسید.
  3. تست‌ها را در CI اجرا کنید.
  4. Trace و گزارش خطا را فعال کنید.
  5. API درواره را برای تولید تست و تحلیل شکست‌ها اضافه کنید.
  6. کیفیت خروجی AI را با معیارهای مشخص اندازه‌گیری کنید.

با این رویکرد، هوش مصنوعی جایگزین تست قطعی نمی‌شود؛ بلکه زمان توسعه، نگهداری و عیب‌یابی تست‌ها را کاهش می‌دهد.

شروع ساخت دستیار تست با API درواره

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

برای شروع:

  • در درواره ثبت‌نام کنید.
  • یک کلید API بسازید.
  • مدل مناسب Coding یا Reasoning را از صفحه مدل‌ها انتخاب کنید.
  • Base URL را روی https://api.darvareh.ir/v1 قرار دهید.
  • نمونه تولید تست و تحلیل خطای همین مقاله را اجرا کنید.

مقالات مرتبط

برای مطالعه شرایط استفاده و محدودیت‌های مسئولیت، صفحه «سلب مسئولیت» را مشاهده کنید.

Read more

اتوماسیون هوش مصنوعی چیست؟ کاربردها و آموزش ساخت AI Automation

اتوماسیون هوش مصنوعی چیست؟ کاربردها و آموزش ساخت AI Automation

اتوماسیون هوش مصنوعی با ترکیب گردش‌کارهای خودکار و مدل‌های هوش مصنوعی، پردازش متن، دسته‌بندی، استخراج اطلاعات و تصمیم‌های پیشنهادی را خودکار می‌کند. در این راهنما، معماری و ساخت نمونه عملی آن با API درواره را می‌آموزید.

Agentic Commerce چیست؟ آینده خرید با ایجنت هوش مصنوعی

Agentic Commerce چیست؟ آینده خرید با ایجنت هوش مصنوعی

Agentic Commerce شیوه‌ای جدید برای خرید اینترنتی است که در آن ایجنت هوش مصنوعی می‌تواند نیاز کاربر را بفهمد، محصولات را جست‌وجو و مقایسه کند و فرایند خرید را پیش ببرد. در این راهنما با معماری، UCP، ACP و پیاده‌سازی آن با API درواره آشنا می‌شوید.