calabash-cucumber 0.20.0 → 0.20.3
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/dylibs/libCalabashDyn.dylib +0 -0
- data/dylibs/libCalabashDynSim.dylib +0 -0
- data/lib/calabash-cucumber/automator/automator.rb +24 -0
- data/lib/calabash-cucumber/automator/device_agent.rb +81 -20
- data/lib/calabash-cucumber/console_helpers.rb +16 -1
- data/lib/calabash-cucumber/core.rb +306 -84
- data/lib/calabash-cucumber/device.rb +6 -0
- data/lib/calabash-cucumber/device_agent.rb +9 -23
- data/lib/calabash-cucumber/environment_helpers.rb +8 -0
- data/lib/calabash-cucumber/keyboard_helpers.rb +13 -8
- data/lib/calabash-cucumber/launcher.rb +36 -19
- data/lib/calabash-cucumber/map.rb +1 -1
- data/lib/calabash-cucumber/usage_tracker.rb +4 -1
- data/lib/calabash-cucumber/version.rb +2 -2
- data/scripts/.irbrc +1 -0
- data/staticlib/calabash.framework.zip +0 -0
- data/staticlib/libFrankCalabash.a +0 -0
- metadata +20 -6
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 5d80bc583ef0ea5ae3fb6548acd4d5ced7f15b2c
         | 
| 4 | 
            +
              data.tar.gz: 61431194a8a83d91b41674c2d5ec6f83076b92fa
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 1b9e3bbb6993f444dfd6a9e83e8e4de9d9c2b48080a820c71032967755366eb984de455bac2bfce9fe18a823050a482c8cdf937c56e1e8ae6cfc592b8047fcc8
         | 
| 7 | 
            +
              data.tar.gz: c25c2390ba6e3b3542bfa5e5a1c5cad9dfc6ad73fea899405f2aacc8b25d09b817a3f92dee5a1285cd8a67044ee7b189730bb67c20fc8c9c439c115c6bb1a0af
         | 
    
        data/dylibs/libCalabashDyn.dylib
    CHANGED
    
    | Binary file | 
| Binary file | 
| @@ -34,6 +34,28 @@ module Calabash | |
| 34 34 | 
             
                      abstract_method!
         | 
| 35 35 | 
             
                    end
         | 
| 36 36 |  | 
| 37 | 
            +
                    # @!visibility private
         | 
| 38 | 
            +
                    #
         | 
| 39 | 
            +
                    # This code is redundant.  It would be easy to pass the Launcher
         | 
| 40 | 
            +
                    # device instance to the automator, but that would require an XTC patch.
         | 
| 41 | 
            +
                    #
         | 
| 42 | 
            +
                    # This code is also duplicated in the EnvironmentHelpers.
         | 
| 43 | 
            +
                    #
         | 
| 44 | 
            +
                    # We need the device screen size to support full-screen pan gestures.
         | 
| 45 | 
            +
                    #
         | 
| 46 | 
            +
                    # Asking for the top-most view is not good enough and asking for the
         | 
| 47 | 
            +
                    # largest UIWindow is not specific enough (map apps have a huge window).
         | 
| 48 | 
            +
                    def device
         | 
| 49 | 
            +
                      @device ||= begin
         | 
| 50 | 
            +
                        require "calabash-cucumber/http/http"
         | 
| 51 | 
            +
                        require "calabash-cucumber/environment"
         | 
| 52 | 
            +
                        require "calabash-cucumber/device"
         | 
| 53 | 
            +
                        _, body = Calabash::Cucumber::HTTP.ensure_connectivity
         | 
| 54 | 
            +
                        endpoint = Calabash::Cucumber::Environment.device_endpoint
         | 
| 55 | 
            +
                        Calabash::Cucumber::Device.new(endpoint, body)
         | 
| 56 | 
            +
                      end
         | 
| 57 | 
            +
                    end
         | 
| 58 | 
            +
             | 
| 37 59 | 
             
                    # @!visibility private
         | 
| 38 60 | 
             
                    def touch(options)
         | 
| 39 61 | 
             
                      abstract_method!
         | 
| @@ -79,6 +101,8 @@ module Calabash | |
| 79 101 | 
             
                    end
         | 
| 80 102 |  | 
| 81 103 | 
             
                    # @!visibility private
         | 
| 104 | 
            +
                    #
         | 
| 105 | 
            +
                    # Callers must validate the options.
         | 
| 82 106 | 
             
                    def pinch(in_or_out, options)
         | 
| 83 107 | 
             
                      abstract_method!
         | 
| 84 108 | 
             
                    end
         | 
| @@ -130,13 +130,14 @@ args[0] = #{args[0]}]) | |
| 130 130 | 
             
                      dupped_options = options.dup
         | 
| 131 131 |  | 
| 132 132 | 
             
                      if dupped_options[:query].nil?
         | 
| 133 | 
            -
                         | 
| 133 | 
            +
                        element = element_for_device_screen
         | 
| 134 | 
            +
                        from_point = point_from(element, options)
         | 
| 135 | 
            +
                      else
         | 
| 136 | 
            +
                        hash = query_for_coordinates(dupped_options)
         | 
| 137 | 
            +
                        from_point = hash[:coordinates]
         | 
| 138 | 
            +
                        element = hash[:view]
         | 
| 134 139 | 
             
                      end
         | 
| 135 140 |  | 
| 136 | 
            -
                      hash = query_for_coordinates(dupped_options)
         | 
| 137 | 
            -
                      from_point = hash[:coordinates]
         | 
| 138 | 
            -
                      element = hash[:view]
         | 
| 139 | 
            -
             | 
| 140 141 | 
             
                      # DeviceAgent does not understand the :force. Does anyone?
         | 
| 141 142 | 
             
                      force = dupped_options[:force]
         | 
| 142 143 | 
             
                      case force
         | 
| @@ -158,7 +159,38 @@ args[0] = #{args[0]}]) | |
| 158 159 | 
             
                      direction = dupped_options[:direction]
         | 
| 159 160 | 
             
                      to_point = Coordinates.end_point_for_swipe(direction, element, force)
         | 
| 160 161 | 
             
                      client.pan_between_coordinates(from_point, to_point, gesture_options)
         | 
| 161 | 
            -
                      [ | 
| 162 | 
            +
                      [element]
         | 
| 163 | 
            +
                    end
         | 
| 164 | 
            +
             | 
| 165 | 
            +
                    # @!visibility private
         | 
| 166 | 
            +
                    def pinch(in_out, options)
         | 
| 167 | 
            +
                      dupped_options = options.dup
         | 
| 168 | 
            +
             | 
| 169 | 
            +
                      if dupped_options[:query].nil?
         | 
| 170 | 
            +
                        element = element_for_device_screen
         | 
| 171 | 
            +
                        coordinates = point_from(element, options)
         | 
| 172 | 
            +
                      else
         | 
| 173 | 
            +
                        hash = query_for_coordinates(dupped_options)
         | 
| 174 | 
            +
                        element = hash[:view]
         | 
| 175 | 
            +
                        coordinates = hash[:coordinates]
         | 
| 176 | 
            +
                      end
         | 
| 177 | 
            +
             | 
| 178 | 
            +
                      in_out = in_out.to_s
         | 
| 179 | 
            +
                      duration = dupped_options[:duration]
         | 
| 180 | 
            +
                      amount = dupped_options[:amount]
         | 
| 181 | 
            +
             | 
| 182 | 
            +
                      gesture_options = {
         | 
| 183 | 
            +
                        :pinch_direction => in_out,
         | 
| 184 | 
            +
                        :amount => amount,
         | 
| 185 | 
            +
                        :duration => duration
         | 
| 186 | 
            +
                      }
         | 
| 187 | 
            +
             | 
| 188 | 
            +
                      client.perform_coordinate_gesture("pinch",
         | 
| 189 | 
            +
                                                        coordinates[:x],
         | 
| 190 | 
            +
                                                        coordinates[:y],
         | 
| 191 | 
            +
                                                        gesture_options)
         | 
| 192 | 
            +
             | 
| 193 | 
            +
                      [element]
         | 
| 162 194 | 
             
                    end
         | 
| 163 195 |  | 
| 164 196 | 
             
                    # @!visibility private
         | 
| @@ -223,12 +255,12 @@ args[0] = #{args[0]}]) | |
| 223 255 |  | 
| 224 256 | 
             
                    # @!visibility private
         | 
| 225 257 | 
             
                    def enter_text_with_keyboard(string, options={})
         | 
| 226 | 
            -
                      client. | 
| 258 | 
            +
                      client.enter_text_without_keyboard_check(string)
         | 
| 227 259 | 
             
                    end
         | 
| 228 260 |  | 
| 229 261 | 
             
                    # @!visibility private
         | 
| 230 262 | 
             
                    def enter_char_with_keyboard(char)
         | 
| 231 | 
            -
                      client. | 
| 263 | 
            +
                      client.enter_text_without_keyboard_check(char)
         | 
| 232 264 | 
             
                    end
         | 
| 233 265 |  | 
| 234 266 | 
             
                    # @!visibility private
         | 
| @@ -242,7 +274,7 @@ args[0] = #{args[0]}]) | |
| 242 274 | 
             
                      if mark
         | 
| 243 275 | 
             
                        begin
         | 
| 244 276 | 
             
                          # The underlying query for coordinates always expects results.
         | 
| 245 | 
            -
                          value = client.touch({marked: mark})
         | 
| 277 | 
            +
                          value = client.touch({type: "Button", marked: mark})
         | 
| 246 278 | 
             
                          return value
         | 
| 247 279 | 
             
                        rescue RuntimeError => _
         | 
| 248 280 | 
             
                          RunLoop.log_debug("Cannot find mark '#{mark}' with query; will send a newline")
         | 
| @@ -252,7 +284,7 @@ args[0] = #{args[0]}]) | |
| 252 284 | 
             
                      end
         | 
| 253 285 |  | 
| 254 286 | 
             
                      code = char_for_keyboard_action("Return")
         | 
| 255 | 
            -
                      client. | 
| 287 | 
            +
                      client.enter_text_without_keyboard_check(code)
         | 
| 256 288 | 
             
                    end
         | 
| 257 289 |  | 
| 258 290 | 
             
                    # @!visibility private
         | 
| @@ -262,7 +294,7 @@ args[0] = #{args[0]}]) | |
| 262 294 |  | 
| 263 295 | 
             
                    # @!visibility private
         | 
| 264 296 | 
             
                    def fast_enter_text(text)
         | 
| 265 | 
            -
                      client. | 
| 297 | 
            +
                      client.enter_text_without_keyboard_check(text)
         | 
| 266 298 | 
             
                    end
         | 
| 267 299 |  | 
| 268 300 | 
             
                    # @!visibility private
         | 
| @@ -353,6 +385,27 @@ Make sure your query returns at least one view. | |
| 353 385 | 
             
                      end
         | 
| 354 386 | 
             
                    end
         | 
| 355 387 |  | 
| 388 | 
            +
                    # @!visibility private
         | 
| 389 | 
            +
                    def element_for_device_screen
         | 
| 390 | 
            +
                      screen_dimensions = device.screen_dimensions
         | 
| 391 | 
            +
             | 
| 392 | 
            +
                      scale = screen_dimensions[:scale]
         | 
| 393 | 
            +
                      height = (screen_dimensions[:height]/scale).to_i
         | 
| 394 | 
            +
                      center_y = (height/2)
         | 
| 395 | 
            +
                      width = (screen_dimensions[:width]/scale).to_i
         | 
| 396 | 
            +
                      center_x = (width/2)
         | 
| 397 | 
            +
             | 
| 398 | 
            +
                      {
         | 
| 399 | 
            +
                        "screen" => true,
         | 
| 400 | 
            +
                        "rect" => {
         | 
| 401 | 
            +
                          "height" => height,
         | 
| 402 | 
            +
                          "width" => width,
         | 
| 403 | 
            +
                          "center_x" => center_x,
         | 
| 404 | 
            +
                          "center_y" => center_y
         | 
| 405 | 
            +
                        }
         | 
| 406 | 
            +
                      }
         | 
| 407 | 
            +
                    end
         | 
| 408 | 
            +
             | 
| 356 409 | 
             
                    # @!visibility private
         | 
| 357 410 | 
             
                    #
         | 
| 358 411 | 
             
                    # Don't change the double quotes.
         | 
| @@ -400,17 +453,25 @@ Make sure your query returns at least one view. | |
| 400 453 | 
             
                    # @!visibility private
         | 
| 401 454 | 
             
                    def return_key_type_of_first_responder
         | 
| 402 455 |  | 
| 403 | 
            -
                       | 
| 404 | 
            -
             | 
| 405 | 
            -
             | 
| 406 | 
            -
             | 
| 407 | 
            -
             | 
| 408 | 
            -
             | 
| 409 | 
            -
             | 
| 456 | 
            +
                      query = "* isFirstResponder:1"
         | 
| 457 | 
            +
                      raw = Calabash::Cucumber::Map.raw_map(query, :query, :returnKeyType)
         | 
| 458 | 
            +
                      elements = raw["results"]
         | 
| 459 | 
            +
                      return nil if elements.count == 0
         | 
| 460 | 
            +
             | 
| 461 | 
            +
                      return_key_type = elements[0]
         | 
| 462 | 
            +
             | 
| 463 | 
            +
                      # first responder did not respond to :text selector
         | 
| 464 | 
            +
                      if return_key_type == "*****"
         | 
| 465 | 
            +
                        RunLoop.log_debug("First responder does not respond to :returnKeyType")
         | 
| 466 | 
            +
                        return nil
         | 
| 467 | 
            +
                      end
         | 
| 468 | 
            +
             | 
| 469 | 
            +
                      if return_key_type.nil?
         | 
| 470 | 
            +
                        RunLoop.log_debug("First responder has nil :returnKeyType")
         | 
| 471 | 
            +
                        return nil
         | 
| 410 472 | 
             
                      end
         | 
| 411 473 |  | 
| 412 | 
            -
                       | 
| 413 | 
            -
                      nil
         | 
| 474 | 
            +
                      return_key_type
         | 
| 414 475 | 
             
                    end
         | 
| 415 476 |  | 
| 416 477 | 
             
                    # @!visibility private
         | 
| @@ -102,7 +102,9 @@ module Calabash | |
| 102 102 | 
             
                      "Uti, non abuti.",
         | 
| 103 103 | 
             
                      "Non Satis Scire",
         | 
| 104 104 | 
             
                      "Nullius in verba",
         | 
| 105 | 
            -
                      "Det ka æn jå væer ei jált"
         | 
| 105 | 
            +
                      "Det ka æn jå væer ei jált",
         | 
| 106 | 
            +
                      "Dzień dobry",
         | 
| 107 | 
            +
                      "Jestem tu by ocalić świat"
         | 
| 106 108 | 
             
                    ]
         | 
| 107 109 | 
             
                    puts RunLoop::Color.green("Calabash says, \"#{messages.shuffle.first}\"")
         | 
| 108 110 | 
             
                  end
         | 
| @@ -148,6 +150,19 @@ module Calabash | |
| 148 150 | 
             
                    puts ""
         | 
| 149 151 | 
             
                  end
         | 
| 150 152 |  | 
| 153 | 
            +
                  # @!visibility private
         | 
| 154 | 
            +
                  # Do not call this method directly.
         | 
| 155 | 
            +
                  def _try_to_attach
         | 
| 156 | 
            +
                    begin
         | 
| 157 | 
            +
                      Calabash::Cucumber::HTTP.ping_app
         | 
| 158 | 
            +
                      launcher = Calabash::Cucumber::Launcher.new
         | 
| 159 | 
            +
                      launcher.attach
         | 
| 160 | 
            +
                      puts(RunLoop::Color.green("Attached to: #{launcher}"))
         | 
| 161 | 
            +
                      launcher
         | 
| 162 | 
            +
                    rescue => _
         | 
| 163 | 
            +
                    end
         | 
| 164 | 
            +
                  end
         | 
| 165 | 
            +
             | 
| 151 166 | 
             
                  private
         | 
| 152 167 |  | 
| 153 168 | 
             
                  # List the visible element with given mark(s).
         | 
| @@ -382,13 +382,13 @@ Expected: options[:offset] = {:x => NUMERIC, :y => NUMERIC} | |
| 382 382 | 
             
                  # @option options {Hash} :offset (nil) optional offset to touch point.
         | 
| 383 383 | 
             
                  #  Offset supports an `:x` and `:y` key and causes the touch to be
         | 
| 384 384 | 
             
                  #  offset with `(x,y)` relative to the center.
         | 
| 385 | 
            -
                  # @option options {String} :query (nil) If specified, the swipe will be
         | 
| 386 | 
            -
                  #  made on the first view matching this query.  If this option is nil
         | 
| 387 | 
            -
                  #  (the default), the swipe will happen on the first view matched by "*".
         | 
| 388 385 | 
             
                  # @option options [Symbol] :force (normal) Indicates the force of the
         | 
| 389 386 | 
             
                  #  swipe.  Valid values are :strong, :normal, :light.
         | 
| 387 | 
            +
                  # @option options {String} :query (nil) If specified, the swipe will be
         | 
| 388 | 
            +
                  #  made on the first view matching this query.  If this option is nil
         | 
| 389 | 
            +
                  #  (the default), the swipe will happen at the center of the screen.
         | 
| 390 390 | 
             
                  #
         | 
| 391 | 
            -
                  # @return {Array<Hash | 
| 391 | 
            +
                  # @return {Array<Hash>} An array with one element; the view that
         | 
| 392 392 | 
             
                  #  was swiped.
         | 
| 393 393 | 
             
                  #
         | 
| 394 394 | 
             
                  # @raise [ArgumentError] If :force is invalid.
         | 
| @@ -584,20 +584,70 @@ The minimum duration is 0.0. | |
| 584 584 | 
             
                  end
         | 
| 585 585 |  | 
| 586 586 | 
             
                  # Performs a "pinch" gesture.
         | 
| 587 | 
            +
                  #
         | 
| 587 588 | 
             
                  # By default, the gesture starts at the center of the screen.
         | 
| 588 | 
            -
                  # | 
| 589 | 
            +
                  #
         | 
| 589 590 | 
             
                  # @example
         | 
| 591 | 
            +
                  #   # Zoom in
         | 
| 590 592 | 
             
                  #   pinch :out
         | 
| 591 | 
            -
                  # | 
| 593 | 
            +
                  #
         | 
| 594 | 
            +
                  #   # Zoom out
         | 
| 592 595 | 
             
                  #   pinch :in, query:"MKMapView", offset:{x:42}
         | 
| 593 | 
            -
                  # | 
| 596 | 
            +
                  #
         | 
| 597 | 
            +
                  # @param {String, Symbol} in_out the direction to pinch ('in' or 'out')
         | 
| 594 598 | 
             
                  # @param {Hash} options option for modifying the details of the touch.
         | 
