PlaywrightSwift

1.0.0

Swift version of the Playwright testing and automation library.
vinayjn/playwright-swift

What's New

PlaywrightSwift 1.0.0

2026-01-11T13:54:35Z

🎉 We are excited to announce the first major release of PlaywrightSwift!

This library enables browser automation for Chromium, Firefox, and WebKit using a modern, type-safe Swift API.

🚀 Key Features

  • TypedLocators: Compile-time type safety for element interactions.
  • Swift Macros: Validate selectors (#selector) and create Page Objects (@PageObject) at compile time.
  • Modern Concurrency: Built entirely with Swift 6 structured concurrency (async/await).
  • Cross-Browser Support: Automate Chromium, Firefox, and WebKit with a single API.
  • Auto-Waiting: Interactions automatically wait for elements to be ready.
  • Network Mocking: Intercept and mock network requests and responses.
  • Robust Testing: specific PageTestCase for XCTest integration.
  • Rich Interactions: Click, fill, type, hover, drag-and-drop, and more.
  • Media Handling: visual regression testing with screenshots and video recording.

PlaywrightSwift

A Swift library for browser automation using Playwright. Control Chromium, Firefox, and WebKit browsers with a modern, async/await API.

Requirements

  • macOS 14.0+
  • Swift 6.0+ (uses Swift Macros)

Installation

Add PlaywrightSwift to your Package.swift:

dependencies: [
    .package(url: "https://github.com/vinayjn/playwright-swift.git", from: "1.0.0")
]

Quick Start

Install Browsers

Before running automation, install the browser binaries:

import PlaywrightSwift

try await Playwright.installBrowsers()

Basic Usage

Given this HTML:

<form id="search-form">
  <input type="text" placeholder="Search..." />
  <button type="submit">Search</button>
</form>

Automate it with:

import PlaywrightSwift

// Launch browser
let playwright = try await Playwright.create()
let browser = try await playwright.chromium.launch()

// Create page and navigate
let page = try await browser.newPage()
try await page.goto("https://example.com")

// Interact with elements
try await page.locator("input").fill("Playwright")
try await page.locator("button").click()

// Take a screenshot
try await page.screenshot(options: .init(path: "screenshot.png"))

try await browser.close()

TypedLocators (Type-Safe Element Access)

Given this HTML:

<form id="login">
  <input id="email" type="email" name="email" />
  <input id="password" type="password" name="password" />
  <button id="submit" data-testid="login-btn">Log In</button>
</form>
<nav>
  <a class="nav" href="/dashboard">Dashboard</a>
</nav>

Use TypedLocators for compile-time type safety:

// Create typed locators with element-specific methods
let emailInput = page.input("#email")     // TypedLocator<InputElement>
let submitBtn = page.button("#submit")    // TypedLocator<ButtonElement>
let navLink = page.link("a.nav")          // TypedLocator<LinkElement>

// Type-specific methods only available on correct types
try await emailInput.fill("user@example.com")  // ✅ Works
try await emailInput.clear()                    // ✅ Works
// submitBtn.fill("text")                       // ❌ Won't compile

// Type-safe attribute access
let href = try await navLink.getHref()         // Returns "/dashboard"
let testId = try await submitBtn.getAttribute("data-testid")

Documentation

Learn more about specific features:

Key Features

  • TypedLocators: Phantom types provide compile-time enforcement of element-specific APIs.
  • Swift Macros: Compile-time selector validation with #selector and type-safe Page Objects with @PageObject.
  • Auto-waiting: Locators automatically wait for elements to be ready before acting.
  • Type-safe API: Leverage Swift's type system for browser options and results.
  • Modern Concurrency: Built from the ground up using Swift's async/await.
  • Event Streams: Type-safe AsyncSequence-based event handling for console, requests, responses, dialogs, and downloads.
  • Cross-browser: Support for Chromium, Firefox, and WebKit.
  • Network Mocking: Intercept any network request to mock backend responses.
  • Video & Downloads: Record test execution and manage file downloads.

Type-Safe Selectors

Given this HTML:

<button role="button" name="Submit">Submit Order</button>
<input data-testid="email-input" type="email" />
<a href="/help">Click here for help</a>

Use the Selector enum for type-safe, autocomplete-friendly selectors:

// Role-based selector (matches the <button>)
let button = page.locator(.role(.button, name: "Submit"))

// Test ID selector (matches the <input>)
let input = page.locator(.testId("email-input"))

// Text-based selector (matches the <a>)
let link = page.locator(.text("Click here", exact: false))

Result Builders

Build complex selectors with the locator chain builder:

Given this HTML:

<div data-testid="product-list">
  <li>Samsung Galaxy</li>
  <li>iPhone 15 Pro</li>
  <li>Google Pixel</li>
</div>
// Find the iPhone item within the product list
let item = page.locate {
    LocatorStep.testId("product-list")
    LocatorStep.css("li")
    LocatorStep.filter(hasText: "iPhone")
}

Configure network routes declaratively:

try await page.configureRoutes {
    RouteConfig.mock("**/api/user", with: "{\"name\": \"Test\"}")
    RouteConfig.block("**/*.analytics.js")
    RouteConfig.passthrough("**/*")
}

Wait Conditions

Given this HTML that updates dynamically:

<div id="status">Loading...</div>
<!-- After API call completes, changes to: -->
<div id="status">Success</div>

Wait for specific element states:

let statusDiv = page.locator("#status")

try await statusDiv.waitFor(.visible)
try await statusDiv.waitFor(.hasText("Success"))
try await statusDiv.waitFor(.enabled, timeout: .seconds(10))

Logging & Debugging

Enable detailed logging and protocol tracing for debugging:

// Enable detailed logs
PlaywrightLogger.level = .debug

// Enable verbose protocol tracing
ProtocolTracer.shared.isEnabled = true
ProtocolTracer.shared.methodFilter = "goto" // Optional filter

Testing Support

Use PageTestCase for XCTest integration:

import PlaywrightSwift
import XCTest

class MyAppTests: PageTestCase {
    func testLogin() async throws {
        try await page.goto("https://app.example.com")
        // ...
    }
}

License

MIT License - see LICENSE for details.

Description

  • Swift Tools 6.2.0
View More Packages from this Author

Dependencies

Last updated: Thu Apr 09 2026 09:31:54 GMT-0900 (Hawaii-Aleutian Daylight Time)