Open-source project
MetaMask/test-dapp avatar
MetaMask/test-dapp

MetaMask's test-dapp is a harness, not an application

The sample dapp used for e2e testing and metamask-extension QA

643 stars371 forksJavaScriptMIT

At a glance

What is it?
MetaMask/test-dapp is a deliberately simple web application used as the fixture for MetaMask end to end tests and manual QA, with a main page of common wallet buttons and a request.html page that calls any RPC method from the URL. It ships only a built dist directory, has no test suite of its own, and its XPath friendly markup is a documented requirement.
Who is it for?
Adopt MetaMask/test-dapp when you are writing end to end tests against a wallet extension and you want a predictable fixture with stable, XPath selectable elements instead of mocking the provider. Skip it if you need a realistic application to test user journeys against, since this page is deliberately bare, or if your CI already drives a different fixture.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A fixture for driving a wallet extension

The purpose of this repository is stated in one line: it is a simple test dapp for use in MetaMask end to end tests and manual QA. It is hosted at metamask.github.io/test-dapp, so there is a live instance to point a browser at.

The distinction that matters is that this is not an example of how to build a dapp. It is a fixture, something to point a test runner at. The main page is described as a simple UI with buttons for common dapp interactions, which is exactly what an automated test needs and exactly what a product team does not need.

Two audiences share it. The end to end suite drives it programmatically, and a human uses it for manual QA when reproducing a bug or checking a flow by hand. The consequences of that shared purpose show up throughout the repository, from the strict rule on how elements must be written to the fact that the package itself ships no tests.

The package is published to npm as @metamask/test-dapp, with the files field listing only the dist directory, so a consumer installs the built output rather than the source.

request.html calls any RPC method from the URL

The second page is the interesting part of the design. request.html allows making requests directly to the provider using query parameters, and the readme describes it as a simple way of testing RPC methods using an in-page provider.

The URL carries both the method and the parameters, for example /request.html?method=eth_getLogs&params=[{ "address": "0x0000000000000000000000000000000000000000" }]. The page then makes the request with the given RPC method and parameters using ethereum.request, and reports the result as plain text.

That design turns RPC testing into a navigation rather than a script. A test can assert on a plain text body instead of parsing a UI, and a human can reproduce a failing call by pasting a URL. The trade-off is that the parameters are carried in the query string, so a request with a large or sensitive parameter set makes for an unwieldy URL, and the output is unformatted plain text rather than a structured response a test could parse field by field.

Serving the dapp from your own test run

The readme gives the integration recipe directly. If you want to use the dapp in your own end to end tests, you install the package and serve its dist directory with a static server on a fixed port:

shell
static-server node_modules/@metamask/test-dapp/dist --port 9011

A fixed port matters here. The extension under test has to be pointed at a known origin, and the port number is part of that configuration, so 9011 is a value to keep rather than an example to change casually.

The served directory is the published artifact rather than the source tree, which keeps the test run independent of the local build state. If you are working on the dapp itself, the development path is the webpack dev server, and the production build is webpack in production mode, both wired through the scripts in package.json.

yarn setup exists because yarn install breaks the environment

The contributing instructions carry the most emphatic warning in the readme. The setup step is a Yarn v1 install of dependencies plus the required post-install scripts, and the readme tells contributors not to use the yarn or yarn install command directly, because the normal install command skips required post-install scripts and leaves the development environment in an invalid state.

The mechanism behind that warning is visible in the dependencies. The devDependency list includes @lavamoat/allow-scripts and @lavamoat/preinstall-always-fail, which is a package manager hardening setup: scripts from dependencies are not run silently, they have to be allowed explicitly. The setup script exists to run the install and then the allow-scripts step, so the approved post-install scripts actually execute.

The rest of the contributor setup is short. Node.js 20.19.0 or later is required, the repository carries an .nvmrc, and the readme notes that nvm users get the right version automatically with nvm use. Yarn v1 is the package manager, and the repository has both .yarnrc and .yarnrc.yml.

XPath selectability is a hard requirement, whitespace included

There is a section in the contributing guide titled elements must be selectable by XPath, and it comes with a concrete bug report from the project's own history.

The rule is that all HTML elements should be easily selectable by XPath, and the readme says plainly that appearances can be misleading. The example is a button whose visible text is Approve Tokens Without Gas:

html
<button
  class="btn btn-primary btn-lg btn-block mb-3"
  id="approveTokensWithoutGas"
  disabled
>
  Approve Tokens Without Gas
</button>

