diff --git a/docs/src/testing/contracts.md b/docs/src/testing/contracts.md index b46cd58cd2..05ddd10865 100644 --- a/docs/src/testing/contracts.md +++ b/docs/src/testing/contracts.md @@ -1,6 +1,7 @@ # Testing Smart Contracts > ℹī¸ **Info** +> > To use the library functions designed for testing smart contracts, > you need to add `snforge_std` package as a dependency in > your [`Scarb.toml`](https://docs.swmansion.com/scarb/docs/guides/dependencies.html#development-dependencies) @@ -15,11 +16,11 @@ writing smart contracts, you often want to test their interactions with the bloc ## The Test Contract -In this tutorial we will be using this Starknet contract +In this tutorial we will be using this Starknet contract, in a new `using_dispatchers` package. ```rust #[starknet::interface] -trait IHelloStarknet { +pub trait IHelloStarknet { fn increase_balance(ref self: TContractState, amount: felt252); fn get_balance(self: @TContractState) -> felt252; } @@ -54,6 +55,7 @@ Let's write a test that will deploy the `HelloStarknet` contract and call some f ```rust use snforge_std::{ declare, ContractClassTrait }; +use using_dispatchers::{ IHelloStarknetDispatcher, IHelloStarknetDispatcherTrait }; #[test] fn call_and_invoke() { @@ -122,14 +124,12 @@ mod HelloStarknet { // Panics fn do_a_panic(self: @ContractState) { - let mut arr = ArrayTrait::new(); - arr.append('PANIC'); - arr.append('DAYTAH'); - panic(arr); + panic(array!['PANIC', 'DAYTAH']); } fn do_a_string_panic(self: @ContractState) { - assert!(false, "This is panicking with a string, which can be longer than 31 characters"); + // A macro which allows panicking with a ByteArray (string) instance + panic!("This is panicking with a string, which can be longer than 31 characters"); } } } @@ -139,11 +139,9 @@ If we called this function in a test, it would result in a failure. ```rust #[test] -#[feature("safe_dispatcher")] fn failing() { - // ... - - let (contract_address, _) = contract.deploy(@calldata).unwrap(); + let contract = declare("HelloStarknet").unwrap(); + let (contract_address, _) = contract.deploy(@array![]).unwrap(); let dispatcher = IHelloStarknetDispatcher { contract_address }; dispatcher.do_a_panic(); @@ -169,19 +167,25 @@ Failures: ### `SafeDispatcher` Using `SafeDispatcher` we can test that the function in fact panics with an expected message. +Safe dispatcher is a special kind of dispatcher, which are not allowed in contracts themselves, +but are available for testing purposes. + +They allow using the contract without automatically unwrapping the result, which allows to catch the error like shown below. ```rust +// Add those to import safe dispatchers, which are autogenerated, like regular dispatchers +use using_dispatchers::{ IHelloStarknetSafeDispatcher, IHelloStarknetSafeDispatcherTrait }; + #[test] #[feature("safe_dispatcher")] fn handling_errors() { // ... - + let contract = declare("HelloStarknet").unwrap(); let (contract_address, _) = contract.deploy(@calldata).unwrap(); let safe_dispatcher = IHelloStarknetSafeDispatcher { contract_address }; - match safe_dispatcher.do_a_panic() { - Result::Ok(_) => panic_with_felt252('shouldve panicked'), + Result::Ok(_) => panic!("Entrypoint did not panic"), Result::Err(panic_data) => { assert(*panic_data.at(0) == 'PANIC', *panic_data.at(0)); assert(*panic_data.at(1) == 'DAYTAH', *panic_data.at(1)); @@ -207,20 +211,20 @@ Similarly, you can handle the panics which use `ByteArray` as an argument (like // Necessary utility function import use snforge_std::byte_array::try_deserialize_bytearray_error; -// ... #[test] #[feature("safe_dispatcher")] fn handling_string_errors() { // ... - let (contract_address, _) = contract.deploy(@calldata).unwrap(); + let contract = declare("HelloStarknet").unwrap(); + let (contract_address, _) = contract.deploy(@array![]).unwrap(); let safe_dispatcher = IHelloStarknetSafeDispatcher { contract_address }; - match safe_dispatcher.do_a_panic_with_bytearray() { - Result::Ok(_) => panic_with_felt252('shouldve panicked'), + match safe_dispatcher.do_a_string_panic() { + Result::Ok(_) => panic!("Entrypoint did not panic"), Result::Err(panic_data) => { let str_err = try_deserialize_bytearray_error(panic_data.span()).expect('wrong format'); assert( - str_err == "This is a very long\n and multiline message that is certain to fill the buffer", + str_err == "This is panicking with a string, which can be longer than 31 characters", 'wrong string received' ); } @@ -231,7 +235,7 @@ You also could skip the de-serialization of the `panic_data`, and not use `try_d > 📝 **Note** > -> To operate with `SafeDispatcher` it's required to annotage its usage with `#[feature("safe_dispatcher")]`. +> To operate with `SafeDispatcher` it's required to annotate its usage with `#[feature("safe_dispatcher")]`. > > There are 3 options: > - module-level declaration