Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions .github/workflows/kitesurf.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
name: Kitesurf Helper Tests

on:
push:
branches:
- 4.x
pull_request:
branches:
- '**'

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

permissions:
contents: read

env:
CI: true
FORCE_COLOR: 1
KITESURF_VERSION: 2026.11.9
KITESURF_ENDPOINT: http://127.0.0.1:8787

jobs:
build:
runs-on: ubuntu-24.04
timeout-minutes: 90

steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- name: Checkout Kitesurf
uses: actions/checkout@v6
with:
repository: cloudflare/kitesurf
ref: ${{ env.KITESURF_VERSION }}
path: kitesurf
persist-credentials: false
- name: Use Node.js
uses: actions/setup-node@v6
with:
node-version-file: '.nvmrc'
- uses: pnpm/action-setup@v4
with:
version: 9.15.4
run_install: false
- uses: shivammathur/setup-php@v2
with:
php-version: 8.0
- name: npm install
run: npm i --force
- name: Install Kitesurf dependencies
working-directory: kitesurf
run: pnpm install --frozen-lockfile
- name: Cache Kitesurf build
id: kitesurf-build
uses: actions/cache@v6
with:
path: |
kitesurf/packages/core/pkg
kitesurf/packages/renderer-core/pkg
kitesurf/packages/engine/public/rbi
kitesurf/packages/dom-shim/dist
kitesurf/packages/page-script/dist
kitesurf/packages/page-renderer/dist
kitesurf/packages/worker-script/dist
key: kitesurf-build-${{ env.KITESURF_VERSION }}-x86_64-linux
- name: Build Kitesurf
if: steps.kitesurf-build.outputs.cache-hit != 'true'
working-directory: kitesurf
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /usr/local/.ghcup /opt/hostedtoolcache/CodeQL
bazel run //packages/engine:dev_build
- name: start Kitesurf
working-directory: kitesurf/packages/engine
run: |
npx wrangler dev --env local -c wrangler.jsonc -c test/fixtures-worker/wrangler.jsonc --port 8787 > ~/kitesurf.log 2>&1 &
for i in $(seq 1 90); do curl -sf http://127.0.0.1:8787/health && break; sleep 2; done
curl -sf http://127.0.0.1:8787/json/version
- name: start test server
run: |
php -S 127.0.0.1:8000 -t test/data/app &
sleep 1
curl -sf http://127.0.0.1:8000/info > /dev/null
- name: run kitesurf helper tests
run: npm run test:unit:webbapi:kitesurf
- name: run kitesurf acceptance tests
run: ./bin/codecept.js run -c test/acceptance/codecept.Kitesurf.js --grep @Kitesurf --debug
- name: Kitesurf log
if: failure()
run: tail -200 ~/kitesurf.log
2 changes: 1 addition & 1 deletion Bunoshfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ const inheritedHelperDocs = {
Obscura: { parent: 'CDPBrowser' },
Lightpanda: { parent: 'CDPBrowser' },
Moli: { parent: 'CDPBrowser' },
Kitesurf: { parent: 'CDPBrowser', excludeConfig: ['endpoint', 'headers'] },
Kitesurf: { parent: 'CDPBrowser' },
}

const abstractHelpers = ['CDPBrowser']
Expand Down
51 changes: 44 additions & 7 deletions docs/alternative-browsers.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ title: Alternative Browser Engines
The `Obscura`, `Lightpanda`, `Moli` and `Kitesurf` helpers are experimental. Keep a Playwright or WebDriver job for compatibility-critical tests.
:::

Playwright drives full Chromium, Firefox and WebKit: the most accurate way to test what users see, at the cost of a heavy browser per worker. Alternative engines trade part of that accuracy for speed, a small footprint, or cloud scale. They are a good fit for functional tests (text appears, form submits, redirect happens, cookie is set) and a poor one for anything visual.
Playwright drives full Chromium, Firefox and WebKit: the most accurate way to test what users see, at the cost of a heavy browser per worker. Alternative engines trade part of that accuracy for speed, a small footprint, or cloud scale. Obscura, Lightpanda, Moli and Kitesurf are open source and run on your machine; Kitesurf also runs in Cloudflare's cloud. They are a good fit for functional tests (text appears, form submits, redirect happens, cookie is set) and a poor one for anything visual.

Your tests do not change. `I.amOnPage`, `I.click`, `I.fillField`, `I.see`, `I.seeElement` and the rest of the `I.*` web API work the same; you only swap the helper in the config. All engines below speak Chrome DevTools Protocol, so there is no `npx playwright install` step.

Expand Down Expand Up @@ -200,14 +200,53 @@ All options: [Moli helper reference](/helpers/moli).

## Kitesurf

[Kitesurf](https://blog.cloudflare.com/kitesurf/) is Cloudflare's browser running on Cloudflare Workers, with a real layout and rendering pipeline. Sessions start in about a second and nothing runs on your machine, so the number of parallel browsers is limited only by how far your suite splits.
[Kitesurf](https://github.com/cloudflare/kitesurf) is Cloudflare's open-source browser engine built on Cloudflare Workers, with real layout and rendering: screenshots and the `screencast` plugin work. Run it locally for development and CI, or use it in the cloud through Cloudflare Browser Run, where sessions start in about a second and the number of parallel browsers is limited only by how far your suite splits.

Page JavaScript runs in Boa, a JavaScript engine written in Rust, not V8, so some libraries fail to start.

Kitesurf starts a fresh isolated worker for every page, so each navigation costs about 200 ms on a local engine. A suite runs about 4 times slower than on Lightpanda, Moli or Obscura, close to Playwright. In exchange, it is the only engine here with real layout and screenshots.

Limitations:

- Cloud only, currently a free beta.
- The browser cannot reach `localhost`: test a deployed environment or expose your app with a tunnel such as `cloudflared tunnel --url http://localhost:3000`.
- `attachFile` does not upload files.
- Clipboard actions do not work: pages are never a secure context, even on `localhost`.
- A click can hit the wrong element when a child overflows a container with `overflow: hidden`.
- Rich text editors Quill, Trix and ACE do not work; TinyMCE does not start on a pre-filled element.
- A Base UI radio group does not uncheck the previously selected radio.
- Links compute `cursor: auto` instead of `pointer`.

### Setup
### Local engine

Build and start the engine following the [Kitesurf README](https://github.com/cloudflare/kitesurf#run-locally). It listens on `http://127.0.0.1:8787`. Point the helper at it with `endpoint`; the helper connects but never starts or stops the engine:

```js
// codecept.conf.js
export const config = {
helpers: {
Kitesurf: {
url: 'http://localhost:3000',
endpoint: 'http://127.0.0.1:8787',
},
},
}
```

The same `endpoint` works for an engine you deploy to your own Cloudflare account. If it sits behind Cloudflare Access, pass the service token in `headers`:

```js
Kitesurf: {
url: 'https://staging.myapp.com',
endpoint: 'https://kitesurf.example.com',
headers: {
'CF-Access-Client-Id': process.env.CF_ACCESS_CLIENT_ID,
'CF-Access-Client-Secret': process.env.CF_ACCESS_CLIENT_SECRET,
},
}
```

### Cloudflare Browser Run

Without `endpoint`, the helper opens a Kitesurf session in Cloudflare Browser Run, currently a free beta. A cloud browser cannot reach `localhost`: test a deployed environment or expose your app with a tunnel such as `cloudflared tunnel --url http://localhost:3000`.

Enable [Cloudflare Browser Run](https://developers.cloudflare.com/browser-run/) and create an API token with the **Browser Rendering → Edit** permission. Export the credentials:

Expand All @@ -229,8 +268,6 @@ export const config = {
}
```

### Usage

Every worker opens its own cloud session:

```sh
Expand Down
Loading
Loading