Skip to content

Commit 53eb7a4

Browse files
committed
Add UITest targets and fix build version handling
- Add UITest targets for iOS and macOS in project.yml - Add ScreenshotTests.swift for automated screenshot capture - Fix Info.plist: use $(CURRENT_PROJECT_VERSION) instead of hardcoded - Update Xcode project and schemes - Update .gitignore for Xcode workspace settings
1 parent 2e66f11 commit 53eb7a4

8 files changed

Lines changed: 486 additions & 30 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ venv/
5353
*.xcarchive
5454
DerivedData/
5555
xcuserdata/
56+
**/*.xcworkspace/xcshareddata/
5657

5758
# IDE
5859
.idea/
@@ -72,3 +73,4 @@ CortexOSApp/generate_icons.py
7273
CortexOSApp/screenshot_results/
7374
CortexOSApp/store_assets/marketing/
7475
CortexOSApp/store_assets/**/*_raw.png
76+
scripts/capture_screenshots.sh

CortexOSApp/CortexOS.xcodeproj/project.pbxproj

Lines changed: 202 additions & 2 deletions
Large diffs are not rendered by default.

CortexOSApp/CortexOS.xcodeproj/xcshareddata/xcschemes/CortexOS-iOS.xcscheme

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
33
LastUpgradeVersion = "1600"
4-
version = "1.7">
4+
version = "1.3">
55
<BuildAction
66
parallelizeBuildables = "YES"
7-
buildImplicitDependencies = "YES"
8-
runPostActionsOnFailure = "NO">
7+
buildImplicitDependencies = "YES">
98
<BuildActionEntries>
109
<BuildActionEntry
1110
buildForTesting = "YES"
@@ -16,32 +15,53 @@
1615
<BuildableReference
1716
BuildableIdentifier = "primary"
1817
BlueprintIdentifier = "9289113ECDE79DBEECBD7E8E"
19-
BuildableName = "CortexOS-iOS.app"
18+
BuildableName = "CortexOS.app"
2019
BlueprintName = "CortexOS-iOS"
2120
ReferencedContainer = "container:CortexOS.xcodeproj">
2221
</BuildableReference>
2322
</BuildActionEntry>
23+
<BuildActionEntry
24+
buildForTesting = "YES"
25+
buildForRunning = "NO"
26+
buildForProfiling = "NO"
27+
buildForArchiving = "NO"
28+
buildForAnalyzing = "NO">
29+
<BuildableReference
30+
BuildableIdentifier = "primary"
31+
BlueprintIdentifier = "0DA937660E7FA94BC5AA74AC"
32+
BuildableName = "CortexOS-iOS-UITests.xctest"
33+
BlueprintName = "CortexOS-iOS-UITests"
34+
ReferencedContainer = "container:CortexOS.xcodeproj">
35+
</BuildableReference>
36+
</BuildActionEntry>
2437
</BuildActionEntries>
2538
</BuildAction>
2639
<TestAction
2740
buildConfiguration = "Debug"
2841
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
2942
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
30-
shouldUseLaunchSchemeArgsEnv = "YES"
31-
onlyGenerateCoverageForSpecifiedTargets = "NO">
43+
shouldUseLaunchSchemeArgsEnv = "YES">
3244
<MacroExpansion>
3345
<BuildableReference
3446
BuildableIdentifier = "primary"
3547
BlueprintIdentifier = "9289113ECDE79DBEECBD7E8E"
36-
BuildableName = "CortexOS-iOS.app"
48+
BuildableName = "CortexOS.app"
3749
BlueprintName = "CortexOS-iOS"
3850
ReferencedContainer = "container:CortexOS.xcodeproj">
3951
</BuildableReference>
4052
</MacroExpansion>
4153
<Testables>
54+
<TestableReference
55+
skipped = "NO">
56+
<BuildableReference
57+
BuildableIdentifier = "primary"
58+
BlueprintIdentifier = "0DA937660E7FA94BC5AA74AC"
59+
BuildableName = "CortexOS-iOS-UITests.xctest"
60+
BlueprintName = "CortexOS-iOS-UITests"
61+
ReferencedContainer = "container:CortexOS.xcodeproj">
62+
</BuildableReference>
63+
</TestableReference>
4264
</Testables>
43-
<CommandLineArguments>
44-
</CommandLineArguments>
4565
</TestAction>
4666
<LaunchAction
4767
buildConfiguration = "Debug"
@@ -58,13 +78,11 @@
5878
<BuildableReference
5979
BuildableIdentifier = "primary"
6080
BlueprintIdentifier = "9289113ECDE79DBEECBD7E8E"
61-
BuildableName = "CortexOS-iOS.app"
81+
BuildableName = "CortexOS.app"
6282
BlueprintName = "CortexOS-iOS"
6383
ReferencedContainer = "container:CortexOS.xcodeproj">
6484
</BuildableReference>
6585
</BuildableProductRunnable>
66-
<CommandLineArguments>
67-
</CommandLineArguments>
6886
</LaunchAction>
6987
<ProfileAction
7088
buildConfiguration = "Release"
@@ -77,7 +95,7 @@
7795
<BuildableReference
7896
BuildableIdentifier = "primary"
7997
BlueprintIdentifier = "9289113ECDE79DBEECBD7E8E"
80-
BuildableName = "CortexOS-iOS.app"
98+
BuildableName = "CortexOS.app"
8199
BlueprintName = "CortexOS-iOS"
82100
ReferencedContainer = "container:CortexOS.xcodeproj">
83101
</BuildableReference>

