Playwright PHP

repository·main·Indexed 42 days ago

https://github.com/playwright-php/playwright

A PHP library for automating Chromium, Firefox, and WebKit browsers. Designed for browser testing, web scraping, and automated workflows, it provides a locator-based API, auto-waiting interactions, and integration with PHPUnit 10.0+ via the PlaywrightTestCaseTrait. Includes tools for network mocking with route(), handling JavaScript dialogs, interacting with iframes, and managing authentication state with storageState.

Tokens
17K
Snippets
56
Records
65
Agent score
53%

What's inside Playwright PHP

  1. Reuse authentication state with storageState

    main

    You can save the authentication state (cookies, local storage, etc.) of a context to a JSON file and reuse it in subsequent sessions to bypass login flows.

    // Save state
    $context->storageState(__DIR__.'/state.json');
    
    // Reuse state in a new context
    $ctx = Playwright::chromium([
      'context' => ['storageState' => __DIR__.'/state.json'],
    ]);
  2. Modify assertion behavior with `.not()`, `.withTimeout()`, and `.withPollInterval()`

    main

    You can chain modifier methods to expect() to change how assertions behave:

    • .not(): Negates the assertion that follows. Use this to assert that a condition is not met.
    • .withTimeout(int $milliseconds): Overrides the default 5-second assertion timeout. Use this for elements that take longer to appear or change.
    • .withPollInterval(int $milliseconds): Overrides the default 100ms polling interval for the next assertion.
    // Assert that an element is not visible
    expect($this->page->locator('.loading-spinner'))->not()->toBeVisible();
    
    // Assert that a checkbox is not checked
    expect($this->page->locator('#terms-and-conditions'))->not()->toBeChecked();
    
    // Wait up to 10 seconds for the success message to appear
    expect($this->page->locator('.success-message'))
        ->withTimeout(10000)
        ->toBeVisible();
  3. How Browser, BrowserContext, Page, and Locator work together

    main

    Playwright's architecture is built on a hierarchy of four main objects that manage the lifecycle of a browser session and interaction with web content:

    1. Browser: Represents a single browser process (e.g., Chromium, Firefox, or WebKit). You typically launch one browser for a test suite.
    2. BrowserContext: An isolated, incognito-like session within a Browser. Each context has its own cookies, local storage, and cache. This allows for running independent tests in parallel without state leakage.
    3. Page: A single tab within a BrowserContext. This is the primary interface for navigating and interacting with web content.
    4. Locator: A 'recipe' for finding elements on a Page. Locators use auto-waiting to ensure elements are actionable (visible, enabled, etc.) before performing actions, which reduces test flakiness.
    <?php
    use Playwright// Playwright static class is the easiest way to get started.
    // This launches a Chromium browser and returns a default BrowserContext.
    $context = Playwright::chromium(['headless' => false]);
    
    // Create a new page in the context.
    $page = $context->newPage();
    
    // Use a locator to interact with the page.
    $searchInput = $page->locator('#search-input');
    $searchInput->fill('Playwright for PHP');
    
    $context->close();
  4. Reuse authentication state across tests (Recommended)

    main

    To make your test suite faster and more stable, avoid logging in before every test. Instead, use the Reusing Authentication State strategy:

    1. Save State: Run a standalone script that performs the login once and uses $context->saveStorageState($path) to save cookies and local storage to a JSON file.
    2. Load State: In your test setup (e.g., by overriding setUp() in a base test class), use $this->context->loadStorageState($path) to inject that state into the browser context before the test begins.

    This allows your tests to start directly on authenticated pages without repeating the login UI interactions.

  5. Playwright PHP Quick Start Guide

    main

    The Playwright PHP Quick Start Guide provides a roadmap for learning the library, covering everything from initial setup to advanced testing patterns. You can navigate through the following core topics:

    • Getting Started: Initial setup and first steps.
    • Browsers, Browser Types, and Channels: Understanding how to manage and select different browser engines.
    • Core Concepts: Fundamental abstractions like Pages, Contexts, and Locators.
    • Handling Authentication: Strategies for managing user sessions and login states.
    • Testing with PHPUnit: Integrating Playwright with the PHPUnit testing framework.
    • Assertions Reference: Using Playwright's assertion library for web testing.
    • Advanced Recipes: Complex automation patterns and solutions.
  6. Using `expect()` for assertions

    main

    Playwright for PHP uses the expect() function to perform assertions on either a Locator or a Page object. A core feature is auto-waiting: Playwright automatically waits for the condition to be met before failing, which helps prevent flaky tests.

    To use it, import Playwright\Testing\expect and pass your target object to the function.

    use function Playwright\Testing\expect;
    
    // Make an assertion about a locator
    expect($this->page->locator('h1'))->toHaveText('Welcome!');
    
    // Make an assertion about the page
    expect($this->page)->toHaveURL('https://my-app.com/dashboard');
  7. Connect to Chromium via Chrome DevTools Protocol (CDP)

    main

    If you have an existing instance of Chrome or Chromium running with remote debugging enabled, you can connect to it using connectOverCDP(). This is only supported for Chromium-based browsers.

    1. Start Chrome with remote debugging

    Launch your browser with the --remote-debugging-port flag. For example, on macOS:

    "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-pw

    2. Connect with connectOverCDP()

    Pass the debugging URL (e.g., http://127.0.0.1:9222) to the connectOverCDP() method.

    <?php
    
    require __DIR__.'/vendor/autoload.php';
    
    use Playwright\PlaywrightFactory;
    
    $playwright = PlaywrightFactory::create();
    $cdpEndpoint = getenv('CDP_ENDPOINT') ?: 'http://127.0.0.1:9222';
    
    $browser = $playwright->chromium()->connectOverCDP($cdpEndpoint);
    $context = $browser->newContext();
    $page = $context->newPage();
    $page->goto('https://example.com');
    
    echo $page->title().PHP_EOL;
    
    $browser->close();
    $playwright->close();
  8. Configure Playwright in GitHub Actions

    main

    When running tests in GitHub Actions, ensure you install Node.js 20+, run composer install, and use vendor/bin/playwright-install --with-deps to set up the environment.

    jobs:
      tests:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
    
          - uses: shivammathur/setup-php@v2
            with:
              php-version: '8.2'
    
          - uses: actions/setup-node@v4
            with:
              node-version: '20'
    
          - run: composer install --no-interaction --prefer-dist
    
          # Install browsers for Playwright PHP
          - run: vendor/bin/playwright-install --with-deps
    
          - run: vendor/bin/phpunit --colors=always
  9. Install Playwright PHP

    main

    To use Playwright PHP in your project, first add the library via Composer. Then, you must install the required browser binaries (Chromium, Firefox, WebKit) using the provided installation script.

    # Add the library
    composer require --dev playwright-php/playwright
    
    # Install all browsers
    vendor/bin/playwright-install --browsers
  10. Handle JavaScript dialogs (alert, confirm, prompt)

    main

    To handle JavaScript dialogs, listen for the dialog event on the page's event system using $page->events()->onDialog(). Inside the callback, you can inspect the dialog message with $dialog->message() and interact with it using $dialog->accept() (to confirm) or $dialog->dismiss() (to cancel).

    // Listen for the next dialog that appears
    $this->page->events()->onDialog(function ($dialog) {
        // Assert the dialog message is correct
        $this->assertSame('Are you sure you want to delete this item?', $dialog->message());
    
        // Accept the dialog
        $dialog->accept();
    });
    
    // Perform the action that triggers the dialog
    $this->page->locator('#delete-item-button')->click();
  11. Perform UI Login for testing authentication flows

    main

    If you need to specifically test the login, logout, or password-reset functionality of your application, you should perform a manual UI login within your test. This involves navigating to the login page, interacting with the form elements (e.g., using fill() and click()), and asserting the result of the login action.

    Note: This approach is slower and should not be used for every test in a large suite, as it adds significant overhead to each test case.

    public function testUserCanLogIn(): void
    {
        $this->page->goto('https://my-app.com/login');
    
        $this->page->locator('#username')->fill('test-user');
        $this->page->locator('#password')->fill('password123');
        $this->page->locator('button[type="submit"]')->click();
    
        // Assert that the user is redirected to the dashboard
        expect($this->page)->toHaveURL('https://my-app.com/dashboard');
    }
  12. Launch a browser and create a context

    main

    You can use the Playwright::chromium() method to launch a Chromium browser instance. This method returns a BrowserContext directly, which is the easiest way to get started. To manage multiple isolated sessions, you can access the Browser object from a context and call newContext() on it.

    <?php
    use Playwright// Launches Chromium and returns a default BrowserContext.
    $context = Playwright::chromium(['headless' => false]);
    
    // Access the underlying browser to create a second, isolated context.
    $browser = $context->browser();
    $adminContext = $browser->newContext();
    
    $context->close();