diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index 78f1c669..02e55325 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -30,8 +30,6 @@ jobs: UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }} UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }} UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }} - ALTSERVER_HOST: 54.66.58.33 - ALTSERVER_PORT: 13000 with: targetPlatform: StandaloneOSX projectPath: sample @@ -39,13 +37,12 @@ jobs: customParameters: -logFile logFile.log -quit -batchmode - name: Upload artifact uses: actions/upload-artifact@v4 - if: always() with: name: Build-StandaloneOSX path: sample/Builds/MacOS test: name: Run UI tests on AltTester 🧪 - runs-on: macos-latest + runs-on: self-hosted needs: build steps: - uses: actions/checkout@v3 @@ -54,21 +51,19 @@ jobs: - uses: actions/download-artifact@v4 with: name: Build-StandaloneOSX - - name: Open application - run: | - export RUN_IN_BROWSERSTACK="false" - export ALTSERVER_HOST="54.66.58.33" - export ALTSERVER_PORT=13000 - chmod -R 755 SampleApp.app - open SampleApp.app - uses: actions/setup-python@v4 with: python-version: "3.10" - name: Install dependencies run: pip install -r "sample/Tests/requirements.txt" - name: Run UI tests + env: + UNITY_APP_PATH: ${{ github.workspace }}/SampleApp.app + UNITY_APP_NAME: SampleApp + MAILSLURP_API_KEY: ${{ secrets.MAILSLURP_API_KEY }} + working-directory: sample/Tests run: | - export ALTSERVER_HOST="54.66.58.33" - export ALTSERVER_PORT=13000 - pytest -s -v sample/Tests/test.py + chmod -R 755 ${{ github.workspace }}/SampleApp.app + chmod +x test_mac.sh + ./test_mac.sh \ No newline at end of file diff --git a/.gitignore b/.gitignore index 587aac0d..efc4daa6 100644 --- a/.gitignore +++ b/.gitignore @@ -103,4 +103,8 @@ sample/AltTester.log sample/mono_crash* # Vuplex -sample/Assets/Vuplex* \ No newline at end of file +sample/Assets/Vuplex* + +__pycache__/ +*.pyc +.pytest_cache/ \ No newline at end of file diff --git a/sample/Tests/requirements.txt b/sample/Tests/requirements.txt index f6ba7653..2cbdd7de 100644 --- a/sample/Tests/requirements.txt +++ b/sample/Tests/requirements.txt @@ -4,4 +4,5 @@ google_auth_oauthlib==1.2.0 protobuf==5.27.2 selenium==4.22.0 pytest==8.2.2 -requests==2.32.3 \ No newline at end of file +requests==2.32.3 +mailslurp-client==15.19.22 \ No newline at end of file diff --git a/sample/Tests/src/device_code_login.py b/sample/Tests/src/device_code_login.py new file mode 100644 index 00000000..da7aa2ef --- /dev/null +++ b/sample/Tests/src/device_code_login.py @@ -0,0 +1,69 @@ +from selenium import webdriver +from selenium.webdriver.chrome.service import Service +from selenium.webdriver.chrome.options import Options +from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.common.keys import Keys +import time +from fetch_otp import EMAIL, fetch_code + +# brew install chromedriver + +def main(): + print("Connect to Chrome") + # Set up Chrome options to connect to the existing Chrome instance + chrome_options = Options() + chrome_options.add_argument('--remote-debugging-port=9222') + # Connect to the existing Chrome instance + driver = webdriver.Chrome(options=chrome_options) + + print("Open a window on Chrome") + # Get the original window handle + original_window = driver.current_window_handle + + print("Waiting for new window...") + WebDriverWait(driver, 30).until(EC.number_of_windows_to_be(2)) + + # Get all window handles + all_windows = driver.window_handles + + print("Find the new window") + new_window = [window for window in all_windows if window != driver.current_window_handle][0] + + print("Switch to the new window") + driver.switch_to.window(new_window) + + wait = WebDriverWait(driver, 60) + + print("Wait for email input...") + email_field = wait.until(EC.presence_of_element_located((By.ID, ':r1:'))) + print("Enter email") + email_field.send_keys(EMAIL) + email_field.send_keys(Keys.RETURN) + + # Wait for the OTP to arrive and page to load + print("Wait for OTP...") + time.sleep(10) + + print("Get OTP from Mailslurp...") + code = fetch_code() + if code: + print(f"Successfully fetched OTP: {code}") + else: + print("Failed to fetch OTP from Gmail") + driver.quit() + + print("Find OTP input...") + otp_field = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'input[data-testid="passwordless_passcode__TextInput--0__input"]'))) + print("Enter OTP") + otp_field.send_keys(code) + + print("Wait for success page...") + success = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'h1[data-testid="device_success_title"]'))) + print("Connected to Passport!") + + driver.quit() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/sample/Tests/src/device_code_login_windows.py b/sample/Tests/src/device_code_login_windows.py new file mode 100644 index 00000000..80a30b2a --- /dev/null +++ b/sample/Tests/src/device_code_login_windows.py @@ -0,0 +1,68 @@ +from selenium import webdriver +from selenium.webdriver.chrome.service import Service +from selenium.webdriver.chrome.options import Options +from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.common.keys import Keys +import time +from gmail_fetch_otp import fetch_gmail_code + +EMAIL = 'user-33f17f82-274b-4269-9ce6-c620e89fcd8d@mailslurp.biz' + +# Add chrome.exe to environment variable +# Download chrome driver and add to environment variable + +def main(): + print("Connect to Chrome") + # Set up Chrome options to connect to the existing Chrome instance + chrome_options = Options() + chrome_options.add_experimental_option("debuggerAddress", "localhost:9222") + # Connect to the existing Chrome instance + driver = webdriver.Chrome(options=chrome_options) + + print("Waiting for new window...") + WebDriverWait(driver, 60).until(EC.number_of_windows_to_be(2)) + + # Get all window handles + all_windows = driver.window_handles + + print("Find the new window") + new_window = [window for window in all_windows if window != driver.current_window_handle][0] + + print("Switch to the new window") + driver.switch_to.window(new_window) + + wait = WebDriverWait(driver, 60) + + print("Wait for email input...") + email_field = wait.until(EC.presence_of_element_located((By.ID, ':r1:'))) + print("Enter email") + email_field.send_keys(EMAIL) + email_field.send_keys(Keys.RETURN) + + # Wait for the OTP to arrive and page to load + print("Wait for OTP...") + time.sleep(10) + + print("Get OTP from Gmail...") + code = fetch_gmail_code() + if code: + print(f"Successfully fetched OTP: {code}") + else: + print("Failed to fetch OTP from Gmail") + driver.quit() + + print("Find OTP input...") + otp_field = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'input[data-testid="passwordless_passcode__TextInput--0__input"]'))) + print("Enter OTP") + otp_field.send_keys(code) + + print("Wait for success page...") + success = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'h1[data-testid="device_success_title"]'))) + print("Connected to Passport!") + + driver.quit() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/sample/Tests/src/device_code_logout.py b/sample/Tests/src/device_code_logout.py new file mode 100644 index 00000000..e639b2c7 --- /dev/null +++ b/sample/Tests/src/device_code_logout.py @@ -0,0 +1,37 @@ + +from selenium import webdriver +from selenium.webdriver.chrome.service import Service +from selenium.webdriver.chrome.options import Options +from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.common.keys import Keys + +def main(): + print("Connect to Chrome") + # Set up Chrome options to connect to the existing Chrome instance + chrome_options = Options() + chrome_options.add_argument('--remote-debugging-port=9222') + # Connect to the existing Chrome instance + driver = webdriver.Chrome(options=chrome_options) + + print("Open a window on Chrome") + # Get the original window handle + original_window = driver.current_window_handle + + print("Waiting for new window...") + WebDriverWait(driver, 60).until(EC.number_of_windows_to_be(2)) + + # Get all window handles + all_windows = driver.window_handles + + print("Find the new window") + new_window = [window for window in all_windows if window != driver.current_window_handle][0] + + print("Switch to the new window") + driver.switch_to.window(new_window) + + driver.quit() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/sample/Tests/src/device_code_logout_windows.py b/sample/Tests/src/device_code_logout_windows.py new file mode 100644 index 00000000..385e56c3 --- /dev/null +++ b/sample/Tests/src/device_code_logout_windows.py @@ -0,0 +1,33 @@ + +from selenium import webdriver +from selenium.webdriver.chrome.service import Service +from selenium.webdriver.chrome.options import Options +from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.common.keys import Keys + +def main(): + print("Connect to Chrome") + # Set up Chrome options to connect to the existing Chrome instance + chrome_options = Options() + chrome_options.add_experimental_option("debuggerAddress", "localhost:9222") + # Connect to the existing Chrome instance + driver = webdriver.Chrome(options=chrome_options) + + print("Waiting for new window...") + WebDriverWait(driver, 60).until(EC.number_of_windows_to_be(2)) + + # Get all window handles + all_windows = driver.window_handles + + print("Find the new window") + new_window = [window for window in all_windows if window != driver.current_window_handle][0] + + print("Switch to the new window") + driver.switch_to.window(new_window) + + driver.quit() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/sample/Tests/src/fetch_otp.py b/sample/Tests/src/fetch_otp.py new file mode 100644 index 00000000..769163bd --- /dev/null +++ b/sample/Tests/src/fetch_otp.py @@ -0,0 +1,30 @@ +import os +import mailslurp_client +from mailslurp_client.api import InboxControllerApi, WaitForControllerApi +import re + +INBOX_ID = "33f17f82-274b-4269-9ce6-c620e89fcd8d" +EMAIL = "user-33f17f82-274b-4269-9ce6-c620e89fcd8d@mailslurp.biz" + +def get_mailslurp_client(): + configuration = mailslurp_client.Configuration() + configuration.api_key['x-api-key'] = os.getenv('MAILSLURP_API_KEY') + api_client = mailslurp_client.ApiClient(configuration) + waitfor_controller = WaitForControllerApi(api_client) + return waitfor_controller + +def extract_otp_from_email(email_body): + # Pattern to match 6-digit code in Passport emails + pattern = r']*>(\d{6})' + match = re.search(pattern, email_body) + if match: + return match.group(1) + return None + +def fetch_code(): + waitfor_controller = get_mailslurp_client() + email = waitfor_controller.wait_for_latest_email(inbox_id=INBOX_ID, timeout=30000, unread_only=True) + if email: + otp = extract_otp_from_email(email.body) + return otp + return None diff --git a/sample/Tests/test.py b/sample/Tests/test.py deleted file mode 100644 index 7df71c3b..00000000 --- a/sample/Tests/test.py +++ /dev/null @@ -1,26 +0,0 @@ -import unittest -import os -from alttester import * - -class UnityTest(unittest.TestCase): - - altdriver = None - - @classmethod - def setUpClass(cls): - host = os.getenv('ALTSERVER_HOST', '127.0.0.1') - port = int(os.getenv('ALTSERVER_PORT', '13000')) - cls.altdriver = AltDriver(host=host, port=port) - - @classmethod - def tearDownClass(cls): - cls.altdriver.stop() - - def test(self): - # Select use device code auth - self.altdriver.find_object(By.NAME, "DeviceCodeAuth").tap() - - # Wait for unauthenticated screen - self.altdriver.wait_for_current_scene_to_be("UnauthenticatedScene") - - assert True \ No newline at end of file diff --git a/sample/Tests/test/test.py b/sample/Tests/test/test.py new file mode 100644 index 00000000..2d4f98ed --- /dev/null +++ b/sample/Tests/test/test.py @@ -0,0 +1,219 @@ +import time +import unittest +import requests +import re + +from alttester import * + +class TestConfig: + EMAIL = "user-33f17f82-274b-4269-9ce6-c620e89fcd8d@mailslurp.biz" + PASSPORT_ID="email|671ed01e2ab74483c4fb1f42" + WALLET_ADDRESS = "0x7dd423aeaccfbdd3a043bb8583085c7d97032de9" + +class UnityTest(unittest.TestCase): + + altdriver = None + + @classmethod + def setUpClass(cls): + cls.altdriver = AltDriver() + + @classmethod + def tearDownClass(cls): + cls.altdriver.stop() + + def test_1_passport_functions(self): + output = self.altdriver.find_object(By.NAME, "Output") + + # Get access token + self.altdriver.find_object(By.NAME, "GetAccessTokenBtn").tap() + self.assertTrue(len(output.get_text()) > 50) + + # Get ID token + self.altdriver.find_object(By.NAME, "GetIdTokenBtn").tap() + self.assertTrue(len(output.get_text()) > 50) + + # Get email + self.altdriver.find_object(By.NAME, "GetEmail").tap() + self.assertEqual(TestConfig.EMAIL, output.get_text()) + + # Get Passport ID + self.altdriver.find_object(By.NAME, "GetPassportId").tap() + self.assertEqual(TestConfig.PASSPORT_ID, output.get_text()) + + # Get linked addresses + self.altdriver.find_object(By.NAME, "GetLinkedAddresses").tap() + time.sleep(1) + self.assertEqual("No linked addresses", output.get_text()) + + def test_2_imx_functions(self): + output = self.altdriver.find_object(By.NAME, "Output") + + # Connect to IMX + self.altdriver.find_object(By.NAME, "ConnectBtn").tap() + self.assertEqual("Connected to IMX", output.get_text()) + + # Is registered off-chain + self.altdriver.wait_for_object(By.NAME, "IsRegisteredOffchainBtn").tap() + time.sleep(1) + self.assertEqual("Registered", output.get_text()) + + # Register off-chain + self.altdriver.find_object(By.NAME, "RegisterOffchainBtn").tap() + self.assertEqual("Registering off-chain...", output.get_text()) + time.sleep(20) + self.assertTrue("Passport account already registered" in output.get_text()) + + # Get address + self.altdriver.find_object(By.NAME, "GetAddressBtn").tap() + self.assertEqual(TestConfig.WALLET_ADDRESS, output.get_text()) + + # Show NFT transfer scene + self.altdriver.find_object(By.NAME, "NftTransferBtn").tap() + self.altdriver.wait_for_current_scene_to_be("ImxNftTransfer") + + # Get all NFTs the user owns + collection = "0x3765d19d5bc39b60718e43b4b12b30e87d383181" + api_url = f"https://api.sandbox.immutable.com/v1/assets?collection={collection}&user={TestConfig.WALLET_ADDRESS}&page_size=3" + token_ids = [] + try: + # Make the API request + response = requests.get(api_url) + + # Raise an exception if the request was unsuccessful + response.raise_for_status() + + # Parse the JSON response + data = response.json() + + # Extract the token_ids + token_ids = [item['token_id'] for item in data['result']] + + # Check that there's enough NFTs to test transfer + if len(token_ids) < 3: + raise SystemExit(f"Not enough NFTs to test transfer") + + except requests.exceptions.HTTPError as err: + raise SystemExit(f"HTTP error occurred: {err}") + except Exception as err: + raise SystemExit(f"An error occurred: {err}") + + # Single transfer + tokenId = self.altdriver.wait_for_object(By.NAME, "TokenId1") + tokenId.set_text(token_ids[0]) + tokenAddress = self.altdriver.wait_for_object(By.NAME, "TokenAddress1") + tokenAddress.set_text(collection) + receiver = self.altdriver.wait_for_object(By.NAME, "Receiver1") + receiver.set_text("0x0000000000000000000000000000000000000000") + self.altdriver.find_object(By.NAME, "TransferButton").tap() + time.sleep(10) + output = self.altdriver.find_object(By.NAME, "Output") + self.assertTrue(output.get_text().startswith("NFT transferred successfully")) + + # Batch transfer + tokenId = self.altdriver.wait_for_object(By.NAME, "TokenId1") + tokenId.set_text(token_ids[1]) + tokenAddress = self.altdriver.wait_for_object(By.NAME, "TokenAddress1") + tokenAddress.set_text(collection) + receiver = self.altdriver.wait_for_object(By.NAME, "Receiver1") + receiver.set_text("0x0000000000000000000000000000000000000000") + tokenId = self.altdriver.wait_for_object(By.NAME, "TokenId2") + tokenId.set_text(token_ids[2]) + tokenAddress = self.altdriver.wait_for_object(By.NAME, "TokenAddress2") + tokenAddress.set_text(collection) + receiver = self.altdriver.wait_for_object(By.NAME, "Receiver2") + receiver.set_text("0x0000000000000000000000000000000000000000") + self.altdriver.find_object(By.NAME, "TransferButton").tap() + time.sleep(10) + output = self.altdriver.find_object(By.NAME, "Output") + self.assertEqual("Successfully transferred 2 NFTs.", output.get_text()) + + # Go back to authenticated scene + self.altdriver.find_object(By.NAME, "CancelButton").tap() + self.altdriver.wait_for_current_scene_to_be("AuthenticatedScene") + + def test_3_zkevm_functions(self): + output = self.altdriver.find_object(By.NAME, "Output") + + # Connect to zkEVM + self.altdriver.find_object(By.NAME, "ConnectEvmBtn").tap() + self.assertEqual("Connected to EVM", output.get_text()) + + # Initiliase wallet and get address + self.altdriver.wait_for_object(By.NAME, "RequestAccountsBtn").tap() + time.sleep(5) + self.assertEqual(TestConfig.WALLET_ADDRESS, output.get_text()) + + # Show get balance scene + self.altdriver.find_object(By.NAME, "GetBalanceBtn").tap() + self.altdriver.wait_for_current_scene_to_be("ZkEvmGetBalance") + + # Get balance of account + address = self.altdriver.wait_for_object(By.NAME, "AddressInput") + address.set_text(TestConfig.WALLET_ADDRESS) + self.altdriver.find_object(By.NAME, "GetBalanceButton").tap() + time.sleep(2) + output = self.altdriver.find_object(By.NAME, "Output") + self.assertEqual("Balance:\nHex: 0x0\nDec: 0", output.get_text()) + + # Go back to authenticated scene + self.altdriver.find_object(By.NAME, "CancelButton").tap() + self.altdriver.wait_for_current_scene_to_be("AuthenticatedScene") + + # Show send transaction scene + self.altdriver.find_object(By.NAME, "SendTransactionBtn").tap() + self.altdriver.wait_for_current_scene_to_be("ZkEvmSendTransaction") + output = self.altdriver.find_object(By.NAME, "Output") + + # Send transaction with confirmation + to = self.altdriver.wait_for_object(By.NAME, "ToInput") + to.set_text("0x912cd5f1cd67F1143b7a5796fd9e5063D755DAbe") + amount = self.altdriver.wait_for_object(By.NAME, "ValueInput") + amount.set_text("0") + data = self.altdriver.wait_for_object(By.NAME, "DataInput") + data.set_text("0x1e957f1e") + self.altdriver.find_object(By.NAME, "SendButton").tap() + time.sleep(15) + self.assertTrue(output.get_text().startswith("Transaction hash")) + self.assertTrue(output.get_text().endswith("Status: Success")) + + # Send transaction without confirmation and get transaction receipt + self.altdriver.wait_for_object(By.NAME, "WithConfirmationToggle").tap() + self.altdriver.find_object(By.NAME, "SendButton").tap() + time.sleep(20) + self.assertTrue(output.get_text().startswith("Transaction hash")) + self.assertTrue(output.get_text().endswith("Status: Success")) + + # Send transaction without confirmation and don't get transaction receipt + self.altdriver.wait_for_object(By.NAME, "GetTransactionReceiptToggle").tap() + self.altdriver.find_object(By.NAME, "SendButton").tap() + time.sleep(15) + self.assertTrue(output.get_text().startswith("Transaction hash")) + + # Grab the transaction hash + match = re.search(r"0x[0-9a-fA-F]+", output.get_text()) + transactionHash = "" + if match: + transactionHash = match.group() + else: + raise SystemExit(f"Could not find transaction hash") + + # Go back to authenticated scene + self.altdriver.find_object(By.NAME, "CancelButton").tap() + self.altdriver.wait_for_current_scene_to_be("AuthenticatedScene") + + # Show get transaction receipt scene + self.altdriver.find_object(By.NAME, "GetTransactionReceiptBtn").tap() + self.altdriver.wait_for_current_scene_to_be("ZkEvmGetTransactionReceipt") + + # Get transaction receipt + hash = self.altdriver.wait_for_object(By.NAME, "HashInput") + hash.set_text(transactionHash) + self.altdriver.find_object(By.NAME, "GetReceiptButton").tap() + time.sleep(2) + output = self.altdriver.find_object(By.NAME, "Output") + self.assertEqual("Status: Success", output.get_text()) + + # Go back to authenticated scene + self.altdriver.find_object(By.NAME, "CancelButton").tap() + self.altdriver.wait_for_current_scene_to_be("AuthenticatedScene") \ No newline at end of file diff --git a/sample/Tests/test/test_mac.py b/sample/Tests/test/test_mac.py new file mode 100644 index 00000000..507df3c1 --- /dev/null +++ b/sample/Tests/test/test_mac.py @@ -0,0 +1,101 @@ +import time +import unittest +import requests +import re + +from alttester import * + +class MacTest(unittest.TestCase): + + altdriver = None + + @classmethod + def setUpClass(cls): + cls.altdriver = AltDriver() + + @classmethod + def tearDownClass(cls): + cls.altdriver.stop() + + def test_1_device_code_login(self): + # Select use device code auth + self.altdriver.find_object(By.NAME, "DeviceCodeAuth").tap() + + # Wait for unauthenticated screen + self.altdriver.wait_for_current_scene_to_be("UnauthenticatedScene") + + # Login + loginBtn = self.altdriver.wait_for_object(By.NAME, "LoginBtn") + loginBtn.tap() + + # Wait for authenticated screen + self.altdriver.wait_for_current_scene_to_be("AuthenticatedScene") + + def test_2_device_code_connect_imx(self): + # Select use device code auth + self.altdriver.find_object(By.NAME, "DeviceCodeAuth").tap() + + # Wait for unauthenticated screen + self.altdriver.wait_for_current_scene_to_be("UnauthenticatedScene") + + # Connect IMX + connectBtn = self.altdriver.wait_for_object(By.NAME, "ConnectBtn") + connectBtn.tap() + + # Wait for authenticated screen + self.altdriver.wait_for_current_scene_to_be("AuthenticatedScene") + + # Get access token + self.altdriver.find_object(By.NAME, "GetAccessTokenBtn").tap() + output = self.altdriver.find_object(By.NAME, "Output") + self.assertTrue(len(output.get_text()) > 50) + + # Get address without having to click Connect to IMX button + self.altdriver.find_object(By.NAME, "GetAddressBtn").tap() + self.assertEqual("0x9cb14f273de4a8c3d8e9b4c5decbb53519dfa7bd", output.get_text()) + + def test_3_device_code_relogin(self): + # Select use device code auth + self.altdriver.find_object(By.NAME, "DeviceCodeAuth").tap() + + # Wait for unauthenticated screen + self.altdriver.wait_for_current_scene_to_be("UnauthenticatedScene") + + # Relogin + reloginBtn = self.altdriver.wait_for_object(By.NAME, "ReloginBtn") + reloginBtn.tap() + + # Wait for authenticated screen + self.altdriver.wait_for_current_scene_to_be("AuthenticatedScene") + + # Get access token + self.altdriver.find_object(By.NAME, "GetAccessTokenBtn").tap() + output = self.altdriver.find_object(By.NAME, "Output") + self.assertTrue(len(output.get_text()) > 50) + + # Click Connect to IMX button + self.altdriver.find_object(By.NAME, "ConnectBtn").tap() + self.assertEqual("Connected to IMX", output.get_text()) + + def test_4_device_code_reconnect(self): + # Select use device code auth + self.altdriver.find_object(By.NAME, "DeviceCodeAuth").tap() + + # Wait for unauthenticated screen + self.altdriver.wait_for_current_scene_to_be("UnauthenticatedScene") + + # Relogin + reloginBtn = self.altdriver.wait_for_object(By.NAME, "ReconnectBtn") + reloginBtn.tap() + + # Wait for authenticated screen + self.altdriver.wait_for_current_scene_to_be("AuthenticatedScene") + + # Get access token + self.altdriver.find_object(By.NAME, "GetAccessTokenBtn").tap() + output = self.altdriver.find_object(By.NAME, "Output") + self.assertTrue(len(output.get_text()) > 50) + + # Get address without having to click Connect to IMX button + self.altdriver.find_object(By.NAME, "GetAddressBtn").tap() + self.assertEqual("0x9cb14f273de4a8c3d8e9b4c5decbb53519dfa7bd", output.get_text()) \ No newline at end of file diff --git a/sample/Tests/test/test_mac_device_code_logout.py b/sample/Tests/test/test_mac_device_code_logout.py new file mode 100644 index 00000000..beb6cb92 --- /dev/null +++ b/sample/Tests/test/test_mac_device_code_logout.py @@ -0,0 +1,25 @@ +import time +import unittest + +from alttester import * + +class MacTest(unittest.TestCase): + + altdriver = None + + @classmethod + def setUpClass(cls): + cls.altdriver = AltDriver() + + @classmethod + def tearDownClass(cls): + cls.altdriver.stop() + + def test_5_logout(self): + # Logout + self.altdriver.find_object(By.NAME, "LogoutBtn").tap() + + time.sleep(10) + + # Wait for authenticated screen + self.altdriver.wait_for_current_scene_to_be("UnauthenticatedScene") diff --git a/sample/Tests/test/test_windows.py b/sample/Tests/test/test_windows.py new file mode 100644 index 00000000..4c66046e --- /dev/null +++ b/sample/Tests/test/test_windows.py @@ -0,0 +1,76 @@ +import time +import unittest +import requests + +from alttester import * + +class WindowsTest(unittest.TestCase): + + altdriver = None + + @classmethod + def setUpClass(cls): + cls.altdriver = AltDriver() + + @classmethod + def tearDownClass(cls): + cls.altdriver.stop() + + def test_1_device_code_login(self): + # Login + loginBtn = self.altdriver.wait_for_object(By.NAME, "LoginBtn") + loginBtn.tap() + + # Wait for authenticated screen + self.altdriver.wait_for_current_scene_to_be("AuthenticatedScene") + + def test_2_device_code_connect_imx(self): + # Connect IMX + connectBtn = self.altdriver.wait_for_object(By.NAME, "ConnectBtn") + connectBtn.tap() + + # Wait for authenticated screen + self.altdriver.wait_for_current_scene_to_be("AuthenticatedScene") + + # Get access token + self.altdriver.find_object(By.NAME, "GetAccessTokenBtn").tap() + output = self.altdriver.find_object(By.NAME, "Output") + self.assertTrue(len(output.get_text()) > 50) + + # Get address without having to click Connect to IMX button + self.altdriver.find_object(By.NAME, "GetAddressBtn").tap() + self.assertEqual("0x9cb14f273de4a8c3d8e9b4c5decbb53519dfa7bd", output.get_text()) + + def test_3_device_code_relogin(self): + # Relogin + reloginBtn = self.altdriver.wait_for_object(By.NAME, "ReloginBtn") + reloginBtn.tap() + + # Wait for authenticated screen + self.altdriver.wait_for_current_scene_to_be("AuthenticatedScene") + + # Get access token + self.altdriver.find_object(By.NAME, "GetAccessTokenBtn").tap() + output = self.altdriver.find_object(By.NAME, "Output") + self.assertTrue(len(output.get_text()) > 50) + + # Click Connect to IMX button + self.altdriver.find_object(By.NAME, "ConnectBtn").tap() + self.assertEqual("Connected to IMX", output.get_text()) + + def test_4_device_code_reconnect(self): + # Relogin + reloginBtn = self.altdriver.wait_for_object(By.NAME, "ReconnectBtn") + reloginBtn.tap() + + # Wait for authenticated screen + self.altdriver.wait_for_current_scene_to_be("AuthenticatedScene") + + # Get access token + self.altdriver.find_object(By.NAME, "GetAccessTokenBtn").tap() + output = self.altdriver.find_object(By.NAME, "Output") + self.assertTrue(len(output.get_text()) > 50) + + # Get address without having to click Connect to IMX button + self.altdriver.find_object(By.NAME, "GetAddressBtn").tap() + self.assertEqual("0x9cb14f273de4a8c3d8e9b4c5decbb53519dfa7bd", output.get_text()) diff --git a/sample/Tests/test_mac.sh b/sample/Tests/test_mac.sh new file mode 100755 index 00000000..eb434081 --- /dev/null +++ b/sample/Tests/test_mac.sh @@ -0,0 +1,134 @@ +#!/bin/bash + +# Function to open the sample app +open_sample_app() { + local app_path="$1" + echo "Opening Unity sample app..." + open "$app_path" + echo "Unity sample app launched. Waiting for 5 seconds..." + sleep 5 +} + +# Function to close the sample app +close_sample_app() { + local app_path="$1" + echo "Closing sample app..." + local PID=$(ps aux | grep "$app_path" | grep -v grep | awk '{print $2}') + if [ -n "$PID" ]; then + kill $PID + echo "Sample app (PID $PID) has been terminated." + else + echo "Sample app is not running." + fi + echo "Waiting for 5 seconds..." + sleep 5 +} + +# Function to run Python scripts in the background +run_python_script() { + local script_path="$1" + echo "Running $script_path script..." + python3 "$script_path" & + echo "$script_path script running in the background..." +} + +# Function to bring the sample app to the foreground +activate_sample_app() { + local app_name="$1" + echo "Bringing Unity sample app to the foreground..." + osascript -e "tell application \"$app_name\" to activate" +} + +close_chrome() { + echo "Closing all Chrome instances..." + pkill -f chrome + if [ $? -eq 0 ]; then + echo "Chrome closed successfully." + else + echo "No Chrome instances were running." + fi +} + +# Main script execution +app_path="${UNITY_APP_PATH:-SampleApp.app}" +app_name="${UNITY_APP_NAME:-SampleApp}" + +# Capture the start time +start_time=$(date +%s) + +echo "Starting Unity sample app..." +open_sample_app "$app_path" + +# Login +run_python_script "src/device_code_login.py" +sleep 5 +activate_sample_app "$app_name" +echo "Running Mac device code login test..." +pytest test/test_mac.py::MacTest::test_1_device_code_login +wait +close_chrome + +# SDK functions +echo "Running SDK functions tests..." +activate_sample_app "$app_name" +pytest test/test.py +wait + +# Relogin +close_sample_app "$app_path" +open_sample_app "$app_path" +echo "Running Mac relogin test..." +pytest test/test_mac.py::MacTest::test_3_device_code_relogin +wait + +# Reconnect +close_sample_app "$app_path" +open_sample_app "$app_path" +echo "Running Mac reconnect test..." +pytest test/test_mac.py::MacTest::test_4_device_code_reconnect +wait + +# Logout +run_python_script "src/device_code_logout.py" +sleep 5 +activate_sample_app "$app_name" +echo "Running Mac device code logout test..." +pytest test/test_mac_device_code_logout.py +wait +close_chrome + +# Connect IMX +close_sample_app "$app_path" +open_sample_app "$app_path" +run_python_script "src/device_code_login.py" +sleep 5 +activate_sample_app "$app_name" +echo "Running Mac device code connect IMX test..." +pytest test/test_mac.py::MacTest::test_2_device_code_connect_imx +wait +close_chrome + +activate_sample_app "$app_name" + +# Logout +run_python_script "src/device_code_logout.py" +sleep 5 +activate_sample_app "$app_name" +echo "Running Mac device code logout test..." +pytest test/test_mac_device_code_logout.py +wait +close_chrome + +# Final stop of Unity sample app +close_sample_app "$app_path" + +# Capture the end time +end_time=$(date +%s) + +# Calculate the duration +execution_time=$((end_time - start_time)) +minutes=$((execution_time / 60)) +seconds=$((execution_time % 60)) + +echo "All tests completed." +echo "Elapsed time: $minutes minutes and $seconds seconds." \ No newline at end of file