Skip to content

[DX-3593] [DX-3617] [DX-3620] ci: fix ios build and ui tests #435

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Mar 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 22 additions & 22 deletions .github/workflows/ui-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -131,26 +131,26 @@ jobs:
security default-keychain -s ~/Library/Keychains/login.keychain-db
security delete-keychain temporary
security list-keychains
# test-ios:
# name: Run iOS UI tests 🧪
# runs-on: [ self-hosted, macOS ]
# steps:
# - uses: actions/checkout@v3
# with:
# lfs: true
# - name: Build iOS app
# working-directory: sample
# run: ./build_ios.sh
# - uses: actions/setup-python@v4
# with:
# python-version: "3.10"
# - name: Install dependencies
# run: pip install -r "sample/Tests/requirements-mobile.txt"
# - name: Run UI tests
# env:
# MAILSLURP_API_KEY: ${{ secrets.MAILSLURP_API_KEY }}
# BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
# BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
# working-directory: sample/Tests
# run: browserstack-sdk pytest -s ./test/test_ios.py --browserstack.config "browserstack.ios.yml"
test-ios:
name: Run iOS UI tests 🧪
runs-on: [ self-hosted, macOS ]
steps:
- uses: actions/checkout@v3
with:
lfs: true
- name: Build iOS app
working-directory: sample
run: ./build_ios.sh
- uses: actions/setup-python@v4
with:
python-version: "3.10"
- name: Install dependencies
run: pip install -r "sample/Tests/requirements-mobile.txt"
- name: Run UI tests
env:
MAILSLURP_API_KEY: ${{ secrets.MAILSLURP_API_KEY }}
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
working-directory: sample/Tests/test/ios
run: browserstack-sdk pytest -xs ./test_ios.py --browserstack.config "browserstack.ios.yml"

3 changes: 3 additions & 0 deletions sample/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
**/Payload.ipa
**/logFile.log
**/local.log
87 changes: 87 additions & 0 deletions sample/Assets/Editor/iOSPostBuildProcessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#if UNITY_IPHONE && UNITY_EDITOR_OSX

using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
using System.IO;
using System.Linq;
using UnityEditor.iOS.Xcode;

public class iOSPostBuildProcessor
{
[PostProcessBuild]
public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
{
if (target == BuildTarget.iOS && IsCommandLineBuild())
{
Debug.Log("Command-line iOS build detected. Modifying Info.plist and Xcode project...");
ModifyInfoPlist(pathToBuiltProject);
ModifyXcodeProject(pathToBuiltProject, GetBundleIdentifierFromArgs());
}
else
{
Debug.Log("Skipping Info.plist modification (not an iOS command-line build).");
}
}

private static bool IsCommandLineBuild()
{
string[] args = System.Environment.GetCommandLineArgs();
return args.Contains("--ciBuild"); // Check for the --ciBuild flag
}

private static void ModifyInfoPlist(string pathToBuiltProject)
{
string plistPath = Path.Combine(pathToBuiltProject, "Info.plist");

if (!File.Exists(plistPath))
{
Debug.LogError("Info.plist not found!");
return;
}

// Load the Info.plist
PlistDocument plist = new PlistDocument();
plist.ReadFromFile(plistPath);

// Get the root dictionary
PlistElementDict rootDict = plist.root;

// Add App Transport Security Settings
PlistElementDict atsDict = rootDict.CreateDict("NSAppTransportSecurity");
atsDict.SetBoolean("NSAllowsArbitraryLoads", true);

// Save the modified Info.plist
plist.WriteToFile(plistPath);

Debug.Log("Successfully updated Info.plist with NSAllowsArbitraryLoads set to YES.");
}

private static void ModifyXcodeProject(string pathToBuiltProject, string bundleIdentifier)
{
string pbxprojPath = PBXProject.GetPBXProjectPath(pathToBuiltProject);
PBXProject pbxProject = new PBXProject();
pbxProject.ReadFromFile(pbxprojPath);

string targetGuid = pbxProject.GetUnityMainTargetGuid(); // Unity 2019+
pbxProject.SetBuildProperty(targetGuid, "PRODUCT_BUNDLE_IDENTIFIER", bundleIdentifier);

pbxProject.WriteToFile(pbxprojPath);
Debug.Log($"Updated Xcode project with bundle identifier: {bundleIdentifier}");
}

private static string GetBundleIdentifierFromArgs()
{
string[] args = System.Environment.GetCommandLineArgs();
for (int i = 0; i < args.Length; i++)
{
if (args[i] == "--bundleIdentifier" && i + 1 < args.Length)
{
return args[i + 1];
}
}
return "com.immutable.Immutable-Sample"; // Default fallback
}
}

#endif
3 changes: 3 additions & 0 deletions sample/Assets/Editor/iOSPostBuildProcessor.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions sample/ProjectSettings/ProjectSettings.asset
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,13 @@ PlayerSettings:
applicationIdentifier:
Android: com.immutable.ImmutableSample
Standalone: com.immutable.Immutable-Sample
iPhone: com.immutable.Immutable-Sample
iPhone: com.immutable.Immutable-Sample-GameSDK
buildNumber:
Standalone: 0
VisionOS: 0
iPhone: 0
tvOS: 0
overrideDefaultApplicationIdentifier: 0
overrideDefaultApplicationIdentifier: 1
AndroidBundleVersionCode: 1
AndroidMinSdkVersion: 26
AndroidTargetSdkVersion: 33
Expand Down
9 changes: 8 additions & 1 deletion sample/Tests/requirements-mobile.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,11 @@ pytest==8.2.2
requests==2.32.3
mailslurp-client==15.19.22
Appium-Python-Client
browserstack-sdk
browserstack-sdk
browserstack-local
pytest-variables
pytest-selenium
jsonmerge
multiprocess
paver
psutil
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ buildName: iOS build
# Read more about buildIdentifiers here -> https://www.browserstack.com/docs/automate/selenium/organize-tests
buildIdentifier: '#${BUILD_NUMBER}' # Supports strings along with either/both ${expression}
framework: pytest
source: pytest-browserstack:sample-sdk:v1.0
source: pytest-appium-browserstack:sample-sdk:v1.0

# Set `app` to define the app that is to be used for testing.
# It can either take the id of any uploaded app or the path of the app directly.
Expand All @@ -35,9 +35,9 @@ app: ./Payload.ipa #For running local tests
# Entire list available here -> (https://www.browserstack.com/list-of-browsers-and-platforms/automate)

platforms:
- platformName: ios
deviceName: iPhone 14 Pro Max
platformVersion: 16
- deviceName: iPhone 14 Pro
osVersion: 16
platformName: ios

# =======================
# Parallels per Platform
Expand All @@ -57,10 +57,10 @@ parallelsPerPlatform: 1
# Set browserStackLocal to true if your website under test is not accessible publicly over the internet
# Learn more about how BrowserStack Local works here -> https://www.browserstack.com/docs/automate/selenium/local-testing-introduction
browserstackLocal: true # <boolean> (Default false)
browserStackLocalOptions:
# browserStackLocalOptions:
#Options to be passed to BrowserStack local in-case of advanced configurations
# localIdentifier: # <string> (Default: null) Needed if you need to run multiple instances of local.
forceLocal: true # <boolean> (Default: false) Set to true if you need to resolve all your traffic via BrowserStack Local tunnel.
# forceLocal: true # <boolean> (Default: false) Set to true if you need to resolve all your traffic via BrowserStack Local tunnel.
# Entire list of arguments available here -> https://www.browserstack.com/docs/automate/selenium/manage-incoming-connections

# ===================
Expand All @@ -70,4 +70,5 @@ debug: false # <boolean> # Set to true if you need screenshots for every seleniu
networkLogs: false # <boolean> Set to true to enable HAR logs capturing
consoleLogs: errors # <string> Remote browser's console debug levels to be printed (Default: errors)
# Available options are `disable`, `errors`, `warnings`, `info`, `verbose` (Default: errors)
acceptInsecureCerts: true

autoAcceptAlerts: true
21 changes: 21 additions & 0 deletions sample/Tests/test/ios/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import pytest
from appium import webdriver
from alttester import *

@pytest.fixture(scope='function')
def setWebdriver(request, session_capabilities):
session_capabilities["autoAcceptAlerts"] = True
remoteURL = "https://hub.browserstack.com/wd/hub"
driver = webdriver.Remote(remoteURL, session_capabilities)

altdriver = AltDriver(timeout=120)

request.instance.driver = driver
request.instance.altdriver = altdriver

request.node._driver = driver

yield driver

driver.quit()
altdriver.stop()
Loading
Loading