Checking CosmWasm error messages with cw_multi_test

Published

I’m constantly using the cw-multi-test package to build tests for my smart contracts.

It’s also good practice to test for errors and not only good execution, but how can we check that the error being returned is the expected one?

Usually when developing a contract with CosmWasm, it’s common practice to define an enum called ContractError which tracks all possible errors. This is usually used in conjunction with the thiserror package.

Here’s a sample of defined errors for a CosmWasm smart contract:

use cosmwasm_std::StdError;
use thiserror::Error;

#[derive(Error, Debug, PartialEq)]
pub enum ContractError {
    #[error("{0}")]
    Std(#[from] StdError),

    #[error("Never")]
    Never {},

    #[error("NotImplemented")]
    NotImplemented {},

    #[error("Unauthorized")]
    Unauthorized {},
}

Our problem here is that the error returned by the cw_multi_test is wrapped, and cannot be directly compared to the errors we’ve defined in our enum.

So, how can we compare them in our tests? As it turns out, the Error type defined in cw_multi_test exposes a method “root_cause” which can be cast to string. Once the value from root_cause has been cast to string it can actually be compared to your error variant, if it has also been cast to string!

Check it out:

// We send a message to our contract
let msg = ExecuteMsg::MyMessage {
    payload: String::from("test_value"),
};
let res = app.execute_contract(caller, contract_addr, &msg, &[]);

// we expect this message to fail, so we'll unwrap the error 
let err = res.unwrap_err();

// In our test we expect the error to be an unauthorized error
// so we'll assert_eq between the stringified error, and the stringified enum
assert_eq!(
    err.root_cause().to_string(),
    ContractError::Unauthorized {}.to_string()
);

That’s it! Now you’re able to know exactly what’s wrong at a given point in the execution of your contract when testing it.