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.
@@ -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