Skip to content

feat(browser): support Locator and Assertion#948

Merged
fi3ework merged 7 commits intomainfrom
locator
Mar 3, 2026
Merged

feat(browser): support Locator and Assertion#948
fi3ework merged 7 commits intomainfrom
locator

Conversation

@fi3ework
Copy link
Copy Markdown
Member

@fi3ework fi3ework commented Feb 6, 2026

This PR adds a native Playwright-style Locator query + action + assertion API to Rstest browser mode. The core design uses an IR (Intermediate Representation) + RPC + Provider abstraction architecture, ensuring future extensibility to multiple browser drivers without changing test code.

User API (Playwright-style surface)

import { page } from "@rstest/browser";
import { expect, test } from "@rstest/core";

test("login", async () => {
  await page.getByRole("textbox", { name: "Username" }).fill("alice");
  await page.getByLabel("Password").fill("123456");
  await page.getByRole("button", { name: "Sign in" }).click();

  await expect.element(page.getByText("Welcome")).toBeVisible();
});

Design goal: zero learning curve for users already familiar with Playwright.

Core Architecture: IR-Driven Client/Host Communication

┌─────────────────────────── Browser (iframe) ───────────────────────────┐
│                                                                        │
│  Test Code                                                             │
│    │  page.getByRole("button", { name: "Save" }).click()               │
│    ▼                                                                   │
│  Locator Class ─── does NOT query DOM directly; builds IR instead ──── │
│    │  IR = { steps: [{ type: "getByRole", role: "button", ... }] }     │
│    ▼                                                                   │
│  browserRpc ─── serializes IR + method + args into BrowserRpcRequest ─ │
│    │                                                                   │
└────┼───────────────────────────────────────────────────────────────────┘
     │  postMessage / page.exposeFunction bridge
     ▼
┌─────────────────────────── Host (Node.js) ─────────────────────────────┐
│                                                                        │
│  DispatchRouter ─── namespace routing (transport-agnostic)             │
│    │                                                                   │
│    ▼                                                                   │
│  BrowserRpcRegistry ─── API allowlist + provider dispatch              │
│    │                                                                   │
│    ▼                                                                   │
│  Provider: Playwright                                                  │
│    ├── compileLocator(IR) ─── IR → real Playwright Locator chain       │
│    └── dispatchBrowserRpc  ─── execute action / _expect() assertion    │
│         │                                                              │
│         ▼                                                              │
│    Playwright Page/Locator ─── native execution                        │
│                                                                        │
└────────────────────────────────────────────────────────────────────────┘
     │  result / error
     ▼
  Browser-side resolve/reject → test case gets the result

Why IR?

  • The browser runner (iframe) and the host (Node.js + Playwright) are naturally isolated — locator descriptions must be serializable for cross-process transport
  • IR decouples the locator description from the provider implementation — the same IR can be compiled into native calls by different providers
  • A serializable step list enables tracing, debugging, and potential record/replay in the future

Provider Abstraction: Multi-Provider Architecture

A BrowserProviderImplementation interface is introduced:

type BrowserProviderImplementation = {
  name: BrowserProvider;
  launchRuntime: (input: LaunchBrowserInput) => Promise<BrowserProviderRuntime>;
  dispatchRpc: (input: DispatchBrowserRpcInput) => Promise<unknown>;
};

A structural type BrowserProviderPage (a subset mirror of Playwright's Page) is also defined to avoid leaking Playwright types into the framework core. Adding a new provider (e.g., WebDriver BiDi) only requires implementing this interface and registering it in the providerImplementations map — no changes needed on the test-side API.

Current Playwright Provider Support

Category Supported APIs
Locator Queries getByRole, getByText, getByLabel, getByPlaceholder, getByAltText, getByTitle, getByTestId, locator(css)
Locator Composition filter({ has, hasNot, hasText, hasNotText }), and(), or(), nth(), first(), last()
Locator Actions click, dblclick, fill, hover, press, clear, check, uncheck, focus, blur, scrollIntoViewIfNeeded, waitFor, dispatchEvent, selectOption, setInputFiles
Element Assertions toBeVisible, toBeHidden, toBeEnabled, toBeDisabled, toBeChecked, toBeUnchecked, toBeAttached, toBeDetached, toBeEditable, toBeFocused, toBeEmpty, toBeInViewport, toHaveText, toContainText, toHaveValue, toHaveId, toHaveAttribute, toHaveClass, toHaveCount, toHaveCSS, toHaveJSProperty
Configuration setTestIdAttribute

Key Code Locations

Browser side (build IR + send RPC):

  • browser/src/client/locator.ts — Locator class, chained step/IR generation
  • browser/src/rpcProtocol.ts — IR type definitions (serialization protocol core)
  • browser/src/client/browserRpc.ts — RPC transport
  • browser/src/client/api.tsexpect.element / page entry points
  • browser/src/augmentExpect.ts — expect type augmentation

Host/Provider side (routing + compilation + execution):

  • browser/src/providers/index.ts — provider abstraction and registration
  • browser/src/browserRpcRegistry.ts — supported API registry (single source of truth)
  • browser/src/providers/playwright/compileLocator.ts — IR → Playwright Locator
  • browser/src/providers/playwright/dispatchBrowserRpc.ts — action/assertion execution

Compatibility

  • Purely additive capability; does not affect existing tests
  • Reuses existing dispatch envelope channel (dispatchRouter + namespace) — no protocol bloat

Checklist

  • Tests updated (or not required).
  • Documentation updated (or not required).

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages bot commented Feb 10, 2026

Deploying rstest with  Cloudflare Pages  Cloudflare Pages

Latest commit: 7767da5
Status: ✅  Deploy successful!
Preview URL: https://cb900432.rstest.pages.dev
Branch Preview URL: https://locator.rstest.pages.dev

View logs

@fi3ework fi3ework changed the title feat: natively support Playwright style locator sutie feat(browser): support Locator and Assersion Feb 11, 2026
@fi3ework fi3ework changed the title feat(browser): support Locator and Assersion feat(browser): support Locator and Assertion Feb 11, 2026
@fi3ework fi3ework force-pushed the locator branch 8 times, most recently from 7d936df to d4a1e8d Compare February 28, 2026 08:17
@fi3ework fi3ework marked this pull request as ready for review March 2, 2026 03:25
@fi3ework fi3ework requested a review from 9aoy March 2, 2026 03:25
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8c76865faf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@fi3ework fi3ework merged commit aa4f4fd into main Mar 3, 2026
10 checks passed
@fi3ework fi3ework deleted the locator branch March 3, 2026 08:57
@fi3ework fi3ework mentioned this pull request Mar 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants