snapshot 0.10.2 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +92 -333
- data/bin/snapshot +11 -28
- data/lib/assets/SnapfileTemplate +14 -33
- data/lib/assets/SnapshotHelper.swift +50 -0
- data/lib/snapshot.rb +23 -4
- data/lib/snapshot/collector.rb +72 -0
- data/lib/snapshot/dependency_checker.rb +14 -26
- data/lib/snapshot/detect_values.rb +33 -0
- data/lib/snapshot/error_handler.rb +31 -0
- data/lib/snapshot/latest_ios_version.rb +9 -4
- data/lib/snapshot/options.rb +98 -0
- data/lib/snapshot/page.html.erb +1 -1
- data/lib/snapshot/reports_generator.rb +33 -37
- data/lib/snapshot/reset_simulators.rb +4 -4
- data/lib/snapshot/runner.rb +59 -246
- data/lib/snapshot/screenshot_flatten.rb +2 -2
- data/lib/snapshot/screenshot_rotate.rb +7 -9
- data/lib/snapshot/setup.rb +33 -0
- data/lib/snapshot/test_command_generator.rb +93 -0
- data/lib/snapshot/version.rb +2 -1
- metadata +83 -13
- data/lib/assets/SnapshotHelper.js +0 -63
- data/lib/assets/snapshot.js +0 -9
- data/lib/snapshot/builder.rb +0 -85
- data/lib/snapshot/simulators.rb +0 -40
- data/lib/snapshot/snapfile_creator.rb +0 -21
- data/lib/snapshot/snapshot_config.rb +0 -233
- data/lib/snapshot/snapshot_file.rb +0 -87
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
require 'fastlane_core'
|
|
2
|
+
|
|
3
|
+
module Snapshot
|
|
4
|
+
class Options
|
|
5
|
+
def self.available_options
|
|
6
|
+
output_directory = (File.directory?("fastlane") ? "fastlane/screenshots" : "screenshots")
|
|
7
|
+
|
|
8
|
+
@@options ||= [
|
|
9
|
+
FastlaneCore::ConfigItem.new(key: :workspace,
|
|
10
|
+
short_option: "-w",
|
|
11
|
+
env_name: "SNAPSHOT_WORKSPACE",
|
|
12
|
+
optional: true,
|
|
13
|
+
description: "Path the workspace file",
|
|
14
|
+
verify_block: proc do |value|
|
|
15
|
+
v = File.expand_path(value.to_s)
|
|
16
|
+
raise "Workspace file not found at path '#{v}'".red unless File.exist?(v)
|
|
17
|
+
raise "Workspace file invalid".red unless File.directory?(v)
|
|
18
|
+
raise "Workspace file is not a workspace, must end with .xcworkspace".red unless v.include?(".xcworkspace")
|
|
19
|
+
end),
|
|
20
|
+
FastlaneCore::ConfigItem.new(key: :project,
|
|
21
|
+
short_option: "-p",
|
|
22
|
+
optional: true,
|
|
23
|
+
env_name: "SNAPSHOT_PROJECT",
|
|
24
|
+
description: "Path the project file",
|
|
25
|
+
verify_block: proc do |value|
|
|
26
|
+
v = File.expand_path(value.to_s)
|
|
27
|
+
raise "Project file not found at path '#{v}'".red unless File.exist?(v)
|
|
28
|
+
raise "Project file invalid".red unless File.directory?(v)
|
|
29
|
+
raise "Project file is not a project file, must end with .xcodeproj".red unless v.include?(".xcodeproj")
|
|
30
|
+
end),
|
|
31
|
+
FastlaneCore::ConfigItem.new(key: :devices,
|
|
32
|
+
description: "A list of devices you want to take the screenshots from",
|
|
33
|
+
is_string: false,
|
|
34
|
+
optional: true,
|
|
35
|
+
verify_block: proc do |value|
|
|
36
|
+
raise "Devices must be an array" unless value.kind_of?(Array)
|
|
37
|
+
available = FastlaneCore::Simulator.all
|
|
38
|
+
value.each do |current|
|
|
39
|
+
unless available.any? { |d| d.name.strip == current.strip }
|
|
40
|
+
raise "Device '#{current}' not in list of available simulators '#{available.join(', ')}'".red
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end),
|
|
44
|
+
FastlaneCore::ConfigItem.new(key: :languages,
|
|
45
|
+
description: "A list of languages which should be used",
|
|
46
|
+
is_string: false,
|
|
47
|
+
default_value: [
|
|
48
|
+
'en-US'
|
|
49
|
+
]),
|
|
50
|
+
FastlaneCore::ConfigItem.new(key: :output_directory,
|
|
51
|
+
short_option: "-o",
|
|
52
|
+
env_name: "SNAPSHOT_OUTPUT_DIRECTORY",
|
|
53
|
+
description: "The directory where to store the screenshots",
|
|
54
|
+
default_value: output_directory),
|
|
55
|
+
FastlaneCore::ConfigItem.new(key: :ios_version,
|
|
56
|
+
description: "By default, the latest version should be used automatically. If you want to change it, do it here",
|
|
57
|
+
default_value: Snapshot::LatestIosVersion.version),
|
|
58
|
+
FastlaneCore::ConfigItem.new(key: :stop_after_first_error,
|
|
59
|
+
env_name: 'SNAPSHOT_BREAK_ON_FIRST_ERROR',
|
|
60
|
+
description: "Should snapshot stop immediately after one of the tests failed on one device?",
|
|
61
|
+
default_value: false,
|
|
62
|
+
is_string: false),
|
|
63
|
+
FastlaneCore::ConfigItem.new(key: :skip_open_summary,
|
|
64
|
+
env_name: 'SNAPSHOT_SKIP_OPEN_SUMMARY',
|
|
65
|
+
description: "Don't open the HTML summary after running `snapshot`",
|
|
66
|
+
default_value: false,
|
|
67
|
+
is_string: false),
|
|
68
|
+
FastlaneCore::ConfigItem.new(key: :clear_previous_screenshots,
|
|
69
|
+
env_name: 'SNAPSHOT_CLEAR_PREVIOUS_SCREENSHOTS',
|
|
70
|
+
description: "Enabling this option will automatically clear previously generated screenshots before running snapshot",
|
|
71
|
+
default_value: false,
|
|
72
|
+
is_string: false),
|
|
73
|
+
|
|
74
|
+
# Everything around building
|
|
75
|
+
FastlaneCore::ConfigItem.new(key: :buildlog_path,
|
|
76
|
+
short_option: "-l",
|
|
77
|
+
env_name: "SNAPSHOT_BUILDLOG_PATH",
|
|
78
|
+
description: "The directory where to store the build log",
|
|
79
|
+
default_value: "~/Library/Logs/snapshot"),
|
|
80
|
+
FastlaneCore::ConfigItem.new(key: :configuration,
|
|
81
|
+
short_option: "-q",
|
|
82
|
+
env_name: "SNAPSHOT_CONFIGURATION",
|
|
83
|
+
description: "The configuration to use when building the app. Defaults to 'Release'",
|
|
84
|
+
optional: true),
|
|
85
|
+
FastlaneCore::ConfigItem.new(key: :sdk,
|
|
86
|
+
short_option: "-k",
|
|
87
|
+
env_name: "SNAPSHOT_SDK",
|
|
88
|
+
description: "The SDK that should be used for building the application",
|
|
89
|
+
optional: true),
|
|
90
|
+
FastlaneCore::ConfigItem.new(key: :scheme,
|
|
91
|
+
short_option: "-s",
|
|
92
|
+
env_name: 'SNAPSHOT_SCHEME',
|
|
93
|
+
description: "The scheme you want to use, this must be the scheme for the UI Tests",
|
|
94
|
+
optional: true) # optional true because we offer a picker to the user
|
|
95
|
+
]
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
data/lib/snapshot/page.html.erb
CHANGED
|
@@ -4,30 +4,25 @@ require 'fastimage'
|
|
|
4
4
|
module Snapshot
|
|
5
5
|
class ReportsGenerator
|
|
6
6
|
def generate
|
|
7
|
+
Helper.log.info "Generating HTML Report"
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
screens_path = config.screenshots_path
|
|
9
|
+
screens_path = Snapshot.config[:output_directory]
|
|
10
10
|
|
|
11
|
-
@title = config.html_title
|
|
12
11
|
@data = {}
|
|
13
12
|
|
|
14
|
-
Dir[
|
|
15
|
-
language = File.basename(
|
|
16
|
-
Dir[File.join(
|
|
13
|
+
Dir[File.join(screens_path, "*")].sort.each do |language_folder|
|
|
14
|
+
language = File.basename(language_folder)
|
|
15
|
+
Dir[File.join(language_folder, '*.png')].sort.each do |screenshot|
|
|
16
|
+
available_devices.each do |key_name, output_name|
|
|
17
|
+
next unless File.basename(screenshot).include?(key_name)
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
output_name += " (#{orientation.capitalize})"
|
|
22
|
-
# This screenshot it from this device
|
|
23
|
-
@data[language] ||= {}
|
|
24
|
-
@data[language][output_name] ||= []
|
|
19
|
+
# This screenshot is from this device
|
|
20
|
+
@data[language] ||= {}
|
|
21
|
+
@data[language][output_name] ||= []
|
|
25
22
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
end
|
|
30
|
-
end
|
|
23
|
+
resulting_path = File.join('.', language, File.basename(screenshot))
|
|
24
|
+
@data[language][output_name] << resulting_path
|
|
25
|
+
break # to not include iPhone 6 and 6 Plus (name is contained in the other name)
|
|
31
26
|
end
|
|
32
27
|
end
|
|
33
28
|
end
|
|
@@ -44,25 +39,26 @@ module Snapshot
|
|
|
44
39
|
end
|
|
45
40
|
|
|
46
41
|
private
|
|
47
|
-
def lib_path
|
|
48
|
-
if not Helper.is_test? and Gem::Specification::find_all_by_name('snapshot').any?
|
|
49
|
-
return [Gem::Specification.find_by_name('snapshot').gem_dir, 'lib'].join('/')
|
|
50
|
-
else
|
|
51
|
-
return './lib'
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
42
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
'iPhone6' => "iPhone 6",
|
|
61
|
-
'iPhone5' => "iPhone 5",
|
|
62
|
-
'iPhone4' => "iPhone 4",
|
|
63
|
-
'iPad' => "iPad",
|
|
64
|
-
'Mac' => "Mac"
|
|
65
|
-
}
|
|
43
|
+
def lib_path
|
|
44
|
+
if !Helper.is_test? and Gem::Specification.find_all_by_name('snapshot').any?
|
|
45
|
+
return [Gem::Specification.find_by_name('snapshot').gem_dir, 'lib'].join('/')
|
|
46
|
+
else
|
|
47
|
+
return './lib'
|
|
66
48
|
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def available_devices
|
|
52
|
+
# The order IS important, since those names are used to check for include?
|
|
53
|
+
# and the iPhone 6 is inlucded in the iPhone 6 Plus
|
|
54
|
+
{
|
|
55
|
+
'iPhone6Plus' => "iPhone 6 Plus",
|
|
56
|
+
'iPhone6' => "iPhone 6",
|
|
57
|
+
'iPhone5' => "iPhone 5",
|
|
58
|
+
'iPhone4' => "iPhone 4",
|
|
59
|
+
'iPad' => "iPad",
|
|
60
|
+
'Mac' => "Mac"
|
|
61
|
+
}
|
|
62
|
+
end
|
|
67
63
|
end
|
|
68
|
-
end
|
|
64
|
+
end
|
|
@@ -21,11 +21,11 @@ module Snapshot
|
|
|
21
21
|
all_devices.split("\n").each do |line|
|
|
22
22
|
parsed = line.match(/\s+([\w\s]+)\s\(([\w\-]+)\)/) || []
|
|
23
23
|
next unless parsed.length == 3 # we don't care about those headers
|
|
24
|
-
|
|
24
|
+
_, name, id = parsed.to_a
|
|
25
25
|
puts "Removing device #{name} (#{id})"
|
|
26
26
|
`xcrun simctl delete #{id}`
|
|
27
27
|
end
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
all_device_types = `xcrun simctl list devicetypes`.scan(/(.*)\s\((.*)\)/)
|
|
30
30
|
# == Device Types ==
|
|
31
31
|
# iPhone 4s (com.apple.CoreSimulator.SimDeviceType.iPhone-4s)
|
|
@@ -33,7 +33,7 @@ module Snapshot
|
|
|
33
33
|
# iPhone 5s (com.apple.CoreSimulator.SimDeviceType.iPhone-5s)
|
|
34
34
|
# iPhone 6 (com.apple.CoreSimulator.SimDeviceType.iPhone-6)
|
|
35
35
|
all_device_types.each do |device_type|
|
|
36
|
-
next if device_type.join(' ').include?"Watch" # we don't want to deal with the Watch right now
|
|
36
|
+
next if device_type.join(' ').include? "Watch" # we don't want to deal with the Watch right now
|
|
37
37
|
|
|
38
38
|
ios_versions.each do |ios_version|
|
|
39
39
|
puts "Creating #{device_type} for iOS version #{ios_version}"
|
|
@@ -42,4 +42,4 @@ module Snapshot
|
|
|
42
42
|
end
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
|
-
end
|
|
45
|
+
end
|
data/lib/snapshot/runner.rb
CHANGED
|
@@ -1,275 +1,88 @@
|
|
|
1
|
-
require 'pty'
|
|
2
1
|
require 'shellwords'
|
|
2
|
+
require 'plist'
|
|
3
3
|
|
|
4
4
|
module Snapshot
|
|
5
5
|
class Runner
|
|
6
|
-
|
|
6
|
+
attr_accessor :number_of_retries
|
|
7
7
|
|
|
8
|
-
def work
|
|
9
|
-
|
|
8
|
+
def work
|
|
9
|
+
FastlaneCore::PrintTable.print_values(config: Snapshot.config, hide_keys: [], title: "Summary")
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
@app_path = determine_app_path
|
|
11
|
+
clear_previous_screenshots if Snapshot.config[:clear_previous_screenshots]
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
errors = []
|
|
16
|
-
|
|
17
|
-
if (SnapshotConfig.shared_instance.clear_previous_screenshots and take_snapshots)
|
|
18
|
-
path_to_clear = (SnapshotConfig.shared_instance.screenshots_path + "/*-*/*.png") # languages always contain a `-`
|
|
19
|
-
Dir[path_to_clear].each { |a| File.delete(a) } # no idea why rm_rf doesn't work
|
|
20
|
-
end
|
|
13
|
+
Helper.log.info "Building and running project - this might take some time...".green
|
|
21
14
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
language = language_item
|
|
27
|
-
locale = language_item
|
|
28
|
-
else
|
|
29
|
-
(language, locale) = language_item
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
prepare_simulator(device, language)
|
|
34
|
-
|
|
35
|
-
reinstall_app(device, language, locale) unless ENV["SNAPSHOT_SKIP_UNINSTALL"]
|
|
36
|
-
|
|
15
|
+
self.number_of_retries = 0
|
|
16
|
+
errors = []
|
|
17
|
+
Snapshot.config[:devices].each do |device|
|
|
18
|
+
Snapshot.config[:languages].each do |language|
|
|
37
19
|
begin
|
|
38
|
-
|
|
20
|
+
launch(language, device)
|
|
39
21
|
rescue => ex
|
|
40
|
-
Helper.log.error
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
# we also want to see the screenshots when something went wrong
|
|
44
|
-
counter += copy_screenshots(language) if take_snapshots
|
|
45
|
-
|
|
46
|
-
teardown_simulator(device, language)
|
|
47
|
-
|
|
48
|
-
break if errors.any? && ENV["SNAPSHOT_BREAK_ON_FIRST_ERROR"]
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
break if errors.any? && ENV["SNAPSHOT_BREAK_ON_FIRST_ERROR"]
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
kill_simulator # close the simulator after the script is finished
|
|
55
|
-
|
|
56
|
-
return unless take_snapshots
|
|
57
|
-
|
|
58
|
-
ReportsGenerator.new.generate
|
|
59
|
-
|
|
60
|
-
if errors.count > 0
|
|
61
|
-
Helper.log.error "-----------------------------------------------------------"
|
|
62
|
-
Helper.log.error errors.join(' - ').red
|
|
63
|
-
Helper.log.error "-----------------------------------------------------------"
|
|
64
|
-
raise "Finished generating #{counter} screenshots with #{errors.count} errors.".red
|
|
65
|
-
else
|
|
66
|
-
Helper.log.info "Successfully finished generating #{counter} screenshots.".green
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
Helper.log.info "Check it out here: #{SnapshotConfig.shared_instance.screenshots_path}".green
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def clean_old_traces
|
|
73
|
-
FileUtils.rm_rf(TRACE_DIR)
|
|
74
|
-
FileUtils.mkdir_p(TRACE_DIR)
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def prepare_simulator(device, language)
|
|
78
|
-
SnapshotConfig.shared_instance.blocks[:setup_for_device_change].call(device, udid_for_simulator(device), language) # Callback
|
|
79
|
-
SnapshotConfig.shared_instance.blocks[:setup_for_language_change].call(language, device) # deprecated
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def teardown_simulator(device, language)
|
|
83
|
-
SnapshotConfig.shared_instance.blocks[:teardown_language].call(language, device) # Callback
|
|
84
|
-
SnapshotConfig.shared_instance.blocks[:teardown_device].call(device, language) # deprecated
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def udid_for_simulator(name) # fetches the UDID of the simulator type
|
|
88
|
-
all = Simulators.raw_simulators.split("\n")
|
|
89
|
-
all.each do |current|
|
|
90
|
-
return current.match(/\[(.*)\]/)[1] if current.include?name
|
|
91
|
-
end
|
|
92
|
-
raise "Could not find simulator '#{name}' to install the app on."
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def reinstall_app(device, language, locale)
|
|
96
|
-
Helper.log.info "Reinstalling app...".yellow unless $verbose
|
|
22
|
+
Helper.log.error ex # we should to show right here as well
|
|
23
|
+
errors << ex
|
|
97
24
|
|
|
98
|
-
|
|
99
|
-
app_identifier ||= @app_identifier
|
|
100
|
-
|
|
101
|
-
def com(cmd)
|
|
102
|
-
puts cmd.magenta if $verbose
|
|
103
|
-
|
|
104
|
-
IO.popen("#{cmd} 2>&1", err: [:child, :out]) do |io|
|
|
105
|
-
io.each do |line|
|
|
106
|
-
puts line if (line.to_s.length > 0 and $verbose)
|
|
25
|
+
raise ex if Snapshot.config[:stop_after_first_error]
|
|
107
26
|
end
|
|
108
|
-
io.close
|
|
109
27
|
end
|
|
110
28
|
end
|
|
111
29
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
kill_simulator
|
|
115
|
-
|
|
116
|
-
if Snapshot.min_xcode7?
|
|
117
|
-
clean_old_traces
|
|
118
|
-
com("xcrun instruments -w '#{udid}' -t 'Blank' -l 1 -D '#{TRACE_DIR}/trace'")
|
|
119
|
-
else
|
|
120
|
-
com("xcrun simctl boot '#{udid}'")
|
|
121
|
-
end
|
|
30
|
+
raise errors.join('; ') if errors.count > 0
|
|
122
31
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
com("xcrun simctl shutdown booted") unless Snapshot.min_xcode7?
|
|
32
|
+
# Generate HTML report
|
|
33
|
+
ReportsGenerator.new.generate
|
|
126
34
|
end
|
|
127
35
|
|
|
128
|
-
def
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
36
|
+
def launch(language, device_type)
|
|
37
|
+
screenshots_path = TestCommandGenerator.derived_data_path
|
|
38
|
+
FileUtils.rm_rf(screenshots_path)
|
|
39
|
+
FileUtils.mkdir_p(screenshots_path)
|
|
132
40
|
|
|
133
|
-
|
|
134
|
-
command = generate_test_command(device, language, locale)
|
|
135
|
-
Helper.log.debug command.yellow
|
|
136
|
-
|
|
137
|
-
retry_run = false
|
|
41
|
+
File.write("/tmp/language.txt", language)
|
|
138
42
|
|
|
139
|
-
|
|
140
|
-
errors = []
|
|
141
|
-
PTY.spawn(command) do |stdout, stdin, pid|
|
|
43
|
+
command = TestCommandGenerator.generate(device_type: device_type)
|
|
142
44
|
|
|
143
|
-
|
|
144
|
-
begin
|
|
145
|
-
stdout.sync
|
|
45
|
+
Helper.log_alert("#{device_type} - #{language}")
|
|
146
46
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
case result
|
|
153
|
-
when :retry
|
|
154
|
-
retry_run = true
|
|
155
|
-
when :screenshot
|
|
156
|
-
Helper.log.info "Successfully took screenshot 📱"
|
|
157
|
-
when :pass
|
|
158
|
-
Helper.log.info line.strip.gsub("Pass:", "✓").green
|
|
159
|
-
when :fail
|
|
160
|
-
Helper.log.info line.strip.gsub("Fail:", "✗").red
|
|
161
|
-
when :need_permission
|
|
162
|
-
raise "Looks like you may need to grant permission for Instruments to analyze other processes.\nPlease Ctrc + C and run this command: \"#{command}\""
|
|
163
|
-
end
|
|
164
|
-
rescue Exception => ex
|
|
165
|
-
Helper.log.error lines.join('')
|
|
166
|
-
Helper.log.error ex.to_s.red
|
|
167
|
-
errors << ex.to_s
|
|
168
|
-
end
|
|
47
|
+
prefix_hash = [
|
|
48
|
+
{
|
|
49
|
+
prefix: "Running Tests: ",
|
|
50
|
+
block: proc do |value|
|
|
51
|
+
value.include?("Touching")
|
|
169
52
|
end
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
FastlaneCore::CommandExecutor.execute(command: command,
|
|
57
|
+
print_all: true,
|
|
58
|
+
print_command: true,
|
|
59
|
+
prefix: prefix_hash,
|
|
60
|
+
loading: "Loading...",
|
|
61
|
+
error: proc do |output, return_code|
|
|
62
|
+
ErrorHandler.handle_test_error(output, return_code)
|
|
63
|
+
|
|
64
|
+
# no exception raised... that means we need to retry
|
|
65
|
+
Helper.log.info "Cought error... #{return_code}".red
|
|
66
|
+
|
|
67
|
+
self.number_of_retries += 1
|
|
68
|
+
if self.number_of_retries < 20
|
|
69
|
+
launch(language, device_type)
|
|
70
|
+
else
|
|
71
|
+
# It's important to raise an error, as we don't want to collect the screenshots
|
|
72
|
+
raise "Too many errors... no more retries...".red
|
|
73
|
+
end
|
|
74
|
+
end)
|
|
75
|
+
|
|
76
|
+
raw_output = File.read(TestCommandGenerator.xcodebuild_log_path)
|
|
77
|
+
Collector.fetch_screenshots(raw_output, language, device_type)
|
|
186
78
|
end
|
|
187
79
|
|
|
188
|
-
def
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
Dir.
|
|
192
|
-
|
|
193
|
-
watchkit_enabled = `/usr/libexec/PlistBuddy -c 'Print WKWatchKitApp' '#{path}' 2>&1`.strip
|
|
194
|
-
next if watchkit_enabled == 'true' # we don't care about WatchKit Apps
|
|
195
|
-
|
|
196
|
-
app_identifier = `/usr/libexec/PlistBuddy -c 'Print CFBundleIdentifier' '#{path}' 2>&1`.strip
|
|
197
|
-
if app_identifier and app_identifier.length > 0
|
|
198
|
-
# This seems to be the valid Info.plist
|
|
199
|
-
@app_identifier = app_identifier
|
|
200
|
-
return File.expand_path("..", path) # the app
|
|
201
|
-
end
|
|
80
|
+
def clear_previous_screenshots
|
|
81
|
+
Helper.log.info "Clearing previously generated screenshots".yellow
|
|
82
|
+
path = File.join(".", Snapshot.config[:output_directory], "*", "*.png")
|
|
83
|
+
Dir[path].each do |current|
|
|
84
|
+
File.delete(current)
|
|
202
85
|
end
|
|
203
|
-
|
|
204
|
-
raise "Could not find app in '#{build_dir}'. Make sure you're following the README and set the build directory to the correct path.".red
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
def parse_test_line(line)
|
|
208
|
-
if line =~ /.*Target failed to run.*/
|
|
209
|
-
return :retry
|
|
210
|
-
elsif line.include?"segmentation fault" # a new bug introduced with Xcode 7
|
|
211
|
-
return :retry
|
|
212
|
-
elsif line.include?"Timed out waiting" # a new bug introduced with Xcode 7
|
|
213
|
-
`killall "iOS Simulator"`
|
|
214
|
-
`killall "Simulator"`
|
|
215
|
-
return :retry
|
|
216
|
-
elsif line.include?"Screenshot captured"
|
|
217
|
-
return :screenshot
|
|
218
|
-
elsif line.include? "Instruments wants permission to analyze other processes"
|
|
219
|
-
return :need_permission
|
|
220
|
-
elsif line.include? "Pass: "
|
|
221
|
-
return :pass
|
|
222
|
-
elsif line.include? "Fail: "
|
|
223
|
-
return :fail
|
|
224
|
-
elsif line =~ /.*Error: (.*)/
|
|
225
|
-
raise "UIAutomation Error: #{$1}"
|
|
226
|
-
elsif line =~ /Instruments Usage Error :(.*)/
|
|
227
|
-
raise "Instruments Usage Error: #{$1}"
|
|
228
|
-
elsif line.include?"__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object"
|
|
229
|
-
raise "Looks like something is wrong with the used app. Make sure the build was successful."
|
|
230
|
-
end
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
def kill_simulator
|
|
234
|
-
`xcrun simctl shutdown booted`
|
|
235
|
-
`killall "iOS Simulator"`
|
|
236
|
-
`killall "Simulator"`
|
|
237
|
-
end
|
|
238
|
-
|
|
239
|
-
def copy_screenshots(language)
|
|
240
|
-
resulting_path = File.join(SnapshotConfig.shared_instance.screenshots_path, language)
|
|
241
|
-
|
|
242
|
-
FileUtils.mkdir_p resulting_path
|
|
243
|
-
|
|
244
|
-
unless SnapshotConfig.shared_instance.skip_alpha_removal
|
|
245
|
-
ScreenshotFlatten.new.run(TRACE_DIR)
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
ScreenshotRotate.new.run(TRACE_DIR)
|
|
249
|
-
|
|
250
|
-
Dir.glob("#{TRACE_DIR}/**/*.png") do |file|
|
|
251
|
-
FileUtils.cp_r(file, resulting_path + '/')
|
|
252
|
-
end
|
|
253
|
-
return Dir.glob("#{TRACE_DIR}/**/*.png").count
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
def generate_test_command(device, language, locale)
|
|
257
|
-
is_ipad = (device.downcase.include?'ipad')
|
|
258
|
-
script_path = SnapshotConfig.shared_instance.js_file(is_ipad)
|
|
259
|
-
custom_run_args = SnapshotConfig.shared_instance.custom_run_args || ENV["SNAPSHOT_CUSTOM_RUN_ARGS"] || ''
|
|
260
|
-
|
|
261
|
-
[
|
|
262
|
-
"instruments",
|
|
263
|
-
"-w '#{device}'",
|
|
264
|
-
"-D '#{TRACE_DIR}/trace'",
|
|
265
|
-
"-t 'Automation'",
|
|
266
|
-
"#{@app_path.shellescape}",
|
|
267
|
-
"-e UIARESULTSPATH '#{TRACE_DIR}'",
|
|
268
|
-
"-e UIASCRIPT '#{script_path}'",
|
|
269
|
-
"-AppleLanguages '(#{language})'",
|
|
270
|
-
"-AppleLocale '#{locale}'",
|
|
271
|
-
custom_run_args,
|
|
272
|
-
].join(' ')
|
|
273
86
|
end
|
|
274
87
|
end
|
|
275
88
|
end
|