Files
Kordant/iOS/KordantUITests/ServiceUITests.swift
Michael Freno e33ddf3002 feat: complete Tasks 21-28 — backend integration, security hardening, UI tests & CI
- Add Apple Sign-In backend (JWKS verification, account linking, session management)
- Implement push notification deep linking with NotificationDeepLinkRouter
- Add jailbreak detection, runtime integrity monitoring, secure enclave service
- Implement OAuth social login, token refresh, and secure logout flows
- Add image caching (memory/disk), optimizer, upload queue, async semaphore
- Implement notification analytics, type preferences, and category setup
- Expand UI test suite with UITestBase, accessibility, auth flow, performance tests
- Add CI pipeline for iOS UI tests (3 device sizes) and performance benchmarks
- Restructure Xcode project to manual groups with KordantWidgets target
- Add SwiftLint, Swift Collections/Algorithms/GoogleSignIn dependencies
- Update project.yml for XcodeGen with new targets and configurations
2026-06-02 15:01:38 -04:00

188 lines
6.7 KiB
Swift

import XCTest
/// UI tests for service screens: DarkWatch, VoicePrint, SpamShield, HomeTitle, RemoveBrokers.
final class ServiceUITests: UITestBase {
// MARK: - Helpers
/// Relaunch the app with a specific scenario
private func relaunch(scenario: UITestScenario) {
app.terminate()
app = XCUIApplication()
app.launchArguments = ["-UITesting"]
app.launchEnvironment["UITestScenario"] = scenario.rawValue
app.launch()
}
/// Navigate to the Services tab
private func navigateToServicesList() {
navigateToTab(.services)
XCTAssertTrue(app.navigationBars["Services"].waitForExistence(timeout: 5),
"Services list should load")
}
/// Tap a service row by its name in the services list
private func tapService(_ name: String) {
app.buttons[name].tap()
}
// MARK: - DarkWatch
/// Verify DarkWatch screen loads with watchlist items
func testDarkWatchWatchlistLoads() {
relaunch(scenario: .darkWatchPopulated)
navigateToServicesList()
tapService("DarkWatch")
XCTAssertTrue(app.navigationBars["DarkWatch"].waitForExistence(timeout: 5),
"DarkWatch screen should load")
// Verify watchlist items are shown
let watchlistItem = app.staticTexts["test@kordant.com"]
XCTAssertTrue(watchlistItem.waitForExistence(timeout: 3),
"Watchlist item should be visible")
captureScreen(name: "DarkWatchWatchlist")
}
/// Verify adding a watchlist item opens the add sheet
func testDarkWatchAddWatchlistItem() {
relaunch(scenario: .darkWatchPopulated)
navigateToServicesList()
tapService("DarkWatch")
XCTAssertTrue(app.navigationBars["DarkWatch"].waitForExistence(timeout: 5))
// Tap the add button in the toolbar
let addButton = app.navigationBars["DarkWatch"].buttons.firstMatch
guard addButton.waitForExistence(timeout: 3) else {
XCTFail("Add button in DarkWatch navigation bar not found")
return
}
addButton.tap()
// Wait for add sheet to appear and fill in the form
let termField = app.textFields.firstMatch
guard termField.waitForExistence(timeout: 3) else {
XCTFail("Term field in add sheet not found")
return
}
termField.tap()
termField.typeText("new-item@test.com")
// Tap the Add confirmation button
let confirmAdd = app.buttons["Add"]
if confirmAdd.waitForExistence(timeout: 2) {
confirmAdd.tap()
}
// Verify sheet dismisses
let sheetGone = termField.waitForExistence(timeout: 2) == false
XCTAssertTrue(sheetGone, "Sheet should dismiss after adding item")
captureScreen(name: "DarkWatchAddItem")
}
// MARK: - VoicePrint
/// Verify VoicePrint screen loads with enrollment information
func testVoicePrintEnrollmentScreen() {
relaunch(scenario: .voicePrintPopulated)
navigateToServicesList()
tapService("VoicePrint")
XCTAssertTrue(app.navigationBars["VoicePrint"].waitForExistence(timeout: 5),
"VoicePrint screen should load")
// Verify enrollment section is shown
let enrollmentSection = app.staticTexts["Voice Enrollments"]
XCTAssertTrue(enrollmentSection.waitForExistence(timeout: 3),
"Voice Enrollments section should be visible")
captureScreen(name: "VoicePrintEnrollments")
}
// MARK: - SpamShield
/// Verify SpamShield screen loads with rules
func testSpamShieldRulesList() {
relaunch(scenario: .spamShieldPopulated)
navigateToServicesList()
tapService("SpamShield")
XCTAssertTrue(app.navigationBars["SpamShield"].waitForExistence(timeout: 5),
"SpamShield screen should load")
// Verify rules are visible
let rulePattern = app.staticTexts["+1 (555) 999-9999"]
XCTAssertTrue(rulePattern.waitForExistence(timeout: 3),
"Spam rule pattern should be visible")
captureScreen(name: "SpamShieldRules")
}
// MARK: - HomeTitle
/// Verify HomeTitle screen loads with property list
func testHomeTitlePropertyList() {
relaunch(scenario: .homeTitlePopulated)
navigateToServicesList()
tapService("HomeTitle")
XCTAssertTrue(app.navigationBars["HomeTitle"].waitForExistence(timeout: 5),
"HomeTitle screen should load")
// Verify properties are visible
let propertyAddress = app.staticTexts["123 Main St"]
XCTAssertTrue(propertyAddress.waitForExistence(timeout: 3),
"Property address should be visible")
captureScreen(name: "HomeTitleProperties")
}
// MARK: - RemoveBrokers
/// Verify RemoveBrokers screen loads with broker listings and removal requests
func testRemoveBrokersListingsShown() {
relaunch(scenario: .removeBrokersPopulated)
navigateToServicesList()
tapService("Remove Brokers")
XCTAssertTrue(app.navigationBars["Remove Brokers"].waitForExistence(timeout: 5),
"Remove Brokers screen should load")
// Verify broker registry section
let brokerSection = app.staticTexts["Broker Registry"]
XCTAssertTrue(brokerSection.waitForExistence(timeout: 3),
"Broker Registry section should be visible")
// Verify broker names are shown
let brokerName = app.staticTexts["DataAggregator Inc"]
XCTAssertTrue(brokerName.waitForExistence(timeout: 3),
"Broker listing should be visible")
captureScreen(name: "RemoveBrokersListings")
}
// MARK: - Back Navigation
/// Verify back navigation works from a service to the services list
func testBackNavigationFromService() {
navigateToServicesList()
tapService("DarkWatch")
XCTAssertTrue(app.navigationBars["DarkWatch"].waitForExistence(timeout: 5))
// Tap back button
app.navigationBars["DarkWatch"].buttons["Services"].tap()
XCTAssertTrue(app.navigationBars["Services"].waitForExistence(timeout: 3),
"Should navigate back to Services list")
}
// MARK: - Service Row Accessibility
/// Verify service rows exist and are tappable
func testAllServiceRowsAreVisible() {
navigateToServicesList()
let serviceNames = ["DarkWatch", "VoicePrint", "SpamShield", "HomeTitle", "Remove Brokers"]
for name in serviceNames {
let row = app.buttons[name]
XCTAssertTrue(row.waitForExistence(timeout: 3),
"Service row '\(name)' should be visible")
}
}
}