Token导航 LogoToken导航

Agent Skill · 研究检索

dotnet-playwright(dotnet Playwright 搜索)

用于辅助测试设计、自动化测试、用例整理和回归验证。它适合让 Agent 编写单元测试、端到端测试、测试计划或根据失败日志定位问题。使用时需要确认项目测试框架、运行命令和夹具数据,避免为了通过测试而改坏真实逻辑;涉及浏览器或外部服务时,应区分本地模拟、测试环境和生产环境。

dotnet-playwright 是研究检索类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为操作浏览器;许可证信息还不明确,第三方扫描有未通过项,按安装量在研究检索类的 73,675 个 Skill 里排第 59,803。

总安装 376周安装 16GitHub Stars 15下载 132核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:dotnet-playwright(dotnet Playwright 搜索)
来源仓库:https://github.com/wshaddix/dotnet-skills
仓库路径:skills/dotnet-playwright
安装命令:
npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-playwright
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-playwright

这个 Skill 是做什么的

研究检索类 Skill 主要解决「找资料、核对事实、把来源整理清楚」的问题,通常会让助手先检索再总结。

用于浏览器自动化测试和端到端测试设计,支持 Chromium、Firefox 和 WebKit。适合编写测试用例、调试页面交互或生成测试脚手架,提升回归验证效率。通过 GitHub 安装,需确认项目测试框架和运行命令,区分模拟与真实环境。涉及外部服务时应注意环境隔离,避免因测试改动影响生产逻辑。

dotnet-playwright 属于研究检索类 Skill,可作为该场景下的辅助能力补充。

来源仓库内路径:skills/dotnet-playwright

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-playwrig…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要操作浏览器,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

dotnet-playwright 怎么安装?

在终端执行 npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-playwright。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

dotnet-playwright 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

dotnet-playwright 需要什么权限?

权限级别是操作浏览器。该 Skill 可能涉及浏览器控制能力,使用时可能读取或操作网页内容,需要在受控环境中确认权限边界。

dotnet-playwright 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

dotnet-playwright 用的人多吗?

公开数据是累计安装 376 次,近一周安装 16 次,下载 132 次,GitHub 15 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

dotnet-playwright 安全吗?

第三方扫描有未通过项,风险较高。除非你确认过源码,否则不建议直接安装到常用环境。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。

先想清楚的地方

  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方扫描存在提醒项或未通过项,需要人工逐条确认。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理研究检索类任务、又不想每次都手写提示词的人。

不太适合

  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

研究检索类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
find-skills

寻找技能 · Codex、Claude

31,199,81316,486操作浏览器MIT有提醒
self-improving-agent

自我改进 Agent · OpenClaw

16,464,0023,396接触敏感数据MIT-0通过
soultrace

灵魂追踪 · Codex、Claude

7,588,94412需要联网未明确有提醒
self-improving

自我完善 · OpenClaw

6,829,2841,046需要联网MIT-0通过
microsoft-foundry

微软代工厂 · Codex、Claude

6,614,144764调用外部服务未明确有提醒
dotnet-playwright

dotnet Playwright 搜索 · 本页

37615操作浏览器未明确未通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

dotnet-playwright

Playwright for.NET: browser automation and end-to-end testing. Covers browser lifecycle management, page interactions, assertions, CI caching of browser binaries, trace viewer for debugging failures, and codegen for rapid test scaffolding.

Version assumptions: Playwright 1.40+ for.NET,.NET 8.0+ baseline. Playwright supports Chromium, Firefox, and WebKit browsers.

Out of scope: Shared UI testing patterns (page object model, selectors, wait strategies) are in [skill:dotnet-ui-testing-core]. Testing strategy (when E2E vs unit vs integration) is covered by [skill:dotnet-testing-strategy]. Test project scaffolding is owned by [skill:dotnet-add-testing].

Prerequisites: Test project scaffolded via [skill:dotnet-add-testing] with Playwright packages referenced. Browsers installed via pwsh bin/Debug/net8.0/playwright.ps1 install or dotnet tool run playwright install.

Cross-references: [skill:dotnet-ui-testing-core] for page object model and selector strategies, [skill:dotnet-testing-strategy] for deciding when E2E tests are appropriate.


