Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/scripts/validate-ui-test-shards.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ destination="$3"

jq -e '
.shards as $shards
| ($shards | length) == 4
and ($shards | map(.name) | unique | length) == 4
and ($shards | map(.shard) | unique | length) == 4
| ($shards | length) == 6
and ($shards | map(.name) | unique | length) == 6
and ($shards | map(.shard) | unique | length) == 6
and all(
$shards[];
(.name | type == "string" and length > 0)
Expand Down Expand Up @@ -91,4 +91,4 @@ if [[ "$validation_failed" == true ]]; then
exit 1
fi

echo "Validated $(wc -l < "$normalized_tests" | tr -d ' ') enabled UI tests across four shards."
echo "Validated $(wc -l < "$normalized_tests" | tr -d ' ') enabled UI tests across six shards."
48 changes: 30 additions & 18 deletions .github/ui-test-shards.json
Original file line number Diff line number Diff line change
@@ -1,42 +1,54 @@
{
"shards": [
{
"name": "Consent Review and Patch, Prompted Actions, Tasks",
"name": "Consent Review and Minor, Basic Usage",
"shard": "01",
"tests": [
"MyHeartCountsUITests/ConsentTests/testReviewConsentForms",
"MyHeartCountsUITests/ConsentTests/testConsentRenewalNewPatch",
"MyHeartCountsUITests/PromptedActionsTests",
"MyHeartCountsUITests/TaskHandlingTests",
"MyHeartCountsUITests/StudyParticipationTests"
"MyHeartCountsUITests/ConsentTests/testConsentRenewalNewMinor",
"MyHeartCountsUITests/BasicAppUsage"
]
},
{
"name": "Consent Major, Other, Timed Walk, Regression",
"name": "Consent Skip, Prompted Actions",
"shard": "02",
"tests": [
"MyHeartCountsUITests/ConsentTests/testConsentRenewalNewMajor",
"MyHeartCountsUITests/OtherTests",
"MyHeartCountsUITests/TimedWalkTestTests",
"MyHeartCountsUITests/RegressionTests"
"MyHeartCountsUITests/ConsentTests/testSkipDuringOnboardingIfAlreadySupplied",
"MyHeartCountsUITests/PromptedActionsTests"
]
},
{
"name": "Consent Skip, Health Dashboard, Scheduled",
"name": "Other, Timed Walk",
"shard": "03",
"tests": [
"MyHeartCountsUITests/ConsentTests/testSkipDuringOnboardingIfAlreadySupplied",
"MyHeartCountsUITests/HealthDashboardTests",
"MyHeartCountsUITests/ScheduledTaskTests"
"MyHeartCountsUITests/OtherTests",
"MyHeartCountsUITests/TimedWalkTestTests"
]
},
{
"name": "Consent Minor, Onboarding, Basic Usage",
"name": "Consent Patch, Onboarding",
"shard": "04",
"tests": [
"MyHeartCountsUITests/ConsentTests/testConsentRenewalNewMinor",
"MyHeartCountsUITests/OnboardingTests",
"MyHeartCountsUITests/BasicAppUsage"
"MyHeartCountsUITests/ConsentTests/testConsentRenewalNewPatch",
"MyHeartCountsUITests/OnboardingTests"
]
},
{
"name": "Consent Major, Health Dashboard, Regression, Study Participation",
"shard": "05",
"tests": [
"MyHeartCountsUITests/ConsentTests/testConsentRenewalNewMajor",
"MyHeartCountsUITests/HealthDashboardTests",
"MyHeartCountsUITests/RegressionTests",
"MyHeartCountsUITests/StudyParticipationTests"
]
},
{
"name": "Scheduled, Tasks",
"shard": "06",
"tests": [
"MyHeartCountsUITests/ScheduledTaskTests",
"MyHeartCountsUITests/TaskHandlingTests"
]
}
]
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ jobs:
contents: read
strategy:
fail-fast: false
max-parallel: 4
max-parallel: 6
matrix: ${{ fromJSON(needs.mhc_app_ui_test_build.outputs.matrix) }}
steps:
- uses: actions/checkout@v7
Expand Down
77 changes: 36 additions & 41 deletions MyHeartCounts/Account/AccountSheet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
@State private var viewState: ViewState = .idle
@State private var isInSetup = false
@State private var isPresentingFeedbackSheet = false
@State private var activeAccountAction: AccountAction?

Check warning on line 40 in MyHeartCounts/Account/AccountSheet.swift

View workflow job for this annotation

GitHub Actions / Periphery / Run Periphery

unused

Unused property 'activeAccountAction'

@AccountFeatureFlagQuery(.isDebugModeEnabled)
private var debugModeEnabled
Expand Down Expand Up @@ -77,19 +77,7 @@
}
.accessibilityIdentifier("MHC:AccountSheet")
.viewStateAlert(state: $viewState)
.accountActionAlert(
currentAction: $activeAccountAction,
viewState: $viewState,
dismiss: dismiss,
operation: { action in
switch action {
case .logOut:
try await account.accountService.logout()
case .withdraw:
try await withdrawFromStudy()
}
}
)
.accountActionAlert(currentAction: $activeAccountAction, perform: performAccountAction)
}