CortexOSApp/CortexOS.xcodeproj/xcshareddata/xcschemes/CortexOS-macOS.xcscheme

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
33
LastUpgradeVersion = "1600"
4-
version = "1.7">
4+
version = "1.3">
55
<BuildAction
66
parallelizeBuildables = "YES"
7-
buildImplicitDependencies = "YES"
8-
runPostActionsOnFailure = "NO">
7+
buildImplicitDependencies = "YES">
98
<BuildActionEntries>
109
<BuildActionEntry
1110
buildForTesting = "YES"
@@ -16,32 +15,53 @@
1615
<BuildableReference
1716
BuildableIdentifier = "primary"
1817
BlueprintIdentifier = "478B9E8325E8EDB61C4E58F1"
19-
BuildableName = "CortexOS-macOS.app"
18+
BuildableName = "CortexOS.app"
2019
BlueprintName = "CortexOS-macOS"
2120
ReferencedContainer = "container:CortexOS.xcodeproj">
2221
</BuildableReference>
2322
</BuildActionEntry>
23+
<BuildActionEntry
24+
buildForTesting = "YES"
25+
buildForRunning = "NO"
26+
buildForProfiling = "NO"
27+
buildForArchiving = "NO"
28+
buildForAnalyzing = "NO">
29+
<BuildableReference
30+
BuildableIdentifier = "primary"
31+
BlueprintIdentifier = "48566068873B85D9B4B03162"
32+
BuildableName = "CortexOS-macOS-UITests.xctest"
33+
BlueprintName = "CortexOS-macOS-UITests"
34+
ReferencedContainer = "container:CortexOS.xcodeproj">
35+
</BuildableReference>
36+
</BuildActionEntry>
2437
</BuildActionEntries>
2538
</BuildAction>
2639
<TestAction
2740
buildConfiguration = "Debug"
2841
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
2942
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
30-
shouldUseLaunchSchemeArgsEnv = "YES"
31-
onlyGenerateCoverageForSpecifiedTargets = "NO">
43+
shouldUseLaunchSchemeArgsEnv = "YES">
3244
<MacroExpansion>
3345
<BuildableReference
3446
BuildableIdentifier = "primary"
3547
BlueprintIdentifier = "478B9E8325E8EDB61C4E58F1"
36-
BuildableName = "CortexOS-macOS.app"
48+
BuildableName = "CortexOS.app"
3749
BlueprintName = "CortexOS-macOS"
3850
ReferencedContainer = "container:CortexOS.xcodeproj">
3951
</BuildableReference>
4052
</MacroExpansion>
4153
<Testables>
54+
<TestableReference
55+
skipped = "NO">
56+
<BuildableReference
57+
BuildableIdentifier = "primary"
58+
BlueprintIdentifier = "48566068873B85D9B4B03162"
59+
BuildableName = "CortexOS-macOS-UITests.xctest"
60+
BlueprintName = "CortexOS-macOS-UITests"
61+
ReferencedContainer = "container:CortexOS.xcodeproj">
62+
</BuildableReference>
63+
</TestableReference>
4264
</Testables>
43-
<CommandLineArguments>
44-
</CommandLineArguments>
4565
</TestAction>
4666
<LaunchAction
4767
buildConfiguration = "Debug"
@@ -58,13 +78,11 @@
5878
<BuildableReference
5979
BuildableIdentifier = "primary"
6080
BlueprintIdentifier = "478B9E8325E8EDB61C4E58F1"
61-
BuildableName = "CortexOS-macOS.app"
81+
BuildableName = "CortexOS.app"
6282
BlueprintName = "CortexOS-macOS"
6383
ReferencedContainer = "container:CortexOS.xcodeproj">
6484
</BuildableReference>
6585
</BuildableProductRunnable>
66-
<CommandLineArguments>
67-
</CommandLineArguments>
6886
</LaunchAction>
6987
<ProfileAction
7088
buildConfiguration = "Release"
@@ -77,7 +95,7 @@
7795
<BuildableReference
7896
BuildableIdentifier = "primary"
7997
BlueprintIdentifier = "478B9E8325E8EDB61C4E58F1"
80-
BuildableName = "CortexOS-macOS.app"
98+
BuildableName = "CortexOS.app"
8199
BlueprintName = "CortexOS-macOS"
82100
ReferencedContainer = "container:CortexOS.xcodeproj">
83101
</BuildableReference>
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
//
2+
// ScreenshotTests.swift
3+
// CortexOS
4+
//
5+
// Automated App Store screenshot capture.
6+
// Navigates through every key screen and saves a screenshot.
7+
//
8+
9+
import XCTest
10+
11+
final class ScreenshotTests: XCTestCase {
12+
let app = XCUIApplication()
13+
14+
override func setUpWithError() throws {
15+
continueAfterFailure = false
16+
app.launchArguments += ["-UITests", "-Screenshots"]
17+
app.launch()
18+
// Give the app time to fully render
19+
sleep(2)
20+
}
21+
22+
// MARK: - iOS Screenshots
23+
24+
#if os(iOS)
25+
func testCaptureFocusTab() throws {
26+
// Focus tab is the default landing screen
27+
let screenshot = app.screenshot()
28+
let attachment = XCTAttachment(screenshot: screenshot)
29+
attachment.name = "01_focus"
30+
attachment.lifetime = .keepAlways
31+
add(attachment)
32+
}
33+
34+
func testCaptureDecideTab() throws {
35+
// Tap the Decide tab
36+
let decideTab = app.tabBars.buttons["Decide"]
37+
XCTAssertTrue(decideTab.waitForExistence(timeout: 5))
38+
decideTab.tap()
39+
sleep(1)
40+
41+
let screenshot = app.screenshot()
42+
let attachment = XCTAttachment(screenshot: screenshot)
43+
attachment.name = "02_decide"
44+
attachment.lifetime = .keepAlways
45+
add(attachment)
46+
}
47+
48+
func testCaptureCaptureTab() throws {
49+
// Tap the Capture tab
50+
let captureTab = app.tabBars.buttons["Capture"]
51+
XCTAssertTrue(captureTab.waitForExistence(timeout: 5))
52+
captureTab.tap()
53+
sleep(1)
54+
55+
let screenshot = app.screenshot()
56+
let attachment = XCTAttachment(screenshot: screenshot)
57+
attachment.name = "03_capture"
58+
attachment.lifetime = .keepAlways
59+
add(attachment)
60+
}
61+
62+
func testCaptureSettings() throws {
63+
// Tap the gear icon to open Settings
64+
let settingsButton = app.navigationBars.buttons.matching(
65+
NSPredicate(format: "label CONTAINS[c] 'gear' OR label CONTAINS[c] 'settings' OR identifier CONTAINS[c] 'gear'")
66+
).firstMatch
67+
68+
if settingsButton.waitForExistence(timeout: 5) {
69+
settingsButton.tap()
70+
} else {
71+
// Try toolbar buttons
72+
let toolbarButtons = app.buttons
73+
for i in 0..<toolbarButtons.count {
74+
let btn = toolbarButtons.element(boundBy: i)
75+
if btn.label.lowercased().contains("gear") || btn.label.lowercased().contains("setting") {
76+
btn.tap()
77+
break
78+
}
79+
}
80+
}
81+
sleep(1)
82+
83+
let screenshot = app.screenshot()
84+
let attachment = XCTAttachment(screenshot: screenshot)
85+
attachment.name = "04_settings"
86+
attachment.lifetime = .keepAlways
87+
add(attachment)
88+
}
89+
#endif
90+
91+
// MARK: - macOS Screenshots
92+
93+
#if os(macOS)
94+
func testCaptureFocusSidebar() throws {
95+
// Focus is the default selection
96+
sleep(1)
97+
let screenshot = app.screenshot()
98+
let attachment = XCTAttachment(screenshot: screenshot)
99+
attachment.name = "01_focus"
100+
attachment.lifetime = .keepAlways
101+
add(attachment)
102+
}
103+
104+
func testCaptureInsightsSidebar() throws {
105+
let sidebar = app.outlines.firstMatch
106+
if sidebar.waitForExistence(timeout: 5) {
107+
let insightsCell = sidebar.cells.containing(
108+
NSPredicate(format: "label CONTAINS[c] 'Insights'")
109+
).firstMatch
110+
if insightsCell.waitForExistence(timeout: 3) {
111+
insightsCell.click()
112+
}
113+
}
114+
sleep(1)
115+
116+
let screenshot = app.screenshot()
117+
let attachment = XCTAttachment(screenshot: screenshot)
118+
attachment.name = "02_insights"
119+
attachment.lifetime = .keepAlways
120+
add(attachment)
121+
}
122+
123+
func testCaptureIngestSidebar() throws {
124+
let sidebar = app.outlines.firstMatch
125+
if sidebar.waitForExistence(timeout: 5) {
126+
let cell = sidebar.cells.containing(
127+
NSPredicate(format: "label CONTAINS[c] 'Ingest'")
128+
).firstMatch
129+
if cell.waitForExistence(timeout: 3) {
130+
cell.click()
131+
}
132+
}
133+
sleep(1)
134+
135+
let screenshot = app.screenshot()
136+
let attachment = XCTAttachment(screenshot: screenshot)
137+
attachment.name = "03_ingest"
138+
attachment.lifetime = .keepAlways
139+
add(attachment)
140+
}
141+
142+
func testCaptureMemorySidebar() throws {
143+
let sidebar = app.outlines.firstMatch
144+
if sidebar.waitForExistence(timeout: 5) {
145+
let cell = sidebar.cells.containing(
146+
NSPredicate(format: "label CONTAINS[c] 'Memory'")
147+
).firstMatch
148+
if cell.waitForExistence(timeout: 3) {
149+
cell.click()
150+
}
151+
}
152+
sleep(1)
153+
154+
let screenshot = app.screenshot()
155+
let attachment = XCTAttachment(screenshot: screenshot)
156+
attachment.name = "04_memory"
157+
attachment.lifetime = .keepAlways
158+
add(attachment)
159+
}
160+
161+
func testCaptureDecisionsSidebar() throws {
162+
let sidebar = app.outlines.firstMatch
163+
if sidebar.waitForExistence(timeout: 5) {
164+
let cell = sidebar.cells.containing(
165+
NSPredicate(format: "label CONTAINS[c] 'Decisions'")
166+
).firstMatch
167+
if cell.waitForExistence(timeout: 3) {
168+
cell.click()
169+
}
170+
}
171+
sleep(1)
172+
173+
let screenshot = app.screenshot()
174+
let attachment = XCTAttachment(screenshot: screenshot)
175+
attachment.name = "05_decisions"
176+
attachment.lifetime = .keepAlways
177+
add(attachment)
178+
}
179+
#endif
180+
}

CortexOSApp/iOS/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<key>CFBundleShortVersionString</key>
2020
<string>$(MARKETING_VERSION)</string>
2121
<key>CFBundleVersion</key>
22-
<string>202604021331</string>
22+
<string>$(CURRENT_PROJECT_VERSION)</string>
2323
<key>ITSAppUsesNonExemptEncryption</key>
2424
<false/>
2525
<key>UILaunchScreen</key>

0 commit comments

Comments
 (0)