Package Setup

<PackageReference Include="Microsoft.Playwright" Version="1.*" />
<!-- For xUnit integration: -->
<PackageReference Include="Microsoft.Playwright.Xunit" Version="1.*" />
<!-- For NUnit integration: -->
<!-- <PackageReference Include="Microsoft.Playwright.NUnit" Version="1.*" /> -->

Installing Browsers

Playwright requires downloading browser binaries before tests can run:

# After building the test project:
pwsh bin/Debug/net8.0/playwright.ps1 install

# Or install specific browsers:
pwsh bin/Debug/net8.0/playwright.ps1 install chromium
pwsh bin/Debug/net8.0/playwright.ps1 install firefox

# Using dotnet tool:
dotnet tool install --global Microsoft.Playwright.CLI
playwright install

Basic Test Structure

With Playwright xUnit Base Class

using Microsoft.Playwright;
using Microsoft.Playwright.Xunit;

// PageTest provides Page, Browser, BrowserContext, and Playwright properties
public class HomePageTests : PageTest
{
    [Fact]
    public async Task HomePage_Title_ContainsAppName()
    {
        await Page.GotoAsync("https://localhost:5001");

        await Expect(Page).ToHaveTitleAsync(new Regex("My App"));
    }

    [Fact]
    public async Task HomePage_NavLinks_AreVisible()
    {
        await Page.GotoAsync("https://localhost:5001");

        var nav = Page.Locator("nav");
        await Expect(nav.GetByRole(AriaRole.Link, new() { Name = "Home" }))
            .ToBeVisibleAsync();
        await Expect(nav.GetByRole(AriaRole.Link, new() { Name = "About" }))
            .ToBeVisibleAsync();
    }
}

Manual Setup (Without Base Class)

public class ManualSetupTests : IAsyncLifetime
{
    private IPlaywright _playwright = null!;
    private IBrowser _browser = null!;
    private IBrowserContext _context = null!;
    private IPage _page = null!;

    public async ValueTask InitializeAsync()
    {
        _playwright = await Playwright.CreateAsync();
        _browser = await _playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions
        {
            Headless = true
        });
        _context = await _browser.NewContextAsync(new BrowserNewContextOptions
        {
            ViewportSize = new ViewportSize { Width = 1280, Height = 720 },
            Locale = "en-US"
        });
        _page = await _context.NewPageAsync();
    }

    public async ValueTask DisposeAsync()
    {
        await _page.CloseAsync();
        await _context.CloseAsync();
        await _browser.CloseAsync();
        _playwright.Dispose();
    }

    [Fact]
    public async Task Login_ValidUser_RedirectsToDashboard()
    {
        await _page.GotoAsync("https://localhost:5001/login");

        await _page.FillAsync("[data-testid='email']", "user@example.com");
        await _page.FillAsync("[data-testid='password']", "P@ssw0rd!");
        await _page.ClickAsync("[data-testid='login-btn']");

        await Expect(_page).ToHaveURLAsync(new Regex("/dashboard"));
    }
}

Locators and Interactions

Recommended Locator Strategies

// BEST: Role-based (accessible and semantic)
var submitBtn = Page.GetByRole(AriaRole.Button, new() { Name = "Submit Order" });

// GOOD: Test ID (stable, explicit)
var emailInput = Page.Locator("[data-testid='email-input']");

// GOOD: Label text (user-visible, accessible)
var nameField = Page.GetByLabel("Full Name");

// GOOD: Placeholder (user-visible)
var searchBox = Page.GetByPlaceholder("Search products...");

// AVOID: CSS class (fragile, changes with styling)
var card = Page.Locator(".card-primary");

// AVOID: XPath (brittle, hard to read)
var cell = Page.Locator("//table/tbody/tr[1]/td[2]");

Common Interactions

// Text input
await Page.FillAsync("[data-testid='name']", "Alice Johnson");

// Click
await Page.ClickAsync("[data-testid='submit']");

// Select dropdown
await Page.SelectOptionAsync("[data-testid='country']", "US");

// Checkbox / radio
await Page.CheckAsync("[data-testid='agree-terms']");

// File upload
await Page.SetInputFilesAsync("[data-testid='avatar']", "testdata/photo.jpg");

// Keyboard
await Page.Keyboard.PressAsync("Enter");
await Page.Keyboard.TypeAsync("search query");

// Hover (for dropdowns, tooltips)
await Page.HoverAsync("[data-testid='user-menu']");

Assertions (Expect API)

Playwright assertions auto-retry until the condition is met or the timeout expires:

// Element visibility
await Expect(Page.Locator("[data-testid='success']")).ToBeVisibleAsync();
await Expect(Page.Locator("[data-testid='spinner']")).ToBeHiddenAsync();

// Text content
await Expect(Page.Locator("[data-testid='total']")).ToHaveTextAsync("$99.99");
await Expect(Page.Locator("[data-testid='status']")).ToContainTextAsync("Completed");

// Attribute
await Expect(Page.Locator("[data-testid='submit']")).ToBeEnabledAsync();
await Expect(Page.Locator("[data-testid='email']")).ToHaveValueAsync("user@example.com");

// Page-level
await Expect(Page).ToHaveURLAsync(new Regex("/orders/\\d+"));
await Expect(Page).ToHaveTitleAsync("Order Details - My App");

// Count
await Expect(Page.Locator("[data-testid='order-row']")).ToHaveCountAsync(5);

Network Interception

Mocking API Responses

[Fact]
public async Task OrderList_WithMockedApi_DisplaysOrders()
{
    // Intercept API calls and return mock data
    await Page.RouteAsync("**/api/orders", async route =>
    {
        var json = JsonSerializer.Serialize(new[]
        {
            new { Id = 1, CustomerName = "Alice", Total = 99.99 },
            new { Id = 2, CustomerName = "Bob", Total = 149.50 }
        });
        await route.FulfillAsync(new RouteFulfillOptions
        {
            Status = 200,
            ContentType = "application/json",
            Body = json
        });
    });

    await Page.GotoAsync("https://localhost:5001/orders");

    await Expect(Page.Locator("[data-testid='order-row']")).ToHaveCountAsync(2);
}

Waiting for Network Requests

[Fact]
public async Task CreateOrder_SubmitForm_WaitsForApiResponse()
{
    await Page.GotoAsync("https://localhost:5001/orders/new");

    await Page.FillAsync("[data-testid='customer']", "Alice");
    await Page.FillAsync("[data-testid='amount']", "99.99");

    // Wait for the API call triggered by form submission
    var responseTask = Page.WaitForResponseAsync(
        response => response.Url.Contains("/api/orders") && response.Status == 201);

    await Page.ClickAsync("[data-testid='submit']");

    var response = await responseTask;
    Assert.Equal(201, response.Status);
}

CI Browser Caching

Downloading browser binaries on every CI run is slow (500MB+). Cache them to speed up builds.

GitHub Actions Caching

# .github/workflows/e2e-tests.yml
jobs:
  e2e:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '8.0.x'

      - name: Build
        run: dotnet build tests/MyApp.E2E/

      - name: Cache Playwright browsers
        id: playwright-cache
        uses: actions/cache@v4
        with:
          path: ~/.cache/ms-playwright
          key: playwright-${{ runner.os }}-${{ hashFiles('tests/MyApp.E2E/MyApp.E2E.csproj') }}

      - name: Install Playwright browsers
        if: steps.playwright-cache.outputs.cache-hit != 'true'
        run: pwsh tests/MyApp.E2E/bin/Debug/net8.0/playwright.ps1 install --with-deps

      - name: Install Playwright system deps
        if: steps.playwright-cache.outputs.cache-hit == 'true'
        run: pwsh tests/MyApp.E2E/bin/Debug/net8.0/playwright.ps1 install-deps

      - name: Run E2E tests
        run: dotnet test tests/MyApp.E2E/

Azure DevOps Caching

# azure-pipelines.yml
steps:
  - task: Cache@2
    inputs:
      key: 'playwright | "$(Agent.OS)" | tests/MyApp.E2E/MyApp.E2E.csproj'
      path: $(HOME)/.cache/ms-playwright
      restoreKeys: |
        playwright | "$(Agent.OS)"
      cacheHitVar: PLAYWRIGHT_CACHE_RESTORED
    displayName: Cache Playwright browsers

  - script: pwsh tests/MyApp.E2E/bin/Debug/net8.0/playwright.ps1 install --with-deps
    condition: ne(variables.PLAYWRIGHT_CACHE_RESTORED, 'true')
    displayName: Install Playwright browsers

  - script: pwsh tests/MyApp.E2E/bin/Debug/net8.0/playwright.ps1 install-deps
    condition: eq(variables.PLAYWRIGHT_CACHE_RESTORED, 'true')
    displayName: Install Playwright system deps (cached browsers)

  - script: dotnet test tests/MyApp.E2E/
    displayName: Run E2E tests

Cache Key Strategy

The cache key should include:

  • OS: Browser binaries are platform-specific
  • Project file hash: Playwright version determines browser versions; changing the package version invalidates the cache
  • Fallback key: Allows partial cache restoration when the project file changes

Trace Viewer

Playwright's trace viewer captures a full recording of test execution for debugging failures. Each trace includes screenshots, DOM snapshots, network logs, and console output.

Enabling Traces

public class TracedTests : IAsyncLifetime
{
    private IPlaywright _playwright = null!;
    private IBrowser _browser = null!;
    private IBrowserContext _context = null!;

    public IPage Page { get; private set; } = null!;

    public async ValueTask InitializeAsync()
    {
        _playwright = await Playwright.CreateAsync();
        _browser = await _playwright.Chromium.LaunchAsync();
        _context = await _browser.NewContextAsync();

        // Start tracing before each test
        await _context.Tracing.StartAsync(new TracingStartOptions
        {
            Screenshots = true,
            Snapshots = true,
            Sources = true
        });

        Page = await _context.NewPageAsync();
    }

    public async ValueTask DisposeAsync()
    {
        // Save trace on failure (check test result in xUnit requires custom wrapper)
        await _context.Tracing.StopAsync(new TracingStopOptions
        {
            Path = Path.Combine("test-results", "traces",
                $"trace-{DateTime.UtcNow:yyyyMMdd-HHmmss}.zip")
        });

        await Page.CloseAsync();
        await _context.CloseAsync();
        await _browser.CloseAsync();
        _playwright.Dispose();
    }
}

Viewing Traces

# Open trace file in browser
pwsh bin/Debug/net8.0/playwright.ps1 show-trace test-results/traces/trace-20260101-120000.zip

# Or use the online trace viewer
# Upload the .zip to https://trace.playwright.dev/

Trace on Failure Only

Save traces only when tests fail to reduce storage:

// In a custom test class or middleware
public async Task RunWithTrace(Func<IPage, Task> testAction, string testName)
{
    await _context.Tracing.StartAsync(new TracingStartOptions
    {
        Screenshots = true,
        Snapshots = true,
        Sources = true
    });

    try
    {
        await testAction(Page);
        // Test passed -- discard trace
        await _context.Tracing.StopAsync();
    }
    catch
    {
        // Test failed -- save trace for debugging
        await _context.Tracing.StopAsync(new TracingStopOptions
        {
            Path = $"test-results/traces/{testName}.zip"
        });
        throw;
    }
}

Codegen

Playwright's code generator records browser interactions and generates test code. Use it to scaffold tests quickly, then refine the generated code.

Running Codegen

# Open codegen with your app URL
pwsh bin/Debug/net8.0/playwright.ps1 codegen https://localhost:5001

# With specific browser
pwsh bin/Debug/net8.0/playwright.ps1 codegen --browser firefox https://localhost:5001

# With device emulation
pwsh bin/Debug/net8.0/playwright.ps1 codegen --device "iPhone 15" https://localhost:5001

# With saved authentication state
pwsh bin/Debug/net8.0/playwright.ps1 codegen --save-storage auth.json https://localhost:5001

Codegen Best Practices

  1. Use codegen as a starting point, not the final test. Generated code often uses fragile selectors and lacks proper assertions.
  2. Replace generated selectors with data-testid or role-based locators immediately after generating.
  3. Add meaningful assertions. Codegen records actions but does not know what to verify. Add Expect() calls for expected outcomes.
  4. Extract page objects from generated code. Group related interactions into page object methods.

Before and After Codegen Refinement

