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.
696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 696 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`
174 175 176 177 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 174 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.
565 566 567 568 569 570 571 572 573 574 575 576 577 578 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 565 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 104 105 106 107 108 109 110 111 112 113 |
# 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? rect = res['rect'] o = .to_sym case o when :left if ios8? rect['center_x'] == 512 and rect['center_y'] == 592 else rect['center_x'] == 592 and rect['center_y'] == 512 end when :right if ios8? rect['center_x'] == 512 and rect['center_y'] == 592 else rect['center_x'] == 176 and rect['center_y'] == 512 end when :up if ios8? rect['center_x'] == 384 and rect['center_y'] == 892 else rect['center_x'] == 384 and rect['center_y'] == 132 end when :down 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
467 468 469 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 467 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`.
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 723 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`.
811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 811 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`.
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 764 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
“‘
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 207 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.
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 350 351 352 353 354 355 356 357 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 294 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_raw 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()") else uia_type_string_raw(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.
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 363 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.
146 147 148 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 146 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.
137 138 139 140 141 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 137 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
445 446 447 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 445 def tap_keyboard_action_key keyboard_enter_char 'Return' 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`
865 866 867 868 869 870 871 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 865 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`.
883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 883 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.
121 122 123 124 125 126 127 128 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 121 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.
163 164 165 166 167 168 169 170 |
# File 'lib/calabash-cucumber/keyboard_helpers.rb', line 163 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 |