TeraAccessibilityUITestSurface.swift (5969B)
1 #if DEBUG 2 import RadrootsKit 3 import SwiftUI 4 5 /// Isolated presentation qualification: real stores and SQLite, no credentials 6 /// or external relays. The photo fixture cannot confirm durability or upload bytes. 7 struct TeraAccessibilityUITestSurface: View { 8 @StateObject private var fixture = TeraAccessibilityFixture() 9 @Environment(\.accessibilityReduceMotion) private var reduceMotion 10 @Environment(\.dynamicTypeSize) private var textSize 11 private let scenario = ProcessInfo.processInfo.environment["TERA_IOS_UI_TEST_ACCESSIBILITY"] 12 13 var body: some View { 14 Group { 15 if scenario == "failure" || scenario == "identity" { 16 RuntimeStatusView(phase: scenario == "identity" ? .identityRequired : .failed(.local( 17 operation: "fixture", code: "ios.fixture.unavailable", safeMessage: "Local state is unavailable." 18 )), retry: { fixture.retried = true }, createIdentity: {}, importIdentity: { _ in }, 19 unlockIdentity: {}, recoverIdentity: {}, applyConfigurationReconfiguration: {}) 20 .overlay(alignment: .bottom) { 21 if fixture.retried { 22 Text("Local state checked").accessibilityIdentifier("tera.test.accessibility.retried") 23 } 24 } 25 } else if let stores = fixture.stores, let snapshot = fixture.snapshot { 26 TeraRootShell(snapshot: snapshot, stores: stores) 27 } else { 28 Text(fixture.failure ?? "Preparing isolated accessibility fixture") 29 } 30 } 31 .accessibilityElement(children: .contain) 32 .accessibilityIdentifier("tera.test.accessibility.root") 33 .accessibilityValue(Text(verbatim: "text=\(textSize); reduceMotion=\(reduceMotion)")) 34 .task { await fixture.start() } 35 .overlay { 36 if scenario == "save-error", !fixture.hasPreparedSaveError { 37 Button("Prepare unconfirmed Save") { 38 Task { await fixture.prepareSaveError() } 39 } 40 .buttonStyle(.borderedProminent) 41 } 42 } 43 } 44 } 45 46 @MainActor 47 private final class TeraAccessibilityFixture: ObservableObject { 48 @Published var stores: TeraProductStores? 49 @Published var snapshot: TeraRuntimeSnapshot? 50 @Published var failure: String? 51 @Published var retried = false 52 @Published var hasPreparedSaveError = false 53 private let client = TeraRuntimeClient.production() 54 55 func start() async { 56 guard stores == nil, failure == nil else { return } 57 do { 58 let root = FileManager.default.temporaryDirectory.appendingPathComponent("tera-accessibility-" + UUID().uuidString) 59 try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true) 60 let publicKey = "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798" 61 let roots = try RadrootsAppleFileRoots(appIdentifier: "test.tera.accessibility", dataRoot: root, 62 cacheRoot: root, temporaryRoot: root) 63 let mobileStore = try RadrootsAppleMobileStore.prepare(roots: roots, publicKeyHex: publicKey, 64 protectedDataAvailability: .available) 65 let configuration = TeraRuntimeLaunchConfiguration( 66 applicationSupportDirectory: mobileStore.applicationSupportDirectory.path, 67 publicKeyHex: publicKey, 68 sourceGenerationHex: String(repeating: "04", count: 32), sourceGenerationCreatedAtUnixMilliseconds: 1_800_000_000_000, 69 protectedData: .available, networkProfile: .simulator, writableRelays: ["ws://127.0.0.1:19999"], blossom: nil, 70 app: .init(bundleIdentifier: "test.tera.accessibility", version: "1", buildNumber: "1", buildSHA: nil), 71 signerGeneration: "accessibility-fixture", signer: TeraAccessibilitySigner(), adoptBootstrapSettings: false 72 ) 73 let snapshot = try await client.start(configuration: configuration) 74 let stores = TeraProductStores(runtimeClient: client, addMedia: TeraAccessibilityMedia()) 75 stores.configure(snapshot: snapshot) 76 await stores.resume() 77 if let label = ProcessInfo.processInfo.environment["TERA_IOS_UI_TEST_FORM"], 78 let type = TeraAddCommandType.allCases.first(where: { $0.label == label }) 79 { 80 stores.add.selectType(type) 81 } 82 self.snapshot = snapshot 83 self.stores = stores 84 } catch { 85 if case let TeraRuntimeClientError.startup(report) = error { 86 failure = "Accessibility fixture failed to start: " + report.code 87 } else { 88 failure = "Accessibility fixture failed to start." 89 } 90 } 91 } 92 93 func prepareSaveError() async { 94 guard let stores, !hasPreparedSaveError else { return } 95 await stores.add.importPhotos() 96 await stores.add.save() 97 hasPreparedSaveError = true 98 } 99 } 100 101 private struct TeraAccessibilitySigner: TeraRuntimeSigner { 102 func availability() async -> TeraRuntimeSignerAvailability { 103 .unavailable 104 } 105 106 func sign(_: TeraRuntimeSigningRequest) async -> TeraRuntimeSigningOutcome { 107 .unavailable 108 } 109 } 110 111 private struct TeraAccessibilityMedia: TeraAddMediaHandling { 112 func support() async throws -> TeraAddMediaSupport { 113 .init(library: true, camera: false) 114 } 115 116 func importImages(limit: Int) async throws -> [TeraPreparedMedia] { 117 guard limit > 0 else { return [] } 118 return [.init(opaqueReference: "media:" + String(repeating: "0", count: 64), remoteURL: nil, 119 sha256: String(repeating: "0", count: 64), mediaType: "image/png", byteSize: 4, 120 width: 2, height: 2, alt: "", preparedAtUnixSeconds: 1_800_000_000)] 121 } 122 123 func captureImage() async throws -> TeraPreparedMedia { 124 throw TeraComposerAcknowledgment.unconfirmed 125 } 126 127 func open(_: [TeraPreparedMedia]) async throws -> TeraOpenedMedia { 128 throw TeraComposerAcknowledgment.unconfirmed 129 } 130 } 131 #endif