Skip to content

Commit f87c037

Browse files
committed
feat(tests): implement reliable CI authentication automation
- Add browser process isolation workaround for Unity Passport authentication - Configure protocol associations and browser permissions programmatically - Handle both full login flows and cached session scenarios - Fix MailSlurp API URL configuration for OTP retrieval - Implement controlled logout process to prevent app crashes - Increase AltDriver timeouts for CI stability
1 parent a91a6d0 commit f87c037

File tree

6 files changed

+648
-49
lines changed

6 files changed

+648
-49
lines changed

sample/.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
**/Payload.ipa
22
**/logFile.log
3-
**/local.log
3+
**/local.log
4+
venv/

sample/Packages/packages-lock.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@
3636
"source": "local",
3737
"dependencies": {
3838
"com.unity.nuget.newtonsoft-json": "3.2.0",
39-
"com.cysharp.unitask": "2.3.3"
39+
"com.cysharp.unitask": "2.3.1",
40+
"com.unity.modules.unitywebrequest": "1.0.0",
41+
"com.unity.modules.jsonserialize": "1.0.0",
42+
"com.unity.modules.androidjni": "1.0.0"
4043
}
4144
},
4245
"com.unity.ai.navigation": {

sample/Tests/src/fetch_otp.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
def get_mailslurp_client():
1010
configuration = mailslurp_client.Configuration()
1111
configuration.api_key['x-api-key'] = os.getenv('MAILSLURP_API_KEY')
12+
# Use the correct API base URL as per official docs
13+
configuration.host = "https://api.mailslurp.com"
1214
api_client = mailslurp_client.ApiClient(configuration)
1315
waitfor_controller = WaitForControllerApi(api_client)
1416
return waitfor_controller
@@ -23,7 +25,7 @@ def extract_otp_from_email(email_body):
2325

2426
def fetch_code():
2527
waitfor_controller = get_mailslurp_client()
26-
email = waitfor_controller.wait_for_latest_email(inbox_id=INBOX_ID, timeout=30000, unread_only=True)
28+
email = waitfor_controller.wait_for_latest_email(inbox_id=INBOX_ID, timeout=60000, unread_only=True)
2729
if email:
2830
otp = extract_otp_from_email(email.body)
2931
return otp

sample/Tests/test/test_windows.py

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@
33
from alttester import *
44

55
from test import TestConfig, UnityTest
6-
from test_windows_helpers import login, open_sample_app, launch_browser, bring_sample_app_to_foreground, stop_browser, stop_sample_app
6+
from test_windows_helpers import login, open_sample_app, launch_browser, bring_sample_app_to_foreground, stop_browser, stop_sample_app, logout_with_controlled_browser
77

88
class WindowsTest(UnityTest):
99

1010
@classmethod
1111
def setUpClass(cls):
1212
open_sample_app()
1313
time.sleep(5) # Give time for the app to open
14-
super().setUpClass()
14+
# Initialize AltDriver with longer timeout for flaky CI environment
15+
cls.altdriver = AltDriver(timeout=120) # 120 seconds instead of default 20
1516

1617
@classmethod
1718
def tearDownClass(cls):
@@ -23,7 +24,8 @@ def restart_app_and_altdriver(self):
2324
stop_sample_app()
2425
open_sample_app()
2526
time.sleep(5) # Give time for the app to open
26-
self.start_altdriver()
27+
# Use same timeout as setUpClass
28+
self.__class__.altdriver = AltDriver(timeout=120)
2729

2830
def login(self):
2931
# Wait for unauthenticated screen
@@ -83,21 +85,49 @@ def login(self):
8385
raise SystemExit(f"Failed to reset app {err}")
8486

8587
def test_1_login(self):
88+
print("=" * 60)
89+
print("STARTING TEST: test_1_login")
90+
print("=" * 60)
8691
self.login()
92+
print("COMPLETED TEST: test_1_login")
93+
print("=" * 60)
8794

8895
def test_2_other_functions(self):
96+
print("=" * 60)
97+
print("STARTING TEST: test_2_other_functions")
98+
print("=" * 60)
8999
self.test_0_other_functions()
100+
print("COMPLETED TEST: test_2_other_functions")
101+
print("=" * 60)
90102

91103
def test_3_passport_functions(self):
104+
print("=" * 60)
105+
print("STARTING TEST: test_3_passport_functions")
106+
print("=" * 60)
92107
self.test_1_passport_functions()
108+
print("COMPLETED TEST: test_3_passport_functions")
109+
print("=" * 60)
93110

94111
def test_4_imx_functions(self):
112+
print("=" * 60)
113+
print("STARTING TEST: test_4_imx_functions")
114+
print("=" * 60)
95115
self.test_2_imx_functions()
116+
print("COMPLETED TEST: test_4_imx_functions")
117+
print("=" * 60)
96118

97119
def test_5_zkevm_functions(self):
120+
print("=" * 60)
121+
print("STARTING TEST: test_5_zkevm_functions")
122+
print("=" * 60)
98123
self.test_3_zkevm_functions()
124+
print("COMPLETED TEST: test_5_zkevm_functions")
125+
print("=" * 60)
99126

100127
def test_6_relogin(self):
128+
print("=" * 60)
129+
print("STARTING TEST: test_6_relogin")
130+
print("=" * 60)
101131
self.restart_app_and_altdriver()
102132

103133
# Relogin
@@ -117,8 +147,14 @@ def test_6_relogin(self):
117147
self.get_altdriver().find_object(By.NAME, "ConnectBtn").tap()
118148
time.sleep(5)
119149
self.assertEqual("Connected to IMX", output.get_text())
150+
151+
print("COMPLETED TEST: test_6_relogin")
152+
print("=" * 60)
120153

121154
def test_7_reconnect_connect_imx(self):
155+
print("=" * 60)
156+
print("STARTING TEST: test_7_reconnect_connect_imx")
157+
print("=" * 60)
122158
self.restart_app_and_altdriver()
123159

124160
# Reconnect
@@ -143,14 +179,33 @@ def test_7_reconnect_connect_imx(self):
143179
launch_browser()
144180
bring_sample_app_to_foreground()
145181
self.get_altdriver().find_object(By.NAME, "LogoutBtn").tap()
182+
183+
# Use controlled browser logout instead of waiting for scene change
184+
logout_with_controlled_browser()
185+
186+
# Give Unity time to process the logout callback
146187
time.sleep(5)
147188
bring_sample_app_to_foreground()
148189

149190
# Wait for authenticated screen
150191
self.get_altdriver().wait_for_current_scene_to_be("UnauthenticatedScene")
192+
151193
stop_browser()
152194
print("Logged out")
153195

196+
print("COMPLETED TEST: test_7_reconnect_connect_imx")
197+
print("=" * 60)
198+
199+
def test_8_connect_imx(self):
200+
print("=" * 60)
201+
print("STARTING TEST: test_8_connect_imx")
202+
print("=" * 60)
203+
# Ensure clean state regardless of previous tests
204+
self.restart_app_and_altdriver()
205+
206+
# Wait for initial scene
207+
self.get_altdriver().wait_for_current_scene_to_be("UnauthenticatedScene")
208+
154209
# Connect IMX
155210
print("Logging in and connecting to IMX...")
156211
launch_browser()
@@ -178,10 +233,13 @@ def test_7_reconnect_connect_imx(self):
178233
bring_sample_app_to_foreground()
179234
print("Logging out...")
180235
self.get_altdriver().find_object(By.NAME, "LogoutBtn").tap()
236+
logout_with_controlled_browser()
181237
time.sleep(5)
182238
bring_sample_app_to_foreground()
183239

184240
# Wait for authenticated screen
185241
self.get_altdriver().wait_for_current_scene_to_be("UnauthenticatedScene")
186242
stop_browser()
187243
print("Logged out")
244+
print("COMPLETED TEST: test_8_connect_imx")
245+
print("=" * 60)

0 commit comments

Comments
 (0)