Ctrl K
ComunidadGuías…

EchoUITests/PhoneToolsUITests.swift

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import XCTest

/// Settings → Phone tools: everything is off until it is turned on, each area has its own
/// setting, and the plugin on the server is named. `-echo.demoPlugin there` stands in for a
/// Hermes that has the plugin; no server is needed.
@MainActor
final class PhoneToolsUITests: XCTestCase {
    private func shot(_ name: String) {
        let attachment = XCTAttachment(screenshot: XCUIScreen.main.screenshot())
        attachment.name = name
        attachment.lifetime = .keepAlways
        add(attachment)
    }

    private func reach(_ element: XCUIElement, in app: XCUIApplication, _ what: String) {
        for _ in 0 ..< 14 where !(element.exists && element.isHittable) { app.swipeUp() }
        XCTAssertTrue(element.exists && element.isHittable, "\(what) isn't on the screen")
    }

    private func flip(_ row: XCUIElement) {
        let knob = row.switches.firstMatch
        (knob.exists ? knob : row).tap()
    }

    func testPhoneToolsAreOffUntilTurnedOnAreaByArea() {
        continueAfterFailure = false
        let app = XCUIApplication()
        app.launchArguments = XCUIApplication.straightToChat + ["-echo.screen", "settings", "-echo.demoPlugin", "there"]
        app.launch()
        XCTAssertTrue(app.navigationBars["Settings"].waitForExistence(timeout: 20), "Settings didn't open")
        app.openSettingsPage("Agent")
        let row = app.buttons.matching(NSPredicate(format: "label BEGINSWITH 'Phone tools'")).firstMatch
        reach(row, in: app, "The Phone tools row")
        row.tap()
        XCTAssertTrue(app.navigationBars["Phone Tools"].waitForExistence(timeout: 10), "The Phone tools screen didn't open")

        let master = app.switches["Phone tools"]
        XCTAssertTrue(master.waitForExistence(timeout: 5))
        if master.value as? String == "1" { flip(master) }   // (left on by a run that stopped halfway)
        XCTAssertFalse(app.staticTexts["What it may use"].exists || app.staticTexts["WHAT IT MAY USE"].exists, "The areas show while phone tools are off")
        shot("phone tools off")

        flip(master)
        let calendar = app.buttons.matching(NSPredicate(format: "label BEGINSWITH 'Calendar'")).firstMatch
        XCTAssertTrue(calendar.waitForExistence(timeout: 5), "Turned on, the areas aren't offered")
        // More areas than fit on the screen at once: each is scrolled to.
        for area in ["Reminders", "Contacts", "Photos", "Files", "Alarms", "Widget", "Calls and Messages"] {
            reach(app.buttons.matching(NSPredicate(format: "label BEGINSWITH %@", area)).firstMatch, in: app, "\(area)")
        }
        for _ in 0 ..< 8 where !master.isHittable { app.swipeDown() }
        // Under Photos: where the pictures are looked at, and what of them leaves the phone.
        XCTAssertTrue(app.staticTexts.containing(NSPredicate(format: "label CONTAINS 'keeps what it finds here' AND label CONTAINS 'to your Hermes and nowhere else'")).firstMatch.exists,
                      "The note under Photos isn't there")
        // An area starts off, and is turned on by choosing how.
        calendar.tap()
        let asking = app.buttons["Ask each time"]
        XCTAssertTrue(asking.waitForExistence(timeout: 5), "The area's choices didn't open")
        XCTAssertTrue(app.buttons["Off"].exists && app.buttons["Allow reading"].exists)
        asking.tap()
        // Where Redde has never been let at the calendar, this is when iOS asks.
        let full = XCUIApplication(bundleIdentifier: "com.apple.springboard").buttons["Allow Full Access"]
        if full.waitForExistence(timeout: 3) { full.tap() }
        XCTAssertTrue(app.buttons.matching(NSPredicate(format: "label BEGINSWITH 'Calendar' AND (label CONTAINS 'Ask each time' OR value CONTAINS 'Ask each time')")).firstMatch
            .waitForExistence(timeout: 5), "The choice didn't take")
        shot("phone tools on")

        // Further down, the plugin on the server is named.
        let plugin = app.staticTexts.containing(NSPredicate(format: "label CONTAINS 'The plugin' AND label CONTAINS 'is on this Hermes'")).firstMatch
        reach(plugin, in: app, "The plugin on the server")
        shot("phone tools plugin")
        for _ in 0 ..< 6 where !master.isHittable { app.swipeDown() }

        // Off again, for whatever runs next: the area, then the whole thing.
        app.buttons.matching(NSPredicate(format: "label BEGINSWITH 'Calendar'")).firstMatch.tap()
        app.buttons["Off"].tap()
        flip(master)
        XCTAssertTrue(calendar.waitForNonExistence(timeout: 5))
    }

    /// Turning Alarms on is when iOS is asked whether Redde may set them. The iOS 27.0 simulator
    /// refuses without asking (the 26.3 one asks), and where it was refused once it stays so.
    func testTurningAlarmsOnAsksIOSForThem() throws {
        continueAfterFailure = false
        let app = XCUIApplication()
        app.launchArguments = XCUIApplication.straightToChat + ["-echo.screen", "settings", "-echo.demoPlugin", "there"]
        app.launch()
        XCTAssertTrue(app.navigationBars["Settings"].waitForExistence(timeout: 20), "Settings didn't open")
        app.openSettingsPage("Agent")
        let row = app.buttons.matching(NSPredicate(format: "label BEGINSWITH 'Phone tools'")).firstMatch
        reach(row, in: app, "The Phone tools row")
        row.tap()
        let master = app.switches["Phone tools"]
        XCTAssertTrue(master.waitForExistence(timeout: 10))
        if master.value as? String != "1" { flip(master) }
        let alarms = app.buttons.matching(NSPredicate(format: "label BEGINSWITH 'Alarms'")).firstMatch
        reach(alarms, in: app, "The Alarms row")
        alarms.tap()
        app.buttons["Ask each time"].tap()
        // The first time, iOS asks whether Redde may schedule alarms and timers.
        let allow = XCUIApplication(bundleIdentifier: "com.apple.springboard").buttons["Allow"]
        if allow.waitForExistence(timeout: 6) { allow.tap() }
        let refused = app.buttons.matching(NSPredicate(format: "label CONTAINS 'allow Redde this'")).firstMatch
        if refused.waitForExistence(timeout: 3) {
            // Refused, the area goes back to Off and says where to allow it: that much is right.
            shot("alarms refused")
            for _ in 0 ..< 6 where !master.isHittable { app.swipeDown() }
            flip(master)
            throw XCTSkip("iOS refused the alarms permission here without being allowed to ask (the iOS 27.0 simulator does)")
        }
        XCTAssertTrue(app.buttons.matching(NSPredicate(format: "label BEGINSWITH 'Alarms' AND (label CONTAINS 'Ask each time' OR value CONTAINS 'Ask each time')")).firstMatch
            .waitForExistence(timeout: 8), "The choice didn't take")
        shot("alarms on")

        app.buttons.matching(NSPredicate(format: "label BEGINSWITH 'Alarms'")).firstMatch.tap()
        app.buttons["Off"].tap()
        for _ in 0 ..< 6 where !master.isHittable { app.swipeDown() }
        flip(master)
    }
}