snapshot 0.10.2 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,12 +4,9 @@ $:.push File.expand_path("../../lib", __FILE__)
4
4
 
5
5
  require 'snapshot'
6
6
  require 'commander'
7
- require 'snapshot/snapfile_creator'
8
- require 'snapshot/snapshot_config'
9
7
 
10
8
  HighLine.track_eof = false
11
9
 
12
-
13
10
  class SnapshotApplication
14
11
  include Commander::Methods
15
12
 
@@ -21,38 +18,23 @@ class SnapshotApplication
21
18
  program :help, 'GitHub', 'https://github.com/krausefx/snapshot'
22
19
  program :help_formatter, :compact
23
20
 
24
- global_option '--snapfile PATH', String, 'Custom path for your Snapfile.'
25
- global_option '--nobuild', 'Skips the build process when running snapshot.'
26
- global_option '--noclean', 'Skips the clean process of the build command when running snapshot.'
27
- global_option('--verbose', 'Shows more output including all output printed by Instruments.') { $verbose = true }
21
+ global_option('--verbose', 'Shows a more verbose output') { $verbose = true }
28
22
 
29
23
  always_trace!
30
24
 
25
+ FastlaneCore::CommanderGenerator.new.generate(Snapshot::Options.available_options)
26
+
31
27
  command :run do |c|
32
28
  c.syntax = 'snapshot'
33
29
  c.description = 'Take new screenshots based on the Snapfile.'
34
30
 
35
31
  c.action do |args, options|
36
- path = (Snapshot::Helper.fastlane_enabled?? './fastlane' : '.')
37
- Dir.chdir(path) do # switch the context
38
- Snapshot::DependencyChecker.check_simulators
39
- Snapshot::SnapshotConfig.shared_instance(options.snapfile)
40
- Snapshot::Runner.new.work(clean: !options.noclean, build: !options.nobuild)
41
- end
42
- end
43
- end
44
-
45
- command :test do |c|
46
- c.syntax = 'snapshot test'
47
- c.description = 'Runs the automated tests.'
32
+ o = options.__hash__.dup
33
+ o.delete(:verbose)
34
+ Snapshot.config = FastlaneCore::Configuration.create(Snapshot::Options.available_options, o)
48
35
 
49
- c.action do |args, options|
50
- path = (Snapshot::Helper.fastlane_enabled?? './fastlane' : '.')
51
- Dir.chdir(path) do # switch the context
52
- Snapshot::DependencyChecker.check_simulators
53
- Snapshot::SnapshotConfig.shared_instance(options.snapfile)
54
- Snapshot::Runner.new.work(clean: !options.noclean, build: !options.nobuild, take_snapshots: false)
55
- end
36
+ Snapshot::DependencyChecker.check_simulators
37
+ Snapshot::Runner.new.work
56
38
  end
57
39
  end
58
40
 
@@ -61,8 +43,9 @@ class SnapshotApplication
61
43
  c.description = "Creates a new Snapfile in the current directory"
62
44
 
63
45
  c.action do |args, options|
64
- path = (Snapshot::Helper.fastlane_enabled?? './fastlane' : '.')
65
- Snapshot::SnapfileCreator.create(path)
46
+ require 'snapshot/setup'
47
+ path = (Snapshot::Helper.fastlane_enabled? ? './fastlane' : '.')
48
+ Snapshot::Setup.create(path)
66
49
  end
67
50
  end
68
51
 
@@ -6,45 +6,26 @@ devices([
6
6
  "iPhone 6 Plus",
7
7
  "iPhone 5",
8
8
  "iPhone 4s",
9
- "iPad Air"
9
+ "iPad Retina"
10
10
  ])
11
11
 
12
12
  languages([
13
- 'en-US',
14
- 'de-DE',
15
- 'it-IT'
13
+ "en-US",
14
+ "de-DE",
15
+ "it-IT"
16
16
  ])
17
17
 
18
- # Where should the resulting screenshots be stored?
19
- screenshots_path "./screenshots"
20
-
21
- # clear_previous_screenshots # remove the '#'' to clear all previously generated screenshots before creating new ones
22
-
23
- # JavaScript UIAutomation file
24
- # js_file './snapshot.js'
25
-
26
- # The name of the project's scheme
27
- # scheme 'SchemeName'
28
-
29
- # Where is your project (or workspace)? Provide the full path here
30
- # project_path './YourProject.xcworkspace'
31
-
32
- # By default, the latest version should be used automatically. If you want to change it, do it here
33
- # ios_version '8.1'
34
-
35
- # Comment out the line below to add a `SNAPSHOT` preprocessor macro
36
- # More information available: https://github.com/krausefx/snapshot#custom-args-for-the-build-command
37
- # custom_build_args "GCC_PREPROCESSOR_DEFINITIONS='$(inherited) SNAPSHOT=1' OTHER_SWIFT_FLAGS='$(inherited) -D SNAPSHOT'"
18
+ # The name of the scheme which contains the UI Tests
19
+ # scheme "SchemeName"
38
20
 