// GENERATED by codegen (fragile, no assertions):
await page.GotoAsync("https://localhost:5001/orders");
await page.Locator("#root > div > main > div:nth-child(2) > button").ClickAsync();
await page.GetByPlaceholder("Customer name").FillAsync("Alice");
await page.GetByPlaceholder("Amount").FillAsync("99.99");
await page.Locator("form > button[type='submit']").ClickAsync();

// REFINED (stable selectors, proper assertions):
await Page.GotoAsync("https://localhost:5001/orders");
await Page.ClickAsync("[data-testid='new-order-btn']");
await Page.FillAsync("[data-testid='customer-name']", "Alice");
await Page.FillAsync("[data-testid='amount']", "99.99");
await Page.ClickAsync("[data-testid='submit-order']");

await Expect(Page.Locator("[data-testid='success-toast']"))
    .ToBeVisibleAsync();
await Expect(Page).ToHaveURLAsync(new Regex("/orders/\\d+"));

Multi-Browser Testing

Running Tests Across Browsers

// Using Playwright xUnit base class with environment variable
// Set BROWSER=chromium|firefox|webkit via CLI or CI config
public class CrossBrowserTests : PageTest
{
    [Fact]
    public async Task OrderFlow_WorksAcrossBrowsers()
    {
        // This test runs in whichever browser BROWSER env var specifies
        await Page.GotoAsync("https://localhost:5001/orders/new");
        await Page.FillAsync("[data-testid='customer']", "Alice");
        await Page.ClickAsync("[data-testid='submit']");

        await Expect(Page.Locator("[data-testid='success']")).ToBeVisibleAsync();
    }
}
# Run tests in each browser
BROWSER=chromium dotnet test
BROWSER=firefox dotnet test
BROWSER=webkit dotnet test

CI Matrix Strategy

# GitHub Actions matrix for multi-browser
strategy:
  matrix:
    browser: [chromium, firefox, webkit]
steps:
  - name: Run E2E tests
    run: dotnet test tests/MyApp.E2E/
    env:
      BROWSER: ${{ matrix.browser }}

Key Principles

  • Use Playwright assertions (Expect) instead of raw xUnit Assert. Playwright assertions auto-retry with configurable timeouts, eliminating flaky timing issues.
  • Cache browser binaries in CI. Downloading 500MB+ of browsers per run wastes time and bandwidth. Cache by OS + Playwright version.
  • Enable trace viewer for debugging CI failures. Traces capture everything needed to reproduce a failure without re-running the test.
  • Use codegen to bootstrap tests, then refine. Generated code gets you started fast; manual refinement makes tests maintainable.
  • Prefer role-based or data-testid locators over CSS classes or XPath. See [skill:dotnet-ui-testing-core] for the full selector priority guide.

Agent Gotchas

  1. Do not forget to install browsers after adding the Playwright package. The NuGet package does not include browser binaries. Run the install script after building.
  2. Do not use Task.Delay for waiting. Playwright's auto-waiting and Expect assertions handle timing automatically. Adding delays makes tests slow and still flaky.
  3. Do not hardcode localhost ports. Use configuration or environment variables for the base URL. CI environments may use different ports than local development.
  4. Do not skip --with-deps on first CI install. Playwright browsers need system libraries (libgbm, libasound, etc.) on Linux. The --with-deps flag installs them. Subsequent cached runs only need install-deps.
  5. Do not store trace files in the repository. Traces are large binary files. Write them to a test-results/ directory that is git-ignored, and upload them as CI artifacts.
  6. Do not create a new browser instance per test. Browser launch is expensive. Use IClassFixture or the Playwright xUnit base class to share a browser across tests in a class. Create a new BrowserContext per test for isolation.

References

平台分布

Codex

37.83%
按下载量换算50

Claude

29.72%
按下载量换算39

Cursor

19.59%
按下载量换算26

Gemini CLI

8.73%
按下载量换算12

安全审计

Gen Agent Trust Hub

通过

Socket

未通过

Snyk

通过

权限和风险

操作浏览器

该 Skill 可能涉及浏览器控制能力,使用时可能读取或操作网页内容,需要在受控环境中确认权限边界。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在提醒或未通过项,安装前请自行复核。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills