Skip to content

Commit 0af90e3

Browse files
authored
Merge pull request #316 from immutable/feature/sdk-3372-connect-alttester
[SDK-3372]: Connect UI tests to the remote AltTester server
2 parents e939167 + 32cd2eb commit 0af90e3

14 files changed

+808
-41
lines changed

.github/workflows/ui-tests.yml

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ jobs:
3030
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
3131
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
3232
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
33-
ALTSERVER_HOST: 54.66.58.33
34-
ALTSERVER_PORT: 13000
3533
with:
3634
targetPlatform: StandaloneOSX
3735
projectPath: sample
@@ -44,7 +42,7 @@ jobs:
4442
path: sample/Builds/MacOS
4543
test:
4644
name: Run UI tests on AltTester 🧪
47-
runs-on: macos-latest
45+
runs-on: self-hosted
4846
needs: build
4947
steps:
5048
- uses: actions/checkout@v3
@@ -53,21 +51,19 @@ jobs:
5351
- uses: actions/download-artifact@v4
5452
with:
5553
name: Build-StandaloneOSX
56-
- name: Open application
57-
run: |
58-
export RUN_IN_BROWSERSTACK="false"
59-
export ALTSERVER_HOST="54.66.58.33"
60-
export ALTSERVER_PORT=13000
61-
chmod -R 755 SampleApp.app
62-
open SampleApp.app
6354
- uses: actions/setup-python@v4
6455
with:
6556
python-version: "3.10"
6657
- name: Install dependencies
6758
run: pip install -r "sample/Tests/requirements.txt"
6859
- name: Run UI tests
60+
env:
61+
UNITY_APP_PATH: ${{ github.workspace }}/SampleApp.app
62+
UNITY_APP_NAME: SampleApp
63+
MAILSLURP_API_KEY: ${{ secrets.MAILSLURP_API_KEY }}
64+
working-directory: sample/Tests
6965
run: |
70-
export ALTSERVER_HOST="54.66.58.33"
71-
export ALTSERVER_PORT=13000
72-
pytest -s -v sample/Tests/test.py
66+
chmod -R 755 ${{ github.workspace }}/SampleApp.app
67+
chmod +x test_mac.sh
68+
./test_mac.sh
7369

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,4 +103,8 @@ sample/AltTester.log
103103
sample/mono_crash*
104104

105105
# Vuplex
106-
sample/Assets/Vuplex*
106+
sample/Assets/Vuplex*
107+
108+
__pycache__/
109+
*.pyc
110+
.pytest_cache/

sample/Tests/requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ google_auth_oauthlib==1.2.0
44
protobuf==5.27.2
55
selenium==4.22.0
66
pytest==8.2.2
7-
requests==2.32.3
7+
requests==2.32.3
8+
mailslurp-client==15.19.22

