آموزش کامل Playwright در ASP.NET Core — از صفر تا صد

Playwright در asp.net core همه سطوح
parsakarimidev.ir

آموزش کامل Playwright در ASP.NET Core — از صفر تا صد

Playwright در asp.net coreفریم‌ورک سطح: همه سطوح 1405/07/05

آموزش کامل Playwright در ASP.NET Core — از صفر تا صد

⚡ خلاصه سریع — اصل کاری‌ها

این‌ها مهم‌ترین چیزهایی هستن که اگه هیچی ندونی، فقط اینا رو بدونی کافیه:

  • نکته ۱: Playwright ابزار رسمی مرورگر خودکار برای .NET است و تست‌های End-to-End واقعی را انجام می‌دهد.
  • نکته ۲: پکیج Microsoft.Playwright را نصب و بلافاصله با playwright.ps1 install مرورگرها را دانلود کن.
  • نکته ۳: نقطه شروع ساخت IPlaywright و سپس IBrowser از طریق Playwright.CreateAsync() و Chromium.LaunchAsync() است.
  • نکته ۴: تمام تعاملات روی IPage صورت می‌گیرد؛ از GotoAsync برای ناوبری، FillAsync برای ورود متن و ClickAsync برای کلیک استفاده کن.
  • نکته ۵: از Locatorهای مدرن مثل GetByRole، GetByLabel و GetByTestId به‌جای Selectorهای CSS شکننده استفاده کن.
  • نکته ۶: برای اتصال Playwright به ASP.NET Core، برنامه را روی یک پورت واقعی مانند http://localhost:5000 اجرا کن.
  • نکته ۷: همیشه منابع را با DisposeAsync یا await using ببند؛ بازماندن Browser باعث قفل مرورگر و هدررفت حافظه می‌شود.
  • نکته ۸: حالت Headless برای CI/CD و حالت Headed برای دیباگ محلی کاربردی است.

۳ اشتباه رایج که باید ازشون پرهیز کنی:

  1. فراموش کردن نصب مرورگرها بعد از افزودن پکیج.
  2. استفاده از Selectorهای شکننده مثل div > span به‌جای Locatorهای مبتنی بر نقش یا متن.
  3. اتصال به TestServer به‌جای Kestrel واقعی؛ مرورگر باید به یک URL شبکه‌ای دسترسی داشته باشد.

اگر فقط ۵ دقیقه وقت داری، این‌ها رو یاد بگیر:

  1. ساخت IPlaywright و IBrowser برای باز کردن مرورگر.
  2. ناوبری و تعامل با page.GotoAsync و page.ClickAsync.
  3. نصب مرورگرها با playwright.ps1 install.

۱. مقدمه

این موضوع چیه؟

Playwright یک کتابخانه اتوماسیون مرورگر متن‌باز از مایکروسافت است که به شما اجازه می‌دهد مرورگرهای Chromium، Firefox و WebKit را به‌صورت برنامه‌نویسی کنترل کنید. نسخه رسمی .NET آن با نام Microsoft.Playwright منتشر می‌شود و می‌تواند مستقیماً در پروژه‌های ASP.NET Core برای تست رابط کاربری (UI) و سناریوهای End-to-End استفاده شود.

چرا باید یادش بگیری؟

  • برخلاف Selenium، Playwright انتظار خودکار (auto-waiting) دارد؛ یعنی قبل از کلیک یا تایپ، صبر می‌کند تا عنصر واقعاً قابل تعامل شود.
  • Locatorهای قوی‌تر و پایدارتر (GetByRole، GetByText، GetByTestId) دارد.
  • جداسازی Contextها باعث تست‌های موازی امن می‌شود.
  • امکانات حرفه‌ای مثل Trace، Video Recording و Network Mocking به‌صورت داخلی فراهم است.

کجا استفاده می‌شود؟

  • تست فرم‌های لاگین و احراز هویت
  • تست جریان‌های تجاری در برنامه‌های Razor Pages و MVC
  • تست رابط کاربری Blazor Server/WebAssembly
  • تست رگرسیون رابط کاربری در CI/CD
  • اسکرین‌شات گرفتن و دیباگ صفحات

۲. پیش‌نیازها

چه چیزهایی رو باید از قبل بدونی؟

  • آشنایی با زبان C# و برنامه‌نویسی async/await
  • آشنایی اولیه با ASP.NET Core (MVC یا Razor Pages)
  • مفاهیم ابتدایی تست‌نویسی (ترجیحاً xUnit)
  • HTML و CSS در حد تشخیص عناصر صفحه

