TeraSubmissionQualificationSupport.swift (7555B)
1 import XCTest 2 3 extension TeraRemoteQualificationUITests { 4 @MainActor 5 func beginNewDraft(_ action: XCUIElement) -> Bool { 6 let ready = NSPredicate { _, _ in 7 action.exists && action.isEnabled && action.isHittable 8 } 9 guard XCTWaiter.wait(for: [XCTNSPredicateExpectation(predicate: ready, object: action)], timeout: 10) == .completed else { return false } 10 action.tap() 11 // New may first preserve the old editor through an asynchronous durable 12 // save. Editing before it settles intentionally cancels that replacement. 13 return XCTWaiter.wait(for: [XCTNSPredicateExpectation(predicate: ready, object: action)], timeout: 60) == .completed 14 } 15 16 @MainActor 17 func enterExactText(_ field: XCUIElement, value: String) { 18 field.typeText(value) 19 XCTAssertEqual(field.value as? String, value, "The fresh form must contain only the supplied field value") 20 } 21 22 @MainActor 23 func openAdd(_ app: XCUIApplication) -> XCUIElement? { 24 let add = app.tabBars.buttons["Add"] 25 guard add.waitForExistence(timeout: 10) else { return nil } 26 let root = app.descendants(matching: .any)["radroots.add.root"] 27 let type = app.descendants(matching: .any)["radroots.add.type"] 28 for _ in 0 ..< 3 { 29 add.tap() 30 guard root.waitForExistence(timeout: 10) else { continue } 31 // Public disclosure precedes the picker in the lazy native Form. 32 // Reveal its actual row before requiring existence and interaction. 33 scrollTo(app, element: type) 34 if type.waitForExistence(timeout: 10), type.isHittable { 35 return type 36 } 37 } 38 return nil 39 } 40 41 @MainActor 42 func recordAccessibilityIssue(_ issue: XCUIAccessibilityAuditIssue) { 43 let description = [ 44 "Audit type: \(issue.auditType.rawValue)", 45 issue.compactDescription, 46 issue.detailedDescription, 47 issue.element?.debugDescription ?? "No associated accessibility element", 48 ].joined(separator: "\n") 49 let attachment = XCTAttachment(string: description) 50 attachment.name = "Accessibility issue details" 51 attachment.lifetime = .keepAlways 52 add(attachment) 53 } 54 55 @MainActor 56 func assertDraftOutboxContainsAtLeast(_ app: XCUIApplication, count: Int) { 57 let sheet = app.descendants(matching: .any)["radroots.add.drafts.sheet"] 58 let list = sheet.descendants(matching: .collectionView).firstMatch 59 guard list.waitForExistence(timeout: 10) else { 60 return XCTFail("The visible Drafts list was unavailable") 61 } 62 63 for _ in 0 ..< 8 { 64 list.swipeDown() 65 } 66 var identifiers = Set<String>() 67 let rows = app.descendants(matching: .any).matching( 68 NSPredicate(format: "identifier BEGINSWITH 'tera.add.submission.' AND NOT identifier CONTAINS '.progress'") 69 ) 70 for _ in 0 ..< 12 where identifiers.count < count { 71 for index in 0 ..< rows.count { 72 let identifier = rows.element(boundBy: index).identifier 73 if identifier.range(of: "^tera\\.add\\.submission\\.[0-9a-f]{32}$", options: .regularExpression) != nil { 74 identifiers.insert(identifier) 75 } 76 } 77 if identifiers.count < count { 78 list.swipeUp() 79 } 80 } 81 XCTAssertGreaterThanOrEqual( 82 identifiers.count, 83 count, 84 "The visible Drafts list omitted persisted outbox rows; identifiers=\(identifiers.sorted())" 85 ) 86 } 87 88 @MainActor 89 func waitForWorkToFinish( 90 _ app: XCUIApplication, 91 submit: XCUIElement, 92 status: XCUIElement, 93 priorStatusLabel: String?, 94 priorSubmitValue: String? 95 ) -> Bool { 96 let addRoot = app.descendants(matching: .any)["radroots.add.root"] 97 let progress = app.descendants(matching: .any)["radroots.add.progress"] 98 let submissionProgress = app.descendants(matching: .any)["tera.add.submission.progress"] 99 let started = NSPredicate { _, _ in 100 if progress.exists || submissionProgress.exists || addRoot.value as? String == "Working" { 101 return true 102 } 103 if status.exists, !status.label.isEmpty, status.label != priorStatusLabel { 104 return true 105 } 106 return submit.exists && submit.value as? String != priorSubmitValue 107 } 108 let startExpectation = XCTNSPredicateExpectation(predicate: started, object: app) 109 _ = XCTWaiter.wait(for: [startExpectation], timeout: 5) 110 let settled = NSPredicate { _, _ in 111 addRoot.value as? String == "Ready" && !progress.exists && !submissionProgress.exists 112 } 113 let settleExpectation = XCTNSPredicateExpectation(predicate: settled, object: app) 114 return XCTWaiter.wait(for: [settleExpectation], timeout: 180) == .completed 115 } 116 117 @MainActor 118 func terminalControlShowsSettledState(_ submit: XCUIElement) -> Bool { 119 if submit.isEnabled { 120 return true 121 } 122 // Both complete and temporarily deferred work disable a new effect. 123 // Successful qualification still requires actual policy completion below. 124 let recognized = ["Delivery policy complete", "Publication waiting"].contains(submit.label) 125 XCTAssertTrue(recognized, "Unexpected inactive publication control: \(submit.label)") 126 return recognized 127 } 128 129 @MainActor 130 func finishOriginalPublication(_ app: XCUIApplication, submit: XCUIElement) -> Bool { 131 for _ in 0 ..< 3 { 132 scrollTo(app, element: submit) 133 guard submit.waitForExistence(timeout: 10) else { return false } 134 if submit.label == "Delivery policy complete" { 135 return true 136 } 137 guard submit.label == "Publication waiting" else { 138 XCTFail("The original publication did not complete: \(submit.label)") 139 return false 140 } 141 let priorValue = submit.value as? String 142 let check = app.buttons["Check saved submission status"] 143 TeraAccessibilityNavigation.scroll(app, to: check, up: false, test: self) 144 guard check.waitForExistence(timeout: 10), check.isHittable else { return false } 145 check.tap() 146 guard waitForWorkToFinish(app, submit: submit, status: app.staticTexts["tera.add.submission.status"], 147 priorStatusLabel: nil, priorSubmitValue: priorValue) else { return false } 148 scrollTo(app, element: submit) 149 guard submit.waitForExistence(timeout: 10) else { return false } 150 if submit.isEnabled { 151 guard let ready = readySubmit(app), submitAndWait(app, submit: ready) != nil else { return false } 152 } 153 } 154 scrollTo(app, element: submit) 155 let completed = submit.exists && submit.label == "Delivery policy complete" 156 XCTAssertTrue(completed, "The original publication did not complete within three visible status/continuation attempts") 157 return completed 158 } 159 160 @MainActor 161 func assertSavedPhotoEditing(_ app: XCUIApplication) { 162 guard openDrafts(app) else { return XCTFail("The saved editing inventory did not open") } 163 let reopen = app.buttons.matching( 164 NSPredicate(format: "identifier BEGINSWITH 'tera.add.composer.' AND label == 'Reopen'") 165 ).firstMatch 166 guard reopen.waitForExistence(timeout: 20) else { 167 return XCTFail("The persisted photo editing inventory omitted its Reopen action") 168 } 169 scrollTo(app, element: reopen) 170 XCTAssertTrue(waitUntilHittable(reopen, timeout: 10)) 171 reopen.tap() 172 XCTAssertTrue(app.navigationBars["Drafts & outbox"].waitForNonExistence(timeout: 20)) 173 let description = app.descendants(matching: .any)["Describe this photo"] 174 scrollTo(app, element: description) 175 XCTAssertEqual(description.value as? String, "A green test image prepared for the photo update", 176 "Reopening persisted photo editing must retain the supplied description") 177 } 178 }