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
This commit is contained in:
2026-06-02 15:01:38 -04:00
parent ab0d4857db
commit e33ddf3002
49 changed files with 10472 additions and 421 deletions

View File

@@ -7,37 +7,63 @@
import XCTest
final class KordantUITests: XCTestCase {
/// Main entry point for Kordant UI test suite.
/// Runs on device farm across iPhone SE, 14, and 15 Pro Max simulators.
///
/// Coverage:
/// - Auth flows (login, signup, forgot password, biometric prompt)
/// - Dashboard (widgets, alerts, threat score, quick actions)
/// - Services (DarkWatch, VoicePrint, SpamShield, HomeTitle, RemoveBrokers)
/// - Settings (profile, notifications, theme, logout)
/// - Accessibility (VoiceOver labels, dynamic type, contrast)
final class KordantUITests: UITestBase {
override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
// MARK: - Launch Performance
// In UI tests it is usually best to stop immediately when a failure occurs.
continueAfterFailure = false
// In UI tests its important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
}
override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
@MainActor
func testExample() throws {
// UI tests must launch the application that they test.
let app = XCUIApplication()
app.launch()
// Use XCTAssert and related functions to verify your tests produce the correct results.
// XCUIAutomation Documentation
// https://developer.apple.com/documentation/xcuiautomation
}
@MainActor
func testLaunchPerformance() throws {
// This measures how long it takes to launch your application.
/// Measures cold launch time of the application.
/// Acceptance criteria: < 2 seconds on iPhone 12 equivalent.
func testLaunchPerformance() {
// Measure the cold launch time of the application
measure(metrics: [XCTApplicationLaunchMetric()]) {
XCUIApplication().launch()
let perfApp = XCUIApplication()
perfApp.launchArguments = ["-UITesting"]
perfApp.launchEnvironment["UITestScenario"] = UITestScenario.authenticated.rawValue
perfApp.launch()
perfApp.terminate()
}
}
// MARK: - Smoke Test
/// Quick smoke test to verify the app launches and basic UI is intact.
/// This is the fastest test in the suite and runs first.
func testSmokeTestAppLaunches() {
// App should launch to either auth or main screen depending on scenario
let appVisible = app.otherElements.firstMatch.waitForExistence(timeout: 5)
XCTAssertTrue(appVisible, "App should launch and display UI")
}
// MARK: - Cross-Cutting Navigation
/// Verify the complete tab navigation flow works
func testCompleteTabNavigationFlow() {
// Navigate through all tabs
let tabs: [TabBarItem] = [.dashboard, .services, .alerts, .settings, .account]
for tab in tabs {
navigateToTab(tab)
let navBar = app.navigationBars[tab.rawValue]
XCTAssertTrue(navBar.waitForExistence(timeout: 3),
"Navigation bar for '\(tab.rawValue)' should exist")
}
}
// MARK: - Test Report Attachment
/// Capture final test report screenshot
func testCaptureFinalState() {
navigateToTab(.dashboard)
captureScreen(name: "FinalTestState-Dashboard")
navigateToTab(.services)
captureScreen(name: "FinalTestState-Services")
}
}