effect-playwright 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -0
- package/dist/experimental/index.d.mts +7 -5
- package/dist/experimental/index.mjs +7 -5
- package/dist/{index-aR0Fa_4Y.d.mts → index-DnbVDccF.d.mts} +199 -29
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/src-BGGNNney.mjs +310 -0
- package/package.json +5 -4
- package/dist/src-DveiwW4g.mjs +0 -167
package/README.md
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
# effect-playwright
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/effect-playwright)
|
|
3
4
|
[](https://github.com/Jobflow-io/effect-playwright/blob/main/LICENSE)
|
|
4
5
|
[](https://effect.website/)
|
|
5
6
|
|
|
6
7
|
A Playwright wrapper for the Effect ecosystem. This library provides a set of services and layers to interact with Playwright in a type-safe way using Effect.
|
|
7
8
|
|
|
9
|
+
> [!NOTE]
|
|
10
|
+
> This library is currently focused on using Playwright for **automation** and **scraping**. It does not provide a wrapper for `@playwright/test` (the test runner).
|
|
11
|
+
|
|
8
12
|
## Installation
|
|
9
13
|
|
|
10
14
|
```bash
|
|
@@ -17,6 +21,8 @@ or
|
|
|
17
21
|
npm install effect-playwright playwright-core
|
|
18
22
|
```
|
|
19
23
|
|
|
24
|
+
You can also install `playwright` instead of `playwright-core` if you want the post-build auto install of the browsers.
|
|
25
|
+
|
|
20
26
|
## Quick Start
|
|
21
27
|
|
|
22
28
|
```ts
|
|
@@ -49,6 +55,36 @@ const program = Effect.gen(function* () {
|
|
|
49
55
|
}).pipe(Effect.scoped);
|
|
50
56
|
```
|
|
51
57
|
|
|
58
|
+
## Connecting via CDP
|
|
59
|
+
|
|
60
|
+
You can connect to an existing browser instance using the Chrome DevTools Protocol (CDP).
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
const program = Effect.gen(function* () {
|
|
64
|
+
const playwright = yield* Playwright;
|
|
65
|
+
|
|
66
|
+
// Use connectCDPScoped to automatically close the CONNECTION when the scope ends
|
|
67
|
+
// Note: This does NOT close the browser process itself, only the CDP connection.
|
|
68
|
+
const browser = yield* playwright.connectCDPScoped("http://localhost:9222");
|
|
69
|
+
|
|
70
|
+
const page = yield* browser.newPage();
|
|
71
|
+
// ...
|
|
72
|
+
}).pipe(Effect.scoped);
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
If you need to manage the connection lifecycle manually, use `connectCDP`:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
const program = Effect.gen(function* () {
|
|
79
|
+
const playwright = yield* Playwright;
|
|
80
|
+
const browser = yield* playwright.connectCDP("http://localhost:9222");
|
|
81
|
+
|
|
82
|
+
// ... use browser ...
|
|
83
|
+
|
|
84
|
+
yield* browser.close;
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
52
88
|
## PlaywrightEnvironment (Experimental)
|
|
53
89
|
|
|
54
90
|
The `PlaywrightEnvironment` simplifies setup by allowing you to configure the browser type and launch options once and reuse them across your application.
|
|
@@ -75,6 +111,20 @@ const program = Effect.gen(function* () {
|
|
|
75
111
|
await Effect.runPromise(program.pipe(Effect.provide(liveLayer)));
|
|
76
112
|
```
|
|
77
113
|
|
|
114
|
+
### `PlaywrightEnvironment.withBrowser`
|
|
115
|
+
|
|
116
|
+
The `withBrowser` utility provides the `PlaywrightBrowser` service to your effect. It internally manages a `Scope`, which means the browser will be launched when the effect starts and closed automatically when the effect finishes (including on failure or interruption).
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
const program = Effect.gen(function* () {
|
|
120
|
+
const browser = yield* PlaywrightBrowser; // Now available in context
|
|
121
|
+
const page = yield* browser.newPage();
|
|
122
|
+
|
|
123
|
+
// ...
|
|
124
|
+
// Browser close is ensured
|
|
125
|
+
}).pipe(PlaywrightEnvironment.withBrowser);
|
|
126
|
+
```
|
|
127
|
+
|
|
78
128
|
## Accessing Native Playwright
|
|
79
129
|
|
|
80
130
|
If you need to access functionality from the underlying Playwright objects that isn't directly exposed, you can use the `use` method available on most services/objects (browsers, pages, locators).
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as PlaywrightError, o as PlaywrightBrowser } from "../index-
|
|
1
|
+
import { d as PlaywrightError, o as PlaywrightBrowser } from "../index-DnbVDccF.mjs";
|
|
2
2
|
import { Context, Effect, Layer } from "effect";
|
|
3
3
|
import { BrowserType, LaunchOptions } from "playwright-core";
|
|
4
4
|
import { Scope as Scope$1 } from "effect/Scope";
|
|
@@ -35,10 +35,11 @@ declare class PlaywrightEnvironment extends PlaywrightEnvironment_base {}
|
|
|
35
35
|
*
|
|
36
36
|
* // use the layer
|
|
37
37
|
* const program = Effect.gen(function* () {
|
|
38
|
-
* const
|
|
38
|
+
* const playwright = yield* PlaywrightEnvironment;
|
|
39
|
+
* const browser = yield* playwright.browser;
|
|
39
40
|
* const page = yield* browser.newPage();
|
|
40
41
|
* yield* page.goto("https://example.com");
|
|
41
|
-
* }).pipe(
|
|
42
|
+
* }).pipe(Effect.scoped, Effect.provide(playwrightEnv));
|
|
42
43
|
* ```
|
|
43
44
|
*
|
|
44
45
|
* @param browser - The Playwright BrowserType implementation (e.g. `chromium`, `firefox`, `webkit`).
|
|
@@ -59,12 +60,13 @@ declare const layer: (browser: BrowserType, launchOptions?: LaunchOptions) => La
|
|
|
59
60
|
* import { PlaywrightEnvironment } from "effect-playwright/experimental";
|
|
60
61
|
* import { chromium } from "playwright-core";
|
|
61
62
|
*
|
|
62
|
-
* const
|
|
63
|
+
* const env = PlaywrightEnvironment.layer(chromium);
|
|
64
|
+
*
|
|
63
65
|
* const program = Effect.gen(function* () {
|
|
64
66
|
* const browser = yield* PlaywrightBrowser;
|
|
65
67
|
* const page = yield* browser.newPage();
|
|
66
68
|
* yield* page.goto("https://example.com");
|
|
67
|
-
* }).pipe(PlaywrightEnvironment.withBrowser);
|
|
69
|
+
* }).pipe(PlaywrightEnvironment.withBrowser, Effect.provide(env));
|
|
68
70
|
* ```
|
|
69
71
|
*
|
|
70
72
|
* @since 0.1.0
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "../chunk-BiucMVzj.mjs";
|
|
2
|
-
import { n as PlaywrightBrowser, t as Playwright } from "../src-
|
|
2
|
+
import { n as PlaywrightBrowser, t as Playwright } from "../src-BGGNNney.mjs";
|
|
3
3
|
import { Context, Effect, Layer } from "effect";
|
|
4
4
|
|
|
5
5
|
//#region src/experimental/environment.ts
|
|
@@ -33,10 +33,11 @@ var PlaywrightEnvironment = class extends Context.Tag("effect-playwright/experim
|
|
|
33
33
|
*
|
|
34
34
|
* // use the layer
|
|
35
35
|
* const program = Effect.gen(function* () {
|
|
36
|
-
* const
|
|
36
|
+
* const playwright = yield* PlaywrightEnvironment;
|
|
37
|
+
* const browser = yield* playwright.browser;
|
|
37
38
|
* const page = yield* browser.newPage();
|
|
38
39
|
* yield* page.goto("https://example.com");
|
|
39
|
-
* }).pipe(
|
|
40
|
+
* }).pipe(Effect.scoped, Effect.provide(playwrightEnv));
|
|
40
41
|
* ```
|
|
41
42
|
*
|
|
42
43
|
* @param browser - The Playwright BrowserType implementation (e.g. `chromium`, `firefox`, `webkit`).
|
|
@@ -61,12 +62,13 @@ const layer = (browser, launchOptions) => {
|
|
|
61
62
|
* import { PlaywrightEnvironment } from "effect-playwright/experimental";
|
|
62
63
|
* import { chromium } from "playwright-core";
|
|
63
64
|
*
|
|
64
|
-
* const
|
|
65
|
+
* const env = PlaywrightEnvironment.layer(chromium);
|
|
66
|
+
*
|
|
65
67
|
* const program = Effect.gen(function* () {
|
|
66
68
|
* const browser = yield* PlaywrightBrowser;
|
|
67
69
|
* const page = yield* browser.newPage();
|
|
68
70
|
* yield* page.goto("https://example.com");
|
|
69
|
-
* }).pipe(PlaywrightEnvironment.withBrowser);
|
|
71
|
+
* }).pipe(PlaywrightEnvironment.withBrowser, Effect.provide(env));
|
|
70
72
|
* ```
|
|
71
73
|
*
|
|
72
74
|
* @since 0.1.0
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Context, Effect, Layer, Scope, Stream } from "effect";
|
|
2
|
-
import { Browser, BrowserContext, BrowserType, ConnectOverCDPOptions, ConsoleMessage, Dialog, Download, ElementHandle, FileChooser, Frame, JSHandle, Locator, Page, Request, Response, WebSocket, Worker, chromium } from "playwright-core";
|
|
1
|
+
import { Context, Effect, Layer, Option, Scope, Stream } from "effect";
|
|
2
|
+
import { Browser, BrowserContext, BrowserType, ConnectOverCDPOptions, ConsoleMessage, Dialog, Download, ElementHandle, FileChooser, Frame, JSHandle, Locator, Page, Request as Request$1, Response as Response$1, WebSocket, Worker as Worker$1, chromium } from "playwright-core";
|
|
3
3
|
import { Scope as Scope$1 } from "effect/Scope";
|
|
4
4
|
import * as effect_Types0 from "effect/Types";
|
|
5
5
|
import * as effect_Cause0 from "effect/Cause";
|
|
@@ -23,6 +23,117 @@ type NoHandles<Arg> = Arg extends JSHandle ? never : Arg extends object ? { [Key
|
|
|
23
23
|
type Unboxed<Arg> = Arg extends ElementHandle<infer T> ? T : Arg extends JSHandle<infer T> ? T : Arg extends NoHandles<Arg> ? Arg : Arg extends [infer A0] ? [Unboxed<A0>] : Arg extends [infer A0, infer A1] ? [Unboxed<A0>, Unboxed<A1>] : Arg extends [infer A0, infer A1, infer A2] ? [Unboxed<A0>, Unboxed<A1>, Unboxed<A2>] : Arg extends [infer A0, infer A1, infer A2, infer A3] ? [Unboxed<A0>, Unboxed<A1>, Unboxed<A2>, Unboxed<A3>] : Arg extends Array<infer T> ? Array<Unboxed<T>> : Arg extends object ? { [Key in keyof Arg]: Unboxed<Arg[Key]> } : Arg;
|
|
24
24
|
type PageFunction<Arg, R> = string | ((arg: Unboxed<Arg>) => R | Promise<R>);
|
|
25
25
|
//#endregion
|
|
26
|
+
//#region src/common.d.ts
|
|
27
|
+
declare const PlaywrightFrame_base: new <A extends Record<string, any> = {}>(args: effect_Types0.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }) => Readonly<A> & {
|
|
28
|
+
readonly _tag: "PlaywrightFrame";
|
|
29
|
+
};
|
|
30
|
+
declare class PlaywrightFrame extends PlaywrightFrame_base<{
|
|
31
|
+
use: <A>(f: (frame: Frame) => Promise<A>) => Effect.Effect<A, PlaywrightError>;
|
|
32
|
+
}> {
|
|
33
|
+
static make(frame: Frame): PlaywrightFrame;
|
|
34
|
+
}
|
|
35
|
+
declare const PlaywrightRequest_base: new <A extends Record<string, any> = {}>(args: effect_Types0.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }) => Readonly<A> & {
|
|
36
|
+
readonly _tag: "PlaywrightRequest";
|
|
37
|
+
};
|
|
38
|
+
declare class PlaywrightRequest extends PlaywrightRequest_base<{
|
|
39
|
+
allHeaders: Effect.Effect<Awaited<ReturnType<Request$1["allHeaders"]>>, PlaywrightError>;
|
|
40
|
+
failure: () => Option.Option<NonNullable<ReturnType<Request$1["failure"]>>>;
|
|
41
|
+
frame: Effect.Effect<PlaywrightFrame>;
|
|
42
|
+
headerValue: (name: string) => Effect.Effect<Option.Option<string>, PlaywrightError>;
|
|
43
|
+
headers: Effect.Effect<ReturnType<Request$1["headers"]>>;
|
|
44
|
+
headersArray: Effect.Effect<Awaited<ReturnType<Request$1["headersArray"]>>, PlaywrightError>;
|
|
45
|
+
isNavigationRequest: Effect.Effect<boolean>;
|
|
46
|
+
method: Effect.Effect<string>;
|
|
47
|
+
postData: () => Option.Option<string>;
|
|
48
|
+
postDataBuffer: () => Option.Option<NonNullable<ReturnType<Request$1["postDataBuffer"]>>>;
|
|
49
|
+
postDataJSON: Effect.Effect<Option.Option<NonNullable<Awaited<ReturnType<Request$1["postDataJSON"]>>>>, PlaywrightError>;
|
|
50
|
+
redirectedFrom: () => Option.Option<PlaywrightRequest>;
|
|
51
|
+
redirectedTo: () => Option.Option<PlaywrightRequest>;
|
|
52
|
+
resourceType: Effect.Effect<ReturnType<Request$1["resourceType"]>>;
|
|
53
|
+
response: Effect.Effect<Option.Option<PlaywrightResponse>, PlaywrightError>;
|
|
54
|
+
serviceWorker: () => Option.Option<PlaywrightWorker>;
|
|
55
|
+
sizes: Effect.Effect<Awaited<ReturnType<Request$1["sizes"]>>, PlaywrightError>;
|
|
56
|
+
timing: Effect.Effect<ReturnType<Request$1["timing"]>>;
|
|
57
|
+
url: Effect.Effect<string>;
|
|
58
|
+
}> {
|
|
59
|
+
static make(request: Request$1): PlaywrightRequest;
|
|
60
|
+
}
|
|
61
|
+
declare const PlaywrightResponse_base: new <A extends Record<string, any> = {}>(args: effect_Types0.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }) => Readonly<A> & {
|
|
62
|
+
readonly _tag: "PlaywrightResponse";
|
|
63
|
+
};
|
|
64
|
+
declare class PlaywrightResponse extends PlaywrightResponse_base<{
|
|
65
|
+
allHeaders: Effect.Effect<Awaited<ReturnType<Response$1["allHeaders"]>>, PlaywrightError>;
|
|
66
|
+
body: Effect.Effect<Awaited<ReturnType<Response$1["body"]>>, PlaywrightError>;
|
|
67
|
+
finished: Effect.Effect<Awaited<ReturnType<Response$1["finished"]>>, PlaywrightError>;
|
|
68
|
+
frame: Effect.Effect<PlaywrightFrame>;
|
|
69
|
+
fromServiceWorker: Effect.Effect<boolean>;
|
|
70
|
+
headers: Effect.Effect<ReturnType<Response$1["headers"]>>;
|
|
71
|
+
headersArray: Effect.Effect<Awaited<ReturnType<Response$1["headersArray"]>>, PlaywrightError>;
|
|
72
|
+
headerValue: (name: string) => Effect.Effect<Option.Option<string>, PlaywrightError>;
|
|
73
|
+
headerValues: (name: string) => Effect.Effect<Awaited<ReturnType<Response$1["headerValues"]>>, PlaywrightError>;
|
|
74
|
+
json: Effect.Effect<Awaited<ReturnType<Response$1["json"]>>, PlaywrightError>;
|
|
75
|
+
ok: Effect.Effect<boolean>;
|
|
76
|
+
request: () => PlaywrightRequest;
|
|
77
|
+
securityDetails: Effect.Effect<Option.Option<NonNullable<Awaited<ReturnType<Response$1["securityDetails"]>>>>, PlaywrightError>;
|
|
78
|
+
serverAddr: Effect.Effect<Option.Option<NonNullable<Awaited<ReturnType<Response$1["serverAddr"]>>>>, PlaywrightError>;
|
|
79
|
+
status: Effect.Effect<number>;
|
|
80
|
+
statusText: Effect.Effect<string>;
|
|
81
|
+
text: Effect.Effect<Awaited<ReturnType<Response$1["text"]>>, PlaywrightError>;
|
|
82
|
+
url: Effect.Effect<string>;
|
|
83
|
+
}> {
|
|
84
|
+
static make(response: Response$1): PlaywrightResponse;
|
|
85
|
+
}
|
|
86
|
+
declare const PlaywrightWorker_base: new <A extends Record<string, any> = {}>(args: effect_Types0.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }) => Readonly<A> & {
|
|
87
|
+
readonly _tag: "PlaywrightWorker";
|
|
88
|
+
};
|
|
89
|
+
declare class PlaywrightWorker extends PlaywrightWorker_base<{
|
|
90
|
+
evaluate: <R, Arg = void>(pageFunction: PageFunction<Arg, R>, arg?: Arg) => Effect.Effect<R, PlaywrightError>;
|
|
91
|
+
url: Effect.Effect<string>;
|
|
92
|
+
}> {
|
|
93
|
+
static make(worker: Worker$1): PlaywrightWorker;
|
|
94
|
+
}
|
|
95
|
+
declare const PlaywrightDialog_base: new <A extends Record<string, any> = {}>(args: effect_Types0.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }) => Readonly<A> & {
|
|
96
|
+
readonly _tag: "PlaywrightDialog";
|
|
97
|
+
};
|
|
98
|
+
declare class PlaywrightDialog extends PlaywrightDialog_base<{
|
|
99
|
+
accept: (promptText?: string) => Effect.Effect<void, PlaywrightError>;
|
|
100
|
+
defaultValue: Effect.Effect<string>;
|
|
101
|
+
dismiss: Effect.Effect<void, PlaywrightError>;
|
|
102
|
+
message: Effect.Effect<string>;
|
|
103
|
+
page: () => Option.Option<PlaywrightPageService>;
|
|
104
|
+
type: Effect.Effect<string>;
|
|
105
|
+
}> {
|
|
106
|
+
static make(dialog: Dialog): PlaywrightDialog;
|
|
107
|
+
}
|
|
108
|
+
declare const PlaywrightFileChooser_base: new <A extends Record<string, any> = {}>(args: effect_Types0.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }) => Readonly<A> & {
|
|
109
|
+
readonly _tag: "PlaywrightFileChooser";
|
|
110
|
+
};
|
|
111
|
+
declare class PlaywrightFileChooser extends PlaywrightFileChooser_base<{
|
|
112
|
+
element: () => ElementHandle;
|
|
113
|
+
isMultiple: Effect.Effect<boolean>;
|
|
114
|
+
page: () => PlaywrightPageService;
|
|
115
|
+
setFiles: (files: Parameters<FileChooser["setFiles"]>[0], options?: Parameters<FileChooser["setFiles"]>[1]) => Effect.Effect<void, PlaywrightError>;
|
|
116
|
+
}> {
|
|
117
|
+
static make(fileChooser: FileChooser): PlaywrightFileChooser;
|
|
118
|
+
}
|
|
119
|
+
declare const PlaywrightDownload_base: new <A extends Record<string, any> = {}>(args: effect_Types0.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }) => Readonly<A> & {
|
|
120
|
+
readonly _tag: "PlaywrightDownload";
|
|
121
|
+
};
|
|
122
|
+
declare class PlaywrightDownload extends PlaywrightDownload_base<{
|
|
123
|
+
cancel: Effect.Effect<void, PlaywrightError>;
|
|
124
|
+
createReadStream: Stream.Stream<Uint8Array, PlaywrightError>;
|
|
125
|
+
delete: Effect.Effect<void, PlaywrightError>;
|
|
126
|
+
failure: Effect.Effect<Option.Option<string | null>, PlaywrightError>;
|
|
127
|
+
page: () => PlaywrightPageService;
|
|
128
|
+
path: Effect.Effect<Option.Option<string | null>, PlaywrightError>;
|
|
129
|
+
saveAs: (path: string) => Effect.Effect<void, PlaywrightError>;
|
|
130
|
+
suggestedFilename: Effect.Effect<string>;
|
|
131
|
+
url: Effect.Effect<string>;
|
|
132
|
+
use: <R>(f: (download: Download) => Promise<R>) => Effect.Effect<R, PlaywrightError>;
|
|
133
|
+
}> {
|
|
134
|
+
static make(download: Download): PlaywrightDownload;
|
|
135
|
+
}
|
|
136
|
+
//#endregion
|
|
26
137
|
//#region src/locator.d.ts
|
|
27
138
|
/**
|
|
28
139
|
* Interface for a Playwright locator.
|
|
@@ -171,27 +282,6 @@ declare class PlaywrightLocator extends PlaywrightLocator_base {
|
|
|
171
282
|
}
|
|
172
283
|
//#endregion
|
|
173
284
|
//#region src/page.d.ts
|
|
174
|
-
interface PlaywrightPageEvents {
|
|
175
|
-
close: Page;
|
|
176
|
-
console: ConsoleMessage;
|
|
177
|
-
crash: Page;
|
|
178
|
-
dialog: Dialog;
|
|
179
|
-
domcontentloaded: Page;
|
|
180
|
-
download: Download;
|
|
181
|
-
filechooser: FileChooser;
|
|
182
|
-
frameattached: Frame;
|
|
183
|
-
framedetached: Frame;
|
|
184
|
-
framenavigated: Frame;
|
|
185
|
-
load: Page;
|
|
186
|
-
pageerror: Error;
|
|
187
|
-
popup: Page;
|
|
188
|
-
request: Request;
|
|
189
|
-
requestfailed: Request;
|
|
190
|
-
requestfinished: Request;
|
|
191
|
-
response: Response;
|
|
192
|
-
websocket: WebSocket;
|
|
193
|
-
worker: Worker;
|
|
194
|
-
}
|
|
195
285
|
interface PlaywrightPageService {
|
|
196
286
|
/**
|
|
197
287
|
* Navigates the page to the given URL.
|
|
@@ -329,7 +419,7 @@ interface PlaywrightPageService {
|
|
|
329
419
|
* @see {@link Page.on}
|
|
330
420
|
* @since 0.1.0
|
|
331
421
|
*/
|
|
332
|
-
readonly eventStream: <K extends keyof
|
|
422
|
+
readonly eventStream: <K extends keyof typeof eventMappings>(event: K) => Stream.Stream<ReturnType<(typeof eventMappings)[K]>>;
|
|
333
423
|
/**
|
|
334
424
|
* Clicks an element matching the given selector.
|
|
335
425
|
*
|
|
@@ -355,7 +445,60 @@ declare class PlaywrightPage extends PlaywrightPage_base {
|
|
|
355
445
|
* @param page - The Playwright `Page` instance to wrap.
|
|
356
446
|
* @since 0.1.0
|
|
357
447
|
*/
|
|
358
|
-
static make(page:
|
|
448
|
+
static make(page: PageWithPatchedEvents): PlaywrightPageService;
|
|
449
|
+
}
|
|
450
|
+
interface PageEvents {
|
|
451
|
+
close: Page;
|
|
452
|
+
console: ConsoleMessage;
|
|
453
|
+
crash: Page;
|
|
454
|
+
dialog: Dialog;
|
|
455
|
+
domcontentloaded: Page;
|
|
456
|
+
download: Download;
|
|
457
|
+
filechooser: FileChooser;
|
|
458
|
+
frameattached: Frame;
|
|
459
|
+
framedetached: Frame;
|
|
460
|
+
framenavigated: Frame;
|
|
461
|
+
load: Page;
|
|
462
|
+
pageerror: Error;
|
|
463
|
+
popup: Page;
|
|
464
|
+
request: Request;
|
|
465
|
+
requestfailed: Request;
|
|
466
|
+
requestfinished: Request;
|
|
467
|
+
response: Response;
|
|
468
|
+
websocket: WebSocket;
|
|
469
|
+
worker: Worker;
|
|
470
|
+
}
|
|
471
|
+
type PageEvent = keyof PageEvents;
|
|
472
|
+
declare const eventMappings: {
|
|
473
|
+
readonly close: typeof PlaywrightPage.make;
|
|
474
|
+
readonly console: (a: ConsoleMessage) => ConsoleMessage;
|
|
475
|
+
readonly crash: typeof PlaywrightPage.make;
|
|
476
|
+
readonly dialog: typeof PlaywrightDialog.make;
|
|
477
|
+
readonly domcontentloaded: typeof PlaywrightPage.make;
|
|
478
|
+
readonly download: typeof PlaywrightDownload.make;
|
|
479
|
+
readonly filechooser: typeof PlaywrightFileChooser.make;
|
|
480
|
+
readonly frameattached: typeof PlaywrightFrame.make;
|
|
481
|
+
readonly framedetached: typeof PlaywrightFrame.make;
|
|
482
|
+
readonly framenavigated: typeof PlaywrightFrame.make;
|
|
483
|
+
readonly load: typeof PlaywrightPage.make;
|
|
484
|
+
readonly pageerror: (a: Error) => Error;
|
|
485
|
+
readonly popup: typeof PlaywrightPage.make;
|
|
486
|
+
readonly request: typeof PlaywrightRequest.make;
|
|
487
|
+
readonly requestfailed: typeof PlaywrightRequest.make;
|
|
488
|
+
readonly requestfinished: typeof PlaywrightRequest.make;
|
|
489
|
+
readonly response: typeof PlaywrightResponse.make;
|
|
490
|
+
readonly websocket: (a: WebSocket) => WebSocket;
|
|
491
|
+
readonly worker: typeof PlaywrightWorker.make;
|
|
492
|
+
};
|
|
493
|
+
/**
|
|
494
|
+
* Page interface with generic on/off methods.
|
|
495
|
+
* Playwright's Page uses overloads for on/off, making generic event handling impossible.
|
|
496
|
+
* This interface provides a unified signature for our event map.
|
|
497
|
+
* @internal
|
|
498
|
+
*/
|
|
499
|
+
interface PageWithPatchedEvents extends Page {
|
|
500
|
+
on<K extends PageEvent>(event: K, listener: (arg: PageEvents[K]) => void): this;
|
|
501
|
+
off<K extends PageEvent>(event: K, listener: (arg: PageEvents[K]) => void): this;
|
|
359
502
|
}
|
|
360
503
|
//#endregion
|
|
361
504
|
//#region src/browser-context.d.ts
|
|
@@ -549,18 +692,19 @@ interface PlaywrightService {
|
|
|
549
692
|
/**
|
|
550
693
|
* Connects to a browser instance via Chrome DevTools Protocol (CDP).
|
|
551
694
|
*
|
|
552
|
-
* Unlike {@link
|
|
553
|
-
* scope is closed. It is the caller's responsibility to manage the
|
|
695
|
+
* Unlike {@link connectCDPScoped}, this method does **not** close the connection when the
|
|
696
|
+
* scope is closed. It is the caller's responsibility to manage the connection's
|
|
554
697
|
* lifecycle.
|
|
555
698
|
*
|
|
556
|
-
* If you want to close the
|
|
699
|
+
* If you want to close the connection using a scope simply add a finalizer:
|
|
557
700
|
*
|
|
558
701
|
* ```ts
|
|
559
702
|
* import { Effect } from "effect";
|
|
560
703
|
* import { Playwright } from "effect-playwright";
|
|
561
704
|
*
|
|
562
705
|
* const program = Effect.gen(function* () {
|
|
563
|
-
* const
|
|
706
|
+
* const playwright = yield* Playwright;
|
|
707
|
+
* const browser = yield* playwright.connectCDP(cdpUrl);
|
|
564
708
|
* yield* Effect.addFinalizer(() => browser.close.pipe(Effect.ignore));
|
|
565
709
|
* });
|
|
566
710
|
*
|
|
@@ -572,6 +716,32 @@ interface PlaywrightService {
|
|
|
572
716
|
* @since 0.1.0
|
|
573
717
|
*/
|
|
574
718
|
connectCDP: (cdpUrl: string, options?: ConnectOverCDPOptions) => Effect.Effect<typeof PlaywrightBrowser.Service, PlaywrightError>;
|
|
719
|
+
/**
|
|
720
|
+
* Connects to a browser instance via Chrome DevTools Protocol (CDP) managed by a Scope.
|
|
721
|
+
*
|
|
722
|
+
* This method automatically closes the connection when the scope is closed.
|
|
723
|
+
*
|
|
724
|
+
* Note that closing a CDP connection does **not** close the browser instance itself,
|
|
725
|
+
* only the CDP connection.
|
|
726
|
+
*
|
|
727
|
+
* ```ts
|
|
728
|
+
* import { Effect } from "effect";
|
|
729
|
+
* import { Playwright } from "effect-playwright";
|
|
730
|
+
*
|
|
731
|
+
* const program = Effect.gen(function* () {
|
|
732
|
+
* const playwright = yield* Playwright;
|
|
733
|
+
* const browser = yield* playwright.connectCDPScoped(cdpUrl);
|
|
734
|
+
* // Connection will be closed automatically when scope closes
|
|
735
|
+
* });
|
|
736
|
+
*
|
|
737
|
+
* await Effect.runPromise(program);
|
|
738
|
+
* ```
|
|
739
|
+
*
|
|
740
|
+
* @param cdpUrl - The CDP URL to connect to.
|
|
741
|
+
* @param options - Optional options for connecting to the CDP URL.
|
|
742
|
+
* @since 0.1.1
|
|
743
|
+
*/
|
|
744
|
+
connectCDPScoped: (cdpUrl: string, options?: ConnectOverCDPOptions) => Effect.Effect<typeof PlaywrightBrowser.Service, PlaywrightError, Scope.Scope>;
|
|
575
745
|
}
|
|
576
746
|
declare const Playwright_base: Context.TagClass<Playwright, "effect-playwright/index/Playwright", PlaywrightService>;
|
|
577
747
|
declare class Playwright extends Playwright_base {
|
package/dist/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as NewPageOptions, c as PlaywrightPageService, i as NewContextOptions, l as PlaywrightLocator, n as PlaywrightService, o as PlaywrightBrowser, r as LaunchOptions, s as PlaywrightPage, t as Playwright, u as PlaywrightLocatorService } from "./index-
|
|
1
|
+
import { a as NewPageOptions, c as PlaywrightPageService, i as NewContextOptions, l as PlaywrightLocator, n as PlaywrightService, o as PlaywrightBrowser, r as LaunchOptions, s as PlaywrightPage, t as Playwright, u as PlaywrightLocatorService } from "./index-DnbVDccF.mjs";
|
|
2
2
|
export { LaunchOptions, NewContextOptions, NewPageOptions, Playwright, PlaywrightBrowser, PlaywrightLocator, PlaywrightLocatorService, PlaywrightPage, PlaywrightPageService, PlaywrightService };
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { i as PlaywrightLocator, n as PlaywrightBrowser, r as PlaywrightPage, t as Playwright } from "./src-
|
|
1
|
+
import { i as PlaywrightLocator, n as PlaywrightBrowser, r as PlaywrightPage, t as Playwright } from "./src-BGGNNney.mjs";
|
|
2
2
|
|
|
3
3
|
export { Playwright, PlaywrightBrowser, PlaywrightLocator, PlaywrightPage };
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import { Context, Data, Effect, Layer, Option, Stream, identity } from "effect";
|
|
2
|
+
import { chromium, errors } from "playwright-core";
|
|
3
|
+
|
|
4
|
+
//#region src/errors.ts
|
|
5
|
+
var PlaywrightError = class extends Data.TaggedError("PlaywrightError") {};
|
|
6
|
+
function wrapError(error) {
|
|
7
|
+
if (error instanceof errors.TimeoutError) return new PlaywrightError({
|
|
8
|
+
reason: "Timeout",
|
|
9
|
+
cause: error
|
|
10
|
+
});
|
|
11
|
+
else return new PlaywrightError({
|
|
12
|
+
reason: "Unknown",
|
|
13
|
+
cause: error
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/utils.ts
|
|
19
|
+
/** @internal */
|
|
20
|
+
const useHelper = (api) => (userFunction) => Effect.tryPromise(() => userFunction(api)).pipe(Effect.mapError(wrapError));
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/common.ts
|
|
24
|
+
var PlaywrightFrame = class PlaywrightFrame extends Data.TaggedClass("PlaywrightFrame") {
|
|
25
|
+
static make(frame) {
|
|
26
|
+
return new PlaywrightFrame({ use: useHelper(frame) });
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
var PlaywrightRequest = class PlaywrightRequest extends Data.TaggedClass("PlaywrightRequest") {
|
|
30
|
+
static make(request) {
|
|
31
|
+
const use = useHelper(request);
|
|
32
|
+
return new PlaywrightRequest({
|
|
33
|
+
allHeaders: use(() => request.allHeaders()),
|
|
34
|
+
failure: Option.liftNullable(request.failure),
|
|
35
|
+
frame: Effect.sync(() => PlaywrightFrame.make(request.frame())),
|
|
36
|
+
headerValue: (name) => use(() => request.headerValue(name)).pipe(Effect.map(Option.fromNullable)),
|
|
37
|
+
headers: Effect.sync(() => request.headers()),
|
|
38
|
+
headersArray: use(() => request.headersArray()),
|
|
39
|
+
isNavigationRequest: Effect.sync(() => request.isNavigationRequest()),
|
|
40
|
+
method: Effect.sync(() => request.method()),
|
|
41
|
+
postData: Option.liftNullable(request.postData),
|
|
42
|
+
postDataBuffer: Option.liftNullable(request.postDataBuffer),
|
|
43
|
+
postDataJSON: use(() => request.postDataJSON()).pipe(Effect.map(Option.fromNullable)),
|
|
44
|
+
redirectedFrom: () => Option.fromNullable(request.redirectedFrom()).pipe(Option.map(PlaywrightRequest.make)),
|
|
45
|
+
redirectedTo: () => Option.fromNullable(request.redirectedTo()).pipe(Option.map(PlaywrightRequest.make)),
|
|
46
|
+
resourceType: Effect.sync(() => request.resourceType()),
|
|
47
|
+
response: use(() => request.response()).pipe(Effect.map(Option.fromNullable), Effect.map(Option.map(PlaywrightResponse.make))),
|
|
48
|
+
serviceWorker: () => Option.fromNullable(request.serviceWorker()).pipe(Option.map(PlaywrightWorker.make)),
|
|
49
|
+
sizes: use(() => request.sizes()),
|
|
50
|
+
timing: Effect.sync(() => request.timing()),
|
|
51
|
+
url: Effect.sync(() => request.url())
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
var PlaywrightResponse = class PlaywrightResponse extends Data.TaggedClass("PlaywrightResponse") {
|
|
56
|
+
static make(response) {
|
|
57
|
+
const use = useHelper(response);
|
|
58
|
+
return new PlaywrightResponse({
|
|
59
|
+
allHeaders: use(() => response.allHeaders()),
|
|
60
|
+
body: use(() => response.body()),
|
|
61
|
+
finished: use(() => response.finished()),
|
|
62
|
+
frame: Effect.sync(() => PlaywrightFrame.make(response.frame())),
|
|
63
|
+
fromServiceWorker: Effect.sync(() => response.fromServiceWorker()),
|
|
64
|
+
headers: Effect.sync(() => response.headers()),
|
|
65
|
+
headersArray: use(() => response.headersArray()),
|
|
66
|
+
headerValue: (name) => use(() => response.headerValue(name)).pipe(Effect.map(Option.fromNullable)),
|
|
67
|
+
headerValues: (name) => use(() => response.headerValues(name)),
|
|
68
|
+
json: use(() => response.json()),
|
|
69
|
+
ok: Effect.sync(() => response.ok()),
|
|
70
|
+
request: () => PlaywrightRequest.make(response.request()),
|
|
71
|
+
securityDetails: use(() => response.securityDetails()).pipe(Effect.map(Option.fromNullable)),
|
|
72
|
+
serverAddr: use(() => response.serverAddr()).pipe(Effect.map(Option.fromNullable)),
|
|
73
|
+
status: Effect.sync(() => response.status()),
|
|
74
|
+
statusText: Effect.sync(() => response.statusText()),
|
|
75
|
+
text: use(() => response.text()),
|
|
76
|
+
url: Effect.sync(() => response.url())
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
var PlaywrightWorker = class PlaywrightWorker extends Data.TaggedClass("PlaywrightWorker") {
|
|
81
|
+
static make(worker) {
|
|
82
|
+
const use = useHelper(worker);
|
|
83
|
+
return new PlaywrightWorker({
|
|
84
|
+
evaluate: (f, arg) => use((w) => w.evaluate(f, arg)),
|
|
85
|
+
url: Effect.sync(() => worker.url())
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
var PlaywrightDialog = class PlaywrightDialog extends Data.TaggedClass("PlaywrightDialog") {
|
|
90
|
+
static make(dialog) {
|
|
91
|
+
const use = useHelper(dialog);
|
|
92
|
+
return new PlaywrightDialog({
|
|
93
|
+
accept: (promptText) => use(() => dialog.accept(promptText)),
|
|
94
|
+
defaultValue: Effect.sync(() => dialog.defaultValue()),
|
|
95
|
+
dismiss: use(() => dialog.dismiss()),
|
|
96
|
+
message: Effect.sync(() => dialog.message()),
|
|
97
|
+
page: () => Option.fromNullable(dialog.page()).pipe(Option.map(PlaywrightPage.make)),
|
|
98
|
+
type: Effect.sync(() => dialog.type())
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
var PlaywrightFileChooser = class PlaywrightFileChooser extends Data.TaggedClass("PlaywrightFileChooser") {
|
|
103
|
+
static make(fileChooser) {
|
|
104
|
+
const use = useHelper(fileChooser);
|
|
105
|
+
return new PlaywrightFileChooser({
|
|
106
|
+
element: () => fileChooser.element(),
|
|
107
|
+
isMultiple: Effect.sync(() => fileChooser.isMultiple()),
|
|
108
|
+
page: () => PlaywrightPage.make(fileChooser.page()),
|
|
109
|
+
setFiles: (files, options) => use(() => fileChooser.setFiles(files, options))
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
var PlaywrightDownload = class PlaywrightDownload extends Data.TaggedClass("PlaywrightDownload") {
|
|
114
|
+
static make(download) {
|
|
115
|
+
const use = useHelper(download);
|
|
116
|
+
return new PlaywrightDownload({
|
|
117
|
+
cancel: use(() => download.cancel()),
|
|
118
|
+
createReadStream: Stream.empty,
|
|
119
|
+
delete: use(() => download.delete()),
|
|
120
|
+
failure: use(() => download.failure()).pipe(Effect.map(Option.fromNullable)),
|
|
121
|
+
page: () => PlaywrightPage.make(download.page()),
|
|
122
|
+
path: use(() => download.path()).pipe(Effect.map(Option.fromNullable)),
|
|
123
|
+
saveAs: (path) => use(() => download.saveAs(path)),
|
|
124
|
+
suggestedFilename: Effect.sync(() => download.suggestedFilename()),
|
|
125
|
+
url: Effect.sync(() => download.url()),
|
|
126
|
+
use
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
//#endregion
|
|
132
|
+
//#region src/locator.ts
|
|
133
|
+
/**
|
|
134
|
+
* A service that provides a `PlaywrightLocator` instance.
|
|
135
|
+
*
|
|
136
|
+
* @since 0.1.0
|
|
137
|
+
* @category tag
|
|
138
|
+
*/
|
|
139
|
+
var PlaywrightLocator = class PlaywrightLocator extends Context.Tag("effect-playwright/PlaywrightLocator")() {
|
|
140
|
+
/**
|
|
141
|
+
* Creates a `PlaywrightLocator` from a Playwright `Locator` instance. This is mostly for internal use.
|
|
142
|
+
* But you could use this if you have used `use` or similar to wrap the locator.
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```ts
|
|
146
|
+
* const playwrightNativeLocator = yield* page.use((p) => p.locator("button"));
|
|
147
|
+
* const locator = PlaywrightLocator.make(playwrightNativeLocator);
|
|
148
|
+
* ```
|
|
149
|
+
*
|
|
150
|
+
* @param locator - The Playwright `Locator` instance to wrap.
|
|
151
|
+
* @since 0.1.0
|
|
152
|
+
* @category constructor
|
|
153
|
+
*/
|
|
154
|
+
static make(locator) {
|
|
155
|
+
const use = useHelper(locator);
|
|
156
|
+
return PlaywrightLocator.of({
|
|
157
|
+
click: (options) => use((l) => l.click(options)),
|
|
158
|
+
fill: (value, options) => use((l) => l.fill(value, options)),
|
|
159
|
+
getAttribute: (name, options) => use((l) => l.getAttribute(name, options)),
|
|
160
|
+
innerText: (options) => use((l) => l.innerText(options)),
|
|
161
|
+
innerHTML: (options) => use((l) => l.innerHTML(options)),
|
|
162
|
+
inputValue: (options) => use((l) => l.inputValue(options)),
|
|
163
|
+
textContent: (options) => use((l) => l.textContent(options)),
|
|
164
|
+
count: use((l) => l.count()),
|
|
165
|
+
first: () => PlaywrightLocator.make(locator.first()),
|
|
166
|
+
last: () => PlaywrightLocator.make(locator.last()),
|
|
167
|
+
nth: (index) => PlaywrightLocator.make(locator.nth(index)),
|
|
168
|
+
evaluate: (pageFunction, arg, options) => use((l) => l.evaluate(pageFunction, arg, options)),
|
|
169
|
+
use
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
//#endregion
|
|
175
|
+
//#region src/page.ts
|
|
176
|
+
/**
|
|
177
|
+
* @category tag
|
|
178
|
+
*/
|
|
179
|
+
var PlaywrightPage = class PlaywrightPage extends Context.Tag("effect-playwright/PlaywrightPage")() {
|
|
180
|
+
/**
|
|
181
|
+
* Creates a `PlaywrightPage` from a Playwright `Page` instance.
|
|
182
|
+
*
|
|
183
|
+
* @param page - The Playwright `Page` instance to wrap.
|
|
184
|
+
* @since 0.1.0
|
|
185
|
+
*/
|
|
186
|
+
static make(page) {
|
|
187
|
+
const use = useHelper(page);
|
|
188
|
+
return PlaywrightPage.of({
|
|
189
|
+
goto: (url, options) => use((p) => p.goto(url, options)),
|
|
190
|
+
waitForURL: (url, options) => use((p) => p.waitForURL(url, options)),
|
|
191
|
+
title: use((p) => p.title()),
|
|
192
|
+
evaluate: (f, arg) => use((p) => p.evaluate(f, arg)),
|
|
193
|
+
locator: (selector, options) => PlaywrightLocator.make(page.locator(selector, options)),
|
|
194
|
+
getByRole: (role, options) => PlaywrightLocator.make(page.getByRole(role, options)),
|
|
195
|
+
getByText: (text, options) => PlaywrightLocator.make(page.getByText(text, options)),
|
|
196
|
+
getByLabel: (label, options) => PlaywrightLocator.make(page.getByLabel(label, options)),
|
|
197
|
+
getByTestId: (testId) => PlaywrightLocator.make(page.getByTestId(testId)),
|
|
198
|
+
url: Effect.sync(() => page.url()),
|
|
199
|
+
reload: use((p) => p.reload()),
|
|
200
|
+
close: use((p) => p.close()),
|
|
201
|
+
click: (selector, options) => use((p) => p.click(selector, options)),
|
|
202
|
+
eventStream: (event) => Stream.asyncPush((emit) => Effect.acquireRelease(Effect.sync(() => {
|
|
203
|
+
const callback = emit.single;
|
|
204
|
+
const closeCallback = emit.end;
|
|
205
|
+
page.on(event, callback);
|
|
206
|
+
page.once("close", closeCallback);
|
|
207
|
+
return {
|
|
208
|
+
callback,
|
|
209
|
+
closeCallback
|
|
210
|
+
};
|
|
211
|
+
}), ({ callback, closeCallback }) => Effect.sync(() => {
|
|
212
|
+
page.off(event, callback);
|
|
213
|
+
page.off("close", closeCallback);
|
|
214
|
+
}))).pipe(Stream.map((e) => {
|
|
215
|
+
const mapper = eventMappings[event];
|
|
216
|
+
return mapper(e);
|
|
217
|
+
})),
|
|
218
|
+
use
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
const eventMappings = {
|
|
223
|
+
close: PlaywrightPage.make,
|
|
224
|
+
console: identity,
|
|
225
|
+
crash: PlaywrightPage.make,
|
|
226
|
+
dialog: PlaywrightDialog.make,
|
|
227
|
+
domcontentloaded: PlaywrightPage.make,
|
|
228
|
+
download: PlaywrightDownload.make,
|
|
229
|
+
filechooser: PlaywrightFileChooser.make,
|
|
230
|
+
frameattached: PlaywrightFrame.make,
|
|
231
|
+
framedetached: PlaywrightFrame.make,
|
|
232
|
+
framenavigated: PlaywrightFrame.make,
|
|
233
|
+
load: PlaywrightPage.make,
|
|
234
|
+
pageerror: identity,
|
|
235
|
+
popup: PlaywrightPage.make,
|
|
236
|
+
request: PlaywrightRequest.make,
|
|
237
|
+
requestfailed: PlaywrightRequest.make,
|
|
238
|
+
requestfinished: PlaywrightRequest.make,
|
|
239
|
+
response: PlaywrightResponse.make,
|
|
240
|
+
websocket: identity,
|
|
241
|
+
worker: PlaywrightWorker.make
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
//#endregion
|
|
245
|
+
//#region src/browser-context.ts
|
|
246
|
+
var PlaywrightBrowserContext = class PlaywrightBrowserContext extends Context.Tag("cehs/backend/lib/playwright/PlaywrightBrowserContext")() {
|
|
247
|
+
static make(context) {
|
|
248
|
+
const use = useHelper(context);
|
|
249
|
+
return PlaywrightBrowserContext.of({
|
|
250
|
+
pages: Effect.sync(() => context.pages().map(PlaywrightPage.make)),
|
|
251
|
+
newPage: use((c) => c.newPage().then(PlaywrightPage.make)),
|
|
252
|
+
close: use((c) => c.close())
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
//#endregion
|
|
258
|
+
//#region src/browser.ts
|
|
259
|
+
/**
|
|
260
|
+
* @category tag
|
|
261
|
+
*/
|
|
262
|
+
var PlaywrightBrowser = class PlaywrightBrowser extends Context.Tag("cehs/backend/lib/playwright/PlaywrightBrowser")() {
|
|
263
|
+
/**
|
|
264
|
+
* @category constructor
|
|
265
|
+
*/
|
|
266
|
+
static make(browser) {
|
|
267
|
+
const use = useHelper(browser);
|
|
268
|
+
return PlaywrightBrowser.of({
|
|
269
|
+
newPage: (options) => use((browser$1) => browser$1.newPage(options).then(PlaywrightPage.make)),
|
|
270
|
+
close: use((browser$1) => browser$1.close()),
|
|
271
|
+
contexts: Effect.sync(() => browser.contexts().map(PlaywrightBrowserContext.make)),
|
|
272
|
+
newContext: (options) => Effect.acquireRelease(use((browser$1) => browser$1.newContext(options).then(PlaywrightBrowserContext.make)), (context) => context.close.pipe(Effect.ignoreLogged)),
|
|
273
|
+
browserType: Effect.sync(() => browser.browserType()),
|
|
274
|
+
version: Effect.sync(() => browser.version()),
|
|
275
|
+
isConnected: Effect.sync(() => browser.isConnected()),
|
|
276
|
+
use
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
//#endregion
|
|
282
|
+
//#region src/playwright.ts
|
|
283
|
+
const launch = Effect.fn(function* (browserType, options) {
|
|
284
|
+
const rawBrowser = yield* Effect.tryPromise({
|
|
285
|
+
try: () => browserType.launch(options),
|
|
286
|
+
catch: wrapError
|
|
287
|
+
});
|
|
288
|
+
return PlaywrightBrowser.make(rawBrowser);
|
|
289
|
+
});
|
|
290
|
+
const connectCDP = Effect.fn(function* (cdpUrl, options) {
|
|
291
|
+
const browser = yield* Effect.tryPromise({
|
|
292
|
+
try: () => chromium.connectOverCDP(cdpUrl, options),
|
|
293
|
+
catch: wrapError
|
|
294
|
+
});
|
|
295
|
+
return PlaywrightBrowser.make(browser);
|
|
296
|
+
});
|
|
297
|
+
var Playwright = class Playwright extends Context.Tag("effect-playwright/index/Playwright")() {
|
|
298
|
+
/**
|
|
299
|
+
* @category layer
|
|
300
|
+
*/
|
|
301
|
+
static layer = Layer.succeed(Playwright, {
|
|
302
|
+
launch,
|
|
303
|
+
launchScoped: (browserType, options) => Effect.acquireRelease(launch(browserType, options), (browser) => browser.close.pipe(Effect.ignore)),
|
|
304
|
+
connectCDP,
|
|
305
|
+
connectCDPScoped: (cdpUrl, options) => Effect.acquireRelease(connectCDP(cdpUrl, options), (browser) => browser.close.pipe(Effect.ignore))
|
|
306
|
+
});
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
//#endregion
|
|
310
|
+
export { PlaywrightLocator as i, PlaywrightBrowser as n, PlaywrightPage as r, Playwright as t };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "effect-playwright",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.1",
|
|
5
5
|
"description": "An Effect-based Playwright library.",
|
|
6
6
|
"author": "Jobflow GmbH",
|
|
7
7
|
"license": "ISC",
|
|
@@ -37,16 +37,17 @@
|
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@biomejs/biome": "2.3.11",
|
|
40
|
-
"@effect/language-service": "^0.
|
|
40
|
+
"@effect/language-service": "^0.65.0",
|
|
41
41
|
"@effect/platform": "^0.94.1",
|
|
42
42
|
"@effect/platform-node": "^0.104.0",
|
|
43
43
|
"@effect/vitest": "^0.27.0",
|
|
44
|
+
"@types/node": "^25.0.8",
|
|
44
45
|
"effect": "^3.19.14",
|
|
45
46
|
"playwright": "^1.57.0",
|
|
46
|
-
"tsdown": "
|
|
47
|
+
"tsdown": "0.20.0-beta.1",
|
|
47
48
|
"tsx": "^4.21.0",
|
|
48
49
|
"typescript": "^5.9.3",
|
|
49
|
-
"vitest": "^4.0.
|
|
50
|
+
"vitest": "^4.0.17"
|
|
50
51
|
},
|
|
51
52
|
"types": "./dist/index.d.mts",
|
|
52
53
|
"scripts": {
|
package/dist/src-DveiwW4g.mjs
DELETED
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import { Context, Data, Effect, Layer, Stream } from "effect";
|
|
2
|
-
import { chromium, errors } from "playwright-core";
|
|
3
|
-
|
|
4
|
-
//#region src/errors.ts
|
|
5
|
-
var PlaywrightError = class extends Data.TaggedError("PlaywrightError") {};
|
|
6
|
-
function wrapError(error) {
|
|
7
|
-
if (error instanceof errors.TimeoutError) return new PlaywrightError({
|
|
8
|
-
reason: "Timeout",
|
|
9
|
-
cause: error
|
|
10
|
-
});
|
|
11
|
-
else return new PlaywrightError({
|
|
12
|
-
reason: "Unknown",
|
|
13
|
-
cause: error
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
//#endregion
|
|
18
|
-
//#region src/utils.ts
|
|
19
|
-
/** @internal */
|
|
20
|
-
const useHelper = (api) => (userFunction) => Effect.tryPromise(() => userFunction(api)).pipe(Effect.mapError(wrapError));
|
|
21
|
-
|
|
22
|
-
//#endregion
|
|
23
|
-
//#region src/locator.ts
|
|
24
|
-
/**
|
|
25
|
-
* A service that provides a `PlaywrightLocator` instance.
|
|
26
|
-
*
|
|
27
|
-
* @since 0.1.0
|
|
28
|
-
* @category tag
|
|
29
|
-
*/
|
|
30
|
-
var PlaywrightLocator = class PlaywrightLocator extends Context.Tag("effect-playwright/PlaywrightLocator")() {
|
|
31
|
-
/**
|
|
32
|
-
* Creates a `PlaywrightLocator` from a Playwright `Locator` instance. This is mostly for internal use.
|
|
33
|
-
* But you could use this if you have used `use` or similar to wrap the locator.
|
|
34
|
-
*
|
|
35
|
-
* @example
|
|
36
|
-
* ```ts
|
|
37
|
-
* const playwrightNativeLocator = yield* page.use((p) => p.locator("button"));
|
|
38
|
-
* const locator = PlaywrightLocator.make(playwrightNativeLocator);
|
|
39
|
-
* ```
|
|
40
|
-
*
|
|
41
|
-
* @param locator - The Playwright `Locator` instance to wrap.
|
|
42
|
-
* @since 0.1.0
|
|
43
|
-
* @category constructor
|
|
44
|
-
*/
|
|
45
|
-
static make(locator) {
|
|
46
|
-
const use = useHelper(locator);
|
|
47
|
-
return PlaywrightLocator.of({
|
|
48
|
-
click: (options) => use((l) => l.click(options)),
|
|
49
|
-
fill: (value, options) => use((l) => l.fill(value, options)),
|
|
50
|
-
getAttribute: (name, options) => use((l) => l.getAttribute(name, options)),
|
|
51
|
-
innerText: (options) => use((l) => l.innerText(options)),
|
|
52
|
-
innerHTML: (options) => use((l) => l.innerHTML(options)),
|
|
53
|
-
inputValue: (options) => use((l) => l.inputValue(options)),
|
|
54
|
-
textContent: (options) => use((l) => l.textContent(options)),
|
|
55
|
-
count: use((l) => l.count()),
|
|
56
|
-
first: () => PlaywrightLocator.make(locator.first()),
|
|
57
|
-
last: () => PlaywrightLocator.make(locator.last()),
|
|
58
|
-
nth: (index) => PlaywrightLocator.make(locator.nth(index)),
|
|
59
|
-
evaluate: (pageFunction, arg, options) => use((l) => l.evaluate(pageFunction, arg, options)),
|
|
60
|
-
use
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
//#endregion
|
|
66
|
-
//#region src/page.ts
|
|
67
|
-
/**
|
|
68
|
-
* @category tag
|
|
69
|
-
*/
|
|
70
|
-
var PlaywrightPage = class PlaywrightPage extends Context.Tag("effect-playwright/PlaywrightPage")() {
|
|
71
|
-
/**
|
|
72
|
-
* Creates a `PlaywrightPage` from a Playwright `Page` instance.
|
|
73
|
-
*
|
|
74
|
-
* @param page - The Playwright `Page` instance to wrap.
|
|
75
|
-
* @since 0.1.0
|
|
76
|
-
*/
|
|
77
|
-
static make(page) {
|
|
78
|
-
const use = useHelper(page);
|
|
79
|
-
return PlaywrightPage.of({
|
|
80
|
-
goto: (url, options) => use((p) => p.goto(url, options)),
|
|
81
|
-
waitForURL: (url, options) => use((p) => p.waitForURL(url, options)),
|
|
82
|
-
title: use((p) => p.title()),
|
|
83
|
-
evaluate: (f, arg) => use((p) => p.evaluate(f, arg)),
|
|
84
|
-
locator: (selector, options) => PlaywrightLocator.make(page.locator(selector, options)),
|
|
85
|
-
getByRole: (role, options) => PlaywrightLocator.make(page.getByRole(role, options)),
|
|
86
|
-
getByText: (text, options) => PlaywrightLocator.make(page.getByText(text, options)),
|
|
87
|
-
getByLabel: (label, options) => PlaywrightLocator.make(page.getByLabel(label, options)),
|
|
88
|
-
getByTestId: (testId) => PlaywrightLocator.make(page.getByTestId(testId)),
|
|
89
|
-
url: Effect.sync(() => page.url()),
|
|
90
|
-
reload: use((p) => p.reload()),
|
|
91
|
-
close: use((p) => p.close()),
|
|
92
|
-
click: (selector, options) => use((p) => p.click(selector, options)),
|
|
93
|
-
eventStream: (event) => Stream.asyncPush((emit) => Effect.acquireRelease(Effect.sync(() => page.on(event, emit.single)), () => Effect.sync(() => page.off(event, emit.single)))),
|
|
94
|
-
use
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
//#endregion
|
|
100
|
-
//#region src/browser-context.ts
|
|
101
|
-
var PlaywrightBrowserContext = class PlaywrightBrowserContext extends Context.Tag("cehs/backend/lib/playwright/PlaywrightBrowserContext")() {
|
|
102
|
-
static make(context) {
|
|
103
|
-
const use = useHelper(context);
|
|
104
|
-
return PlaywrightBrowserContext.of({
|
|
105
|
-
pages: Effect.sync(() => context.pages().map(PlaywrightPage.make)),
|
|
106
|
-
newPage: use((c) => c.newPage().then(PlaywrightPage.make)),
|
|
107
|
-
close: use((c) => c.close())
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
//#endregion
|
|
113
|
-
//#region src/browser.ts
|
|
114
|
-
/**
|
|
115
|
-
* @category tag
|
|
116
|
-
*/
|
|
117
|
-
var PlaywrightBrowser = class PlaywrightBrowser extends Context.Tag("cehs/backend/lib/playwright/PlaywrightBrowser")() {
|
|
118
|
-
/**
|
|
119
|
-
* @category constructor
|
|
120
|
-
*/
|
|
121
|
-
static make(browser) {
|
|
122
|
-
const use = useHelper(browser);
|
|
123
|
-
return PlaywrightBrowser.of({
|
|
124
|
-
newPage: (options) => use((browser$1) => browser$1.newPage(options).then(PlaywrightPage.make)),
|
|
125
|
-
close: use((browser$1) => browser$1.close()),
|
|
126
|
-
contexts: Effect.sync(() => browser.contexts().map(PlaywrightBrowserContext.make)),
|
|
127
|
-
newContext: (options) => Effect.acquireRelease(use((browser$1) => browser$1.newContext(options).then(PlaywrightBrowserContext.make)), (context) => context.close.pipe(Effect.ignoreLogged)),
|
|
128
|
-
browserType: Effect.sync(() => browser.browserType()),
|
|
129
|
-
version: Effect.sync(() => browser.version()),
|
|
130
|
-
isConnected: Effect.sync(() => browser.isConnected()),
|
|
131
|
-
use
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
//#endregion
|
|
137
|
-
//#region src/playwright.ts
|
|
138
|
-
const launch = Effect.fn(function* (browserType, options) {
|
|
139
|
-
const rawBrowser = yield* Effect.tryPromise({
|
|
140
|
-
try: () => browserType.launch(options),
|
|
141
|
-
catch: wrapError
|
|
142
|
-
});
|
|
143
|
-
return PlaywrightBrowser.make(rawBrowser);
|
|
144
|
-
});
|
|
145
|
-
var Playwright = class Playwright extends Context.Tag("effect-playwright/index/Playwright")() {
|
|
146
|
-
/**
|
|
147
|
-
* @category layer
|
|
148
|
-
*/
|
|
149
|
-
static layer = Layer.succeed(Playwright, {
|
|
150
|
-
launch,
|
|
151
|
-
launchScoped: Effect.fn(function* (browserType, options) {
|
|
152
|
-
const browser = yield* launch(browserType, options);
|
|
153
|
-
yield* Effect.addFinalizer(() => browser.close.pipe(Effect.ignore));
|
|
154
|
-
return browser;
|
|
155
|
-
}),
|
|
156
|
-
connectCDP: Effect.fn(function* (cdpUrl, options) {
|
|
157
|
-
const browser = yield* Effect.tryPromise({
|
|
158
|
-
try: () => chromium.connectOverCDP(cdpUrl, options),
|
|
159
|
-
catch: wrapError
|
|
160
|
-
});
|
|
161
|
-
return PlaywrightBrowser.make(browser);
|
|
162
|
-
})
|
|
163
|
-
});
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
//#endregion
|
|
167
|
-
export { PlaywrightLocator as i, PlaywrightBrowser as n, PlaywrightPage as r, Playwright as t };
|