Remediate all P0-S priority findings from cross-platform architecture audit: - Harden token storage with EncryptedSharedPreferences (Android) and Keychain (iOS) - Add SSL pinning and certificate validation to API clients - Fix subscription cache race conditions and add thread-safe access - Add input validation for document uploads and file type restrictions - Refactor DocumentApi to use proper multipart upload flow - Add rate limiting awareness and retry logic to API layer - Harden subscription tier enforcement in SubscriptionHelper - Add biometric prompt for sensitive actions (Login, Onboarding) - Fix notification permission handling and device registration - Add UI test infrastructure (page objects, fixtures, smoke tests) - Add CI workflow for mobile builds Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
121 lines
4.2 KiB
Swift
121 lines
4.2 KiB
Swift
import XCTest
|
|
|
|
/// Smoke tests - run on every PR. Must complete in <2 minutes.
|
|
///
|
|
/// Tests that the app launches successfully, the auth screen renders correctly,
|
|
/// and core navigation is functional. These are the minimum-viability tests
|
|
/// that must pass before any PR can merge.
|
|
final class SmokeTests: XCTestCase {
|
|
var app: XCUIApplication!
|
|
|
|
override func setUp() {
|
|
super.setUp()
|
|
continueAfterFailure = false
|
|
app = TestLaunchConfig.launchApp()
|
|
}
|
|
|
|
override func tearDown() {
|
|
app = nil
|
|
super.tearDown()
|
|
}
|
|
|
|
// MARK: - App Launch
|
|
|
|
func testAppLaunches() {
|
|
// App should show either login screen or main tab view
|
|
let loginScreen = LoginScreen(app: app)
|
|
let mainScreen = MainTabScreen(app: app)
|
|
|
|
let loginAppeared = loginScreen.emailField.waitForExistence(timeout: 15)
|
|
let mainAppeared = mainScreen.residencesTab.waitForExistence(timeout: 5)
|
|
|
|
XCTAssertTrue(loginAppeared || mainAppeared, "App should show login or main screen on launch")
|
|
}
|
|
|
|
// MARK: - Login Screen Elements
|
|
|
|
func testLoginScreenElements() {
|
|
let login = LoginScreen(app: app)
|
|
guard login.emailField.waitForExistence(timeout: 15) else {
|
|
// Already logged in, skip this test
|
|
return
|
|
}
|
|
|
|
XCTAssertTrue(login.emailField.exists, "Email field should exist")
|
|
XCTAssertTrue(login.passwordField.exists, "Password field should exist")
|
|
XCTAssertTrue(login.loginButton.exists, "Login button should exist")
|
|
}
|
|
|
|
// MARK: - Login Flow
|
|
|
|
func testLoginWithExistingCredentials() {
|
|
let login = LoginScreen(app: app)
|
|
guard login.emailField.waitForExistence(timeout: 15) else {
|
|
// Already on main screen - verify tabs
|
|
let main = MainTabScreen(app: app)
|
|
XCTAssertTrue(main.isDisplayed, "Main tabs should be visible")
|
|
return
|
|
}
|
|
|
|
// Login with the known test user
|
|
let user = TestFixtures.TestUser.existing
|
|
login.login(email: user.email, password: user.password)
|
|
|
|
let main = MainTabScreen(app: app)
|
|
XCTAssertTrue(main.residencesTab.waitForExistence(timeout: 15), "Should navigate to main screen after login")
|
|
}
|
|
|
|
// MARK: - Tab Navigation
|
|
|
|
func testMainTabsExistAfterLogin() {
|
|
let login = LoginScreen(app: app)
|
|
if login.emailField.waitForExistence(timeout: 15) {
|
|
// Need to login first
|
|
let user = TestFixtures.TestUser.existing
|
|
login.login(email: user.email, password: user.password)
|
|
}
|
|
|
|
let main = MainTabScreen(app: app)
|
|
guard main.residencesTab.waitForExistence(timeout: 15) else {
|
|
XCTFail("Main screen did not appear")
|
|
return
|
|
}
|
|
|
|
XCTAssertTrue(main.residencesTab.exists, "Residences tab should exist")
|
|
XCTAssertTrue(main.tasksTab.exists, "Tasks tab should exist")
|
|
XCTAssertTrue(main.contractorsTab.exists, "Contractors tab should exist")
|
|
XCTAssertTrue(main.documentsTab.exists, "Documents tab should exist")
|
|
XCTAssertTrue(main.profileTab.exists, "Profile tab should exist")
|
|
}
|
|
|
|
func testTabNavigation() {
|
|
let login = LoginScreen(app: app)
|
|
if login.emailField.waitForExistence(timeout: 15) {
|
|
let user = TestFixtures.TestUser.existing
|
|
login.login(email: user.email, password: user.password)
|
|
}
|
|
|
|
let main = MainTabScreen(app: app)
|
|
guard main.residencesTab.waitForExistence(timeout: 15) else {
|
|
XCTFail("Main screen did not appear")
|
|
return
|
|
}
|
|
|
|
// Navigate through each tab and verify selection
|
|
main.goToTasks()
|
|
XCTAssertTrue(main.tasksTab.isSelected, "Tasks tab should be selected")
|
|
|
|
main.goToContractors()
|
|
XCTAssertTrue(main.contractorsTab.isSelected, "Contractors tab should be selected")
|
|
|
|
main.goToDocuments()
|
|
XCTAssertTrue(main.documentsTab.isSelected, "Documents tab should be selected")
|
|
|
|
main.goToProfile()
|
|
XCTAssertTrue(main.profileTab.isSelected, "Profile tab should be selected")
|
|
|
|
main.goToResidences()
|
|
XCTAssertTrue(main.residencesTab.isSelected, "Residences tab should be selected")
|
|
}
|
|
}
|