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:
129
iOS/KordantUITests/DashboardUITests.swift
Normal file
129
iOS/KordantUITests/DashboardUITests.swift
Normal file
@@ -0,0 +1,129 @@
|
||||
import XCTest
|
||||
|
||||
/// UI tests for the dashboard: widgets, alerts, threat score, navigation.
|
||||
final class DashboardUITests: UITestBase {
|
||||
override class var scenario: UITestScenario { .populatedDashboard }
|
||||
|
||||
// MARK: - Dashboard Loads with Widgets
|
||||
|
||||
/// Verify the dashboard loads with all widget sections
|
||||
func testDashboardLoadsWithWidgets() {
|
||||
// Navigate to Dashboard tab (should be default)
|
||||
navigateToTab(.dashboard)
|
||||
|
||||
// Verify key dashboard elements exist
|
||||
XCTAssertTrue(app.navigationBars["Dashboard"].waitForExistence(timeout: 5),
|
||||
"Dashboard navigation bar should exist")
|
||||
|
||||
// Threat score section
|
||||
let threatScoreLabel = text("Threat Score")
|
||||
XCTAssertTrue(threatScoreLabel.waitForExistence(timeout: 3),
|
||||
"Threat Score label should be visible")
|
||||
XCTAssertTrue(text("Alerts").exists, "Alerts stat badge should be visible")
|
||||
XCTAssertTrue(text("Exposures").exists, "Exposures stat badge should be visible")
|
||||
XCTAssertTrue(text("Watched").exists, "Watched stat badge should be visible")
|
||||
|
||||
// Recent Alerts section
|
||||
XCTAssertTrue(text("Recent Alerts").waitForExistence(timeout: 3),
|
||||
"Recent Alerts section should be visible")
|
||||
|
||||
// Services section
|
||||
XCTAssertTrue(text("Services").exists, "Services section should be visible")
|
||||
|
||||
// Quick Actions section
|
||||
XCTAssertTrue(text("Quick Actions").exists, "Quick Actions section should be visible")
|
||||
|
||||
captureScreen(name: "DashboardWithWidgets")
|
||||
}
|
||||
|
||||
// MARK: - Alert Tap Opens Detail View
|
||||
|
||||
/// Verify tapping an alert navigates to the detail view
|
||||
func testTapAlertOpensDetailView() {
|
||||
navigateToTab(.dashboard)
|
||||
|
||||
// Wait for alerts to load
|
||||
let alertTitle = text("Data Exposure Detected")
|
||||
guard alertTitle.waitForExistence(timeout: 5) else {
|
||||
XCTFail("Expected alert 'Data Exposure Detected' not found")
|
||||
return
|
||||
}
|
||||
|
||||
// Tap the alert (it's inside a NavigationLink)
|
||||
alertTitle.tap()
|
||||
|
||||
// Should navigate to alert detail (the navigation bar title changes)
|
||||
let detailExists = app.navigationBars.element(boundBy: 0).waitForExistence(timeout: 3)
|
||||
XCTAssertTrue(detailExists, "Alert detail view should open")
|
||||
|
||||
captureScreen(name: "AlertDetail")
|
||||
}
|
||||
|
||||
// MARK: - Threat Score Display
|
||||
|
||||
/// Verify threat score displays and updates correctly
|
||||
func testThreatScoreUpdatesCorrectly() {
|
||||
navigateToTab(.dashboard)
|
||||
|
||||
// With populatedDashboard scenario, we have mock alerts and exposures
|
||||
// The threat score should be visible
|
||||
let scoreExists = app.staticTexts.matching(NSPredicate(format: "label MATCHES '\\\\d+'")).element.exists
|
||||
XCTAssertTrue(scoreExists || app.staticTexts["0"].exists || app.staticTexts["100"].exists,
|
||||
"Threat score number should be visible")
|
||||
}
|
||||
|
||||
// MARK: - Services Section on Dashboard
|
||||
|
||||
/// Verify the services grid is visible on dashboard
|
||||
func testDashboardShowsServiceSummaries() {
|
||||
navigateToTab(.dashboard)
|
||||
|
||||
// The services grid should show all 5 service names
|
||||
let serviceNames = ["DarkWatch", "VoicePrint", "SpamShield", "HomeTitle", "RemoveBrokers"]
|
||||
for name in serviceNames {
|
||||
XCTAssertTrue(text(name).exists, "Service '\(name)' should be visible on dashboard")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Quick Actions
|
||||
|
||||
/// Verify quick action buttons are present
|
||||
func testQuickActionsAreVisible() {
|
||||
navigateToTab(.dashboard)
|
||||
|
||||
// Scroll down to make sure Quick Actions are visible
|
||||
scrollDown()
|
||||
|
||||
let quickActions = ["Scan", "Alerts", "Profile", "Settings"]
|
||||
for action in quickActions {
|
||||
XCTAssertTrue(text(action).exists, "Quick action '\(action)' should be visible")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Dashboard Tab Navigation
|
||||
|
||||
/// Verify tab bar navigation works from dashboard
|
||||
func testTabNavigationFromDashboard() {
|
||||
navigateToTab(.dashboard)
|
||||
|
||||
// Navigate to Services tab
|
||||
navigateToTab(.services)
|
||||
XCTAssertTrue(app.navigationBars["Services"].waitForExistence(timeout: 3),
|
||||
"Services screen should appear")
|
||||
|
||||
// Navigate back to Dashboard
|
||||
navigateToTab(.dashboard)
|
||||
XCTAssertTrue(app.navigationBars["Dashboard"].waitForExistence(timeout: 3),
|
||||
"Dashboard should appear after switching back")
|
||||
|
||||
// Navigate to Alerts tab
|
||||
navigateToTab(.alerts)
|
||||
XCTAssertTrue(app.navigationBars["Alerts"].waitForExistence(timeout: 3),
|
||||
"Alerts screen should appear")
|
||||
|
||||
// Navigate to Settings tab
|
||||
navigateToTab(.settings)
|
||||
XCTAssertTrue(app.navigationBars["Settings"].waitForExistence(timeout: 3),
|
||||
"Settings screen should appear")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user