The readme explains that the value included the whitespace on the second line, and that this caused XPath queries for the intended value to fail. The button looked correct on the page and was broken for the test suite.

That is a useful thing to know before you modify this repository, and it is a symptom of a broader point. Once a test suite depends on the exact text content of an element, every refactor of the markup becomes a potential test failure, so the whitespace rule is really a warning that this fixture is load bearing for a test suite you cannot see.

The dependency list shows what the fixture exercises

The package publishes with no runtime dependencies at all, the dependencies object in package.json is empty, and only the built dist directory is included in the tarball. Everything the dapp needs is a devDependency, because the published artifact is static files.

The devDependencies describe the surface the fixture covers. @metamask/sdk at version 0.34.0 and @metamask/connect-evm cover the connection flow, @metamask/onboarding covers the onboarding path, and @metamask/eth-sig-util covers message signing. Two wallet connection libraries are present, @walletconnect/modal and @web3modal/ethers5, so the page exercises more than one connection method.

There is a contracts/ directory and @openzeppelin/contracts pinned at 4.9.6, which is how the fixture gets tokens and contracts to interact with. The build tooling is webpack with clean-webpack-plugin and copy-webpack-plugin, and the linting is eslint with the MetaMask shared configs plus prettier for JSON, Markdown and YAML files.

One more detail is easy to miss. The resolutions field pins elliptic to ^6.6.1, and the changelog is generated by auto-changelog with an update-changelog script, which means the release notes are machine produced from commit history.

No test suite of its own, and a manual deploy step

The readme states it without hedging: this package has no tests. The test script in package.json runs the linter rather than any test runner, so yarn test is a lint pass.

That is a coherent choice rather than an oversight. The repository is a fixture for somebody else's test suite, and testing a fixture that exists to be clicked would add maintenance without adding assurance. It does mean the contract is informal. Nothing verifies that the buttons still trigger the expected provider calls, and nothing checks that request.html still returns plain text, so a change here surfaces as a failure in the MetaMask end to end suite rather than in this repository.

Deployment is also manual. After merging or pushing to main, contributors are asked to run yarn deploy in the package root if the contents of the dist directory have changed, and the deploy script is a shell file at the top level of the repository. The hosted site at metamask.github.io/test-dapp is therefore updated by a deliberate step, which means a merge can leave the hosted copy behind the source until someone runs it.

The licence is MIT, with the author recorded as MetaMask, and the release history shows regular versions, including 9.9.0 in March 2026 and 9.8.0 in February 2026, with the last push on 2026-10-15.

Editorial conclusion

Adopt MetaMask/test-dapp when you are writing end to end tests against a wallet extension and you want a predictable fixture with stable, XPath selectable elements instead of mocking the provider. Skip it if you need a realistic application to test user journeys against, since this page is deliberately bare, or if your CI already drives a different fixture. Before using it, serve the published package on a fixed port with static-server, confirm your runner can find elements by XPath rather than by class, and expect to run yarn setup rather than yarn install, because the normal install path skips post-install scripts and leaves the environment invalid.

Frequently asked questions

What is the MetaMask test-dapp for?

It is a simple test dapp used in MetaMask end to end tests and for manual QA. The main page has buttons for common dapp interactions, and it is hosted at metamask.github.io/test-dapp.

How do I test an RPC method with the MetaMask test-dapp?

Open request.html with a method and params query string, for example /request.html?method=eth_getLogs&params=[...]. The page makes the request using ethereum.request and reports the result as plain text.

How do I run the MetaMask test-dapp locally for a test suite?

Install the @metamask/test-dapp package and serve its dist directory, for example with static-server node_modules/@metamask/test-dapp/dist --port 9011, then point the extension under test at that origin.

Why does the contributing guide say not to run yarn install?

Because the normal install skips required post-install scripts and leaves the development environment invalid. Run yarn setup instead, which performs the install and then the allow-scripts step used by the LavaMoat tooling in the devDependencies.

Does the MetaMask test-dapp have its own test suite?

No, the readme states that the package has no tests. The test script in package.json runs the linter, and the package publishes only the dist directory with no runtime dependencies.

Why must HTML elements be selectable by XPath?

Because end to end tests query the page by XPath, and the readme warns that appearances can be misleading. A past bug had a button whose visible text included stray whitespace, which made XPath queries for the intended value fail.

Official sources

  1. License: MIT
  2. MetaMask/test-dapp on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/metamask-test-dapp.svg)](https://hysenlabs.com/projects/metamask-test-dapp)

Was this useful?