@walletwright/core 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,110 @@
1
+ # @walletwright/core
2
+
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 25a0f0b: Run wallet suites headless. `launchWallet` takes `{ headless }` and `createWalletFixtures` passes
8
+ Playwright's own `headless` option through, so `--headed` and `use: { headless }` now reach the
9
+ wallet's browser. Headless launches the `chromium` channel, because Playwright's default headless
10
+ build is the headless shell, which cannot load an extension at all.
11
+
12
+ Whether it then works is per wallet, and a wallet says so with the new
13
+ `WalletDefinition.headlessApprovals`: Phantom's and Rabby's approval windows surface as pages
14
+ headless, MetaMask's is created but never exposed, and Solflare rejects a headless connect outright.
15
+ `launchWallet` throws a named error for a wallet that has not declared it, rather than hanging at
16
+ the first approval.
17
+
18
+ Two smaller changes go with it. `WalletDefinition.approvalControls` lets a wallet say which controls
19
+ mean "a request is on screen", so a popup that renders the wallet's home screen is not mistaken for
20
+ an approval; MetaMask declares it. And an approval window is now pinned to 360x592 and moved on
21
+ screen over CDP before it is clicked, because a popup that opens partly off a small or virtual
22
+ display renders fine but cannot be clicked.
23
+
24
+ ### Patch Changes
25
+
26
+ - b84bd5a: Declare each wallet capability once. `AccountActions`, `NetworkActions` and `SettingsActions` are now
27
+ derived from the matching `AccountsApi`, `NetworkApi` and `SettingsApi` types on `Wallet`, so a
28
+ capability's name and argument list are written in a single place and the controller stops compiling
29
+ until a new one is bound. Published types are unchanged: the derived aliases resolve to exactly the
30
+ shapes they replaced.
31
+ - a7f7a51: Fix the `walletwright` CLI doing nothing when run from an installed package.
32
+
33
+ The entry guard compared `import.meta.url` against a raw `process.argv[1]`. Node resolves the
34
+ former through symlinks and leaves the latter alone, so every invocation through
35
+ `node_modules/.bin/walletwright` (a symlink under any pnpm install) compared unequal, skipped
36
+ `main()`, and exited 0 without output. The guard now resolves the entry path first.
37
+
38
+ With the CLI reachable again, `walletwright --help` and `walletwright -h` print the help text
39
+ instead of erroring with "unknown command": flags are now parsed from the whole argv rather than
40
+ only the tokens after a command, so a leading flag is seen.
41
+
42
+ - 0341a74: Drop the `prepare` script. It rebuilt the package after every `pnpm install`, outside turbo's cache
43
+ and graph, duplicating work `prepack` already does when publishing. Installing from a git reference
44
+ now needs an explicit build.
45
+ - 0341a74: Fail loudly when a wallet is not actually ready, instead of handing back a broken one.
46
+
47
+ - Phantom and Slush now tell "already unlocked" apart from "still locked", and throw when the
48
+ extension page rendered neither. Previously Phantom's `reachUnlockScreen` returned whatever it
49
+ found after six polls and its `unlock` returned early whenever no password field was visible, so a
50
+ broken wallet looked launched and failed later at the first approval.
51
+ - `buildCache` asserts that the wallet wrote state into the profile before reporting the cache, and
52
+ the MetaMask onboarding patch throws (rather than returning quietly) when the state it means to
53
+ patch is missing. Slush's import waits for the wallet home instead of falling through.
54
+ - Every poll loop shares one `waitUntil` helper, so the timeout a failure reports is the timeout it
55
+ actually waited.
56
+ - The `wallet` fixture reads from the same launch as `context` rather than a worker-level variable,
57
+ and no longer launches an extra Chromium per worker that no test drives.
58
+
59
+ - 25a0f0b: Fix the Slush cache build. Slush's own backend answers an automated browser with a Cloudflare 403
60
+ whose body is a marketing page, so its GraphQL client throws at boot and renders an error screen
61
+ instead of the wallet, which surfaced several screens later as a `Word 1` input timeout. Slush now
62
+ answers `*.slush.app` with an empty GraphQL body through `WalletDefinition.prepareContext`, a new
63
+ optional hook applied to both the cache-build and the test context before anything navigates.
64
+ Onboarding, unlock, connect, and sign need nothing from that API.
65
+ - 0341a74: Verify the pinned MetaMask download against a recorded sha256. The integrity option existed but no
66
+ caller passed it, so the pinned release archive was fetched and extracted unverified. The hash is now
67
+ required at every download site, recorded per MetaMask version in one place, and `undefined` only for
68
+ the Chrome Web Store fetches, whose endpoint always serves the current version and cannot be pinned.
69
+
70
+ ## 0.1.0
71
+
72
+ Initial release.
73
+
74
+ ### Wallets
75
+
76
+ Connect and sign are verified end to end against the real extension, headed, for every wallet below.
77
+ A wallet is only registered once it has been driven for real.
78
+
79
+ - **MetaMask** (EVM + Solana)
80
+ - **Phantom** (EVM + Solana)
81
+ - **Rabby** (EVM)
82
+ - **Solflare** (Solana)
83
+ - **Slush** (Sui)
84
+
85
+ ### API
86
+
87
+ - `buildCache(setup)` onboards a wallet from a seed phrase into a cached profile on disk, once.
88
+ - `createWalletFixtures(setup)` returns a `@playwright/test` `test` with a `wallet` fixture, so there
89
+ is no framework lock-in.
90
+ - `launchWallet(setup)` for driving a wallet outside the fixture.
91
+ - `wallet.connectToDapp()`, `confirmSignature()`, `confirmTransaction()`, `approve()`, and the
92
+ matching `reject*()` methods.
93
+ - Optional per-wallet capabilities under `wallet.settings`, `wallet.network`, and `wallet.accounts`.
94
+ A wallet declares only what has been driven against the real extension; anything else throws
95
+ `[walletwright] <wallet> does not support <action>()`.
96
+ - `wallets` and `walletKindsByEcosystem(ecosystem)` for the registry.
97
+ - `walletwright cache` CLI for building profiles ahead of a test run.
98
+
99
+ ### Subpath exports
100
+
101
+ - `@walletwright/core/chain` spins up a local anvil chain through `prool` for transaction tests.
102
+ - `@walletwright/core/mock` and `@walletwright/core/mock-standard` provide headless provider mocks
103
+ (EIP-1193 and the Solana Wallet Standard) for tests that do not need a real extension.
104
+
105
+ ### Notes
106
+
107
+ - Approval popups only open in **headed** Chromium. On CI, use a virtual display such as `xvfb-run`.
108
+ - `prool` and `viem` are optional peer dependencies. `@walletwright/core/chain` needs both;
109
+ `@walletwright/core/mock` needs `viem`. The main entry and `@walletwright/core/mock-standard` need
110
+ neither.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Pedro Filho
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,112 @@
1
+ # walletwright
2
+
3
+ Playwright wallet automation for **MetaMask (EVM + Solana)**, **Phantom (EVM + Solana)**,
4
+ **Rabby (EVM)**, **Solflare (Solana)**, and **Slush (Sui)**.
5
+ It connects and signs in the real browser extensions.
6
+
7
+ - Real extensions, no mocks: MetaMask, Phantom, Rabby, Solflare, and Slush on their current
8
+ versions.
9
+ - EVM, Solana, and Sui from one fixture: `window.ethereum`, `window.phantom.solana`, and the Sui
10
+ Wallet Standard.
11
+ - Onboard a wallet once into a cached profile, then unlock it and drive the popups in every test.
12
+ - Plain `@playwright/test` fixtures, so there is no framework lock-in.
13
+
14
+ ## Install
15
+
16
+ ```sh
17
+ pnpm add -D @walletwright/core @playwright/test
18
+ pnpm exec playwright install chromium
19
+ ```
20
+
21
+ `@playwright/test` is a peer dependency.
22
+
23
+ ## 1. Describe the wallet
24
+
25
+ ```ts
26
+ // wallet-setup.ts
27
+ import type { WalletSetup } from "@walletwright/core";
28
+
29
+ export const metamask: WalletSetup = {
30
+ wallet: "metamask",
31
+ seedPhrase: "test test test test test test test test test test test junk",
32
+ password: "Tester@1234",
33
+ };
34
+ ```
35
+
36
+ > **Phantom and Slush** reject the famous public test seed (Phantom flags it as malicious and drops
37
+ > the connection). Use a fresh, unfunded mnemonic for those two.
38
+
39
+ ## 2. Build the cache (once)
40
+
41
+ ```sh
42
+ walletwright cache --setup ./wallet-setup.ts
43
+ # or: walletwright cache --wallet metamask --seed "YOUR_SEED_HERE" --password "YOUR_PASSWORD_HERE"
44
+ ```
45
+
46
+ Or call it from code, which works well as a Playwright global setup:
47
+
48
+ ```ts
49
+ import { buildCache } from "@walletwright/core";
50
+ import { metamask } from "./wallet-setup.ts";
51
+
52
+ await buildCache(metamask);
53
+ ```
54
+
55
+ ## 3. Write a test
56
+
57
+ ```ts
58
+ import { createWalletFixtures } from "@walletwright/core";
59
+ import { metamask } from "./wallet-setup.ts";
60
+
61
+ const test = createWalletFixtures(metamask);
62
+ const { expect } = test;
63
+
64
+ test("connect and sign", async ({ page, wallet }) => {
65
+ await page.goto("/");
66
+
67
+ await page.getByRole("button", { name: "Connect" }).click();
68
+ await wallet.connectToDapp();
69
+ await expect(page.locator("#account")).toContainText("0x");
70
+
71
+ await page.getByRole("button", { name: "Sign" }).click();
72
+ await wallet.confirmSignature();
73
+ });
74
+ ```
75
+
76
+ The `wallet` fixture:
77
+
78
+ | Method | Description |
79
+ | ----------------------- | --------------------------------------------------------------------------------- |
80
+ | `connectToDapp()` | Approve a pending connection popup. Resolves quietly if the wallet auto-approved. |
81
+ | `confirmSignature()` | Approve a pending signature popup. |
82
+ | `approve({ optional })` | Approve any pending popup, whether connect, sign, or a transaction. |
83
+ | `extensionId` | The loaded extension id. |
84
+
85
+ The same two calls drive every chain. A Phantom test can connect and sign on
86
+ `window.phantom.ethereum` and then on `window.phantom.solana`; a Slush test does the same on Sui. See
87
+ `apps/demo` for a full example.
88
+
89
+ ## Without fixtures
90
+
91
+ ```ts
92
+ import { launchWallet } from "@walletwright/core";
93
+
94
+ const { context, wallet } = await launchWallet(metamask);
95
+ const page = await context.newPage();
96
+ // drive the page and the wallet here
97
+ await context.close();
98
+ ```
99
+
100
+ ## Requirements and notes
101
+
102
+ - **Headless works for Phantom and Rabby**, whose approval windows surface as pages that way.
103
+ MetaMask, Solflare and Slush need a real window, so default those suites to headed and give CI a
104
+ virtual display: `xvfb-run --auto-servernum pnpm exec playwright test`.
105
+ - MetaMask is pinned to a known-good version (override it with `WalletSetup.version`). Phantom,
106
+ Rabby, Solflare, and Slush always use the current Web Store build.
107
+ - The cache lives in `.walletwright/` (override it with `WalletSetup.cacheDir`). Add that directory to
108
+ `.gitignore`.
109
+
110
+ ## License
111
+
112
+ MIT