21
+ # Where should the resulting screenshots be stored?
22
+ # screenshots_path "./screenshots"
39
23
 
40
- # Custom Callbacks
24
+ # clear_previous_screenshots # remove the '#' to clear all previously generated screenshots before creating new ones
41
25
 
42
- # setup_for_device_change do |device, udid, language|
43
- # puts "Running #{language} on #{device}"
44
- # system("./populateDatabase.sh")
45
- # end
26
+ # Choose which project/workspace to use
27
+ # project "./Project.xcodeproj"
28
+ # workspace "./Project.xcworkspace"
46
29
 
47
- # teardown_device do |language, device|
48
- # puts "Finished with #{language} on #{device}"
49
- # system("./cleanup.sh")
50
- # end
30
+ # For more information about all available options run
31
+ # snapshot --help
@@ -0,0 +1,50 @@
1
+ //
2
+ // SnapshotHelper.swift
3
+ // Example
4
+ //
5
+ // Created by Felix Krause on 10/8/15.
6
+ // Copyright © 2015 Felix Krause. All rights reserved.
7
+ //
8
+
9
+ import Foundation
10
+ import XCTest
11
+
12
+ var deviceLanguage = ""
13
+
14
+ func setLanguage(app: XCUIApplication)
15
+ {
16
+ let path = "/tmp/language.txt"
17
+
18
+ do {
19
+ let locale = try NSString(contentsOfFile: path, encoding: NSUTF8StringEncoding) as String
20
+ deviceLanguage = locale
21
+ app.launchArguments = ["-AppleLanguages", "(\(locale))"]
22
+ } catch {
23
+ print("Couldn't detect/set language...")
24
+ }
25
+ }
26
+
27
+ func snapshot(name: String, waitForLoadingIndicator: Bool = true)
28
+ {
29
+ if (waitForLoadingIndicator)
30
+ {
31
+ waitForLoadingIndicatorToDisappear()
32
+ }
33
+ print("snapshot: \(name)") // more information about this, check out https://github.com/krausefx/snapshot
34
+
35
+ let view = XCUIApplication()
36
+ let start = view.coordinateWithNormalizedOffset(CGVectorMake(32.10, 30000))
37
+ let finish = view.coordinateWithNormalizedOffset(CGVectorMake(31, 30000))
38
+ start.pressForDuration(0, thenDragToCoordinate: finish)
39
+ sleep(1)
40
+ }
41
+
42
+ func waitForLoadingIndicatorToDisappear()
43
+ {
44
+ let query = XCUIApplication().statusBars.childrenMatchingType(.Other).elementBoundByIndex(1).childrenMatchingType(.Other)
45
+
46
+ while (query.count > 4) {
47
+ sleep(1)
48
+ print("Number of Elements in Status Bar: \(query.count)... waiting for status bar to disappear")
49
+ }
50
+ }
@@ -1,18 +1,37 @@
1
1
  require 'snapshot/version'
2
- require 'snapshot/snapshot_config'
3
2
  require 'snapshot/runner'
4
- require 'snapshot/builder'
5
- require 'snapshot/snapshot_file'
6
3
  require 'snapshot/reports_generator'
4
+ require 'snapshot/detect_values'
7
5
  require 'snapshot/screenshot_flatten'
8
6
  require 'snapshot/screenshot_rotate'
9
- require 'snapshot/simulators'
10
7
  require 'snapshot/dependency_checker'
11
8
  require 'snapshot/latest_ios_version'
9
+ require 'snapshot/test_command_generator'
10
+ require 'snapshot/error_handler'
11
+ require 'snapshot/collector'
12
+ require 'snapshot/options'
12
13
 
13
14
  require 'fastlane_core'
14
15
 
16
+ require 'open3'
17
+
15
18
  module Snapshot
19
+ # Use this to just setup the configuration attribute and set it later somewhere else
20
+ class << self
21
+ attr_accessor :config
22
+
23
+ attr_accessor :project
24
+
25
+ def config=(value)
26
+ @config = value
27
+ DetectValues.set_additional_default_values
28
+ end
29
+
30
+ def snapfile_name
31
+ "Snapfile"
32
+ end
33
+ end
34
+
16
35
  Helper = FastlaneCore::Helper # you gotta love Ruby: Helper.* should use the Helper class contained in FastlaneCore
17
36
 
18
37
  Snapshot::DependencyChecker.check_dependencies