| 595 | 
            -
                  # @option options {Hash} :offset (nil) optional offset to touch point. | 
| 596 | 
            -
                  # | 
| 597 | 
            -
                  #  | 
| 598 | 
            -
                  # @ | 
| 599 | 
            +
                  # @option options {Hash} :offset (nil) optional offset to touch point.
         | 
| 600 | 
            +
                  # @option options {String} :query (nil) The view to pinch on.  If this
         | 
| 601 | 
            +
                  #  value is nil, the pinch happens at the center of the screen.
         | 
| 602 | 
            +
                  # @option options {Numeric} :amount (100) How large (in points) the
         | 
| 603 | 
            +
                  #  pinch should be.  This option is ignored when running with UIAutomation.
         | 
| 604 | 
            +
                  # @option options {Numeric} :duration (1.0) duration of the 'pinch'.  The
         | 
| 605 | 
            +
                  #  minimum value of pan in UIAutomation is 0.5.  For DeviceAgent, the
         | 
| 606 | 
            +
                  #  duration must be > 0.
         | 
| 607 | 
            +
                  # @return {Array<Hash>} array containing the serialized version of
         | 
| 608 | 
            +
                  #  the view touched.
         | 
| 609 | 
            +
                  #
         | 
| 610 | 
            +
                  # @raise [ArgumentError] If duration is < 0.5 for UIAutomation and <= 0
         | 
| 611 | 
            +
                  #  for DeviceAgent.
         | 
| 612 | 
            +
                  # @raise [ArgumentError] If in_out argument is invalid.
         | 
| 599 613 | 
             
                  def pinch(in_out, options={})
         | 
| 600 | 
            -
                     | 
| 614 | 
            +
                    merged_options = {
         | 
| 615 | 
            +
                      :query => nil,
         | 
| 616 | 
            +
                      # Ignored by UIAutomation
         | 
| 617 | 
            +
                      :amount => 100,
         | 
| 618 | 
            +
                      :duration => 0.5
         | 
| 619 | 
            +
                    }.merge(options)
         | 
| 620 | 
            +
             | 
| 621 | 
            +
                    symbol = in_out.to_sym
         | 
| 622 | 
            +
             | 
| 623 | 
            +
                    if ![:in, :out].include?(symbol)
         | 
| 624 | 
            +
                      raise ArgumentError, %Q[
         | 
| 625 | 
            +
            Invalid pinch direction: '#{symbol}'.  Valid directions are:
         | 
| 626 | 
            +
             | 
| 627 | 
            +
            "in", "out", :in, :out
         | 
| 628 | 
            +
             | 
| 629 | 
            +
            ]
         | 
| 630 | 
            +
                    end
         | 
| 631 | 
            +
             | 
| 632 | 
            +
                    duration = merged_options[:duration]
         | 
| 633 | 
            +
             | 
| 634 | 
            +
                    if uia_available? && duration < 0.5
         | 
| 635 | 
            +
                      raise ArgumentError, %Q[
         | 
| 636 | 
            +
            Invalid duration: #{duration}
         | 
| 637 | 
            +
             | 
| 638 | 
            +
            The minimum duration is 0.5
         | 
| 639 | 
            +
             | 
| 640 | 
            +
            ]
         | 
| 641 | 
            +
                    elsif duration <= 0.0
         | 
| 642 | 
            +
                      raise ArgumentError, %Q[
         | 
| 643 | 
            +
            Invalid duration: #{duration}
         | 
| 644 | 
            +
             | 
| 645 | 
            +
            The minimum duration is 0.0.
         | 
| 646 | 
            +
             | 
| 647 | 
            +
            ]
         | 
| 648 | 
            +
                    end
         | 
| 649 | 
            +
             | 
| 650 | 
            +
                    launcher.automator.pinch(in_out.to_sym, merged_options)
         | 
| 601 651 | 
             
                  end
         | 
| 602 652 |  | 
| 603 653 | 
             
                  # @deprecated 0.21.0 Use #keyboard_enter_text
         | 
| @@ -757,7 +807,7 @@ To type strings with more than one character, use keyboard_enter_text. | |
| 757 807 | 
             
                  # for the keyboard to disappear.
         | 
| 758 808 | 
             
                  #
         | 
| 759 809 | 
             
                  # @note
         | 
| 760 | 
            -
                  #   | 
| 810 | 
            +
                  #  The dismiss keyboard key does not exist on the iPhone or iPod
         | 
| 761 811 | 
             
                  #
         | 
| 762 812 | 
             
                  # @raise [RuntimeError] If the device is not an iPad
         | 
| 763 813 | 
             
                  # @raise [Calabash::Cucumber::WaitHelpers::WaitError] If the keyboard does
         | 
| @@ -802,38 +852,111 @@ Use `ipad?` to branch in your test. | |
| 802 852 | 
             
                    views_touched
         | 
| 803 853 | 
             
                  end
         | 
| 804 854 |  | 
| 855 | 
            +
                  # Scrolls to a mark in a UIScrollView.
         | 
| 856 | 
            +
                  #
         | 
| 857 | 
            +
                  # Make sure your query matches exactly one UIScrollView.  If multiple
         | 
| 858 | 
            +
                  # scroll views are matched, the results can be unpredictable.
         | 
| 859 | 
            +
                  #
         | 
| 860 | 
            +
                  # @example
         | 
| 861 | 
            +
                  #  scroll_to_mark("settings")
         | 
| 862 | 
            +
                  #  scroll_to_mark("Android", {:animated => false})
         | 
| 863 | 
            +
                  #  scroll_to_mark("Alarm", {:query => "UIScrollView marked:'Settings'"})
         | 
| 864 | 
            +
                  #
         | 
| 865 | 
            +
                  # @see #scroll_to_row_with_mark
         | 
| 866 | 
            +
                  # @see #scroll_to_collection_view_item_with_mark
         | 
| 867 | 
            +
                  #
         | 
| 868 | 
            +
                  # @param [String] mark an accessibility label or identifier or text
         | 
| 869 | 
            +
                  # @param [Hash] options controls the query and and scroll behavior
         | 
| 870 | 
            +
                  # @option options [String] :query ("UIScrollView index:0") A query to
         | 
| 871 | 
            +
                  #  uniquely identify the scroll view if there are multiple scroll views.
         | 
| 872 | 
            +
                  # @option options [Boolean] :animate (true) should the scrolling be animated
         | 
| 873 | 
            +
                  # @option options [String] :failure_message (nil) If nil, a default failure
         | 
| 874 | 
            +
                  #  message will be shown if this scroll scroll cannot be performed.
         | 
| 875 | 
            +
                  #
         | 
| 876 | 
            +
                  # @raise [RuntimeError] If the scroll cannot be performed
         | 
| 877 | 
            +
                  # @raise [RuntimeError] If the :query finds no scroll view
         | 
| 878 | 
            +
                  # @raise [ArgumentError] If the mark is nil
         | 
| 879 | 
            +
                  # @raise [ArgumentError] If the :query value is nil, "", or "*".
         | 
| 880 | 
            +
                  def scroll_to_mark(mark, options={})
         | 
| 881 | 
            +
                    if mark.nil?
         | 
| 882 | 
            +
                      raise ArgumentError, "The mark cannot be nil"
         | 
| 883 | 
            +
                    end
         | 
| 884 | 
            +
             | 
| 885 | 
            +
                    merged_options = {:query => "UIScrollView index:0",
         | 
| 886 | 
            +
                                      :animate => true,
         | 
| 887 | 
            +
                                      :failure_message => nil}.merge(options)
         | 
| 888 | 
            +
             | 
| 889 | 
            +
                    uiquery = merged_options[:query]
         | 
| 890 | 
            +
             | 
| 891 | 
            +
                    if uiquery.nil?
         | 
| 892 | 
            +
                      raise ArgumentError, "The :query option cannot be nil"
         | 
| 893 | 
            +
                    end
         | 
| 894 | 
            +
             | 
| 895 | 
            +
                    if uiquery == ""
         | 
| 896 | 
            +
                      raise ArgumentError, "The :query option cannot be the empty string"
         | 
| 897 | 
            +
                    end
         | 
| 898 | 
            +
             | 
| 899 | 
            +
                    if uiquery == "*"
         | 
| 900 | 
            +
                      raise ArgumentError, "The :query option cannot be the wildcard '*'"
         | 
| 901 | 
            +
                    end
         | 
| 902 | 
            +
             | 
| 903 | 
            +
                    args = [merged_options[:animate]]
         | 
| 904 | 
            +
             | 
| 905 | 
            +
                    views_touched = Map.map(uiquery, :scrollToMark, mark, *args)
         | 
| 906 | 
            +
             | 
| 907 | 
            +
                    message = merged_options[:failure_message]
         | 
| 908 | 
            +
             | 
| 909 | 
            +
                    if !message
         | 
| 910 | 
            +
                      message = %Q[
         | 
| 911 | 
            +
             | 
| 912 | 
            +
            Unable to scroll to mark '#{mark}' in UIScrollView matching #{uiquery}"
         | 
| 913 | 
            +
             | 
| 914 | 
            +
            ]
         | 
| 915 | 
            +
                    end
         | 
| 916 | 
            +
             | 
| 917 | 
            +
                    Map.assert_map_results(views_touched, message)
         | 
| 918 | 
            +
                    views_touched
         | 
| 919 | 
            +
                  end
         | 
| 920 | 
            +
             | 
| 805 921 | 
             
                  # Scroll a table view to a row. Table view should have only one section.
         | 
| 922 | 
            +
                  #
         | 
| 923 | 
            +
                  # Make sure your query matches exactly one UITableView.  If multiple views
         | 
| 924 | 
            +
                  # are matched, the results can be unpredictable.
         | 
| 925 | 
            +
                  #
         | 
| 806 926 | 
             
                  # @see #scroll_to_cell
         | 
| 927 | 
            +
                  #
         | 
| 807 928 | 
             
                  # @example
         | 
| 808 | 
            -
                  #   scroll_to_row "UITableView", 2
         | 
| 809 | 
            -
                  # @note this is implemented by calling the Obj-C `scrollToRowAtIndexPath:atScrollPosition:animated:` method
         | 
| 810 | 
            -
                  #   and can do things users cant.
         | 
| 929 | 
            +
                  #   scroll_to_row "UITableView index:0", 2
         | 
| 811 930 | 
             
                  #
         | 
| 812 | 
            -
                  # @param {String} uiquery  | 
| 931 | 
            +
                  # @param {String} uiquery Should match a UITableView
         | 
| 813 932 | 
             
                  def scroll_to_row(uiquery, number)
         | 
| 814 933 | 
             
                    views_touched = Map.map(uiquery, :scrollToRow, number)
         | 
| 815 | 
            -
                    msg = " | 
| 934 | 
            +
                    msg = "Unable to scroll to row #{number} in table view with '#{uiquery}'"
         | 
| 816 935 | 
             
                    Map.assert_map_results(views_touched, msg)
         | 
| 817 936 | 
             
                    views_touched
         | 
| 818 937 | 
             
                  end
         | 
| 819 938 |  | 
| 820 | 
            -
                  # Scroll a table view to a section and row. | 
| 939 | 
            +
                  # Scroll a table view to a section and row.
         | 
| 940 | 
            +
                  #
         | 
| 941 | 
            +
                  # Make sure your query matches exactly one UITableView.  If multiple views
         | 
| 942 | 
            +
                  # are matched, the results can be unpredictable.
         | 
| 821 943 | 
             
                  #
         | 
| 822 944 | 
             
                  # @todo should expose a non-option first argument query and required parameters `section`, `row`
         | 
| 823 945 | 
             
                  #
         | 
| 824 946 | 
             
                  # @see #scroll_to_row
         | 
| 825 947 | 
             
                  # @example
         | 
| 826 | 
            -
                  #   scroll_to_cell | 
| 827 | 
            -
                  # @note this is implemented by calling the Obj-C `scrollToRowAtIndexPath:atScrollPosition:animated:` method
         | 
| 828 | 
            -
                  #   and can do things users cant.
         | 
| 948 | 
            +
                  #   scroll_to_cell  row:4, section:0, animate: false
         | 
| 829 949 | 
             
                  #
         | 
| 830 950 | 
             
                  # @param {Hash} options specifies details of the scroll
         | 
| 831 | 
            -
                  # @option options {String} :query ( | 
| 951 | 
            +
                  # @option options {String} :query ("UITableView index:0") query specifying
         | 
| 952 | 
            +
                  #   which table view to scroll
         | 
| 832 953 | 
             
                  # @option options {Fixnum} :section section to scroll to
         | 
| 833 954 | 
             
                  # @option options {Fixnum} :row row to scroll to
         | 
| 834 955 | 
             
                  # @option options {String} :scroll_position position to scroll to
         | 
| 835 956 | 
             
                  # @option options {Boolean} :animated (true) animate or not
         | 
| 836 | 
            -
                   | 
| 957 | 
            +
                  # @raise [ArgumentError] If row or section is nil
         | 
| 958 | 
            +
                  # @raise [ArgumentError] If the :query value is nil, "", or "*".
         | 
| 959 | 
            +
                  def scroll_to_cell(options={:query => "UITableView index:0",
         | 
| 837 960 | 
             
                                              :row => 0,
         | 
| 838 961 | 
             
                                              :section => 0,
         | 
| 839 962 | 
             
                                              :scroll_position => :top,
         | 
| @@ -841,8 +964,8 @@ Use `ipad?` to branch in your test. | |
| 841 964 | 
             
                    uiquery = options[:query] || 'tableView'
         | 
| 842 965 | 
             
                    row = options[:row]
         | 
| 843 966 | 
             
                    sec = options[:section]
         | 
| 844 | 
            -
                    if row.nil?  | 
| 845 | 
            -
                      raise 'You must supply both :row and :section keys to scroll_to_cell'
         | 
| 967 | 
            +
                    if row.nil? || sec.nil?
         | 
| 968 | 
            +
                      raise ArgumentError, 'You must supply both :row and :section keys to scroll_to_cell'
         | 
| 846 969 | 
             
                    end
         | 
| 847 970 |  | 
| 848 971 | 
             
                    args = []
         | 
| @@ -862,14 +985,16 @@ Use `ipad?` to branch in your test. | |
| 862 985 |  | 
| 863 986 | 
             
                  # Scrolls to a mark in a UITableView.
         | 
| 864 987 | 
             
                  #
         | 
| 988 | 
            +
                  # Make sure your query matches exactly one UITableView.  If multiple
         | 
| 989 | 
            +
                  # views are matched, the results can be unpredictable.
         | 
| 990 | 
            +
                  #
         | 
| 865 991 | 
             
                  # @example Scroll to the top of the item with the given mark.
         | 
| 866 992 | 
             
                  #  scroll_to_row_with_mark('settings', {:scroll_position => :top})
         | 
| 867 993 | 
             
                  #
         | 
| 868 994 | 
             
                  # @example Scroll to the bottom of the item with the given mark.
         | 
| 869 995 | 
             
                  #  scroll_to_row_with_mark('about', {:scroll_position => :bottom})
         | 
| 870 996 | 
             
                  #
         | 
| 871 | 
            -
                  # @param [String] mark an accessibility  | 
| 872 | 
            -
                  #  or on the row
         | 
| 997 | 
            +
                  # @param [String] mark an accessibility label or identifier or text in row
         | 
| 873 998 | 
             
                  # @param [Hash] options controls the query and and scroll behavior
         | 
| 874 999 | 
             
                  #
         | 
| 875 1000 | 
             
                  # @option options [String] :query ('tableView')
         | 
| @@ -879,38 +1004,64 @@ Use `ipad?` to branch in your test. | |
| 879 1004 | 
             
                  #  `{:middle | :top | :bottom}`
         | 
| 880 1005 | 
             
                  # @option options [Boolean] :animate (true)
         | 
| 881 1006 | 
             
                  #  should the scrolling be animated
         | 
| 1007 | 
            +
                  # @option options [String] :failure_message (nil) If nil, a default failure
         | 
| 1008 | 
            +
                  #  message will be shown if this scroll scroll cannot be performed.
         | 
| 882 1009 | 
             
                  #
         | 
| 883 1010 | 
             
                  # @raise [RuntimeError] if the scroll cannot be performed
         | 
| 884 | 
            -
                  # @raise [RuntimeError] if the mark is nil
         | 
| 885 1011 | 
             
                  # @raise [RuntimeError] if the table query finds no table view
         | 
| 886 1012 | 
             
                  # @raise [RuntimeError] if the scroll position is invalid
         | 
| 887 | 
            -
                   | 
| 888 | 
            -
             | 
| 889 | 
            -
             | 
| 1013 | 
            +
                  # @raise [ArgumentError] if the mark is nil
         | 
| 1014 | 
            +
                  # @raise [ArgumentError] If the :query value is nil, "", or "*".
         | 
| 1015 | 
            +
                  def scroll_to_row_with_mark(mark, options={})
         | 
| 1016 | 
            +
                    merged_options = {:query => "UITableView index:0",
         | 
| 1017 | 
            +
                                      :scroll_position => :middle,
         | 
| 1018 | 
            +
                                      :animate => true,
         | 
| 1019 | 
            +
                                      :failure_message => nil}.merge(options)
         | 
| 1020 | 
            +
             | 
| 890 1021 | 
             
                    if mark.nil?
         | 
| 891 | 
            -
                       | 
| 1022 | 
            +
                      raise ArgumentError, "The mark cannot be nil"
         | 
| 892 1023 | 
             
                    end
         | 
| 893 1024 |  | 
| 894 | 
            -
                    uiquery =  | 
| 1025 | 
            +
                    uiquery = merged_options[:query]
         | 
| 895 1026 |  | 
| 896 | 
            -
                     | 
| 897 | 
            -
             | 
| 898 | 
            -
                      args << options[:scroll_position]
         | 
| 899 | 
            -
                    else
         | 
| 900 | 
            -
                      args << 'middle'
         | 
| 1027 | 
            +
                    if uiquery.nil?
         | 
| 1028 | 
            +
                      raise ArgumentError, "The :query option cannot be nil"
         | 
| 901 1029 | 
             
                    end
         | 
| 902 | 
            -
             | 
| 903 | 
            -
             | 
| 1030 | 
            +
             | 
| 1031 | 
            +
                    if uiquery == ""
         | 
| 1032 | 
            +
                      raise ArgumentError, "The :query option cannot be the empty string"
         | 
| 904 1033 | 
             
                    end
         | 
| 905 1034 |  | 
| 1035 | 
            +
                    if uiquery == "*"
         | 
| 1036 | 
            +
                      raise ArgumentError, "The :query option cannot be the wildcard '*'"
         | 
| 1037 | 
            +
                    end
         | 
| 1038 | 
            +
             | 
| 1039 | 
            +
                    args = [merged_options[:scroll_position], merged_options[:animate]]
         | 
| 1040 | 
            +
             | 
| 906 1041 | 
             
                    views_touched = Map.map(uiquery, :scrollToRowWithMark, mark, *args)
         | 
| 907 | 
            -
             | 
| 908 | 
            -
                     | 
| 1042 | 
            +
             | 
| 1043 | 
            +
                    message = merged_options[:failure_message]
         | 
| 1044 | 
            +
                    if !message
         | 
| 1045 | 
            +
                      message = %Q[
         | 
| 1046 | 
            +
            Unable to scroll to mark: '#{mark}' in table view matched by query:
         | 
| 1047 | 
            +
             | 
| 1048 | 
            +
            #{uiquery}
         | 
| 1049 | 
            +
             | 
| 1050 | 
            +
            with options:
         | 
| 1051 | 
            +
             | 
| 1052 | 
            +
            #{merged_options}
         | 
| 1053 | 
            +
             | 
| 1054 | 
            +
            ]
         | 
| 1055 | 
            +
                    end
         | 
| 1056 | 
            +
                    Map.assert_map_results(views_touched, message)
         | 
| 909 1057 | 
             
                    views_touched
         | 
| 910 1058 | 
             
                  end
         | 
| 911 1059 |  | 
| 912 1060 | 
             
                  # Scrolls to an item in a section of a UICollectionView.
         | 
| 913 1061 | 
             
                  #
         | 
| 1062 | 
            +
                  # Make sure your query matches exactly one UICollectionView.  If multiple
         | 
| 1063 | 
            +
                  # views are matched, the results can be unpredictable.
         | 
| 1064 | 
            +
                  #
         | 
| 914 1065 | 
             
                  # @note item and section are zero-indexed
         | 
| 915 1066 | 
             
                  #
         | 
| 916 1067 | 
             
                  # @example Scroll to item 0 in section 2 to top.
         | 
| @@ -922,12 +1073,12 @@ Use `ipad?` to branch in your test. | |
| 922 1073 | 
             
                  # @example The following are the allowed :scroll_position values.
         | 
| 923 1074 | 
             
                  #  {:top | :center_vertical | :bottom | :left | :center_horizontal | :right}
         | 
| 924 1075 | 
             
                  #
         | 
| 925 | 
            -
                  # @param [Integer]  | 
| 926 | 
            -
                  # @param [Integer]  | 
| 927 | 
            -
                  # @param [Hash]  | 
| 1076 | 
            +
                  # @param [Integer] item_index the index of the item to scroll to.  Must be >= 0.
         | 
| 1077 | 
            +
                  # @param [Integer] section_index the section of the item to scroll to. Must be > 0.
         | 
| 1078 | 
            +
                  # @param [Hash] options options for controlling the collection view query
         | 
| 928 1079 | 
             
                  #  and scroll behavior
         | 
| 929 1080 | 
             
                  #
         | 
| 930 | 
            -
                  # @option opts [String] :query ( | 
| 1081 | 
            +
                  # @option opts [String] :query ("UICollectionView index:0")
         | 
| 931 1082 | 
             
                  #  the query that is used to identify which collection view to scroll
         | 
| 932 1083 | 
             
                  #
         | 
| 933 1084 | 
             
                  # @option opts [Symbol] :scroll_position (top)
         | 
| @@ -936,46 +1087,86 @@ Use `ipad?` to branch in your test. | |
| 936 1087 | 
             
                  # @option opts [Boolean] :animate (true)
         | 
| 937 1088 | 
             
                  #  should the scrolling be animated
         | 
| 938 1089 | 
             
                  #
         | 
| 939 | 
            -
                  # @option opts [String] : | 
| 1090 | 
            +
                  # @option opts [String] :failure_message (nil)
         | 
| 940 1091 | 
             
                  #  a custom error message to display if the scrolling fails - if not
         | 
| 941 1092 | 
             
                  #  specified, a generic failure will be displayed
         | 
| 942 1093 | 
             
                  #
         | 
| 943 1094 | 
             
                  # @raise [RuntimeError] if the scroll cannot be performed
         | 
| 944 1095 | 
             
                  # @raise [RuntimeError] :query finds no collection view
         | 
| 945 1096 | 
             
                  # @raise [RuntimeError] the collection view does not contain a cell at item/section
         | 
| 946 | 
            -
                  # @raise [ | 
| 947 | 
            -
                   | 
| 948 | 
            -
             | 
| 1097 | 
            +
                  # @raise [ArgumentError] :scroll_position is invalid
         | 
| 1098 | 
            +
                  # @raise [ArgumentError] item or section is < 0.
         | 
| 1099 | 
            +
                  # @raise [ArgumentError] If the :query value is nil, "", or "*".
         | 
| 1100 | 
            +
                  def scroll_to_collection_view_item(item_index, section_index, options={})
         | 
| 1101 | 
            +
                    default_options = {:query => "UICollectionView index:0",
         | 
| 949 1102 | 
             
                                       :scroll_position => :top,
         | 
| 950 1103 | 
             
                                       :animate => true,
         | 
| 951 | 
            -
                                       : | 
| 952 | 
            -
                     | 
| 953 | 
            -
                    uiquery =  | 
| 1104 | 
            +
                                       :failure_message => nil}
         | 
| 1105 | 
            +
                    merged_options = default_options.merge(options)
         | 
| 1106 | 
            +
                    uiquery = merged_options[:query]
         | 
| 1107 | 
            +
             | 
| 1108 | 
            +
                    if uiquery.nil?
         | 
| 1109 | 
            +
                      raise ArgumentError, "The :query option cannot be nil"
         | 
| 1110 | 
            +
                    end
         | 
| 1111 | 
            +
             | 
| 1112 | 
            +
                    if uiquery == ""
         | 
| 1113 | 
            +
                      raise ArgumentError, "The :query option cannot be the empty string"
         | 
| 1114 | 
            +
                    end
         | 
| 1115 | 
            +
             | 
| 1116 | 
            +
                    if uiquery == "*"
         | 
| 1117 | 
            +
                      raise ArgumentError, "The :query option cannot be the wildcard '*'"
         | 
| 1118 | 
            +
                    end
         | 
| 1119 | 
            +
             | 
| 1120 | 
            +
                    if item_index < 0
         | 
| 1121 | 
            +
                      raise ArgumentError, "Invalid item index: '#{item_index}' - must be >= 0"
         | 
| 1122 | 
            +
                    end
         | 
| 1123 | 
            +
             | 
| 1124 | 
            +
                    if section_index < 0
         | 
| 1125 | 
            +
                      raise ArgumentError, "Invalid section index: '#{section_index}' - must be >= 0"
         | 
| 1126 | 
            +
                    end
         | 
| 954 1127 |  | 
| 955 | 
            -
                    scroll_position =  | 
| 1128 | 
            +
                    scroll_position = merged_options[:scroll_position]
         | 
| 956 1129 | 
             
                    candidates = [:top, :center_vertical, :bottom, :left, :center_horizontal, :right]
         | 
| 957 | 
            -
                     | 
| 958 | 
            -
                      raise  | 
| 1130 | 
            +
                    if !candidates.include?(scroll_position)
         | 
| 1131 | 
            +
                      raise ArgumentError, %Q[
         | 
| 1132 | 
            +
             | 
| 1133 | 
            +
            Invalid :scroll_position option '#{scroll_position}'.  Valid options are:
         | 
| 1134 | 
            +
             | 
| 1135 | 
            +
            #{candidates.join(", ")}
         | 
| 1136 | 
            +
             | 
| 1137 | 
            +
                      ]
         | 
| 959 1138 | 
             
                    end
         | 
| 960 1139 |  | 
| 961 | 
            -
                    animate =  | 
| 1140 | 
            +
                    animate = merged_options[:animate]
         | 
| 962 1141 |  | 
| 963 1142 | 
             
                    views_touched = Map.map(uiquery, :collectionViewScroll,
         | 
| 964 | 
            -
                                             | 
| 1143 | 
            +
                                            item_index.to_i, section_index.to_i,
         | 
| 965 1144 | 
             
                                            scroll_position, animate)
         | 
| 966 1145 |  | 
| 967 | 
            -
                     | 
| 968 | 
            -
             | 
| 969 | 
            -
             | 
| 970 | 
            -
             | 
| 1146 | 
            +
                    message = merged_options[:failure_message]
         | 
| 1147 | 
            +
                    if !message
         | 
| 1148 | 
            +
                      message = %Q[
         | 
| 1149 | 
            +
            Unable to scroll to item index '#{item_index}' in section index '#{section_index}'
         | 
| 1150 | 
            +
            in CollectionView matched by:
         | 
| 1151 | 
            +
             | 
| 1152 | 
            +
            #{uiquery}
         | 
| 1153 | 
            +
             | 
| 1154 | 
            +
            with options:
         | 
| 1155 | 
            +
             | 
| 1156 | 
            +
            #{merged_options}
         | 
| 1157 | 
            +
             | 
| 1158 | 
            +
            ]
         | 
| 971 1159 | 
             
                    end
         | 
| 972 1160 |  | 
| 973 | 
            -
                    Map.assert_map_results(views_touched,  | 
| 1161 | 
            +
                    Map.assert_map_results(views_touched, message)
         | 
| 974 1162 | 
             
                    views_touched
         | 
| 975 1163 | 
             
                  end
         | 
| 976 1164 |  | 
| 977 1165 | 
             
                  # Scrolls to mark in a UICollectionView.
         | 
| 978 1166 | 
             
                  #
         | 
| 1167 | 
            +
                  # Make sure your query matches exactly one UICollectionView.  If multiple
         | 
| 1168 | 
            +
                  # views are matched, the results can be unpredictable.
         | 
| 1169 | 
            +
                  #
         | 
| 979 1170 | 
             
                  # @example Scroll to the top of the item with the given mark.
         | 
| 980 1171 | 
             
                  #  scroll_to_collection_view_item_with_mark('cat', {:scroll_position => :top})
         | 
| 981 1172 | 
             
                  #
         | 
| @@ -987,7 +1178,7 @@ Use `ipad?` to branch in your test. | |
| 987 1178 | 
             
                  #
         | 
| 988 1179 | 
             
                  # @param [String] mark an accessibility `{label | identifier}` or text in
         | 
| 989 1180 | 
             
                  #  or on the item
         | 
| 990 | 
            -
                  # @param [Hash]  | 
| 1181 | 
            +
                  # @param [Hash] options options for controlling the collection view query
         | 
| 991 1182 | 
             
                  #  and scroll behavior
         | 
| 992 1183 | 
             
                  #
         | 
| 993 1184 | 
             
                  # @option opts [String] :query ('collectionView')
         | 
| @@ -996,43 +1187,74 @@ Use `ipad?` to branch in your test. | |
| 996 1187 | 
             
                  #   the position in the collection view to scroll the item to
         | 
| 997 1188 | 
             
                  # @option opts [Boolean] :animate (true) should the scroll
         | 
| 998 1189 | 
             
                  #   be animated
         | 
| 999 | 
            -
                  # @option opts [String] : | 
| 1000 | 
            -
                  # | 
| 1001 | 
            -
                  # | 
| 1190 | 
            +
                  # @option opts [String] :failure_message (nil) a custom error message to
         | 
| 1191 | 
            +
                  #   display if the scrolling fails - if not specified, a generic failure
         | 
| 1192 | 
            +
                  #   will be displayed
         | 
| 1002 1193 | 
             
                  #
         | 
| 1003 1194 | 
             
                  # @raise [RuntimeError] if the scroll cannot be performed
         | 
| 1004 | 
            -
                  # @raise [RuntimeError] if the mark is nil
         | 
| 1005 1195 | 
             
                  # @raise [RuntimeError] :query finds no collection view
         | 
| 1006 1196 | 
             
                  # @raise [RuntimeError] the collection view does not contain a cell
         | 
| 1007 1197 | 
             
                  #  with the mark
         | 
| 1008 1198 | 
             
                  # @raise [RuntimeError] :scroll_position is invalid
         | 
| 1009 | 
            -
                   | 
| 1010 | 
            -
             | 
| 1199 | 
            +
                  # @raise [ArgumentError] If the :query value is nil, "", or "*".
         | 
| 1200 | 
            +
                  # @raise [ArgumentError] if the mark is nil
         | 
| 1201 | 
            +
                  def scroll_to_collection_view_item_with_mark(mark, options={})
         | 
| 1202 | 
            +
                    default_options = {:query => "UICollectionView index:0",
         | 
| 1011 1203 | 
             
                                       :scroll_position => :top,
         | 
| 1012 1204 | 
             
                                       :animate => true,
         | 
| 1013 | 
            -
                                       : | 
| 1014 | 
            -
                     | 
| 1015 | 
            -
                    uiquery =  | 
| 1205 | 
            +
                                       :failure_message => nil}
         | 
| 1206 | 
            +
                    merged_options = default_options.merge(options)
         | 
| 1207 | 
            +
                    uiquery = merged_options[:query]
         | 
| 1016 1208 |  | 
| 1017 1209 | 
             
                    if mark.nil?
         | 
| 1018 | 
            -
                      raise  | 
| 1210 | 
            +
                      raise ArgumentError, "The mark cannot be nil"
         | 
| 1019 1211 | 
             
                    end
         | 
| 1020 1212 |  | 
| 1021 | 
            -
                     | 
| 1022 | 
            -
             | 
| 1213 | 
            +
                    if uiquery.nil?
         | 
| 1214 | 
            +
                      raise ArgumentError, "The :query option cannot be nil"
         | 
| 1215 | 
            +
                    end
         | 
| 1216 | 
            +
             | 
| 1217 | 
            +
                    if uiquery == ""
         | 
| 1218 | 
            +
                      raise ArgumentError, "The :query option cannot be the empty string"
         | 
| 1219 | 
            +
                    end
         | 
| 1220 | 
            +
             | 
| 1221 | 
            +
                    if uiquery == "*"
         | 
| 1222 | 
            +
                      raise ArgumentError, "The :query option cannot be the wildcard '*'"
         | 
| 1223 | 
            +
                    end
         | 
| 1224 | 
            +
             | 
| 1225 | 
            +
                    scroll_position = merged_options[:scroll_position]
         | 
| 1023 1226 | 
             
                    candidates = [:top, :center_vertical, :bottom, :left, :center_horizontal, :right]
         | 
| 1024 | 
            -
                     | 
| 1025 | 
            -
                      raise  | 
| 1227 | 
            +
                    if !candidates.include?(scroll_position)
         | 
| 1228 | 
            +
                      raise ArgumentError, %Q[
         | 
| 1229 | 
            +
             | 
| 1230 | 
            +
            Invalid :scroll_position option '#{scroll_position}'.  Valid options are:
         | 
| 1231 | 
            +
             | 
| 1232 | 
            +
            #{candidates.join(", ")}
         | 
| 1233 | 
            +
             | 
| 1234 | 
            +
                      ]
         | 
| 1026 1235 | 
             
                    end
         | 
| 1027 1236 |  | 
| 1028 | 
            -
                    args  | 
| 1029 | 
            -
                    args << opts[:animate]
         | 
| 1237 | 
            +
                    args = [scroll_position, merged_options[:animate]]
         | 
| 1030 1238 |  | 
| 1031 | 
            -
                    views_touched = Map.map(uiquery, | 
| 1239 | 
            +
                    views_touched = Map.map(uiquery,
         | 
| 1240 | 
            +
                                            :collectionViewScrollToItemWithMark,
         | 
| 1032 1241 | 
             
                                            mark, *args)
         | 
| 1033 1242 |  | 
| 1034 | 
            -
                     | 
| 1035 | 
            -
                     | 
| 1243 | 
            +
                    message = merged_options[:failure_message]
         | 
| 1244 | 
            +
                    if !message
         | 
| 1245 | 
            +
                      message = %Q[
         | 
| 1246 | 
            +
            Unable to scroll to item with mark '#{mark}' in UICollectionView matching query:
         | 
| 1247 | 
            +
             | 
| 1248 | 
            +
            #{uiquery}
         | 
| 1249 | 
            +
             | 
| 1250 | 
            +
            with options:
         | 
| 1251 | 
            +
             | 
| 1252 | 
            +
            #{merged_options}
         | 
| 1253 | 
            +
             | 
| 1254 | 
            +
            ]
         | 
| 1255 | 
            +
                    end
         | 
| 1256 | 
            +
             | 
| 1257 | 
            +
                    Map.assert_map_results(views_touched, message)
         | 
| 1036 1258 | 
             
                    views_touched
         | 
| 1037 1259 | 
             
                  end
         | 
| 1038 1260 |  | 
| @@ -239,6 +239,12 @@ module Calabash | |
| 239 239 | 
             
                    ios_version_object.major.to_s
         | 
| 240 240 | 
             
                  end
         | 
| 241 241 |  | 
| 242 | 
            +
                  # Is this device running iOS 10?
         | 
| 243 | 
            +
                  # @return [Boolean] true if the major version of the OS is 10
         | 
| 244 | 
            +
                  def ios10?
         | 
| 245 | 
            +
                    ios_version_object.major == 10
         | 
| 246 | 
            +
                  end
         | 
| 247 | 
            +
             | 
| 242 248 | 
             
                  # Is this device running iOS 9?
         | 
| 243 249 | 
             
                  # @return [Boolean] true if the major version of the OS is 9
         | 
| 244 250 | 
             
                  def ios9?
         | 
| @@ -24,7 +24,7 @@ module Calabash | |
| 24 24 | 
             
                    @world = world
         | 
| 25 25 | 
             
                  end
         | 
| 26 26 |  | 
| 27 | 
            -
                  #  | 
| 27 | 
            +
                  # Query the UI for elements.
         | 
| 28 28 | 
             
                  #
         | 
| 29 29 | 
             
                  # @example
         | 
| 30 30 | 
             
                  #  query({id: "login", :type "Button"})
         | 
| @@ -126,7 +126,7 @@ module Calabash | |
| 126 126 | 
             
                  #
         | 
| 127 127 | 
             
                  # @raise [RuntimeError] if no view matches the uiquery after waiting.
         | 
| 128 128 | 
             
                  def query_for_coordinate(uiquery)
         | 
| 129 | 
            -
                     | 
| 129 | 
            +
                    with_screenshot_on_failure { client.query_for_coordinate(uiquery) }
         | 
| 130 130 | 
             
                  end
         | 
| 131 131 |  | 
| 132 132 | 
             
                  # Perform a touch on the center of the first view matched the uiquery.
         | 
| @@ -140,7 +140,7 @@ module Calabash | |
| 140 140 | 
             
                  #
         | 
| 141 141 | 
             
                  # @raise [RuntimeError] if no view matches the uiquery after waiting.
         | 
| 142 142 | 
             
                  def touch(uiquery)
         | 
| 143 | 
            -
                     | 
| 143 | 
            +
                    with_screenshot_on_failure { client.touch(uiquery) }
         | 
| 144 144 | 
             
                  end
         | 
| 145 145 |  | 
| 146 146 | 
             
                  # Perform a touch at a coordinate.
         | 
| @@ -173,7 +173,7 @@ module Calabash | |
| 173 173 | 
             
                  #
         | 
| 174 174 | 
             
                  # @raise [RuntimeError] if no view matches the uiquery after waiting.
         | 
| 175 175 | 
             
                  def double_tap(uiquery)
         | 
| 176 | 
            -
                     | 
| 176 | 
            +
                    with_screenshot_on_failure { client.double_tap(uiquery) }
         | 
| 177 177 | 
             
                  end
         | 
| 178 178 |  | 
| 179 179 | 
             
                  # Perform a two finger tap on the center of the first view matched the uiquery.
         | 
| @@ -187,7 +187,7 @@ module Calabash | |
| 187 187 | 
             
                  #
         | 
| 188 188 | 
             
                  # @raise [RuntimeError] if no view matches the uiquery after waiting.
         | 
| 189 189 | 
             
                  def two_finger_tap(uiquery)
         | 
| 190 | 
            -
                     | 
| 190 | 
            +
                    with_screenshot_on_failure { client.two_finger_tap(uiquery) }
         | 
| 191 191 | 
             
                  end
         | 
| 192 192 |  | 
| 193 193 | 
             
                  # Perform a long press on the center of the first view matched the uiquery.
         | 
| @@ -202,7 +202,7 @@ module Calabash | |
| 202 202 | 
             
                  #
         | 
| 203 203 | 
             
                  # @raise [RuntimeError] if no view matches the uiquery after waiting.
         | 
| 204 204 | 
             
                  def long_press(uiquery, duration)
         | 
| 205 | 
            -
                     | 
| 205 | 
            +
                    with_screenshot_on_failure { client.long_press(uiquery, {:duration => duration}) }
         | 
| 206 206 | 
             
                  end
         | 
| 207 207 |  | 
| 208 208 | 
             
                  # Returns true if there is a keyboard visible.
         | 
| @@ -228,7 +228,7 @@ module Calabash | |
| 228 228 | 
             
                  # @raise [RuntimeError] if there is no visible keyboard.
         | 
| 229 229 | 
             
                  # @deprecated 0.21.0 Use Core#enter_text
         | 
| 230 230 | 
             
                  def enter_text(text)
         | 
| 231 | 
            -
                     | 
| 231 | 
            +
                    with_screenshot_on_failure { client.enter_text(text) }
         | 
| 232 232 | 
             
                  end
         | 
| 233 233 |  | 
| 234 234 | 
             
                  # Enter text into the first view matched by uiquery.
         | 
| @@ -244,7 +244,7 @@ module Calabash | |
| 244 244 | 
             
                  #
         | 
| 245 245 | 
             
                  # @deprecated 0.21.0 Use Core#enter_text
         | 
| 246 246 | 
             
                  def enter_text_in(uiquery, text)
         | 
| 247 | 
            -
                     | 
| 247 | 
            +
                    with_screenshot_on_failure do
         | 
| 248 248 | 
             
                      client.touch(uiquery)
         | 
| 249 249 | 
             
                      client.wait_for_keyboard
         | 
| 250 250 | 
             
                      client.enter_text(text)
         | 
| @@ -311,20 +311,6 @@ module Calabash | |
| 311 311 | 
             
                    client.springboard_alert
         | 
| 312 312 | 
             
                  end
         | 
| 313 313 |  | 
| 314 | 
            -
            =begin
         | 
| 315 | 
            -
            PROTECTED
         | 
| 316 | 
            -
            =end
         | 
| 317 | 
            -
                  protected
         | 
| 318 | 
            -
             | 
| 319 | 
            -
                  # @!visibility private
         | 
| 320 | 
            -
                  def method_missing(name, *args, &block)
         | 
| 321 | 
            -
                    if world.respond_to?(name)
         | 
| 322 | 
            -
                      world.send(name, *args, &block)
         | 
| 323 | 
            -
                    else
         | 
| 324 | 
            -
                      super
         | 
| 325 | 
            -
                    end
         | 
| 326 | 
            -
                  end
         | 
| 327 | 
            -
             | 
| 328 314 | 
             
            =begin
         | 
| 329 315 | 
             
            PRIVATE
         | 
| 330 316 | 
             
            =end
         | 
| @@ -334,7 +320,7 @@ PRIVATE | |
| 334 320 | 
             
                  attr_reader :client, :world
         | 
| 335 321 |  | 
| 336 322 | 
             
                  # @!visibility private
         | 
| 337 | 
            -
                  def  | 
| 323 | 
            +
                  def with_screenshot_on_failure(&block)
         | 
| 338 324 | 
             
                    begin
         | 
| 339 325 | 
             
                      block.call
         | 
| 340 326 | 
             
                    rescue => e
         | 
| @@ -192,6 +192,14 @@ module Calabash | |
| 192 192 | 
             
                   _default_device_or_create.ios9?
         | 
| 193 193 | 
             
                  end
         | 
| 194 194 |  | 
| 195 | 
            +
                  # Is the device under test running iOS 10?
         | 
| 196 | 
            +
                  #
         | 
| 197 | 
            +
                  # @raise [RuntimeError] if the server cannot be reached
         | 
| 198 | 
            +
                  # @return [Boolean] true if device under test is running iOS 9
         | 
| 199 | 
            +
                  def ios10?
         | 
| 200 | 
            +
                   _default_device_or_create.ios10?
         | 
| 201 | 
            +
                  end
         | 
| 202 | 
            +
             | 
| 195 203 | 
             
                  # Is the app that is being tested an iPhone app emulated on an iPad?
         | 
| 196 204 | 
             
                  #
         | 
| 197 205 | 
             
                  # @see Calabash::Cucumber::IPad
         | 
| @@ -173,14 +173,19 @@ module Calabash | |
| 173 173 | 
             
                      screenshot_and_raise "There must be a visible keyboard"
         | 
| 174 174 | 
             
                    end
         | 
| 175 175 |  | 
| 176 | 
            -
                     | 
| 177 | 
            -
             | 
| 178 | 
            -
             | 
| 179 | 
            -
             | 
| 180 | 
            -
             | 
| 181 | 
            -
             | 
| 182 | 
            -
             | 
| 183 | 
            -
                     | 
| 176 | 
            +
                    query = "* isFirstResponder:1"
         | 
| 177 | 
            +
                    elements = _query_wrapper(query, :text)
         | 
| 178 | 
            +
             | 
| 179 | 
            +
                    return "" if elements.count == 0
         | 
| 180 | 
            +
             | 
| 181 | 
            +
                    text = elements[0]
         | 
| 182 | 
            +
             | 
| 183 | 
            +
                    # first responder did not respond to :text selector
         | 
| 184 | 
            +
                    return "" if text == "*****"
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                    return "" if text.nil?
         | 
| 187 | 
            +
             | 
| 188 | 
            +
                    text
         | 
| 184 189 | 
             
                  end
         | 
| 185 190 |  | 
| 186 191 | 
             
                  # @visibility private
         | 
| @@ -132,11 +132,11 @@ module Calabash | |
| 132 132 | 
             
                  #
         | 
| 133 133 | 
             
                  # +1 for tools to ask physical devices about attributes.
         | 
| 134 134 | 
             
                  def device
         | 
| 135 | 
            -
                    @device ||=  | 
| 135 | 
            +
                    @device ||= begin
         | 
| 136 136 | 
             
                      _, body = Calabash::Cucumber::HTTP.ensure_connectivity
         | 
| 137 137 | 
             
                      endpoint = Calabash::Cucumber::Environment.device_endpoint
         | 
| 138 138 | 
             
                      Calabash::Cucumber::Device.new(endpoint, body)
         | 
| 139 | 
            -
                    end | 
| 139 | 
            +
                    end
         | 
| 140 140 | 
             
                  end
         | 
| 141 141 |  | 
| 142 142 | 
             
                  # @!visibility private
         | 
| @@ -170,20 +170,6 @@ module Calabash | |
| 170 170 | 
             
                                       :http_connection_timeout => 10}
         | 
| 171 171 | 
             
                    merged_options = default_options.merge(options)
         | 
| 172 172 |  | 
| 173 | 
            -
                    @run_loop = RunLoop::HostCache.default.read
         | 
| 174 | 
            -
             | 
| 175 | 
            -
                    if @run_loop[:automator] == :device_agent
         | 
| 176 | 
            -
                      # TODO Attach to DeviceAgent - run-loop supports this!
         | 
| 177 | 
            -
                      # TODO Rewrite UIA methods to raise in the context of UIA
         | 
| 178 | 
            -
                      raise RuntimeError, %Q[
         | 
| 179 | 
            -
             | 
| 180 | 
            -
            Cannot attach to DeviceAgent automator.
         | 
| 181 | 
            -
             | 
| 182 | 
            -
            This behavior is not implemented yet.
         | 
| 183 | 
            -
             | 
| 184 | 
            -
            ]
         | 
| 185 | 
            -
                    end
         | 
| 186 | 
            -
             | 
| 187 173 | 
             
                    begin
         | 
| 188 174 | 
             
                      Calabash::Cucumber::HTTP.ensure_connectivity(merged_options)
         | 
| 189 175 | 
             
                    rescue Calabash::Cucumber::ServerNotRespondingError => _
         | 
| @@ -207,13 +193,22 @@ Try `start_test_server_in_background` | |
| 207 193 | 
             
                      return false
         | 
| 208 194 | 
             
                    end
         | 
| 209 195 |  | 
| 210 | 
            -
                     | 
| 211 | 
            -
             | 
| 196 | 
            +
                    # TODO check that the :pid is alive - no sense attaching if Automator
         | 
| 197 | 
            +
                    # is not running.
         | 
| 198 | 
            +
                    run_loop_cache = RunLoop::HostCache.default.read
         | 
| 199 | 
            +
             | 
| 200 | 
            +
                    if run_loop_cache[:automator] == :device_agent
         | 
| 201 | 
            +
                      # Sets the @run_loop variable to a new RunLoop::DeviceAgent::Client
         | 
| 202 | 
            +
                      # instance.
         | 
| 203 | 
            +
                      @automator = _attach_to_device_agent!(run_loop_cache)
         | 
| 204 | 
            +
                    elsif run_loop_cache[:automator] == :instruments
         | 
| 205 | 
            +
                      @run_loop = run_loop_cache
         | 
| 206 | 
            +
                      @automator = Calabash::Cucumber::Automator::Instruments.new(run_loop_cache)
         | 
| 212 207 | 
             
                    else
         | 
| 213 208 | 
             
                      RunLoop.log_warn(
         | 
| 214 209 | 
             
            %Q[
         | 
| 215 210 |  | 
| 216 | 
            -
            Connected to an app that was not launched by Calabash using instruments.
         | 
| 211 | 
            +
            Connected to an app that was not launched by Calabash using instruments or DeviceAgent.
         | 
| 217 212 |  | 
| 218 213 | 
             
            Queries will work, but gestures and other automator actions will not.
         | 
| 219 214 |  | 
| @@ -627,6 +622,28 @@ true.  Please remove this method call from your hooks. | |
| 627 622 | 
             
                      value
         | 
| 628 623 | 
             
                    end
         | 
| 629 624 | 
             
                  end
         | 
| 625 | 
            +
             | 
| 626 | 
            +
                  # @!visibility private
         | 
| 627 | 
            +
                  def _attach_to_device_agent!(hash)
         | 
| 628 | 
            +
                    simctl = Calabash::Cucumber::Environment.simctl
         | 
| 629 | 
            +
                    instruments = Calabash::Cucumber::Environment.instruments
         | 
| 630 | 
            +
                    xcode = Calabash::Cucumber::Environment.xcode
         | 
| 631 | 
            +
             | 
| 632 | 
            +
                    options = { simctl: simctl, instruments: instruments, xcode: xcode}
         | 
| 633 | 
            +
                    device = RunLoop::Device.device_with_identifier(hash[:udid], options)
         | 
| 634 | 
            +
                    bundle_id = hash[:app]
         | 
| 635 | 
            +
             | 
| 636 | 
            +
                    options = { cbx_launcher: hash[:launcher] }
         | 
| 637 | 
            +
                    cbx_launcher = RunLoop::DeviceAgent::Client.detect_cbx_launcher(options, device)
         | 
| 638 | 
            +
                    launcher_options = hash[:launcher_options]
         | 
| 639 | 
            +
             | 
| 640 | 
            +
                    device_agent_client = RunLoop::DeviceAgent::Client.new(bundle_id,
         | 
| 641 | 
            +
                                                                           device,
         | 
| 642 | 
            +
                                                                           cbx_launcher,
         | 
| 643 | 
            +
                                                                           launcher_options)
         | 
| 644 | 
            +
                    @run_loop = device_agent_client
         | 
| 645 | 
            +
                    Calabash::Cucumber::Automator::DeviceAgent.new(@run_loop)
         | 
| 646 | 
            +
                  end
         | 
| 630 647 | 
             
                end
         | 
| 631 648 | 
             
              end
         | 
| 632 649 | 
             
            end
         | 
| @@ -145,7 +145,7 @@ details: #{hash["details"]} | |
| 145 145 | 
             
                  def self.assert_map_results(map_results, msg)
         | 
| 146 146 | 
             
                    compact = map_results.compact
         | 
| 147 147 | 
             
                    if compact.empty? or compact.member? '<VOID>' or compact.member? '*****'
         | 
| 148 | 
            -
                       | 
| 148 | 
            +
                      self.map_factory.screenshot_and_raise msg
         | 
| 149 149 | 
             
                    end
         | 
| 150 150 | 
             
                  end
         | 
| 151 151 |  | 
| @@ -163,7 +163,7 @@ module Calabash | |
| 163 163 | 
             
                    hash = {
         | 
| 164 164 | 
             
                      :event_name => "session",
         | 
| 165 165 | 
             
                      :data_version => DATA_VERSION,
         | 
| 166 | 
            -
                      : | 
| 166 | 
            +
                      :distinct_id => user_id
         | 
| 167 167 | 
             
                    }
         | 
| 168 168 |  | 
| 169 169 | 
             
                    if allowed == "system_info"
         | 
| @@ -178,6 +178,9 @@ module Calabash | |
| 178 178 | 
             
                          :used_cucumber => used_cucumber?,
         | 
| 179 179 |  | 
| 180 180 | 
             
                          :version => Calabash::Cucumber::VERSION,
         | 
| 181 | 
            +
                          :run_loop_version => RunLoop::VERSION,
         | 
| 182 | 
            +
             | 
| 183 | 
            +
                          :xcode_version => RunLoop::Xcode.new.version,
         | 
| 181 184 |  | 
| 182 185 | 
             
                          :ci => RunLoop::Environment.ci?,
         | 
| 183 186 | 
             
                          :jenkins => RunLoop::Environment.jenkins?,
         | 
| @@ -3,10 +3,10 @@ module Calabash | |
| 3 3 |  | 
| 4 4 | 
             
                # @!visibility public
         | 
| 5 5 | 
             
                # The Calabash iOS gem version.
         | 
| 6 | 
            -
                VERSION = "0.20. | 
| 6 | 
            +
                VERSION = "0.20.3"
         | 
| 7 7 |  | 
| 8 8 | 
             
                # @!visibility public
         | 
| 9 9 | 
             
                # The minimum required version of the Calabash embedded server.
         | 
| 10 | 
            -
                MIN_SERVER_VERSION = "0.20. | 
| 10 | 
            +
                MIN_SERVER_VERSION = "0.20.3"
         | 
| 11 11 | 
             
              end
         | 
| 12 12 | 
             
            end
         | 
    
        data/scripts/.irbrc
    CHANGED
    
    
| Binary file | 
| Binary file | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: calabash-cucumber
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.20. | 
| 4 | 
            +
              version: 0.20.3
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Karl Krukow
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2016- | 
| 11 | 
            +
            date: 2016-10-14 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: cucumber
         | 
| @@ -84,7 +84,7 @@ dependencies: | |
| 84 84 | 
             
                requirements:
         | 
| 85 85 | 
             
                - - ">="
         | 
| 86 86 | 
             
                  - !ruby/object:Gem::Version
         | 
| 87 | 
            -
                    version: 2. | 
| 87 | 
            +
                    version: 2.7.1
         | 
| 88 88 | 
             
                - - "<"
         | 
| 89 89 | 
             
                  - !ruby/object:Gem::Version
         | 
| 90 90 | 
             
                    version: '3.0'
         | 
| @@ -94,7 +94,7 @@ dependencies: | |
| 94 94 | 
             
                requirements:
         | 
| 95 95 | 
             
                - - ">="
         | 
| 96 96 | 
             
                  - !ruby/object:Gem::Version
         | 
| 97 | 
            -
                    version: 2. | 
| 97 | 
            +
                    version: 2.7.1
         | 
| 98 98 | 
             
                - - "<"
         | 
| 99 99 | 
             
                  - !ruby/object:Gem::Version
         | 
| 100 100 | 
             
                    version: '3.0'
         | 
| @@ -132,7 +132,7 @@ dependencies: | |
| 132 132 | 
             
                requirements:
         | 
| 133 133 | 
             
                - - ">="
         | 
| 134 134 | 
             
                  - !ruby/object:Gem::Version
         | 
| 135 | 
            -
                    version: 2.2. | 
| 135 | 
            +
                    version: 2.2.2
         | 
| 136 136 | 
             
                - - "<"
         | 
| 137 137 | 
             
                  - !ruby/object:Gem::Version
         | 
| 138 138 | 
             
                    version: '3.0'
         | 
| @@ -142,7 +142,7 @@ dependencies: | |
| 142 142 | 
             
                requirements:
         | 
| 143 143 | 
             
                - - ">="
         | 
| 144 144 | 
             
                  - !ruby/object:Gem::Version
         | 
| 145 | 
            -
                    version: 2.2. | 
| 145 | 
            +
                    version: 2.2.2
         | 
| 146 146 | 
             
                - - "<"
         | 
| 147 147 | 
             
                  - !ruby/object:Gem::Version
         | 
| 148 148 | 
             
                    version: '3.0'
         | 
| @@ -286,6 +286,20 @@ dependencies: | |
| 286 286 | 
             
                - - ">="
         | 
| 287 287 | 
             
                  - !ruby/object:Gem::Version
         | 
| 288 288 | 
             
                    version: '0'
         | 
| 289 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 290 | 
            +
              name: rb-readline
         | 
| 291 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 292 | 
            +
                requirements:
         | 
| 293 | 
            +
                - - ">="
         | 
| 294 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 295 | 
            +
                    version: '0'
         | 
| 296 | 
            +
              type: :development
         | 
| 297 | 
            +
              prerelease: false
         | 
| 298 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 299 | 
            +
                requirements:
         | 
| 300 | 
            +
                - - ">="
         | 
| 301 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 302 | 
            +
                    version: '0'
         | 
| 289 303 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 290 304 | 
             
              name: guard-rspec
         | 
| 291 305 | 
             
              requirement: !ruby/object:Gem::Requirement
         |