mirror of
https://github.com/yattee/yattee.git
synced 2026-02-20 01:39:46 +00:00
- Skip onboarding in tests by setting UserDefaults before launch - Update all addSource.* identifiers to addRemoteServer.* for new flow - Switch from identifier-based to text-based element lookups (iOS 26 AXe limitation) - Add Yattee Server credential support in instance setup - Update baseline screenshots for Home tab and settings
126 lines
3.9 KiB
Ruby
126 lines
3.9 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'open3'
|
|
|
|
module UITest
|
|
# Manages app build, install, and launch lifecycle
|
|
class App
|
|
class AppError < StandardError; end
|
|
|
|
class << self
|
|
# Build the app for simulator
|
|
# @param device [String] Device name for destination
|
|
# @param skip [Boolean] Skip build if true
|
|
def build(device:, skip: false)
|
|
if skip
|
|
puts 'Skipping build (--skip-build)'
|
|
validate_app_exists!
|
|
return
|
|
end
|
|
|
|
puts "Building Yattee for #{device}..."
|
|
|
|
args = [
|
|
'xcodebuild',
|
|
'-project', Config.xcodeproj,
|
|
'-scheme', Config.scheme,
|
|
'-configuration', Config.configuration,
|
|
'-destination', "platform=iOS Simulator,name=#{device}",
|
|
'-derivedDataPath', Config.derived_data_path,
|
|
'build'
|
|
]
|
|
|
|
# Run build and capture output
|
|
output, status = Open3.capture2e(*args)
|
|
|
|
unless status.success?
|
|
# Extract relevant error lines
|
|
error_lines = output.lines.select { |l| l.include?('error:') }.join
|
|
raise AppError, "Build failed:\n#{error_lines.empty? ? output.last(2000) : error_lines}"
|
|
end
|
|
|
|
puts 'Build succeeded'
|
|
validate_app_exists!
|
|
end
|
|
|
|
# Install app to simulator
|
|
# @param udid [String] UDID of the simulator
|
|
# By default, uninstalls first to reset app data (use --keep-app-data to skip)
|
|
def install(udid:)
|
|
validate_app_exists!
|
|
|
|
# Uninstall first to reset app data (unless --keep-app-data)
|
|
unless Config.keep_app_data?
|
|
puts 'Resetting app data (uninstalling previous install)...'
|
|
uninstall(udid: udid)
|
|
|
|
# Reset keychain to prevent "Save Password?" dialogs during tests
|
|
puts 'Resetting simulator keychain...'
|
|
reset_keychain(udid: udid)
|
|
end
|
|
|
|
puts 'Installing app...'
|
|
output, status = Open3.capture2e('xcrun', 'simctl', 'install', udid, Config.app_path)
|
|
|
|
raise AppError, "Install failed: #{output}" unless status.success?
|
|
|
|
puts 'App installed'
|
|
end
|
|
|
|
# Launch app on simulator
|
|
# @param udid [String] UDID of the simulator
|
|
def launch(udid:)
|
|
puts 'Launching app...'
|
|
|
|
# Terminate if already running
|
|
terminate(udid: udid, silent: true)
|
|
|
|
# Skip onboarding in tests by passing launch argument
|
|
# iOS apps accept UserDefaults overrides via launch arguments
|
|
output, status = Open3.capture2e(
|
|
'xcrun', 'simctl', 'launch', udid, Config.bundle_id,
|
|
'-onboardingCompleted', 'YES'
|
|
)
|
|
|
|
raise AppError, "Launch failed: #{output}" unless status.success?
|
|
|
|
puts 'App launched'
|
|
end
|
|
|
|
# Terminate app on simulator
|
|
# @param udid [String] UDID of the simulator
|
|
# @param silent [Boolean] Don't raise error if app not running
|
|
def terminate(udid:, silent: false)
|
|
output, status = Open3.capture2e('xcrun', 'simctl', 'terminate', udid, Config.bundle_id)
|
|
|
|
# simctl terminate returns non-zero if app isn't running
|
|
return if silent
|
|
|
|
raise AppError, "Terminate failed: #{output}" unless status.success?
|
|
end
|
|
|
|
# Uninstall app from simulator
|
|
# @param udid [String] UDID of the simulator
|
|
def uninstall(udid:)
|
|
Open3.capture2e('xcrun', 'simctl', 'uninstall', udid, Config.bundle_id)
|
|
# Ignore errors - app might not be installed
|
|
end
|
|
|
|
# Reset simulator keychain to prevent "Save Password?" dialogs
|
|
# @param udid [String] UDID of the simulator
|
|
def reset_keychain(udid:)
|
|
Open3.capture2e('xcrun', 'simctl', 'keychain', udid, 'reset')
|
|
# Ignore errors - reset is best effort
|
|
end
|
|
|
|
private
|
|
|
|
def validate_app_exists!
|
|
return if File.exist?(Config.app_path)
|
|
|
|
raise AppError, "App not found at #{Config.app_path}. Run build first or remove --skip-build"
|
|
end
|
|
end
|
|
end
|
|
end
|