@@ -31,7 +31,7 @@ program-tests/
31
31
** All programs in ` programs/** ` have corresponding integration test programs:**
32
32
33
33
- ** Account Compression Program** (` programs/account-compression/ ` ) → ` program-tests/account-compression-test/ `
34
- - ** Compressed Token Program** (` programs/compressed-token/ ` ) → ` program-tests/compressed-token-test/ `
34
+ - ** Compressed Token Program** (` programs/compressed-token/ ` ) → ` program-tests/compressed-token-test/ `
35
35
- ** Registry Program** (` programs/registry/ ` ) → ` program-tests/registry-test/ `
36
36
- ** System Program** (` programs/system/ ` ) → ` program-tests/system-test/ `
37
37
@@ -86,7 +86,7 @@ pub async fn assert_mint_operation(
86
86
) {
87
87
// Get actual state
88
88
let actual = get_actual_state (rpc , operation_params ). await ;
89
-
89
+
90
90
// Single comprehensive assertion
91
91
assert_eq! (actual , expected_output );
92
92
}
@@ -102,14 +102,14 @@ pub async fn assert_mint_operation(
102
102
#[tokio:: test]
103
103
async fn test_complete_token_lifecycle () {
104
104
// 1. Create mint
105
- // 2. Mint tokens
105
+ // 2. Mint tokens
106
106
// 3. Transfer tokens
107
107
// 4. Compress/decompress
108
108
// Each step verified with assertions
109
109
}
110
110
```
111
111
112
- ### Error Test Coverage
112
+ ### Error Test Coverage
113
113
** Every error condition must have a failing test**
114
114
115
115
``` rust
@@ -139,14 +139,14 @@ assert_eq!(actual_state, expected_end_state);
139
139
{
140
140
// Parse complete state before operation
141
141
let mut expected_after_state = parse_state_before (& state_data_before );
142
-
142
+
143
143
// Apply the expected changes to the before state
144
144
expected_after_state . field1 = new_value ; // Only change what should change
145
145
expected_after_state . amount -= transfer_amount ;
146
-
146
+
147
147
// Parse actual state after operation
148
148
let actual_after_state = parse_state_after (& state_data_after );
149
-
149
+
150
150
// Single comprehensive assertion: after = before + changes
151
151
assert_eq! (actual_after_state , expected_after_state );
152
152
}
@@ -165,7 +165,7 @@ From `/program-tests/utils/src/assert_decompressed_token_transfer.rs`:
165
165
spl_token_2022 :: state :: Account :: unpack (& recipient_data_before [.. 165 ]). unwrap ();
166
166
recipient_token_before . amount += transfer_amount ;
167
167
168
- // Parse as SPL token accounts first
168
+ // Parse as SPL token accounts first
169
169
let sender_account_after =
170
170
spl_token_2022 :: state :: Account :: unpack (& sender_account_data . data[.. 165 ]). unwrap ();
171
171
let recipient_account_after =
@@ -181,6 +181,12 @@ This pattern ensures you're testing **exact state transitions** rather than arbi
181
181
182
182
### ** ❌ Assertion Anti-Patterns to Avoid**
183
183
184
+ The test indexer in combination with litesvm LightProgram does not need time to catch up it is local.
185
+ ``` rust
186
+ // Give test indexer time to catch up
187
+ tokio :: time :: sleep (tokio :: time :: Duration :: from_millis (500 )). await ;
188
+ ```
189
+
184
190
``` rust
185
191
// ❌ WRONG: Individual field assertions
186
192
assert_eq! (actual . field1, expected_field1 );
@@ -265,10 +271,10 @@ async fn create_mint_helper(rpc: &mut RPC) -> Result<Signature, RpcError> {
265
271
** ✅ CORRECT: Use borsh deserialization for easier type handling**
266
272
``` rust
267
273
// Parse complete structs using borsh for easier handling
268
- let mint_data : CompressedMint =
274
+ let mint_data : CompressedMint =
269
275
BorshDeserialize :: deserialize (& mut account_data . as_slice ())
270
276
. expect (" Failed to deserialize CompressedMint" );
271
-
277
+
272
278
// Work with the complete struct
273
279
assert_eq! (actual_mint , expected_mint );
274
280
```
@@ -296,29 +302,29 @@ use light_test_utils::assert_operation_result;
296
302
#[serial]
297
303
async fn test_functional_flow () {
298
304
let mut rpc = setup_test_environment (). await ;
299
-
305
+
300
306
// Execute operation
301
307
let result = perform_operation (& mut rpc , test_params ). await . unwrap ();
302
-
308
+
303
309
// Assert complete expected outcome
304
310
let expected = ExpectedOperationResult {
305
311
transaction_signature : result . signature,
306
312
modified_accounts : expected_account_changes ,
307
313
emitted_events : expected_events ,
308
314
// ... all expected outputs
309
315
};
310
-
316
+
311
317
assert_operation_result (& mut rpc , & expected ). await ;
312
318
}
313
319
314
320
#[tokio:: test]
315
- #[serial]
321
+ #[serial]
316
322
async fn test_operation_fails_with_invalid_input () {
317
323
let mut rpc = setup_test_environment (). await ;
318
324
let invalid_params = create_invalid_test_params ();
319
-
325
+
320
326
let result = perform_operation (& mut rpc , invalid_params ). await ;
321
-
327
+
322
328
assert! (result . is_err ());
323
329
assert_eq! (
324
330
result . unwrap_err (). to_string (),
@@ -337,11 +343,11 @@ async fn test_operation_fails_with_invalid_input() {
337
343
## Key Principles
338
344
339
345
### 1. Comprehensive Coverage
340
- - ** Integration tests** : Every user workflow
346
+ - ** Integration tests** : Every user workflow
341
347
- ** Error tests** : Every error condition
342
348
- ** Edge cases** : Boundary conditions and invalid inputs
343
349
344
- ### 2. Clear Test Structure
350
+ ### 2. Clear Test Structure
345
351
- ** Arrange** : Set up test data and environment
346
352
- ** Act** : Execute the operation under test
347
353
- ** Assert** : Verify complete expected outcome using assertion helpers
@@ -409,4 +415,4 @@ Features:
409
415
7 . ** Include all required signers** in transaction calls
410
416
8 . ** Handle multi-signer scenarios** correctly
411
417
9 . ** Test with realistic amounts** not just trivial values
412
- 10 . ** Verify amount conservation** in transfer operations
418
+ 10 . ** Verify amount conservation** in transfer operations
0 commit comments