johnandersen777.bsky.social/knotless
git that lives in your Atmosphere account
Forked from chadtmiller.com/knotless
0
0
import XCTest
/// Draws the screens `ios/look.mjs` asks for. It's that script's hands, not a
/// test: with no plan it's skipped.
final class LookTests: XCTestCase {
private struct Plan: Decodable {
let answers: String
let misses: String
let now: String
let signedIn: Bool
let runs: [Run]
}
private struct Run: Decodable {
let route: String
let scheme: String
let theme: String?
let steps: [Step]
let top: Bool
let out: String
}
private struct Step: Decodable {
var tap: String?
var type: String?
var swipe: String?
}
func testLook() throws {
guard let path = ProcessInfo.processInfo.environment["KNOTLESS_LOOK"] else {
throw XCTSkip("ios/look.mjs names the plan")
}
let plan = try JSONDecoder().decode(Plan.self, from: Data(contentsOf: URL(fileURLWithPath: path)))
continueAfterFailure = true
for run in plan.runs {
let app = XCUIApplication()
app.launchEnvironment = [
"KNOTLESS_ANSWERS": plan.answers,
"KNOTLESS_MISSES": plan.misses,
"KNOTLESS_NOW": plan.now,
"KNOTLESS_ROUTE": run.route,
"KNOTLESS_SCHEME": run.scheme,
]
if plan.signedIn { app.launchEnvironment["KNOTLESS_SIGNED_IN"] = "1" }
if let theme = run.theme { app.launchEnvironment["KNOTLESS_THEME"] = theme }
// From nothing this simulator's app was last left in, as a picture holds only to what it's asked.
app.launchEnvironment["KNOTLESS_FRESH"] = "1"
app.launch()
sleep(2)
for step in run.steps { take(step, in: app) }
sleep(1)
var last = shot(to: "\(run.out).png")
guard !run.top else { continue }
for page in 2...8 {
app.swipeUp()
// Till the scroll bar has gone, or the end looks like a move.
sleep(3)
let now = XCUIScreen.main.screenshot().pngRepresentation
if now == last { break }
try? now.write(to: URL(fileURLWithPath: "\(run.out)-\(page).png"))
last = now
}
}
}
private func shot(to path: String) -> Data {
let png = XCUIScreen.main.screenshot().pngRepresentation
try? png.write(to: URL(fileURLWithPath: path))
return png
}
private func take(_ step: Step, in app: XCUIApplication) {
if let label = step.tap, label.hasPrefix("@") {
let xy = label.dropFirst().split(separator: ",").compactMap { Double($0) }
app.coordinate(withNormalizedOffset: .zero).withOffset(CGVector(dx: xy[0], dy: xy[1])).tap()
sleep(2)
} else if let label = step.tap {
let match = NSPredicate(format: "label == %@ OR identifier == %@", label, label)
let found = app.descendants(matching: .any).matching(match).firstMatch
for _ in 0..<8 where !(found.exists && found.isHittable) { app.swipeUp() }
guard found.exists, found.isHittable else {
XCTFail("LOOK: nothing to tap called \(label)")
return
}
found.tap()
sleep(1)
}
if let text = step.type {
let box = app.textViews.firstMatch.exists ? app.textViews.firstMatch : app.textFields.firstMatch
guard box.waitForExistence(timeout: 5) else {
XCTFail("LOOK: nothing to type into")
return
}
box.tap()
box.typeText(text)
}
if step.swipe == "up" { app.swipeUp() }
if step.swipe == "down" { app.swipeDown() }
if step.swipe == "left" { app.swipeLeft() }
if step.swipe == "right" { app.swipeRight() }
}
}