# Writing e2e tests with ink-wrapper

## Introduction

{% hint style="info" %}
While this tutorial focuses on writing e2e (end-to-end) tests, the same approach can be utilized to call your contracts from any backend application written in Rust.
{% endhint %}

The default tooling for calling contracts provided by [`subxt`](https://crates.io/crates/subxt) and similar tools relies on runtime checks on input data and received responses. In order to provide compile-time checks as well as easy access to code completion and documentation for contracts, we've developed `ink-wrapper`. Simply put, it's a tool that generates a bunch of strongly-typed wrapper code around submitting contract-related transactions. You can include this generated code in your project and use it, instead of calling primitives like `subxt` directly.

## Setup

To get started you will need to install `ink-wrapper` itself (this tutorial uses `0.4.1` so please install the same version to follow along):

```bash
cargo install ink-wrapper --locked --force --version 0.4.1
```

In this guide we will write e2e tests for an example PSP22 contract that we use to test `ink-wrapper` itself. You will need [docker](https://www.docker.com/) to run a chain for testing and use the tooling provided in the repo to compile contracts. With that:

```bash
git clone git@github.com:Cardinal-Cryptography/ink-wrapper.git
```

Finally, let's create a new project that will house our tests:

```bash
cargo new --lib psp22-tests
```

## Generating contract wrappers

The `ink-wrapper` takes a `.json` metadata file generated while compiling the contract and produces a Rust file based on that. First, setup a node with the contract in question compiled and deployed. This will also run `ink-wrapper`'s own tests at the end - just ignore that.

```bash
cd ink-wrapper
make all-dockerized
```

Then, invoke `ink-wrapper` on the produced `.json` metadata file and put the results in the `src` directory in the `psp22-tests` project:

```bash
ink-wrapper -m test-project/psp22_contract/target/ink/psp22_contract.json \
  | rustfmt --edition 2021 > ../psp22-tests/src/psp22_contract.rs
```

Notice that we're piping the output of `ink-wrapper` through `rustfmt` - the output is not guaranteed to be formatted, so in order to commit nicely formatted code into your repo, it's recommended to use this method when regenerating the wrapper files.

## Using the wrappers

Now, let's move to the `psp22-tests` project. We will need to add some dependencies to make the wrappers compile:

{% code title="Cargo.toml" %}

```toml
# ...

[dependencies]
ink-wrapper-types = "0.4.0"
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
ink_primitives = "4.0.1"
aleph_client = "3.0.0"
async-trait = "0.1.68"

# These are a couple dependencies we will use to write our tests
tokio = { version = "1.25.0", features = ["macros"] }
rand = "0.8.5"
anyhow = "1.0.71"
```

{% endcode %}

As well as switch to nightly by putting the following in `rust-toolchain.toml`:

{% code title="rust-toolchain.toml" %}

```toml
[toolchain]
channel = "nightly-2023-04-20"
components = ["rustfmt", "rust-src", "clippy"]
```

{% endcode %}

Attach the module produced by `ink-wrapper` to `psp22-tests`:

{% code title="lib.rs" %}

```rust
mod psp22_contract;
```

{% endcode %}

Now add the following test code:

{% code title="lib.rs" %}

```rust
#[cfg(test)]
mod tests {
    use crate::psp22_contract;
    // The PSP22-specific methods of the contract are hidden behind a trait.
    // This will only happen for contract methods with names like "PSP22::transfer".
    // Other contract methods will just be available on the contract instance without
    // any extra trait.
    use crate::psp22_contract::PSP22 as _;
    use aleph_client::keypair_from_string;
    use aleph_client::Connection;
    use aleph_client::SignedConnection;
    use anyhow::Result;
    // This is just a convenience helper for converting any AsRef<[u8; 32]> to
    // ink_primitives::AccountId - the datatype used by the generated code to
    // represent account ids.
    use ink_wrapper_types::util::ToAccountId as _;
    use rand::RngCore as _;

    #[tokio::test]
    async fn it_works() -> Result<()> {
        // Connect to the node launched earlier.
        let conn = Connection::new("ws://localhost:9944").await;
        let conn = SignedConnection::from_connection(conn, keypair_from_string("//Alice"));
        let bob = keypair_from_string("//Bob");

        // We're using a random salt here so that each test run is independent.
        let mut salt = vec![0; 32];
        rand::thread_rng().fill_bytes(&mut salt);
        let total_supply = 1000;
        // Constructors take a connection, the salt, and any arguments
        // the actual constructor requires afterwards.
        let contract = psp22_contract::Instance::new(&conn, salt, total_supply).await?;

        // A mutating method takes a signed connection and any arguments afterwards.
        contract
            .transfer(&conn, bob.account_id().to_account_id(), 100, vec![])
            .await?;

        // A reader method takes a connection (may be unsigned) and any arguments afterwards.
        let balance = contract
            .balance_of(&conn, bob.account_id().to_account_id())
            .await??;
        assert_eq!(balance, 100);

        Ok(())
    }
}
```

{% endcode %}

With that, you should be able to run `cargo test` and have it pass with 1 test run!