ابزارهای لازم

  • .NET SDK نسخه 8 یا بالاتر
  • Visual Studio / Rider / VS Code
  • PowerShell یا Bash
  • مرورگر Chromium یا Firefox برای اجرای تست‌ها

۳. نصب و راه‌اندازی

۳.۱ ساخت پروژه تست

یک پروژه xUnit برای تست‌ها بساز:

dotnet new xunit -n PlaywrightDemo.Tests
cd PlaywrightDemo.Tests

۳.۲ نصب پکیج Playwright

dotnet add package Microsoft.Playwright

۳.۳ نصب مرورگرها

بعد از افزودن پکیج، باید یک بار پروژه را Build کنی تا اسکریپت playwright.ps1 در پوشه خروجی ساخته شود:

dotnet build

سپس مرورگرها را نصب کن:

pwsh bin/Debug/net8.0/playwright.ps1 install

اگر فقط Chromium نیاز داری:

pwsh bin/Debug/net8.0/playwright.ps1 install chromium

در لینوکس/CI معمولاً نیاز به نصب وابستگی‌های سیستمی هم داری:

pwsh bin/Debug/net8.0/playwright.ps1 install --with-deps

توجه: مسیر net8.0 بسته به نسخه .NET تو ممکن است net6.0، net7.0 یا net9.0 باشد.

۳.۴ اولین پروژه ساده

برای تست سریع، یک برنامه Console بساز:

dotnet new console -n PlaywrightIntro
cd PlaywrightIntro
dotnet add package Microsoft.Playwright
dotnet build
pwsh bin/Debug/net8.0/playwright.ps1 install chromium

محتویات Program.cs را این‌طور بنویس:

using Microsoft.Playwright;

// ساخت Playwright
using var playwright = await Playwright.CreateAsync();

// باز کردن مرورگر Chromium
await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions
{
    Headless = false // برای دیدن مرورگر
});

// ساخت یک صفحه جدید
var page = await browser.NewPageAsync();

// رفتن به یک URL
await page.GotoAsync("https://example.com");

Console.WriteLine("Title: " + await page.TitleAsync());

توضیح:

  • Playwright.CreateAsync() نقطه ورود اصلی است.
  • Chromium.LaunchAsync() مرورگر را اجرا می‌کند.
  • NewPageAsync() یک تب جدید باز می‌کند.
  • GotoAsync() به یک آدرس می‌رود.
  • TitleAsync() عنوان صفحه را برمی‌گرداند.

۴. مفاهیم پایه

۴.۱ IPlaywright

IPlaywright شیء اصلی و نقطه شروع است. با استفاده از آن می‌توانی به انواع مرورگر (Chromium، Firefox، WebKit) دسترسی پیدا کنی:

using var playwright = await Playwright.CreateAsync();
var chromium = playwright.Chromium;
var firefox = playwright.Firefox;
var webkit = playwright.Webkit;

۴.۲ IBrowser و IBrowserContext

IBrowser یک نمونه مرورگر را نشان می‌دهد. اما IBrowserContext یک جلسه ایزوله با کوکی‌ها، حافظه محلی و تب‌های مخصوص به خود است. هر Context مانند یک پروفایل جداگانه مرورگر عمل می‌کند:

await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions
{
    Headless = true
});

// ساخت Context جداگانه
await using var context = await browser.NewContextAsync();

// ساخت صفحه در داخل Context
var page = await context.NewPageAsync();

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

۴.۳ IPage

IPage یک تب یا صفحه وب را نشان می‌دهد. مهم‌ترین متدهای آن:

متد کاربرد
GotoAsync() رفتن به آدرس
ClickAsync() کلیک روی عنصر
FillAsync() پر کردن ورودی متن
TitleAsync() گرفتن عنوان صفحه
ContentAsync() گرفتن HTML صفحه
ScreenshotAsync() عکس گرفتن

۴.۴ Locator

Locator روشی برای پیدا کردن عناصر صفحه است. Locatorهای مدرن نسبت به Selectorهای CSS پایدارترند:

// با متن
var link = page.GetByText("Home");

// با نقش (Role)
var button = page.GetByRole(AriaRole.Button, new() { Name = "Login" });

// با Label
var usernameInput = page.GetByLabel("Username");

// با data-testid
var submit = page.GetByTestId("submit-button");

