Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.near.org/llms.txt

Use this file to discover all available pages before exploring further.

Integration tests enable you to deploy a contract in the NEAR testnet or a local sandbox and create test users to interact with it. This way, you can thoroughly test your contract in a realistic environment. Moreover, when using the local sandbox you gain complete control of the network:
  1. Create test Accounts and manipulate their State and Balance.
  2. Simulate errors on callbacks.
  3. Control the time-flow and fast-forward into the future (Rust ready, TS coming soon).
In NEAR, integration tests are implemented using a framework called Sandbox. Sandbox comes in two flavors: 🦀 Rust and 🌐 Typescript. For Go contracts, unit tests are run with the near-go CLI:
near-go test project
This runs unit tests using the MockSystem environment to simulate the NEAR blockchain locally — no sandbox required. For full integration tests that deploy to a sandbox, Go contracts use the Rust workspaces-rs framework. See the Go Integration Testing section below.
Sandbox TestingNEAR Sandbox allows you to write tests once, and run them either on testnet or a local Sandbox. By default, Sandbox will start a sandbox and run your tests locally. Lets dive into the features of our framework and see how they can help you.

Create Accounts

Account


Dev Account

Subaccount

Using Secret Key

Using Credentials From File


WASM Files

Compile Contract Code

You don’t need to assert compiling process everytime. You can use ? operator to get the result as Vec<u8> without dealing with Result<Vec<u8>>, Error> type. That way you can directly use this vector to deploy the wasm file into account. Your test will still fail if compiling process fails.
let contract_wasm_path = cargo_near_build::build_with_cli(Default::default())?;

Loading From File

The same as in the case of compilation wasm from code, you don’t need to assert reading file process everytime. You can use expect method to get the reading file result as Vec<u8> and provide error message as a parameter. Your test will still fail if compiling process fails.
let contract_wasm = std::fs::read(artifact_path)
    .expect(format!("Could not read WASM file from {}", artifact_path).as_str());

Deploy Contracts

Dev Deploy

Deploy To Account


Logs

Show contract’s logs.
You can use println or dbg! when you want to see information from your code.In Rust, the output from your code is captured by default and not displayed in the terminal. In order to see the output, you have to use the --nocapture flageg. cargo test -- --nocaptureIf you want to access the contracts logs, you can find them in the tx_outcome.logs() Vec.
let tx_outcome = contract
        .call_function("set_greeting", json!({"greeting": "Hello World!"}))
        .transaction()
        .gas(Gas::from_tgas(100))
        .with_signer(contract.account_id().clone(), signer.clone())
        .send_to(&sandbox_network)
        .await?;
    assert!(tx_outcome.is_success());

    dbg!(tx_outcome.logs());
    // [tests/test_basics.rs:29:5] tx_outcome.logs() = [
    //     "Saving greeting: Hello World!",
    // ]

Account Balance


Transactions

Call

View


Patch State on the Fly

In Sandbox-mode, you can add or modify any contract state, contract code, account or access key with patchState. You can alter contract code, accounts, and access keys using normal transactions via the DeployContract, CreateAccount, and AddKey actions. But this limits you to altering your own account or sub-account. patchState allows you to perform these operations on any account.
As an alternative to patchState, you can stop the node, dump state at genesis, edit the genesis, and restart the node. This approach is more complex to do and also cannot be performed without restarting the node.

Time Traveling

sandbox offers support for forwarding the state of the blockchain to the future. This means contracts which require time sensitive data do not need to sit and wait the same amount of time for blocks on the sandbox to be produced. We can simply just call sandbox.fast_forward to get us further in time:

Using Testnet

NEAR Sandbox is set up so that you can write tests once and run them against a local Sandbox node (the default behavior) or against NEAR TestNet. Some reasons this might be helpful:
  • Gives higher confidence that your contracts work as expected
  • You can test against deployed testnet contracts
  • If something seems off in Sandbox mode, you can compare it to testnet
If you can create a new account on each iteration as well.

Spooning Contracts

Spooning a blockchain is copying the data from one network into a different network. NEAR Sandbox makes it easy to copy data from Mainnet or Testnet contracts into your local Sandbox environment:
Specify the contract name from testnet you want to be pulling, and a specific block ID referencing back to a specific time. (Just in case the contract you’re referencing has been changed or updated)Create a function called pull_contract which will pull the contract’s .wasm file from the chain and deploy it onto your local sandbox. You’ll have to re-initialize it with all the data to run tests. This is because the contract’s data is too big for the RPC service to pull down. (limits are set to 50Mb)

Snippets

Snippet I: Testing Hello NEAR

Lets take a look at the test of our Quickstart Project 👋 Hello NEAR, where we deploy the contract on an account and test it correctly retrieves and sets the greeting.

Snippet II: Testing Donations

In most cases we will want to test complex methods involving multiple users and money transfers. A perfect example for this is our Donation Example, which enables users to donate money to a beneficiary. Lets see its integration tests

Go Integration Testing

Go contracts use the Rust workspaces-rs framework for integration tests. The workflow is:
  1. Build your contract to WASM with near-go build
  2. Write integration tests in a separate Rust project using workspaces-rs
  3. Run with cargo test
Unit tests vs Integration testsnear-go test project runs unit tests using the MockSystem environment locally. For full integration tests that deploy to a sandbox, use the workspaces-rs Rust crate as described below.

Project Structure

my-contract/
├── main.go              # your Go contract
├── go.mod
├── go.sum
└── integration-tests/   # Standalone Rust integration test project
    ├── Cargo.toml
    └── tests/
        └── test_my_contract.rs

Running Tests

# Step 1: Build the Go contract to WASM (from the contract root)
near-go build

# Step 2: Run integration tests
cargo test --manifest-path integration-tests/Cargo.toml

Writing Integration Tests

Integration tests follow the workspaces-rs pattern. The compiled main.wasm sits one directory above integration-tests/, so tests load it with std::fs::read("../main.wasm").
Double-encoded return valuesnear-sdk-go wraps every return value in an extra JSON string encoding. When reading a view result, always deserialize in two steps: first parse the outer String, then parse the inner type.
// ✅ Correct two-step deserialization
let raw: String = contract.view("get_greeting").args_json(json!({})).await?.json()?;
let greeting: String = serde_json::from_str(&raw)?;

// ❌ Will fail – skips the outer wrapper
let greeting: String = contract.view("get_greeting").args_json(json!({})).await?.json()?;
// integration-tests/tests/test_greeting.rs
use serde_json::json;

#[tokio::test]
async fn test_greeting_init() -> anyhow::Result<()> {
    let sandbox = near_workspaces::sandbox().await?;
    let wasm = std::fs::read("../main.wasm")?;
    let contract = sandbox.dev_deploy(&wasm).await?;

    contract
        .call("init")
        .args_json(json!({}))
        .transact()
        .await?
        .into_result()?;

    // Two-step deserialization: outer String wrapper → inner type
    let raw: String = contract.view("get_greeting").args_json(json!({})).await?.json()?;
    let greeting: String = serde_json::from_str(&raw)?;
    assert_eq!(greeting, "Hello");
    Ok(())
}

#[tokio::test]
async fn test_set_greeting() -> anyhow::Result<()> {
    let sandbox = near_workspaces::sandbox().await?;
    let wasm = std::fs::read("../main.wasm")?;
    let contract = sandbox.dev_deploy(&wasm).await?;

    contract.call("init").args_json(json!({})).transact().await?.into_result()?;

    let caller = sandbox.dev_create_account().await?;
    caller
        .call(contract.id(), "set_greeting")
        .args_json(json!({ "greeting": "Howdy" }))
        .transact()
        .await?
        .into_result()?;

    let raw: String = contract.view("get_greeting").args_json(json!({})).await?.json()?;
    let greeting: String = serde_json::from_str(&raw)?;
    assert_eq!(greeting, "Howdy");
    Ok(())
}
# integration-tests/Cargo.toml
[package]
name = "greeting-integration-tests"
version = "0.1.0"
edition = "2021"

[dev-dependencies]
near-workspaces = "0.22.0"
tokio = { version = "1.41.1", features = ["full"] }
anyhow = "1.0.93"
serde_json = "1.0.133"
serde = { version = "1.0.215", features = ["derive"] }
You can also test your Go contract on NEAR testnet by deploying it first with near deploy and calling methods via the near CLI.See full example on GitHub

Additional Resources

Advanced Examples

Test Driven Design Using Workspaces and AVA

The video below walks through how to apply TDD with Workspaces and AVA for a simple contract: