cmux/GhosttyTabsUITests/UpdatePillUITests.swift
Lawrence Chen 9817d131f8
Release v1.23.0 (#31)
* Rename cmuxterm to cmux across entire codebase

- Rename GitHub repos: manaflow-ai/cmuxterm -> manaflow-ai/cmux,
  manaflow-ai/homebrew-cmuxterm -> manaflow-ai/homebrew-cmux
- Rename bundle IDs: com.cmuxterm.app -> com.cmux.app
- Rename CLI: CLI/cmuxterm.swift -> CLI/cmux.swift
- Rename homebrew submodule: homebrew-cmuxterm -> homebrew-cmux
- Update all socket paths: /tmp/cmuxterm*.sock -> /tmp/cmux*.sock
- Update all GitHub URLs, DMG names, Sparkle URLs
- Update all source files, scripts, tests, docs, CI workflows

* Bump version to 1.23.0
2026-02-09 15:30:43 -08:00

136 lines
5.9 KiB
Swift

import XCTest
import Foundation
final class UpdatePillUITests: XCTestCase {
override func setUp() {
super.setUp()
continueAfterFailure = false
}
func testUpdatePillShowsForAvailableUpdate() {
let systemSettings = XCUIApplication(bundleIdentifier: "com.apple.systempreferences")
systemSettings.terminate()
let app = XCUIApplication()
app.launchEnvironment["CMUX_UI_TEST_MODE"] = "1"
app.launchEnvironment["CMUX_UI_TEST_UPDATE_STATE"] = "available"
app.launchEnvironment["CMUX_UI_TEST_UPDATE_VERSION"] = "9.9.9"
app.launch()
app.activate()
let pill = app.descendants(matching: .any)["UpdatePill"]
XCTAssertTrue(pill.waitForExistence(timeout: 5.0))
XCTAssertTrue(waitForLabel(pill, label: "Update Available: 9.9.9", timeout: 5.0))
assertVisibleSize(pill)
attachScreenshot(name: "update-available")
attachScreenshot(name: "update-available-pill", screenshot: pill.screenshot())
}
func testUpdatePillShowsForNoUpdateThenDismisses() {
let systemSettings = XCUIApplication(bundleIdentifier: "com.apple.systempreferences")
systemSettings.terminate()
let timingPath = FileManager.default.temporaryDirectory
.appendingPathComponent("cmux-ui-test-timing-\(UUID().uuidString).json")
let app = XCUIApplication()
app.launchEnvironment["CMUX_UI_TEST_MODE"] = "1"
app.launchEnvironment["CMUX_UI_TEST_UPDATE_STATE"] = "notFound"
app.launchEnvironment["CMUX_UI_TEST_TIMING_PATH"] = timingPath.path
app.launch()
app.activate()
let pill = app.descendants(matching: .any)["UpdatePill"]
XCTAssertTrue(pill.waitForExistence(timeout: 5.0))
XCTAssertTrue(waitForLabel(pill, label: "No Updates Available", timeout: 5.0))
assertVisibleSize(pill)
attachScreenshot(name: "no-updates")
attachScreenshot(name: "no-updates-pill", screenshot: pill.screenshot())
let gone = XCTNSPredicateExpectation(
predicate: NSPredicate(format: "exists == false"),
object: pill
)
XCTAssertEqual(XCTWaiter().wait(for: [gone], timeout: 7.0), .completed)
let payload = loadTimingPayload(from: timingPath)
let shownAt = payload["noUpdateShownAt"] ?? 0
let hiddenAt = payload["noUpdateHiddenAt"] ?? 0
XCTAssertGreaterThan(shownAt, 0)
XCTAssertGreaterThan(hiddenAt, shownAt)
XCTAssertGreaterThanOrEqual(hiddenAt - shownAt, 4.8)
}
func testCheckForUpdatesUsesMockFeedWithUpdate() {
let systemSettings = XCUIApplication(bundleIdentifier: "com.apple.systempreferences")
systemSettings.terminate()
let app = launchAppWithMockFeed(mode: "available", version: "9.9.9")
let pill = app.descendants(matching: .any)["UpdatePill"]
XCTAssertTrue(pill.waitForExistence(timeout: 5.0))
XCTAssertTrue(waitForLabel(pill, label: "Update Available: 9.9.9", timeout: 5.0))
assertVisibleSize(pill)
attachScreenshot(name: "mock-update-available")
}
func testCheckForUpdatesUsesMockFeedWithNoUpdate() {
let systemSettings = XCUIApplication(bundleIdentifier: "com.apple.systempreferences")
systemSettings.terminate()
let timingPath = FileManager.default.temporaryDirectory
.appendingPathComponent("cmux-ui-test-timing-\(UUID().uuidString).json")
let app = launchAppWithMockFeed(mode: "none", version: "9.9.9", timingPath: timingPath)
let pill = app.descendants(matching: .any)["UpdatePill"]
XCTAssertTrue(pill.waitForExistence(timeout: 5.0))
XCTAssertTrue(waitForLabel(pill, label: "No Updates Available", timeout: 5.0))
assertVisibleSize(pill)
attachScreenshot(name: "mock-no-updates")
}
private func waitForLabel(_ element: XCUIElement, label: String, timeout: TimeInterval) -> Bool {
let predicate = NSPredicate(format: "label == %@", label)
let expectation = XCTNSPredicateExpectation(predicate: predicate, object: element)
return XCTWaiter().wait(for: [expectation], timeout: timeout) == .completed
}
private func assertVisibleSize(_ element: XCUIElement, timeout: TimeInterval = 2.0) {
let deadline = Date().addingTimeInterval(timeout)
var size = element.frame.size
while Date() < deadline {
size = element.frame.size
if size.width > 20 && size.height > 10 {
return
}
RunLoop.current.run(until: Date().addingTimeInterval(0.05))
}
XCTFail("Expected UpdatePill to have visible size, got \(size)")
}
private func attachScreenshot(name: String, screenshot: XCUIScreenshot = XCUIScreen.main.screenshot()) {
let attachment = XCTAttachment(screenshot: screenshot)
attachment.name = name
attachment.lifetime = .keepAlways
add(attachment)
}
private func launchAppWithMockFeed(mode: String, version: String, timingPath: URL? = nil) -> XCUIApplication {
let app = XCUIApplication()
app.launchEnvironment["CMUX_UI_TEST_MODE"] = "1"
app.launchEnvironment["CMUX_UI_TEST_FEED_URL"] = "https://cmux.test/appcast.xml"
app.launchEnvironment["CMUX_UI_TEST_FEED_MODE"] = mode
app.launchEnvironment["CMUX_UI_TEST_UPDATE_VERSION"] = version
app.launchEnvironment["CMUX_UI_TEST_AUTO_ALLOW_PERMISSION"] = "1"
app.launchEnvironment["CMUX_UI_TEST_TRIGGER_UPDATE_CHECK"] = "1"
if let timingPath {
app.launchEnvironment["CMUX_UI_TEST_TIMING_PATH"] = timingPath.path
}
app.launch()
app.activate()
return app
}
private func loadTimingPayload(from url: URL) -> [String: Double] {
guard let data = try? Data(contentsOf: url),
let object = try? JSONSerialization.jsonObject(with: data) as? [String: Double] else {
return [:]
}
return object
}
}