Skip to content

Commit bd6efad

Browse files
authored
Merge pull request #668 from immutable/test/mac-ui-tests
Improve UI tests
2 parents ee39ad6 + c01b9ac commit bd6efad

2 files changed

Lines changed: 95 additions & 21 deletions

File tree

.github/workflows/ui-tests.yml

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ jobs:
8989
name: Build & Test Unity 6 macOS 🛠️🧪
9090
runs-on: [self-hosted, macOS]
9191
concurrency:
92-
group: ui-tests-email-inbox-macos-unity6
92+
group: ui-tests-email-inbox-macos
9393
cancel-in-progress: false # Let tests complete rather than cancelling
9494
if: github.event_name != 'workflow_dispatch' || github.event.inputs.targetPlatform == 'All' || github.event.inputs.targetPlatform == 'StandaloneOSX-Unity6'
9595
steps:
@@ -133,8 +133,10 @@ jobs:
133133
ls -la sample-unity6/Tests/
134134
- name: Create temporary keychain
135135
run: |
136-
security list-keychains
136+
# Clean up any leftover temporary keychain from a previous failed run
137+
security default-keychain -s ~/Library/Keychains/login.keychain-db || true
137138
security delete-keychain temporary || true
139+
security list-keychains -d user -s ~/Library/Keychains/login.keychain-db
138140
security list-keychains
139141
security create-keychain -p "" temporary
140142
security default-keychain -s temporary
@@ -156,6 +158,12 @@ jobs:
156158
BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
157159
working-directory: sample-unity6/Tests
158160
run: pytest -xs test/test_mac.py::MacTest
161+
- name: Close Brave Browser
162+
if: always()
163+
run: |
164+
osascript -e 'tell application "Brave Browser" to quit' 2>/dev/null || true
165+
sleep 2
166+
pkill -f "Brave Browser" 2>/dev/null || true
159167
- name: Remove temporary keychain
160168
if: always()
161169
run: |
@@ -181,7 +189,7 @@ jobs:
181189
name: Build & Test Unity 6 Windows 🛠️🧪
182190
runs-on: [self-hosted, windows]
183191
concurrency:
184-
group: ui-tests-email-inbox-windows-unity6
192+
group: ui-tests-email-inbox-windows
185193
cancel-in-progress: false # Let tests complete rather than cancelling
186194
if: github.event_name != 'workflow_dispatch' || github.event.inputs.targetPlatform == 'All' || github.event.inputs.targetPlatform == 'StandaloneWindows64-Unity6'
187195
steps:
@@ -359,8 +367,10 @@ jobs:
359367
- name: Create temporary keychain
360368
if: contains(matrix.targetPlatform, 'StandaloneOSX') && (github.event_name != 'workflow_dispatch' || github.event.inputs.targetPlatform == 'All' || github.event.inputs.targetPlatform == matrix.targetPlatform)
361369
run: |
362-
security list-keychains
370+
# Clean up any leftover temporary keychain from a previous failed run
371+
security default-keychain -s ~/Library/Keychains/login.keychain-db || true
363372
security delete-keychain temporary || true
373+
security list-keychains -d user -s ~/Library/Keychains/login.keychain-db
364374
security list-keychains
365375
security create-keychain -p "" temporary
366376
security default-keychain -s temporary
@@ -396,6 +406,12 @@ jobs:
396406
BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
397407
working-directory: ${{ matrix.projectPath }}/Tests
398408
run: ${{ matrix.test_script }}
409+
- name: Close Brave Browser
410+
if: contains(matrix.targetPlatform, 'StandaloneOSX') && always()
411+
run: |
412+
osascript -e 'tell application "Brave Browser" to quit' 2>/dev/null || true
413+
sleep 2
414+
pkill -f "Brave Browser" 2>/dev/null || true
399415
- name: Remove temporary keychain
400416
if: contains(matrix.targetPlatform, 'StandaloneOSX') && (github.event_name != 'workflow_dispatch' || github.event.inputs.targetPlatform == 'All' || github.event.inputs.targetPlatform == matrix.targetPlatform)
401417
run: |

sample/Tests/test/test_mac.py

Lines changed: 75 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,53 @@ def tearDownClass(cls):
3737
cls.altdriver.stop()
3838
cls.stop_browser()
3939

40+
@classmethod
41+
def ensure_browser_clean(cls):
42+
"""Kill any running Brave instance and delete session restore files.
43+
Call this before any action that may open the browser (login, logout, etc.)
44+
so Brave always starts with a clean slate."""
45+
result = subprocess.run(["pgrep", "-f", "Brave Browser"], capture_output=True, text=True)
46+
if result.returncode == 0:
47+
print("Brave Browser already running, stopping it...")
48+
subprocess.run(["osascript", "-e", 'tell application "Brave Browser" to quit'],
49+
check=False, capture_output=True, timeout=5)
50+
time.sleep(2)
51+
subprocess.run(["pkill", "-f", "Brave Browser"], check=False, capture_output=True)
52+
time.sleep(2)
53+
print("Existing Brave Browser stopped")
54+
55+
brave_profile = os.path.expanduser(
56+
"~/Library/Application Support/BraveSoftware/Brave-Browser/Default"
57+
)
58+
59+
# Clear session data (Brave stores sessions in Sessions/ directory)
60+
import shutil
61+
sessions_dir = os.path.join(brave_profile, "Sessions")
62+
if os.path.isdir(sessions_dir):
63+
shutil.rmtree(sessions_dir, ignore_errors=True)
64+
print("Removed Sessions directory")
65+
session_storage_dir = os.path.join(brave_profile, "Session Storage")
66+
if os.path.isdir(session_storage_dir):
67+
shutil.rmtree(session_storage_dir, ignore_errors=True)
68+
print("Removed Session Storage directory")
69+
70+
# Patch Preferences so Brave thinks it shut down cleanly,
71+
# otherwise it forces session restore on "Crashed" exit_type
72+
prefs_path = os.path.join(brave_profile, "Preferences")
73+
try:
74+
if os.path.exists(prefs_path):
75+
import json
76+
with open(prefs_path, "r") as f:
77+
prefs = json.load(f)
78+
prefs.setdefault("profile", {})["exit_type"] = "Normal"
79+
prefs["profile"]["exited_cleanly"] = True
80+
prefs.setdefault("session", {})["restore_on_startup"] = 5
81+
with open(prefs_path, "w") as f:
82+
json.dump(prefs, f)
83+
print("Patched Preferences: exit_type=Normal, restore_on_startup=NewTab")
84+
except Exception as e:
85+
print(f"Could not patch Preferences: {e}")
86+
4087
@classmethod
4188
def launch_browser(cls):
4289
print("Starting Browser...")
@@ -54,18 +101,33 @@ def launch_browser(cls):
54101
print("Brave Browser executable not found.")
55102
exit(1)
56103

104+
cls.ensure_browser_clean()
105+
57106
subprocess.Popen([
58107
browser_path,
59108
"--remote-debugging-port=9222",
60109
"--no-first-run",
61-
"--no-default-browser-check"
110+
"--no-default-browser-check",
111+
"--disable-session-crashed-bubble",
112+
"--restore-last-session=false"
62113
])
63114

64-
# Give Brave more time to fully initialize remote debugging
65115
print("Waiting for Brave to fully initialize...")
66116
time.sleep(10)
67-
68-
# Verify remote debugging is accessible
117+
118+
# Dismiss any macOS keychain dialog from a previous failed cleanup
119+
subprocess.run([
120+
"osascript", "-e",
121+
'tell application "System Events"\n'
122+
'if exists (process "SecurityAgent") then\n'
123+
'tell process "SecurityAgent"\n'
124+
'click button "OK" of window 1\n'
125+
'end tell\n'
126+
'end if\n'
127+
'end tell'
128+
], check=False, capture_output=True, timeout=5)
129+
time.sleep(1)
130+
69131
try:
70132
import urllib.request
71133
with urllib.request.urlopen("http://127.0.0.1:9222/json", timeout=5) as response:
@@ -79,26 +141,23 @@ def launch_browser(cls):
79141
def stop_browser(cls):
80142
print("Stopping Brave Browser...")
81143
try:
82-
# First try graceful shutdown using AppleScript
83144
subprocess.run([
84-
"osascript", "-e",
145+
"osascript", "-e",
85146
'tell application "Brave Browser" to quit'
86-
], check=False, capture_output=True)
147+
], check=False, capture_output=True, timeout=10)
87148
time.sleep(2)
88-
89-
# Check if still running, then force kill
90-
result = subprocess.run(["pgrep", "-f", "Brave Browser"],
91-
capture_output=True, text=True)
149+
150+
result = subprocess.run(["pgrep", "-f", "Brave Browser"],
151+
capture_output=True, text=True)
92152
if result.returncode == 0:
93-
# Still running, force kill
94-
subprocess.run(["pkill", "-f", "Brave Browser"],
95-
check=False, capture_output=True)
153+
subprocess.run(["pkill", "-f", "Brave Browser"],
154+
check=False, capture_output=True)
96155
print("Killed Brave Browser processes")
97-
156+
98157
print("Brave Browser has been closed.")
99158
except Exception as e:
100159
print("Brave Browser might not be running.")
101-
160+
102161
time.sleep(3)
103162
print("Stopped Brave Browser")
104163

@@ -215,7 +274,6 @@ def test_1_login(self):
215274
self.altdriver.wait_for_current_scene_to_be("AuthenticatedScene")
216275
print("Re-logged in")
217276

218-
# Logout
219277
self.logout()
220278
print("Logged out and successfully reset app")
221279
time.sleep(2)

0 commit comments

Comments
 (0)