Skip to content

Instantly share code, notes, and snippets.

@Ashraf-Ali-aa
Last active August 16, 2017 08:07
Show Gist options
  • Save Ashraf-Ali-aa/0a70aec9d1f9bf5dec581f5f8a84f0cd to your computer and use it in GitHub Desktop.
Save Ashraf-Ali-aa/0a70aec9d1f9bf5dec581f5f8a84f0cd to your computer and use it in GitHub Desktop.
xcuitest runner
UITest:
Workspace: 'Test.xcworkspace'
Scheme: 'TestUITests'
Bundle: 'TestUITests'
SearchPaths:
- 'TestUITests/UITests/*/*UITests.swift'
Device: 'platform=iOS Simulator,name=iPad Air,OS=10.2'
PatternMatching:
testSuite: 'class\W+(?<class_name>\w*)'
testCase: '(?<scenario>(s|S)cenario.*)?\s+\S+\s(?<tags>(((?!@))|@.*))\s+\S+\s(?<test_case>test\w*)'
XcodeBuild:
- "set -o pipefail && env NSUnbufferedIO=YES"
- "xcodebuild clean test"
- "-workspace %{workspace} -scheme %{scheme}"
- "-derivedDataPath build/UITests"
- "-destination \'%{device}\' %{option}"
- "| tee build/ui-test.log"
- "| xcpretty -r junit -r html"
include UITests
desc <<-DOC
Run UI test cases using tags
Examples:
Test multiple tags: rake test:case[app_preview/sleep]
Filter out tags: rake test:case[-app_preview]
DOC
task :case, [:tag] => [:list_case] do |_t, args|
UITests.run_tests_using_tags(args[:tag])
end
desc 'Run UI test suite using a tag'
task :suite, [:tag] => [:list_suite] do |_t, args|
UITests.run_tests_using_tags('test_suite', args[:tag])
end
desc 'List all Tags'
task :list_all_tags do
UITests.list_all_tags
end
# desc 'List test cases that are Tagged'
task :list_case, [:tag] do |_t, args|
UITests.list_test_cases_with_tags(args[:tag])
end
# desc 'List test suite that are Tagged'
task :list_suite, [:tag] do |_t, args|
UITests.list_test_suite_with_tags(args[:tag])
end
task :ci do
UITests.run_tests_using_tags(:test_case, ['-flakey_test'])
end
require 'json'
require 'yaml'
module UITests
@yaml_data = YAML.load_file('.hive.yml')
@workspace = @yaml_data['UITest']['Workspace']
@scheme = @yaml_data['UITest']['Scheme']
@device = @yaml_data['UITest']['Device']
@search_paths = @yaml_data['UITest']['SearchPaths']
@test_bundle = @yaml_data['UITest']['Bundle']
@build_settings = @yaml_data['XcodeBuild'].join(' ')
def test_case_commands(tags = [])
list_tests(:test_case, tags).map { |list| "-only-testing:#{list}" }.join(' ')
end
def test_suite_commands
list_tests(:test_suite).map { |list| "-only-testing:#{list}" }.join(' ')
end
def list_all_tags
data = filter_data.select { |h| h[:tags] }.map { |h| h[:tags] }.flatten
return puts 'No test cases found with that tag' if data.empty?
create_table(%w[Num Tags Count], item_count(data))
end
def list_test_cases_with_tags(tags)
tag_list = tags.is_a?(Array) ? tags : tags.split('/')
data = list_tests(:test_case, tag_list)
return puts 'No test cases found with that tag' if data.empty?
create_grid('Tag:', tags, data)
end
def list_test_suite_with_tags(tags)
tag_list = tags.is_a?(Array) ? tags : tags.split('/')
data = list_tests(:test_suite, tag_list)
return puts 'No test suite found with that tag' if data.empty?
create_grid('Tag:', tags, data)
end
def run_tests_using_tags(type = :test_case, tags = [])
option = type == :test_case ? test_case_commands(tags) : test_suite_commands
return puts 'No tests found!' if option.empty?
list_test_cases_with_tags(tags)
Signal.trap('INT') do
puts 'Test interrupted'
exit 1
end
command = format(
@build_settings,
workspace: @workspace,
scheme: @scheme,
device: @device,
option: option
)
system command
end
private
def item_count(data)
data.each_with_object(Hash.new(0)) { |word, counts| counts[word] += 1 }
end
def create_grid(message, tag, data)
puts ''
puts '-------------'
puts '-------------'
puts "#{message} #{tag}"
puts data
puts '-------------'
puts '-------------'
puts ''
end
def create_table(header, data)
text_format = '%-5s %-20s %-20s'
puts text_format % header
counts = 0
data.each_with_index do |(num, id, name), i|
puts format(text_format, i + 1, num, id, name)
counts += id
end
puts "\nTotal Tests: #{counts}"
end
def find_ui_test_files
folders = File.join(@search_paths)
Dir.glob(folders)
end
# Parse test files and output the data as a Hash
# file: "TestUITests/UITests/Legals/EulaUITests.swift",
# test_suite: "EulaUITests",
# scenario: "Scenario:",
# tags: [Tags],
# test_case: "testRetainingEulaAcceptance"
def construct_test_case_data(file)
data = []
test_file = File.open(file, 'r:UTF-8').read
test_suite = test_file.scan(/#{@yaml_data['UITest']['PatternMatching']['testSuite']}/).flatten.first
test_cases = test_file.scan(/#{@yaml_data['UITest']['PatternMatching']['testCase']}/)
test_cases.each do |test_case|
test_data = Hash.new { |hash, key| hash[key] = [] }
test_data[:file] = file
test_data[:test_suite] = test_suite
test_data[:scenario] = test_case[0]
test_data[:tags] = test_case[1].tr('@', '').split(' ') || []
test_data[:test_case] = test_case[2]
data << test_data
end
data
end
def filter_data(tags = [])
filtered_out_tags = tags.select { |tag| tag.include?('-') }.map { |e| e.tr('-', '') }
available_tags = tags.map { |tag| tag.tr('-', '') } - filtered_out_tags
test_data = generate_data.flatten
data = available_tags.empty? ? test_data : test_data.select { |item| (item[:tags] & tags).any? }
data.reject { |item| (item[:tags] & filtered_out_tags).any? }
end
# @option opts [Symbol] :test_case Scan for Test cases
# @option opts [Symbol] :test_suite Scan for Test Suites
def list_tests(type = :test_case, tags = [])
data = []
filter_data(tags).each do |match|
option = case type
when :test_case
"#{@test_bundle}/#{match[:test_suite]}/#{match[:test_case]}"
else
"#{@test_bundle}/#{match[:test_suite]}"
end
data << option
end
data
end
def generate_data
data = []
find_ui_test_files.each do |file|
test_case = construct_test_case_data(file)
data << test_case unless test_case.empty?
end
data
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment