Skip to content

Testing ​

This page covers two different kinds of end-to-end testing on Agoric: browser-driven DApp testing with Keplr, and on-chain testing of the chain software itself (upgrades and core-eval proposals). If you're testing a frontend that talks to a wallet, start with Testing DApps with @agoric/synpress below. If you're testing chain software, a governance proposal, or a contract's on-chain behavior across a chain upgrade, see Testing chain software with @agoric/synthetic-chain.

Testing DApps with @agoric/synpress ​

Developing Decentralized Applications (DApps) on the Cosmos network often involves integrating with the Keplr wallet. Testing is key for ensuring users can flawlessly interact with your DApp through the Keplr wallet.

@agoric/synpress is an end-to-end (e2e) testing framework that simplifies the testing process for Keplr-based DApps. This framework automates testing how your DApp interacts with the Keplr wallet, simulating real user experiences. @agoric/synpress is a long-lived fork of synthetixio/synpress predating that project's move to a Playwright-only architecture; @agoric/synpress still uses the original Cypress-based API described below.

Since @agoric/synpress is based on Cypress, the official Cypress documentation has a lot of information that you can use with @agoric/synpress.

Installation ​

Before you start testing your DApp with Keplr, you'll need to install the @agoric/synpress in your project using the following command:

bash
yarn add -D @agoric/synpress

Project structure ​

We recommend the following project structure for keeping your e2e tests clean and manageable:

text
project_dir
└── src
└── tests
    └── e2e
        └── synpress.config.js
        └── support.js
        └── specs
            └── test.spec.js

Configure synpress.config.js ​

Before you start writing your E2E tests, you'll need to create a configuration file named synpress.config.js in the tests/e2e directory of your project.

Inside synpress.config.js, you'll set the baseUrl property within the e2e configuration. This tells Cypress where to find your DApp during testing. Here's an example configuration:

js
const baseConfig = require('@agoric/synpress/synpress.config');
const { defineConfig } = require('cypress');

module.exports = defineConfig({
  ...baseConfig,
  e2e: {
    ...baseConfig.e2e,
    baseUrl: 'http://localhost:5173',
  },
});

In this example, baseUrl is set to http://localhost:5173. Make sure to replace this with the actual URL where your DApp is running.

By default, if you don't create a synpress.config.js file, @agoric/synpress assumes your DApp runs on port 3000 of your local machine (http://localhost:3000). Specifying the correct baseUrl ensures your tests interact with the right instance of your DApp.

Since you have a separate synpress.config.js in the tests/e2e folder, you need to specify its location when running your tests. Use the --configFile flag with the synpress run command:

bash
EXTENSION=keplr synpress run --configFile=tests/e2e/synpress.config.js

Creating a Support File ​

Navigate to your project's tests/e2e directory and create a new file named support.js. This file can be used to create reusable commands that encapsulate common testing actions. For example, you can create a custom command to navigate to a specific page within your application. You can read more about it over here.

After creating your support.js file, make sure to include the following import statement:

js
import '@agoric/synpress/support/index';

This import is essential because it brings in the necessary functionalities from @agoric/synpress to interact with the Keplr wallet within your e2e tests. Without it, your tests won't be able to leverage the features provided by @agoric/synpress for Keplr integration.

Example Tests ​

With the environment set up, let's write end-to-end (e2e) tests to test your DApp's functionality. In the tests/e2e/specs folder, create a new file with a descriptive name that reflects what it tests (e.g., user_login.spec.js or token_transfer.spec.js).

Test Structure ​

You use describe blocks to group related tests together, and it blocks to define individual test cases within those groups.

js
describe('User Login', () => {
  it('should login with valid credentials', () => {
    // Test steps for login functionality
  });
});

Test 1: Setting Up Keplr Wallet ​

js
it('should setup a Keplr wallet', () => {
  cy.setupWallet({
    secretWords: 'KEPLR_MNEMONIC',
  });
  cy.visit('/');
});

This test case simulates setting up a Keplr wallet for your tests, using the cy.setupWallet method. Make sure to replace KEPLR_MNEMONIC with a 24-word mnemonic phrase. The setupWallet method creates a wallet based on the provided mnemonic phrase, which can then be used throughout your test suite.

After setting up the wallet, we visit the root path (/) of the DApp using cy.visit('/').

Test 2: Connecting Keplr Wallet ​

js
it('should accept connection with wallet', () => {
  cy.contains('Connect Wallet').click();
  cy.acceptAccess();
});

This test simulates a user connecting their Keplr wallet to your DApp. cy.contains('Connect Wallet') searches for an element containing the text Connect Wallet on the webpage and triggers a click event. cy.acceptAccess simulates accepting Keplr wallet access for your DApp.

Test 3: Signing a Transaction ​

js
it('should confirm make an offer transaction', () => {
  cy.contains('Make an Offer').click();
  cy.confirmTransaction();
});

This test simulates transaction Signing on your DApp. cy.contains('Make an Offer') searches for an element containing the text Make an Offer and triggers a click event. cy.confirmTransaction simulates confirming a transaction.

Running the Tests ​

You can now trigger the tests by running this command:

bash
EXTENSION=keplr synpress run --configFile=tests/e2e/synpress.config.js

Projects Using @agoric/synpress ​

Some examples projects utilizing @agoric/synpress for e2e tests:

@agoric/synpress Commands ​

The @agoric/synpress commands are custom Cypress commands designed for use with Keplr. They provide ready-made functions to interact with Keplr-specific elements and workflows.

setupWallet ​

Initializes a Keplr wallet for testing. You can either create a new one or import an existing one using the provided options.

Arguments:

(All arguments are optional)

The command takes a single object as an argument with the following keys:

  • secretWords (string): The secret words for the wallet. (default is a predefined mnemonic phrase that represents a wallet address on the Agoric chain)
  • privateKey (string): The private key for the wallet.
  • password (string): The password for the wallet. (default is Test1234).
  • walletName (string): The name of the wallet. (default is My Wallet).
  • selectedChains (array): The chains to select. (default is an empty array, []).
  • createNewWallet (boolean): Whether to create a new wallet (default is false).

Returns:

  • (boolean): true if the wallet was set up successfully, false otherwise.

acceptAccess ​

Handles the authorization process for connecting the Keplr wallet to a DApp. DApps provide a Connect Wallet option to initiate this process.

Returns:

  • (boolean): true if access was accepted successfully, false otherwise.

confirmTransaction ​

Handles signing transactions within a DApp using the Keplr wallet. This occurs when a user initiates a transaction, such as sending tokens or interacting with a smart contract.

Returns:

  • (boolean): true if transaction was approved successfully, false otherwise.

disconnectWalletFromDapp ​

Disconnects the Keplr wallet from all previously connected DApps.

Returns:

  • (boolean):true if the disconnection was successful, false otherwise.

getWalletAddress ​

Retrieves the wallet address of the currently active wallet associated with a specified blockchain.

Arguments:

  • chainName (string): The name of the blockchain for which you want to obtain the wallet address.

Returns:

  • (string): The wallet address for the specified blockchain.

switchWallet ​

Switches the active wallet to the specified wallet by name.

Arguments:

  • walletName (string): The name of the wallet you want to switch to. This should match the name used when the wallet was created using the setupWallet command.

Returns:

  • (boolean): true if the wallet switch was successful, false otherwise.

addNewTokensFound ​

Adds all the new tokens discovered by the Keplr extension to the user's token portfolio when it connects to a new blockchain network.

Returns:

  • (boolean): true if the tokens were successfully added to the user's token portfolio false otherwise.

getTokenAmount ​

Retrieves the balance of a specified token in the wallet.

Arguments:

  • tokenName (string): The name of the token for which you want to retrieve the balance.

Returns:

  • (number): The amount of the specified token currently held in the wallet.

isExtensionWindowActive ​

Determines whether the Keplr extension window is the currently active tab.

Returns:

  • (boolean):true if the Keplr extension window is active, false otherwise.

switchToExtensionWindow ​

Switches the focus to the Keplr extension window tab. Keplr window is used for managing wallet related operations.

Returns:

  • (boolean):true if the focus change was successful, false otherwise.

isCypressWindowActive ​

Determines whether the Cypress window, where the DApp is running, is the currently active tab.

Returns:

  • (boolean):true if the Cypress window is active, false otherwise.

switchToCypressWindow ​

Switches the focus to the Cypress window tab.

Returns:

  • (boolean):true if the focus change was successful, false otherwise.

For a full list of commands, you can refer to the Keplr plugin file.

Testing chain software with @agoric/synthetic-chain ​

The tests above exercise a DApp frontend against a wallet. A different kind of e2e test exercises the chain software itself: does a governance proposal or a chain software upgrade actually produce the on-chain state it's supposed to, against an environment that behaves like the real agoric-3 mainnet chain? That's what a3p-integration in agoric-sdk is for, built on the @agoric/synthetic-chain test tool (published from the agoric-3-proposals repository).

a3p-integration spins up a synthetic agoric-3-like chain in Docker, applies one or more proposals (a chain software upgrade, a core-eval proposal, or both in sequence), and then runs functional tests against the result. This is the harness the SDK itself uses to verify that a chain upgrade or a core-eval (like deploying Fast USDC) behaves as intended before it goes to a real network.

Proposal packages ​

Each proposal lives in its own package under a3p-integration/proposals, isolated from the rest of the SDK and from each other; they run inside the Docker image and can't reach SDK source directly. A proposal's package.jsonagoricProposal field configures its type (Software Upgrade Proposal or /agoric.swingset.CoreEvalProposal), its ordering relative to other proposals, and, for a core-eval, the submission it evaluates.

Running it ​

a3p-integration is a self-contained Yarn 4 project, not part of the agoric-sdk root workspace (so it doesn't run under the root CI for packages/). From agoric-sdk/a3p-integration, with Docker and Buildx available:

bash
corepack enable
yarn install

# build the synthetic chain image, including this checkout's chain software
yarn build

# run every proposal's tests
yarn test

# run a single proposal's tests, or drop into it interactively
yarn test -m fast-usdc --debug

-m <substring> matches proposal package names, so yarn test -m fast-usdc runs (or --debug-attaches to) just the Fast USDC core-eval proposal. See the a3p-integration README and the agoric-3-proposals README for the full proposal-package layout and how to add a new one.