// با Selector CSS (کمتر توصیه می‌شود)
var oldWay = page.Locator("div > span.login");

۴.۵ انتظار خودکار (Auto-waiting)

برخلاف Selenium که باید دستی Thread.Sleep یا WebDriverWait بنویسی، Playwright قبل از عملیات‌ها منتظر می‌ماند تا عنصر قابل مشاهده و فعال شود:

// این کلیک منتظر می‌ماند تا دکمه واقعاً قابل کلیک باشد
await page.GetByRole(AriaRole.Button, new() { Name = "Login" }).ClickAsync();

اگر عنصر در مدت‌زمان پیش‌فرض (معمولاً ۳۰ ثانیه) پیدا نشود، خطای Timeout می‌گیرید.


۵. مثال‌های کد ساده

۵.۱ رفتن به یک صفحه و چاپ عنوان

using Microsoft.Playwright;

using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions
{
    Headless = true
});

var page = await browser.NewPageAsync();
await page.GotoAsync("https://example.com");
Console.WriteLine(await page.TitleAsync());

۵.۲ پر کردن فرم و کلیک

var page = await browser.NewPageAsync();
await page.GotoAsync("https://demo.example.com/login");

// پر کردن فیلدها با label
await page.GetByLabel("Username").FillAsync("admin");
await page.GetByLabel("Password").FillAsync("123456");

// کلیک روی دکمه Login
await page.GetByRole(AriaRole.Button, new() { Name = "Login" }).ClickAsync();

۵.۳ گرفتن اسکرین‌شات

await page.ScreenshotAsync(new PageScreenshotOptions
{
    Path = "screenshot.png",
    FullPage = true // تمام صفحه، نه فقط قسمت قابل مشاهده
});

۵.۴ انتظار برای نمایش یک عنصر

using static Microsoft.Playwright.Assertions;

// بعد از لاگین منتظر نمایش متن Welcome باش
await Expect(page.GetByText("Welcome")).ToBeVisibleAsync();

۵.۵ کار با ASP.NET Core روی localhost

await page.GotoAsync("http://localhost:5000");

// کلیک روی لینک Home
await page.GetByRole(AriaRole.Link, new() { Name = "Home" }).ClickAsync();

۶. مثال واقعی و کاربردی

سناریو: تست لاگین در ASP.NET Core MVC

قدم ۱: ساخت برنامه ASP.NET Core MVC

dotnet new sln -n PlaywrightDemo
dotnet new mvc -n PlaywrightDemo.Web
dotnet new xunit -n PlaywrightDemo.Tests
dotnet sln add PlaywrightDemo.Web PlaywrightDemo.Tests

قدم ۲: افزودن صفحه لاگین ساده

فایل Models/LoginViewModel.cs:

namespace PlaywrightDemo.Web.Models;

public class LoginViewModel
{
    public string Username { get; set; }
    public string Password { get; set; }
}

فایل Controllers/AccountController.cs:

using Microsoft.AspNetCore.Mvc;
using PlaywrightDemo.Web.Models;

namespace PlaywrightDemo.Web.Controllers;

public class AccountController : Controller
{
    [HttpGet]
    public IActionResult Login()
    {
        return View();
    }

    [HttpPost]
    public IActionResult Login(LoginViewModel model)
    {
        if (model.Username == "admin" && model.Password == "123456")
        {
            ViewData["WelcomeMessage"] = "خوش آمدید، admin!";
            return View("Welcome");
        }

        ModelState.AddModelError("", "Invalid credentials");
        return View(model);
    }
}

فایل Views/Account/Login.cshtml:

@model LoginViewModel

<h1>Login</h1>

<form asp-action="Login" method="post">
    <div>
        <label asp-for="Username">Username</label>
        <input asp-for="Username" />
    </div>
    <div>
        <label asp-for="Password">Password</label>
        <input asp-for="Password" type="password" />
    </div>
    <button type="submit">Login</button>
</form>

فایل Views/Account/Welcome.cshtml:

<h1>@ViewData["WelcomeMessage"]</h1>

قدم ۳: آماده‌سازی پروژه تست

cd PlaywrightDemo.Tests
dotnet add package Microsoft.Playwright
dotnet build
pwsh bin/Debug/net8.0/playwright.ps1 install chromium

قدم ۴: ساخت Fixture برای مدیریت مرورگر

فایل PlaywrightFixture.cs:

using Microsoft.Playwright;

namespace PlaywrightDemo.Tests;

public class PlaywrightFixture : IAsyncLifetime
{
    public IPlaywright Playwright { get; private set; }
    public IBrowser Browser { get; private set; }

    public async Task InitializeAsync()
    {
        Playwright = await Playwright.CreateAsync();
        Browser = await Playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions
        {
            Headless = true, // در CI معمولاً true
            SlowMo = 100      // فقط برای دیباگ محلی
        });
    }

    public async Task DisposeAsync()
    {
        await Browser.DisposeAsync();
        Playwright.Dispose();
    }
}

قدم ۵: نوشتن تست لاگین

فایل LoginTests.cs:

using Microsoft.Playwright;
using static Microsoft.Playwright.Assertions;

namespace PlaywrightDemo.Tests;

public class LoginTests : IClassFixture<PlaywrightFixture>
{
    private const string BaseUrl = "http://localhost:5000";
    private readonly PlaywrightFixture _fixture;

    public LoginTests(PlaywrightFixture fixture)
    {
        _fixture = fixture;
    }

    [Fact]
    public async Task Should_Show_Welcome_After_Login()
    {
        // ساخت Context جداگانه برای تست
        await using var context = await _fixture.Browser.NewContextAsync();
        var page = await context.NewPageAsync();

        // رفتن به صفحه لاگین
        await page.GotoAsync($"{BaseUrl}/Account/Login");

        // پر کردن فرم
        await page.GetByLabel("Username").FillAsync("admin");
        await page.GetByLabel("Password").FillAsync("123456");

        // کلیک روی دکمه Login
        await page.GetByRole(AriaRole.Button, new() { Name = "Login" }).ClickAsync();

        // انتظار برای نمایش پیام خوش‌آمد
        var heading = page.GetByRole(AriaRole.Heading, new() { Name = "خوش آمدید، admin!" });
        await Expect(heading).ToBeVisibleAsync();
    }
}

قدم ۶: اجرای برنامه و تست

ابتدا برنامه وب را روی پورت 5000 اجرا کن:

cd PlaywrightDemo.Web
dotnet run --urls=http://localhost:5000

در ترمینال دیگر تست‌ها را اجرا کن:

cd PlaywrightDemo.Tests
dotnet test

۷. مباحث پیشرفته

۷.۱ ایزوله‌سازی با Context برای تست‌های موازی

به‌جای به‌اشتراک‌گذاشتن یک IPage بین تست‌ها، برای هر تست یک IBrowserContext جدید بساز. این کار کوکی‌ها و Sessionها را ایزوله نگه می‌دارد:

[Fact]
public async Task Test_With_Isolated_Context()
{
    await using var context = await _fixture.Browser.NewContextAsync();
    var page = await context.NewPageAsync();

    // تست بدون تداخل با تست‌های دیگر
}

۷.۲ ضبط Trace

Trace برای دیباگ خطاها در CI بسیار مفید است:

await context.Tracing.StartAsync(new TracingStartOptions
{
    Screenshots = true,
    Snapshots = true
});

try
{
    // ... عملیات تست ...
}
finally
{
    await context.Tracing.StopAsync(new TracingStopOptions
    {
        Path = "trace.zip"
    });
}

برای مشاهده Trace:

pwsh bin/Debug/net8.0/playwright.ps1 show-trace trace.zip

۷.۳ ضبط ویدیو

var context = await browser.NewContextAsync(new BrowserNewContextOptions
{
    RecordVideoDir = "videos",
    ViewportSize = new ViewportSize { Width = 1280, Height = 720 }
});

var page = await context.NewPageAsync();
await page.GotoAsync("http://localhost:5000");

// بعد از پایان تست، ویدیو در پوشه videos ذخیره می‌شود
await context.DisposeAsync();

۷.۴ شبیه‌سازی API با Route

می‌توانی درخواست‌های شبکه را قطع کنی و پاسخ جعلی برگردانی:

await page.RouteAsync("**/api/user", async route =>
{
    await route.FulfillAsync(new RouteFulfillOptions
    {
        Status = 200,
        ContentType = "application/json",
        Body = "{\"name\":\"admin\",\"role\":\"admin\"}"
    });
});

await page.GotoAsync("http://localhost:5000/users");

یا درخواست‌های اضافی مثل تصاویر را مسدود کن:

await page.RouteAsync("**/*.{png,jpg,jpeg}", route => route.AbortAsync());

