- UITests: Fixes for setup/teardown and added repeatability tests

This commit is contained in:
Magesh K
2025-02-23 15:12:55 +05:30
parent 359b38609b
commit 0070519736

View File

@@ -22,7 +22,8 @@ final class UITests: XCTestCase {
override func setUpWithError() throws { override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class. // Put setup code here. This method is called before the invocation of each test method in the class.
// Self.dismissSpotlight() // Self.dismissSpotlight()
Self.dismissSpringboardAlerts() // Self.deleteMyApp()
Self.deleteMyApp2()
// In UI tests it is usually best to stop immediately when a failure occurs. // In UI tests it is usually best to stop immediately when a failure occurs.
continueAfterFailure = false continueAfterFailure = false
@@ -32,8 +33,6 @@ final class UITests: XCTestCase {
override func tearDownWithError() throws { override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class. // Put teardown code here. This method is called after the invocation of each test method in the class.
// Self.deleteMyApp()
Self.deleteMyApp2()
super.tearDown() super.tearDown()
} }
@@ -69,6 +68,21 @@ final class UITests: XCTestCase {
try performBulkAddingInputSources(for: app) try performBulkAddingInputSources(for: app)
} }
func testRepeatabilityForStagingInputSources() throws {
let app = XCUIApplication()
app.launch()
let systemAlert = Self.springboard_app.alerts["\(Self.APP_NAME)” Would Like to Send You Notifications"]
// if it exists keep going immediately else wait for upto 5 sec with polling every 1 sec for existence
XCTAssertTrue(systemAlert.exists || systemAlert.waitForExistence(timeout: 5), "Notifications alert did not appear")
systemAlert.scrollViews.otherElements.buttons["Allow"].tap()
// Do the actual validation
try performRepeatabilityForStagingInputSources(for: app)
}
// @MainActor // @MainActor
// func testLaunchPerformance() throws { // func testLaunchPerformance() throws {
@@ -154,8 +168,8 @@ private extension UITests {
button.tap() button.tap()
} }
// Press home once to make the icons stop wiggling // // Press home once to make the icons stop wiggling
XCUIDevice.shared.press(.home) // XCUIDevice.shared.press(.home)
} }
} }
@@ -176,6 +190,17 @@ private extension UITests {
} }
struct SeededGenerator: RandomNumberGenerator {
var seed: UInt64
mutating func next() -> UInt64 {
// A basic LCG (not cryptographically secure, but fine for testing)
seed = 6364136223846793005 &* seed &+ 1
return seed
}
}
// Test guts (definition) // Test guts (definition)
private extension UITests { private extension UITests {
@@ -186,7 +211,7 @@ private extension UITests {
cellsQuery: XCUIElementQuery cellsQuery: XCUIElementQuery
) throws { ) throws {
// Tap on each textInputSources source's "add" button. // Tap on each sorucesMapping source's "add" button.
for source in sorucesMapping { for source in sorucesMapping {
let sourceButton = cellsQuery.otherElements let sourceButton = cellsQuery.otherElements
.containing(.button, identifier: source.identifier) .containing(.button, identifier: source.identifier)
@@ -277,6 +302,67 @@ private extension UITests {
} }
private func performRepeatabilityForStagingInputSources(for app: XCUIApplication) throws {
// set content into clipboard (for bulk add (paste))
// NOTE: THIS IS AN ORDERED SEQUENCE AND MUST MATCH THE ORDER in textInputSources BELOW (Remember to take this into account when adding more entries)
UIPasteboard.general.string = """
https://alts.lao.sb
https://taurine.app/altstore/taurinestore.json
https://randomblock1.com/altstore/apps.json
https://burritosoftware.github.io/altstore/channels/burritosource.json
https://bit.ly/40Isul6
""".trimmedIndentation
let app = XCUIApplication()
app.tabBars["Tab Bar"].buttons["Sources"].tap()
app.navigationBars["Sources"].buttons["Add"].tap()
let collectionViewsQuery = app.collectionViews
let appsSidestoreIoTextField = collectionViewsQuery.textFields["apps.sidestore.io"]
_ = appsSidestoreIoTextField.exists || appsSidestoreIoTextField.waitForExistence(timeout: 5)
appsSidestoreIoTextField.tap()
appsSidestoreIoTextField.tap()
_ = appsSidestoreIoTextField.exists || appsSidestoreIoTextField.waitForExistence(timeout: 5)
collectionViewsQuery.staticTexts["Paste"].tap()
if app.keyboards.count > 0 {
appsSidestoreIoTextField.typeText("\n") // Fallback to newline so that soft kb is dismissed
}
let cellsQuery = collectionViewsQuery.cells
// Data model for recommended sources. NOTE: This list order is required to be the same as that of "Add Source" Screen
let textInputSources: [(identifier: String, alertTitle: String, requiresSwipe: Bool)] = [
("Laoalts\nalts.lao.sb", "Laoalts", false),
("Taurine\ntaurine.app/altstore/taurinestore.json", "Taurine", false),
("RandomSource\nrandomblock1.com/altstore/apps.json", "RandomSource", false),
("Burrito's AltStore\nburritosoftware.github.io/altstore/channels/burritosource.json", "Burrito's AltStore", false),
("Qn_'s AltStore Repo\nbit.ly/40Isul6", "Qn_'s AltStore Repo", false),
]
let repeatCount = 3 // number of times to run the entire sequence
let timeSeed = UInt64(Date().timeIntervalSince1970)
var seededGenerator = SeededGenerator(seed: timeSeed) // time is unique (upto microseconds) - uncomment this to use non-deterministic seed based RNG (random number generator)
// var seededGenerator = SeededGenerator(seed: 42) // fixed seed for deterministic start of this generator
for _ in 0..<repeatCount {
// The same fixed seeded generator will yield the same permutation if not advanced, so you might want to reinitialize or use a fresh copy for each iteration:
// var seededGenerator = seededGenerator // uncomment this for repeats to use same(shuffled once due to inital seed) order for all repeats
// for source in textInputSources.shuffled() { // use this for non-deterministic shuffling
for source in textInputSources.shuffled(using: &seededGenerator) { // use this for deterministic shuffling based on seed
let sourceButton = cellsQuery.otherElements
.containing(.button, identifier: source.identifier)
.children(matching: .button)[source.identifier]
XCTAssert(sourceButton.exists || sourceButton.waitForExistence(timeout: 5), "Source preview for id '\(source.alertTitle)' not found in the view")
let addButton = sourceButton.children(matching: .button)["add"]
addButton.tap()
}
}
}
private func performBulkAddingRecommendedSources(for app: XCUIApplication) throws { private func performBulkAddingRecommendedSources(for app: XCUIApplication) throws {
// Navigate to the Sources screen and open the Add Source view. // Navigate to the Sources screen and open the Add Source view.
@@ -291,8 +377,8 @@ private extension UITests {
("Provenance EMU\nprovenance-emu.com/apps.json", "Provenance EMU", false), ("Provenance EMU\nprovenance-emu.com/apps.json", "Provenance EMU", false),
("Countdown Respository\nneoarz.github.io/Countdown-App/Countdown.json", "Countdown Respository", false), ("Countdown Respository\nneoarz.github.io/Countdown-App/Countdown.json", "Countdown Respository", false),
("OatmealDome's AltStore Source\naltstore.oatmealdome.me", "OatmealDome's AltStore Source", false), ("OatmealDome's AltStore Source\naltstore.oatmealdome.me", "OatmealDome's AltStore Source", false),
("UTM Repository\nVirtual machines for iOS", "UTM Repository", true), ("UTM Repository\nVirtual machines for iOS", "UTM Repository", false),
("Flyinghead\nflyinghead.github.io/flycast-builds/altstore.json", "Flyinghead", false), ("Flyinghead\nflyinghead.github.io/flycast-builds/altstore.json", "Flyinghead", true),
("PojavLauncher Repository\nalt.crystall1ne.dev", "PojavLauncher Repository", false), ("PojavLauncher Repository\nalt.crystall1ne.dev", "PojavLauncher Repository", false),
("PokeMMO\npokemmo.eu/altstore/", "PokeMMO", false), ("PokeMMO\npokemmo.eu/altstore/", "PokeMMO", false),
("Odyssey\ntheodyssey.dev/altstore/odysseysource.json", "Odyssey", false), ("Odyssey\ntheodyssey.dev/altstore/odysseysource.json", "Odyssey", false),