generated from StanfordBDHG/SwiftPackageTemplate
-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Paul Schmiedmayer <[email protected]>
- Loading branch information
1 parent
6e9344a
commit 9f33d81
Showing
14 changed files
with
698 additions
and
351 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
// | ||
// This source file is part of the Stanford XCTHealthKit open-source project | ||
// | ||
// SPDX-FileCopyrightText: 2025 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
|
||
|
||
import XCTest | ||
|
||
|
||
/// A category in the health app | ||
public enum HealthAppCategory: String, Hashable { | ||
case activity = "Activity" | ||
case bodyMeasurements = "Body Measurements" | ||
case cycleTracking = "Cycle Tracking" | ||
case hearing = "Hearing" | ||
case heart = "Heart" | ||
case medications = "Medications" | ||
case mentalWellbeing = "Mental Wellbeing" | ||
case mobility = "Mobility" | ||
case nutrition = "Nutrition" | ||
case respiratory = "Respiratory" | ||
case sleep = "Sleep" | ||
case symptoms = "Symptoms" | ||
case vitals = "Vitals" | ||
case otherData = "Other Data" | ||
|
||
|
||
/// The category's english-language display title in the Health app's "Browse" tab. | ||
public var healthAppDisplayTitle: String { | ||
rawValue | ||
} | ||
|
||
|
||
/// Navigates in the health app to the category, and selects it. | ||
public func navigateToPage(in healthApp: XCUIApplication) throws { | ||
try healthApp.assertIsHealthApp() | ||
|
||
let categoryTitle = self.rawValue | ||
|
||
// Dismiss any sheets that may still be open | ||
if healthApp.navigationBars["Browse"].buttons["Cancel"].exists { | ||
healthApp.navigationBars["Browse"].buttons["Cancel"].tap() | ||
} | ||
|
||
let browseTabBarButton = healthApp.tabBars["Tab Bar"].buttons["Browse"] | ||
|
||
if !browseTabBarButton.waitForExistence(timeout: 2) && browseTabBarButton.isHittable { | ||
XCTFail("Unable to find 'Browse' tab bar item") | ||
return | ||
} | ||
|
||
browseTabBarButton.tap() // tap once to select the tab (if necessary) | ||
browseTabBarButton.tap() // tap again to pop all VC off the navigation stack (if necessary) | ||
|
||
// Find category: | ||
let categoryStaticTextPredicate = NSPredicate(format: "label CONTAINS[cd] %@", categoryTitle) | ||
let categoryStaticText = healthApp.staticTexts.element(matching: categoryStaticTextPredicate).firstMatch | ||
|
||
if categoryStaticText.waitForExistence(timeout: 30), !categoryStaticText.isHittable { | ||
healthApp.swipeUp() | ||
|
||
if !categoryStaticText.isHittable { | ||
healthApp.swipeUp() | ||
} | ||
} | ||
|
||
categoryStaticText.tap() | ||
|
||
// Retry ... | ||
if !healthApp.navigationBars.staticTexts[categoryTitle].waitForExistence(timeout: 20) { | ||
categoryStaticText.tap() | ||
} | ||
|
||
guard healthApp.navigationBars.staticTexts[categoryTitle].waitForExistence(timeout: 20) else { | ||
logger.notice("Failed to find category: \(healthApp.staticTexts.allElementsBoundByIndex)") | ||
throw XCTestError(.failureWhileWaiting) | ||
} | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
// | ||
// This source file is part of the XCTHealthKit open-source project | ||
// | ||
// SPDX-FileCopyrightText: 2025 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
|
||
|
||
import HealthKit | ||
import XCTest | ||
|
||
|
||
/// A Sample type within the Health app. | ||
public struct HealthAppSampleType: Hashable { | ||
public let category: HealthAppCategory | ||
public let sampleType: HKSampleType | ||
public let healthAppDisplayTitle: String | ||
|
||
/// Creates a new sample type, with the specified fields | ||
public init(category: HealthAppCategory, sampleType: HKSampleType, healthAppDisplayTitle: String) { | ||
self.category = category | ||
self.sampleType = sampleType | ||
self.healthAppDisplayTitle = healthAppDisplayTitle | ||
} | ||
} | ||
|
||
|
||
// MARK: Some Well-Known Sample Types | ||
|
||
extension HealthAppSampleType { | ||
/// The active energy subpage of the Apple Health app. Corresponds to `HKQuantityType(.activeEnergyBurned)` samples. | ||
public static let activeEnergy = Self( | ||
category: .activity, | ||
sampleType: HKQuantityType(.activeEnergyBurned), | ||
healthAppDisplayTitle: "Active Energy" | ||
) | ||
/// The resting heart rate subpage of the Apple Health app. Corresponds to `HKQuantityType(.restingHeartRate)` samples. | ||
public static let restingHeartRate = Self( | ||
category: .heart, | ||
sampleType: HKQuantityType(.restingHeartRate), | ||
healthAppDisplayTitle: "Resting Heart Rate" | ||
) | ||
/// The electrocardiograms subpage of the Apple Health app. Corresponds to `HKQuantityType.electrocardiogramType()` samples. | ||
public static let electrocardiograms = Self( | ||
category: .heart, | ||
sampleType: .electrocardiogramType(), | ||
healthAppDisplayTitle: "Electrocardiograms (ECG)" | ||
) | ||
/// The steps subpage of the Apple Health app. Corresponds to `HKQuantityType(.stepCount)` samples. | ||
public static let steps = Self( | ||
category: .activity, | ||
sampleType: HKQuantityType(.stepCount), | ||
healthAppDisplayTitle: "Steps" | ||
) | ||
/// The pushes subpage of the Apple Health app. Corresponds to `HKQuantityType(.pushCount)` samples. | ||
public static let pushes = Self( | ||
category: .activity, | ||
sampleType: HKQuantityType(.pushCount), | ||
healthAppDisplayTitle: "Pushes" | ||
) | ||
|
||
/// All currently well-known sample types. | ||
public static let all: [Self] = [ | ||
.activeEnergy, .restingHeartRate, .electrocardiograms, .steps, .pushes | ||
] | ||
} | ||
|
||
|
||
// MARK: XCTest Navigation | ||
|
||
extension HealthAppSampleType { | ||
/// Navigates the Health app to the sample type's page. | ||
public func navigateToPage(in healthApp: XCUIApplication, assumeAlreadyInCategory: Bool) throws { | ||
if !assumeAlreadyInCategory { | ||
try category.navigateToPage(in: healthApp) | ||
} | ||
|
||
let elementStaticTextPredicate = NSPredicate(format: "label CONTAINS[cd] %@", healthAppDisplayTitle) | ||
let elementStaticText = healthApp.staticTexts.element(matching: elementStaticTextPredicate).firstMatch | ||
|
||
guard elementStaticText.waitForExistence(timeout: 30), elementStaticText.isHittable else { | ||
healthApp.swipeUp() | ||
if elementStaticText.waitForExistence(timeout: 10), elementStaticText.isHittable { | ||
elementStaticText.tap() | ||
return | ||
} | ||
|
||
healthApp.swipeUp() | ||
if elementStaticText.waitForExistence(timeout: 10), elementStaticText.isHittable { | ||
elementStaticText.tap() | ||
return | ||
} | ||
|
||
logger.notice("Failed to find element in category: \(healthApp.staticTexts.allElementsBoundByIndex)") | ||
throw XCTestError(.failureWhileWaiting) | ||
} | ||
|
||
elementStaticText.tap() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// | ||
// This source file is part of the XCTHealthKit open-source project | ||
// | ||
// SPDX-FileCopyrightText: 2025 Stanford University and the project authors (see CONTRIBUTORS.md) | ||
// | ||
// SPDX-License-Identifier: MIT | ||
// | ||
|
||
import OSLog | ||
|
||
|
||
let logger = Logger(subsystem: "XCTHealthKit", category: "") |
Oops, something went wrong.