cmux/cmuxUITests/BrowserImportProfilesUITests.swift
2026-03-17 04:48:21 -07:00

236 lines
9.3 KiB
Swift

import XCTest
import Foundation
private func browserImportPollUntil(
timeout: TimeInterval,
pollInterval: TimeInterval = 0.05,
condition: () -> Bool
) -> Bool {
let start = ProcessInfo.processInfo.systemUptime
while true {
if condition() {
return true
}
if (ProcessInfo.processInfo.systemUptime - start) >= timeout {
return false
}
RunLoop.current.run(until: Date().addingTimeInterval(pollInterval))
}
}
final class BrowserImportProfilesUITests: XCTestCase {
private var capturePath = ""
override func setUp() {
super.setUp()
continueAfterFailure = false
capturePath = "/tmp/cmux-ui-test-browser-import-\(UUID().uuidString).json"
try? FileManager.default.removeItem(atPath: capturePath)
}
func testMultipleSourceProfilesDefaultToSeparateDestinations() throws {
let app = launchApp()
app.buttons["Next"].click()
app.buttons["Next"].click()
XCTAssertTrue(
app.radioButtons["Separate profiles"].waitForExistence(timeout: 5.0),
"Expected Step 3 to show the separate-profiles default"
)
XCTAssertTrue(app.radioButtons["Merge into one"].exists)
XCTAssertTrue(app.popUpButtons["BrowserImportDestinationPopup-you"].exists)
XCTAssertTrue(app.popUpButtons["BrowserImportDestinationPopup-austin"].exists)
app.buttons["Start Import"].click()
let capture = try XCTUnwrap(waitForCapturedSelection(timeout: 5.0))
XCTAssertEqual(capture["mode"] as? String, "separateProfiles")
XCTAssertEqual(capture["scope"] as? String, "cookiesAndHistory")
let entries = try XCTUnwrap(capture["entries"] as? [[String: Any]])
XCTAssertEqual(entries.count, 2)
XCTAssertEqual(entries[0]["sourceProfiles"] as? [String], ["You"])
XCTAssertEqual(entries[0]["destinationKind"] as? String, "create")
XCTAssertEqual(entries[0]["destinationName"] as? String, "You")
XCTAssertEqual(entries[1]["sourceProfiles"] as? [String], ["austin"])
XCTAssertEqual(entries[1]["destinationKind"] as? String, "create")
XCTAssertEqual(entries[1]["destinationName"] as? String, "austin")
}
func testMergeModeCapturesSingleMergedDestination() throws {
let app = launchApp()
app.buttons["Next"].click()
app.buttons["Next"].click()
let mergeRadio = app.radioButtons["Merge into one"]
XCTAssertTrue(mergeRadio.waitForExistence(timeout: 5.0))
mergeRadio.click()
XCTAssertTrue(
app.popUpButtons["BrowserImportDestinationPopup-merge"].waitForExistence(timeout: 5.0),
"Expected merge mode to show the single destination popup"
)
app.buttons["Start Import"].click()
let capture = try XCTUnwrap(waitForCapturedSelection(timeout: 5.0))
XCTAssertEqual(capture["mode"] as? String, "mergeIntoOne")
let entries = try XCTUnwrap(capture["entries"] as? [[String: Any]])
XCTAssertEqual(entries.count, 1)
XCTAssertEqual(entries[0]["sourceProfiles"] as? [String], ["You", "austin"])
XCTAssertEqual(entries[0]["destinationKind"] as? String, "existing")
XCTAssertEqual(entries[0]["destinationName"] as? String, "Default")
}
func testAdditionalDataSelectionCapturesEverythingScope() throws {
let app = launchApp()
app.buttons["Next"].click()
app.buttons["Next"].click()
let cookiesCheckbox = app.checkBoxes["BrowserImportCookiesCheckbox"]
XCTAssertTrue(cookiesCheckbox.waitForExistence(timeout: 5.0))
cookiesCheckbox.click()
let historyCheckbox = app.checkBoxes["BrowserImportHistoryCheckbox"]
XCTAssertTrue(historyCheckbox.waitForExistence(timeout: 5.0))
historyCheckbox.click()
let additionalDataCheckbox = app.checkBoxes["BrowserImportAdditionalDataCheckbox"]
XCTAssertTrue(
additionalDataCheckbox.waitForExistence(timeout: 5.0),
"Expected Step 3 to expose the additional data checkbox"
)
additionalDataCheckbox.click()
app.buttons["Start Import"].click()
let capture = try XCTUnwrap(waitForCapturedSelection(timeout: 5.0))
XCTAssertEqual(capture["scope"] as? String, "everything")
}
func testBlankBrowserImportHintCanOpenBrowserSettings() {
let app = launchAppForBlankImportHint()
let settingsButton = app.buttons["BrowserImportHintSettingsButton"]
XCTAssertTrue(settingsButton.waitForExistence(timeout: 5.0))
settingsButton.click()
let importSection = app.otherElements["SettingsBrowserImportSection"]
XCTAssertTrue(
importSection.waitForExistence(timeout: 5.0),
"Expected Browser Settings to scroll to the import section"
)
let chooseButton = app.buttons["SettingsBrowserImportChooseButton"]
XCTAssertTrue(
chooseButton.waitForExistence(timeout: 5.0),
"Expected Browser Settings to expose the import actions"
)
XCTAssertTrue(
browserImportPollUntil(timeout: 5.0) {
importSection.isHittable && chooseButton.isHittable
},
"Expected Browser Settings to scroll directly to the import controls"
)
}
func testBlankBrowserImportHintCanBeDismissed() {
let app = launchAppForBlankImportHint()
let dismissButton = app.buttons["BrowserImportHintDismissButton"]
XCTAssertTrue(dismissButton.waitForExistence(timeout: 5.0))
dismissButton.click()
XCTAssertTrue(
browserImportPollUntil(timeout: 2.0) { !dismissButton.exists },
"Expected the blank-tab import hint to disappear after dismissal"
)
}
private func launchApp() -> XCUIApplication {
let app = XCUIApplication()
app.launchEnvironment["CMUX_UI_TEST_MODE"] = "1"
app.launchEnvironment["CMUX_UI_TEST_BROWSER_IMPORT_FIXTURE"] = #"{"browserName":"Helium","profiles":["You","austin"]}"#
app.launchEnvironment["CMUX_UI_TEST_BROWSER_IMPORT_DESTINATIONS"] = #"["Default"]"#
app.launchEnvironment["CMUX_UI_TEST_BROWSER_IMPORT_MODE"] = "capture-only"
app.launchEnvironment["CMUX_UI_TEST_BROWSER_IMPORT_CAPTURE_PATH"] = capturePath
app.launchEnvironment["CMUX_UI_TEST_BROWSER_IMPORT_HINT_VARIANT"] = "inlineStrip"
app.launchEnvironment["CMUX_UI_TEST_BROWSER_IMPORT_HINT_SHOW"] = "1"
app.launchEnvironment["CMUX_UI_TEST_BROWSER_IMPORT_HINT_DISMISSED"] = "0"
app.launchEnvironment["CMUX_UI_TEST_BROWSER_IMPORT_HINT_OPEN_BLANK_BROWSER"] = "1"
launchAndActivate(app)
openImportWizardFromBlankImportHint(app)
return app
}
private func launchAppForBlankImportHint() -> XCUIApplication {
let app = XCUIApplication()
app.launchEnvironment["CMUX_UI_TEST_MODE"] = "1"
app.launchEnvironment["CMUX_UI_TEST_BROWSER_IMPORT_HINT_VARIANT"] = "inlineStrip"
app.launchEnvironment["CMUX_UI_TEST_BROWSER_IMPORT_HINT_SHOW"] = "1"
app.launchEnvironment["CMUX_UI_TEST_BROWSER_IMPORT_HINT_DISMISSED"] = "0"
app.launchEnvironment["CMUX_UI_TEST_BROWSER_IMPORT_HINT_OPEN_BLANK_BROWSER"] = "1"
launchAndActivate(app)
waitForBlankImportHint(app)
return app
}
private func waitForImportWizard(_ app: XCUIApplication) {
let wizardOpened = browserImportPollUntil(timeout: 5.0) {
app.buttons["Next"].exists || app.windows["Import Browser Data"].exists
}
XCTAssertTrue(wizardOpened, "Expected the import wizard to open")
}
private func waitForBlankImportHint(_ app: XCUIApplication) {
let hintOpened = browserImportPollUntil(timeout: 5.0) {
app.buttons["BrowserImportHintImportButton"].exists
}
XCTAssertTrue(hintOpened, "Expected the blank browser import hint to appear")
}
private func openImportWizardFromBlankImportHint(_ app: XCUIApplication) {
waitForBlankImportHint(app)
let importButton = app.buttons["BrowserImportHintImportButton"]
XCTAssertTrue(importButton.waitForExistence(timeout: 5.0))
importButton.click()
waitForImportWizard(app)
}
private func waitForCapturedSelection(timeout: TimeInterval) -> [String: Any]? {
let url = URL(fileURLWithPath: capturePath)
let foundCapture = browserImportPollUntil(timeout: timeout) {
if let data = try? Data(contentsOf: url),
let object = try? JSONSerialization.jsonObject(with: data) as? [String: Any] {
return !object.isEmpty
}
return false
}
if foundCapture,
let data = try? Data(contentsOf: url),
let object = try? JSONSerialization.jsonObject(with: data) as? [String: Any] {
return object
}
return nil
}
private func launchAndActivate(_ app: XCUIApplication, activateTimeout: TimeInterval = 2.0) {
app.launch()
let activated = browserImportPollUntil(timeout: activateTimeout) {
guard app.state != .runningForeground else {
return true
}
app.activate()
return app.state == .runningForeground
}
if !activated {
app.activate()
}
}
}