-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Simple SyncUp tutorial fixes #3141
Changes from 18 commits
8b43dd0
81895df
0e0deac
3384ee1
8756062
f6d67d9
9d93448
ccac45b
142fbd0
061e90d
b56f255
58f5777
8688606
1ab1b55
d8be214
702e0b2
d37254d
c3e67ea
357580f
10e1410
4c504e8
43d2c71
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -155,7 +155,7 @@ | |||||||||||||||
|
||||||||||||||||
> Note: We are pre-emptively applying the `@CasePathable` macro to make it possible to write | ||||||||||||||||
tests against these actions in a keypath-like syntax. The `@CasePathable` macro is | ||||||||||||||||
automatically applied to `Action` enums inside reducers, but macros cannot recursive apply | ||||||||||||||||
automatically applied to `Action` enums inside reducers, but macros cannot recursively apply | ||||||||||||||||
themselves and so we must do it manually sometimes. | ||||||||||||||||
|
||||||||||||||||
@Code(name: "SyncUpDetail.swift", file: EditingAndDeletingSyncUp-02-code-0001.swift, previousFile: EditingAndDeletingSyncUp-02-code-0001-previous.swift) | ||||||||||||||||
|
@@ -184,7 +184,8 @@ | |||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
@Step { | ||||||||||||||||
Use the ``ComposableArchitecture/Reducer/ifLet(_:action:then:fileID:line:)-42kki`` operator | ||||||||||||||||
Add support for the `.alert` case, and | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. because the step also makes this change in the diff from Lines 28 to 29 in af38644
to EditingAndDeletingSyncUp-02-code-0004.swift Lines 28 to 32 in af38644
|
||||||||||||||||
use the ``ComposableArchitecture/Reducer/ifLet(_:action:then:fileID:line:)-42kki`` operator | ||||||||||||||||
stephencelis marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||
again to integrate the alert's logic into the `SyncUpDetail` reducer. | ||||||||||||||||
|
||||||||||||||||
@Code(name: "SyncUpDetail.swift", file: EditingAndDeletingSyncUp-02-code-0004.swift) | ||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -37,7 +37,7 @@ | |||||
} | ||||||
|
||||||
Next we add a case to the `Action` enum for each action the user can perform in the view. | ||||||
Currently there are 3 buttons, and so we will have an action for each. | ||||||
Currently there are 2 buttons, and so we will have an action for each. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From this, which today just covers the two actions - delete and edit. Lines 43 to 44 in af38644
|
||||||
|
||||||
@Step { | ||||||
Add an action for each of the buttons in the UI, including tapping the "Delete" button, | ||||||
|
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -46,9 +46,7 @@ | |||
|
||||
@Step { | ||||
Assert how the state changes after sending the action. In particular, the `syncUp` data | ||||
inside the `edit` case of the destination should change. We can use the special | ||||
``ComposableArchitecture/PresentationState/subscript(case:)-7uqte`` defined on | ||||
`$destination` to modify the data in a particular case. | ||||
inside the `edit` case of the destination should change. | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This subscript syntax isn't being used here: Line 24 in af38644
|
||||
|
||||
Run the test suite again to confirm that everything still passes. | ||||
|
||||
|
@@ -71,79 +69,5 @@ | |||
It is also possible to shorten this test quite a bit by using a non-exhaustive test store, as | ||||
we did in <doc:PresentingSyncUpForm>, but we will leave that as an exercise for the reader. | ||||
} | ||||
} | ||||
|
||||
<!-- | ||||
This is all old now that we are using @Shared and deleting directly in the reducer. We can | ||||
either omit this or update it. | ||||
|
||||
@Section(title: "Testing the delete flow") { | ||||
@ContentAndMedia { | ||||
Next we will test the flow of the user deleting the sync-up. This involves asserting that the | ||||
confirmation alert shows, and emulating the user interacting with the alert. | ||||
} | ||||
|
||||
@Steps { | ||||
@Step { | ||||
Create a new test method for testing the delete user flow. Also create a | ||||
``ComposableArchitecture/TestStore`` for the `SyncUpDetail` feature. | ||||
|
||||
@Code(name: "SyncUpDetailTests.swift", file: TestingSyncUpDetail-02-code-0001.swift, previousFile: TestingSyncUpDetail-02-code-0001-previous.swift) | ||||
} | ||||
|
||||
@Step { | ||||
Emulate the user tapping the "Delete" button and assert that the alert state is populated. | ||||
|
||||
Run the test suite to confirm that it passes. | ||||
|
||||
@Code(name: "SyncUpDetailTests.swift", file: TestingSyncUpDetail-02-code-0002.swift) | ||||
} | ||||
|
||||
@Step { | ||||
Emulate the user confirming deletion of the sync-up by sending a deeply nested action to the | ||||
`.destination`, when it is `.presented`, in the `.alert` case, and then finally the | ||||
`.confirmButtonTapped` action. Also assert that the alert will be dismissed by setting the | ||||
`destination` state to `nil`. | ||||
|
||||
TODO: Make alert action case-pathable | ||||
|
||||
@Code(name: "SyncUpDetailTests.swift", file: TestingSyncUpDetail-02-code-0003.swift) | ||||
} | ||||
|
||||
@Step { | ||||
Run the test suite again to see that now it does _not_ pass. We have a test failure. | ||||
|
||||
@Code(name: "SyncUpDetailTests.swift", file: TestingSyncUpDetail-02-code-0004.swift) | ||||
} | ||||
|
||||
This failure is happening because we are now making use effects that emit actions, and by | ||||
default the ``ComposableArchitecture/TestStore`` forces us to assert on _everything_ happening | ||||
in the feature. This is really great because it helps us catch potential problems when new | ||||
logic and behavior is added to our features. | ||||
|
||||
The failure is letting us know that the system received an action that we did not | ||||
assert against. This is also a great failure to have because it forces us to prove that we | ||||
know how effects execute and feed their data back in the system. | ||||
|
||||
Let's fix this test failure by asserting on more of what is happening in the system. | ||||
|
||||
@Step { | ||||
Use the ``ComposableArchitecture/TestStore/receive(_:_:timeout:assert:file:line:)-dkei`` | ||||
method to assert that we expect to receive a delegate action to delete the sync-up. | ||||
|
||||
Run the test suite to see that one of the previous two test failures has now been fixed. | ||||
|
||||
> Note: We are using case key path composition in order to describe the deeply nested action | ||||
> that is being received. | ||||
|
||||
@Code(name: "SyncUpDetailTests.swift", file: TestingSyncUpDetail-02-code-0005.swift) | ||||
} | ||||
|
||||
Now that this test passes we have definitively proven that | ||||
the `.deleteSyncUp` delegate action is sent when the user confirms deletion of the sync-up. | ||||
That will communicate to the parent that it should finish deleting the sync-up _and_ it should | ||||
dismiss the presented sheet. | ||||
} | ||||
} | ||||
--> | ||||
} | ||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,6 +23,31 @@ struct MeetingView: View { | |
} | ||
} | ||
|
||
extension SyncUp { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding |
||
static let mock = Self( | ||
id: SyncUp.ID(), | ||
attendees: [ | ||
Attendee(id: Attendee.ID(), name: "Blob"), | ||
Attendee(id: Attendee.ID(), name: "Blob Jr"), | ||
Attendee(id: Attendee.ID(), name: "Blob Sr"), | ||
], | ||
duration: .seconds(60), | ||
meetings: [ | ||
Meeting( | ||
id: Meeting.ID(), | ||
date: Date().addingTimeInterval(-60 * 60 * 24 * 7), | ||
transcript: """ | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor \ | ||
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud \ | ||
… | ||
""" | ||
) | ||
], | ||
theme: .orange, | ||
title: "Design" | ||
) | ||
} | ||
|
||
stephencelis marked this conversation as resolved.
Show resolved
Hide resolved
|
||
#Preview { | ||
MeetingView(meeting: SyncUp.mock.meetings[0], syncUp: .mock) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a suggestion to throw this in, because often when I go through enough steps in a tutorial without code compiling, I end up wondering if I missed something in a step, which distracts from the tutorial itself.
However, if you don't want this change, you can revert 9d93448 where this is added