Replace the custom themed presentation with the bare native iOS design language across a three-tab TabView (Home / Rules / Settings): - MainTabView hosts the enforcement lifecycle (refresh loop, rule-change and scene-active reconcile) so it runs regardless of the selected tab - HomeView: "Currently Blocking" + "Usage" sections (replaces AppsHomeView) - RulesListView: rules grouped into Schedule / Time Limit / Open Limit - SettingsView: Uninstall Protection toggle + Manage App Lists - AppListLibraryView / ManageAppListsView: shared App List management - AppSettings: app-group-backed settings store Uninstall Protection: while enabled and any Hard Mode rule is actively blocking, deny device app-removal via a dedicated ManagedSettingsStore (RulePolicy.shouldDenyAppRemoval -> RuleEnforcer -> ShieldController). Slim AppListPickerSheet to the picker role; drop AppsHomeView and the custom Theme/HoldToCommitButton/RuleCardView chrome. Update spec section 6 and the unit/UI test suites accordingly.
59 lines
2.0 KiB
Swift
59 lines
2.0 KiB
Swift
//
|
|
// UITestSupport.swift
|
|
// OpenAppLockUITests
|
|
//
|
|
|
|
import XCTest
|
|
|
|
extension XCUIApplication {
|
|
/// Launches the app in UI-testing mode: in-memory storage, mocked Screen
|
|
/// Time authorization, and no shield side effects.
|
|
static func launchOpenAppLock(
|
|
onboardingCompleted: Bool = true,
|
|
seedScenario: String? = nil
|
|
) -> XCUIApplication {
|
|
let app = XCUIApplication()
|
|
var arguments = ["-ui-testing"]
|
|
arguments.append(onboardingCompleted ? "-onboarding-completed" : "-onboarding-required")
|
|
if let seedScenario {
|
|
arguments.append("-seed-scenario=\(seedScenario)")
|
|
}
|
|
app.launchArguments = arguments
|
|
app.launch()
|
|
return app
|
|
}
|
|
}
|
|
|
|
extension XCUIApplication {
|
|
/// Finds an element by accessibility identifier regardless of how SwiftUI
|
|
/// exposes it (Other, StaticText, Button, …).
|
|
func element(_ identifier: String) -> XCUIElement {
|
|
descendants(matching: .any).matching(identifier: identifier).firstMatch
|
|
}
|
|
}
|
|
|
|
extension XCUIApplication {
|
|
/// Switches to the Home tab (Currently Blocking + Usage). Home is the
|
|
/// default selection, so most Home-tab tests don't need to call this.
|
|
func goToHomeTab() { tabBars.buttons["Home"].waitToAppear().tap() }
|
|
/// Switches to the Rules tab (the rule list + New Rule button).
|
|
func goToRulesTab() { tabBars.buttons["Rules"].waitToAppear().tap() }
|
|
/// Switches to the Settings tab (Uninstall Protection + Manage App Lists).
|
|
func goToSettingsTab() { tabBars.buttons["Settings"].waitToAppear().tap() }
|
|
}
|
|
|
|
extension XCUIElement {
|
|
/// Asserts the element appears within the timeout, then returns it.
|
|
@discardableResult
|
|
func waitToAppear(
|
|
timeout: TimeInterval = 5, file: StaticString = #filePath, line: UInt = #line
|
|
) -> XCUIElement {
|
|
XCTAssertTrue(
|
|
waitForExistence(timeout: timeout),
|
|
"Expected \(self) to exist within \(timeout)s",
|
|
file: file, line: line
|
|
)
|
|
return self
|
|
}
|
|
}
|