Search code examples
rustsubstrate

getting payload from a substrate event back in rust tests


i've created my first substrate project successful and the built pallet also works fine. Now i wanted to create tests for the flow and the provided functions.

My flow is to generate a random hash and store this hash associated to the sender of the transaction

let _sender = ensure_signed(origin)?;
let nonce = Nonce::get();
let _random_seed = <randomness_collective_flip::Module<T>>::random_seed();
let random_hash = (_random_seed, &_sender, nonce).using_encoded(T::Hashing::hash);


ensure!(!<Hashes<T>>::contains_key(random_hash), "This new id already exists");

let _now = <timestamp::Module<T>>::get();

let new_elem = HashElement {
    id: random_hash,
    parent: parent,
    updated: _now,
    created: _now
};

<Hashes<T>>::insert(random_hash, new_pid);
<HashOwner<T>>::insert(random_hash, &_sender);

Self::deposit_event(RawEvent::Created(random_hash, _sender));

Ok(())

works good so far, when now i want to test the flow with a written test, i want to check if the hash emitted in the Created event is also assigned in the HashOwner Map. For this i need to get the value out of the event back.

And this is my problem :D i'm not professional in rust and all examples i found are expecting all values emitted in the event like this:

// construct event that should be emitted in the method call directly above
let expected_event = TestEvent::generic_event(RawEvent::EmitInput(1, 32));

// iterate through array of `EventRecord`s
assert!(System::events().iter().any(|a| a.event == expected_event));

When debugging my written test:

assert_ok!(TemplateModule::create_hash(Origin::signed(1), None));
let events = System::events();

let lastEvent = events.last().unwrap();
let newHash = &lastEvent.event;

i see in VSCode that the values are available:

debug window of vs code

but i dont know how to get this Hash in a variable back... maybe this is only a one liner ... but my rust knowledge is damn too small :D

thank you for your help


Solution

  • Here's a somewhat generic example of how to parse and check events, if you only care about the last event that your module put in system and nothing else.

    assert_eq!(
        System::events()
            // this gives you an EventRecord { event: ..., ...}
            .into_iter() 
            // map into the inner `event`.
            .map(|r| r.event)
            // the inner event is like `OuterEvent::mdouleEvent(EventEnum)`. The name of the outer 
            // event comes from whatever you have placed in your `delc_event! {}` in test mocks.
            .filter_map(|e| { 
                if let MetaEvent::templateModule(inner) = e {
                    Some(inner)
                } else {
                    None
                }
            })
            .last()
            .unwrap(),
    
        // RawEvent is defined and imported in the template.rs file. 
        // val1 and val2 are things that you want to assert against.
        RawEvent::Created(val1, val2),
    );
    

    Indeed you can also omit the first map or do it in more compact ways, but I have done it like this so you can see it step by step.

    Print the System::events(), this also helps.