Fluent Command Assertions#523
Conversation
|
@StuartHarris @charypar I'm open to changing the ergonomics of this, I just made a judgement call on what looked best to me here, happy to rename anything if you find it confusing. This has been something I've been wanting that I've built internally but just makes life easier while writing tests. |
292fe3d to
02e9577
Compare
charypar
left a comment
There was a problem hiding this comment.
This is super nice! 👏🏻 I left some minor suggestions, but it reads really nicely and makes the tests more readable still. Great! ❤️
| let test_ext = quote! { | ||
| pub trait #test_ext_trait_ident<Event> | ||
| where | ||
| Event: ::core::marker::Send + 'static, | ||
| { | ||
| #(#test_ext_trait_methods)* | ||
|
|
||
| fn then_event<F>(&mut self, f: F) -> &mut Self | ||
| where | ||
| F: ::core::ops::FnOnce(&Event); | ||
| } | ||
|
|
||
| impl<Event> #test_ext_trait_ident<Event> for ::crux_core::Command<#enum_ident, Event> | ||
| where | ||
| Event: ::core::marker::Send + 'static, | ||
| { | ||
| #(#test_ext_impl_methods)* | ||
|
|
||
| #[track_caller] | ||
| fn then_event<F>(&mut self, f: F) -> &mut Self | ||
| where | ||
| F: ::core::ops::FnOnce(&Event), | ||
| { | ||
| let ev = self.events().next() | ||
| .unwrap_or_else(|| panic!("expected an event but got none")); | ||
| f(&ev); | ||
| self | ||
| } | ||
| } | ||
| }; |
There was a problem hiding this comment.
Can we make sure we only compile these in #[cfg(test)]? Should be as easy as annotating the trait definition and implementation as such.
There was a problem hiding this comment.
@charypar that would make them only available in in the same crate that declared Effect and would shut out integration tests or other crates. The current assertions don't have cfg(test), I believe, for this reason.
So I think we leave it as is; does that work for you?
There was a problem hiding this comment.
Is that right? I'd have thought that the test binaries built from tests/ modules would automatically build their parent crate (which declares the Effect) in cfg(test) as well 🤔
I'd really like us to avoid generating test-only helpers and code in people's production binaries, for both compile times and wasm bundle sizes.
There was a problem hiding this comment.
I've gated as many test helpers behind #[cfg(test)] as I can. The others I've left. e.g. Effect::is_*() and Effect::into_*() are more general purpose and the others are used cross-crate currently (although I'll see if we can fix that too)
There was a problem hiding this comment.
Actually I'm going to put these in a stacked PR
|
I love it, thanks @mhedgpeth 🚀 |
Co-authored-by: Viktor Charypar <charypar@gmail.com>
Co-authored-by: Viktor Charypar <charypar@gmail.com>
1cd1187 to
3471d48
Compare
* gate as many test helpers behind cfg(test) as we can * cross crate calls to testing helpers now need feature=testing in dev-deps * replace cfg(test) with doc(hidden)
|
@StuartHarris I'm going to make sure the new declaration in |
…ffect assertion message and docs.
|
@StuartHarris I made three changes after merging from your change:
I think these are ready, let me know and we can merge. It would be great to include this in 0.18. |
StuartHarris
left a comment
There was a problem hiding this comment.
This is great. Thank you. It's a shame the tokens are now emitted without formatting, but I don't suppose that matters. The extra compile time to pretty print them is probably not warranted seeing as few if anyone needs to see the expanded content here. I'll merge and look at getting 0.18 out
The current way to assert effects and resolve them to events is verbose, and that leaves me not testing my app as much as I would like.
This change introduces a fluent way to do this, which would make testing more
accessible while writing it, leading to better tests.
There are three variants of this:
Quick render assertion: single effect, no payload check:
Multiple chained assertions: assert each effect's variant and operation, in order:
Resolve to an event: assert, resolve, and hand back the event for
update():The closure does double duty: assert on
&op, then return the response payload the validator hands torequest.resolve(...)for you. The next chain step (or.expect_event()) sees whatever the resolved task emits.Since the current API still allows for edge-case testing and since I don't want to introduce breaking changes, it's untouched.
The examples are updated with the fluent style, as well as the book. New panic-case tests in
crux_core/tests/effect_test_ext.rscover empty queues, wrong variants, missing events, andexpect_only_*strictness.