sample/Tests/src/device_code_login.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
from selenium import webdriver
2+
from selenium.webdriver.chrome.service import Service
3+
from selenium.webdriver.chrome.options import Options
4+
from selenium.webdriver.common.by import By
5+
from selenium.webdriver.support.ui import WebDriverWait
6+
from selenium.webdriver.support import expected_conditions as EC
7+
from selenium.webdriver.common.keys import Keys
8+
import time
9+
from fetch_otp import EMAIL, fetch_code
10+
11+
# brew install chromedriver
12+
13+
def main():
14+
print("Connect to Chrome")
15+
# Set up Chrome options to connect to the existing Chrome instance
16+
chrome_options = Options()
17+
chrome_options.add_argument('--remote-debugging-port=9222')
18+
# Connect to the existing Chrome instance
19+
driver = webdriver.Chrome(options=chrome_options)
20+
21+
print("Open a window on Chrome")
22+
# Get the original window handle
23+
original_window = driver.current_window_handle
24+
25+
print("Waiting for new window...")
26+
WebDriverWait(driver, 30).until(EC.number_of_windows_to_be(2))
27+
28+
# Get all window handles
29+
all_windows = driver.window_handles
30+
31+
print("Find the new window")
32+
new_window = [window for window in all_windows if window != driver.current_window_handle][0]
33+
34+
print("Switch to the new window")
35+
driver.switch_to.window(new_window)
36+
37+
wait = WebDriverWait(driver, 60)
38+
39+
print("Wait for email input...")
40+
email_field = wait.until(EC.presence_of_element_located((By.ID, ':r1:')))
41+
print("Enter email")
42+
email_field.send_keys(EMAIL)
43+
email_field.send_keys(Keys.RETURN)
44+
45+
# Wait for the OTP to arrive and page to load
46+
print("Wait for OTP...")
47+
time.sleep(10)
48+
49+
print("Get OTP from Mailslurp...")
50+
code = fetch_code()
51+
if code:
52+
print(f"Successfully fetched OTP: {code}")
53+
else:
54+
print("Failed to fetch OTP from Gmail")
55+
driver.quit()
56+
57+
print("Find OTP input...")
58+
otp_field = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'input[data-testid="passwordless_passcode__TextInput--0__input"]')))
59+
print("Enter OTP")
60+
otp_field.send_keys(code)
61+
62+
print("Wait for success page...")
63+
success = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'h1[data-testid="device_success_title"]')))
64+
print("Connected to Passport!")
65+
66+
driver.quit()
67+
68+
if __name__ == "__main__":
69+
main()
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
from selenium import webdriver
2+
from selenium.webdriver.chrome.service import Service
3+
from selenium.webdriver.chrome.options import Options
4+
from selenium.webdriver.common.by import By
5+
from selenium.webdriver.support.ui import WebDriverWait
6+
from selenium.webdriver.support import expected_conditions as EC
7+
from selenium.webdriver.common.keys import Keys
8+
import time
9+
from gmail_fetch_otp import fetch_gmail_code
10+
11+
12+
13+
# Add chrome.exe to environment variable
14+
# Download chrome driver and add to environment variable
15+
16+
def main():
17+
print("Connect to Chrome")
18+
# Set up Chrome options to connect to the existing Chrome instance
19+
chrome_options = Options()
20+
chrome_options.add_experimental_option("debuggerAddress", "localhost:9222")
21+
# Connect to the existing Chrome instance
22+
driver = webdriver.Chrome(options=chrome_options)
23+
24+
print("Waiting for new window...")
25+
WebDriverWait(driver, 60).until(EC.number_of_windows_to_be(2))
26+
27+
# Get all window handles
28+
all_windows = driver.window_handles
29+
30+
print("Find the new window")
31+
new_window = [window for window in all_windows if window != driver.current_window_handle][0]
32+
33+
print("Switch to the new window")
34+
driver.switch_to.window(new_window)
35+
36+
wait = WebDriverWait(driver, 60)
37+
38+
print("Wait for email input...")
39+
email_field = wait.until(EC.presence_of_element_located((By.ID, ':r1:')))
40+
print("Enter email")
41+
email_field.send_keys(EMAIL)
42+
email_field.send_keys(Keys.RETURN)
43+
44+
# Wait for the OTP to arrive and page to load
45+
print("Wait for OTP...")
46+
time.sleep(10)
47+
48+
print("Get OTP from Gmail...")
49+
code = fetch_gmail_code()
50+
if code:
51+
print(f"Successfully fetched OTP: {code}")
52+
else:
53+
print("Failed to fetch OTP from Gmail")
54+
driver.quit()
55+
56+
print("Find OTP input...")
57+
otp_field = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'input[data-testid="passwordless_passcode__TextInput--0__input"]')))
58+
print("Enter OTP")
59+
otp_field.send_keys(code)
60+
61+
print("Wait for success page...")
62+
success = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'h1[data-testid="device_success_title"]')))
63+
print("Connected to Passport!")
64+
65+
driver.quit()
66+
67+
if __name__ == "__main__":
68+
main()
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
2+
from selenium import webdriver
3+
from selenium.webdriver.chrome.service import Service
4+
from selenium.webdriver.chrome.options import Options
5+
from selenium.webdriver.common.by import By
6+
from selenium.webdriver.support.ui import WebDriverWait
7+
from selenium.webdriver.support import expected_conditions as EC
8+
from selenium.webdriver.common.keys import Keys
9+
10+
def main():
11+
print("Connect to Chrome")
12+
# Set up Chrome options to connect to the existing Chrome instance
13+
chrome_options = Options()
14+
chrome_options.add_argument('--remote-debugging-port=9222')
15+
# Connect to the existing Chrome instance
16+
driver = webdriver.Chrome(options=chrome_options)
17+
18+
print("Open a window on Chrome")
19+
# Get the original window handle
20+
original_window = driver.current_window_handle
21+
22+
print("Waiting for new window...")
23+
WebDriverWait(driver, 60).until(EC.number_of_windows_to_be(2))
24+
25+
# Get all window handles
26+
all_windows = driver.window_handles
27+
28+
print("Find the new window")
29+
new_window = [window for window in all_windows if window != driver.current_window_handle][0]
30+
31+
print("Switch to the new window")
32+
driver.switch_to.window(new_window)
33+
34+
driver.quit()
35+
36+
if __name__ == "__main__":
37+
main()
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
from selenium import webdriver
3+
from selenium.webdriver.chrome.service import Service
4+
from selenium.webdriver.chrome.options import Options
5+
from selenium.webdriver.common.by import By
6+
from selenium.webdriver.support.ui import WebDriverWait
7+
from selenium.webdriver.support import expected_conditions as EC
8+
from selenium.webdriver.common.keys import Keys
9+
10+
def main():
11+
print("Connect to Chrome")
12+
# Set up Chrome options to connect to the existing Chrome instance
13+
chrome_options = Options()
14+
chrome_options.add_experimental_option("debuggerAddress", "localhost:9222")
15+
# Connect to the existing Chrome instance
16+
driver = webdriver.Chrome(options=chrome_options)
17+
18+
print("Waiting for new window...")
19+
WebDriverWait(driver, 60).until(EC.number_of_windows_to_be(2))
20+
21+
# Get all window handles
22+
all_windows = driver.window_handles
23+
24+
print("Find the new window")
25+
new_window = [window for window in all_windows if window != driver.current_window_handle][0]
26+
27+
print("Switch to the new window")
28+
driver.switch_to.window(new_window)
29+
30+
driver.quit()
31+
32+
if __name__ == "__main__":
33+
main()