@@ -0,0 +1,72 @@
1
+ module Snapshot
2
+ # Responsible for collecting the generated screenshots and copying them over to the output directory
3
+ class Collector
4
+ def self.fetch_screenshots(output, language, device_type)
5
+ # Documentation about how this works in the project README
6
+ containing = File.join(TestCommandGenerator.derived_data_path, "Logs", "Test")
7
+ attachments_path = File.join(containing, "Attachments")
8
+
9
+ to_store = attachments(containing)
10
+ matches = output.scan(/snapshot: (.*)/)
11
+
12
+ if matches.count != to_store.count
13
+ Helper.log.error "Looks like the number of screenshots (#{to_store.count}) doesn't match the number of names (#{matches.count})"
14
+ end
15
+
16
+ matches.each_with_index do |current, index|
17
+ name = current[0]
18
+ filename = to_store[index]
19
+
20
+ language_folder = File.join(Snapshot.config[:output_directory], language)
21
+ FileUtils.mkdir_p(language_folder)
22
+
23
+ device_name = device_type.delete(" ")
24
+ output_path = File.join(language_folder, [device_name, name].join("-") + ".png")
25
+ from_path = File.join(attachments_path, filename)
26
+ if $verbose
27
+ Helper.log.info "Copying file '#{from_path}' to '#{output_path}'...".green
28
+ else
29
+ Helper.log.info "Copying '#{output_path}'...".green
30
+ end
31
+ FileUtils.cp(from_path, output_path)
32
+ end
33
+ end
34
+
35
+ def self.attachments(containing)
36
+ Helper.log.info "Collecting screenshots..."
37
+
38
+ plist_path = Dir[File.join(containing, "*.plist")].last # we clean the folder before each run
39
+ Helper.log.info "Loading up '#{plist_path}'..." if $verbose
40
+ report = Plist.parse_xml(plist_path)
41
+
42
+ activities = []
43
+ report["TestableSummaries"].each do |summary|
44
+ (summary["Tests"] || []).each do |test|
45
+ (test["Subtests"] || []).each do |subtest|
46
+ (subtest["Subtests"] || []).each do |subtest2|
47
+ (subtest2["Subtests"] || []).each do |subtest3|
48
+ (subtest3["ActivitySummaries"] || []).each do |activity|
49
+ # We now check if it's the drag gesture with a negative value
50
+ was_snapshot = activity["Title"].match(/Press and drag from Target Application.*\[32.10.*\].*/)
51
+ activities << activity if was_snapshot
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ Helper.log.info "Found #{activities.count} screenshots..."
60
+
61
+ to_store = [] # contains the names of all the attachments we want to use
62
+ activities.each do |activity|
63
+ # We do care about this, all "Long press Target" events mean screenshots
64
+ attachment_entry = activity["SubActivities"].last # the latest event is fine
65
+ to_store << attachment_entry["Attachments"].last["FileName"]
66
+ end
67
+
68
+ Helper.log.info "Found #{to_store.join(', ')}" if $verbose
69
+ return to_store
70
+ end
71
+ end
72
+ end
@@ -2,13 +2,11 @@ module Snapshot
2
2
  class DependencyChecker
3
3
  def self.check_dependencies
4
4
  self.check_xcode_select
5
- self.check_xctool
6
- self.check_for_automation_subfolder
7
5
  self.check_simctl
8
6
  end
9
7
 
10
8
  def self.check_xcode_select
11
- unless `xcode-select -v`.include?"xcode-select version "
9
+ unless `xcode-select -v`.include? "xcode-select version"
12
10
  Helper.log.fatal '#############################################################'
13
11
  Helper.log.fatal "# You have to install the Xcode commdand line tools to use snapshot"
14
12
  Helper.log.fatal "# Install the latest version of Xcode from the AppStore"
@@ -16,11 +14,21 @@ module Snapshot
16
14
  Helper.log.fatal '#############################################################'
17
15
  raise "Run 'xcode-select --install' and start snapshot again"
18
16
  end
17
+
18
+ if Snapshot::LatestIosVersion.version.to_f < 9 # to_f is bad, but should be good enough
19
+ Helper.log.fatal '#############################################################'
20
+ Helper.log.fatal "# Your xcode-select Xcode version is below 9.0"
21
+ Helper.log.fatal "# To use snapshot 1.0 and above you need at leat iOS 9"
22
+ Helper.log.fatal "# Set the path to the Xcode version that supports UI Tests"
23
+ Helper.log.fatal "# or downgrade to versions older than snapshot 1.0"
24
+ Helper.log.fatal '#############################################################'
25
+ raise "Run 'sudo xcode-select -s /Applications/Xcode-beta.app'"
26
+ end
19
27
  end
20
28
 
21
29
  def self.check_simulators
22
- Helper.log.debug "Found #{Simulators.available_devices.count} simulators." if $verbose
23
- if Simulators.available_devices.count < 1
30
+ Helper.log.debug "Found #{FastlaneCore::Simulator.all.count} simulators." if $verbose
31
+ if FastlaneCore::Simulator.all.count == 0
24
32
  Helper.log.fatal '#############################################################'
25
33
  Helper.log.fatal "# You have to add new simulators using Xcode"
26
34
  Helper.log.fatal "# You can let snapshot create new simulators: 'snapshot reset_simulators'"
@@ -31,28 +39,8 @@ module Snapshot
31
39
  end
32
40
  end
33
41
 
34
- def self.xctool_installed?
35
- return `which xctool`.length > 1
36
- end
37
-
38
- def self.check_xctool
39
- if not self.xctool_installed?
40
- Helper.log.info '#############################################################'
41
- Helper.log.info "# xctool is recommended to build the apps"
42
- Helper.log.info "# Install it using 'brew install xctool'"
43
- Helper.log.info "# Falling back to xcodebuild instead "
44
- Helper.log.info '#############################################################'
45
- end
46
- end
47
-
48
- def self.check_for_automation_subfolder
49
- if File.directory?"./Automation" or File.exists?"./Automation"
50
- raise "Seems like you have an 'Automation' folder in the current directory. You need to delete/rename it!".red
51
- end
52
- end
53
-
54
42
  def self.check_simctl
55
- unless `xcrun simctl`.include?"openurl"
43
+ unless `xcrun simctl`.include? "openurl"
56
44
  raise "Could not find `xcrun simctl`. Make sure you have the latest version of Xcode and Mac OS installed.".red
57
45
  end
58
46
  end
@@ -0,0 +1,33 @@
1
+ module Snapshot
2
+ class DetectValues
3
+ # This is needed as these are more complex default values
4
+ def self.set_additional_default_values
5
+ config = Snapshot.config
6
+
7
+ FastlaneCore::Project.detect_projects(config)
8
+
9
+ Snapshot.project = FastlaneCore::Project.new(config)
10
+
11
+ # Go into the project's folder
12
+ Dir.chdir(File.expand_path("..", Snapshot.project.path)) do
13
+ config.load_configuration_file(Snapshot.snapfile_name)
14
+ end
15
+
16
+ Snapshot.project.select_scheme
17
+
18
+ # Devices
19
+ unless config[:devices]
20
+ config[:devices] = []
21
+
22
+ # We only care about a subset of the simulators
23
+ FastlaneCore::Simulator.all.each do |sim|
24
+ next if sim.name.include?("iPad") and !sim.name.include?("Retina") # we only need one iPad
25
+ next if sim.name.include?("6s") # same screen resolution
26
+ next if sim.name.include?("5s") # same screen resolution
27
+
28
+ config[:devices] << sim.name
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,31 @@
1
+ module Snapshot
2
+ # This classes methods are called when something goes wrong in the building process
3
+ class ErrorHandler
4
+ class TestsFailedException < StandardError
5
+ end
6
+
7
+ class << self
8
+ # @param [Array] The output of the errored build (line by line)
9
+ # This method should raise an exception in any case, as the return code indicated a failed build
10
+ def handle_test_error(output, return_code)
11
+ # The order of the handling below is import
12
+
13
+ if return_code == 65
14
+ raise TestsFailedException.new, "Tests failed - check out the log above".red
15
+ end
16
+
17
+ case output
18
+ when /com\.apple\.CoreSimulator\.SimError/
19
+ print "The simulator failed to launch - retrying..."
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ # Just to make things easier
26
+ def print(text)
27
+ Helper.log.error text.red
28
+ end
29
+ end
30
+ end
31
+ end
@@ -5,9 +5,14 @@ module Snapshot
5
5
  return ENV["SNAPSHOT_IOS_VERSION"] if ENV["SNAPSHOT_IOS_VERSION"]
6
6
  return @version if @version
7
7
 
8
- output = `xcodebuild -version -sdk`.split("Mac").last # don't care about the Mac Part
9
- matched = output.match(/iPhoneSimulator([\d\.]+)\.sdk/)
10
-
8
+ # We do all this, because we would get all kind of crap output generated by xcodebuild
9
+ # so we need to ignore stderror
10
+ output = ''
11
+ Open3.popen3('xcodebuild -version -sdk') do |stdin, stdout, stderr, wait_thr|
12
+ output = stdout.read
13
+ end
14
+
15
+ matched = output.match(/iOS ([\d\.]+) \(.*/)
11
16
  if matched.length > 1
12
17
  return @version ||= matched[1]
13
18
  else
@@ -15,4 +20,4 @@ module Snapshot
15
20
  end
16
21
  end
17
22
  end
18
- end
23
+ end