Skip to content

Commit 26da77e

Browse files
committed
Add Intel Cmd+D smoke test
1 parent 22c50a4 commit 26da77e

5 files changed

Lines changed: 129 additions & 9 deletions

File tree

.github/workflows/ci-macos-compat.yml

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,17 @@ jobs:
1717
- os: warp-macos-15-arm64-6x
1818
timeout: 30
1919
smoke: true
20+
ui_smoke_test: ""
21+
skip_zig: false
22+
- os: macos-15-intel
23+
timeout: 35
24+
smoke: false
25+
ui_smoke_test: IntelCmdDSmokeUITests
2026
skip_zig: false
2127
- os: warp-macos-26-arm64-6x
2228
timeout: 30
2329
smoke: false
30+
ui_smoke_test: ""
2431
skip_zig: true # zig 0.15.2 MachO linker can't resolve libSystem on macOS 26
2532
runs-on: ${{ matrix.os }}
2633
timeout-minutes: ${{ matrix.timeout }}
@@ -74,12 +81,22 @@ jobs:
7481
if command -v zig >/dev/null 2>&1 && zig version 2>/dev/null | grep -q "^${ZIG_REQUIRED}"; then
7582
echo "zig ${ZIG_REQUIRED} already installed"
7683
else
84+
ARCH="$(uname -m)"
85+
case "$ARCH" in
86+
arm64) ZIG_ARCH="aarch64" ;;
87+
x86_64) ZIG_ARCH="x86_64" ;;
88+
*)
89+
echo "Unsupported macOS runner architecture: $ARCH" >&2
90+
exit 1
91+
;;
92+
esac
93+
ARCHIVE="zig-${ZIG_ARCH}-macos-${ZIG_REQUIRED}"
7794
echo "Installing zig ${ZIG_REQUIRED} from tarball"
78-
curl -fSL "https://ziglang.org/download/${ZIG_REQUIRED}/zig-aarch64-macos-${ZIG_REQUIRED}.tar.xz" -o /tmp/zig.tar.xz
95+
curl -fSL "https://ziglang.org/download/${ZIG_REQUIRED}/${ARCHIVE}.tar.xz" -o /tmp/zig.tar.xz
7996
tar xf /tmp/zig.tar.xz -C /tmp
8097
sudo mkdir -p /usr/local/bin /usr/local/lib
81-
sudo cp -f /tmp/zig-aarch64-macos-${ZIG_REQUIRED}/zig /usr/local/bin/zig
82-
sudo cp -rf /tmp/zig-aarch64-macos-${ZIG_REQUIRED}/lib /usr/local/lib/zig
98+
sudo cp -f "/tmp/${ARCHIVE}/zig" /usr/local/bin/zig
99+
sudo cp -rf "/tmp/${ARCHIVE}/lib" /usr/local/lib/zig
83100
export PATH="/usr/local/bin:$PATH"
84101
zig version
85102
fi
@@ -166,7 +183,7 @@ jobs:
166183
fi
167184
168185
- name: Create virtual display
169-
if: matrix.smoke
186+
if: matrix.smoke || matrix.ui_smoke_test != ''
170187
run: |
171188
set -euo pipefail
172189
echo "=== Display before ==="
@@ -197,3 +214,16 @@ jobs:
197214
set -euo pipefail
198215
chmod +x scripts/smoke-test-ci.sh
199216
scripts/smoke-test-ci.sh
217+
218+
- name: Run Intel Cmd+D smoke UI test
219+
if: matrix.ui_smoke_test != ''
220+
run: |
221+
set -euo pipefail
222+
SOURCE_PACKAGES_DIR="$PWD/.ci-source-packages"
223+
xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux -configuration Debug \
224+
-clonedSourcePackagesDirPath "$SOURCE_PACKAGES_DIR" \
225+
-disableAutomaticPackageResolution \
226+
-destination "platform=macOS" \
227+
-maximum-test-execution-time-allowance 120 \
228+
-only-testing:cmuxUITests/${{ matrix.ui_smoke_test }} \
229+
test

.github/workflows/test-e2e.yml

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@ on:
2020
default: true
2121
type: boolean
2222
runner:
23-
description: "Runner OS (Depot runners for GUI activation support)"
23+
description: "Runner OS"
2424
required: false
2525
default: "depot-macos-latest"
2626
type: choice
2727
options:
2828
- depot-macos-latest
2929
- depot-macos-14
30+
- macos-15-intel
3031