۷.۵ ذخیره و بازیابی State احراز هویت

بعد از لاگین، می‌توانی Session را ذخیره و در تست‌های بعدی استفاده کنی:

// ذخیره state بعد از لاگین
await context.StorageStateAsync(new StorageStateOptions
{
    Path = "state.json"
});

// استفاده در Context جدید
var context = await browser.NewContextAsync(new BrowserNewContextOptions
{
    StorageStatePath = "state.json"
});

۷.۶ استفاده از data-testid

در Viewهای Razor خود از data-testid استفاده کن تا Locatorها پایدارتر شوند:

<button type="submit" data-testid="login-button">Login</button>

سپس در تست:

await page.GetByTestId("login-button").ClickAsync();

۸. اشتباهات رایج

  1. نصب نکردن مرورگرها
    بعد از dotnet add package Microsoft.Playwright فکر می‌کنی همه‌چیز آماده است. اما باید حتماً playwright.ps1 install را اجرا کنی.

  2. باز گذاشتن Browser و Context
    اگر Browser یا Playwright را Dispose نکنی، مرورگرها باز می‌مانند و منابع سیستم هدر می‌رود. همیشه از await using یا DisposeAsync استفاده کن.

  3. استفاده از Selectorهای CSS شکننده
    Selectorهایی مثل div > span به محض تغییر ساختار HTML می‌شکنند. به‌جای آن از GetByRole، GetByLabel یا GetByTestId استفاده کن.

  4. استفاده از Thread.Sleep یا WaitForTimeout
    Playwright انتظار خودکار دارد. استفاده از Sleep باعث کندی و تست‌های غیرقابل اعتماد می‌شود. از Assertionها و انتظارهای صریح استفاده کن.

  5. اتصال به TestServer به‌جای Kestrel واقعی
    اگر از WebApplicationFactory استفاده می‌کنی، دقت کن که TestServer درون‌حافظه است و مرورگر نمی‌تواند به آن متصل شود. برای تست با Playwright باید برنامه را روی یک پورت واقعی اجرا کنی.

  6. فراموش کردن اجرای برنامه قبل از تست
    تست‌های Playwright به یک URL واقعی نیاز دارند. قبل از dotnet test، برنامه ASP.NET Core را با dotnet run اجرا کن یا در CI یک سرویس واقعی بالا بیاور.


۹. بهترین روش‌ها (Best Practices)

  • از Locatorهای مدرن استفاده کن
    GetByRole، GetByLabel، GetByTestId را به Selectorهای CSS ترجیح بده.

  • هر تست یک Context جداگانه داشته باشد
    این کار تست‌های موازی را ایزوله و قابل اعتماد نگه می‌دارد.

  • از انتظار خودکار استفاده کن
    به‌جای WaitForTimeout از Expect(locator).ToBeVisibleAsync() استفاده کن.

  • از data-testid در Viewها استفاده کن
    این ویژگی انتخاب‌ها را از جزئیات ظاهری جدا می‌کند.

  • در CI از حالت Headless استفاده کن
    مرورگر بدون رابط کاربری سریع‌تر و پایدارتر است.

  • خطاها را با Trace ضبط کن
    در CI همیشه Trace را ذخیره کن تا دیباگ خطاها راحت‌تر شود.

  • تست‌ها را مستقل از یکدیگر بنویس
    هیچ تستی نباید به ترتیب یا state تست دیگر وابسته باشد.

  • از ذخیره State برای تست‌های نیازمند لاگین استفاده کن
    به‌جای لاگین در ابتدای هر تست، State را یک بار ذخیره و بارگذاری کن.

  • URL پایه را ثابت نگه دار
    یک ثابت BaseUrl تعریف کن و در همه تست‌ها از آن استفاده کن.


۱۰. منابع و ادامه مسیر

مسیر پیشنهادی بعد از این آموزش

  1. یک پروژه Blazor Server بساز و تست‌های End-to-End برای آن بنویس.
  2. در CI/CD خود Playwright را با GitHub Actions یا Azure DevOps ادغام کن.
  3. تست‌های چندمرورگری (Chromium + Firefox + WebKit) را اجرا کن.
  4. با Network Mocking و API Mocking سناریوهای پیچیده را شبیه‌سازی کن.
  5. از Playwright Codegen برای تولید خودکار Locator و کدهای تست استفاده کن:
pwsh bin/Debug/net8.0/playwright.ps1 codegen http://localhost:5000

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please retry or reload the page.