# `Playwriter`
[🔗](https://github.com/nshkrdotcom/playwriter/blob/v0.1.0/lib/playwriter.ex#L1)

Cross-platform browser automation with WSL-to-Windows support.

Playwriter provides a simple, composable API for browser automation,
with special support for running in WSL while controlling a visible
browser on Windows.

## Quick Start

    # Fetch HTML from a URL (headless)
    {:ok, html} = Playwriter.fetch_html("https://example.com")

    # Fetch with visible browser on Windows
    {:ok, html} = Playwriter.fetch_html("https://example.com",
      mode: :remote,
      ws_endpoint: "ws://localhost:3337/"
    )

    # Take a screenshot
    {:ok, png_data} = Playwriter.screenshot("https://example.com")
    File.write!("screenshot.png", png_data)

    # Full control with session
    {:ok, result} = Playwriter.with_browser(headless: true, fn ctx ->
      Playwriter.goto(ctx, "https://example.com")
      Playwriter.click(ctx, "button.accept")
      Playwriter.content(ctx)
    end)

## Transport Modes

- `:local` - Uses playwright_ex with local browser (default)
- `:windows` - Runs Playwright on Windows via PowerShell (WSL only, no server needed!)
- `:remote` - Connects to a Playwright server via WebSocket
- `:auto` - Auto-detects best transport

## WSL-to-Windows Integration

**Recommended: Use `:windows` mode** (no server setup required):

    Playwriter.fetch_html("https://example.com", mode: :windows)

This runs Playwright directly on Windows via PowerShell, bypassing WSL networking.
Requires playwright to be installed in `%TEMP%\playwriter-server` on Windows.

**Alternative: Remote server mode** (requires running server):

1. Start the Playwright server on Windows:

       powershell.exe -ExecutionPolicy Bypass -File priv/scripts/start_server.ps1

2. Connect from your Elixir code:

       Playwriter.fetch_html("https://example.com",
         mode: :remote,
         ws_endpoint: "ws://localhost:3337/"
       )

# `context`

```elixir
@type context() :: %{session: pid(), page: String.t()}
```

# `result`

```elixir
@type result() :: {:ok, term()} | {:error, term()}
```

# `click`

```elixir
@spec click(context(), String.t(), keyword()) :: :ok | {:error, term()}
```

Click an element.

Use inside `with_browser/2` callback.

## Examples

    Playwriter.with_browser(fn ctx ->
      Playwriter.goto(ctx, "https://example.com")
      :ok = Playwriter.click(ctx, "button.submit")
    end)

# `content`

```elixir
@spec content(context()) :: {:ok, String.t()} | {:error, term()}
```

Get page HTML content.

Use inside `with_browser/2` callback.

# `fetch_html`

```elixir
@spec fetch_html(
  String.t(),
  keyword()
) :: {:ok, String.t()} | {:error, term()}
```

Fetch HTML content from a URL.

This is a convenience wrapper around `with_browser/2`.

## Options

All options from `with_browser/2` plus:

- `:timeout` - Navigation timeout in ms (default: 30000)
- `:wait_until` - When to consider navigation complete

## Examples

    {:ok, html} = Playwriter.fetch_html("https://example.com")

    {:ok, html} = Playwriter.fetch_html("https://example.com",
      mode: :remote,
      ws_endpoint: "ws://localhost:3337/"
    )

# `fill`

```elixir
@spec fill(context(), String.t(), String.t(), keyword()) :: :ok | {:error, term()}
```

Fill an input field.

Use inside `with_browser/2` callback.

## Examples

    Playwriter.with_browser(fn ctx ->
      Playwriter.goto(ctx, "https://example.com/login")
      :ok = Playwriter.fill(ctx, "input[name=email]", "test@example.com")
      :ok = Playwriter.fill(ctx, "input[name=password]", "secret123")
      :ok = Playwriter.click(ctx, "button[type=submit]")
    end)

# `goto`

```elixir
@spec goto(context(), String.t(), keyword()) :: :ok | {:error, term()}
```

Navigate to a URL.

Use inside `with_browser/2` callback.

## Examples

    Playwriter.with_browser(fn ctx ->
      :ok = Playwriter.goto(ctx, "https://example.com")
      # ...
    end)

# `screenshot`

```elixir
@spec screenshot(
  String.t(),
  keyword()
) :: {:ok, binary()} | {:error, term()}
```

Take a screenshot of a URL.

Returns the screenshot as PNG binary data.

## Options

All options from `with_browser/2` plus:

- `:full_page` - Capture entire scrollable page (default: false)
- `:omit_background` - Transparent background (default: false)

## Examples

    {:ok, png} = Playwriter.screenshot("https://example.com")
    File.write!("screenshot.png", png)

    {:ok, png} = Playwriter.screenshot("https://example.com", full_page: true)

# `take_screenshot`

```elixir
@spec take_screenshot(
  context(),
  keyword()
) :: {:ok, binary()} | {:error, term()}
```

Take a screenshot of the current page.

Use inside `with_browser/2` callback.

## Options

- `:full_page` - Capture entire scrollable page (default: false)
- `:omit_background` - Transparent background (default: false)

## Examples

    Playwriter.with_browser(fn ctx ->
      Playwriter.goto(ctx, "https://example.com")
      {:ok, png} = Playwriter.take_screenshot(ctx)
      File.write!("screenshot.png", png)
    end)

# `version`

```elixir
@spec version() :: String.t()
```

Returns the library version.

# `with_browser`

```elixir
@spec with_browser(
  keyword(),
  (context() -&gt; term())
) :: result()
```

Execute a function with a browser session.

The function receives a context map with `:session` and `:page` keys.
Session and page are automatically created and cleaned up.

## Options

- `:mode` - `:local`, `:remote`, or `:auto` (default: `:auto`)
- `:ws_endpoint` - WebSocket URL for remote mode
- `:headless` - Run browser in headless mode (default: true)
- `:browser_type` - `:chromium`, `:firefox`, or `:webkit` (default: `:chromium`)

## Examples

    {:ok, html} = Playwriter.with_browser(headless: true, fn ctx ->
      Playwriter.goto(ctx, "https://example.com")
      Playwriter.content(ctx)
    end)

    # With visible Windows browser
    {:ok, html} = Playwriter.with_browser(mode: :remote, fn ctx ->
      Playwriter.goto(ctx, "https://example.com")
      Playwriter.click(ctx, "#accept-cookies")
      Playwriter.content(ctx)
    end)

---

*Consult [api-reference.md](api-reference.md) for complete listing*
