@moveindustries/movewright
v1.0.1
Published
End-to-End (E2E) testing for dApps using Playwright + Move Wallets
Readme
movewright
E2E testing for dApps using Playwright + Move Wallets on Movement Network
Installation
npm install @moveindustries/movewright
yarn add @moveindustries/movewrightUsage
Quick setup
Declare the wallet on each Playwright project, then use the fixture the package ships. One spec then runs against every wallet listed.
// playwright.config.ts
import { defineConfig } from '@playwright/test';
import { NightlyWallet } from '@moveindustries/movewright';
export default defineConfig({
use: { headless: false },
projects: [
{
name: 'Nightly',
metadata: {
wallet: 'nightly',
version: NightlyWallet.recommendedVersion,
seed: 'pioneer casual canoe gorilla embrace width fiction bounce spy exhibit another dog',
password: 'password1234!@#$',
},
},
],
});// wallet.spec.ts
import { expect } from '@playwright/test';
import { testWithMovewright } from '@moveindustries/movewright/fixtures';
const test = testWithMovewright();
test('should be able to connect', async ({ wallet, page }) => {
// https, not http: wallets restrict their injected provider to secure
// origins, so a dApp served over http is invisible to them.
await page.goto('https://localhost:8080');
await page.click('.connect-button');
await wallet.approve();
await page.waitForSelector('#connected');
expect(await wallet.getAccountAddress()).toMatch(/^0x[0-9a-f]+$/i);
});An extension needs a persistent browser context, which Playwright's own
context fixture cannot create, so the fixture makes one at worker scope and
hands it back. page and context work as you would expect, with one caveat:
because the context is created by the package rather than by Playwright's own
factory, the config options that factory applies — trace, video,
screenshot, viewport, baseURL — do not reach it. Pass an argument to
testWithMovewright({ ... }) to override the project metadata for one spec.
The fixture is a separate entry point because it imports @playwright/test.
Importing the package itself never pulls the test runner in, so a consumer using
only bootstrap does not need it installed.
If you would rather wire it yourself, bootstrap is still exported and returns
[wallet, page, context].
API Reference
Network Management
The wallet provides full network management capabilities:
switchNetwork(network: string)- Switch between available networks (e.g., "Movement", "Bardock Testnet")addNetwork(options: AddNetwork)- Point the current chain at a custom RPC endpointupdateNetworkRpc(options: UpdateNetworkRpc)- Update the RPC URL for an existing networkhasNetwork(name: string)- Check if a network existsconfirmNetworkSwitch()- Confirm network switch requests from dApps
Motion compiles its two networks in and ships no custom-network UI, so
addNetwork and updateNetworkRpc throw there rather than silently doing
nothing.
Accounts
getAccountAddress()- The active account's address, in fullrenameAccount(name: string)- Rename the active accountswitchAccount(name: string)- Switch to another accountcountAccounts()- How many accounts the wallet holdscreateAccount(name?: string)- Add a new account, optionally naming itimportPK(privateKey: string, name: string)- Import an account from a private key
Neither wallet shows the full address in its header, so getAccountAddress
reads it off the surface that does: Motion's receive card, and for Nightly the
clipboard write its header fires.
Nightly names accounts itself and offers no naming step while creating one, so
createAccount(name) creates and then renames.
Both wallets discard a name past their own limit without reporting anything —
15 characters for Nightly, 32 for Motion, readable as
NightlyWallet.walletNameMaxLength and MotionWallet.walletNameMaxLength — so
renameAccount, createAccount and importPK all refuse a longer name with a
RangeError rather than leaving you with a name you cannot switch back to.
Renaming to the name an account already has succeeds on both; Motion
short-circuits, since it keeps its Save control disabled until the field
changes.
Motion derives accounts inside its service worker and has no add-account
control, so createAccount throws there whatever it is passed.
Navigation
openSettings()- Open the wallet's settingsgoBackToHomePage()- Return to the wallet's home viewlock()/unlock(password?)- Lock and unlock the wallet
Example: Update Network RPC
// Point the current chain at a different RPC endpoint
await wallet.updateNetworkRpc({
rpc: 'https://new-rpc-endpoint.example.com',
});Special Thanks
This project is a fork of the Chainsafe and TenKeylabs version of dAppeteer and Metamask/Coinbase wallets.