sample/Tests/src/fetch_otp.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import os
2+
import mailslurp_client
3+
from mailslurp_client.api import InboxControllerApi, WaitForControllerApi
4+
import re
5+
6+
INBOX_ID = "33f17f82-274b-4269-9ce6-c620e89fcd8d"
7+
8+
9+
def get_mailslurp_client():
10+
configuration = mailslurp_client.Configuration()
11+
configuration.api_key['x-api-key'] = os.getenv('MAILSLURP_API_KEY')
12+
api_client = mailslurp_client.ApiClient(configuration)
13+
waitfor_controller = WaitForControllerApi(api_client)
14+
return waitfor_controller
15+
16+
def extract_otp_from_email(email_body):
17+
# Pattern to match 6-digit code in Passport emails
18+
pattern = r'<h1[^>]*>(\d{6})</h1>'
19+
match = re.search(pattern, email_body)
20+
if match:
21+
return match.group(1)
22+
return None
23+
24+
def fetch_code():
25+
waitfor_controller = get_mailslurp_client()
26+
email = waitfor_controller.wait_for_latest_email(inbox_id=INBOX_ID, timeout=30000, unread_only=True)
27+
if email:
28+
otp = extract_otp_from_email(email.body)
29+
return otp
30+
return None

sample/Tests/test.py

Lines changed: 0 additions & 26 deletions
This file was deleted.

0 commit comments

Comments
 (0)