3132
jobs:
3233
e2e:
@@ -97,12 +98,22 @@ jobs:
9798
if command -v zig >/dev/null 2>&1 && zig version 2>/dev/null | grep -q "^${ZIG_REQUIRED}"; then
9899
echo "zig ${ZIG_REQUIRED} already installed"
99100
else
101+
ARCH="$(uname -m)"
102+
case "$ARCH" in
103+
arm64) ZIG_ARCH="aarch64" ;;
104+
x86_64) ZIG_ARCH="x86_64" ;;
105+
*)
106+
echo "Unsupported macOS runner architecture: $ARCH" >&2
107+
exit 1
108+
;;
109+
esac
110+
ARCHIVE="zig-${ZIG_ARCH}-macos-${ZIG_REQUIRED}"
100111
echo "Installing zig ${ZIG_REQUIRED} from tarball"
101-
curl -fSL "https://ziglang.org/download/${ZIG_REQUIRED}/zig-aarch64-macos-${ZIG_REQUIRED}.tar.xz" -o /tmp/zig.tar.xz
112+
curl -fSL "https://ziglang.org/download/${ZIG_REQUIRED}/${ARCHIVE}.tar.xz" -o /tmp/zig.tar.xz
102113
tar xf /tmp/zig.tar.xz -C /tmp
103114
sudo mkdir -p /usr/local/bin /usr/local/lib
104-
sudo cp -f /tmp/zig-aarch64-macos-${ZIG_REQUIRED}/zig /usr/local/bin/zig
105-
sudo cp -rf /tmp/zig-aarch64-macos-${ZIG_REQUIRED}/lib /usr/local/lib/zig
115+
sudo cp -f "/tmp/${ARCHIVE}/zig" /usr/local/bin/zig
116+
sudo cp -rf "/tmp/${ARCHIVE}/lib" /usr/local/lib/zig
106117
export PATH="/usr/local/bin:$PATH"
107118
zig version
108119
fi

GhosttyTabs.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
84E00D47E4584162AE53BC8D /* xterm-ghostty in Resources */ = {isa = PBXBuildFile; fileRef = B2E7294509CC42FE9191870E /* xterm-ghostty */; };
7979
A5002000 /* THIRD_PARTY_LICENSES.md in Resources */ = {isa = PBXBuildFile; fileRef = A5002001 /* THIRD_PARTY_LICENSES.md */; };
8080
B9000012A1B2C3D4E5F60719 /* AutomationSocketUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9000011A1B2C3D4E5F60719 /* AutomationSocketUITests.swift */; };
81+
C9100000A1B2C3D4E5F60718 /* IntelCmdDSmokeUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9100001A1B2C3D4E5F60718 /* IntelCmdDSmokeUITests.swift */; };
8182
B8F266236A1A3D9A45BD840F /* SidebarResizeUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 818DBCD4AB69EB72573E8138 /* SidebarResizeUITests.swift */; };
8283
B8F266246A1A3D9A45BD840F /* SidebarHelpMenuUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8F266256A1A3D9A45BD840F /* SidebarHelpMenuUITests.swift */; };
8384
B8F266266A1A3D9A45BD840F /* DisplayResolutionRegressionUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8F266276A1A3D9A45BD840F /* DisplayResolutionRegressionUITests.swift */; };
@@ -251,6 +252,7 @@
251252
B9000001A1B2C3D4E5F60719 /* cmux.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = cmux.swift; sourceTree = "<group>"; };
252253
B9000004A1B2C3D4E5F60719 /* cmux */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = cmux; sourceTree = BUILT_PRODUCTS_DIR; };
253254
B9000011A1B2C3D4E5F60719 /* AutomationSocketUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutomationSocketUITests.swift; sourceTree = "<group>"; };
255+
C9100001A1B2C3D4E5F60718 /* IntelCmdDSmokeUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntelCmdDSmokeUITests.swift; sourceTree = "<group>"; };
254256
B9000013A1B2C3D4E5F60719 /* JumpToUnreadUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JumpToUnreadUITests.swift; sourceTree = "<group>"; };
255257
B9000016A1B2C3D4E5F60719 /* MultiWindowNotificationsUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiWindowNotificationsUITests.swift; sourceTree = "<group>"; };
256258
B9000019A1B2C3D4E5F60719 /* CloseWorkspaceConfirmDialogUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloseWorkspaceConfirmDialogUITests.swift; sourceTree = "<group>"; };
@@ -498,6 +500,7 @@
498500
isa = PBXGroup;
499501
children = (
500502
B9000011A1B2C3D4E5F60719 /* AutomationSocketUITests.swift */,
503+
C9100001A1B2C3D4E5F60718 /* IntelCmdDSmokeUITests.swift */,
501504
B9000013A1B2C3D4E5F60719 /* JumpToUnreadUITests.swift */,
502505
B9000022A1B2C3D4E5F60719 /* CloseWorkspaceCmdDUITests.swift */,
503506
B9000019A1B2C3D4E5F60719 /* CloseWorkspaceConfirmDialogUITests.swift */,
@@ -761,6 +764,7 @@
761764
buildActionMask = 2147483647;
762765
files = (
763766
B9000012A1B2C3D4E5F60719 /* AutomationSocketUITests.swift in Sources */,
767+
C9100000A1B2C3D4E5F60718 /* IntelCmdDSmokeUITests.swift in Sources */,
764768
B9000014A1B2C3D4E5F60719 /* JumpToUnreadUITests.swift in Sources */,
765769
B900001AA1B2C3D4E5F60719 /* CloseWorkspaceConfirmDialogUITests.swift in Sources */,
766770
B9000023A1B2C3D4E5F60719 /* CloseWorkspaceCmdDUITests.swift in Sources */,
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import XCTest
2+
3+
final class IntelCmdDSmokeUITests: XCTestCase {
4+
private let launchTag = "ui-tests-intel-cmd-d-smoke"
5+
6+
override func setUp() {
7+
super.setUp()
8+
continueAfterFailure = false
9+
}
10+
11+
func testLaunchAndCmdDDoesNotCrash() {
12+
let app = XCUIApplication()
13+
app.launchEnvironment["CMUX_TAG"] = launchTag
14+
launchAndEnsureStarted(app)
15+
16+
XCTAssertTrue(
17+
waitForWindowCount(app: app, atLeast: 1, timeout: 12.0),
18+
"Expected app to open a window before Cmd+D. state=\(app.state.rawValue)"
19+
)
20+
21+
app.typeKey("d", modifierFlags: [.command])
22+
23+
XCTAssertTrue(
24+
waitForWindowCount(app: app, atLeast: 1, timeout: 5.0),
25+
"Expected app window to stay open after Cmd+D. state=\(app.state.rawValue)"
26+
)
27+
XCTAssertTrue(
28+
waitForAppToKeepRunning(app: app, timeout: 5.0),
29+
"Expected app to keep running after Cmd+D. state=\(app.state.rawValue)"
30+
)
31+
}
32+
33+
private func launchAndEnsureStarted(_ app: XCUIApplication) {
34+
let options = XCTExpectedFailure.Options()
35+
options.isStrict = false
36+
XCTExpectFailure("App activation may fail on headless CI runners", options: options) {
37+
app.launch()
38+
}
39+
40+
if app.state == .runningForeground || app.state == .runningBackground {
41+
return
42+
}
43+
44+
XCTFail("App failed to start. state=\(app.state.rawValue)")
45+
}
46+
47+
private func waitForWindowCount(app: XCUIApplication, atLeast count: Int, timeout: TimeInterval) -> Bool {
48+
let expectation = XCTNSPredicateExpectation(
49+
predicate: NSPredicate { _, _ in
50+
app.windows.count >= count
51+
},
52+
object: NSObject()
53+
)
54+
return XCTWaiter().wait(for: [expectation], timeout: timeout) == .completed
55+
}
56+
57+
private func waitForAppToKeepRunning(app: XCUIApplication, timeout: TimeInterval) -> Bool {
58+
let expectation = XCTNSPredicateExpectation(
59+
predicate: NSPredicate { _, _ in
60+
app.state != .notRunning
61+
},
62+
object: NSObject()
63+
)
64+
return XCTWaiter().wait(for: [expectation], timeout: timeout) == .completed
65+
}
66+
}

scripts/run-e2e.sh

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ REF=""
1616
WAIT=false
1717
RECORD_VIDEO=true
1818
TIMEOUT=120
19+
RUNNER=""
1920

2021
usage() {
2122
cat <<EOF
@@ -28,6 +29,7 @@ Options:
2829
--ref <ref> Branch or SHA to test (default: current branch)
2930
--wait Wait for the run to complete and print result
3031
--no-video Disable video recording
32+
--runner <name> Runner label (e.g. macos-15-intel)
3133
--timeout <sec> Per-test timeout in seconds (default: 120)
3234
-h, --help Show this help
3335
EOF
@@ -55,6 +57,10 @@ while [ $# -gt 0 ]; do
5557
RECORD_VIDEO=false
5658
shift
5759
;;
60+
--runner)
61+
RUNNER="$2"
62+
shift 2
63+
;;
5864
--timeout)
5965
TIMEOUT="$2"
6066
shift 2
@@ -71,8 +77,11 @@ FIELDS=(-f "test_filter=$TEST_FILTER" -f "record_video=$RECORD_VIDEO" -f "test_t
7177
if [ -n "$REF" ]; then
7278
FIELDS+=(-f "ref=$REF")
7379
fi
80+
if [ -n "$RUNNER" ]; then
81+
FIELDS+=(-f "runner=$RUNNER")
82+
fi
7483

75-
echo "Triggering $WORKFLOW with test_filter=$TEST_FILTER ref=${REF:-<default>} video=$RECORD_VIDEO timeout=$TIMEOUT"
84+
echo "Triggering $WORKFLOW with test_filter=$TEST_FILTER ref=${REF:-<default>} runner=${RUNNER:-<default>} video=$RECORD_VIDEO timeout=$TIMEOUT"
7685
gh workflow run "$WORKFLOW" --repo "$REPO" "${FIELDS[@]}"
7786

7887
# Wait a moment for the run to register

0 commit comments

Comments
 (0)