chainwright 0.8.11 → 0.8.12

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.
Files changed (2) hide show
  1. package/README.md +183 -52
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -16,7 +16,7 @@ Test, automate, and verify every wallet interaction, with the precision your use
16
16
 
17
17
 
18
18
 
19
- Chainwright is an end-to-end testing toolkit for Web3 dapps built on top of Playwright. It helps you prebuild browser extension wallet state, then reuse it in your end-to-end tests through ready-made fixtures.
19
+ Chainwright is an end-to-end testing toolkit for Web3 dapps built on Playwright. It helps you build and cache browser wallet extension state, then reuse it in your end-to-end tests through ready-made fixtures.
20
20
 
21
21
  ## Features
22
22
 
@@ -24,45 +24,52 @@ Chainwright is an end-to-end testing toolkit for Web3 dapps built on top of Play
24
24
  - Playwright fixtures for wallet + Dapp testing
25
25
  - Support for multiple wallet profiles per wallet
26
26
  - Wallet action APIs for onboarding, account switching, transaction confirmation, and more
27
- - Multiple wallet profile caching
28
27
 
29
28
  ## Supported Wallets
30
29
 
30
+ - Keplr
31
31
  - MetaMask
32
- - Solflare
32
+ - Meteor
33
33
  - Petra
34
34
  - Phantom
35
- - Meteor
36
- - Keplr
35
+ - Solflare
37
36
 
38
37
  ## Requirements
39
38
 
40
39
  - Node.js `>=22`
41
40
  - `@playwright/test@1.60.0` (peer dependency)
42
41
 
42
+ ## Operating Systems
43
+ Supports the following operating systems:
44
+ - MacOS
45
+ - Linux
46
+ - Windows
47
+
43
48
  ## Installation
44
49
 
50
+ Before installing Chainwright, ensure to install Playwright's browser using the command below.
51
+
45
52
  ```bash
46
- pnpm add -D chainwright @playwright/test
53
+ npx playwright install chromium
47
54
  ```
55
+
48
56
  ```bash
49
- bun add -D chainwright @playwright/test
57
+ bunx playwright install chromium
50
58
  ```
59
+
60
+ After Installing Playwright's browser, install `Chainwright` and `@playwright/test`
61
+
51
62
  ```bash
52
- npm install --save-dev chainwright @playwright/test
63
+ pnpm add -D chainwright @playwright/test
53
64
  ```
54
65
  ```bash
55
- yarn add -D chainwright @playwright/test
66
+ bun add -D chainwright @playwright/test
56
67
  ```
57
-
58
- After installation, make sure Playwright browsers are installed in your machine.
59
-
60
68
  ```bash
61
- npx playwright install --chromium #Optional
69
+ npm install --save-dev chainwright @playwright/test
62
70
  ```
63
-
64
71
  ```bash
65
- bunx playwright install --chromium #Optional
72
+ yarn add -D chainwright @playwright/test
66
73
  ```
67
74
 
68
75
  ## Quick Start
@@ -71,7 +78,8 @@ bunx playwright install --chromium #Optional
71
78
 
72
79
  Create a setup directory (default: `tests/wallet-setup`) and add `*.setup.ts` files with a wallet name in the filename, for example:
73
80
 
74
- - `metamask.setup.ts`
81
+ - `base.setup.ts`
82
+ - `base-two.setup.ts`
75
83
  - `petra.setup.ts`
76
84
  - `phantom-team-a.setup.ts`
77
85
 
@@ -135,14 +143,49 @@ export default defineWalletSetup(
135
143
  );