@ViewBuilder private var accountSheetExtraContent: some View {
Expand Down Expand Up @@ -139,6 +127,7 @@
}
}
AccountMgmtSection(currentAction: $activeAccountAction)
.disabled(viewState == .processing)
}

private var isProcessingHealthData: Bool {
Expand Down Expand Up @@ -243,6 +232,28 @@
.call([:])
try await account.accountService.logout()
}

/// Runs in its own `Task`, because the action needs to outlive the alert that triggered it:
/// the alert dismisses itself as soon as its button is tapped.
private func performAccountAction(_ action: AccountAction) {
viewState = .processing
Task {
do {
switch action {
case .logOut:
try await account.accountService.logout()
case .withdraw:
try await withdrawFromStudy()
}
viewState = .idle
dismiss()
} catch is CancellationError {
viewState = .idle
} catch {
viewState = .error(AnyLocalizedError(error: error, defaultErrorDescription: action.defaultErrorDescription))
}
}
}
}


Expand Down Expand Up @@ -455,7 +466,7 @@
}
}

var confirmationTitle: LocalizedStringResource {

Check warning on line 469 in MyHeartCounts/Account/AccountSheet.swift

View workflow job for this annotation

GitHub Actions / Periphery / Run Periphery

unused

Unused property 'confirmationTitle'
switch self {
case .logOut:
"Log Out"
Expand All @@ -472,11 +483,20 @@
"Are you sure you want to withdraw from the My Heart Counts study?\nYou can re-enroll later if you choose."
}
}

var defaultErrorDescription: LocalizedStringResource {
switch self {
case .logOut:
"Failed to log out"
case .withdraw:
"Failed to withdraw from study"
}
}
}


extension AccountOverviewOperationLabels {
fileprivate static let withdrawFromStudy = Self(

Check warning on line 499 in MyHeartCounts/Account/AccountSheet.swift

View workflow job for this annotation

GitHub Actions / Periphery / Run Periphery

unused

Unused property 'withdrawFromStudy'
formButton: "Withdraw from Study",
confirmationAlertTitle: "Withdraw from Study",
confirmationAlertMessage: "Are you sure you want to withdraw from the My Heart Counts study?\nYou can re-enroll later if you choose.",
Expand All @@ -486,41 +506,16 @@


extension View {
@ViewBuilder
fileprivate func accountActionAlert(
currentAction: Binding<AccountSheet.AccountAction?>,
viewState: Binding<ViewState>,
dismiss: DismissAction,
operation: @MainActor @escaping (_ action: AccountSheet.AccountAction) async throws -> Void
perform: @MainActor @escaping (_ action: AccountSheet.AccountAction) -> Void
) -> some View {
self.alert(currentAction.wrappedValue?.title ?? "", item: currentAction) { action in
// Note how the below AsyncButton (in the HStack) uses the same `destructiveViewState`.
// Due to SwiftUI behavior, the alert will be dismissed immediately. We use the AsyncButton here still
// to manage our async task and setting the ViewState.
AsyncButton(role: .destructive, state: viewState) {
do {
try await operation(action)
} catch {
if error is CancellationError {
return
}
throw error
}
dismiss()
Button(role: .destructive) {
perform(action)
} label: {
Text(action.shortTitle)
}
.environment(\.defaultErrorDescription, { () -> LocalizedStringResource? in
switch currentAction.wrappedValue {
case .logOut:
"Failed to log out"
case .withdraw:
"Failed to withdraw from study"
case nil:
nil
}
}())

Button(role: .cancel, action: {}) {
Text("Cancel")
}
Expand Down
4 changes: 2 additions & 2 deletions MyHeartCountsUITests/BasicAppUsage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ final class BasicAppUsage: MHCTestCase, @unchecked Sendable {
try launchAppAndEnrollIntoStudy()
openAccountSheet()
app.swipeUp()
app.buttons["Logout"].tap()
app.alerts["Are you sure you want to logout?"].buttons["Logout"].tap()
app.buttons["Log Out"].tap()
app.alerts["Log Out"].buttons["Log Out"].tap()
XCTAssert(app.staticTexts["Welcome to the My Heart Counts\nCardiovascular Health Study"].waitForExistence(timeout: 20))
}

Expand Down
Loading