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
1 change: 1 addition & 0 deletions .agents/skills/implement-playwright-method/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,4 +169,5 @@ Implement the method in the `make` function of the implementation class (e.g., `
### 6. Verify

- Ensure types match `PlaywrightXService`.
- Run `pnpm exec biome check --write .` to ensure code style and lint rules are followed.
- Run `pnpm type-check` and `pnpm test` to verify implementation.
1 change: 1 addition & 0 deletions .agents/skills/upgrade-playwright/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ pnpm exec playwright install

### 6. Verification

- Run `pnpm exec biome check --write .` to ensure code style and lint rules are followed.
- Run `pnpm type-check`.
- Run `pnpm test` to ensure no regressions.
- Ensure no temporary files remain
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
],
"packageManager": "pnpm@10.27.0",
"dependencies": {
"playwright-core": "^1.59.1"
"playwright-core": "^1.60.0"
},
"peerDependencies": {
"@effect/platform": "^0.93.3",
Expand All @@ -54,7 +54,7 @@
"@effect/vitest": "^0.29.0",
"@types/node": "^25.6.1",
"effect": "^3.21.2",
"playwright": "^1.59.1",
"playwright": "^1.60.0",
"ts-morph": "^28.0.0",
"tsdown": "0.22.0",
"tsx": "^4.21.0",
Expand Down
22 changes: 11 additions & 11 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 36 additions & 0 deletions src/browser-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import type {
BrowserContext,
ConsoleMessage,
Dialog,
Download,
Frame,
Page,
Request,
Response,
Expand All @@ -13,21 +15,31 @@ import { PlaywrightBrowser, type PlaywrightBrowserService } from "./browser";
import { PlaywrightClock, type PlaywrightClockService } from "./clock";
import {
PlaywrightDialog,
PlaywrightDownload,
PlaywrightRequest,
PlaywrightResponse,
PlaywrightWorker,
} from "./common";
import type { PlaywrightError } from "./errors";
import { PlaywrightFrame } from "./frame";
import { PlaywrightPage } from "./page";
import type { PatchedEvents } from "./playwright-types";
import { PlaywrightTracing, type PlaywrightTracingService } from "./tracing";
import { useHelper } from "./utils";

interface BrowserContextEvents {
/** @deprecated Since Playwright 1.56.0. This event is no longer emitted. */
backgroundpage: Page;
close: BrowserContext;
console: ConsoleMessage;
dialog: Dialog;
download: Download;
frameattached: Frame;
framedetached: Frame;
framenavigated: Frame;
page: Page;
pageclose: Page;
pageload: Page;
request: Request;
requestfailed: Request;
requestfinished: Request;
Expand All @@ -41,7 +53,13 @@ const eventMappings = {
close: (context: BrowserContext) => PlaywrightBrowserContext.make(context),
console: identity<ConsoleMessage>,
dialog: (dialog: Dialog) => PlaywrightDialog.make(dialog),
download: (download: Download) => PlaywrightDownload.make(download),
frameattached: (frame: Frame) => PlaywrightFrame.make(frame),
framedetached: (frame: Frame) => PlaywrightFrame.make(frame),
framenavigated: (frame: Frame) => PlaywrightFrame.make(frame),
page: (page: Page) => PlaywrightPage.make(page),
pageclose: (page: Page) => PlaywrightPage.make(page),
pageload: (page: Page) => PlaywrightPage.make(page),
request: (request: Request) => PlaywrightRequest.make(request),
requestfailed: (request: Request) => PlaywrightRequest.make(request),
requestfinished: (request: Request) => PlaywrightRequest.make(request),
Expand All @@ -64,6 +82,12 @@ export interface PlaywrightBrowserContextService {
* Access the clock.
*/
readonly clock: PlaywrightClockService;
/**
* Access the tracing.
*
* @since 0.5.0
*/
readonly tracing: PlaywrightTracingService;
/**
* Returns the list of all open pages in the browser context.
*
Expand Down Expand Up @@ -214,6 +238,16 @@ export interface PlaywrightBrowserContextService {
*/
readonly setDefaultTimeout: (timeout: number) => void;

/**
* Sets the storage state for the browser context.
*
* @see {@link BrowserContext.setStorageState}
* @since 0.5.0
*/
readonly setStorageState: (
options: Parameters<BrowserContext["setStorageState"]>[0],
) => Effect.Effect<void, PlaywrightError>;

/**
* Creates a stream of the given event from the browser context.
*
Expand Down Expand Up @@ -249,6 +283,7 @@ export class PlaywrightBrowserContext extends Context.Tag(
const use = useHelper(context);
return PlaywrightBrowserContext.of({
clock: PlaywrightClock.make(context.clock),
tracing: PlaywrightTracing.make(context.tracing),
pages: () => context.pages().map(PlaywrightPage.make),
newPage: use((c) => c.newPage().then(PlaywrightPage.make)),
close: use((c) => c.close()),
Expand All @@ -271,6 +306,7 @@ export class PlaywrightBrowserContext extends Context.Tag(
setDefaultNavigationTimeout: (timeout) =>
context.setDefaultNavigationTimeout(timeout),
setDefaultTimeout: (timeout) => context.setDefaultTimeout(timeout),
setStorageState: (options) => use((c) => c.setStorageState(options)),
eventStream: <K extends keyof BrowserContextEvents>(event: K) =>
Stream.asyncPush<BrowserContextEvents[K]>((emit) =>
Effect.acquireRelease(
Expand Down
30 changes: 29 additions & 1 deletion src/browser.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { Context, Effect, Stream } from "effect";
import type { Scope } from "effect/Scope";
import type { Browser, BrowserType, chromium } from "playwright-core";
import type {
Browser,
BrowserContext,
BrowserType,
chromium,
} from "playwright-core";
import { PlaywrightBrowserContext } from "./browser-context";
import type { PlaywrightError } from "./errors";
import { PlaywrightPage } from "./page";
Expand All @@ -13,10 +18,12 @@ export type NewContextOptions = Parameters<Browser["newContext"]>[0];

interface BrowserEvents {
disconnected: Browser;
context: BrowserContext;
}

const eventMappings = {
disconnected: (browser: Browser) => PlaywrightBrowser.make(browser),
context: (context: BrowserContext) => PlaywrightBrowserContext.make(context),
} as const;

type BrowserWithPatchedEvents = PatchedEvents<Browser, BrowserEvents>;
Expand Down Expand Up @@ -94,6 +101,25 @@ export interface PlaywrightBrowserService {
*/
readonly isConnected: () => boolean;

/**
* Binds the browser to a title.
*
* @see {@link Browser.bind}
* @since 0.5.0
*/
readonly bind: (
title: string,
options?: Parameters<Browser["bind"]>[1],
) => Effect.Effect<{ endpoint: string }, PlaywrightError>;

/**
* Unbinds the browser.
*
* @see {@link Browser.unbind}
* @since 0.5.0
*/
readonly unbind: Effect.Effect<void, PlaywrightError>;

/**
* Creates a stream of the given event from the browser.
*
Expand Down Expand Up @@ -138,6 +164,8 @@ export class PlaywrightBrowser extends Context.Tag(
browserType: () => browser.browserType(),
version: () => browser.version(),
isConnected: () => browser.isConnected(),
bind: (title, options) => use((browser) => browser.bind(title, options)),
unbind: use((browser) => browser.unbind()),
eventStream: <K extends keyof BrowserEvents>(event: K) =>
Stream.asyncPush<BrowserEvents[K]>((emit) =>
Effect.acquireRelease(
Expand Down
3 changes: 3 additions & 0 deletions src/locator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,9 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightLocator", (it) => {
// highlight
yield* buttons.first().highlight();

// hideHighlight
yield* buttons.first().hideHighlight;

// screenshot
const screenshotBuffer = yield* buttons.first().screenshot();
assert(screenshotBuffer.length > 0);
Expand Down
36 changes: 34 additions & 2 deletions src/locator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,36 @@ export interface PlaywrightLocatorService {
* @see {@link Locator.highlight}
* @since 0.4.1
*/
readonly highlight: () => Effect.Effect<void, PlaywrightError>;
readonly highlight: (
options?: Parameters<Locator["highlight"]>[0],
) => Effect.Effect<void, PlaywrightError>;
/**
* Hides the element highlight previously added by highlight.
*
* @see {@link Locator.hideHighlight}
* @since 0.5.0
*/
readonly hideHighlight: Effect.Effect<void, PlaywrightError>;
/**
* Drops the locator.
*
* @see {@link Locator.drop}
* @since 0.5.0
*/
readonly drop: (
data: Parameters<Locator["drop"]>[0],
options?: Parameters<Locator["drop"]>[1],
) => Effect.Effect<void, PlaywrightError>;
/**
* Normalizes the locator.
*
* @see {@link Locator.normalize}
* @since 0.5.0
*/
readonly normalize: () => Effect.Effect<
PlaywrightLocatorService,
PlaywrightError
>;
/**
* Captures a screenshot of the element.
*
Expand Down Expand Up @@ -778,7 +807,10 @@ export class PlaywrightLocator extends Context.Tag(
Array<ElementHandle<SVGElement | HTMLElement>>
>,
),
highlight: () => use((l) => l.highlight()),
highlight: (options) => use((l) => l.highlight(options)),
hideHighlight: use((l) => l.hideHighlight()),
drop: (data, options) => use((l) => l.drop(data, options)),
normalize: () => use((l) => l.normalize().then(PlaywrightLocator.make)),
screenshot: (options) => use((l) => l.screenshot(options)),
blur: (options) => use((l) => l.blur(options)),
clear: (options) => use((l) => l.clear(options)),
Expand Down
4 changes: 2 additions & 2 deletions src/page.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => {
console.warn("Warning from page");
});

const messages = yield* page.consoleMessages;
const messages = yield* page.consoleMessages();

assert.strictEqual(messages.length, 2);
assert.strictEqual(messages[0].text(), "Hello from page");
Expand Down Expand Up @@ -628,7 +628,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => {

yield* Fiber.join(errorFiber);

const errors = yield* page.pageErrors;
const errors = yield* page.pageErrors();
assert.ok(errors.length >= 1);
assert.strictEqual(errors[0].message, "Test Error");
}).pipe(PlaywrightEnvironment.withBrowser),
Expand Down
Loading
Loading