From e38f642a2ac710fca89fceaa7df42d4c055ef1e7 Mon Sep 17 00:00:00 2001 From: Filip Weiss Date: Thu, 20 Aug 2026 23:10:22 +0200 Subject: [PATCH] Port effect-playwright to Effect v4 RC --- package.json | 10 +- pnpm-lock.yaml | 463 ++----------------------- pnpm-workspace.yaml | 7 +- scripts/coverage.ts | 25 +- src/browser-context.test.ts | 8 +- src/browser-context.ts | 28 +- src/browser.test.ts | 28 +- src/browser.ts | 28 +- src/clock.ts | 2 +- src/common.test.ts | 48 ++- src/common.ts | 41 +-- src/credentials.ts | 2 +- src/event-stream.test.ts | 14 +- src/experimental/browser-utils.test.ts | 21 +- src/frame-locator.ts | 2 +- src/frame.test.ts | 8 +- src/frame.ts | 4 +- src/keyboard.ts | 2 +- src/locator.test.ts | 28 +- src/locator.ts | 8 +- src/mouse.ts | 2 +- src/page.test.ts | 116 ++++--- src/page.ts | 50 +-- src/playwright-spawner.test.ts | 2 +- src/playwright-spawner.ts | 2 +- src/playwright.test.ts | 16 +- src/playwright.ts | 2 +- src/screencast.ts | 2 +- src/test.spec.ts | 26 +- src/test.ts | 24 +- src/touchscreen.ts | 2 +- src/tracing.ts | 2 +- src/web-storage.ts | 4 +- 33 files changed, 310 insertions(+), 717 deletions(-) diff --git a/package.json b/package.json index 7b7d67e..2c85667 100644 --- a/package.json +++ b/package.json @@ -50,9 +50,8 @@ "playwright-core": "^1.62.1" }, "peerDependencies": { - "@effect/platform": "^0.93.3", "@playwright/test": "^1.62.1", - "effect": "^3.19.6" + "effect": "^4.0.0-rc.111" }, "peerDependenciesMeta": { "@playwright/test": { @@ -61,14 +60,11 @@ }, "devDependencies": { "@biomejs/biome": "2.5.9", - "@effect/cli": "^0.77.0", "@effect/language-service": "0.87.2", - "@effect/platform": "^0.97.1", - "@effect/platform-node": "^0.108.1", - "@effect/vitest": "^0.30.0", + "@effect/vitest": "^4.0.0-rc.111", "@playwright/test": "^1.62.1", "@types/node": "^25.9.5", - "effect": "^3.22.1", + "effect": "^4.0.0-rc.111", "pkg-pr-new": "^0.0.88", "playwright": "^1.62.1", "ts-morph": "^28.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9ce6662..abbcafd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,21 +15,12 @@ importers: '@biomejs/biome': specifier: 2.5.9 version: 2.5.9 - '@effect/cli': - specifier: ^0.77.0 - version: 0.77.0(@effect/platform@0.97.1(effect@3.22.1))(@effect/printer-ansi@0.49.0(@effect/typeclass@0.40.0(effect@3.22.1))(effect@3.22.1))(@effect/printer@0.49.0(@effect/typeclass@0.40.0(effect@3.22.1))(effect@3.22.1))(effect@3.22.1) '@effect/language-service': specifier: 0.87.2 version: 0.87.2 - '@effect/platform': - specifier: ^0.97.1 - version: 0.97.1(effect@3.22.1) - '@effect/platform-node': - specifier: ^0.108.1 - version: 0.108.1(@effect/cluster@0.59.0(@effect/platform@0.97.1(effect@3.22.1))(@effect/rpc@0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/sql@0.51.1(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/workflow@0.18.2(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(@effect/rpc@0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(@effect/rpc@0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/sql@0.51.1(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(effect@3.22.1) '@effect/vitest': - specifier: ^0.30.0 - version: 0.30.0(effect@3.22.1)(vitest@4.1.11(@types/node@25.9.5)(vite@8.2.1(@types/node@25.9.5)(esbuild@0.28.2)(tsx@4.23.12)(yaml@2.9.0))) + specifier: ^4.0.0-rc.111 + version: 4.0.0-rc.111(effect@4.0.0-rc.111)(vitest@4.1.11(@types/node@25.9.5)(vite@8.2.1(@types/node@25.9.5)(esbuild@0.28.2)(tsx@4.23.12)(yaml@2.9.0))) '@playwright/test': specifier: ^1.62.1 version: 1.62.1 @@ -37,8 +28,8 @@ importers: specifier: ^25.9.5 version: 25.9.5 effect: - specifier: ^3.22.1 - version: 3.22.1 + specifier: ^4.0.0-rc.111 + version: 4.0.0-rc.111 pkg-pr-new: specifier: ^0.0.88 version: 0.0.88 @@ -126,106 +117,15 @@ packages: cpu: [x64] os: [win32] - '@effect/cli@0.77.0': - resolution: {integrity: sha512-uVw33bcqPaSu6YZqGf6MyM2CbYsE79mrAnQsDzSFnP8jmnjNfXWrfmWUGK2yy0jXD0wWmVbmvwm4xVFv2Utsog==} - peerDependencies: - '@effect/platform': ^0.97.1 - '@effect/printer': ^0.51.0 - '@effect/printer-ansi': ^0.51.0 - effect: ^3.22.1 - - '@effect/cluster@0.59.0': - resolution: {integrity: sha512-rxtJ0zlcdDDtn9wau0z/PFfwPP2FsYPB2/tSK4tT8DkTYQmACJ5AwRwZm3Ea83iL/gv3df63lRe94oMiS8bFfg==} - peerDependencies: - '@effect/platform': ^0.96.1 - '@effect/rpc': ^0.75.1 - '@effect/sql': ^0.51.1 - '@effect/workflow': ^0.18.2 - effect: ^3.21.2 - - '@effect/experimental@0.60.0': - resolution: {integrity: sha512-i5zIg7Xup2KgHyqHlYtkgqSE1bNzCL0GbbTQxrpIzKF0q/ebknOk/ox8B/gIq2vImjoEE81h/oxU+6i1NH210g==} - peerDependencies: - '@effect/platform': ^0.96.0 - effect: ^3.21.0 - ioredis: ^5 - lmdb: ^3 - peerDependenciesMeta: - ioredis: - optional: true - lmdb: - optional: true - '@effect/language-service@0.87.2': resolution: {integrity: sha512-CfiSoaVQO8pZgaMZGw5VvMvRGybsJ2LaSDoLYaqiVGvo/YYPYVR2GzUKY0h1NtIweq/+SQ5XLrvtzPIttWQ0GQ==} hasBin: true - '@effect/platform-node-shared@0.61.1': - resolution: {integrity: sha512-MJAJ1Nc43pYJb5ulFtdNID8klNyRLcbQ0zZ7XYRcBAlT/DrCyN4yAD89AzosmUyfOU+LMHdc8LTMt4rKNEMFaA==} - peerDependencies: - '@effect/cluster': ^0.60.1 - '@effect/platform': ^0.97.1 - '@effect/rpc': ^0.76.1 - '@effect/sql': ^0.52.1 - effect: ^3.22.1 - - '@effect/platform-node@0.108.1': - resolution: {integrity: sha512-BlPW+k/AaVS2ofPGZY1IV3HfLQ3gKGTfkY/jPVOJNOB9NiWb6ufAKOsuNTSAIYP8EzYxTH8tKOENXUXUcANoZA==} - peerDependencies: - '@effect/cluster': ^0.60.2 - '@effect/platform': ^0.97.1 - '@effect/rpc': ^0.76.2 - '@effect/sql': ^0.52.1 - effect: ^3.22.1 - - '@effect/platform@0.97.1': - resolution: {integrity: sha512-IevWxwmrxCdeXxbXDx/hiOstHtERRigd1nhZSuHgiFEl7NkBmS/5GVWsRacq4NfJN2uCXqggETKNwij15VEpew==} - peerDependencies: - effect: ^3.22.1 - - '@effect/printer-ansi@0.49.0': - resolution: {integrity: sha512-N2OyqDTqcGLKeUy2URowThoU5issZQwG/Ihv5qOYWJD0neq9qBIgC57/9BkFpTRPNSMtPHyCOk1TFj297HGLLQ==} - peerDependencies: - '@effect/typeclass': ^0.40.0 - effect: ^3.21.0 - - '@effect/printer@0.49.0': - resolution: {integrity: sha512-hrjTuExF87wuWjOnnND1c2fKcCWhleQBVaoA7JlrU3rC7s+RYPETDOXtpgAK3/uuMCRnDhfVFQMevtKT8MBdKg==} - peerDependencies: - '@effect/typeclass': ^0.40.0 - effect: ^3.21.0 - - '@effect/rpc@0.75.1': - resolution: {integrity: sha512-8yxF8+mMGGEbF8BUCp34HjdJj7CvTpGeZxBcpsDF6v7zPiGbJL1UDLzA8ZqYjmcngBHhPecbmeONTk/LiLAaEg==} - peerDependencies: - '@effect/platform': ^0.96.1 - effect: ^3.21.2 - - '@effect/sql@0.51.1': - resolution: {integrity: sha512-iPDAefrJcI0HcTk9keP9Gq8Pg08K1HmpnmZZt85AqyTcvorhoNsXDFiKBbPldfV2CortwVkacX8KjO9GPpSYCA==} - peerDependencies: - '@effect/experimental': ^0.60.0 - '@effect/platform': ^0.96.1 - effect: ^3.21.2 - - '@effect/typeclass@0.40.0': - resolution: {integrity: sha512-L/2o2ImeqbemFlqH0b3y2PqQTFc+E0/DUnffCU8bkJUGh0yUZmh2RXuXhR8QOpfNCe718JQjI+mLnpVF2MMmaQ==} + '@effect/vitest@4.0.0-rc.111': + resolution: {integrity: sha512-YDaEVT+grREBVMzykRNFtJwGxy02achzT0WXZYwMJA4ukzuB9krkgQ5roc3N6zhC3NQq/j4IyM32/Pcov7AhHw==} peerDependencies: - effect: ^3.21.0 - - '@effect/vitest@0.30.0': - resolution: {integrity: sha512-2qcK7F4XSwOn7Ye9vgEkrndHiiHVf9Nl+U5jvvLBKeYx4+8++O5Y8RFezaQzs/rWx8GkdlStv/s+HYMHZ/2/AQ==} - peerDependencies: - effect: ^3.22.0 - vitest: ^3.2.0 - - '@effect/workflow@0.18.2': - resolution: {integrity: sha512-2av0TexhxHnapQa3eLn6TkniokUFRZKf8dlWlLqbODMpXAJ3mm+DOHWM0ozMGkg9K/+zGCtiL3dMqJyJ8r7G8g==} - peerDependencies: - '@effect/experimental': ^0.60.0 - '@effect/platform': ^0.96.1 - '@effect/rpc': ^0.75.1 - effect: ^3.21.2 + effect: ^4.0.0-rc.111 + vitest: '>=4.1.0 <5.0.0' '@esbuild/aix-ppc64@0.28.2': resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} @@ -422,88 +322,6 @@ packages: '@oxc-project/types@0.146.0': resolution: {integrity: sha512-XC0QsnnhVe7sLIWmYmdPw7x5P0h4W8vUU3Nv1ySgWXtvCz8NizoAEpGXA0sOYoJQV2Rl13LgURAHQ5cI5ILCSA==} - '@parcel/watcher-android-arm64@2.6.0': - resolution: {integrity: sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [android] - - '@parcel/watcher-darwin-arm64@2.6.0': - resolution: {integrity: sha512-Y3QV0gl7Q1zbfueunkWIERICbEojQFCgpyG7YqOGNFLsckXyI1xu9mAIUpKY9QBYzBtSkN8dBPwd3yiAO9ovMw==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [darwin] - - '@parcel/watcher-darwin-x64@2.6.0': - resolution: {integrity: sha512-Ohv6OpzhUfKYD7Beb8kDvG0jbIxORCYY1JRdZnaBtnjjkJxgD7ZVL0nw2sCYd0yTMKTvz3nnTnOF3cDifK+kvw==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [darwin] - - '@parcel/watcher-freebsd-x64@2.6.0': - resolution: {integrity: sha512-5HmXvDgs8VK+74jF9y9/2FE3/OnlcKmc56tjmSrEuZjpSZOGL+fvAu+HKJBdPs9uwoP2hE6TlSUpXZ/C5jUFmQ==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [freebsd] - - '@parcel/watcher-linux-arm-glibc@2.6.0': - resolution: {integrity: sha512-Ps/hui3A+vMbjdqlqAowK2ZL8+BO8dBjxeWXj6npTBs3jx4wWmbPpaLuqwrQrSqIVMCnpWo238bJ1U37GhQOYg==} - engines: {node: '>= 10.0.0'} - cpu: [arm] - os: [linux] - libc: [glibc] - - '@parcel/watcher-linux-arm-musl@2.6.0': - resolution: {integrity: sha512-9c6AUHgHoG+IY88MRIHupztQiQnrbqHYQjkM2btA+Bf/wQnQMuiD0Wfk1EVv3TlNT3x41uU71rn6E4xh/+zvkw==} - engines: {node: '>= 10.0.0'} - cpu: [arm] - os: [linux] - libc: [musl] - - '@parcel/watcher-linux-arm64-glibc@2.6.0': - resolution: {integrity: sha512-yHRqS2owEXe6Hic9z6Mh1ECsCd+ODVOGvZDyciqRd21+v+o+DnXMOrw50DSpIG2sb8GPEaPPmfeCAWKPJdq46g==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@parcel/watcher-linux-arm64-musl@2.6.0': - resolution: {integrity: sha512-WhB2e/V7rqdHHWZusBSPuy5Ei8S6lSz6FE5TKKQz5h3a0O+C+mhY7vxU9b/stqvMb8beLnPY82ZrFTLKs+SrKA==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@parcel/watcher-linux-x64-glibc@2.6.0': - resolution: {integrity: sha512-ulGE6x6Oz6iAwg75T8YQSoguBWasniIbX+QWpaYPcCnDOpdWX3k+4xbEYPZVLxOuoJI+svJJPD3sEj8G7lrQ3A==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@parcel/watcher-linux-x64-musl@2.6.0': - resolution: {integrity: sha512-tkBYKt7YQrjIJWYDnto2YgO8MRkjlMTSNoRHzsXinBqbLdeOM3L32wPZJvIZxqaLMfSlS/4sUjH/6STVP/XDLw==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [linux] - libc: [musl] - - '@parcel/watcher-win32-arm64@2.6.0': - resolution: {integrity: sha512-gIZAP23jaHjGWasY/TY6yL7NHFClf0Ga7FN+iINvk+KN94rhm94lYZhFsbYFNcA04/onvGD9kKmiJLJB2HbNwQ==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [win32] - - '@parcel/watcher-win32-x64@2.6.0': - resolution: {integrity: sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [win32] - - '@parcel/watcher@2.6.0': - resolution: {integrity: sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==} - engines: {node: '>= 10.0.0'} - '@playwright/test@1.62.1': resolution: {integrity: sha512-DTcUc8qii+cpHvtOwggMtBRMjKZHXYWdw8syRYu2vtzuq4Wxphqq4NfCs5Zt44L6mA8rfDfj+PHnxFc/FeK6mQ==} engines: {node: '>=20'} @@ -863,8 +681,8 @@ packages: oxc-resolver: optional: true - effect@3.22.1: - resolution: {integrity: sha512-TNoXushmPOBAjJlthF5d2QwnX2xBPEtcNJr5XKNKbRLbDvBcOYkXlYDfvGfSA0zriwLFuCll5MDtNMAdZL17PQ==} + effect@4.0.0-rc.111: + resolution: {integrity: sha512-ASd5L58EIR0CUNueZNKKjSsyOCd+2alxOAIaTcHaqkJkPsaYSsw5Cg/cfANk5K4Jr2YsX756xvX11shzqsreWA==} empathic@2.0.1: resolution: {integrity: sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q==} @@ -889,9 +707,9 @@ packages: resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} engines: {node: '>=12.0.0'} - fast-check@3.23.2: - resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} - engines: {node: '>=8.0.0'} + fast-check@4.9.0: + resolution: {integrity: sha512-7ms6T7SybUev/PQITciI0yLM2pOSFy5zpG8Ty7tQofcVaQUvrMXp6CBwqF6fThLCLOrfBtuHAtwq6Yu4XPCllg==} + engines: {node: '>=12.17.0'} fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} @@ -902,9 +720,6 @@ packages: picomatch: optional: true - find-my-way-ts@0.1.6: - resolution: {integrity: sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA==} - fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -926,21 +741,6 @@ packages: resolution: {integrity: sha512-NkJQA7oZ4YHQhd2+H3BoRFKF3d/XNsiKpHZCQEMH9pDX27hQQLsTyOocyRgaIVtf8gHX3Nt3LPkR4e5EdtPAGQ==} engines: {node: ^22.18.0 || >=24.0.0} - ini@4.1.3: - resolution: {integrity: sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - kubernetes-types@1.30.0: - resolution: {integrity: sha512-Dew1okvhM/SQcIa2rcgujNndZwU8VnSapDgdxlYoB84ZlpAD43U6KLAFqYo17ykSFGHNPrg0qry0bP+GJd9v7Q==} - lightningcss-android-arm64@1.33.0: resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} engines: {node: '>= 12.0.0'} @@ -1031,11 +831,6 @@ packages: mdurl@2.1.0: resolution: {integrity: sha512-1+HBaOx0zi/dQWht8rNv9MYf9qqpqL/kxI0hXImU6Y547zM6Sni8BQibt7ifgMcYtQg41ao3Ivd6cnSM86inpg==} - mime@3.0.0: - resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} - engines: {node: '>=10.0.0'} - hasBin: true - minimatch@10.2.6: resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} engines: {node: 18 || 20 || >=22} @@ -1044,20 +839,14 @@ packages: resolution: {integrity: sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw==} hasBin: true - msgpackr@1.12.1: - resolution: {integrity: sha512-4EUH9tQHnMmEgzW/MdAP0KIfa1T9AF+htl0ffe2n5vb2EKn9y2co8ccpgWko6S52Jy1PQZKwRnx5/KkYjtd9MQ==} - - multipasta@0.2.8: - resolution: {integrity: sha512-ZPWuMKyv0cSO29f7hozp+k6+crZbQijV8ipMvxNxRf2SwtYGTX1ZX89Kd20VV4H9Znonx+EQn+iy1wGQsJ+b+Q==} + msgpackr@2.0.5: + resolution: {integrity: sha512-cef05H/dSYpLpqp3sj/qyZh5vhUYCalnaLO7j1yOmpsR0y/XwLVtK7r5gn+U/F7CTEfMowcGhlUQJDLcLf7jcA==} nanoid@3.3.18: resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - node-addon-api@7.1.1: - resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - node-gyp-build-optional-packages@5.2.2: resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==} hasBin: true @@ -1101,8 +890,8 @@ packages: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} - pure-rand@6.1.0: - resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + pure-rand@8.4.2: + resolution: {integrity: sha512-vvuOGgcuPJAirlHvuQw1TrOiw7ptaIXXmIbNuiNOY6lNGJJH49PQ1Kj4nd783nPdQhQdicgOjVI2yI/9BD6/Ng==} quansync@1.0.0: resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==} @@ -1162,9 +951,6 @@ packages: resolution: {integrity: sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==} engines: {node: '>=14.0.0'} - toml@3.0.0: - resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} - tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -1232,14 +1018,6 @@ packages: undici-types@7.24.6: resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} - undici@7.29.0: - resolution: {integrity: sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==} - engines: {node: '>=20.18.1'} - - uuid@11.1.1: - resolution: {integrity: sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==} - hasBin: true - verkit@0.3.2: resolution: {integrity: sha512-zj/ob3UsvJGN0whEAKFp53REA5X66hvffVqoCtVQAakJKnKlH+/PcOfMoFwIG/o4rElqLv/ycAFlx8ZlXUorCg==} engines: {node: '>=18.12.0'} @@ -1333,18 +1111,6 @@ packages: engines: {node: '>=8'} hasBin: true - ws@8.21.3: - resolution: {integrity: sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - yaml@2.9.0: resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} engines: {node: '>= 14.6'} @@ -1396,109 +1162,13 @@ snapshots: '@biomejs/cli-win32-x64@2.5.9': optional: true - '@effect/cli@0.77.0(@effect/platform@0.97.1(effect@3.22.1))(@effect/printer-ansi@0.49.0(@effect/typeclass@0.40.0(effect@3.22.1))(effect@3.22.1))(@effect/printer@0.49.0(@effect/typeclass@0.40.0(effect@3.22.1))(effect@3.22.1))(effect@3.22.1)': - dependencies: - '@effect/platform': 0.97.1(effect@3.22.1) - '@effect/printer': 0.49.0(@effect/typeclass@0.40.0(effect@3.22.1))(effect@3.22.1) - '@effect/printer-ansi': 0.49.0(@effect/typeclass@0.40.0(effect@3.22.1))(effect@3.22.1) - effect: 3.22.1 - ini: 4.1.3 - toml: 3.0.0 - yaml: 2.9.0 - - '@effect/cluster@0.59.0(@effect/platform@0.97.1(effect@3.22.1))(@effect/rpc@0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/sql@0.51.1(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/workflow@0.18.2(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(@effect/rpc@0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(effect@3.22.1))(effect@3.22.1)': - dependencies: - '@effect/platform': 0.97.1(effect@3.22.1) - '@effect/rpc': 0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1) - '@effect/sql': 0.51.1(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1) - '@effect/workflow': 0.18.2(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(@effect/rpc@0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(effect@3.22.1) - effect: 3.22.1 - kubernetes-types: 1.30.0 - - '@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1)': - dependencies: - '@effect/platform': 0.97.1(effect@3.22.1) - effect: 3.22.1 - uuid: 11.1.1 - '@effect/language-service@0.87.2': {} - '@effect/platform-node-shared@0.61.1(@effect/cluster@0.59.0(@effect/platform@0.97.1(effect@3.22.1))(@effect/rpc@0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/sql@0.51.1(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/workflow@0.18.2(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(@effect/rpc@0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(@effect/rpc@0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/sql@0.51.1(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(effect@3.22.1)': + '@effect/vitest@4.0.0-rc.111(effect@4.0.0-rc.111)(vitest@4.1.11(@types/node@25.9.5)(vite@8.2.1(@types/node@25.9.5)(esbuild@0.28.2)(tsx@4.23.12)(yaml@2.9.0)))': dependencies: - '@effect/cluster': 0.59.0(@effect/platform@0.97.1(effect@3.22.1))(@effect/rpc@0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/sql@0.51.1(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/workflow@0.18.2(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(@effect/rpc@0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(effect@3.22.1))(effect@3.22.1) - '@effect/platform': 0.97.1(effect@3.22.1) - '@effect/rpc': 0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1) - '@effect/sql': 0.51.1(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1) - '@parcel/watcher': 2.6.0 - effect: 3.22.1 - multipasta: 0.2.8 - ws: 8.21.3 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - '@effect/platform-node@0.108.1(@effect/cluster@0.59.0(@effect/platform@0.97.1(effect@3.22.1))(@effect/rpc@0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/sql@0.51.1(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/workflow@0.18.2(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(@effect/rpc@0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(@effect/rpc@0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/sql@0.51.1(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(effect@3.22.1)': - dependencies: - '@effect/cluster': 0.59.0(@effect/platform@0.97.1(effect@3.22.1))(@effect/rpc@0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/sql@0.51.1(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/workflow@0.18.2(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(@effect/rpc@0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(effect@3.22.1))(effect@3.22.1) - '@effect/platform': 0.97.1(effect@3.22.1) - '@effect/platform-node-shared': 0.61.1(@effect/cluster@0.59.0(@effect/platform@0.97.1(effect@3.22.1))(@effect/rpc@0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/sql@0.51.1(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/workflow@0.18.2(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(@effect/rpc@0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(@effect/rpc@0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/sql@0.51.1(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(effect@3.22.1) - '@effect/rpc': 0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1) - '@effect/sql': 0.51.1(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1) - effect: 3.22.1 - mime: 3.0.0 - undici: 7.29.0 - ws: 8.21.3 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - '@effect/platform@0.97.1(effect@3.22.1)': - dependencies: - effect: 3.22.1 - find-my-way-ts: 0.1.6 - msgpackr: 1.12.1 - multipasta: 0.2.8 - - '@effect/printer-ansi@0.49.0(@effect/typeclass@0.40.0(effect@3.22.1))(effect@3.22.1)': - dependencies: - '@effect/printer': 0.49.0(@effect/typeclass@0.40.0(effect@3.22.1))(effect@3.22.1) - '@effect/typeclass': 0.40.0(effect@3.22.1) - effect: 3.22.1 - - '@effect/printer@0.49.0(@effect/typeclass@0.40.0(effect@3.22.1))(effect@3.22.1)': - dependencies: - '@effect/typeclass': 0.40.0(effect@3.22.1) - effect: 3.22.1 - - '@effect/rpc@0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1)': - dependencies: - '@effect/platform': 0.97.1(effect@3.22.1) - effect: 3.22.1 - msgpackr: 1.12.1 - - '@effect/sql@0.51.1(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1)': - dependencies: - '@effect/experimental': 0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1) - '@effect/platform': 0.97.1(effect@3.22.1) - effect: 3.22.1 - uuid: 11.1.1 - - '@effect/typeclass@0.40.0(effect@3.22.1)': - dependencies: - effect: 3.22.1 - - '@effect/vitest@0.30.0(effect@3.22.1)(vitest@4.1.11(@types/node@25.9.5)(vite@8.2.1(@types/node@25.9.5)(esbuild@0.28.2)(tsx@4.23.12)(yaml@2.9.0)))': - dependencies: - effect: 3.22.1 + effect: 4.0.0-rc.111 vitest: 4.1.11(@types/node@25.9.5)(vite@8.2.1(@types/node@25.9.5)(esbuild@0.28.2)(tsx@4.23.12)(yaml@2.9.0)) - '@effect/workflow@0.18.2(@effect/experimental@0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(@effect/platform@0.97.1(effect@3.22.1))(@effect/rpc@0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1))(effect@3.22.1)': - dependencies: - '@effect/experimental': 0.60.0(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1) - '@effect/platform': 0.97.1(effect@3.22.1) - '@effect/rpc': 0.75.1(@effect/platform@0.97.1(effect@3.22.1))(effect@3.22.1) - effect: 3.22.1 - '@esbuild/aix-ppc64@0.28.2': optional: true @@ -1607,62 +1277,6 @@ snapshots: '@oxc-project/types@0.146.0': {} - '@parcel/watcher-android-arm64@2.6.0': - optional: true - - '@parcel/watcher-darwin-arm64@2.6.0': - optional: true - - '@parcel/watcher-darwin-x64@2.6.0': - optional: true - - '@parcel/watcher-freebsd-x64@2.6.0': - optional: true - - '@parcel/watcher-linux-arm-glibc@2.6.0': - optional: true - - '@parcel/watcher-linux-arm-musl@2.6.0': - optional: true - - '@parcel/watcher-linux-arm64-glibc@2.6.0': - optional: true - - '@parcel/watcher-linux-arm64-musl@2.6.0': - optional: true - - '@parcel/watcher-linux-x64-glibc@2.6.0': - optional: true - - '@parcel/watcher-linux-x64-musl@2.6.0': - optional: true - - '@parcel/watcher-win32-arm64@2.6.0': - optional: true - - '@parcel/watcher-win32-x64@2.6.0': - optional: true - - '@parcel/watcher@2.6.0': - dependencies: - detect-libc: 2.1.2 - is-glob: 4.0.3 - node-addon-api: 7.1.1 - picomatch: 4.0.5 - optionalDependencies: - '@parcel/watcher-android-arm64': 2.6.0 - '@parcel/watcher-darwin-arm64': 2.6.0 - '@parcel/watcher-darwin-x64': 2.6.0 - '@parcel/watcher-freebsd-x64': 2.6.0 - '@parcel/watcher-linux-arm-glibc': 2.6.0 - '@parcel/watcher-linux-arm-musl': 2.6.0 - '@parcel/watcher-linux-arm64-glibc': 2.6.0 - '@parcel/watcher-linux-arm64-musl': 2.6.0 - '@parcel/watcher-linux-x64-glibc': 2.6.0 - '@parcel/watcher-linux-x64-musl': 2.6.0 - '@parcel/watcher-win32-arm64': 2.6.0 - '@parcel/watcher-win32-x64': 2.6.0 - '@playwright/test@1.62.1': dependencies: playwright: 1.62.1 @@ -1906,10 +1520,11 @@ snapshots: dts-resolver@3.0.0: {} - effect@3.22.1: + effect@4.0.0-rc.111: dependencies: '@standard-schema/spec': 1.1.0 - fast-check: 3.23.2 + fast-check: 4.9.0 + msgpackr: 2.0.5 empathic@2.0.1: {} @@ -1952,16 +1567,14 @@ snapshots: expect-type@1.4.0: {} - fast-check@3.23.2: + fast-check@4.9.0: dependencies: - pure-rand: 6.1.0 + pure-rand: 8.4.2 fdir@6.5.0(picomatch@4.0.5): optionalDependencies: picomatch: 4.0.5 - find-my-way-ts@0.1.6: {} - fsevents@2.3.2: optional: true @@ -1976,16 +1589,6 @@ snapshots: import-without-cache@0.4.0: {} - ini@4.1.3: {} - - is-extglob@2.1.1: {} - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - kubernetes-types@1.30.0: {} - lightningcss-android-arm64@1.33.0: optional: true @@ -2056,8 +1659,6 @@ snapshots: mdurl@2.1.0: {} - mime@3.0.0: {} - minimatch@10.2.6: dependencies: brace-expansion: 5.0.9 @@ -2074,16 +1675,12 @@ snapshots: '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.4 optional: true - msgpackr@1.12.1: + msgpackr@2.0.5: optionalDependencies: msgpackr-extract: 3.0.4 - multipasta@0.2.8: {} - nanoid@3.3.18: {} - node-addon-api@7.1.1: {} - node-gyp-build-optional-packages@5.2.2: dependencies: detect-libc: 2.1.2 @@ -2117,7 +1714,7 @@ snapshots: punycode.js@2.3.1: {} - pure-rand@6.1.0: {} + pure-rand@8.4.2: {} quansync@1.0.0: {} @@ -2177,8 +1774,6 @@ snapshots: tinyrainbow@3.1.1: {} - toml@3.0.0: {} - tree-kill@1.2.2: {} ts-morph@28.0.0: @@ -2238,10 +1833,6 @@ snapshots: undici-types@7.24.6: {} - undici@7.29.0: {} - - uuid@11.1.1: {} - verkit@0.3.2: {} vite@8.2.1(@types/node@25.9.5)(esbuild@0.28.2)(tsx@4.23.12)(yaml@2.9.0): @@ -2290,8 +1881,6 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 - ws@8.21.3: {} - yaml@2.9.0: {} yuku-ast@0.8.7: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index a8034cf..223ac71 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -3,8 +3,5 @@ allowBuilds: esbuild: false msgpackr-extract: false minimumReleaseAgeExclude: - - "@effect/cli@0.75.2" - - "@effect/cluster@0.59.0" - - "@effect/platform-node-shared@0.60.0" - - "@effect/platform-node@0.107.0" - - "@effect/workflow@0.18.2" + - '@effect/vitest@4.0.0-rc.111' + - effect@4.0.0-rc.111 diff --git a/scripts/coverage.ts b/scripts/coverage.ts index c09be03..5704e90 100644 --- a/scripts/coverage.ts +++ b/scripts/coverage.ts @@ -1,6 +1,5 @@ -import { Command } from "@effect/cli"; -import { FileSystem, Path } from "@effect/platform"; -import { NodeContext, NodeRuntime } from "@effect/platform-node"; +import { existsSync } from "node:fs"; +import { join } from "node:path"; import { Console, Effect } from "effect"; import { type JSDocableNode, Project } from "ts-morph"; @@ -72,12 +71,9 @@ function isDeprecated(node: JSDocableNode): boolean { } const runCoverage = Effect.gen(function* () { - const fs = yield* FileSystem.FileSystem; - const pathService = yield* Path.Path; - const cwd = process.cwd(); - const tsConfigFilePath = pathService.join(cwd, "tsconfig.json"); - const pwTypesPath = pathService.join( + const tsConfigFilePath = join(cwd, "tsconfig.json"); + const pwTypesPath = join( cwd, "node_modules", "playwright-core", @@ -85,8 +81,7 @@ const runCoverage = Effect.gen(function* () { "types.d.ts", ); - const exists = yield* fs.exists(pwTypesPath); - if (!exists) { + if (!existsSync(pwTypesPath)) { return yield* Effect.fail( new Error(`Could not find playwright-core types at ${pwTypesPath}`), ); @@ -247,12 +242,4 @@ const runCoverage = Effect.gen(function* () { ); yield* Console.log("=============================\n"); }); - -const command = Command.make("coverage", {}, () => runCoverage); - -const run = Command.run(command, { - name: "effect-playwright-coverage", - version: "0.1.0", -}); - -run(process.argv).pipe(Effect.provide(NodeContext.layer), NodeRuntime.runMain); +await Effect.runPromise(runCoverage); diff --git a/src/browser-context.test.ts b/src/browser-context.test.ts index 5d46c7d..1857401 100644 --- a/src/browser-context.test.ts +++ b/src/browser-context.test.ts @@ -9,7 +9,7 @@ type TestWindow = Window & { }; layer(PlaywrightSpawner.layer(chromium))("BrowserContext", (it) => { - it.scoped("should wrap context methods", () => + it.effect("should wrap context methods", () => Effect.gen(function* () { const browser = yield* Browser; const context = yield* browser.newContext(); @@ -64,7 +64,7 @@ layer(PlaywrightSpawner.layer(chromium))("BrowserContext", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("addInitScript should execute script in all new pages", () => + it.effect("addInitScript should execute script in all new pages", () => Effect.gen(function* () { const browser = yield* Browser; const context = yield* browser.newContext(); @@ -93,7 +93,7 @@ layer(PlaywrightSpawner.layer(chromium))("BrowserContext", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped( + it.effect( "isClosed should return the closed state of the browser context", () => Effect.gen(function* () { @@ -107,7 +107,7 @@ layer(PlaywrightSpawner.layer(chromium))("BrowserContext", (it) => { assert.strictEqual(context.isClosed(), true); }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("credentials should create, get, and delete credentials", () => + it.effect("credentials should create, get, and delete credentials", () => Effect.gen(function* () { const browser = yield* Browser; const context = yield* browser.newContext(); diff --git a/src/browser-context.ts b/src/browser-context.ts index 7cc464c..758ba50 100644 --- a/src/browser-context.ts +++ b/src/browser-context.ts @@ -5,7 +5,7 @@ * @since 0.1.0 */ -import { Context, Effect, identity, Option, Stream } from "effect"; +import { Context, Effect, identity, Option, Queue, Stream } from "effect"; import type { ConsoleMessage, BrowserContext as CoreBrowserContext, @@ -302,7 +302,7 @@ export interface BrowserContext { * @category services * @since 0.1.0 */ -export const BrowserContext = Context.GenericTag( +export const BrowserContext = Context.Service( "effect-playwright/browser-context/BrowserContext", ); @@ -339,7 +339,7 @@ export const makeBrowserContext = ( ), ).pipe(Effect.asVoid), browser: () => - Option.fromNullable(context.browser()).pipe(Option.map(makeBrowser)), + Option.fromNullishOr(context.browser()).pipe(Option.map(makeBrowser)), clearCookies: (options) => use((c) => c.clearCookies(options)), clearPermissions: use((c) => c.clearPermissions()), cookies: (urls) => use((c) => c.cookies(urls)), @@ -356,19 +356,25 @@ export const makeBrowserContext = ( storageState: (options) => use((c) => c.storageState(options)), setStorageState: (options) => use((c) => c.setStorageState(options)), eventStream: (event: K) => - Stream.asyncPush((emit) => - Effect.acquireRelease( + Stream.callback((queue) => { + const emit = (value: BrowserContextEvents[K]) => { + Queue.offerUnsafe(queue, value); + }; + const end = () => { + Queue.endUnsafe(queue); + }; + return Effect.acquireRelease( Effect.sync(() => { - events.on(event, emit.single); - events.once("close", emit.end); + events.on(event, emit); + events.once("close", end); }), () => Effect.sync(() => { - events.off(event, emit.single); - events.off("close", emit.end); + events.off(event, emit); + events.off("close", end); }), - ), - ).pipe( + ); + }).pipe( Stream.map((value) => { const mapping = eventMappings[event]; // The selected event and mapping share the same generic event key. diff --git a/src/browser.test.ts b/src/browser.test.ts index 0879116..eebe87c 100644 --- a/src/browser.test.ts +++ b/src/browser.test.ts @@ -1,11 +1,11 @@ import { assert, layer } from "@effect/vitest"; -import { Chunk, Effect, Fiber, Stream } from "effect"; +import { Effect, Fiber, Stream } from "effect"; import { chromium } from "playwright-core"; import type { Browser } from "./browser"; import { Playwright } from "./index"; layer(Playwright.layer)("Browser", (it) => { - it.scoped("newPage should create a page", () => + it.effect("newPage should create a page", () => Effect.gen(function* () { const playwright = yield* Playwright.Playwright; const browser = yield* playwright.launchScoped(chromium); @@ -15,7 +15,7 @@ layer(Playwright.layer)("Browser", (it) => { }), ); - it.scoped("use should allow accessing raw browser", () => + it.effect("use should allow accessing raw browser", () => Effect.gen(function* () { const playwright = yield* Playwright.Playwright; const browser = yield* playwright.launchScoped(chromium); @@ -27,7 +27,7 @@ layer(Playwright.layer)("Browser", (it) => { }), ); - it.scoped("browserType should return the browser type", () => + it.effect("browserType should return the browser type", () => Effect.gen(function* () { const playwright = yield* Playwright.Playwright; const browser = yield* playwright.launchScoped(chromium); @@ -37,7 +37,7 @@ layer(Playwright.layer)("Browser", (it) => { }), ); - it.scoped("version should return the browser version", () => + it.effect("version should return the browser version", () => Effect.gen(function* () { const playwright = yield* Playwright.Playwright; const browser = yield* playwright.launchScoped(chromium); @@ -48,7 +48,7 @@ layer(Playwright.layer)("Browser", (it) => { }), ); - it.scoped("close should close the browser", () => + it.effect("close should close the browser", () => Effect.gen(function* () { const playwright = yield* Playwright.Playwright; const browser = yield* playwright.launchScoped(chromium); @@ -61,7 +61,7 @@ layer(Playwright.layer)("Browser", (it) => { assert.isFalse(isConnected); }), ); - it.scoped("contexts should return the list of contexts", () => + it.effect("contexts should return the list of contexts", () => Effect.gen(function* () { const playwright = yield* Playwright.Playwright; const browser = yield* playwright.launchScoped(chromium); @@ -75,7 +75,7 @@ layer(Playwright.layer)("Browser", (it) => { }), ); - it.scoped("newContext should create a new context", () => + it.effect("newContext should create a new context", () => Effect.gen(function* () { const playwright = yield* Playwright.Playwright; const browser = yield* playwright.launchScoped(chromium); @@ -88,7 +88,7 @@ layer(Playwright.layer)("Browser", (it) => { }), ); - it.scoped("newContext should allow creating pages", () => + it.effect("newContext should allow creating pages", () => Effect.gen(function* () { const playwright = yield* Playwright.Playwright; const browser = yield* playwright.launchScoped(chromium); @@ -102,7 +102,7 @@ layer(Playwright.layer)("Browser", (it) => { }), ); - it.scoped("contexts should reflect newPage creation", () => + it.effect("contexts should reflect newPage creation", () => Effect.gen(function* () { const playwright = yield* Playwright.Playwright; const browser = yield* playwright.launchScoped(chromium); @@ -144,20 +144,20 @@ layer(Playwright.layer)("Browser", (it) => { assert.isFalse(isConnected); }), ); - it.scoped("eventStream should emit disconnected event", () => + it.effect("eventStream should emit disconnected event", () => Effect.gen(function* () { const playwright = yield* Playwright.Playwright; const browser = yield* playwright.launchScoped(chromium); const eventsFiber = yield* browser .eventStream("disconnected") - .pipe(Stream.runCollect, Effect.fork); + .pipe(Stream.runCollect, Effect.forkChild); yield* browser.close; const events = yield* Fiber.join(eventsFiber); - assert.strictEqual(Chunk.size(events), 1); + assert.strictEqual(events.length, 1); - const firstEvent = yield* Chunk.head(events); + const firstEvent = events[0]; assert.strictEqual(firstEvent.version(), browser.version()); }), ); diff --git a/src/browser.ts b/src/browser.ts index 97c0c34..a4e61df 100644 --- a/src/browser.ts +++ b/src/browser.ts @@ -5,7 +5,7 @@ * @since 0.1.0 */ -import { Context, Effect, Stream } from "effect"; +import { Context, Effect, Queue, Stream } from "effect"; import type { Scope } from "effect/Scope"; import type { BrowserType, @@ -197,7 +197,7 @@ export interface Browser { * @category services * @since 0.1.0 */ -export const Browser = Context.GenericTag( +export const Browser = Context.Service( "effect-playwright/browser/Browser", ); @@ -220,7 +220,7 @@ export const makeBrowser = (browser: CoreBrowser): Browser => { newContext: (options) => Effect.acquireRelease( use((browser) => browser.newContext(options).then(makeBrowserContext)), - (context) => context.close.pipe(Effect.ignoreLogged), + (context) => context.close.pipe(Effect.ignore({ log: true })), ), browserType: () => browser.browserType(), version: () => browser.version(), @@ -228,19 +228,25 @@ export const makeBrowser = (browser: CoreBrowser): Browser => { bind: (title, options) => use((browser) => browser.bind(title, options)), unbind: use((browser) => browser.unbind()), eventStream: (event: K) => - Stream.asyncPush((emit) => - Effect.acquireRelease( + Stream.callback((queue) => { + const emit = (value: BrowserEvents[K]) => { + Queue.offerUnsafe(queue, value); + }; + const end = () => { + Queue.endUnsafe(queue); + }; + return Effect.acquireRelease( Effect.sync(() => { - events.on(event, emit.single); - events.once("disconnected", emit.end); + events.on(event, emit); + events.once("disconnected", end); }), () => Effect.sync(() => { - events.off(event, emit.single); - events.off("disconnected", emit.end); + events.off(event, emit); + events.off("disconnected", end); }), - ), - ).pipe( + ); + }).pipe( Stream.map((value) => { const mapping = eventMappings[event]; // The selected event and mapping share the same generic event key. diff --git a/src/clock.ts b/src/clock.ts index a85a3ec..693659d 100644 --- a/src/clock.ts +++ b/src/clock.ts @@ -103,7 +103,7 @@ export interface Clock { * @since 0.1.0 * @category services */ -export const Clock = Context.GenericTag("effect-playwright/clock/Clock"); +export const Clock = Context.Service("effect-playwright/clock/Clock"); /** * Creates a `Clock` from a Playwright `Clock` instance. diff --git a/src/common.test.ts b/src/common.test.ts index e5712ce..a16fd5c 100644 --- a/src/common.test.ts +++ b/src/common.test.ts @@ -1,27 +1,31 @@ import { assert, layer } from "@effect/vitest"; -import { Chunk, Effect, Fiber, Option, Stream } from "effect"; +import { Effect, Fiber, Option, Stream } from "effect"; import { PlaywrightSpawner } from "effect-playwright"; import { chromium } from "playwright-core"; import { Browser } from "./browser"; layer(PlaywrightSpawner.layer(chromium))("PlaywrightCommon", (it) => { - it.scoped("Request and Response", () => + it.effect("Request and Response", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); const requestFiber = yield* page .eventStream("request") - .pipe(Stream.runHead, Effect.fork); + .pipe(Stream.runHead, Effect.forkChild); const responseFiber = yield* page .eventStream("response") - .pipe(Stream.runHead, Effect.fork); + .pipe(Stream.runHead, Effect.forkChild); yield* page.goto("http://example.com"); - const request = yield* Fiber.join(requestFiber).pipe(Effect.flatten); - const response = yield* Fiber.join(responseFiber).pipe(Effect.flatten); + const request = yield* Fiber.join(requestFiber).pipe( + Effect.flatMap(Effect.fromOption), + ); + const response = yield* Fiber.join(responseFiber).pipe( + Effect.flatMap(Effect.fromOption), + ); assert.strictEqual(request._tag, "effect-playwright/common/Request"); assert.strictEqual(response._tag, "effect-playwright/common/Response"); @@ -53,14 +57,14 @@ layer(PlaywrightSpawner.layer(chromium))("PlaywrightCommon", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("Worker", () => + it.effect("Worker", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); const workerFiber = yield* page .eventStream("worker") - .pipe(Stream.runHead, Effect.fork); + .pipe(Stream.runHead, Effect.forkChild); yield* page.evaluate(() => { const blob = new Blob(['console.log("worker")'], { @@ -69,7 +73,9 @@ layer(PlaywrightSpawner.layer(chromium))("PlaywrightCommon", (it) => { new Worker(URL.createObjectURL(blob)); }); - const worker = yield* Fiber.join(workerFiber).pipe(Effect.flatten); + const worker = yield* Fiber.join(workerFiber).pipe( + Effect.flatMap(Effect.fromOption), + ); assert.strictEqual(worker._tag, "effect-playwright/common/Worker"); assert(worker.url().startsWith("blob:")); @@ -78,20 +84,22 @@ layer(PlaywrightSpawner.layer(chromium))("PlaywrightCommon", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("Dialog", () => + it.effect("Dialog", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); const dialogFiber = yield* page .eventStream("dialog") - .pipe(Stream.runHead, Effect.fork); + .pipe(Stream.runHead, Effect.forkChild); yield* page.evaluate(() => { setTimeout(() => alert("hello world"), 10); }); - const dialog = yield* Fiber.join(dialogFiber).pipe(Effect.flatten); + const dialog = yield* Fiber.join(dialogFiber).pipe( + Effect.flatMap(Effect.fromOption), + ); assert.strictEqual(dialog._tag, "effect-playwright/common/Dialog"); assert(dialog.message() === "hello world"); @@ -101,7 +109,7 @@ layer(PlaywrightSpawner.layer(chromium))("PlaywrightCommon", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("FileChooser", () => + it.effect("FileChooser", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -112,12 +120,12 @@ layer(PlaywrightSpawner.layer(chromium))("PlaywrightCommon", (it) => { const fileChooserFiber = yield* page .eventStream("filechooser") - .pipe(Stream.runHead, Effect.fork); + .pipe(Stream.runHead, Effect.forkChild); yield* page.locator("#fileinput").click(); const fileChooser = yield* Fiber.join(fileChooserFiber).pipe( - Effect.flatten, + Effect.flatMap(Effect.fromOption), ); assert.strictEqual( fileChooser._tag, @@ -129,7 +137,7 @@ layer(PlaywrightSpawner.layer(chromium))("PlaywrightCommon", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("Download", () => + it.effect("Download", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -141,11 +149,13 @@ layer(PlaywrightSpawner.layer(chromium))("PlaywrightCommon", (it) => { const downloadFiber = yield* page .eventStream("download") - .pipe(Stream.runHead, Effect.fork); + .pipe(Stream.runHead, Effect.forkChild); yield* page.locator("#download").click(); - const download = yield* Fiber.join(downloadFiber).pipe(Effect.flatten); + const download = yield* Fiber.join(downloadFiber).pipe( + Effect.flatMap(Effect.fromOption), + ); assert.strictEqual(download._tag, "effect-playwright/common/Download"); assert(download.suggestedFilename() === "test.txt"); @@ -155,7 +165,7 @@ layer(PlaywrightSpawner.layer(chromium))("PlaywrightCommon", (it) => { const text = yield* download.stream.pipe( Stream.decodeText(), Stream.runCollect, - Effect.map(Chunk.join("")), + Effect.map((chunks) => chunks.join("")), ); assert.strictEqual(text, "hello world"); diff --git a/src/common.ts b/src/common.ts index 6b48d91..65eebde 100644 --- a/src/common.ts +++ b/src/common.ts @@ -155,42 +155,42 @@ export class Request extends Data.TaggedClass( return new Request({ allHeaders: use(() => request.allHeaders()), existingResponse: (): Option.Option => - Option.fromNullable(request.existingResponse()).pipe( + Option.fromNullishOr(request.existingResponse()).pipe( Option.map(Response.make), ), - failure: Option.liftNullable(request.failure), + failure: Option.liftNullishOr(request.failure), frame: Effect.try({ try: () => makeFrame(request.frame()), catch: wrapError, }), headerValue: (name) => use(() => request.headerValue(name)).pipe( - Effect.map(Option.fromNullable), + Effect.map(Option.fromNullishOr), ), headers: () => request.headers(), headersArray: use(() => request.headersArray()), isNavigationRequest: () => request.isNavigationRequest(), method: () => request.method(), - postData: Option.liftNullable(request.postData), - postDataBuffer: Option.liftNullable(request.postDataBuffer), + postData: Option.liftNullishOr(request.postData), + postDataBuffer: Option.liftNullishOr(request.postDataBuffer), postDataJSON: use(() => request.postDataJSON()).pipe( - Effect.map(Option.fromNullable), + Effect.map(Option.fromNullishOr), ), redirectedFrom: (): Option.Option => - Option.fromNullable(request.redirectedFrom()).pipe( + Option.fromNullishOr(request.redirectedFrom()).pipe( Option.map(Request.make), ), redirectedTo: (): Option.Option => - Option.fromNullable(request.redirectedTo()).pipe( + Option.fromNullishOr(request.redirectedTo()).pipe( Option.map(Request.make), ), resourceType: () => request.resourceType(), response: use(() => request.response()).pipe( - Effect.map(Option.fromNullable), + Effect.map(Option.fromNullishOr), Effect.map(Option.map(Response.make)), ), serviceWorker: () => - Option.fromNullable(request.serviceWorker()).pipe( + Option.fromNullishOr(request.serviceWorker()).pipe( Option.map(Worker.make), ), sizes: use(() => request.sizes()), @@ -284,7 +284,7 @@ export class Response extends Data.TaggedClass( headersArray: use(() => response.headersArray()), headerValue: (name) => use(() => response.headerValue(name)).pipe( - Effect.map(Option.fromNullable), + Effect.map(Option.fromNullishOr), ), headerValues: (name) => use(() => response.headerValues(name)), httpVersion: use(() => response.httpVersion()), @@ -292,10 +292,10 @@ export class Response extends Data.TaggedClass( ok: () => response.ok(), request: () => Request.make(response.request()), securityDetails: use(() => response.securityDetails()).pipe( - Effect.map(Option.fromNullable), + Effect.map(Option.fromNullishOr), ), serverAddr: use(() => response.serverAddr()).pipe( - Effect.map(Option.fromNullable), + Effect.map(Option.fromNullishOr), ), status: () => response.status(), statusText: () => response.statusText(), @@ -357,7 +357,8 @@ export class Dialog extends Data.TaggedClass( defaultValue: () => dialog.defaultValue(), dismiss: use(() => dialog.dismiss()), message: () => dialog.message(), - page: () => Option.fromNullable(dialog.page()).pipe(Option.map(makePage)), + page: () => + Option.fromNullishOr(dialog.page()).pipe(Option.map(makePage)), type: () => dialog.type(), }); } @@ -425,19 +426,19 @@ export class Download extends Data.TaggedClass( download.createReadStream().then((s) => Readable.toWeb(s)), ).pipe( Effect.map((s) => - Stream.fromReadableStream( - () => s as ReadableStream, - wrapError, - ), + Stream.fromReadableStream({ + evaluate: () => s as ReadableStream, + onError: wrapError, + }), ), Stream.unwrap, ), delete: use(() => download.delete()), failure: use(() => download.failure()).pipe( - Effect.map(Option.fromNullable), + Effect.map(Option.fromNullishOr), ), page: () => makePage(download.page()), - path: use(() => download.path()).pipe(Effect.map(Option.fromNullable)), + path: use(() => download.path()).pipe(Effect.map(Option.fromNullishOr)), saveAs: (path) => use(() => download.saveAs(path)), suggestedFilename: () => download.suggestedFilename(), url: () => download.url(), diff --git a/src/credentials.ts b/src/credentials.ts index a2369ad..3789d05 100644 --- a/src/credentials.ts +++ b/src/credentials.ts @@ -86,7 +86,7 @@ export interface Credentials { * @category services * @since 0.5.1 */ -export const Credentials = Context.GenericTag( +export const Credentials = Context.Service( "effect-playwright/credentials/Credentials", ); diff --git a/src/event-stream.test.ts b/src/event-stream.test.ts index d6c2a32..a0a0976 100644 --- a/src/event-stream.test.ts +++ b/src/event-stream.test.ts @@ -1,11 +1,11 @@ import { layer } from "@effect/vitest"; -import { Effect, Stream } from "effect"; +import { Effect, Fiber, Stream } from "effect"; import { PlaywrightSpawner } from "effect-playwright"; import { chromium } from "playwright-core"; import { Browser } from "./browser"; layer(PlaywrightSpawner.layer(chromium))("eventStream", (it) => { - it.scoped("should complete when the page closes", () => + it.effect("should complete when the page closes", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -14,19 +14,19 @@ layer(PlaywrightSpawner.layer(chromium))("eventStream", (it) => { const stream = page.eventStream("console"); // Run the stream in the background - const fiber = yield* Stream.runCollect(stream).pipe(Effect.fork); + const fiber = yield* Stream.runCollect(stream).pipe(Effect.forkChild); // Close the page yield* page.close; // Wait for the stream to complete - yield* fiber.await; + yield* Fiber.await(fiber); // test will timeout if the stream does not complete }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("should complete when the browser closes", () => + it.effect("should complete when the browser closes", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -35,13 +35,13 @@ layer(PlaywrightSpawner.layer(chromium))("eventStream", (it) => { const stream = page.eventStream("console"); // Run the stream in the background - const fiber = yield* Stream.runCollect(stream).pipe(Effect.fork); + const fiber = yield* Stream.runCollect(stream).pipe(Effect.forkChild); // Close the browser yield* browser.close; // Wait for the stream to complete - yield* fiber.await; + yield* Fiber.await(fiber); // test will timeout if the stream does not complete }).pipe(PlaywrightSpawner.withBrowser), diff --git a/src/experimental/browser-utils.test.ts b/src/experimental/browser-utils.test.ts index fd49b39..1b4c8b5 100644 --- a/src/experimental/browser-utils.test.ts +++ b/src/experimental/browser-utils.test.ts @@ -1,11 +1,11 @@ import { assert, layer } from "@effect/vitest"; -import { Chunk, Effect, Fiber, Stream } from "effect"; +import { Effect, Fiber, Stream } from "effect"; import { chromium } from "playwright-core"; import { Playwright } from "../index"; import * as BrowserUtils from "./browser-utils"; layer(Playwright.layer)("BrowserUtils", (it) => { - it.scoped("allPages should return all pages from all contexts", () => + it.effect("allPages should return all pages from all contexts", () => Effect.gen(function* () { const playwright = yield* Playwright.Playwright; const browser = yield* playwright.launchScoped(chromium); @@ -22,7 +22,7 @@ layer(Playwright.layer)("BrowserUtils", (it) => { }), ); - it.scoped("allFrames should return all frames from all pages", () => + it.effect("allFrames should return all frames from all pages", () => Effect.gen(function* () { const playwright = yield* Playwright.Playwright; const browser = yield* playwright.launchScoped(chromium); @@ -38,7 +38,7 @@ layer(Playwright.layer)("BrowserUtils", (it) => { }), ); - it.scoped( + it.effect( "allFrameNavigatedEventStream should capture navigations from existing and new pages across multiple contexts", () => Effect.gen(function* () { @@ -52,7 +52,10 @@ layer(Playwright.layer)("BrowserUtils", (it) => { // Start the event stream const stream = BrowserUtils.allFrameNavigatedEventStream(browser); - const eventFiber = yield* stream.pipe(Stream.runCollect, Effect.fork); + const eventFiber = yield* stream.pipe( + Stream.runCollect, + Effect.forkChild, + ); // 1. Navigate existing page yield* page1.goto( @@ -82,11 +85,11 @@ layer(Playwright.layer)("BrowserUtils", (it) => { yield* browser.close; const events = yield* Fiber.join(eventFiber); - assert.strictEqual(Chunk.size(events), 4); + assert.strictEqual(events.length, 4); }), ); - it.scoped("page eventStream should capture framenavigated", () => + it.effect("page eventStream should capture framenavigated", () => Effect.gen(function* () { const playwright = yield* Playwright.Playwright; const browser = yield* playwright.launchScoped(chromium); @@ -94,12 +97,12 @@ layer(Playwright.layer)("BrowserUtils", (it) => { const fiber = yield* BrowserUtils.allFrameNavigatedEventStream( browser, - ).pipe(Stream.take(1), Stream.runCollect, Effect.fork); + ).pipe(Stream.take(1), Stream.runCollect, Effect.forkChild); yield* page.goto("https://example.com"); const events = yield* Fiber.join(fiber); - assert.strictEqual(Chunk.size(events), 1); + assert.strictEqual(events.length, 1); }), ); }); diff --git a/src/frame-locator.ts b/src/frame-locator.ts index 1b56fa0..fa328ff 100644 --- a/src/frame-locator.ts +++ b/src/frame-locator.ts @@ -157,7 +157,7 @@ export interface FrameLocator { * @since 0.1.0 * @category services */ -export const FrameLocator = Context.GenericTag( +export const FrameLocator = Context.Service( "effect-playwright/frame-locator/FrameLocator", ); diff --git a/src/frame.test.ts b/src/frame.test.ts index cbf84e6..c805b85 100644 --- a/src/frame.test.ts +++ b/src/frame.test.ts @@ -6,7 +6,7 @@ import { Browser } from "./browser"; import type { Frame } from "./frame"; layer(PlaywrightSpawner.layer(chromium))("Frame", (it) => { - it.scoped("should wrap frame methods", () => + it.effect("should wrap frame methods", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -30,7 +30,7 @@ layer(PlaywrightSpawner.layer(chromium))("Frame", (it) => { Effect.succeed(f.name() === "test-frame"); const frame = yield* Effect.findFirst(frames, isTestFrame).pipe( - Effect.flatten, + Effect.flatMap(Effect.fromOption), Effect.retry({ times: 3, }), @@ -122,7 +122,7 @@ layer(PlaywrightSpawner.layer(chromium))("Frame", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped( + it.effect( "evaluate should expose a function-valued argument in the frame context", () => Effect.gen(function* () { @@ -141,7 +141,7 @@ layer(PlaywrightSpawner.layer(chromium))("Frame", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("waitForLoadState should resolve on frame", () => + it.effect("waitForLoadState should resolve on frame", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); diff --git a/src/frame.ts b/src/frame.ts index d069303..00c4bc4 100644 --- a/src/frame.ts +++ b/src/frame.ts @@ -262,7 +262,7 @@ export interface Frame { * @category services * @since 0.1.2 */ -export const Frame = Context.GenericTag("effect-playwright/frame/Frame"); +export const Frame = Context.Service("effect-playwright/frame/Frame"); /** * Creates a `Frame` from a Playwright `Frame` instance. @@ -307,7 +307,7 @@ export const makeFrame = (frame: CoreFrame): Frame => { getByTitle: (text, options) => makeLocator(frame.getByTitle(text, options)), page: () => makePage(frame.page()), parentFrame: () => - Option.fromNullable(frame.parentFrame()).pipe(Option.map(makeFrame)), + Option.fromNullishOr(frame.parentFrame()).pipe(Option.map(makeFrame)), childFrames: () => Array.map(frame.childFrames(), (f) => makeFrame(f)), isDetached: () => frame.isDetached(), waitForTimeout: (timeout) => use((f) => f.waitForTimeout(timeout)), diff --git a/src/keyboard.ts b/src/keyboard.ts index 6b0a889..4ab1842 100644 --- a/src/keyboard.ts +++ b/src/keyboard.ts @@ -66,7 +66,7 @@ export interface Keyboard { /** * @category services */ -export const Keyboard = Context.GenericTag( +export const Keyboard = Context.Service( "effect-playwright/keyboard/Keyboard", ); diff --git a/src/locator.test.ts b/src/locator.test.ts index 563eaff..406fe83 100644 --- a/src/locator.test.ts +++ b/src/locator.test.ts @@ -6,7 +6,7 @@ import { chromium } from "playwright-core"; import { Browser } from "./browser"; layer(PlaywrightSpawner.layer(chromium))("Locator", (it) => { - it.scoped("should work", () => + it.effect("should work", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -19,7 +19,7 @@ layer(PlaywrightSpawner.layer(chromium))("Locator", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("evaluate", () => + it.effect("evaluate", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -41,7 +41,7 @@ layer(PlaywrightSpawner.layer(chromium))("Locator", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("waitFor", () => + it.effect("waitFor", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -69,7 +69,7 @@ layer(PlaywrightSpawner.layer(chromium))("Locator", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("waitForFunction", () => + it.effect("waitForFunction", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -92,7 +92,7 @@ layer(PlaywrightSpawner.layer(chromium))("Locator", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("evaluate options expose function arguments", () => + it.effect("evaluate options expose function arguments", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -118,7 +118,7 @@ layer(PlaywrightSpawner.layer(chromium))("Locator", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("kitchensink", () => + it.effect("kitchensink", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -348,7 +348,7 @@ layer(PlaywrightSpawner.layer(chromium))("Locator", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped( + it.effect( "new methods: all, and, filter, or, page, frameLocator, contentFrame", () => Effect.gen(function* () { @@ -357,12 +357,12 @@ layer(PlaywrightSpawner.layer(chromium))("Locator", (it) => { yield* page.evaluate(() => { document.body.innerHTML = ` -
- - - -
- `; +
+ + + +
+ `; }); const buttons = page.locator(".btn"); @@ -409,7 +409,7 @@ layer(PlaywrightSpawner.layer(chromium))("Locator", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("action methods", () => + it.effect("action methods", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); diff --git a/src/locator.ts b/src/locator.ts index 844f5ae..7a14fe7 100644 --- a/src/locator.ts +++ b/src/locator.ts @@ -736,7 +736,7 @@ export interface Locator { * @since 0.1.0 * @category services */ -export const Locator = Context.GenericTag( +export const Locator = Context.Service( "effect-playwright/locator/Locator", ); @@ -789,10 +789,10 @@ export const makeLocator = (locator: CoreLocator): Locator => { ariaSnapshot: (options) => use((locator) => locator.ariaSnapshot(options)), boundingBox: (options) => use((locator) => locator.boundingBox(options)).pipe( - Effect.map(Option.fromNullable), + Effect.map(Option.fromNullishOr), ), describe: (description) => makeLocator(locator.describe(description)), - description: () => Option.fromNullable(locator.description()), + description: () => Option.fromNullishOr(locator.description()), count: use((locator) => locator.count()), first: () => makeLocator(locator.first()), last: () => makeLocator(locator.last()), @@ -903,7 +903,7 @@ export const makeLocator = (locator: CoreLocator): Locator => { ), elementHandle: (options) => use((locator) => locator.elementHandle(options)).pipe( - Effect.map(Option.fromNullable), + Effect.map(Option.fromNullishOr), ), elementHandles: () => use( diff --git a/src/mouse.ts b/src/mouse.ts index 3860009..746f964 100644 --- a/src/mouse.ts +++ b/src/mouse.ts @@ -80,7 +80,7 @@ export interface Mouse { /** * @category services */ -export const Mouse = Context.GenericTag("effect-playwright/mouse/Mouse"); +export const Mouse = Context.Service("effect-playwright/mouse/Mouse"); /** * Creates a `Mouse` from a Playwright `Mouse` instance. diff --git a/src/page.test.ts b/src/page.test.ts index bf28cba..8aae3fe 100644 --- a/src/page.test.ts +++ b/src/page.test.ts @@ -12,7 +12,7 @@ type TestWindow = Window & { }; layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { - it.scoped("goto should navigate to a URL", () => + it.effect("goto should navigate to a URL", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -25,7 +25,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("setContent should set the page content", () => + it.effect("setContent should set the page content", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -36,7 +36,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("title should return the page title", () => + it.effect("title should return the page title", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -47,7 +47,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("content should return the page content", () => + it.effect("content should return the page content", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -60,7 +60,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("click should click an element", () => + it.effect("click should click an element", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -81,7 +81,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("goto should work with options", () => + it.effect("goto should work with options", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -92,7 +92,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("waitForTimeout should wait", () => + it.effect("waitForTimeout should wait", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -104,7 +104,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped( + it.effect( "evaluate should run code in the page context with destructured arg", () => Effect.gen(function* () { @@ -119,7 +119,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("evaluate should run code with a single value arg", () => + it.effect("evaluate should run code with a single value arg", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -129,7 +129,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped( + it.effect( "evaluate should expose a function-valued argument in the page context", () => Effect.gen(function* () { @@ -147,7 +147,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("click should work with options", () => + it.effect("click should work with options", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -172,7 +172,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("use should allow accessing raw playwright page", () => + it.effect("use should allow accessing raw playwright page", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -182,7 +182,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("locator should work with options", () => + it.effect("locator should work with options", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -203,7 +203,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("getBy* methods should work", () => + it.effect("getBy* methods should work", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -248,7 +248,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("waitForURL should work with History API", () => + it.effect("waitForURL should work with History API", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -264,7 +264,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("filechooser event should work", () => + it.effect("filechooser event should work", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -275,17 +275,19 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { const fileChooser = yield* page .eventStream("filechooser") - .pipe(Stream.runHead, Effect.fork); + .pipe(Stream.runHead, Effect.forkChild); yield* page.locator("#fileinput").click(); - const results = yield* Fiber.join(fileChooser).pipe(Effect.flatten); + const results = yield* Fiber.join(fileChooser).pipe( + Effect.flatMap(Effect.fromOption), + ); assert(results.isMultiple() === false, "isMultiple should be false"); }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("waitForLoadState should resolve", () => + it.effect("waitForLoadState should resolve", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -301,7 +303,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { assert.ok(true); }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("url property should update after navigation", () => + it.effect("url property should update after navigation", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -316,7 +318,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("goBack and goForward should navigate through history", () => + it.effect("goBack and goForward should navigate through history", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -336,7 +338,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("requestGC should execute without error", () => + it.effect("requestGC should execute without error", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -346,7 +348,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("clock should allow fast forwarding time", () => + it.effect("clock should allow fast forwarding time", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -375,7 +377,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("clock should allow fast forwarding time on context", () => + it.effect("clock should allow fast forwarding time on context", () => Effect.gen(function* () { const browser = yield* Browser; const context = yield* browser.newContext(); @@ -407,7 +409,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("addInitScript should execute script before page load", () => + it.effect("addInitScript should execute script before page load", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -429,7 +431,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("keyboard should allow typing text", () => + it.effect("keyboard should allow typing text", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -448,7 +450,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("mouse should allow dispatching events", () => + it.effect("mouse should allow dispatching events", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -473,7 +475,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("touchscreen should allow dispatching events", () => + it.effect("touchscreen should allow dispatching events", () => Effect.gen(function* () { const browser = yield* Browser; const context = yield* browser.newContext({ hasTouch: true }); @@ -509,7 +511,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("screenshot should capture an image", () => + it.effect("screenshot should capture an image", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -522,7 +524,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("pdf should capture a PDF", () => + it.effect("pdf should capture a PDF", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -535,7 +537,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("addScriptTag should add a script tag to the page", () => + it.effect("addScriptTag should add a script tag to the page", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -551,7 +553,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("addStyleTag should add a style tag to the page", () => + it.effect("addStyleTag should add a style tag to the page", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -573,7 +575,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { assert.strictEqual(color, "rgb(255, 0, 0)"); }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("bringToFront should bring the page to the front", () => + it.effect("bringToFront should bring the page to the front", () => Effect.gen(function* () { const browser = yield* Browser; const context = yield* browser.newContext(); @@ -588,7 +590,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("consoleMessages should return console messages", () => + it.effect("consoleMessages should return console messages", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -608,7 +610,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("pageerror event should work", () => + it.effect("pageerror event should work", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -617,7 +619,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { const errorFiber = yield* page .eventStream("pageerror") - .pipe(Stream.runHead, Effect.fork); + .pipe(Stream.runHead, Effect.forkChild); yield* page.evaluate(() => { setTimeout(() => { @@ -631,7 +633,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("pageErrors should return all page errors", () => + it.effect("pageErrors should return all page errors", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -640,7 +642,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { const errorFiber = yield* page .eventStream("pageerror") - .pipe(Stream.runHead, Effect.fork); + .pipe(Stream.runHead, Effect.forkChild); yield* page.evaluate(() => { setTimeout(() => { @@ -656,7 +658,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("context should return the associated browser context", () => + it.effect("context should return the associated browser context", () => Effect.gen(function* () { const browser = yield* Browser; const context = yield* browser.newContext(); @@ -671,7 +673,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("dragAndDrop should drag and drop an element", () => + it.effect("dragAndDrop should drag and drop an element", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -703,7 +705,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("emulateMedia should emulate media features", () => + it.effect("emulateMedia should emulate media features", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -728,7 +730,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped( + it.effect( "exposeFunction should expose an function that runs an effect", () => Effect.gen(function* () { @@ -751,7 +753,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("exposeFunction should work with Effect.fn", () => + it.effect("exposeFunction should work with Effect.fn", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -776,7 +778,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("exposeEffect should expose an effect", () => + it.effect("exposeEffect should expose an effect", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -798,7 +800,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("frame should return an Option of Frame", () => + it.effect("frame should return an Option of Frame", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -818,7 +820,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("isClosed should return the closed state of the page", () => + it.effect("isClosed should return the closed state of the page", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -831,7 +833,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("mainFrame should return the main frame", () => + it.effect("mainFrame should return the main frame", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -844,7 +846,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("opener should return the opener page", () => + it.effect("opener should return the opener page", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -853,7 +855,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { const popupFiber = yield* page .eventStream("popup") - .pipe(Stream.runHead, Effect.fork); + .pipe(Stream.runHead, Effect.forkChild); yield* page.evaluate(() => { window.open("about:blank"); @@ -871,7 +873,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("setViewportSize should update viewport dimensions", () => + it.effect("setViewportSize should update viewport dimensions", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -887,7 +889,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("viewportSize should return the current viewport size", () => + it.effect("viewportSize should return the current viewport size", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -902,7 +904,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("setExtraHTTPHeaders should not crash", () => + it.effect("setExtraHTTPHeaders should not crash", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -912,7 +914,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("setDefaultNavigationTimeout should not crash", () => + it.effect("setDefaultNavigationTimeout should not crash", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -922,7 +924,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("setDefaultTimeout should influence timeouts", () => + it.effect("setDefaultTimeout should influence timeouts", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); @@ -938,14 +940,14 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("workers should return the list of workers", () => + it.effect("workers should return the list of workers", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); const workerFiber = yield* page .eventStream("worker") - .pipe(Stream.runHead, Effect.fork); + .pipe(Stream.runHead, Effect.forkChild); yield* page.goto( "data:text/html,", @@ -958,7 +960,7 @@ layer(PlaywrightSpawner.layer(chromium))("Page", (it) => { assert.strictEqual(typeof workers[0].url(), "string"); }).pipe(PlaywrightSpawner.withBrowser), ); - it.scoped("web storage should round-trip items on a page origin", () => + it.effect("web storage should round-trip items on a page origin", () => Effect.gen(function* () { const browser = yield* Browser; const page = yield* browser.newPage(); diff --git a/src/page.ts b/src/page.ts index 72f09c8..907cc8c 100644 --- a/src/page.ts +++ b/src/page.ts @@ -11,7 +11,7 @@ import { Effect, identity, Option, - Runtime, + Queue, Stream, } from "effect"; import type { @@ -365,10 +365,10 @@ export interface Page { * import { Playwright } from "effect-playwright"; * * // A custom Database service used in your Effect application - * class Database extends Context.Tag("Database")< + * class Database extends Context.Service< * Database, * { readonly insertProduct: (name: string, price: number) => Effect.Effect } - * >() {} + * >()("Database") {} * * const program = Effect.gen(function* () { * const browser = yield* Playwright.Browser; @@ -859,7 +859,7 @@ export interface Page { * @category services * @since 0.1.0 */ -export const Page = Context.GenericTag("effect-playwright/page/Page"); +export const Page = Context.Service("effect-playwright/page/Page"); /** * Creates a `Page` from a Playwright `Page` instance. @@ -891,7 +891,7 @@ export const makePage = (page: CorePage): Page => { use((page) => page.setExtraHTTPHeaders(headers)), setViewportSize: (viewportSize) => use((page) => page.setViewportSize(viewportSize)), - viewportSize: () => Option.fromNullable(page.viewportSize()), + viewportSize: () => Option.fromNullishOr(page.viewportSize()), waitForURL: (url, options) => use((page) => page.waitForURL(url, options)), waitForLoadState: (state, options) => use((page) => page.waitForLoadState(state, options)), @@ -927,8 +927,8 @@ export const makePage = (page: CorePage): Page => { name: string, effectFn: (...args: Args) => Effect.Effect, ) => - Effect.runtime().pipe( - Effect.map((runtime) => Runtime.runPromise(runtime)), + Effect.context().pipe( + Effect.map((context) => Effect.runPromiseWith(context)), Effect.flatMap((runPromise) => use((page) => page.exposeFunction(name, (...args: Args) => @@ -938,8 +938,8 @@ export const makePage = (page: CorePage): Page => { ), ), exposeEffect: (name: string, effectFn: Effect.Effect) => - Effect.runtime().pipe( - Effect.map((runtime) => Runtime.runPromise(runtime)), + Effect.context().pipe( + Effect.map((context) => Effect.runPromiseWith(context)), Effect.flatMap((runPromise) => use((page) => page.exposeFunction(name, () => runPromise(effectFn))), ), @@ -970,12 +970,12 @@ export const makePage = (page: CorePage): Page => { ariaSnapshot: (options) => use((page) => page.ariaSnapshot(options)), context: () => makeBrowserContext(page.context()), opener: use((page) => page.opener()).pipe( - Effect.map(Option.fromNullable), + Effect.map(Option.fromNullishOr), Effect.map(Option.map(makePage)), ), workers: () => page.workers().map(Worker.make), frame: (frameSelector) => - Option.fromNullable(page.frame(frameSelector)).pipe( + Option.fromNullishOr(page.frame(frameSelector)).pipe( Option.map(makeFrame), ), frames: use((page) => Promise.resolve(page.frames().map(makeFrame))), @@ -983,12 +983,12 @@ export const makePage = (page: CorePage): Page => { reload: use((page) => page.reload()), goBack: (options) => use((page) => page.goBack(options)).pipe( - Effect.map(Option.fromNullable), + Effect.map(Option.fromNullishOr), Effect.map(Option.map(Response.make)), ), goForward: (options) => use((page) => page.goForward(options)).pipe( - Effect.map(Option.fromNullable), + Effect.map(Option.fromNullishOr), Effect.map(Option.map(Response.make)), ), requestGC: use((page) => page.requestGC()), @@ -1002,20 +1002,26 @@ export const makePage = (page: CorePage): Page => { use((page) => page.dragAndDrop(source, target, options)), click: (selector, options) => use((page) => page.click(selector, options)), emulateMedia: (options) => use((page) => page.emulateMedia(options)), - eventStream: (event: K) => - Stream.asyncPush((emit) => - Effect.acquireRelease( + eventStream: (event: K) => + Stream.callback((queue) => { + const emit = (value: CorePageEventMap[K]) => { + Queue.offerUnsafe(queue, value); + }; + const end = () => { + Queue.endUnsafe(queue); + }; + return Effect.acquireRelease( Effect.sync(() => { - events.on(event, emit.single); - events.once("close", emit.end); + events.on(event, emit); + events.once("close", end); }), () => Effect.sync(() => { - events.off(event, emit.single); - events.off("close", emit.end); + events.off(event, emit); + events.off("close", end); }), - ), - ).pipe( + ); + }).pipe( Stream.map((value) => { const mapping = eventMappings[event]; // The selected event and mapping share the same generic event key. diff --git a/src/playwright-spawner.test.ts b/src/playwright-spawner.test.ts index 55bbf01..2e64e7c 100644 --- a/src/playwright-spawner.test.ts +++ b/src/playwright-spawner.test.ts @@ -44,7 +44,7 @@ const accessSecond = Effect.gen(function* () { }); layer(PlaywrightSpawner.layer(chromium))("PlaywrightSpawner", (it) => { - it.scoped("should launch a browser", () => + it.effect("should launch a browser", () => Effect.gen(function* () { const program = Effect.gen(function* () { const spawner: PlaywrightSpawner.PlaywrightSpawner = diff --git a/src/playwright-spawner.ts b/src/playwright-spawner.ts index 855f153..bf7335a 100644 --- a/src/playwright-spawner.ts +++ b/src/playwright-spawner.ts @@ -31,7 +31,7 @@ export interface PlaywrightSpawner { * @category services * @since 0.7.0 */ -export const PlaywrightSpawner = Context.GenericTag( +export const PlaywrightSpawner = Context.Service( "effect-playwright/playwright-spawner/PlaywrightSpawner", ); diff --git a/src/playwright.test.ts b/src/playwright.test.ts index dade632..3ca1077 100644 --- a/src/playwright.test.ts +++ b/src/playwright.test.ts @@ -5,7 +5,7 @@ import { chromium } from "playwright-core"; import type { BrowserContext } from "./browser-context"; layer(Playwright.layer)("Playwright", (it) => { - it.scoped("should launch a browser", () => + it.effect("should launch a browser", () => Effect.gen(function* () { const program = Effect.gen(function* () { const playwright: Playwright.Playwright = yield* Playwright.Playwright; @@ -77,7 +77,7 @@ layer(Playwright.layer)("Playwright", (it) => { }), ); - it.scoped("should launch and run some commands", () => + it.effect("should launch and run some commands", () => Effect.gen(function* () { const program = Effect.gen(function* () { const playwright = yield* Playwright.Playwright; @@ -97,7 +97,7 @@ layer(Playwright.layer)("Playwright", (it) => { }), ); - it.scoped("should launch a persistent context", () => + it.effect("should launch a persistent context", () => Effect.gen(function* () { const playwright = yield* Playwright.Playwright; const context = yield* playwright.launchPersistentContext(chromium, ""); @@ -111,7 +111,7 @@ layer(Playwright.layer)("Playwright", (it) => { }), ); - it.scoped("should launch a persistent context and close with scope", () => + it.effect("should launch a persistent context and close with scope", () => Effect.gen(function* () { const playwright = yield* Playwright.Playwright; let capturedContext: BrowserContext | undefined; @@ -137,7 +137,7 @@ layer(Playwright.layer)("Playwright", (it) => { }), ); - it.scoped("should fail to launch a browser with invalid path", () => + it.effect("should fail to launch a browser with invalid path", () => Effect.gen(function* () { const playwright = yield* Playwright.Playwright; const result: Playwright.PlaywrightError = yield* playwright @@ -152,7 +152,7 @@ layer(Playwright.layer)("Playwright", (it) => { }), ); - it.scoped("should fail with timeout 1", () => + it.effect("should fail with timeout 1", () => Effect.gen(function* () { const playwright = yield* Playwright.Playwright; const result = yield* playwright @@ -169,7 +169,7 @@ layer(Playwright.layer)("Playwright", (it) => { }), ); - it.scoped( + it.effect( "should connect via CDP (confirm browser.close only closes CDP connection)", Effect.fn(function* () { const playwright = yield* Playwright.Playwright; @@ -199,7 +199,7 @@ layer(Playwright.layer)("Playwright", (it) => { }), ); - it.scoped( + it.effect( "should connect via CDP and close automatically with scope", Effect.fn(function* () { const playwright = yield* Playwright.Playwright; diff --git a/src/playwright.ts b/src/playwright.ts index 8409178..0640e7d 100644 --- a/src/playwright.ts +++ b/src/playwright.ts @@ -309,7 +309,7 @@ const launchPersistentContext: ( * @category services * @since 0.1.0 */ -export const Playwright = Context.GenericTag( +export const Playwright = Context.Service( "effect-playwright/playwright/Playwright", ); diff --git a/src/screencast.ts b/src/screencast.ts index 8b168f1..e26882a 100644 --- a/src/screencast.ts +++ b/src/screencast.ts @@ -92,7 +92,7 @@ export interface Screencast { /** * @category services */ -export const Screencast = Context.GenericTag( +export const Screencast = Context.Service( "effect-playwright/screencast/Screencast", ); diff --git a/src/test.spec.ts b/src/test.spec.ts index 0c0def9..159511f 100644 --- a/src/test.spec.ts +++ b/src/test.spec.ts @@ -5,29 +5,29 @@ import { expect, layer, makeMethods, test } from "effect-playwright/test"; class ExpectedTestError extends Data.TaggedError("ExpectedTestError") {} -class SharedValue extends Context.Tag("SharedValue")< +class SharedValue extends Context.Service< SharedValue, { readonly acquisition: number } ->() {} +>()("SharedValue") {} -class NestedValue extends Context.Tag("NestedValue")() {} +class NestedValue extends Context.Service()( + "NestedValue", +) {} -class AnonymousValue extends Context.Tag("AnonymousValue")< - AnonymousValue, - string ->() {} +class AnonymousValue extends Context.Service()( + "AnonymousValue", +) {} -class CustomLayerValue extends Context.Tag("CustomLayerValue")< - CustomLayerValue, - string ->() {} +class CustomLayerValue extends Context.Service()( + "CustomLayerValue", +) {} let sharedLayerAcquisitions = 0; let sharedLayerReleases = 0; let anonymousLayerAcquisitions = 0; let anonymousLayerReleases = 0; -const sharedLayer = Layer.scoped( +const sharedLayer = Layer.effect( SharedValue, Effect.acquireRelease( Effect.sync(() => ({ acquisition: ++sharedLayerAcquisitions })), @@ -43,7 +43,7 @@ const nestedLayer = Layer.effect( Effect.map(SharedValue, ({ acquisition }) => acquisition + 1), ); -const anonymousLayer = Layer.scoped( +const anonymousLayer = Layer.effect( AnonymousValue, Effect.acquireRelease( Effect.sync(() => { diff --git a/src/test.ts b/src/test.ts index 3e6d6c2..237b859 100644 --- a/src/test.ts +++ b/src/test.ts @@ -20,16 +20,7 @@ import { type TestInfo, type TestType, } from "@playwright/test"; -import { - Cause, - Context, - Duration, - Effect, - Exit, - Layer, - Logger, - Scope, -} from "effect"; +import { Cause, Context, Duration, Effect, Exit, Layer, Scope } from "effect"; import { Browser, makeBrowser } from "./browser"; import { BrowserContext, makeBrowserContext } from "./browser-context"; import { makePage, Page } from "./page"; @@ -164,7 +155,7 @@ export interface EffectTester */ export interface LayerOptions { readonly memoMap?: Layer.MemoMap; - readonly timeout?: Duration.DurationInput; + readonly timeout?: Duration.Input; } /** * Options for a nested shared layer. Nested layers reuse their parent's memo @@ -174,7 +165,7 @@ export interface LayerOptions { * @since 0.6.0 */ export interface NestedLayerOptions { - readonly timeout?: Duration.DurationInput; + readonly timeout?: Duration.Input; } /** @@ -278,7 +269,7 @@ const runPromise = ( }); } return yield* exit; - }).pipe(Effect.provide(Logger.pretty)), + }), { signal }, ); @@ -395,14 +386,13 @@ const makeLayer = ( ): LayerRegistration => { const memoMap = options?.memoMap ?? Effect.runSync(Layer.makeMemoMap); const scope = Effect.runSync(Scope.make()); - const runtimeEffect = Layer.toRuntimeWithMemoMap(layer, memoMap).pipe( - Scope.extend(scope), + const runtimeEffect = Layer.buildWithMemoMap(layer, memoMap, scope).pipe( Effect.orDie, Effect.cached, Effect.runSync, ); const transform: EffectTransform = (effect) => - Effect.flatMap(runtimeEffect, (runtime) => Effect.provide(effect, runtime)); + Effect.flatMap(runtimeEffect, (context) => Effect.provide(effect, context)); const tester = makeTester(effectTestType, transform); const makeLayerMethods = (): LayerTestMethods => { @@ -620,7 +610,7 @@ export const test = makeMethods(playwrightTest); * import { Context, Effect, Layer } from "effect"; * import { expect, layer } from "effect-playwright/test"; * - * class Greeting extends Context.Tag("Greeting")() {} + * class Greeting extends Context.Service()("Greeting") {} * * layer(Layer.succeed(Greeting, "hello"))("Greeting", (it) => { * it.effect("provides the layer", () => diff --git a/src/touchscreen.ts b/src/touchscreen.ts index 3fc9c74..9b55f5e 100644 --- a/src/touchscreen.ts +++ b/src/touchscreen.ts @@ -31,7 +31,7 @@ export interface Touchscreen { * @category services * @since 0.3.0 */ -export const Touchscreen = Context.GenericTag( +export const Touchscreen = Context.Service( "effect-playwright/touchscreen/Touchscreen", ); diff --git a/src/tracing.ts b/src/tracing.ts index ffe2a9c..f3b2fea 100644 --- a/src/tracing.ts +++ b/src/tracing.ts @@ -76,7 +76,7 @@ export interface Tracing { /** * @category services */ -export const Tracing = Context.GenericTag( +export const Tracing = Context.Service( "effect-playwright/tracing/Tracing", ); diff --git a/src/web-storage.ts b/src/web-storage.ts index 2b18316..fcc5198 100644 --- a/src/web-storage.ts +++ b/src/web-storage.ts @@ -95,7 +95,7 @@ export interface WebStorage { * @category services * @since 0.5.1 */ -export const WebStorage = Context.GenericTag( +export const WebStorage = Context.Service( "effect-playwright/web-storage/WebStorage", ); @@ -113,7 +113,7 @@ export const makeWebStorage = (webStorage: CoreWebStorage): WebStorage => { clear: use((storage) => storage.clear()), getItem: (name) => use((storage) => storage.getItem(name)).pipe( - Effect.map(Option.fromNullable), + Effect.map(Option.fromNullishOr), ), items: use((storage) => storage.items()), removeItem: (name) => use((storage) => storage.removeItem(name)),