use aleo_rust_sdk::AleoClient;
use snarkvm::console::program::ProgramID;
use snarkvm::prelude::{FromStr, PrivateKey, TestRng, TestnetV0};
use wiremock::{
Mock, MockServer, ResponseTemplate,
matchers::{method, path},
};
#[tokio::test]
async fn test_client_get_block_height() {
let mock_server = MockServer::start().await;
let base_url = mock_server.uri();
Mock::given(method("GET"))
.and(path("/block/height/latest"))
.respond_with(ResponseTemplate::new(200).set_body_string("42"))
.mount(&mock_server)
.await;
let client = AleoClient::new(&base_url).unwrap();
let height = client.get_block_height().await.unwrap();
assert_eq!(height, 42);
}
#[tokio::test]
async fn test_client_get_state_root_from_client() {
let mock_server = MockServer::start().await;
let base_url = mock_server.uri();
Mock::given(method("GET"))
.and(path("/stateRoot/latest"))
.respond_with(
ResponseTemplate::new(200).set_body_string(
"\"sr1lkr8fzg8mk69qrtycxjvtrg8rvh77puaq7fm56cjkh04xhprdqzq3a355s\"",
),
)
.mount(&mock_server)
.await;
let client = AleoClient::new(&base_url).unwrap();
let root = client.get_state_root().await.unwrap();
assert_eq!(
root.to_string(),
"sr1lkr8fzg8mk69qrtycxjvtrg8rvh77puaq7fm56cjkh04xhprdqzq3a355s"
);
}
#[tokio::test]
async fn test_client_execute_and_broadcast_covers_first_half() {
let mock_server = MockServer::start().await;
let base_url = mock_server.uri();
let rpc_url = format!("{}/jsonrpc", base_url);
let hello_src = "program hello.aleo;\nfunction hello:\n input r0 as u32.public;\n input r1 as u32.private;\n add r0 r1 into r2;\n output r2 as u32.private;\n";
Mock::given(method("GET"))
.and(path("/program/hello.aleo"))
.respond_with(ResponseTemplate::new(200).set_body_string(hello_src))
.mount(&mock_server)
.await;
Mock::given(method("GET"))
.and(path("/stateRoot/latest"))
.respond_with(
ResponseTemplate::new(200).set_body_string(
"\"sr1lkr8fzg8mk69qrtycxjvtrg8rvh77puaq7fm56cjkh04xhprdqzq3a355s\"",
),
)
.mount(&mock_server)
.await;
Mock::given(method("GET"))
.and(path("/block/height/latest"))
.respond_with(ResponseTemplate::new(200).set_body_string("42"))
.mount(&mock_server)
.await;
let mut client = AleoClient::new_with_rpc(&base_url, &rpc_url).unwrap();
let mut rng = TestRng::default();
let pk: PrivateKey<TestnetV0> = PrivateKey::new(&mut rng).unwrap();
let _ = client.set_account_from_private_key_str(&pk.to_string());
let program_id = ProgramID::<TestnetV0>::from_str("hello.aleo").unwrap();
let result = client
.execute_and_broadcast(&pk, &program_id, "hello", vec!["1u32", "2u32"], 0, 0)
.await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_client_get_balance_none() {
let mock_server = MockServer::start().await;
let base_url = mock_server.uri();
let json_resp = serde_json::json!({
"jsonrpc": "2.0", "id": 1, "result": null
});
Mock::given(method("POST"))
.respond_with(ResponseTemplate::new(200).set_body_json(json_resp))
.mount(&mock_server)
.await;
let mut client = AleoClient::new(&base_url).unwrap();
let mut rng = TestRng::default();
let pk: PrivateKey<TestnetV0> = PrivateKey::new(&mut rng).unwrap();
let pk_str = pk.to_string();
let _ = client.set_account_from_private_key_str(&pk_str);
let balance = client.get_balance().await.unwrap();
assert!(balance.is_none());
}
#[tokio::test]
async fn test_deploy_program_end_to_end() {
if std::env::var("ALEO_TEST_DEPLOY").is_err() {
eprintln!("Skipping e2e deploy: set ALEO_TEST_DEPLOY=1 to run");
return;
}
let pk_str = std::env::var("PRIVATE_KEY").expect("PRIVATE_KEY env var required");
let pk = PrivateKey::<TestnetV0>::from_str(&pk_str).expect("Invalid private key");
let mut client = AleoClient::new("https://api.explorer.provable.com/v2/testnet").unwrap();
let _ = client.set_account_from_private_key_str(&pk.to_string());
let suffix: u64 = rand::random();
let source = format!(
"program hello_e2e_{suffix}.aleo;\n\nconstructor:\n add 1u32 2u32 into r0;\n\nfunction hello:\n input r0 as u32.public;\n output r0 as u32.public;\n"
);
println!("Deploying with min cost...");
let tx_id = client.deploy_program(&source, 0).await.expect("Deploy should succeed");
println!("✅ Tx: {tx_id}");
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
let check = client
.network
.fetch_transaction(&tx_id)
.await
.unwrap_or_else(|e| panic!("Transaction not found on chain: {e}"));
let parsed: serde_json::Value =
serde_json::from_str(&check).expect("fetch_transaction should return valid JSON");
assert!(
parsed.get("id").is_some(),
"Transaction must have an 'id' field"
);
assert_eq!(
parsed["type"], "deploy",
"Transaction type must be 'deploy'"
);
println!(
"✅ Deploy verified on chain: tx={tx_id}, type={}",
parsed["type"]
);
}