From f0eb2bbe608cb0f2b1886dbb45a0c011c4dbe818 Mon Sep 17 00:00:00 2001 From: Filip Weiss Date: Sat, 23 May 2026 12:05:32 +0200 Subject: [PATCH] port library to effect v4 --- package.json | 11 +- pnpm-lock.yaml | 566 ++++++++----------------- src/browser-context.test.ts | 4 +- src/browser-context.ts | 39 +- src/browser.test.ts | 30 +- src/browser.ts | 38 +- src/clock.ts | 9 +- src/common.test.ts | 48 ++- src/common.ts | 38 +- src/event-stream.test.ts | 14 +- src/experimental/browser-utils.test.ts | 21 +- src/experimental/environment.test.ts | 4 +- src/experimental/environment.ts | 43 +- src/frame-locator.ts | 11 +- src/frame.test.ts | 9 +- src/frame.ts | 25 +- src/keyboard.ts | 24 +- src/locator.test.ts | 12 +- src/locator.ts | 17 +- src/mouse.ts | 7 +- src/page.test.ts | 133 +++--- src/page.ts | 73 ++-- src/playwright.test.ts | 18 +- src/playwright.ts | 35 +- src/screencast.ts | 7 +- src/touchscreen.ts | 7 +- src/tracing.ts | 7 +- 27 files changed, 541 insertions(+), 709 deletions(-) diff --git a/package.json b/package.json index 62eb074..b942f08 100644 --- a/package.json +++ b/package.json @@ -47,18 +47,15 @@ "playwright-core": "^1.60.0" }, "peerDependencies": { - "@effect/platform": "^0.93.3", - "effect": "^3.19.6" + "effect": "^4.0.0-beta.70" }, "devDependencies": { "@biomejs/biome": "2.4.14", - "@effect/cli": "^0.75.1", "@effect/language-service": "0.85.1", - "@effect/platform": "^0.96.1", - "@effect/platform-node": "^0.106.0", - "@effect/vitest": "^0.29.0", + "@effect/platform-node": "4.0.0-beta.70", + "@effect/vitest": "4.0.0-beta.70", "@types/node": "^25.6.1", - "effect": "^3.21.2", + "effect": "4.0.0-beta.70", "playwright": "^1.60.0", "ts-morph": "^28.0.0", "tsdown": "0.22.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6d063d7..b336b80 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,27 +15,21 @@ importers: '@biomejs/biome': specifier: 2.4.14 version: 2.4.14 - '@effect/cli': - specifier: ^0.75.1 - version: 0.75.1(@effect/platform@0.96.1(effect@3.21.2))(@effect/printer-ansi@0.47.0(@effect/typeclass@0.38.0(effect@3.21.2))(effect@3.21.2))(@effect/printer@0.47.0(@effect/typeclass@0.38.0(effect@3.21.2))(effect@3.21.2))(effect@3.21.2) '@effect/language-service': specifier: 0.85.1 version: 0.85.1 - '@effect/platform': - specifier: ^0.96.1 - version: 0.96.1(effect@3.21.2) '@effect/platform-node': - specifier: ^0.106.0 - version: 0.106.0(@effect/cluster@0.56.1(@effect/platform@0.96.1(effect@3.21.2))(@effect/rpc@0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/sql@0.49.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/workflow@0.16.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(@effect/rpc@0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(@effect/rpc@0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/sql@0.49.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(effect@3.21.2) + specifier: 4.0.0-beta.70 + version: 4.0.0-beta.70(effect@4.0.0-beta.70)(ioredis@5.10.1) '@effect/vitest': - specifier: ^0.29.0 - version: 0.29.0(effect@3.21.2)(vitest@4.1.5(@types/node@25.6.1)(vite@8.0.11(@types/node@25.6.1)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.8.4))) + specifier: 4.0.0-beta.70 + version: 4.0.0-beta.70(effect@4.0.0-beta.70)(vitest@4.1.5(@types/node@25.6.1)(vite@8.0.11(@types/node@25.6.1)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.9.0))) '@types/node': specifier: ^25.6.1 version: 25.6.1 effect: - specifier: ^3.21.2 - version: 3.21.2 + specifier: 4.0.0-beta.70 + version: 4.0.0-beta.70 playwright: specifier: ^1.60.0 version: 1.60.0 @@ -56,10 +50,10 @@ importers: version: 6.0.3 vite: specifier: ^8.0.11 - version: 8.0.11(@types/node@25.6.1)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.8.4) + version: 8.0.11(@types/node@25.6.1)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.9.0) vitest: specifier: ^4.1.5 - version: 4.1.5(@types/node@25.6.1)(vite@8.0.11(@types/node@25.6.1)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.8.4)) + version: 4.1.5(@types/node@25.6.1)(vite@8.0.11(@types/node@25.6.1)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.9.0)) packages: @@ -137,106 +131,28 @@ packages: cpu: [x64] os: [win32] - '@effect/cli@0.75.1': - resolution: {integrity: sha512-aDZ1OZzaFAb6NyBOrP+Bl52eICds5ERI9aa67LzloJELt5SCWeNwthtaEacBvvMkwVUcykJ+YHcGCkD1t47g8g==} - peerDependencies: - '@effect/platform': ^0.96.0 - '@effect/printer': ^0.49.0 - '@effect/printer-ansi': ^0.49.0 - effect: ^3.21.1 - - '@effect/cluster@0.56.1': - resolution: {integrity: sha512-gnrsH6kfrUjn+82j/bw1IR4yFqJqV8tc7xZvrbJPRgzANycc6K1hu3LMg548uYbUkTzD8YYyqrSatMO1mkQpzw==} - peerDependencies: - '@effect/platform': ^0.94.1 - '@effect/rpc': ^0.73.0 - '@effect/sql': ^0.49.0 - '@effect/workflow': ^0.16.0 - effect: ^3.19.14 - - '@effect/experimental@0.58.0': - resolution: {integrity: sha512-IEP9sapjF6rFy5TkoqDPc86st/fnqUfjT7Xa3pWJrFGr1hzaMXHo+mWsYOZS9LAOVKnpHuVziDK97EP5qsCHVA==} - peerDependencies: - '@effect/platform': ^0.94.0 - effect: ^3.19.13 - ioredis: ^5 - lmdb: ^3 - peerDependenciesMeta: - ioredis: - optional: true - lmdb: - optional: true - '@effect/language-service@0.85.1': resolution: {integrity: sha512-EXnJjIy6zQ3nUO/MZ+ynWUb8B895KZPotd1++oTs9JjDkplwM7cb6zo8Zq2zU6piwq+KflO7amXbEfj1UMpHkw==} hasBin: true - '@effect/platform-node-shared@0.59.0': - resolution: {integrity: sha512-3bq2YKKfLY7UFauZSxqZUneCXoA3SMSls82V+0RKunvRlfPuPQW0hVn6t1RkvEdh0PDoygWG2mZXYQa6Iqgp9A==} - peerDependencies: - '@effect/cluster': ^0.58.0 - '@effect/platform': ^0.96.0 - '@effect/rpc': ^0.75.0 - '@effect/sql': ^0.51.0 - effect: ^3.21.0 - - '@effect/platform-node@0.106.0': - resolution: {integrity: sha512-mpsJK2jNLVd0jQAjHKBo8j3wdKWznSGvfnKBcAuG/9Rr4mb8bMRZFLXHHT9wUP7EvnZ0tDZJgEDxkC+j+ByRag==} - peerDependencies: - '@effect/cluster': ^0.58.0 - '@effect/platform': ^0.96.0 - '@effect/rpc': ^0.75.0 - '@effect/sql': ^0.51.0 - effect: ^3.21.0 - - '@effect/platform@0.96.1': - resolution: {integrity: sha512-cjB1QZZYEP8JXCFNGvBLVi0T6YUBQTmOVEUA3SDbiQ6RUO+p6CE3eyD2vMWmrz5nE8yY5QSAuOV9v0boEcUv+A==} - peerDependencies: - effect: ^3.21.2 - - '@effect/printer-ansi@0.47.0': - resolution: {integrity: sha512-tDEQ9XJpXDNYoWMQJHFRMxKGmEOu6z32x3Kb8YLOV5nkauEKnKmWNs7NBp8iio/pqoJbaSwqDwUg9jXVquxfWQ==} - peerDependencies: - '@effect/typeclass': ^0.38.0 - effect: ^3.19.0 - - '@effect/printer@0.47.0': - resolution: {integrity: sha512-VgR8e+YWWhMEAh9qFOjwiZ3OXluAbcVLIOtvp2S5di1nSrPOZxj78g8LE77JSvyfp5y5bS2gmFW+G7xD5uU+2Q==} - peerDependencies: - '@effect/typeclass': ^0.38.0 - effect: ^3.19.0 - - '@effect/rpc@0.73.0': - resolution: {integrity: sha512-iMPf6tTriz8sK0l5x4koFId8Hz5nFptHYg8WqyjHGIIVLTpZxuiSqhmXZG7FnAs5N2n6uCEws4wWGcIgXNUrFg==} - peerDependencies: - '@effect/platform': ^0.94.0 - effect: ^3.19.13 - - '@effect/sql@0.49.0': - resolution: {integrity: sha512-9UEKR+z+MrI/qMAmSvb/RiD9KlgIazjZUCDSpwNgm0lEK9/Q6ExEyfziiYFVCPiptp52cBw8uBHRic8hHnwqXA==} - peerDependencies: - '@effect/experimental': ^0.58.0 - '@effect/platform': ^0.94.0 - effect: ^3.19.13 - - '@effect/typeclass@0.38.0': - resolution: {integrity: sha512-lMUcJTRtG8KXhXoczapZDxbLK5os7M6rn0zkvOgncJW++A0UyelZfMVMKdT5R+fgpZcsAU/1diaqw3uqLJwGxA==} + '@effect/platform-node-shared@4.0.0-beta.70': + resolution: {integrity: sha512-3VXuL63IDmq13We+ApRKn2JW3Rb9g5gj1YEmfb8u2b73norur1VsIJ/pRE4qjShevg19dQYi2JsLawSZ6gApug==} + engines: {node: '>=18.0.0'} peerDependencies: - effect: ^3.19.0 + effect: ^4.0.0-beta.70 - '@effect/vitest@0.29.0': - resolution: {integrity: sha512-DvWr1aeEcaZ8mtu8hNVb4e3rEYvGEwQSr7wsNrW53t6nKYjkmjRICcvVEsXUhjoCblRHSxRsRV0TOt0+UmcvaQ==} + '@effect/platform-node@4.0.0-beta.70': + resolution: {integrity: sha512-Ls1WtLaO2CbcO8jHtZRRi6eZa4YOJZ9KXm6udMvwhjV/XhqdsT6AzmcXbc1hINbKgvRcik6qM/441YEaBMYoqw==} + engines: {node: '>=18.0.0'} peerDependencies: - effect: ^3.21.0 - vitest: ^3.2.0 + effect: ^4.0.0-beta.70 + ioredis: ^5.7.0 - '@effect/workflow@0.16.0': - resolution: {integrity: sha512-MiAdlxx3TixkgHdbw+Yf1Z3tHAAE0rOQga12kIydJqj05Fnod+W/I+kQGRMY/XWRg+QUsVxhmh1qTr7Ype6lrw==} + '@effect/vitest@4.0.0-beta.70': + resolution: {integrity: sha512-XDteNN0xfOgoMauAVoN5iylxVgEjp7kFsGFq18tZ5XYjek0eOZa0nOoes5s7Bs71VvwjnCeCbFMD7IhxswEt8A==} peerDependencies: - '@effect/experimental': ^0.58.0 - '@effect/platform': ^0.94.0 - '@effect/rpc': ^0.73.0 - effect: ^3.19.13 + effect: ^4.0.0-beta.70 + vitest: ^3.0.0 || ^4.0.0 '@emnapi/core@1.10.0': resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} @@ -406,6 +322,9 @@ packages: '@gerrit0/mini-shiki@3.23.0': resolution: {integrity: sha512-bEMORlG0cqdjVyCEuU0cDQbORWX+kYCeo0kV1lbxF5bt4r7SID2l9bqsxJEM0zndaxpOUT7riCyIVEuqq/Ynxg==} + '@ioredis/commands@1.5.1': + resolution: {integrity: sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw==} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -464,88 +383,6 @@ packages: '@oxc-project/types@0.129.0': resolution: {integrity: sha512-3oz8m3FGdr2nDXVqmFUw7jolKliC4MoyXYIG2c7gpjBnzUWQpUGIYcXYKxTdTi+N2jusvt610ckTMkxdwHkYEg==} - '@parcel/watcher-android-arm64@2.5.6': - resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [android] - - '@parcel/watcher-darwin-arm64@2.5.6': - resolution: {integrity: sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [darwin] - - '@parcel/watcher-darwin-x64@2.5.6': - resolution: {integrity: sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [darwin] - - '@parcel/watcher-freebsd-x64@2.5.6': - resolution: {integrity: sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [freebsd] - - '@parcel/watcher-linux-arm-glibc@2.5.6': - resolution: {integrity: sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==} - engines: {node: '>= 10.0.0'} - cpu: [arm] - os: [linux] - - '@parcel/watcher-linux-arm-musl@2.5.6': - resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} - engines: {node: '>= 10.0.0'} - cpu: [arm] - os: [linux] - - '@parcel/watcher-linux-arm64-glibc@2.5.6': - resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [linux] - - '@parcel/watcher-linux-arm64-musl@2.5.6': - resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [linux] - - '@parcel/watcher-linux-x64-glibc@2.5.6': - resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [linux] - - '@parcel/watcher-linux-x64-musl@2.5.6': - resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [linux] - - '@parcel/watcher-win32-arm64@2.5.6': - resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [win32] - - '@parcel/watcher-win32-ia32@2.5.6': - resolution: {integrity: sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==} - engines: {node: '>= 10.0.0'} - cpu: [ia32] - os: [win32] - - '@parcel/watcher-win32-x64@2.5.6': - resolution: {integrity: sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [win32] - - '@parcel/watcher@2.5.6': - resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==} - engines: {node: '>= 10.0.0'} - '@quansync/fs@1.0.0': resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} @@ -870,6 +707,9 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/ws@8.18.1': + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + '@vitest/expect@4.1.5': resolution: {integrity: sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==} @@ -933,15 +773,32 @@ packages: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} + cluster-key-slot@1.1.2: + resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} + engines: {node: '>=0.10.0'} + code-block-writer@13.0.3: resolution: {integrity: sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==} convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + defu@6.1.7: resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -955,8 +812,8 @@ packages: oxc-resolver: optional: true - effect@3.21.2: - resolution: {integrity: sha512-rXd2FGDM8KdjSIrc+mqEELo7ScW7xTVxEf1iInmPSpIde9/nyGuFM710cjTo7/EreGXiUX2MOonPpprbz2XHCg==} + effect@4.0.0-beta.70: + resolution: {integrity: sha512-8AwGTRiNriirHGEYHrOS0E9fzdhIqCdZjiHP1YXmNo2UyPGS43ILsymsSHT7V0DJS+8dvlKq2RxnrDBUhDNZHg==} empathic@2.0.1: resolution: {integrity: sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q==} @@ -981,9 +838,9 @@ packages: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} - fast-check@3.23.2: - resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} - engines: {node: '>=8.0.0'} + fast-check@4.8.0: + resolution: {integrity: sha512-GOJ158CUMnN6cSahsv4+ExARvIDuzzinFjkp0E9WtiBa5zcVeLozVkWaE4IzFcc+Y48Wp1EDlUZsXRyAztQcSg==} + engines: {node: '>=12.17.0'} fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} @@ -1021,17 +878,13 @@ 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'} + ini@7.0.0: + resolution: {integrity: sha512-ifK0CgjALofS5bkrcTy4RaQ9Vx2Knf/eLeIO+NaswQEpH1UblrtTSCIvN71qQDMq0PeQ/SSPojvEJp9vvvfr+w==} + engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} + ioredis@5.10.1: + resolution: {integrity: sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==} + engines: {node: '>=12.22.0'} jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} @@ -1114,6 +967,12 @@ packages: linkify-it@5.0.0: resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + lodash.defaults@4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + + lodash.isarguments@3.1.0: + resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} + lunr@2.3.9: resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} @@ -1127,21 +986,24 @@ packages: mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} - mime@3.0.0: - resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} - engines: {node: '>=10.0.0'} + mime@4.1.0: + resolution: {integrity: sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==} + engines: {node: '>=16'} hasBin: true minimatch@10.2.5: resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + msgpackr-extract@3.0.3: resolution: {integrity: sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==} hasBin: true - msgpackr@1.11.12: - resolution: {integrity: sha512-RBdJ1Un7yGlXWajrkxcSa93nvQ0w4zBf60c0yYv7YtBelP8H2FA7XsfBbMHtXKXUMUxH7zV3Zuozh+kUQWhHvg==} + msgpackr@2.0.1: + resolution: {integrity: sha512-9J+tqTEsbHqY8YohazYgty7LgerFIWxvMLpUjqETSmjHojtJm2WnX2kK/2a1fLI7CO7ERP1YSEUXMucz4j+yBA==} multipasta@0.2.7: resolution: {integrity: sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA==} @@ -1151,9 +1013,6 @@ packages: 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 @@ -1192,12 +1051,20 @@ packages: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} - pure-rand@6.1.0: - resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + pure-rand@8.4.0: + resolution: {integrity: sha512-IoM8YF/jY0hiugFo/wOWqfmarlE6J0wc6fDK1PhftMk7MGhVZl88sZimmqBBFomLOCSmcCCpsfj7wXASCpvK9A==} quansync@1.0.0: resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==} + redis-errors@1.2.0: + resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} + engines: {node: '>=4'} + + redis-parser@3.0.0: + resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} + engines: {node: '>=4'} + resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} @@ -1250,6 +1117,9 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + standard-as-callback@2.1.0: + resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} + std-env@4.1.0: resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} @@ -1268,8 +1138,9 @@ packages: resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} engines: {node: '>=14.0.0'} - toml@3.0.0: - resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} + toml@4.1.1: + resolution: {integrity: sha512-EBJnVBr3dTXdA89WVFoAIPUqkBjxPMwRqsfuo1r240tKFHXv3zgca4+NJib/h6TyvGF7vOawz0jGuryJCdNHrw==} + engines: {node: '>=20'} tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} @@ -1341,9 +1212,9 @@ packages: undici-types@7.19.2: resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==} - undici@7.25.0: - resolution: {integrity: sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==} - engines: {node: '>=20.18.1'} + undici@8.3.0: + resolution: {integrity: sha512-TkUDgb6tl7KOGZ+7e8E3d2FYgUQgF6z5YypqjWmixVQSQERFcVrVg0ySADm2LVLRh5ljAaHTCR5Fmz3Q34rB7Q==} + engines: {node: '>=22.19.0'} unrun@0.2.34: resolution: {integrity: sha512-LyaghRBR++r7svhDK6tnDz2XaYHWdneBOA0jbS8wnRsHerI9MFljX4fIiTgbbNbEVzZ0C9P1OjWLLe1OqoaaEw==} @@ -1355,8 +1226,8 @@ packages: synckit: optional: true - uuid@11.1.1: - resolution: {integrity: sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==} + uuid@14.0.0: + resolution: {integrity: sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==} hasBin: true vite@8.0.11: @@ -1465,6 +1336,11 @@ packages: engines: {node: '>= 14.6'} hasBin: true + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} + hasBin: true + snapshots: '@babel/generator@8.0.0-rc.4': @@ -1524,108 +1400,32 @@ snapshots: '@biomejs/cli-win32-x64@2.4.14': optional: true - '@effect/cli@0.75.1(@effect/platform@0.96.1(effect@3.21.2))(@effect/printer-ansi@0.47.0(@effect/typeclass@0.38.0(effect@3.21.2))(effect@3.21.2))(@effect/printer@0.47.0(@effect/typeclass@0.38.0(effect@3.21.2))(effect@3.21.2))(effect@3.21.2)': - dependencies: - '@effect/platform': 0.96.1(effect@3.21.2) - '@effect/printer': 0.47.0(@effect/typeclass@0.38.0(effect@3.21.2))(effect@3.21.2) - '@effect/printer-ansi': 0.47.0(@effect/typeclass@0.38.0(effect@3.21.2))(effect@3.21.2) - effect: 3.21.2 - ini: 4.1.3 - toml: 3.0.0 - yaml: 2.8.4 - - '@effect/cluster@0.56.1(@effect/platform@0.96.1(effect@3.21.2))(@effect/rpc@0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/sql@0.49.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/workflow@0.16.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(@effect/rpc@0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(effect@3.21.2))(effect@3.21.2)': - dependencies: - '@effect/platform': 0.96.1(effect@3.21.2) - '@effect/rpc': 0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2) - '@effect/sql': 0.49.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2) - '@effect/workflow': 0.16.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(@effect/rpc@0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(effect@3.21.2) - effect: 3.21.2 - kubernetes-types: 1.30.0 - - '@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2)': - dependencies: - '@effect/platform': 0.96.1(effect@3.21.2) - effect: 3.21.2 - uuid: 11.1.1 - '@effect/language-service@0.85.1': {} - '@effect/platform-node-shared@0.59.0(@effect/cluster@0.56.1(@effect/platform@0.96.1(effect@3.21.2))(@effect/rpc@0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/sql@0.49.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/workflow@0.16.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(@effect/rpc@0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(@effect/rpc@0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/sql@0.49.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(effect@3.21.2)': + '@effect/platform-node-shared@4.0.0-beta.70(effect@4.0.0-beta.70)': dependencies: - '@effect/cluster': 0.56.1(@effect/platform@0.96.1(effect@3.21.2))(@effect/rpc@0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/sql@0.49.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/workflow@0.16.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(@effect/rpc@0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(effect@3.21.2))(effect@3.21.2) - '@effect/platform': 0.96.1(effect@3.21.2) - '@effect/rpc': 0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2) - '@effect/sql': 0.49.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2) - '@parcel/watcher': 2.5.6 - effect: 3.21.2 - multipasta: 0.2.7 + '@types/ws': 8.18.1 + effect: 4.0.0-beta.70 ws: 8.20.0 transitivePeerDependencies: - bufferutil - utf-8-validate - '@effect/platform-node@0.106.0(@effect/cluster@0.56.1(@effect/platform@0.96.1(effect@3.21.2))(@effect/rpc@0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/sql@0.49.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/workflow@0.16.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(@effect/rpc@0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(@effect/rpc@0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/sql@0.49.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(effect@3.21.2)': + '@effect/platform-node@4.0.0-beta.70(effect@4.0.0-beta.70)(ioredis@5.10.1)': dependencies: - '@effect/cluster': 0.56.1(@effect/platform@0.96.1(effect@3.21.2))(@effect/rpc@0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/sql@0.49.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/workflow@0.16.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(@effect/rpc@0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(effect@3.21.2))(effect@3.21.2) - '@effect/platform': 0.96.1(effect@3.21.2) - '@effect/platform-node-shared': 0.59.0(@effect/cluster@0.56.1(@effect/platform@0.96.1(effect@3.21.2))(@effect/rpc@0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/sql@0.49.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/workflow@0.16.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(@effect/rpc@0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(@effect/rpc@0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/sql@0.49.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(effect@3.21.2) - '@effect/rpc': 0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2) - '@effect/sql': 0.49.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2) - effect: 3.21.2 - mime: 3.0.0 - undici: 7.25.0 - ws: 8.20.0 + '@effect/platform-node-shared': 4.0.0-beta.70(effect@4.0.0-beta.70) + effect: 4.0.0-beta.70 + ioredis: 5.10.1 + mime: 4.1.0 + undici: 8.3.0 transitivePeerDependencies: - bufferutil - utf-8-validate - '@effect/platform@0.96.1(effect@3.21.2)': - dependencies: - effect: 3.21.2 - find-my-way-ts: 0.1.6 - msgpackr: 1.11.12 - multipasta: 0.2.7 - - '@effect/printer-ansi@0.47.0(@effect/typeclass@0.38.0(effect@3.21.2))(effect@3.21.2)': + '@effect/vitest@4.0.0-beta.70(effect@4.0.0-beta.70)(vitest@4.1.5(@types/node@25.6.1)(vite@8.0.11(@types/node@25.6.1)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.9.0)))': dependencies: - '@effect/printer': 0.47.0(@effect/typeclass@0.38.0(effect@3.21.2))(effect@3.21.2) - '@effect/typeclass': 0.38.0(effect@3.21.2) - effect: 3.21.2 - - '@effect/printer@0.47.0(@effect/typeclass@0.38.0(effect@3.21.2))(effect@3.21.2)': - dependencies: - '@effect/typeclass': 0.38.0(effect@3.21.2) - effect: 3.21.2 - - '@effect/rpc@0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2)': - dependencies: - '@effect/platform': 0.96.1(effect@3.21.2) - effect: 3.21.2 - msgpackr: 1.11.12 - - '@effect/sql@0.49.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2)': - dependencies: - '@effect/experimental': 0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2) - '@effect/platform': 0.96.1(effect@3.21.2) - effect: 3.21.2 - uuid: 11.1.1 - - '@effect/typeclass@0.38.0(effect@3.21.2)': - dependencies: - effect: 3.21.2 - - '@effect/vitest@0.29.0(effect@3.21.2)(vitest@4.1.5(@types/node@25.6.1)(vite@8.0.11(@types/node@25.6.1)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.8.4)))': - dependencies: - effect: 3.21.2 - vitest: 4.1.5(@types/node@25.6.1)(vite@8.0.11(@types/node@25.6.1)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.8.4)) - - '@effect/workflow@0.16.0(@effect/experimental@0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(@effect/platform@0.96.1(effect@3.21.2))(@effect/rpc@0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2))(effect@3.21.2)': - dependencies: - '@effect/experimental': 0.58.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2) - '@effect/platform': 0.96.1(effect@3.21.2) - '@effect/rpc': 0.73.0(@effect/platform@0.96.1(effect@3.21.2))(effect@3.21.2) - effect: 3.21.2 + effect: 4.0.0-beta.70 + vitest: 4.1.5(@types/node@25.6.1)(vite@8.0.11(@types/node@25.6.1)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.9.0)) '@emnapi/core@1.10.0': dependencies: @@ -1729,6 +1529,8 @@ snapshots: '@shikijs/types': 3.23.0 '@shikijs/vscode-textmate': 10.0.2 + '@ioredis/commands@1.5.1': {} + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -1775,66 +1577,6 @@ snapshots: '@oxc-project/types@0.129.0': {} - '@parcel/watcher-android-arm64@2.5.6': - optional: true - - '@parcel/watcher-darwin-arm64@2.5.6': - optional: true - - '@parcel/watcher-darwin-x64@2.5.6': - optional: true - - '@parcel/watcher-freebsd-x64@2.5.6': - optional: true - - '@parcel/watcher-linux-arm-glibc@2.5.6': - optional: true - - '@parcel/watcher-linux-arm-musl@2.5.6': - optional: true - - '@parcel/watcher-linux-arm64-glibc@2.5.6': - optional: true - - '@parcel/watcher-linux-arm64-musl@2.5.6': - optional: true - - '@parcel/watcher-linux-x64-glibc@2.5.6': - optional: true - - '@parcel/watcher-linux-x64-musl@2.5.6': - optional: true - - '@parcel/watcher-win32-arm64@2.5.6': - optional: true - - '@parcel/watcher-win32-ia32@2.5.6': - optional: true - - '@parcel/watcher-win32-x64@2.5.6': - optional: true - - '@parcel/watcher@2.5.6': - dependencies: - detect-libc: 2.1.2 - is-glob: 4.0.3 - node-addon-api: 7.1.1 - picomatch: 4.0.4 - optionalDependencies: - '@parcel/watcher-android-arm64': 2.5.6 - '@parcel/watcher-darwin-arm64': 2.5.6 - '@parcel/watcher-darwin-x64': 2.5.6 - '@parcel/watcher-freebsd-x64': 2.5.6 - '@parcel/watcher-linux-arm-glibc': 2.5.6 - '@parcel/watcher-linux-arm-musl': 2.5.6 - '@parcel/watcher-linux-arm64-glibc': 2.5.6 - '@parcel/watcher-linux-arm64-musl': 2.5.6 - '@parcel/watcher-linux-x64-glibc': 2.5.6 - '@parcel/watcher-linux-x64-musl': 2.5.6 - '@parcel/watcher-win32-arm64': 2.5.6 - '@parcel/watcher-win32-ia32': 2.5.6 - '@parcel/watcher-win32-x64': 2.5.6 - '@quansync/fs@1.0.0': dependencies: quansync: 1.0.0 @@ -2048,6 +1790,10 @@ snapshots: '@types/unist@3.0.3': {} + '@types/ws@8.18.1': + dependencies: + '@types/node': 25.6.1 + '@vitest/expect@4.1.5': dependencies: '@standard-schema/spec': 1.1.0 @@ -2057,13 +1803,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.5(vite@8.0.11(@types/node@25.6.1)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.8.4))': + '@vitest/mocker@4.1.5(vite@8.0.11(@types/node@25.6.1)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.9.0))': dependencies: '@vitest/spy': 4.1.5 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.11(@types/node@25.6.1)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.8.4) + vite: 8.0.11(@types/node@25.6.1)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.9.0) '@vitest/pretty-format@4.1.5': dependencies: @@ -2113,20 +1859,36 @@ snapshots: chai@6.2.2: {} + cluster-key-slot@1.1.2: {} + code-block-writer@13.0.3: {} convert-source-map@2.0.0: {} + debug@4.4.3: + dependencies: + ms: 2.1.3 + defu@6.1.7: {} + denque@2.1.0: {} + detect-libc@2.1.2: {} dts-resolver@3.0.0: {} - effect@3.21.2: + effect@4.0.0-beta.70: dependencies: '@standard-schema/spec': 1.1.0 - fast-check: 3.23.2 + fast-check: 4.8.0 + find-my-way-ts: 0.1.6 + ini: 7.0.0 + kubernetes-types: 1.30.0 + msgpackr: 2.0.1 + multipasta: 0.2.7 + toml: 4.1.1 + uuid: 14.0.0 + yaml: 2.9.0 empathic@2.0.1: {} @@ -2169,9 +1931,9 @@ snapshots: expect-type@1.3.0: {} - fast-check@3.23.2: + fast-check@4.8.0: dependencies: - pure-rand: 6.1.0 + pure-rand: 8.4.0 fdir@6.5.0(picomatch@4.0.4): optionalDependencies: @@ -2197,13 +1959,21 @@ snapshots: import-without-cache@0.4.0: {} - ini@4.1.3: {} + ini@7.0.0: {} - is-extglob@2.1.1: {} - - is-glob@4.0.3: + ioredis@5.10.1: dependencies: - is-extglob: 2.1.1 + '@ioredis/commands': 1.5.1 + cluster-key-slot: 1.1.2 + debug: 4.4.3 + denque: 2.1.0 + lodash.defaults: 4.2.0 + lodash.isarguments: 3.1.0 + redis-errors: 1.2.0 + redis-parser: 3.0.0 + standard-as-callback: 2.1.0 + transitivePeerDependencies: + - supports-color jsesc@3.1.0: {} @@ -2262,6 +2032,10 @@ snapshots: dependencies: uc.micro: 2.1.0 + lodash.defaults@4.2.0: {} + + lodash.isarguments@3.1.0: {} + lunr@2.3.9: {} magic-string@0.30.21: @@ -2279,12 +2053,14 @@ snapshots: mdurl@2.0.0: {} - mime@3.0.0: {} + mime@4.1.0: {} minimatch@10.2.5: dependencies: brace-expansion: 5.0.5 + ms@2.1.3: {} + msgpackr-extract@3.0.3: dependencies: node-gyp-build-optional-packages: 5.2.2 @@ -2297,7 +2073,7 @@ snapshots: '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.3 optional: true - msgpackr@1.11.12: + msgpackr@2.0.1: optionalDependencies: msgpackr-extract: 3.0.3 @@ -2305,8 +2081,6 @@ snapshots: nanoid@3.3.12: {} - node-addon-api@7.1.1: {} - node-gyp-build-optional-packages@5.2.2: dependencies: detect-libc: 2.1.2 @@ -2338,10 +2112,16 @@ snapshots: punycode.js@2.3.1: {} - pure-rand@6.1.0: {} + pure-rand@8.4.0: {} quansync@1.0.0: {} + redis-errors@1.2.0: {} + + redis-parser@3.0.0: + dependencies: + redis-errors: 1.2.0 + resolve-pkg-maps@1.0.0: {} rolldown-plugin-dts@0.25.0(rolldown@1.0.0)(typescript@6.0.3): @@ -2435,6 +2215,8 @@ snapshots: stackback@0.0.2: {} + standard-as-callback@2.1.0: {} + std-env@4.1.0: {} tinybench@2.9.0: {} @@ -2448,7 +2230,7 @@ snapshots: tinyrainbow@3.1.0: {} - toml@3.0.0: {} + toml@4.1.1: {} tree-kill@1.2.2: {} @@ -2514,7 +2296,7 @@ snapshots: undici-types@7.19.2: {} - undici@7.25.0: {} + undici@8.3.0: {} unrun@0.2.34(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0): dependencies: @@ -2524,9 +2306,9 @@ snapshots: - '@emnapi/runtime' optional: true - uuid@11.1.1: {} + uuid@14.0.0: {} - vite@8.0.11(@types/node@25.6.1)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.8.4): + vite@8.0.11(@types/node@25.6.1)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.9.0): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 @@ -2538,12 +2320,12 @@ snapshots: esbuild: 0.27.7 fsevents: 2.3.3 tsx: 4.21.0 - yaml: 2.8.4 + yaml: 2.9.0 - vitest@4.1.5(@types/node@25.6.1)(vite@8.0.11(@types/node@25.6.1)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.8.4)): + vitest@4.1.5(@types/node@25.6.1)(vite@8.0.11(@types/node@25.6.1)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.5 - '@vitest/mocker': 4.1.5(vite@8.0.11(@types/node@25.6.1)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.8.4)) + '@vitest/mocker': 4.1.5(vite@8.0.11(@types/node@25.6.1)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.9.0)) '@vitest/pretty-format': 4.1.5 '@vitest/runner': 4.1.5 '@vitest/snapshot': 4.1.5 @@ -2560,7 +2342,7 @@ snapshots: tinyexec: 1.1.2 tinyglobby: 0.2.16 tinyrainbow: 3.1.0 - vite: 8.0.11(@types/node@25.6.1)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.8.4) + vite: 8.0.11(@types/node@25.6.1)(esbuild@0.27.7)(tsx@4.21.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 25.6.1 @@ -2575,3 +2357,5 @@ snapshots: ws@8.20.0: {} yaml@2.8.4: {} + + yaml@2.9.0: {} diff --git a/src/browser-context.test.ts b/src/browser-context.test.ts index d61fe1a..41d0fb7 100644 --- a/src/browser-context.test.ts +++ b/src/browser-context.test.ts @@ -11,7 +11,7 @@ type TestWindow = Window & { layer(PlaywrightEnvironment.layer(chromium))( "PlaywrightBrowserContext", (it) => { - it.scoped("should wrap context methods", () => + it.effect("should wrap context methods", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const context = yield* browser.newContext(); @@ -51,7 +51,7 @@ layer(PlaywrightEnvironment.layer(chromium))( }).pipe(PlaywrightEnvironment.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* PlaywrightBrowser; const context = yield* browser.newContext(); diff --git a/src/browser-context.ts b/src/browser-context.ts index 9eeb382..1191d96 100644 --- a/src/browser-context.ts +++ b/src/browser-context.ts @@ -1,4 +1,4 @@ -import { Context, Effect, identity, Option, Stream } from "effect"; +import { Context, Effect, identity, Option, Queue, Stream } from "effect"; import type { BrowserContext, ConsoleMessage, @@ -94,7 +94,7 @@ export interface PlaywrightBrowserContextService { * @see {@link BrowserContext.pages} * @since 0.1.0 */ - readonly pages: () => Array; + readonly pages: () => Array; /** * Opens a new page in the browser context. * @@ -106,10 +106,7 @@ export interface PlaywrightBrowserContextService { * @see {@link BrowserContext.newPage} * @since 0.1.0 */ - readonly newPage: Effect.Effect< - typeof PlaywrightPage.Service, - PlaywrightError - >; + readonly newPage: Effect.Effect; /** * Closes the browser context. * @@ -268,9 +265,10 @@ export interface PlaywrightBrowserContextService { /** * @category tag */ -export class PlaywrightBrowserContext extends Context.Tag( - "effect-playwright/PlaywrightBrowserContext", -)() { +export class PlaywrightBrowserContext extends Context.Service< + PlaywrightBrowserContext, + PlaywrightBrowserContextService +>()("effect-playwright/PlaywrightBrowserContext") { /** * Creates a `PlaywrightBrowserContext` from a Playwright `BrowserContext` instance. * @@ -289,7 +287,7 @@ export class PlaywrightBrowserContext extends Context.Tag( close: use((c) => c.close()), addInitScript: (script, arg) => use((c) => c.addInitScript(script, arg)), browser: () => - Option.fromNullable(context.browser()).pipe( + Option.fromNullishOr(context.browser()).pipe( Option.map(PlaywrightBrowser.make), ), clearCookies: (options) => use((c) => c.clearCookies(options)), @@ -307,20 +305,23 @@ export class PlaywrightBrowserContext extends Context.Tag( context.setDefaultNavigationTimeout(timeout), setDefaultTimeout: (timeout) => context.setDefaultTimeout(timeout), setStorageState: (options) => use((c) => c.setStorageState(options)), - eventStream: (event: K) => - Stream.asyncPush((emit) => - Effect.acquireRelease( + eventStream: (event: K) => + Stream.callback((queue) => { + const handler = (value: BrowserContextEvents[K]) => + Queue.offerUnsafe(queue, value); + const closeHandler = () => Queue.endUnsafe(queue); + return Effect.acquireRelease( Effect.sync(() => { - context.on(event, emit.single); - context.once("close", emit.end); + context.on(event, handler); + context.once("close", closeHandler); }), () => Effect.sync(() => { - context.off(event, emit.single); - context.off("close", emit.end); + context.off(event, handler); + context.off("close", closeHandler); }), - ), - ).pipe( + ); + }).pipe( Stream.map((e) => { const mapping = eventMappings[event]; // biome-ignore lint/suspicious/noExplicitAny: Don't know how to fix this … diff --git a/src/browser.test.ts b/src/browser.test.ts index d750fae..a4223c5 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 { PlaywrightBrowser } from "./browser"; import { Playwright } from "./index"; layer(Playwright.layer)("PlaywrightBrowser", (it) => { - it.scoped("newPage should create a page", () => + it.effect("newPage should create a page", () => Effect.gen(function* () { const playwright = yield* Playwright; const browser = yield* playwright.launchScoped(chromium); @@ -15,7 +15,7 @@ layer(Playwright.layer)("PlaywrightBrowser", (it) => { }), ); - it.scoped("use should allow accessing raw browser", () => + it.effect("use should allow accessing raw browser", () => Effect.gen(function* () { const playwright = yield* Playwright; const browser = yield* playwright.launchScoped(chromium); @@ -27,7 +27,7 @@ layer(Playwright.layer)("PlaywrightBrowser", (it) => { }), ); - it.scoped("browserType should return the browser type", () => + it.effect("browserType should return the browser type", () => Effect.gen(function* () { const playwright = yield* Playwright; const browser = yield* playwright.launchScoped(chromium); @@ -37,7 +37,7 @@ layer(Playwright.layer)("PlaywrightBrowser", (it) => { }), ); - it.scoped("version should return the browser version", () => + it.effect("version should return the browser version", () => Effect.gen(function* () { const playwright = yield* Playwright; const browser = yield* playwright.launchScoped(chromium); @@ -48,7 +48,7 @@ layer(Playwright.layer)("PlaywrightBrowser", (it) => { }), ); - it.scoped("close should close the browser", () => + it.effect("close should close the browser", () => Effect.gen(function* () { const playwright = yield* Playwright; const browser = yield* playwright.launchScoped(chromium); @@ -61,7 +61,7 @@ layer(Playwright.layer)("PlaywrightBrowser", (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; const browser = yield* playwright.launchScoped(chromium); @@ -75,7 +75,7 @@ layer(Playwright.layer)("PlaywrightBrowser", (it) => { }), ); - it.scoped("newContext should create a new context", () => + it.effect("newContext should create a new context", () => Effect.gen(function* () { const playwright = yield* Playwright; const browser = yield* playwright.launchScoped(chromium); @@ -88,7 +88,7 @@ layer(Playwright.layer)("PlaywrightBrowser", (it) => { }), ); - it.scoped("newContext should allow creating pages", () => + it.effect("newContext should allow creating pages", () => Effect.gen(function* () { const playwright = yield* Playwright; const browser = yield* playwright.launchScoped(chromium); @@ -102,7 +102,7 @@ layer(Playwright.layer)("PlaywrightBrowser", (it) => { }), ); - it.scoped("contexts should reflect newPage creation", () => + it.effect("contexts should reflect newPage creation", () => Effect.gen(function* () { const playwright = yield* Playwright; const browser = yield* playwright.launchScoped(chromium); @@ -119,7 +119,7 @@ layer(Playwright.layer)("PlaywrightBrowser", (it) => { it.effect("newContext and browser finalizers should work", () => Effect.gen(function* () { const playwright = yield* Playwright; - let capturedBrowser: typeof PlaywrightBrowser.Service | undefined; + let capturedBrowser: PlaywrightBrowser["Service"] | undefined; yield* Effect.scoped( Effect.gen(function* () { @@ -144,20 +144,20 @@ layer(Playwright.layer)("PlaywrightBrowser", (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; 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 52284fb..4a76700 100644 --- a/src/browser.ts +++ b/src/browser.ts @@ -1,4 +1,4 @@ -import { Context, Effect, Stream } from "effect"; +import { Context, Effect, Queue, Stream } from "effect"; import type { Scope } from "effect/Scope"; import type { Browser, @@ -47,7 +47,7 @@ export interface PlaywrightBrowserService { */ readonly newPage: ( options?: NewPageOptions, - ) => Effect.Effect; + ) => Effect.Effect; /** * A generic utility to execute any promise-based method on the underlying Playwright `Browser`. * Can be used to access any Browser functionality not directly exposed by this service. @@ -74,12 +74,12 @@ export interface PlaywrightBrowserService { * Returns the list of all open browser contexts. * @see {@link Browser.contexts} */ - readonly contexts: () => Array; + readonly contexts: () => Array; readonly newContext: ( options?: NewContextOptions, ) => Effect.Effect< - typeof PlaywrightBrowserContext.Service, + PlaywrightBrowserContext["Service"], PlaywrightError, Scope >; @@ -140,9 +140,10 @@ export interface PlaywrightBrowserService { /** * @category tag */ -export class PlaywrightBrowser extends Context.Tag( - "effect-playwright/PlaywrightBrowser", -)() { +export class PlaywrightBrowser extends Context.Service< + PlaywrightBrowser, + PlaywrightBrowserService +>()("effect-playwright/PlaywrightBrowser") { /** * @category constructor */ @@ -159,27 +160,30 @@ export class PlaywrightBrowser extends Context.Tag( use((browser) => browser.newContext(options).then(PlaywrightBrowserContext.make), ), - (context) => context.close.pipe(Effect.ignoreLogged), + (context) => context.close.pipe(Effect.ignore), ), browserType: () => browser.browserType(), version: () => browser.version(), isConnected: () => browser.isConnected(), bind: (title, options) => use((browser) => browser.bind(title, options)), unbind: use((browser) => browser.unbind()), - eventStream: (event: K) => - Stream.asyncPush((emit) => - Effect.acquireRelease( + eventStream: (event: K) => + Stream.callback((queue) => { + const handler = (value: BrowserEvents[K]) => + Queue.offerUnsafe(queue, value); + const closeHandler = () => Queue.endUnsafe(queue); + return Effect.acquireRelease( Effect.sync(() => { - browser.on(event, emit.single); - browser.once("disconnected", emit.end); + browser.on(event, handler); + browser.once("disconnected", closeHandler); }), () => Effect.sync(() => { - browser.off(event, emit.single); - browser.off("disconnected", emit.end); + browser.off(event, handler); + browser.off("disconnected", closeHandler); }), - ), - ).pipe( + ); + }).pipe( Stream.map((e) => { const mapping = eventMappings[event]; // biome-ignore lint/suspicious/noExplicitAny: Don't know how to fix this … diff --git a/src/clock.ts b/src/clock.ts index 88ac267..62d0a39 100644 --- a/src/clock.ts +++ b/src/clock.ts @@ -97,9 +97,10 @@ export interface PlaywrightClockService { * @since 0.1.0 * @category tag */ -export class PlaywrightClock extends Context.Tag( - "effect-playwright/PlaywrightClock", -)() { +export class PlaywrightClock extends Context.Service< + PlaywrightClock, + PlaywrightClockService +>()("effect-playwright/PlaywrightClock") { /** * Creates a `PlaywrightClock` from a Playwright `Clock` instance. * @@ -107,7 +108,7 @@ export class PlaywrightClock extends Context.Tag( * @since 0.1.0 * @category constructor */ - static make(clock: Clock): typeof PlaywrightClock.Service { + static make(clock: Clock): PlaywrightClock["Service"] { const use = useHelper(clock); return PlaywrightClock.of({ diff --git a/src/common.test.ts b/src/common.test.ts index 05d02bb..a06b386 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 { chromium } from "playwright-core"; import { PlaywrightBrowser } from "./browser"; import { PlaywrightEnvironment } from "./experimental"; layer(PlaywrightEnvironment.layer(chromium))("PlaywrightCommon", (it) => { - it.scoped("PlaywrightRequest and PlaywrightResponse", () => + it.effect("PlaywrightRequest and PlaywrightResponse", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; 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(request.url().includes("example.com")); assert(request.method() === "GET"); @@ -43,14 +47,14 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightCommon", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("PlaywrightWorker", () => + it.effect("PlaywrightWorker", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; 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")'], { @@ -59,7 +63,9 @@ layer(PlaywrightEnvironment.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(worker.url().startsWith("blob:")); const result = yield* worker.evaluate(() => 1 + 1); @@ -67,20 +73,22 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightCommon", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("PlaywrightDialog", () => + it.effect("PlaywrightDialog", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; 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(dialog.message() === "hello world"); assert(dialog.type() === "alert"); @@ -89,7 +97,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightCommon", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("PlaywrightFileChooser", () => + it.effect("PlaywrightFileChooser", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -100,12 +108,12 @@ layer(PlaywrightEnvironment.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(fileChooser.isMultiple() === false); @@ -113,7 +121,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightCommon", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("PlaywrightDownload", () => + it.effect("PlaywrightDownload", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -125,11 +133,13 @@ layer(PlaywrightEnvironment.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(download.suggestedFilename() === "test.txt"); const url = download.url(); @@ -138,7 +148,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightCommon", (it) => { const text = yield* download.stream.pipe( Stream.decodeText(), Stream.runCollect, - Effect.map(Chunk.join("")), + Effect.map((arr) => arr.join("")), ); assert.strictEqual(text, "hello world"); diff --git a/src/common.ts b/src/common.ts index 49f0b1e..4ade435 100644 --- a/src/common.ts +++ b/src/common.ts @@ -134,39 +134,39 @@ export class PlaywrightRequest extends Data.TaggedClass("PlaywrightRequest")<{ return new PlaywrightRequest({ allHeaders: use(() => request.allHeaders()), - failure: Option.liftNullable(request.failure), + failure: Option.liftNullishOr(request.failure), frame: Effect.try({ try: () => PlaywrightFrame.make(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(PlaywrightRequest.make), ), redirectedTo: (): Option.Option => - Option.fromNullable(request.redirectedTo()).pipe( + Option.fromNullishOr(request.redirectedTo()).pipe( Option.map(PlaywrightRequest.make), ), resourceType: () => request.resourceType(), response: use(() => request.response()).pipe( - Effect.map(Option.fromNullable), + Effect.map(Option.fromNullishOr), Effect.map(Option.map(PlaywrightResponse.make)), ), serviceWorker: () => - Option.fromNullable(request.serviceWorker()).pipe( + Option.fromNullishOr(request.serviceWorker()).pipe( Option.map(PlaywrightWorker.make), ), sizes: use(() => request.sizes()), @@ -240,17 +240,17 @@ export class PlaywrightResponse extends Data.TaggedClass("PlaywrightResponse")<{ 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)), json: use(() => response.json()), ok: () => response.ok(), request: () => PlaywrightRequest.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(), @@ -303,7 +303,7 @@ export class PlaywrightDialog extends Data.TaggedClass("PlaywrightDialog")<{ dismiss: use(() => dialog.dismiss()), message: () => dialog.message(), page: () => - Option.fromNullable(dialog.page()).pipe( + Option.fromNullishOr(dialog.page()).pipe( Option.map(PlaywrightPage.make), ), type: () => dialog.type(), @@ -371,19 +371,19 @@ export class PlaywrightDownload extends Data.TaggedClass("PlaywrightDownload")<{ 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: () => PlaywrightPage.make(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/event-stream.test.ts b/src/event-stream.test.ts index 0e26945..cbff078 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 { chromium } from "playwright-core"; import { PlaywrightBrowser } from "./browser"; import { PlaywrightEnvironment } from "./experimental"; layer(PlaywrightEnvironment.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* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -14,19 +14,19 @@ layer(PlaywrightEnvironment.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(PlaywrightEnvironment.withBrowser), ); - it.scoped("should complete when the browser closes", () => + it.effect("should complete when the browser closes", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -35,13 +35,13 @@ layer(PlaywrightEnvironment.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(PlaywrightEnvironment.withBrowser), diff --git a/src/experimental/browser-utils.test.ts b/src/experimental/browser-utils.test.ts index 652840b..8775fa1 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; 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; 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; 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/experimental/environment.test.ts b/src/experimental/environment.test.ts index 6dea270..e6188ed 100644 --- a/src/experimental/environment.test.ts +++ b/src/experimental/environment.test.ts @@ -49,7 +49,7 @@ const accessSecond = Effect.gen(function* () { }); layer(layerPlaywrightEnvironment(chromium))("PlaywrightEnvironment", (it) => { - it.scoped("should launch a browser", () => + it.effect("should launch a browser", () => Effect.gen(function* () { const program = Effect.gen(function* () { const playwright = yield* PlaywrightEnvironment; @@ -94,7 +94,7 @@ layer(layerPlaywrightEnvironment(chromium))("PlaywrightEnvironment", (it) => { it.effect("withBrowser scope cleanup", () => Effect.gen(function* () { - let capturedBrowser: typeof PlaywrightBrowser.Service | undefined; + let capturedBrowser: PlaywrightBrowser["Service"] | undefined; yield* withBrowser( Effect.gen(function* () { diff --git a/src/experimental/environment.ts b/src/experimental/environment.ts index 1f18cb2..ab2e4c4 100644 --- a/src/experimental/environment.ts +++ b/src/experimental/environment.ts @@ -1,8 +1,9 @@ -import { Context, Effect, Layer } from "effect"; +import { Context, Effect, Layer, pipe } from "effect"; import type { Scope } from "effect/Scope"; -import { Playwright, PlaywrightBrowser } from "effect-playwright"; import type { BrowserType, LaunchOptions } from "playwright-core"; +import { PlaywrightBrowser } from "../browser"; import type { PlaywrightError } from "../errors"; +import { Playwright } from "../playwright"; /** * Most of the time you want to use the same kind of browser and configuration every time you use Playwright. @@ -14,18 +15,16 @@ import type { PlaywrightError } from "../errors"; * @since 0.1.0 * @category tag */ -export class PlaywrightEnvironment extends Context.Tag( - "effect-playwright/experimental/PlaywrightEnvironment", -)< +export class PlaywrightEnvironment extends Context.Service< PlaywrightEnvironment, { browser: Effect.Effect< - typeof PlaywrightBrowser.Service, + PlaywrightBrowser["Service"], PlaywrightError, Scope >; } ->() {} +>()("effect-playwright/experimental/PlaywrightEnvironment") {} /** * Creates a Layer that initializes the `PlaywrightEnvironment`. @@ -54,7 +53,8 @@ export class PlaywrightEnvironment extends Context.Tag( * @category layer */ export const layer = (browser: BrowserType, launchOptions?: LaunchOptions) => - Playwright.pipe( + pipe( + Playwright, Effect.map((playwright) => PlaywrightEnvironment.of({ browser: playwright.launchScoped(browser, launchOptions), @@ -64,10 +64,20 @@ export const layer = (browser: BrowserType, launchOptions?: LaunchOptions) => Layer.provide(Playwright.layer), ); -const withBrowserUnscoped = Effect.provideServiceEffect( - PlaywrightBrowser, - PlaywrightEnvironment.pipe(Effect.flatMap((e) => e.browser)), -); +const withBrowserUnscoped = ( + self: Effect.Effect, +): Effect.Effect< + A, + E | PlaywrightError, + Exclude | Scope | PlaywrightEnvironment +> => + Effect.provideServiceEffect( + PlaywrightBrowser, + pipe( + PlaywrightEnvironment, + Effect.flatMap((e) => e.browser), + ), + )(self); /** * Provides a scoped `PlaywrightBrowser` service, allowing you to access the browser from the context (e.g. by yielding `PlaywrightBrowser`). @@ -94,5 +104,10 @@ const withBrowserUnscoped = Effect.provideServiceEffect( * @since 0.1.0 * @category util */ -export const withBrowser = (self: Effect.Effect) => - Effect.scoped(withBrowserUnscoped(self)); // TODO: roast check if using Effect.scope here is an anti-pattern +export const withBrowser = ( + self: Effect.Effect, +): Effect.Effect< + A, + E | PlaywrightError, + Exclude | PlaywrightEnvironment +> => Effect.scoped(withBrowserUnscoped(self)); diff --git a/src/frame-locator.ts b/src/frame-locator.ts index 336facf..3fb6444 100644 --- a/src/frame-locator.ts +++ b/src/frame-locator.ts @@ -148,9 +148,10 @@ export interface PlaywrightFrameLocatorService { * @since 0.1.0 * @category tag */ -export class PlaywrightFrameLocator extends Context.Tag( - "effect-playwright/PlaywrightFrameLocator", -)() { +export class PlaywrightFrameLocator extends Context.Service< + PlaywrightFrameLocator, + PlaywrightFrameLocatorService +>()("effect-playwright/PlaywrightFrameLocator") { /** * Creates a `PlaywrightFrameLocator` from a Playwright `FrameLocator` instance. * @@ -158,9 +159,7 @@ export class PlaywrightFrameLocator extends Context.Tag( * @since 0.1.0 * @category constructor */ - static make( - frameLocator: FrameLocator, - ): typeof PlaywrightFrameLocator.Service { + static make(frameLocator: FrameLocator): PlaywrightFrameLocator["Service"] { const unwrap = Match.type< string | Locator | PlaywrightLocatorService >().pipe( diff --git a/src/frame.test.ts b/src/frame.test.ts index 22cf3ef..2ca079b 100644 --- a/src/frame.test.ts +++ b/src/frame.test.ts @@ -6,7 +6,7 @@ import { PlaywrightEnvironment } from "./experimental"; import type { PlaywrightFrameService } from "./frame"; layer(PlaywrightEnvironment.layer(chromium))("PlaywrightFrame", (it) => { - it.scoped("should wrap frame methods", () => + it.effect("should wrap frame methods", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -30,10 +30,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightFrame", (it) => { Effect.succeed(f.name() === "test-frame"); const frame = yield* Effect.findFirst(frames, isTestFrame).pipe( - Effect.flatten, - Effect.retry({ - times: 3, - }), + Effect.flatMap(Effect.fromOption), ); assert.isOk(frame, "Frame not found"); @@ -114,7 +111,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightFrame", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("waitForLoadState should resolve on frame", () => + it.effect("waitForLoadState should resolve on frame", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); diff --git a/src/frame.ts b/src/frame.ts index 3fa707c..eed027f 100644 --- a/src/frame.ts +++ b/src/frame.ts @@ -79,7 +79,7 @@ export interface PlaywrightFrameService { readonly locator: ( selector: string, options?: Parameters[1], - ) => typeof PlaywrightLocator.Service; + ) => PlaywrightLocator["Service"]; /** * Returns a locator that matches the given role. * @@ -89,7 +89,7 @@ export interface PlaywrightFrameService { readonly getByRole: ( role: Parameters[0], options?: Parameters[1], - ) => typeof PlaywrightLocator.Service; + ) => PlaywrightLocator["Service"]; /** * Returns a locator that matches the given text. * @@ -99,7 +99,7 @@ export interface PlaywrightFrameService { readonly getByText: ( text: Parameters[0], options?: Parameters[1], - ) => typeof PlaywrightLocator.Service; + ) => PlaywrightLocator["Service"]; /** * Returns a locator that matches the given label. * @@ -109,7 +109,7 @@ export interface PlaywrightFrameService { readonly getByLabel: ( label: Parameters[0], options?: Parameters[1], - ) => typeof PlaywrightLocator.Service; + ) => PlaywrightLocator["Service"]; /** * Returns a locator that matches the given test id. * @@ -118,7 +118,7 @@ export interface PlaywrightFrameService { */ readonly getByTestId: ( testId: Parameters[0], - ) => typeof PlaywrightLocator.Service; + ) => PlaywrightLocator["Service"]; /** * Returns a locator that matches the given placeholder. @@ -129,7 +129,7 @@ export interface PlaywrightFrameService { readonly getByPlaceholder: ( text: Parameters[0], options?: Parameters[1], - ) => typeof PlaywrightLocator.Service; + ) => PlaywrightLocator["Service"]; /** * Returns a locator that matches the given alt text. @@ -140,7 +140,7 @@ export interface PlaywrightFrameService { readonly getByAltText: ( text: Parameters[0], options?: Parameters[1], - ) => typeof PlaywrightLocator.Service; + ) => PlaywrightLocator["Service"]; /** * Returns a locator that matches the given title. @@ -151,7 +151,7 @@ export interface PlaywrightFrameService { readonly getByTitle: ( text: Parameters[0], options?: Parameters[1], - ) => typeof PlaywrightLocator.Service; + ) => PlaywrightLocator["Service"]; /** * Returns the page that the frame belongs to. @@ -248,9 +248,10 @@ export interface PlaywrightFrameService { * @category tag * @since 0.1.2 */ -export class PlaywrightFrame extends Context.Tag( - "effect-playwright/PlaywrightFrame", -)() { +export class PlaywrightFrame extends Context.Service< + PlaywrightFrame, + PlaywrightFrameService +>()("effect-playwright/PlaywrightFrame") { /** * Creates a `PlaywrightFrame` from a Playwright `Frame` instance. * @@ -287,7 +288,7 @@ export class PlaywrightFrame extends Context.Tag( PlaywrightLocator.make(frame.getByTitle(text, options)), page: () => PlaywrightPage.make(frame.page()), parentFrame: () => - Option.fromNullable(frame.parentFrame()).pipe( + Option.fromNullishOr(frame.parentFrame()).pipe( Option.map(PlaywrightFrame.make), ), childFrames: () => diff --git a/src/keyboard.ts b/src/keyboard.ts index e00cbab..68e5169 100644 --- a/src/keyboard.ts +++ b/src/keyboard.ts @@ -60,9 +60,10 @@ export interface PlaywrightKeyboardService { /** * @category tag */ -export class PlaywrightKeyboard extends Context.Tag( - "effect-playwright/PlaywrightKeyboard", -)() { +export class PlaywrightKeyboard extends Context.Service< + PlaywrightKeyboard, + PlaywrightKeyboardService +>()("effect-playwright/PlaywrightKeyboard") { /** * Creates a `PlaywrightKeyboard` from a Playwright `Keyboard` instance. * @@ -73,11 +74,18 @@ export class PlaywrightKeyboard extends Context.Tag( const use = useHelper(keyboard); return PlaywrightKeyboard.of({ - down: (key) => use((k) => k.down(key)), - insertText: (text) => use((k) => k.insertText(text)), - press: (key, options) => use((k) => k.press(key, options)), - type: (text, options) => use((k) => k.type(text, options)), - up: (key) => use((k) => k.up(key)), + down: (key: Parameters[0]) => use((k) => k.down(key)), + insertText: (text: Parameters[0]) => + use((k) => k.insertText(text)), + press: ( + key: Parameters[0], + options?: Parameters[1], + ) => use((k) => k.press(key, options)), + type: ( + text: Parameters[0], + options?: Parameters[1], + ) => use((k) => k.type(text, options)), + up: (key: Parameters[0]) => use((k) => k.up(key)), }); } } diff --git a/src/locator.test.ts b/src/locator.test.ts index 4f59808..f9b9f94 100644 --- a/src/locator.test.ts +++ b/src/locator.test.ts @@ -6,7 +6,7 @@ import { PlaywrightBrowser } from "./browser"; import { PlaywrightEnvironment } from "./experimental"; layer(PlaywrightEnvironment.layer(chromium))("PlaywrightLocator", (it) => { - it.scoped("should work", () => + it.effect("should work", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -19,7 +19,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightLocator", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("evaluate", () => + it.effect("evaluate", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -41,7 +41,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightLocator", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("waitFor", () => + it.effect("waitFor", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -69,7 +69,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightLocator", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("kitchensink", () => + it.effect("kitchensink", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -299,7 +299,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightLocator", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped( + it.effect( "new methods: all, and, filter, or, page, frameLocator, contentFrame", () => Effect.gen(function* () { @@ -360,7 +360,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightLocator", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("action methods", () => + it.effect("action methods", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); diff --git a/src/locator.ts b/src/locator.ts index 16a617a..04b9b8f 100644 --- a/src/locator.ts +++ b/src/locator.ts @@ -506,7 +506,7 @@ export interface PlaywrightLocatorService { * @see {@link Locator.page} * @since 0.4.1 */ - readonly page: () => typeof PlaywrightPage.Service; + readonly page: () => PlaywrightPage["Service"]; /** * Removes keyboard focus from the current element. * @@ -684,9 +684,10 @@ export interface PlaywrightLocatorService { * @since 0.1.0 * @category tag */ -export class PlaywrightLocator extends Context.Tag( - "effect-playwright/PlaywrightLocator", -)() { +export class PlaywrightLocator extends Context.Service< + PlaywrightLocator, + PlaywrightLocatorService +>()("effect-playwright/PlaywrightLocator") { /** * Creates a `PlaywrightLocator` from a Playwright `Locator` instance. This is mostly for internal use. * But you could use this if you have used `use` or similar to wrap the locator. @@ -701,7 +702,7 @@ export class PlaywrightLocator extends Context.Tag( * @since 0.1.0 * @category constructor */ - static make(locator: Locator): typeof PlaywrightLocator.Service { + static make(locator: Locator): PlaywrightLocator["Service"] { const use = useHelper(locator); const unwrap = Match.type().pipe( Match.when(Predicate.hasProperty("_raw"), (l) => l._raw), @@ -724,11 +725,11 @@ export class PlaywrightLocator extends Context.Tag( ariaSnapshot: (options) => use((l) => l.ariaSnapshot(options)), boundingBox: (options) => use((l) => l.boundingBox(options)).pipe( - Effect.map(Option.fromNullable), + Effect.map(Option.fromNullishOr), ), describe: (description) => PlaywrightLocator.make(locator.describe(description)), - description: () => Option.fromNullable(locator.description()), + description: () => Option.fromNullishOr(locator.description()), count: use((l) => l.count()), first: () => PlaywrightLocator.make(locator.first()), last: () => PlaywrightLocator.make(locator.last()), @@ -798,7 +799,7 @@ export class PlaywrightLocator extends Context.Tag( ) => use((l) => l.evaluateHandle(pageFunction, arg as Arg)), elementHandle: (options) => use((l) => l.elementHandle(options)).pipe( - Effect.map(Option.fromNullable), + Effect.map(Option.fromNullishOr), ), elementHandles: () => use( diff --git a/src/mouse.ts b/src/mouse.ts index af9843d..c72fa20 100644 --- a/src/mouse.ts +++ b/src/mouse.ts @@ -74,9 +74,10 @@ export interface PlaywrightMouseService { /** * @category tag */ -export class PlaywrightMouse extends Context.Tag( - "effect-playwright/PlaywrightMouse", -)() { +export class PlaywrightMouse extends Context.Service< + PlaywrightMouse, + PlaywrightMouseService +>()("effect-playwright/PlaywrightMouse") { /** * Creates a `PlaywrightMouse` from a Playwright `Mouse` instance. * diff --git a/src/page.test.ts b/src/page.test.ts index ee76e9f..b716cb5 100644 --- a/src/page.test.ts +++ b/src/page.test.ts @@ -12,7 +12,7 @@ type TestWindow = Window & { }; layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { - it.scoped("goto should navigate to a URL", () => + it.effect("goto should navigate to a URL", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -25,7 +25,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("setContent should set the page content", () => + it.effect("setContent should set the page content", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -36,7 +36,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("title should return the page title", () => + it.effect("title should return the page title", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -47,7 +47,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("content should return the page content", () => + it.effect("content should return the page content", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -60,7 +60,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("click should click an element", () => + it.effect("click should click an element", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -81,7 +81,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("goto should work with options", () => + it.effect("goto should work with options", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -92,7 +92,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("waitForTimeout should wait", () => + it.effect("waitForTimeout should wait", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -104,7 +104,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped( + it.effect( "evaluate should run code in the page context with destructured arg", () => Effect.gen(function* () { @@ -119,7 +119,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.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* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -129,7 +129,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("click should work with options", () => + it.effect("click should work with options", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -154,7 +154,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.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* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -164,7 +164,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("locator should work with options", () => + it.effect("locator should work with options", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -185,7 +185,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("getBy* methods should work", () => + it.effect("getBy* methods should work", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -230,7 +230,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("waitForURL should work with History API", () => + it.effect("waitForURL should work with History API", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -246,7 +246,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("filechooser event should work", () => + it.effect("filechooser event should work", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -257,17 +257,19 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (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(PlaywrightEnvironment.withBrowser), ); - it.scoped("waitForLoadState should resolve", () => + it.effect("waitForLoadState should resolve", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -283,7 +285,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { assert.ok(true); }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("url property should update after navigation", () => + it.effect("url property should update after navigation", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -298,7 +300,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.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* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -318,7 +320,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("requestGC should execute without error", () => + it.effect("requestGC should execute without error", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -328,7 +330,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("clock should allow fast forwarding time", () => + it.effect("clock should allow fast forwarding time", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -357,7 +359,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.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* PlaywrightBrowser; const context = yield* browser.newContext(); @@ -389,7 +391,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.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* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -407,7 +409,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("keyboard should allow typing text", () => + it.effect("keyboard should allow typing text", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -426,7 +428,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("mouse should allow dispatching events", () => + it.effect("mouse should allow dispatching events", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -451,7 +453,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("touchscreen should allow dispatching events", () => + it.effect("touchscreen should allow dispatching events", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const context = yield* browser.newContext({ hasTouch: true }); @@ -487,7 +489,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("screenshot should capture an image", () => + it.effect("screenshot should capture an image", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -500,7 +502,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("pdf should capture a PDF", () => + it.effect("pdf should capture a PDF", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -513,7 +515,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.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* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -529,7 +531,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.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* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -551,7 +553,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { assert.strictEqual(color, "rgb(255, 0, 0)"); }).pipe(PlaywrightEnvironment.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* PlaywrightBrowser; const context = yield* browser.newContext(); @@ -566,7 +568,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("consoleMessages should return console messages", () => + it.effect("consoleMessages should return console messages", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -586,7 +588,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("pageerror event should work", () => + it.effect("pageerror event should work", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -595,7 +597,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { const errorFiber = yield* page .eventStream("pageerror") - .pipe(Stream.runHead, Effect.fork); + .pipe(Stream.runHead, Effect.forkChild()); yield* page.evaluate(() => { setTimeout(() => { @@ -603,13 +605,14 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }, 0); }); - const errorOpt = yield* Fiber.join(errorFiber); - const error = Option.getOrThrow(errorOpt); + const error = yield* Fiber.join(errorFiber).pipe( + Effect.flatMap(Effect.fromOption), + ); assert.strictEqual(error.message, "Test Error"); }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("pageErrors should return all page errors", () => + it.effect("pageErrors should return all page errors", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -618,7 +621,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { const errorFiber = yield* page .eventStream("pageerror") - .pipe(Stream.runHead, Effect.fork); + .pipe(Stream.runHead, Effect.forkChild()); yield* page.evaluate(() => { setTimeout(() => { @@ -634,7 +637,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.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* PlaywrightBrowser; const context = yield* browser.newContext(); @@ -649,7 +652,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.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* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -681,7 +684,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("emulateMedia should emulate media features", () => + it.effect("emulateMedia should emulate media features", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -706,7 +709,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped( + it.effect( "exposeFunction should expose an function that runs an effect", () => Effect.gen(function* () { @@ -729,7 +732,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("exposeFunction should work with Effect.fn", () => + it.effect("exposeFunction should work with Effect.fn", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -754,7 +757,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("exposeEffect should expose an effect", () => + it.effect("exposeEffect should expose an effect", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -776,7 +779,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("frame should return an Option of PlaywrightFrame", () => + it.effect("frame should return an Option of PlaywrightFrame", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -796,7 +799,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.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* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -809,7 +812,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("mainFrame should return the main frame", () => + it.effect("mainFrame should return the main frame", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -822,7 +825,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("opener should return the opener page", () => + it.effect("opener should return the opener page", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -831,25 +834,25 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { const popupFiber = yield* page .eventStream("popup") - .pipe(Stream.runHead, Effect.fork); + .pipe(Stream.runHead, Effect.forkChild()); yield* page.evaluate(() => { window.open("about:blank"); }); - const popupOpt = yield* Fiber.join(popupFiber); - const popup = Option.getOrThrow(popupOpt); - - const openerOpt = yield* popup.opener; - assert(Option.isSome(openerOpt), "Opener should be Some"); + const popup = yield* Fiber.join(popupFiber).pipe( + Effect.flatMap(Effect.fromOption), + ); - const opener = Option.getOrThrow(openerOpt); + const opener = yield* popup.opener.pipe( + Effect.flatMap(Effect.fromOption), + ); const url = opener.url(); assert.strictEqual(url, "about:blank"); }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("setViewportSize should update viewport dimensions", () => + it.effect("setViewportSize should update viewport dimensions", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -865,22 +868,20 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.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* PlaywrightBrowser; const page = yield* browser.newPage(); yield* page.setViewportSize({ width: 600, height: 400 }); - const sizeOpt = page.viewportSize(); - assert(Option.isSome(sizeOpt)); - const size = Option.getOrThrow(sizeOpt); + const size = yield* Effect.fromOption(page.viewportSize()); assert.strictEqual(size.width, 600); assert.strictEqual(size.height, 400); }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("setExtraHTTPHeaders should not crash", () => + it.effect("setExtraHTTPHeaders should not crash", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -890,7 +891,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("setDefaultNavigationTimeout should not crash", () => + it.effect("setDefaultNavigationTimeout should not crash", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -900,7 +901,7 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.withBrowser), ); - it.scoped("setDefaultTimeout should influence timeouts", () => + it.effect("setDefaultTimeout should influence timeouts", () => Effect.gen(function* () { const browser = yield* PlaywrightBrowser; const page = yield* browser.newPage(); @@ -916,14 +917,14 @@ layer(PlaywrightEnvironment.layer(chromium))("PlaywrightPage", (it) => { }).pipe(PlaywrightEnvironment.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* PlaywrightBrowser; 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,", diff --git a/src/page.ts b/src/page.ts index edb4e13..a433101 100644 --- a/src/page.ts +++ b/src/page.ts @@ -4,7 +4,7 @@ import { Effect, identity, Option, - Runtime, + Queue, Stream, } from "effect"; import type { @@ -453,7 +453,7 @@ export interface PlaywrightPageService { readonly locator: ( selector: string, options?: Parameters[1], - ) => typeof PlaywrightLocator.Service; + ) => PlaywrightLocator["Service"]; /** * Returns a locator that matches the given role. * @@ -463,7 +463,7 @@ export interface PlaywrightPageService { readonly getByRole: ( role: Parameters[0], options?: Parameters[1], - ) => typeof PlaywrightLocator.Service; + ) => PlaywrightLocator["Service"]; /** * Returns a locator that matches the given text. * @@ -473,7 +473,7 @@ export interface PlaywrightPageService { readonly getByText: ( text: Parameters[0], options?: Parameters[1], - ) => typeof PlaywrightLocator.Service; + ) => PlaywrightLocator["Service"]; /** * Returns a locator that matches the given label. * @@ -483,7 +483,7 @@ export interface PlaywrightPageService { readonly getByLabel: ( label: Parameters[0], options?: Parameters[1], - ) => typeof PlaywrightLocator.Service; + ) => PlaywrightLocator["Service"]; /** * Returns a locator that matches the given test id. * @@ -492,7 +492,7 @@ export interface PlaywrightPageService { */ readonly getByTestId: ( testId: Parameters[0], - ) => typeof PlaywrightLocator.Service; + ) => PlaywrightLocator["Service"]; /** * Returns a locator that matches the given alt text. * @@ -502,7 +502,7 @@ export interface PlaywrightPageService { readonly getByAltText: ( text: Parameters[0], options?: Parameters[1], - ) => typeof PlaywrightLocator.Service; + ) => PlaywrightLocator["Service"]; /** * Returns a locator that matches the given placeholder. * @@ -512,7 +512,7 @@ export interface PlaywrightPageService { readonly getByPlaceholder: ( text: Parameters[0], options?: Parameters[1], - ) => typeof PlaywrightLocator.Service; + ) => PlaywrightLocator["Service"]; /** * Returns a locator that matches the given title. * @@ -522,7 +522,7 @@ export interface PlaywrightPageService { readonly getByTitle: ( text: Parameters[0], options?: Parameters[1], - ) => typeof PlaywrightLocator.Service; + ) => PlaywrightLocator["Service"]; /** * Captures a screenshot of the page. @@ -760,7 +760,7 @@ export interface PlaywrightPageService { * @since 0.5.0 */ readonly pickLocator: Effect.Effect< - typeof PlaywrightLocator.Service, + PlaywrightLocator["Service"], PlaywrightError >; @@ -822,7 +822,7 @@ export interface PlaywrightPageService { */ readonly frame: ( frameSelector: Parameters[0], - ) => Option.Option; + ) => Option.Option; /** * Returns all frames attached to the page. @@ -831,7 +831,7 @@ export interface PlaywrightPageService { * @since 0.2.0 */ readonly frames: Effect.Effect< - ReadonlyArray, + ReadonlyArray, PlaywrightError >; /** @@ -840,7 +840,7 @@ export interface PlaywrightPageService { * @see {@link Page.mainFrame} * @since 0.3.0 */ - readonly mainFrame: () => typeof PlaywrightFrame.Service; + readonly mainFrame: () => PlaywrightFrame["Service"]; /** * Creates a stream of the given event from the page. * @@ -861,9 +861,10 @@ export interface PlaywrightPageService { /** * @category tag */ -export class PlaywrightPage extends Context.Tag( - "effect-playwright/PlaywrightPage", -)() { +export class PlaywrightPage extends Context.Service< + PlaywrightPage, + PlaywrightPageService +>()("effect-playwright/PlaywrightPage") { /** * Creates a `PlaywrightPage` from a Playwright `Page` instance. * @@ -889,7 +890,7 @@ export class PlaywrightPage extends Context.Tag( use((p) => p.setExtraHTTPHeaders(headers)), setViewportSize: (viewportSize) => use((p) => p.setViewportSize(viewportSize)), - viewportSize: () => Option.fromNullable(page.viewportSize()), + viewportSize: () => Option.fromNullishOr(page.viewportSize()), waitForURL: (url, options) => use((p) => p.waitForURL(url, options)), waitForLoadState: (state, options) => use((p) => p.waitForLoadState(state, options)), @@ -904,8 +905,8 @@ export class PlaywrightPage extends Context.Tag( name: string, effectFn: (...args: Args) => Effect.Effect, ) => - Effect.runtime().pipe( - Effect.map((r) => Runtime.runPromise(r)), + Effect.context().pipe( + Effect.map((services) => Effect.runPromiseWith(services)), Effect.flatMap((runPromise) => use((p) => p.exposeFunction(name, (...args: Args) => @@ -915,8 +916,8 @@ export class PlaywrightPage extends Context.Tag( ), ), exposeEffect: (name: string, effectFn: Effect.Effect) => - Effect.runtime().pipe( - Effect.map((r) => Runtime.runPromise(r)), + Effect.context().pipe( + Effect.map((services) => Effect.runPromiseWith(services)), Effect.flatMap((runPromise) => use((p) => p.exposeFunction(name, () => runPromise(effectFn))), ), @@ -950,13 +951,12 @@ export class PlaywrightPage extends Context.Tag( ariaSnapshot: (options) => use((p) => p.ariaSnapshot(options)), context: () => PlaywrightBrowserContext.make(page.context()), opener: use((p) => p.opener()).pipe( - Effect.map(Option.fromNullable), + Effect.map(Option.fromNullishOr), Effect.map(Option.map(PlaywrightPage.make)), ), workers: () => page.workers().map(PlaywrightWorker.make), - frame: (frameSelector) => - Option.fromNullable(page.frame(frameSelector)).pipe( + Option.fromNullishOr(page.frame(frameSelector)).pipe( Option.map(PlaywrightFrame.make), ), frames: use((p) => Promise.resolve(p.frames().map(PlaywrightFrame.make))), @@ -964,12 +964,12 @@ export class PlaywrightPage extends Context.Tag( reload: use((p) => p.reload()), goBack: (options) => use((p) => p.goBack(options)).pipe( - Effect.map(Option.fromNullable), + Effect.map(Option.fromNullishOr), Effect.map(Option.map(PlaywrightResponse.make)), ), goForward: (options) => use((p) => p.goForward(options)).pipe( - Effect.map(Option.fromNullable), + Effect.map(Option.fromNullishOr), Effect.map(Option.map(PlaywrightResponse.make)), ), requestGC: use((p) => p.requestGC()), @@ -983,20 +983,23 @@ export class PlaywrightPage extends Context.Tag( use((p) => p.dragAndDrop(source, target, options)), click: (selector, options) => use((p) => p.click(selector, options)), emulateMedia: (options) => use((p) => p.emulateMedia(options)), - eventStream: (event: K) => - Stream.asyncPush((emit) => - Effect.acquireRelease( + eventStream: (event: K) => + Stream.callback((queue) => { + const handler = (value: PageEvents[K]) => + Queue.offerUnsafe(queue, value); + const closeHandler = () => Queue.endUnsafe(queue); + return Effect.acquireRelease( Effect.sync(() => { - page.on(event, emit.single); - page.once("close", emit.end); + page.on(event, handler); + page.once("close", closeHandler); }), () => Effect.sync(() => { - page.off(event, emit.single); - page.off("close", emit.end); + page.off(event, handler); + page.off("close", closeHandler); }), - ), - ).pipe( + ); + }).pipe( Stream.map((e) => { const mapping = eventMappings[event]; // biome-ignore lint/suspicious/noExplicitAny: Don't know how to fix this … diff --git a/src/playwright.test.ts b/src/playwright.test.ts index 35fbc26..aa6f47b 100644 --- a/src/playwright.test.ts +++ b/src/playwright.test.ts @@ -5,7 +5,7 @@ import { chromium } from "playwright-core"; import type { PlaywrightBrowserContext } 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 = yield* Playwright; @@ -19,7 +19,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; @@ -39,7 +39,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; const context = yield* playwright.launchPersistentContext(chromium, ""); @@ -53,10 +53,10 @@ 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; - let capturedContext: typeof PlaywrightBrowserContext.Service | undefined; + let capturedContext: PlaywrightBrowserContext["Service"] | undefined; yield* Effect.gen(function* () { const context = yield* playwright.launchPersistentContextScoped( @@ -79,7 +79,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; const result = yield* playwright @@ -94,7 +94,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; const result = yield* playwright @@ -111,7 +111,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; @@ -141,7 +141,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; diff --git a/src/playwright.ts b/src/playwright.ts index 76deeee..14cd65e 100644 --- a/src/playwright.ts +++ b/src/playwright.ts @@ -46,7 +46,7 @@ export interface PlaywrightService { launch: ( browserType: BrowserType, options?: LaunchOptions, - ) => Effect.Effect; + ) => Effect.Effect; /** * Launches a new browser instance managed by a Scope. * @@ -73,7 +73,7 @@ export interface PlaywrightService { browserType: BrowserType, options?: LaunchOptions, ) => Effect.Effect< - typeof PlaywrightBrowser.Service, + PlaywrightBrowser["Service"], PlaywrightError, Scope.Scope >; @@ -137,7 +137,7 @@ export interface PlaywrightService { browserType: BrowserType, userDataDir: string, options?: LaunchPersistentContextOptions, - ) => Effect.Effect; + ) => Effect.Effect; /** * Launches a persistent browser context managed by a Scope. * @@ -173,7 +173,7 @@ export interface PlaywrightService { userDataDir: string, options?: LaunchPersistentContextOptions, ) => Effect.Effect< - typeof PlaywrightBrowserContext.Service, + PlaywrightBrowserContext["Service"], PlaywrightError, Scope.Scope >; @@ -206,7 +206,7 @@ export interface PlaywrightService { connectCDP: ( cdpUrl: string, options?: ConnectOverCDPOptions, - ) => Effect.Effect; + ) => Effect.Effect; /** * Connects to a browser instance via Chrome DevTools Protocol (CDP) managed by a Scope. * @@ -236,7 +236,7 @@ export interface PlaywrightService { cdpUrl: string, options?: ConnectOverCDPOptions, ) => Effect.Effect< - typeof PlaywrightBrowser.Service, + PlaywrightBrowser["Service"], PlaywrightError, Scope.Scope >; @@ -245,34 +245,36 @@ export interface PlaywrightService { const launch: ( browserType: BrowserType, options?: LaunchOptions, -) => Effect.Effect = - Effect.fn(function* (browserType: BrowserType, options?: LaunchOptions) { +) => Effect.Effect = Effect.fn( + function* (browserType: BrowserType, options?: LaunchOptions) { const rawBrowser = yield* Effect.tryPromise({ try: () => browserType.launch(options), catch: wrapError, }); return PlaywrightBrowser.make(rawBrowser); - }); + }, +); const connectCDP: ( cdpUrl: string, options?: ConnectOverCDPOptions, -) => Effect.Effect = - Effect.fn(function* (cdpUrl: string, options?: ConnectOverCDPOptions) { +) => Effect.Effect = Effect.fn( + function* (cdpUrl: string, options?: ConnectOverCDPOptions) { const browser = yield* Effect.tryPromise({ try: () => chromium.connectOverCDP(cdpUrl, options), catch: wrapError, }); return PlaywrightBrowser.make(browser); - }); + }, +); const launchPersistentContext: ( browserType: BrowserType, userDataDir: string, options?: LaunchPersistentContextOptions, -) => Effect.Effect = +) => Effect.Effect = Effect.fn(function* ( browserType: BrowserType, userDataDir: string, @@ -290,9 +292,10 @@ const launchPersistentContext: ( * @category tag * @since 0.1.0 */ -export class Playwright extends Context.Tag( - "effect-playwright/index/Playwright", -)() { +export class Playwright extends Context.Service< + Playwright, + PlaywrightService +>()("effect-playwright/index/Playwright") { /** * @category layer */ diff --git a/src/screencast.ts b/src/screencast.ts index 8028bb6..ef8e5a8 100644 --- a/src/screencast.ts +++ b/src/screencast.ts @@ -86,9 +86,10 @@ export interface PlaywrightScreencastService { /** * @category tag */ -export class PlaywrightScreencast extends Context.Tag( - "effect-playwright/PlaywrightScreencast", -)() { +export class PlaywrightScreencast extends Context.Service< + PlaywrightScreencast, + PlaywrightScreencastService +>()("effect-playwright/PlaywrightScreencast") { /** * @category constructor */ diff --git a/src/touchscreen.ts b/src/touchscreen.ts index b137bda..e707e69 100644 --- a/src/touchscreen.ts +++ b/src/touchscreen.ts @@ -25,9 +25,10 @@ export interface PlaywrightTouchscreenService { * @category tag * @since 0.3.0 */ -export class PlaywrightTouchscreen extends Context.Tag( - "effect-playwright/PlaywrightTouchscreen", -)() { +export class PlaywrightTouchscreen extends Context.Service< + PlaywrightTouchscreen, + PlaywrightTouchscreenService +>()("effect-playwright/PlaywrightTouchscreen") { /** * Creates a `PlaywrightTouchscreen` from a Playwright `Touchscreen` instance. * diff --git a/src/tracing.ts b/src/tracing.ts index ef32fae..6df9001 100644 --- a/src/tracing.ts +++ b/src/tracing.ts @@ -70,9 +70,10 @@ export interface PlaywrightTracingService { /** * @category tag */ -export class PlaywrightTracing extends Context.Tag( - "effect-playwright/PlaywrightTracing", -)() { +export class PlaywrightTracing extends Context.Service< + PlaywrightTracing, + PlaywrightTracingService +>()("effect-playwright/PlaywrightTracing") { /** * @category constructor */