136
144
  ```
137
145
 
146
+ To support multiple profiles in a single wallet (for example, MetaMask), only setup files from the second profile onward need an explicit, distinct profile name.
147
+
148
+ `main.setup.ts` can use the default profile, while `main-two.setup.ts` (and any additional setup files) should declare a unique profile name. Then, in any fixture that should use that profile, pass the exact same profileName value.
149
+
150
+ Example:
151
+ - `main.setup.ts`: uses the default profile
152
+ - `main-two.setup.ts`: defines `profileName: "profile two"`
153
+ - Fixture usage: `metamaskFixture({ profileName: "profile two" })`
154
+
155
+ ```ts
156
+ // tests/wallet-setup/main-two.setup.ts
157
+ import { defineWalletSetup } from "chainwright/core";
158
+ import { Metamask } from "chainwright/metamask";
159
+
160
+ const PASSWORD = "test1234"; // For Petra wallet, you have to use a strong password. e.g. PlayerPetra45!!
161
+ const SEED_PHRASE = "test test test test test test test test test test test test test";
162
+
163
+ export default defineWalletSetup(
164
+ PASSWORD,
165
+ async ({ walletPage }) => {
166
+ const metamask = new Metamask(walletPage);
167
+
168
+ await metamask.onboard({
169
+ mode: "import",
170
+ secretRecoveryPhrase: SEED_PHRASE,
171
+ mainAccountName: "Main",
172
+ });
173
+ },
174
+ {
175
+ profileName: "profile two"
176
+ },
177
+ );
178
+ ```
179
+
138
180
  ### 2. Build wallet cache
139
181
 
140
- Run setup with the CLI (Supports npx, bun, pnpm, and yarn):
182
+ Run setup with the CLI (Supports **npx**, **bun**, **pnpm**, and **yarn**):
141
183
 
142
- > NB: By default, Chainwright looks for `tests/wallet-setup` in your base directory. However, you can specify the directory you want Chainwright to get your setup files from.
184
+ >[!NOTE]
185
+ > By default, Chainwright looks for `tests/wallet-setup` in your base directory. However, you can specify the directory you want Chainwright to get your setup files from.
143
186
 
144
187
  ```bash
145
- bun chainwright --wallets metamask
188
+ bun chainwright --wallets <Wallets you want to support>
146
189
  ```
147
190
 
148
191
  To specify a directory:
@@ -153,6 +196,7 @@ bun chainwright <directory path> <wallet> -f #Optional flag
153
196
 
154
197
  Useful flags:
155
198
 
199
+ - `-h, --help` shows you all the commands
156
200
  - `-f, --force` overwrite existing cache
157
201
  - `--wallets <wallets...>` select wallets (`metamask`, `solflare`, `petra`, `phantom`, `meteor`, `keplr`). Setup multiple wallets at the same time.
158
202
  - `-a, --all` setup all wallets
@@ -163,7 +207,7 @@ Useful flags:
163
207
  - `--ph, --phantom` setup phantom wallet
164
208
  - `-s, --solflare` setup solflare wallet
165
209
 
166
- Cache is stored under:
210
+ Wallet profile cache is stored under:
167
211
 
168
212
  - `.wallet-cache/<wallet>/wallet-data` (default profile)
169
213
  - `.wallet-cache/<wallet>/<profileName>` (custom profile)
@@ -171,33 +215,34 @@ Cache is stored under:
171
215
  ### 3. Use wallet fixtures in Playwright tests
172
216
 
173
217
  ```ts
174
- import { expect } from "@playwright/test";
218
+ import { expect, type Page } from "@playwright/test";
175
219
  import { testWithChainwright } from "chainwright/core";
176
220
  import { metamaskFixture } from "chainwright/metamask";
177
221
 
178
- // Fixture
222
+ // Chainwright's Fixture
179
223
  export const testWithMetamask = testWithChainwright(metamaskFixture());
180
224
 
181
225
  // Extend Chainwright's metamaskFixture to suit your need
182
- export const testDappFixture = testWithMetamask.extend<TestDappFixture>({
183
- context: async({ context: _ }, use) => {
184
- //...Context content here
185
- },
226
+ export const testDappFixture = testWithMetamask.extend<{dAppPage: Page}>({
186
227
  dappPage: async ({ page, baseURL }, use) => {
187
- await page.goto(`dApp's url`);
228
+ await page.goto(`https://your-dapp.example`);
188
229
  await use(page);
189
230
  },
190
231
  });
191
232
 
192
- test("connect wallet to dapp", async ({ page, metamask }) => {
193
- await page.goto("https://your-dapp.example");
194
- const connectButton = page.getByRole("button", { name: /Connect/i})
195
- await connectButton.click();
196
- await metamask.connectToApp("Account 1");
197
- await expect(page.getByText("Connected")).toBeVisible();
198
- });
233
+ // Then in your tests do:
234
+ const test = testDappFixture;
235
+ test.describe("Example tests", () => {
236
+ test("connect wallet to dapp", async ({ dappPage, metamask }) => {
237
+ const connectButton = dappPage.getByRole("button", { name: /Connect/i})
238
+ await connectButton.click();
239
+ await metamask.connectToApp("Account 1");
240
+ await expect(dappPage.getByText("Connected")).toBeVisible();
241
+ });
242
+ })
199
243
  ```
200
- > N.B: The wallet fixture will make use of the `default` wallet profile. If you specified a `profile-name` at the point of setting up, make sure to include it in the fixture.
244
+ > [!NOTE]
245
+ > The wallet fixture will make use of the `default` wallet profile. If you specified a `profile-name` at the point of setting up, make sure to include it in the fixture.
201
246
 
202
247
  ```ts
203
248
  // No profile name is specified at setup time
@@ -207,33 +252,119 @@ const testWithFixture = testWithChainwright(fixture())
207
252
  const testWithFixture = testWithChainwright(fixture({ profileName: "profile name" }))
208
253
  ```
209
254
 
210
- `Wallet fixture parameters` (Optinoal):
211
- - `profileName`: string,
212
- - `slowMo`: number
255
+ `Wallet fixture parameters`:
256
+ - `profileName`?: string,
257
+ - `slowMo`?: number
213
258
 
214
259
  ## Worker-Scoped Fixture
215
260
 
216
- Use worker-scoped fixtures when you want one wallet context for the duration of a test suite. This is important for saving time on the setup and teardown cost when running tests in CI
261
+ Use worker-scoped fixtures when tests in a `test.describe()` block can safely share a wallet context. Setup and teardown run once per worker instead of per test, which speeds up CI runs and reduces flakiness caused by repeated wallet initialization.
217
262
 
218
263
  ```ts
264
+ import { type Page } from "@playwright/test";
265
+ import { testWithChainwright } from "chainwright/core";
219
266
  import { metamaskWorkerScopeFixture } from "chainwright/metamask";
220
267
 
221
- export const test = metamaskWorkerScopeFixture({
222
- profileName: "default",
223
- dappUrl: "https://your-dapp.example",
224
- });
268
+ // Chainwright's worker scoped fixture
269
+ export const testWithFixture = testWithChainwright(metamaskWorkerScopeFixture());
270
+
271
+ // Your worker scoped fixture that extends Chainwright's worker scoped fixture
272
+ export const workerScopedFixture = testWithFixture.extend<{dAppPage: Page}>({
273
+ dappPage: [
274
+ async ({ workerScopeContents }, use) => {
275
+ const { context, wallet, walletPage } = workerScopeContents;
276
+ /** N.B:
277
+ * wallet represents -> metamask, phantom, keplr, etc...
278
+ * walletPage represents -> metamask wallet page, phantom wallet page, keplr wallet page, etc...
279
+ */
280
+ const _dappPage = await context.newPage();
281
+ await _dappPage.goto(`http://example-site.com`);
282
+ await use(_dappPage);
283
+ },
284
+ { scope: "worker" },
285
+ ],
286
+ })
287
+
288
+ // Then in your tests do:
289
+ const test = workerScopedFixture;
290
+
291
+ test.describe("Example test", () => {
292
+ test("Should confirm transaction", ({ dappPage, workerScopeContents}) => {
293
+ const { wallet: metamask } = workerScopeContents
294
+ await dappPage.getByRole("button", { name: "Send Tx" }).click();
295
+ await metamask.confirmTransaction();
296
+ });
297
+
298
+ test("Should reject transaction", async ({ dappPage, workerScopeContents })=> {
299
+ const { wallet: metamask } = workerScopeContents
300
+ await dappPage.getByRole("button", { name: "Send Tx" }).click();
301
+ await metamask.rejectTransaction();
302
+ });
303
+ })
225
304
 
226
- test("confirm transaction", async ({ dappPage, metamask }) => {
227
- await dappPage.getByRole("button", { name: "Send Tx" }).click();
228
- await metamask.confirmTransaction();
229
- });
230
305
  ```
231
306
 
232
- `Worker scoped fixture parameters` (Optional):
307
+ `Worker scoped fixture parameters`:
233
308
 
234
309
  - `profileName?: string`
235
310
  - `slowMo?: number`
236
- - `dappUrl?: string`
311
+
312
+ ### 4. Using in CI (GitHub Actions)
313
+ Running Chainwright in CI is very similar to running Playwright in CI. The only additional requirement is a cache-build step before executing tests, as shown below:
314
+
315
+ Why we make use of **xvfb**:
316
+ > [!IMPORTANT]
317
+ > Browser extensions don't load in headless Chromium, so the tests have to run in headed mode. CI machines have no display, so launching a headed browser fails. xvfb provides a fake virtual display, letting Chromium run headed in CI as if a screen were attached.
318
+
319
+ ```yml
320
+ name: CI
321
+
322
+ on:
323
+ workflow_dispatch:
324
+ pull_request:
325
+ branches: ["main"]
326
+
327
+ jobs:
328
+ test:
329
+ runs-on: ubuntu-22.04
330
+ timeout-minutes: 60
331
+
332
+ steps:
333
+ - name: Checkout code
334
+ uses: actions/checkout@v5
335
+ with:
336
+ submodules: "recursive"
337
+ fetch-depth: 0
338
+
339
+ - name: Install pnpm
340
+ uses: pnpm/action-setup@v5
341
+ with:
342
+ version: 10
343
+
344
+ - name: Use Node LTS
345
+ uses: actions/setup-node@v6
346
+ with:
347
+ node-version: 24.x
348
+ cache: "pnpm"
349
+
350
+ - name: Install dependencies
351
+ run: pnpm install
352
+
353
+ - name: Install XVFB
354
+ run: sudo apt-get install -y xvfb
355
+
356
+ - name: Install Playwright browsers
357
+ run: pnpx playwright install chromium
358
+
359
+ - name: Install Foundry
360
+ uses: foundry-rs/foundry-toolchain@v1
361
+
362
+ - name: Build cache
363
+ run: xvfb-run pnpm run setup-wallets
364
+
365
+ - name: Run end-to-end tests (Headful)
366
+ run: xvfb-run pnpm playwright test --config=tests/playwright.config.ts
367
+ ```
237
368
 
238
369
  ## Wallets By Module
239
370
 
@@ -269,9 +400,9 @@ Extra Phantom/Solflare fixtures:
269
400
  defineWalletSetup(password, setupFn, config?)
270
401
  ```
271
402
 
272
- - `password: string` wallet unlock password saved in cache metadata
273
- - `setupFn: ({ context, walletPage }) => Promise<void>` runs onboarding/import flow
274
- - `config?: { profileName?: string; slowMo?: number }`
403
+ - `password: string` - wallet unlock password saved in cache metadata
404
+ - `setupFn: ({ context, walletPage }) => Promise<void>` - runs onboarding/import flow
405
+ - `config?: { profileName?: string; slowMo?: number }` - useful for setting up multiple wallet profiles and running the setup in slow motion `slowMo`.
275
406
 
276
407
  ### `testWithChainwright`
277
408
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chainwright",
3
- "version": "0.8.11",
3
+ "version": "0.8.12",
4
4
  "description": "Playwright Web3 wallet testing framework for end-to-end dApp automation with MetaMask, Phantom, Solflare, Petra, Meteor, and Keplr",
5
5
  "type": "module",
6
6
  "license": "MIT",