macOS: update tests and add test plan (#12473)

This updates UI tests and adds a test plan on disk, so we can change the
configuration to different ones with the host app.

If you changed the icon in regular ghostty config file, the tests can
only be run once, since the signature is changed after changing the
icon. Adding an on-disk test plan helps us to better control the
environment for the tests.
This commit is contained in:
Mitchell Hashimoto
2026-04-27 09:25:51 -07:00
committed by GitHub
8 changed files with 67 additions and 24 deletions

View File

@@ -73,6 +73,7 @@
3B39CAA42B33949B00DABEB8 /* GhosttyReleaseLocal.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = GhosttyReleaseLocal.entitlements; sourceTree = "<group>"; };
55154BDF2B33911F001622DC /* ghostty */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ghostty; path = "../zig-out/share/ghostty"; sourceTree = "<group>"; };
552964E52B34A9B400030505 /* vim */ = {isa = PBXFileReference; lastKnownFileType = folder; name = vim; path = "../zig-out/share/vim"; sourceTree = "<group>"; };
80B155F32F9E3FF90040F9D8 /* Ghostty.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = file; path = Ghostty.xctestplan; sourceTree = "<group>"; };
810ACC9F2E9D3301004F8F92 /* GhosttyUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GhosttyUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
8193244D2F24E6C000A9ED8F /* DockTilePlugin.plugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DockTilePlugin.plugin; sourceTree = BUILT_PRODUCTS_DIR; };
8F3A9B4B2FA6B88000A18D13 /* Ghostty.sdef */ = {isa = PBXFileReference; lastKnownFileType = text.sdef; path = Ghostty.sdef; sourceTree = "<group>"; };
@@ -337,6 +338,7 @@
A5B30528299BEAAA0047F10C = {
isa = PBXGroup;
children = (
80B155F32F9E3FF90040F9D8 /* Ghostty.xctestplan */,
A571AB1C2A206FC600248498 /* Ghostty-Info.plist */,
8F3A9B4B2FA6B88000A18D13 /* Ghostty.sdef */,
A5B30538299BEAAB0047F10C /* Assets.xcassets */,

View File

@@ -26,8 +26,13 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
shouldUseLaunchSchemeArgsEnv = "YES">
<TestPlans>
<TestPlanReference
reference = "container:Ghostty.xctestplan"
default = "YES">
</TestPlanReference>
</TestPlans>
<Testables>
<TestableReference
skipped = "NO"

49
macos/Ghostty.xctestplan Normal file
View File

@@ -0,0 +1,49 @@
{
"configurations" : [
{
"id" : "22895D97-CB9E-4452-A6AA-702CC0152032",
"name" : "Test Scheme Action",
"options" : {
}
}
],
"defaultOptions" : {
"commandLineArgumentEntries" : [
{
"argument" : "-NS🐞 YES"
}
],
"environmentVariableEntries" : [
{
"key" : "GHOSTTY_CONFIG_PATH",
"value" : "\/tmp\/Ghostty\/testing_config.ghostty"
}
],
"performanceAntipatternCheckerEnabled" : true,
"targetForVariableExpansion" : {
"containerPath" : "container:Ghostty.xcodeproj",
"identifier" : "A5B30530299BEAAA0047F10C",
"name" : "Ghostty"
}
},
"testTargets" : [
{
"parallelizable" : true,
"target" : {
"containerPath" : "container:Ghostty.xcodeproj",
"identifier" : "A54F45F22E1F047A0046BD5C",
"name" : "GhosttyTests"
}
},
{
"parallelizable" : true,
"target" : {
"containerPath" : "container:Ghostty.xcodeproj",
"identifier" : "810ACC9E2E9D3301004F8F92",
"name" : "GhosttyUITests"
}
}
],
"version" : 1
}

View File

@@ -8,7 +8,6 @@
import XCTest
final class GhosttyCommandPaletteTests: GhosttyCustomConfigCase {
override static var runsForEachTargetApplicationUIConfiguration: Bool { false }
@MainActor func testDismissingCommandPalette() async throws {
let app = try ghosttyApplication()
app.activate()

View File

@@ -23,38 +23,26 @@ class GhosttyCustomConfigCase: XCTestCase {
}
}
override class var runsForEachTargetApplicationUIConfiguration: Bool {
true
}
static let defaultsSuiteName: String = "GHOSTTY_UI_TESTS"
var configFile: URL?
private let configFile: URL = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
.appendingPathExtension("ghostty")
override func setUpWithError() throws {
continueAfterFailure = false
}
override func tearDown() async throws {
if let configFile {
try FileManager.default.removeItem(at: configFile)
}
try? FileManager.default.removeItem(at: configFile)
}
func updateConfig(_ newConfig: String) throws {
if configFile == nil {
let temporaryConfig = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
.appendingPathExtension("ghostty")
configFile = temporaryConfig
}
try newConfig.write(to: configFile!, atomically: true, encoding: .utf8)
try newConfig.write(to: configFile, atomically: true, encoding: .utf8)
}
func ghosttyApplication(defaultsSuite: String = GhosttyCustomConfigCase.defaultsSuiteName) throws -> XCUIApplication {
let app = XCUIApplication()
app.launchArguments.append(contentsOf: ["-ApplePersistenceIgnoreState", "YES"])
guard let configFile else {
return app
}
app.launchEnvironment["GHOSTTY_CONFIG_PATH"] = configFile.path
app.launchEnvironment["GHOSTTY_USER_DEFAULTS_SUITE"] = defaultsSuite
return app

View File

@@ -8,8 +8,6 @@
import XCTest
final class GhosttyMouseStateTests: GhosttyCustomConfigCase {
override static var runsForEachTargetApplicationUIConfiguration: Bool { false }
// https://github.com/ghostty-org/ghostty/pull/11276
@MainActor func testSelectionFocusChange() async throws {
let app = XCUIApplication()

View File

@@ -9,6 +9,10 @@ import AppKit
import XCTest
final class GhosttyThemeTests: GhosttyCustomConfigCase {
override static var runsForEachTargetApplicationUIConfiguration: Bool {
true
}
let windowTitle = "GhosttyThemeTests"
private func assertTitlebarAppearance(
_ appearance: XCUIDevice.Appearance,

View File

@@ -8,8 +8,6 @@
import XCTest
final class GhosttyWindowPositionUITests: GhosttyCustomConfigCase {
override static var runsForEachTargetApplicationUIConfiguration: Bool { false }
// MARK: - Cascading
@MainActor func testWindowCascading() async throws {