Skip to content

Commit 967d498

Browse files
committed
migrate tests from workspaces to sandbox
1 parent a2a24f4 commit 967d498

7 files changed

Lines changed: 506 additions & 210 deletions

File tree

.github/workflows/tests.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ jobs:
1515
steps:
1616
- name: Checkout branch
1717
uses: actions/checkout@v4
18+
19+
- name: Install cargo-near
20+
run: curl --proto '=https' --tlsv1.2 -LsSf https://github.com/near/cargo-near/releases/latest/download/cargo-near-installer.sh | sh
21+
1822
- name: Run integration test
1923
run: cd integration-tests && cargo run --example integration-tests
2024
- name: Market tests

integration-tests/Cargo.toml

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,20 @@ publish = false
55
edition = "2021"
66

77
[dev-dependencies]
8-
near-sdk = { version = "5.11.0", features = ["unit-testing"] }
9-
near-workspaces = { version = "0.18.0", features = ["unstable"] }
10-
tokio = { version = "1.12.0", features = ["full"] }
8+
near-sdk = { version = "5.24.0", features = ["unit-testing"] }
9+
near-sandbox = "0.3"
10+
near-api = "0.8"
11+
cargo-near-build = "=0.10"
12+
tokio = { version = "1.48.0", features = ["full"] }
1113
serde_json = "1"
14+
testresult = "0.4.1"
15+
anyhow = "1.0"
16+
# This is temporary fix for the build error since those crates with a higher version require a higher version of Rust compiler (1.88.0)
17+
cargo-platform = "=0.3.1"
18+
darling = "=0.20.11"
19+
bon = "=3.8.1"
20+
time = "=0.3.44"
21+
time-core = "=0.1.6"
1222

1323
[[example]]
1424
name = "integration-tests"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[toolchain]
2-
channel = "stable"
2+
channel = "1.86.0"
33
components = ["rustfmt"]
44
targets = ["wasm32-unknown-unknown"]

integration-tests/src/helpers.rs

