Skip to content

Conversation

gilgtm
Copy link
Contributor

@gilgtm gilgtm commented Aug 11, 2023

  • Before: To perform exhaustive state assertions with a RenderTester you have to manually keep track of the initial state.
  • After: Added RenderTesterResult/assertState which makes it easy to perform exhaustive state assertions by mutating the initial state

Checklist

  • Unit Tests
  • UI Tests
  • Snapshot Tests (iOS only)
  • I have made corresponding changes to the documentation

- Before: To perform exhaustive state assertions with a RenderTester you have to manually keep track of the initial state.
- After: Added RenderTesterResult/assertState which makes it easy to perform exhaustive state assertions by mutating the initial state
@gilgtm gilgtm requested a review from a team as a code owner August 11, 2023 15:27
@CLAassistant
Copy link

CLAassistant commented Aug 11, 2023

CLA assistant check
All committers have signed the CLA.

file: StaticString = #file,
line: UInt = #line,
changes: (inout WorkflowType.State) throws -> Void
) rethrows -> RenderTesterResult<WorkflowType> where WorkflowType.State: Equatable {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: there is an extension below (~L130) where the utilities for equatable states should probably all go

Copy link
Contributor Author

@gilgtm gilgtm Aug 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • move to extension

) rethrows -> RenderTesterResult<WorkflowType> where WorkflowType.State: Equatable {
var initialState = self.initialState
try changes(&initialState)
XCTAssertEqual(initialState, state, "Initial state did not match new state", file: file, line: line)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this error message seems a little confusing to me. we don't actually expect the 'initial state' to match the new state right? we expect the explicitly transformed state to match. not sure what the best wording to communicate this is though...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm yeah this doesn't make sense... perhaps something more vague like

Expected state does not match

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also perhaps I should reverse the order here

XCTAssertEqual(state, initialState

/// - changes: A function that receives the initial state
/// and is expected to mutate it to match the new state.
@discardableResult
public func assertState(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i wonder if naming like assertStateModifications, assertModifiedState, assertTransformedState, or something along those lines might be a bit more clear. since there's already an assert(state:) method, might be good to make the difference a bit more obvious.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assertStateModifications is pretty close to what I have now if you read the argument as part of the name

assertState(changes:)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

come to think of it assert(stateChanges:) or assert(stateModifications:) might be a closer match to the existing pattern. wdyt?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i guess my personal preference is just to try and avoid having a number of different methods that end up reading like assert { ... } with different closure types, as i find that harder to search for, and harder to understand when visually scanning.

Copy link
Contributor

@square-tomb square-tomb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this improvement. Looks good to me, and I agree with the naming/phrasing tweaks that you and @jamieQ are discussing.

This reminded me of a post I read arguing against exhaustive testing in TCA. But re-reading the post, it really only makes a good case against mandating all tests be exhaustive over state and effects.

let result = TestWorkflow()
.renderTester(initialState: .idle)
.render { _ in }

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall we test that assertState can succeed as well?

I'm not sure why we haven't done so for the other, existing assert/verify methods 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are already doing that in WorkflowRenderTesterTests/test_childWorkflowOutput for both this new method and verifyState


/// Exhaustive state testing against the initial state.
/// - Parameters:
/// - changes: A function that receives the initial state
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: param name doesn't match

@jamieQ jamieQ merged commit aab735b into square:main Aug 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants