class Snapshot::Collector

Responsible for collecting the generated screenshots and copying them over to the output directory

Public Class Methods

attachments(containing) click to toggle source
# File snapshot/lib/snapshot/collector.rb, line 75
def self.attachments(containing)
  UI.message("Collecting screenshots...")
  plist_path = Dir[File.join(containing, "*.plist")].last # we clean the folder before each run
  return attachments_in_file(plist_path)
end
attachments_in_file(plist_path) click to toggle source
# File snapshot/lib/snapshot/collector.rb, line 81
def self.attachments_in_file(plist_path)
  UI.verbose("Loading up '#{plist_path}'...")
  report = Plist.parse_xml(plist_path)

  to_store = [] # contains the names of all the attachments we want to use

  report["TestableSummaries"].each do |summary|
    (summary["Tests"] || []).each do |test|
      (test["Subtests"] || []).each do |subtest|
        (subtest["Subtests"] || []).each do |subtest2|
          (subtest2["Subtests"] || []).each do |subtest3|
            (subtest3["ActivitySummaries"] || []).each do |activity|
              check_activity(activity, to_store)
            end
          end
        end
      end
    end
  end

  UI.message("Found #{to_store.count} screenshots...")
  UI.verbose("Found #{to_store.join(', ')}")
  return to_store
end
check_activity(activity, to_store) click to toggle source
# File snapshot/lib/snapshot/collector.rb, line 106
def self.check_activity(activity, to_store)
  # On iOS, we look for the "Unknown" rotation gesture that signals a snapshot was taken here.
  # On tvOS, we look for "Browser" count.
  # On OSX we look for type `Fn` key on keyboard, it shouldn't change anything for app
  # These are events that are not normally triggered by UI testing, making it easy for us to
  # locate where snapshot() was invoked.
  ios_detected = activity["Title"] == "Set device orientation to Unknown"
  tvos_detected = activity["Title"] == "Get number of matches for: Children matching type Browser"
  osx_detected = activity["Title"] == "Type 'Fn' key (XCUIKeyboardKeySecondaryFn) with no modifiers"
  if ios_detected || tvos_detected || osx_detected
    find_screenshot = find_screenshot(activity)
    to_store << find_screenshot
  end

  (activity["SubActivities"] || []).each do |subactivity|
    check_activity(subactivity, to_store)
  end
end
collect_screenshots_for_language_folder(destination) click to toggle source

Returns true if it succeeds

# File snapshot/lib/snapshot/collector.rb, line 54
def self.collect_screenshots_for_language_folder(destination)
  screenshots = Dir["#{SCREENSHOTS_DIR}/*.png"]
  return false if screenshots.empty?
  screenshots.each do |screenshot|
    filename = File.basename(screenshot)
    to_path = File.join(destination, filename)
    copy(screenshot, to_path)
  end
  FileUtils.rm_rf(SCREENSHOTS_DIR)
  return true
end
copy(from_path, to_path) click to toggle source
# File snapshot/lib/snapshot/collector.rb, line 66
def self.copy(from_path, to_path)
  if FastlaneCore::Globals.verbose?
    UI.success("Copying file '#{from_path}' to '#{to_path}'...")
  else
    UI.success("Copying '#{to_path}'...")
  end
  FileUtils.cp(from_path, to_path)
end
fetch_screenshots(output, dir_name, device_type, launch_arguments_index) click to toggle source

Returns true if it succeeds

# File snapshot/lib/snapshot/collector.rb, line 10
def self.fetch_screenshots(output, dir_name, device_type, launch_arguments_index)
  # Documentation about how this works in the project README
  containing = File.join(TestCommandGenerator.derived_data_path, "Logs", "Test")
  attachments_path = File.join(containing, "Attachments")

  language_folder = File.join(Snapshot.config[:output_directory], dir_name)
  FileUtils.mkdir_p(language_folder)

  # Xcode 9 introduced a new API to take screenshots which allows us
  # to avoid parsing the generated plist file to find the screenshots
  # and instead, we can save them to a known location to use later on.
  if Helper.xcode_at_least?(9)
    return collect_screenshots_for_language_folder(language_folder)
  else
    to_store = attachments(containing)
    matches = output.scan(/snapshot: (.*)/)
  end

  if to_store.count == 0 && matches.count == 0
    return false
  end

  if matches.count != to_store.count
    UI.error("Looks like the number of screenshots (#{to_store.count}) doesn't match the number of names (#{matches.count})")
  end

  matches.each_with_index do |current, index|
    name = current[0]
    filename = to_store[index]

    device_name = device_type.delete(" ")

    components = [launch_arguments_index].delete_if { |a| a.to_s.length == 0 }
    screenshot_name = device_name + "-" + name + "-" + Digest::MD5.hexdigest(components.join("-")) + ".png"
    output_path = File.join(language_folder, screenshot_name)

    from_path = File.join(attachments_path, filename)

    copy(from_path, output_path)
  end
  return true
end
find_screenshot(activity) click to toggle source
# File snapshot/lib/snapshot/collector.rb, line 125
def self.find_screenshot(activity)
  (activity["SubActivities"] || []).each do |subactivity|
    # we are interested in `Synthesize event` part of event in subactivities
    return find_screenshot(subactivity) if subactivity["Title"] == "Synthesize event"
  end

  if activity["Attachments"] && activity["Attachments"].last && activity["Attachments"].last["Filename"]
    return activity["Attachments"].last["Filename"]
  elsif activity["Attachments"]
    return activity["Attachments"].last["FileName"]
  else # Xcode 7.3 has stopped including 'Attachments', so we synthesize the filename manually
    return "Screenshot_#{activity['UUID']}.png"
  end
end