Module: Calabash::Cucumber::KeyboardHelpers
- Includes:
- Logging, TestsHelpers
- Included in:
- Operations
- Defined in:
- lib/calabash-cucumber/keyboard_helpers.rb
Overview
We have an exhaustive set of keyboard related test.s The API is reasonably stable. We are fighting against known bugs in Apple’s UIAutomation. You should only need to fall back to the examples below in unusual situations.
Collection of methods for interacting with the keyboard.
We’ve gone to great lengths to provide the fastest keyboard entry possible.
If you are having trouble with skipped or are receiving JSON octet errors when typing, you might be able to resolve the problems by slowing down the rate of typing.
Example: Use keyboard_enter_char + :wait_after_char.
“‘ str.each_char do |char|
# defaults to 0.05 seconds
keyboard_enter_char(char, `{wait_after_char:0.5}`)
end “‘
Example: Use keyboard_enter_char + POST_ENTER_KEYBOARD
“‘ $ POST_ENTER_KEYBOARD=0.1 bundle exec cucumber str.each_char do |char|
# defaults to 0.05 seconds
keyboard_enter_char(char)
end “‘
Instance Method Summary collapse
-
#_touch_top_keyboard_mode_row ⇒ Object
Touches the top option on the popup dialog that is presented when the the iPad keyboard mode key is touched and held.
-
#await_keyboard ⇒ Object
deprecated
Deprecated.
0.9.163 replaced with ‘wait_for_keyboard`
-
#dismiss_ipad_keyboard ⇒ Object
Dismisses a iPad keyboard by touching the ‘Hide keyboard’ button and waits for the keyboard to disappear.
-
#docked_keyboard_visible? ⇒ Boolean
Returns true if a docked keyboard is visible.
-
#done ⇒ Object
deprecated
Deprecated.
0.10.0 replaced with ‘tap_keyboard_action_key`
-
#ensure_docked_keyboard ⇒ Object
Ensures that the iPad keyboard is docked.
-
#ensure_split_keyboard ⇒ Object
Ensures that the iPad keyboard is split.
-
#ensure_undocked_keyboard ⇒ Object
Ensures that the iPad keyboard is undocked.
-
#ipad_keyboard_mode(opts = {}) ⇒ Symbol
Returns the keyboard mode.
-
#keyboard_enter_char(chr, opts = {}) ⇒ Object
Use keyboard to enter a character.
-
#keyboard_enter_text(text) ⇒ Object
Uses the keyboard to enter text.
-
#keyboard_visible? ⇒ Boolean
Returns true if there is a visible keyboard.
-
#split_keyboard_visible? ⇒ Boolean
Returns true if a split keyboard is visible.
-
#tap_keyboard_action_key ⇒ Object
Touches the keyboard action key.
-
#uia_keyboard_visible? ⇒ Boolean
Used for detecting keyboards that are not normally visible to calabash; e.g.
-
#uia_wait_for_keyboard(opts = {}) ⇒ Object
Waits for a keyboard that is not normally visible to calabash; e.g.
-
#undocked_keyboard_visible? ⇒ Boolean
Returns true if an undocked keyboard is visible.
-
#wait_for_keyboard(opts = {}) ⇒ Object
Waits for a keyboard to appear and once it does appear waits for ‘:post_timeout` seconds.
Methods included from Logging
#calabash_info, #calabash_warn
Methods included from TestsHelpers
#check_element_does_not_exist, #check_element_exists, #check_view_with_mark_exists, #classes, #each_cell, #element_does_not_exist, #element_exists, #view_with_mark_exists
Methods included from FailureHelpers
#fail, #screenshot, #screenshot_and_raise, #screenshot_embed
Instance Method Details
#_touch_top_keyboard_mode_row ⇒ Object
Touches the top option on the popup dialog that is presented when the the iPad keyboard mode key is touched and held.
The ‘mode` key is also know as the ’Hide keyboard’ key.
The ‘mode` key allows the user to undock, dock, or split the keyboard.
647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 647 def _touch_top_keyboard_mode_row mode = ipad_keyboard_mode if uia_available? start_pt = _point_for_ipad_keyboard_mode_key # there are 10 pt btw the key and the popup and each row is 50 pt # NB: no amount of offsetting seems to allow touching the top row # when the keyboard is split y_offset = 10 + 50 + 25 end_pt = {:x => (start_pt[:x] - 40), :y => (start_pt[:y] - y_offset)} uia_pan_offset(start_pt, end_pt, {:duration => 1.0}) else pan(_query_for_keyboard_mode_key, nil, {}) touch(_query_for_touch_for_keyboard_mode_option(:top, mode)) sleep(0.5) end 2.times { sleep(0.5) } end |
#await_keyboard ⇒ Object
0.9.163 replaced with ‘wait_for_keyboard`
164 165 166 167 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 164 def await_keyboard _deprecated('0.9.163', "use 'wait_for_keyboard' instead", :warn) wait_for_keyboard end |
#dismiss_ipad_keyboard ⇒ Object
the dismiss keyboard key does not exist on the iPhone or iPod
Dismisses a iPad keyboard by touching the ‘Hide keyboard’ button and waits for the keyboard to disappear.
516 517 518 519 520 521 522 523 524 525 526 527 528 529 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 516 def dismiss_ipad_keyboard screenshot_and_raise 'cannot dismiss keyboard on iphone' if device_family_iphone? if uia_available? send_uia_command({:command => "#{}.tap()"}) else touch(_query_for_keyboard_mode_key) end opts = {:timeout_message => 'keyboard did not disappear'} wait_for(opts) do not keyboard_visible? end end |
#docked_keyboard_visible? ⇒ Boolean
Returns true if a docked keyboard is visible.
A docked keyboard is pinned to the bottom of the view.
Keyboards on the iPhone and iPod are docked.
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 81 def docked_keyboard_visible? res = query(_qstr_for_keyboard).first return false if res.nil? return true if device_family_iphone? # ipad rect = res['rect'] o = .to_sym case o when :left then rect['center_x'] == 592 and rect['center_y'] == 512 when :right then rect['center_x'] == 176 and rect['center_y'] == 512 when :up then rect['center_x'] == 384 and rect['center_y'] == 132 when :down then rect['center_x'] == 384 and rect['center_y'] == 892 else false end end |
#done ⇒ Object
0.10.0 replaced with ‘tap_keyboard_action_key`
Not all keyboards have an action key. For example, numeric keyboards do not have an action key.
Touches the keyboard action key.
The action key depends on the keyboard. Some examples include:
-
Return
-
Next
-
Go
-
Join
-
Search
418 419 420 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 418 def done tap_keyboard_action_key end |
#ensure_docked_keyboard ⇒ Object
Ensures that the iPad keyboard is docked.
Docked means the keyboard is pinned to bottom of the view.
If the device is not an iPad, this is behaves like a call to ‘wait_for_keyboard`.
674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 674 def ensure_docked_keyboard wait_for_keyboard return if device_family_iphone? mode = ipad_keyboard_mode case mode when :split then _touch_bottom_keyboard_mode_row when :undocked then _touch_top_keyboard_mode_row when :docked then # already docked else screenshot_and_raise "expected '#{mode}' to be one of #{_ipad_keyboard_modes}" end begin wait_for({:post_timeout => 1.0}) do docked_keyboard_visible? end rescue mode = ipad_keyboard_mode o = screenshot_and_raise "expected keyboard to be ':docked' but found '#{mode}' in orientation '#{o}'" end end |
#ensure_split_keyboard ⇒ Object
Ensures that the iPad keyboard is split.
Split means the keyboard is floating in the middle of the view and is split into two sections to enable faster thumb typing.
If the device is not an iPad, this is behaves like a call to ‘wait_for_keyboard`.
If the device is not an iPad, this is behaves like a call to ‘wait_for_keyboard`.
762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 762 def ensure_split_keyboard wait_for_keyboard return if device_family_iphone? mode = ipad_keyboard_mode case mode when :split then # already split when :undocked then _touch_bottom_keyboard_mode_row when :docked then _touch_bottom_keyboard_mode_row else screenshot_and_raise "expected '#{mode}' to be one of #{_ipad_keyboard_modes}" end _wait_for_keyboard_in_mode(:split) end |
#ensure_undocked_keyboard ⇒ Object
Ensures that the iPad keyboard is undocked.
Undocked means the keyboard is floating in the middle of the view.
If the device is not an iPad, this is behaves like a call to ‘wait_for_keyboard`.
If the device is not an iPad, this is behaves like a call to ‘wait_for_keyboard`.
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 715 def ensure_undocked_keyboard wait_for_keyboard() return if device_family_iphone? mode = ipad_keyboard_mode case mode when :split then # keep these condition separate because even though they do the same # thing, the else condition is a hack if ios5? # iOS 5 has no 'Merge' feature in split keyboard, so dock first then # undock from docked mode _touch_bottom_keyboard_mode_row _wait_for_keyboard_in_mode(:docked) else # in iOS > 5, it seems to be impossible consistently touch the # the top keyboard mode popup button, so we punt _touch_bottom_keyboard_mode_row _wait_for_keyboard_in_mode(:docked) end _touch_top_keyboard_mode_row when :undocked then # already undocked when :docked then _touch_top_keyboard_mode_row else screenshot_and_raise "expected '#{mode}' to be one of #{_ipad_keyboard_modes}" end _wait_for_keyboard_in_mode(:undocked) end |
#ipad_keyboard_mode(opts = {}) ⇒ Symbol
Returns the keyboard mode.
“‘
keyboard is pinned to bottom of the view #=> :docked
keyboard is floating in the middle of the view #=> :undocked
keyboard is floating and split #=> :split
no keyboard and :raise_on_no_visible_keyboard == false #=> :unknown
“‘
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 197 def ipad_keyboard_mode(opts = {}) raise 'the keyboard mode does not exist on the iphone or ipod' if device_family_iphone? default_opts = {:raise_on_no_visible_keyboard => true} merged_opts = default_opts.merge(opts) if merged_opts[:raise_on_no_visible_keyboard] screenshot_and_raise 'there is no visible keyboard' unless keyboard_visible? return :docked if docked_keyboard_visible? return :undocked if undocked_keyboard_visible? :split else return :docked if docked_keyboard_visible? return :undocked if undocked_keyboard_visible? return :split if split_keyboard_visible? :unknown end end |
#keyboard_enter_char(chr, opts = {}) ⇒ Object
IMPORTANT: Use the ‘POST_ENTER_KEYBOARD` environmental variable to slow down the typing; adds a wait after each character is touched. this can fix problems where the typing is too fast and characters are skipped.
There are several special ‘characters’, some of which do not appear on all keyboards; e.g. ‘Delete`, `Return`.
Since 0.9.163, this method accepts a Hash as the second parameter. The previous second parameter was a Boolean that controlled whether or not to screenshot on errors.
You should prefer to call ‘keyboard_enter_text`.
Use keyboard to enter a character.
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 284 def keyboard_enter_char(chr, opts={}) unless opts.is_a?(Hash) msg = "you should no longer pass a boolean as the second arg; pass {:should_screenshot => '#{opts}'} hash instead" _deprecated('0.9.163', msg, :warn) opts = {:should_screenshot => opts} end default_opts = {:should_screenshot => true, # introduce a small wait to avoid skipping characters # keep this as short as possible :wait_after_char => (ENV['POST_ENTER_KEYBOARD'] || 0.05).to_f} opts = default_opts.merge(opts) should_screenshot = opts[:should_screenshot] _ensure_can_enter_text({:screenshot => should_screenshot, :skip => (not should_screenshot)}) if uia_available? if chr.length == 1 uia_type_string chr else code = UIA_SUPPORTED_CHARS[chr] unless code raise "typing character '#{chr}' is not yet supported when running with Instruments" end # on iOS 6, the Delete char code is _not_ \b # on iOS 7, the Delete char code is \b on non-numeric keyboards # on numeric keyboards, it is actually a button on the # keyboard and not a key if code.eql?(UIA_SUPPORTED_CHARS['Delete']) uia("uia.keyboard().elements().firstWithName('Delete').tap()") elsif code.eql?(UIA_SUPPORTED_CHARS['Return']) tap_keyboard_action_key else uia_type_string(code, '') end end # noinspection RubyStringKeysInHashInspection res = {'results' => []} else res = http({:method => :post, :path => 'keyboard'}, {:key => chr, :events => load_playback_data('touch_done')}) res = JSON.parse(res) if res['outcome'] != 'SUCCESS' msg = "Keyboard enter failed failed because: #{res['reason']}\n#{res['details']}" if should_screenshot screenshot_and_raise msg else raise msg end end end if ENV['POST_ENTER_KEYBOARD'] w = ENV['POST_ENTER_KEYBOARD'].to_f if w > 0 sleep(w) end end pause = opts[:wait_after_char] sleep(pause) if pause > 0 res['results'] end |
#keyboard_enter_text(text) ⇒ Object
Uses the keyboard to enter text.
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 355 def keyboard_enter_text(text) _ensure_can_enter_text if uia_available? text_before = _text_from_first_responder() text_before = text_before.gsub("\n","\\n") if text_before uia_type_string(text, text_before) else text.each_char do |ch| begin keyboard_enter_char(ch, {:should_screenshot => false}) rescue _search_keyplanes_and_enter_char(ch) end end end end |
#keyboard_visible? ⇒ Boolean
Returns true if there is a visible keyboard.
136 137 138 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 136 def keyboard_visible? docked_keyboard_visible? or undocked_keyboard_visible? or split_keyboard_visible? end |
#split_keyboard_visible? ⇒ Boolean
Returns true if a split keyboard is visible.
A split keyboard is floats in the middle of the view and is split to allow faster thumb typing
keyboards on the Phone and iPod are docked and not split.
127 128 129 130 131 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 127 def split_keyboard_visible? return false if device_family_iphone? query("view:'UIKBKeyView'").count > 0 and element_does_not_exist(_qstr_for_keyboard) end |
#tap_keyboard_action_key ⇒ Object
Not all keyboards have an action key. For example, numeric keyboards do not have an action key.
Touches the keyboard action key.
The action key depends on the keyboard. Some examples include:
-
Return
-
Next
-
Go
-
Join
-
Search
387 388 389 390 391 392 393 394 395 396 397 398 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 387 def tap_keyboard_action_key if uia_available? run_loop = Calabash::Cucumber::Launcher.launcher.run_loop if run_loop[:uia_strategy] == :host uia_type_string "\\\\n", '', false else uia_type_string '\n', '', false end else keyboard_enter_char 'Return' end end |
#uia_keyboard_visible? ⇒ Boolean
IMPORTANT this should only be used when the app does not respond to ‘keyboard_visible?`.
Used for detecting keyboards that are not normally visible to calabash; e.g. the keyboard on the ‘MFMailComposeViewController`
816 817 818 819 820 821 822 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 816 def uia_keyboard_visible? unless uia_available? screenshot_and_raise 'only available if there is a run_loop i.e. the app was launched with Instruments' end res = uia_query_windows(:keyboard) not res.eql?(':nil') end |
#uia_wait_for_keyboard(opts = {}) ⇒ Object
IMPORTANT this should only be used when the app does not respond to ‘keyboard_visible?`.
Waits for a keyboard that is not normally visible to calabash; e.g. the keyboard on ‘MFMailComposeViewController`.
834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 834 def uia_wait_for_keyboard(opts={}) unless uia_available? screenshot_and_raise 'only available if there is a run_loop i.e. the app was launched with Instruments' end default_opts = {:timeout => 10, :retry_frequency => 0.1, :post_timeout => 0.5} opts = default_opts.merge(opts) unless opts[:timeout_message] msg = "waited for '#{opts[:timeout]}' for keyboard" opts[:timeout_message] = msg end wait_for(opts) do uia_keyboard_visible? end end |
#undocked_keyboard_visible? ⇒ Boolean
Returns true if an undocked keyboard is visible.
A undocked keyboard is floats in the middle of the view.
keyboards on the iPhone and iPod are docked.
111 112 113 114 115 116 117 118 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 111 def undocked_keyboard_visible? return false if device_family_iphone? res = query(_qstr_for_keyboard).first return false if res.nil? not docked_keyboard_visible? end |
#wait_for_keyboard(opts = {}) ⇒ Object
Waits for a keyboard to appear and once it does appear waits for ‘:post_timeout` seconds.
153 154 155 156 157 158 159 160 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 153 def wait_for_keyboard(opts={}) default_opts = {:timeout_message => 'keyboard did not appear', :post_timeout => 0.3} opts = default_opts.merge(opts) wait_for(opts) do keyboard_visible? end end |