dappress 0.3.0 → 0.3.1
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/README.md +10 -5
- package/package.json +1 -1
- package/src/index.js +10 -2
- package/src/metamask.js +13 -5
- package/types/index.d.ts +1 -1
package/README.md
CHANGED
|
@@ -95,12 +95,14 @@ Add the command types to `tsconfig.json`:
|
|
|
95
95
|
|
|
96
96
|
JavaScript projects use the same files with a `.js` extension and `module.exports`.
|
|
97
97
|
|
|
98
|
-
Run the tests in a
|
|
98
|
+
Run the tests in a browser that supports extensions:
|
|
99
99
|
|
|
100
100
|
```bash
|
|
101
101
|
npx cypress run --browser chrome-for-testing --headed
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
+
Without `--headed`, the run is headless and works the same, except for the wallet cache, which needs a headed browser.
|
|
105
|
+
|
|
104
106
|
## Usage
|
|
105
107
|
|
|
106
108
|
```ts
|
|
@@ -157,7 +159,7 @@ Settings normally live in `cypress/wallet.setup.ts`. Secrets go in `cypress.env.
|
|
|
157
159
|
| `network` | | None. The dapp stays on the network MetaMask starts on, Ethereum mainnet. |
|
|
158
160
|
| `backupAndSync` | | `false`. Dappress turns off MetaMask's backup and sync while importing the wallet, so that an account a test adds is not restored by the next import of the same seed phrase. With `true`, MetaMask keeps saving and restoring the accounts and contacts of that phrase. |
|
|
159
161
|
| `autoSetup` | | `true`. Dappress imports or unlocks the wallet before the first test of each spec. Set to `false` to call `cy.setupMetaMask()` yourself. |
|
|
160
|
-
| `cache` | | `false`. The wallet is imported in every run, about fifteen seconds. With `true`, and a seed phrase of your own, it is imported once, in a browser Dappress opens before the run, and the resulting profile is reused by later runs, which then start by unlocking the wallet. |
|
|
162
|
+
| `cache` | | `false`. The wallet is imported in every run, about fifteen seconds. With `true`, and a seed phrase of your own, it is imported once, in a browser Dappress opens before the run, and the resulting profile is reused by later runs, which then start by unlocking the wallet. Headed runs only: a headless run imports the wallet as usual. |
|
|
161
163
|
| `timeout` | | `20000` ms. The time allowed for MetaMask to display a request before a command fails. |
|
|
162
164
|
|
|
163
165
|
### Security
|
|
@@ -171,8 +173,9 @@ With `cache: true`, the profile under `~/.cache/dappress/profiles` holds the wal
|
|
|
171
173
|
The suite runs one test per command against [MetaMask's test dapp](https://metamask.github.io/test-dapp/). Each run makes a wallet nobody has used, with Foundry's `cast`, and starts a local [Anvil](https://getfoundry.sh) node that funds it. It requires Chrome for Testing and Foundry.
|
|
172
174
|
|
|
173
175
|
```bash
|
|
174
|
-
npm run conformance
|
|
175
|
-
npm run conformance -- 13.51.0
|
|
176
|
+
npm run conformance # default MetaMask version
|
|
177
|
+
npm run conformance -- 13.51.0 # a specific release
|
|
178
|
+
DAPPRESS_HEADLESS=1 npm run conformance # without a browser window
|
|
176
179
|
```
|
|
177
180
|
|
|
178
181
|
Each run writes `reports/metamask-<version>.json`. The GitHub workflow runs the suite daily against the latest MetaMask release that has no report yet.
|
|
@@ -189,6 +192,8 @@ Cypress executes tests inside the dapp's tab and has no access to the extension.
|
|
|
189
192
|
|
|
190
193
|
MetaMask displays requests in its side panel when the panel is open, and in its popup window otherwise. Without the cache, the import of the wallet ends by opening the side panel, so requests appear there. With the cache, the wallet was imported in another browser, the panel is closed, and requests appear in the popup. Dappress handles both, and the conformance suite covers both.
|
|
191
194
|
|
|
195
|
+
Cypress leaves extensions out of a headless launch, so Dappress passes MetaMask to Chrome itself. Headless Chrome displays the side panel but does not open the popup window, which is why the cache, whose requests appear in the popup, is limited to headed runs.
|
|
196
|
+
|
|
192
197
|
With `cache: true`, Dappress imports the wallet once before the run, in a browser of its own, and keeps the profile; MetaMask's storage is copied from it into the profile Cypress is about to launch, so each run starts from a wallet that has never seen the dapp.
|
|
193
198
|
|
|
194
199
|
```
|
|
@@ -217,7 +222,7 @@ Selectors are MetaMask's `data-testid` attributes, each with the button's Englis
|
|
|
217
222
|
|
|
218
223
|
## Status
|
|
219
224
|
|
|
220
|
-
Verified with MetaMask 13.49.0 and 13.50.0, Cypress 16 and Chrome for Testing 154
|
|
225
|
+
Verified with MetaMask 13.49.0 and 13.50.0, Cypress 16 and Chrome for Testing 154: in headed mode on macOS and on GitHub's Linux runners, and in headless mode on macOS.
|
|
221
226
|
|
|
222
227
|
## License
|
|
223
228
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dappress",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "MetaMask automation for Cypress: load the real extension, import a test wallet, answer dapp requests with cy.* commands. Tracks the latest MetaMask release.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Benjamin Lassaut",
|
package/src/index.js
CHANGED
|
@@ -20,9 +20,12 @@ function configureDappress(on, config, userOptions = {}) {
|
|
|
20
20
|
console.warn('[dappress] chromeWebSecurity is off: MetaMask cannot start its snaps, so adding or importing an account will hang');
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
// A cached wallet gets its requests in MetaMask's popup window, which headless Chrome doesn't open
|
|
24
|
+
const usesCache = (browser) => options.cache && !browser.isHeadless;
|
|
25
|
+
|
|
23
26
|
// Build the wallet profile before the run, out of the time Cypress allows a browser to come up
|
|
24
27
|
on('before:run', async ({ browser }) => {
|
|
25
|
-
if (
|
|
28
|
+
if (browser && usesCache(browser)) await prepareProfile({ browserPath: browser.path, extensionDir: await prepareExtension(options), options });
|
|
26
29
|
});
|
|
27
30
|
|
|
28
31
|
on('before:browser:launch', async (browser, launchOptions) => {
|
|
@@ -31,7 +34,12 @@ function configureDappress(on, config, userOptions = {}) {
|
|
|
31
34
|
}
|
|
32
35
|
const extensionDir = await prepareExtension(options);
|
|
33
36
|
launchOptions.extensions.push(extensionDir);
|
|
34
|
-
if (
|
|
37
|
+
if (browser.isHeadless) {
|
|
38
|
+
// Cypress leaves extensions out of a headless launch, so ask Chrome directly
|
|
39
|
+
launchOptions.args.push(`--load-extension=${extensionDir}`);
|
|
40
|
+
if (options.cache) console.warn('[dappress] The wallet cache needs a headed browser: importing the wallet in this run instead');
|
|
41
|
+
}
|
|
42
|
+
if (usesCache(browser)) {
|
|
35
43
|
const profileDir = await prepareProfile({ browserPath: browser.path, extensionDir, options });
|
|
36
44
|
await installProfile(profileDir, browser, config.isTextTerminal);
|
|
37
45
|
}
|
package/src/metamask.js
CHANGED
|
@@ -259,15 +259,23 @@ async function switchAccount(page, name) {
|
|
|
259
259
|
await selectAccount(page, name);
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
-
// Picking an account closes the list and shows it in the home header
|
|
262
|
+
// Picking an account closes the list and shows it in the home header. As with
|
|
263
|
+
// adding one, a lost click leaves the list open, so the account is pressed again.
|
|
263
264
|
async function selectAccount(page, name) {
|
|
264
|
-
|
|
265
|
-
|
|
265
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
266
|
+
await click(page, selectors.accounts.cell(name));
|
|
267
|
+
if (await isSelected(page, name, 5000)) return;
|
|
268
|
+
}
|
|
269
|
+
throw await failure(page, `MetaMask did not select "${name}"`);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
async function isSelected(page, name, timeout) {
|
|
273
|
+
const deadline = Date.now() + timeout;
|
|
266
274
|
while (Date.now() < deadline) {
|
|
267
|
-
if ((await selectedAccount(page)) === name) return;
|
|
275
|
+
if ((await selectedAccount(page)) === name) return true;
|
|
268
276
|
await sleep(250);
|
|
269
277
|
}
|
|
270
|
-
|
|
278
|
+
return false;
|
|
271
279
|
}
|
|
272
280
|
|
|
273
281
|
async function selectedAccount(page) {
|
package/types/index.d.ts
CHANGED
|
@@ -33,7 +33,7 @@ export interface DappressOptions extends WalletSetup {
|
|
|
33
33
|
backupAndSync?: boolean;
|
|
34
34
|
/** Run cy.setupMetaMask() before the first test of each spec. Default: true. */
|
|
35
35
|
autoSetup?: boolean;
|
|
36
|
-
/** Import the wallet once and reuse the profile across runs. Keeps the vault under cacheDir. Default: false. */
|
|
36
|
+
/** Import the wallet once and reuse the profile across runs. Keeps the vault under cacheDir. Headed runs only. Default: false. */
|
|
37
37
|
cache?: boolean;
|
|
38
38
|
/** Time allowed for MetaMask to display a request, in ms. Default: 20000. */
|
|
39
39
|
timeout?: number;
|