Ctrl K
ComunidadGuías…

EchoUITests/NewConversationEntryUITests.swift

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

Archivo original ↗Preguntar a KiBot
import XCTest

/// GitHub issue 21: a card's question, a share and a Siri draft can start a new conversation
/// instead of going into the open one. On the demo conversation, with no server: the OpenAI-
/// compatible connection pointed at nothing, so a question is sent (and fails) without one.
@MainActor
final class NewConversationEntryUITests: XCTestCase {
    private func launch(_ extra: [String]) -> XCUIApplication {
        continueAfterFailure = false
        let app = XCUIApplication()
        app.launchArguments = ["-echo.demo", "-echo.demoShort", "-echo.clearDrafts",
                               "-transport", "chatCompletions", "-fastLaneURL", "http://127.0.0.1:9", "-fastLaneModel", "test"]
            + extra + XCUIApplication.straightToChat
        app.launch()
        return app
    }

    /// Drafts outlast the app, and other tests start from an empty message field: what a share or
    /// a Siri draft left here would be in front of their text. And the card's conversation goes,
    /// so the next run starts as this one did. (Not through the list: its question waits to be
    /// sent, and each try at sending it closes the list.)
    override func tearDownWithError() throws {
        MainActor.assumeIsolated {
            let app = XCUIApplication()
            app.launchArguments = ["-echo.clearDrafts", "-echo.forget", "About kanban card"] + XCUIApplication.straightToChat
            app.launch()
            _ = app.textFields.firstMatch.waitForExistence(timeout: 10)
            sleep(1)
            app.terminate()
        }
    }

    /// The demo conversation's first message, in the transcript.
    private func question(_ app: XCUIApplication) -> XCUIElement {
        app.text(containing: "What's on my calendar tomorrow")
    }

    /// The start screen, shown only on an empty conversation.
    private func startScreen(_ app: XCUIApplication) -> XCUIElement {
        app.text(containing: "What should Redde look into")
    }

    /// What the message field holds, once it holds `fragment`.
    private func composerHolds(_ fragment: String, in app: XCUIApplication) -> Bool {
        let field = app.textFields.firstMatch
        guard field.waitForExistence(timeout: 20) else { return false }
        let deadline = Date().addingTimeInterval(10)
        while Date() < deadline {
            if (field.value as? String)?.contains(fragment) == true { return true }
            RunLoop.current.run(until: Date().addingTimeInterval(0.25))
        }
        return false
    }

    func testACardAskedInANewConversationLeavesTheOpenOne() {
        let app = launch(["-echo.demoKanban", "-echo.screen", "sessions", "-echo.section", "kanban"])
        let card = app.text(containing: "Compare heat pump quotes")
        XCTAssertTrue(card.waitForExistence(timeout: 20), "The demo board isn't on screen")
        card.tap()
        let fresh = app.buttons["Ask in a new conversation"]
        XCTAssertTrue(fresh.waitForExistence(timeout: 10), "No way to ask in a new conversation")
        XCTAssertTrue(app.text(containing: "Ask in the open conversation").exists, "No way to ask in the open one")
        fresh.tap()
        XCTAssertTrue(app.text(containing: "About kanban card").waitForExistence(timeout: 10), "The card's question wasn't sent")
        XCTAssertFalse(question(app).exists, "It went into the open conversation")
    }

    /// Hermes's other boards (GitHub issue 65): the switcher over the columns names the board
    /// shown, and picking another shows that board's cards.
    func testAnotherKanbanBoardCanBePicked() {
        let app = launch(["-echo.demoKanban", "-echo.screen", "sessions", "-echo.section", "kanban"])
        XCTAssertTrue(app.text(containing: "Compare heat pump quotes").waitForExistence(timeout: 20), "The demo board isn't on screen")
        let switcher = app.descendants(matching: .any).matching(NSPredicate(format: "label == 'Board: Household'")).firstMatch
        XCTAssertTrue(switcher.waitForExistence(timeout: 5), "No board switcher over the columns")
        switcher.tap()
        let garden = app.buttons.matching(NSPredicate(format: "label CONTAINS 'Garden'")).firstMatch
        XCTAssertTrue(garden.waitForExistence(timeout: 5), "The other board isn't offered")
        garden.tap()
        XCTAssertTrue(app.text(containing: "Order the tomato seeds").waitForExistence(timeout: 10), "The other board's cards didn't show")
        XCTAssertFalse(app.text(containing: "Compare heat pump quotes").exists, "The first board's cards are still up")
        XCTAssertTrue(app.descendants(matching: .any).matching(NSPredicate(format: "label == 'Board: Garden'")).firstMatch.exists, "The switcher doesn't name the board picked")
    }

    func testACardAskedInTheOpenConversationStaysThere() {
        let app = launch(["-echo.demoKanban", "-echo.screen", "sessions", "-echo.section", "kanban"])
        let card = app.text(containing: "Compare heat pump quotes")
        XCTAssertTrue(card.waitForExistence(timeout: 20), "The demo board isn't on screen")
        card.tap()
        let open = app.text(containing: "Ask in the open conversation")
        XCTAssertTrue(open.waitForExistence(timeout: 10), "No way to ask in the open conversation")
        open.tap()
        XCTAssertTrue(app.text(containing: "About kanban card").waitForExistence(timeout: 10), "The card's question wasn't sent")
        XCTAssertTrue(question(app).exists, "It didn't go into the open conversation")
    }

    func testAShareWithNewConversationWaitsInANewOne() {
        let app = launch(["-echo.shareNew", "Shared from Safari"])
        XCTAssertTrue(startScreen(app).waitForExistence(timeout: 20), "The share kept the old conversation")
        XCTAssertTrue(composerHolds("Shared from Safari", in: app), "The share isn't in the new conversation's message field")
        // Back in the one it left (the start screen's Continue card): the share didn't stay
        // behind as its draft too.
        let back = app.text(containing: "Continue: What's on my calendar tomorrow")
        XCTAssertTrue(back.waitForExistence(timeout: 10), "No way back to the conversation it left")
        back.tap()
        XCTAssertTrue(question(app).waitForExistence(timeout: 10), "The demo conversation didn't open")
        let field = app.textFields.firstMatch
        XCTAssertTrue(field.waitForExistence(timeout: 10), "No message field")
        XCTAssertFalse((field.value as? String)?.contains("Shared from Safari") == true, "The share stayed behind in the old conversation too")
    }

    func testAShareWithoutItWaitsInTheOpenOne() {
        let app = launch(["-echo.share", "Shared from Safari"])
        XCTAssertTrue(composerHolds("Shared from Safari", in: app), "The share isn't in the message field")
        XCTAssertTrue(question(app).exists, "The share left the open conversation")
    }

    func testASiriDraftWaitsInANewConversationWhenSoSet() {
        let app = launch(["-siriAIEnabled", "YES", "-siriDraftsInNewConversation", "YES", "-echo.siriDraft", "Drafted by Siri"])
        XCTAssertTrue(startScreen(app).waitForExistence(timeout: 20), "The draft kept the old conversation")
        XCTAssertTrue(composerHolds("Drafted by Siri", in: app), "The draft isn't in the new conversation's message field")
    }
}