From 7fb5f29a9bccacd483602e6a3bde0af9a3b23864 Mon Sep 17 00:00:00 2001 From: Ngo Quoc Dat Date: Wed, 19 Aug 2026 14:29:32 +0700 Subject: [PATCH] test(hig): skip the inspector toolbar placement test on a screen too narrow to host it --- .../InspectorToolbarPlacementUITests.swift | 39 +++++++++++++++++-- TableProUITests/Support/UITestCase.swift | 17 ++++++-- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/TableProUITests/InspectorToolbarPlacementUITests.swift b/TableProUITests/InspectorToolbarPlacementUITests.swift index 03dcef459..572025892 100644 --- a/TableProUITests/InspectorToolbarPlacementUITests.swift +++ b/TableProUITests/InspectorToolbarPlacementUITests.swift @@ -8,6 +8,7 @@ // is why the identifier-order unit tests are not enough on their own. // +import AppKit import XCTest final class InspectorToolbarPlacementUITests: UITestCase { @@ -21,16 +22,27 @@ final class InspectorToolbarPlacementUITests: UITestCase { /// The window size is pinned because the measurement is a distance from the window's trailing /// edge: a restored frame narrow enough to overflow the toolbar would move the last item for - /// reasons that have nothing to do with the inspector. The language is pinned because the only - /// handle on the toggle is the label AppKit gives its own standard item, which is localized. + /// reasons that have nothing to do with the inspector. + private let pinnedWindowSize = CGSize(width: 1512, height: 861) + private var pinnedEnvironment: [String: String] { - ["TABLEPRO_SCREENSHOT_FRAME": "1512x861", "AppleLanguages": "(en)"] + ["TABLEPRO_SCREENSHOT_FRAME": "\(Int(pinnedWindowSize.width))x\(Int(pinnedWindowSize.height))"] } + /// The only handle on the toggle is the label AppKit gives its own standard item, which is + /// localized, so the app has to run in a known language. `AppleLanguages` is a defaults key + /// rather than an environment variable, and this test used to pass it in the environment, where + /// nothing reads it: the match worked only because both machines happened to be English. + private let pinnedArguments = ["-AppleLanguages", "(en)"] + /// The inspector remembers whether it was open, so the starting state is whatever the previous /// launch left. Both directions are asserted rather than assuming one. func testTheInspectorToggleHoldsTheTrailingEdgeThroughBothTransitions() throws { - let app = try launchWithSampleDatabase(environment: pinnedEnvironment) + try skipUnlessTheScreenFitsThePinnedWindow() + let app = try launchWithSampleDatabase( + environment: pinnedEnvironment, + arguments: pinnedArguments + ) let window = try mainWindow(of: app) let toggle = try inspectorToggle(in: window) @@ -70,6 +82,25 @@ final class InspectorToolbarPlacementUITests: UITestCase { // MARK: - Helpers + /// A window pinned wider than the screen is placed partly off it, and its toolbar collapses the + /// trailing items into the overflow menu, so there is no toggle in the toolbar to measure at + /// all. That is unmeasurable rather than wrong, and it is what the CI runner is: a 1024x768 + /// virtual machine, where this reported "No inspector toggle in the toolbar" on every run while + /// passing on any real display. + private func skipUnlessTheScreenFitsThePinnedWindow() throws { + /// Width only, and against the screen's own frame rather than its visible one. The failure + /// this guards is horizontal, and the menu bar and Dock take height, not toolbar room. + let width = NSScreen.main?.frame.width ?? 0 + try XCTSkipUnless( + width >= pinnedWindowSize.width, + """ + Needs a screen at least \(Int(pinnedWindowSize.width))pt wide to hold the pinned window; \ + this one is \(Int(width))pt. Anything narrower overflows the toolbar's trailing items \ + into its menu, and the toggle is then not in the toolbar to measure. + """ + ) + } + private func mainWindow(of app: XCUIApplication) throws -> XCUIElement { let window = app.windows.matching(NSPredicate(format: "identifier != %@", "welcome")).firstMatch XCTAssertTrue(window.waitForExistence(timeout: 60), "The sample database produced no window") diff --git a/TableProUITests/Support/UITestCase.swift b/TableProUITests/Support/UITestCase.swift index 1120b2d31..740c81ca8 100644 --- a/TableProUITests/Support/UITestCase.swift +++ b/TableProUITests/Support/UITestCase.swift @@ -82,7 +82,14 @@ internal class UITestCase: XCTestCase { } } - internal func launchApp(environment: [String: String] = [:]) throws -> XCUIApplication { + /// `arguments` is separate from `environment` because the two are not interchangeable. A + /// defaults override such as `-AppleLanguages` only takes effect as a launch argument: passed + /// in the environment it is an ordinary variable nothing reads, so the pin silently does + /// nothing and the test passes only on a machine that was already in that language. + internal func launchApp( + environment: [String: String] = [:], + arguments: [String] = [] + ) throws -> XCUIApplication { let root = try XCTUnwrap(sandboxRoot, "setUpWithError did not prepare a sandbox") let app = XCUIApplication() app.launchEnvironment["TABLEPRO_UI_TESTING"] = "1" @@ -90,6 +97,7 @@ internal class UITestCase: XCTestCase { for (key, value) in environment { app.launchEnvironment[key] = value } + app.launchArguments.append(contentsOf: arguments) app.launch() launchedApps.append(app) return app @@ -103,8 +111,11 @@ internal class UITestCase: XCTestCase { /// menu during menu traversal"; XCUITest then falls back to hovering and resolves the item to an /// unhittable zero-size frame. That failed every suite this helper serves. @discardableResult - internal func launchWithSampleDatabase(environment: [String: String] = [:]) throws -> XCUIApplication { - let app = try launchApp(environment: environment) + internal func launchWithSampleDatabase( + environment: [String: String] = [:], + arguments: [String] = [] + ) throws -> XCUIApplication { + let app = try launchApp(environment: environment, arguments: arguments) let menuBar = app.menuBars.firstMatch XCTAssertTrue(menuBar.waitForExistence(timeout: 10)) let openSample = menuBar.menuItems["Open Sample Database"]