Lines changed: 177 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,127 @@
1-
use near_sdk::Gas;
2-
use near_workspaces::{
3-
types::{AccountDetails, NearToken},
4-
Account, Contract,
1+
use std::sync::Arc;
2+
3+
use near_api::{
4+
errors::ExecuteTransactionError, types::transaction::result::ExecutionFinalResult, Account,
5+
AccountId, Contract, NearToken, NetworkConfig, Signer,
56
};
7+
use near_sandbox::Sandbox;
8+
use near_sdk::Gas;
69
use serde_json::json;
710

11+
const INITIAL_BALANCE: NearToken = NearToken::from_near(30);
812
pub const DEFAULT_DEPOSIT: u128 = 10000000000000000000000;
913
pub const ONE_YOCTO_NEAR: NearToken = NearToken::from_yoctonear(1);
1014

15+
pub async fn init_sandbox() -> anyhow::Result<(Sandbox, NetworkConfig)> {
16+
// Initialize the sandbox
17+
let sandbox = near_sandbox::Sandbox::start_sandbox().await?;
18+
let sandbox_network =
19+
near_api::NetworkConfig::from_rpc_url("sandbox", sandbox.rpc_addr.parse()?);
20+
21+
Ok((sandbox, sandbox_network))
22+
}
23+
24+
pub async fn init_contracts(
25+
sandbox: &Sandbox,
26+
sandbox_network: &NetworkConfig,
27+
) -> anyhow::Result<(Contract, Contract, Arc<Signer>)> {
28+
// Build the NFT contract wasm file
29+
let nft_contract_wasm_path = cargo_near_build::build_with_cli(
30+
cargo_near_build::BuildOpts::builder()
31+
.manifest_path("../nft-contract-royalty/Cargo.toml")
32+
.build(),
33+
)
34+
.unwrap();
35+
let nft_contract_wasm = std::fs::read(nft_contract_wasm_path)?;
36+
37+
// Build the Market contract wasm file
38+
let market_contract_wasm_path = cargo_near_build::build_with_cli(
39+
cargo_near_build::BuildOpts::builder()
40+
.manifest_path("../market-contract/Cargo.toml")
41+
.build(),
42+
)
43+
.unwrap();
44+
let market_contract_wasm = std::fs::read(market_contract_wasm_path)?;
45+
46+
// Create the NFT and Market contracts accounts
47+
let nft_contract = create_subaccount(&sandbox, "nft-contract.sandbox")
48+
.await
49+
.unwrap()
50+
.as_contract();
51+
let market_contract = create_subaccount(&sandbox, "market-contract.sandbox")
52+
.await
53+
.unwrap()
54+
.as_contract();
55+
56+
// Initialize signer for the contract deployment
57+
let signer = near_api::Signer::from_secret_key(
58+
near_sandbox::config::DEFAULT_GENESIS_ACCOUNT_PRIVATE_KEY
59+
.parse()
60+
.unwrap(),
61+
)?;
62+
63+
// Deploy the ft contract
64+
near_api::Contract::deploy(nft_contract.account_id().clone())
65+
.use_code(nft_contract_wasm.to_vec())
66+
.with_init_call(
67+
"new_default_meta",
68+
json!({"owner_id": nft_contract.account_id().clone()}),
69+
)?
70+
.with_signer(signer.clone())
71+
.send_to(&sandbox_network)
72+
.await?
73+
.assert_success();
74+
75+
near_api::Contract::deploy(market_contract.account_id().clone())
76+
.use_code(market_contract_wasm.to_vec())
77+
.with_init_call(
78+
"new",
79+
json!({"owner_id": market_contract.account_id().clone()}),
80+
)?
81+
.with_signer(signer.clone())
82+
.send_to(&sandbox_network)
83+
.await?
84+
.assert_success();
85+
86+
return Ok((nft_contract, market_contract, signer));
87+
}
88+
89+
pub async fn init_accounts(sandbox: &Sandbox) -> anyhow::Result<(Account, Account, Account)> {
90+
// create accounts
91+
let alice = create_subaccount(&sandbox, "alice.sandbox").await.unwrap();
92+
let bob = create_subaccount(&sandbox, "bob.sandbox").await.unwrap();
93+
let charlie = create_subaccount(&sandbox, "charlie.sandbox")
94+
.await
95+
.unwrap();
96+
97+
return Ok((alice, bob, charlie));
98+
}
99+
11100
pub async fn mint_nft(
12101
user: &Account,
13102
nft_contract: &Contract,
14103
token_id: &str,
104+
signer: &Arc<Signer>,
105+
sandbox_network: &NetworkConfig,
15106
) -> Result<(), Box<dyn std::error::Error>> {
16107
let request_payload = json!({
17108
"token_id": token_id,
18-
"token_owner_id": user.id(),
109+
"token_owner_id": user.account_id(),
19110
"token_metadata": {
20111
"title": "Grumpy Cat",
21112
"description": "Not amused.",
22113
"media": "https://www.adamsdrafting.com/wp-content/uploads/2018/06/More-Grumpy-Cat.jpg"
23114
},
24115
});
25116

26-
let _ = user
27-
.call(nft_contract.id(), "nft_mint")
28-
.args_json(request_payload)
117+
let _ = nft_contract
118+
.call_function("nft_mint", json!(request_payload))
119+
.transaction()
29120
.deposit(NearToken::from_yoctonear(DEFAULT_DEPOSIT))
30-
.transact()
31-
.await;
121+
.with_signer(user.account_id().clone(), signer.clone())
122+
.send_to(&sandbox_network)
123+
.await?
124+
.assert_success();
32125

33126
Ok(())
34127
}
@@ -38,19 +131,23 @@ pub async fn approve_nft(
38131
user: &Account,
39132
nft_contract: &Contract,
40133
token_id: &str,
134+
signer: &Arc<Signer>,
135+
sandbox_network: &NetworkConfig,
41136
) -> Result<(), Box<dyn std::error::Error>> {
42137
let request_payload = json!({
43138
"token_id": token_id,
44-
"account_id": market_contract.id(),
139+
"account_id": market_contract.as_account().account_id(),
45140
"msg": serde_json::Value::Null,
46141
});
47142

48-
let _ = user
49-
.call(nft_contract.id(), "nft_approve")
50-
.args_json(request_payload)
143+
let _ = nft_contract
144+
.call_function("nft_approve", json!(request_payload))
145+
.transaction()
51146
.deposit(NearToken::from_yoctonear(DEFAULT_DEPOSIT))
52-
.transact()
53-
.await;
147+
.with_signer(user.account_id().clone(), signer.clone())
148+
.send_to(&sandbox_network)
149+
.await?
150+
.assert_success();
54151

55152
Ok(())
56153
}
@@ -59,15 +156,19 @@ pub async fn pay_for_storage(
59156
user: &Account,
60157
market_contract: &Contract,
61158
amount: NearToken,
159+
signer: &Arc<Signer>,
160+
sandbox_network: &NetworkConfig,
62161
) -> Result<(), Box<dyn std::error::Error>> {
63162
let request_payload = json!({});
64163

65-
let _ = user
66-
.call(market_contract.id(), "storage_deposit")
67-
.args_json(request_payload)
164+
let _ = market_contract
165+
.call_function("storage_deposit", json!(request_payload))
166+
.transaction()
68167
.deposit(amount)
69-
.transact()
70-
.await;
168+
.with_signer(user.account_id().clone(), signer.clone())
169+
.send_to(&sandbox_network)
170+
.await?
171+
.assert_success();
71172

72173
Ok(())
73174
}
@@ -79,29 +180,34 @@ pub async fn place_nft_for_sale(
79180
token_id: &str,
80181
approval_id: u64,
81182
price: &NearToken,
183+
signer: &Arc<Signer>,
184+
sandbox_network: &NetworkConfig,
82185
) -> Result<(), Box<dyn std::error::Error>> {
83186
let request_payload = json!({
84-
"nft_contract_id": nft_contract.id(),
187+
"nft_contract_id": nft_contract.as_account().account_id(),
85188
"token_id": token_id,
86189
"approval_id": approval_id,
87190
"sale_conditions": NearToken::as_yoctonear(price).to_string(),
88191
});
89-
let _ = user
90-
.call(market_contract.id(), "list_nft_for_sale")
91-
.args_json(request_payload)
192+
let _ = market_contract
193+
.call_function("list_nft_for_sale", json!(request_payload))
194+
.transaction()
92195
.gas(Gas::from_tgas(100))
93-
.transact()
94-
.await;
196+
.with_signer(user.account_id().clone(), signer.clone())
197+
.send_to(&sandbox_network)
198+
.await?
199+
.assert_success();
95200

96201
Ok(())
97202
}
98203

99-
pub async fn get_user_balance(user: &Account) -> NearToken {
100-
let details: AccountDetails = user
101-
.view_account()
204+
pub async fn get_user_balance(user: &Account, sandbox_network: &NetworkConfig) -> NearToken {
205+
user.tokens()
206+
.near_balance()
207+
.fetch_from(&sandbox_network)
102208
.await
103-
.expect("Account has to have some balance");
104-
details.balance
209+
.expect("Failed to get user balance")
210+
.total
105211
}
106212

107213
pub async fn purchase_listed_nft(
@@ -110,57 +216,61 @@ pub async fn purchase_listed_nft(
110216
nft_contract: &Contract,
111217
token_id: &str,
112218
offer_price: NearToken,
113-
) -> Result<(), Box<dyn std::error::Error>> {
219+
signer: &Arc<Signer>,
220+
sandbox_network: &NetworkConfig,
221+
) -> Result<ExecutionFinalResult, ExecuteTransactionError> {
114222
let request_payload = json!({
115223
"token_id": token_id,
116-
"nft_contract_id": nft_contract.id(),
224+
"nft_contract_id": nft_contract.as_account().account_id(),
117225
});
118226

119-
let _ = bidder
120-
.call(market_contract.id(), "offer")
121-
.args_json(request_payload)
122-
.max_gas()
227+
market_contract
228+
.call_function("offer", json!(request_payload))
229+
.transaction()
123230
.deposit(offer_price)
124-
.transact()
125-
.await;
126-
127-
Ok(())
231+
.max_gas()
232+
.with_signer(bidder.account_id().clone(), signer.clone())
233+
.send_to(&sandbox_network)
234+
.await
128235
}
129236

130237
pub async fn transfer_nft(
131238
sender: &Account,
132239
receiver: &Account,
133240
nft_contract: &Contract,
134241
token_id: &str,
242+
signer: &Arc<Signer>,
243+
sandbox_network: &NetworkConfig,
135244
) -> Result<(), Box<dyn std::error::Error>> {
136245
let request_payload = json!({
137246
"token_id": token_id,
138-
"receiver_id": receiver.id(),
247+
"receiver_id": receiver.account_id(),
139248
"approval_id": 1 as u64,
140249
});
141250

142-
let _ = sender
143-
.call(nft_contract.id(), "nft_transfer")
144-
.args_json(request_payload)
145-
.max_gas()
251+
let _ = nft_contract
252+
.call_function("nft_transfer", json!(request_payload))
253+
.transaction()
146254
.deposit(ONE_YOCTO_NEAR)
147-
.transact()
148-
.await;
255+
.with_signer(sender.account_id().clone(), signer.clone())
256+
.send_to(&sandbox_network)
257+
.await?
258+
.assert_success();
149259

150260
Ok(())
151261
}
152262

153263
pub async fn get_nft_token_info(
154264
nft_contract: &Contract,
155265
token_id: &str,
266+
sandbox_network: &NetworkConfig,
156267
) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
157268
let token_info: serde_json::Value = nft_contract
158-
.call("nft_token")
159-
.args_json(json!({"token_id": token_id}))
160-
.transact()
269+
.call_function("nft_token", json!({"token_id": token_id}))
270+
.read_only()
271+
.fetch_from(&sandbox_network)
161272
.await?
162-
.json()
163-
.unwrap();
273+
.data;
164274

165275
Ok(token_info)
166276
}
@@ -169,3 +279,16 @@ pub fn round_to_near_dp(amount: u128, sf: u128) -> String {
169279
let near_amount = amount as f64 / 1_000_000_000_000_000_000_000_000.0; // yocto in 1 NEAR
170280
return format!("{:.1$}", near_amount, sf as usize);
171281
}
282+
283+
pub async fn create_subaccount(
284+
sandbox: &near_sandbox::Sandbox,
285+
name: &str,
286+
) -> testresult::TestResult<near_api::Account> {
287+
let account_id: AccountId = name.parse().unwrap();
288+
sandbox
289+
.create_account(account_id.clone())
290+
.initial_balance(INITIAL_BALANCE)
291+
.send()
292+
.await?;
293+
Ok(near_api::Account(account_id))
294+
}

0 commit comments

Comments
 (0)