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
2 changes: 1 addition & 1 deletion biome.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$schema": "https://biomejs.dev/schemas/2.3.11/schema.json",
"$schema": "https://biomejs.dev/schemas/2.4.6/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
Expand Down
42 changes: 41 additions & 1 deletion src/browser-context.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { assert, layer } from "@effect/vitest";
import { Effect } from "effect";
import { Effect, Option } from "effect";
import { chromium } from "playwright-core";
import { PlaywrightBrowser } from "./browser";
import { PlaywrightEnvironment } from "./experimental";
Expand All @@ -11,6 +11,46 @@ type TestWindow = Window & {
layer(PlaywrightEnvironment.layer(chromium))(
"PlaywrightBrowserContext",
(it) => {
it.scoped("should wrap context methods", () =>
Effect.gen(function* () {
const browser = yield* PlaywrightBrowser;
const context = yield* browser.newContext();

// Test browser()
const contextBrowser = context.browser();
assert.isTrue(Option.isSome(contextBrowser));

// Test cookies/addCookies/clearCookies
yield* context.addCookies([
{
name: "test-cookie",
value: "test-value",
url: "https://example.com",
},
]);
const cookies = yield* context.cookies(["https://example.com"]);
assert.strictEqual(cookies.length, 1);
assert.strictEqual(cookies[0].name, "test-cookie");

yield* context.clearCookies();
const cookiesAfterClear = yield* context.cookies([
"https://example.com",
]);
assert.strictEqual(cookiesAfterClear.length, 0);

// Test grantPermissions/clearPermissions
yield* context.grantPermissions(["notifications"]);
yield* context.clearPermissions;

// Test setters
context.setDefaultNavigationTimeout(30000);
context.setDefaultTimeout(30000);
yield* context.setExtraHTTPHeaders({ "X-Test": "test" });
yield* context.setGeolocation({ latitude: 52, longitude: 13 });
yield* context.setOffline(false);
}).pipe(PlaywrightEnvironment.withBrowser),
);

it.scoped("addInitScript should execute script in all new pages", () =>
Effect.gen(function* () {
const browser = yield* PlaywrightBrowser;
Expand Down
129 changes: 128 additions & 1 deletion src/browser-context.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Context, Effect, identity, Stream } from "effect";
import { Context, Effect, identity, Option, Stream } from "effect";
import type {
BrowserContext,
ConsoleMessage,
Expand All @@ -9,6 +9,7 @@ import type {
WebError,
Worker,
} from "playwright-core";
import { PlaywrightBrowser, type PlaywrightBrowserService } from "./browser";
import { PlaywrightClock, type PlaywrightClockService } from "./clock";
import {
PlaywrightDialog,
Expand Down Expand Up @@ -105,6 +106,114 @@ export interface PlaywrightBrowserContextService {
arg?: Parameters<BrowserContext["addInitScript"]>[1],
) => Effect.Effect<void, PlaywrightError>;

/**
* Returns the browser that the context belongs to.
*
* @see {@link BrowserContext.browser}
* @since 0.4.0
*/
readonly browser: () => Option.Option<PlaywrightBrowserService>;

/**
* Clears the cookies from the browser context.
*
* @see {@link BrowserContext.clearCookies}
* @since 0.4.0
*/
readonly clearCookies: (options?: {
name?: string | RegExp;
domain?: string | RegExp;
path?: string | RegExp;
}) => Effect.Effect<void, PlaywrightError>;

/**
* Clears the permissions from the browser context.
*
* @see {@link BrowserContext.clearPermissions}
* @since 0.4.0
*/
readonly clearPermissions: Effect.Effect<void, PlaywrightError>;

/**
* Returns the cookies for the browser context.
*
* @see {@link BrowserContext.cookies}
* @since 0.4.0
*/
readonly cookies: (
urls?: string | string[],
) => Effect.Effect<
Awaited<ReturnType<BrowserContext["cookies"]>>,
PlaywrightError
>;

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

/**
* Grants permissions to the browser context.
*
* @see {@link BrowserContext.grantPermissions}
* @since 0.4.0
*/
readonly grantPermissions: (
permissions: Parameters<BrowserContext["grantPermissions"]>[0],
options?: Parameters<BrowserContext["grantPermissions"]>[1],
) => Effect.Effect<void, PlaywrightError>;

/**
* Sets the extra HTTP headers for the browser context.
*
* @see {@link BrowserContext.setExtraHTTPHeaders}
* @since 0.4.0
*/
readonly setExtraHTTPHeaders: (
headers: Parameters<BrowserContext["setExtraHTTPHeaders"]>[0],
) => Effect.Effect<void, PlaywrightError>;

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

/**
* Sets the offline state for the browser context.
*
* @see {@link BrowserContext.setOffline}
* @since 0.4.0
*/
readonly setOffline: (
offline: boolean,
) => Effect.Effect<void, PlaywrightError>;

/**
* Sets the default navigation timeout for the browser context.
*
* @see {@link BrowserContext.setDefaultNavigationTimeout}
* @since 0.4.0
*/
readonly setDefaultNavigationTimeout: (timeout: number) => void;

/**
* Sets the default timeout for the browser context.
*
* @see {@link BrowserContext.setDefaultTimeout}
* @since 0.4.0
*/
readonly setDefaultTimeout: (timeout: number) => void;

/**
* Creates a stream of the given event from the browser context.
*
Expand Down Expand Up @@ -144,6 +253,24 @@ export class PlaywrightBrowserContext extends Context.Tag(
newPage: use((c) => c.newPage().then(PlaywrightPage.make)),
close: use((c) => c.close()),
addInitScript: (script, arg) => use((c) => c.addInitScript(script, arg)),
browser: () =>
Option.fromNullable(context.browser()).pipe(
Option.map(PlaywrightBrowser.make),
),
clearCookies: (options) => use((c) => c.clearCookies(options)),
clearPermissions: use((c) => c.clearPermissions()),
cookies: (urls) => use((c) => c.cookies(urls)),
addCookies: (cookies) => use((c) => c.addCookies(cookies)),
grantPermissions: (permissions, options) =>
use((c) => c.grantPermissions(permissions, options)),
setExtraHTTPHeaders: (headers) =>
use((c) => c.setExtraHTTPHeaders(headers)),
setGeolocation: (geolocation) =>
use((c) => c.setGeolocation(geolocation)),
setOffline: (offline) => use((c) => c.setOffline(offline)),
setDefaultNavigationTimeout: (timeout) =>
context.setDefaultNavigationTimeout(timeout),
setDefaultTimeout: (timeout) => context.setDefaultTimeout(timeout),
eventStream: <K extends keyof BrowserContextEvents>(event: K) =>
Stream.asyncPush<BrowserContextEvents[K]>((emit) =>
Effect.acquireRelease(
Expand Down
52 changes: 51 additions & 1 deletion src/frame.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { assert, layer } from "@effect/vitest";
import { Effect } from "effect";
import { Effect, Option } from "effect";
import { chromium } from "playwright-core";
import { PlaywrightBrowser } from "./browser";
import { PlaywrightEnvironment } from "./experimental";
Expand Down Expand Up @@ -58,9 +58,59 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightFrame", (it) => {
const byText = yield* frame.getByText("Hello from Frame").count;
assert.strictEqual(byText, 1);

// Test getByPlaceholder
yield* frame.evaluate(() => {
const input = document.createElement("input");
input.placeholder = "Search...";
document.body.appendChild(input);
});
const byPlaceholder = yield* frame.getByPlaceholder("Search...").count;
assert.strictEqual(byPlaceholder, 1);

// Test getByAltText
yield* frame.evaluate(() => {
const img = document.createElement("img");
img.alt = "Playwright Logo";
document.body.appendChild(img);
});
const byAltText = yield* frame.getByAltText("Playwright Logo").count;
assert.strictEqual(byAltText, 1);

// Test getByTitle
yield* frame.evaluate(() => {
const span = document.createElement("span");
span.title = "Tooltip";
document.body.appendChild(span);
});
const byTitle = yield* frame.getByTitle("Tooltip").count;
assert.strictEqual(byTitle, 1);

// Test name
const name = frame.name();
assert.strictEqual(name, "test-frame");

// Test page
const framePage = frame.page();
assert.isOk(framePage);

// Test parentFrame
const parent = frame.parentFrame();
assert.isTrue(Option.isSome(parent));

// Test childFrames
const children = frame.childFrames();
assert.strictEqual(children.length, 0);

// Test isDetached
assert.isFalse(frame.isDetached());

// Test waitForTimeout
yield* frame.waitForTimeout(100);

// Test setContent
yield* frame.setContent("<h1>New Content</h1>");
const newContent = yield* frame.content;
assert.isTrue(newContent.includes("New Content"));
}).pipe(PlaywrightEnvironment.withBrowser),
);

Expand Down
Loading
Loading