rutl 0.6.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.bundle/config +2 -0
  3. data/.gitignore +1 -1
  4. data/.rubocop.yml +1 -1
  5. data/.rubocop_todo.yml +37 -10
  6. data/.travis.yml +1 -0
  7. data/README.md +75 -38
  8. data/appveyor.yml +48 -0
  9. data/bin/ie.reg +0 -0
  10. data/bin/window_data.rb +27 -0
  11. data/lib/rspec/default_method_object_to_app.rb +28 -0
  12. data/lib/rspec/rutl_matchers.rb +7 -5
  13. data/lib/rutl.rb +26 -6
  14. data/lib/rutl/appium/appium_extension.rb +27 -0
  15. data/lib/rutl/appium/appium_server.rb +36 -0
  16. data/lib/rutl/appium/windows_test_app_wrapper.rb +40 -0
  17. data/lib/rutl/application.rb +70 -0
  18. data/lib/rutl/camera.rb +20 -4
  19. data/lib/rutl/element/click_to_change_state_mixin.rb +1 -1
  20. data/lib/rutl/element/element.rb +9 -10
  21. data/lib/rutl/element/element_context.rb +5 -4
  22. data/lib/rutl/element/string_reader_writer_mixin.rb +11 -7
  23. data/lib/rutl/interface/base.rb +30 -28
  24. data/lib/rutl/interface/browser/browser.rb +22 -0
  25. data/lib/rutl/interface/{chrome.rb → browser/chrome.rb} +3 -10
  26. data/lib/rutl/interface/{firefox.rb → browser/firefox.rb} +3 -10
  27. data/lib/rutl/interface/browser/internet_explorer.rb +23 -0
  28. data/lib/rutl/interface/browser/null.rb +36 -0
  29. data/lib/rutl/interface/windows/hello.rb +36 -0
  30. data/lib/rutl/interface/windows/notepad.rb +26 -0
  31. data/lib/rutl/interface/windows/windows_app.rb +35 -0
  32. data/lib/rutl/null_driver/null_driver.rb +4 -4
  33. data/lib/rutl/null_driver/null_element.rb +4 -4
  34. data/lib/rutl/version.rb +1 -1
  35. data/lib/rutl/{page.rb → view.rb} +37 -28
  36. data/lib/utilities/check_view.rb +12 -0
  37. data/lib/utilities/string.rb +12 -0
  38. data/lib/utilities/waiter.rb +23 -0
  39. data/rutl.gemspec +13 -0
  40. metadata +94 -10
  41. data/lib/rspec/default_rspec_to_browser.rb +0 -22
  42. data/lib/rutl/browser.rb +0 -70
  43. data/lib/rutl/interface/null.rb +0 -35
  44. data/lib/utilities.rb +0 -41
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 21fa6d406b33dee3134e1cf6da770e4f51434664d55d109b19858290ec5f0776
4
- data.tar.gz: ab14d6f097caa9bbdc888ca8409c711fed65da87129bbcb03f96fa265aa5df34
3
+ metadata.gz: f18aec216e23b12e55da96c52395e8da7521920cf48ab5090038192a034e991b
4
+ data.tar.gz: 7b3bc290be5e444a4c19952230b2ea1544efda3ab5e76cb16266a952c2f036a4
5
5
  SHA512:
6
- metadata.gz: 5c81506c59bc5224d50928351455241d83123cfb7d2ff3a8383b0aad7e0914ede6f20128e5dbe34d87743c0575ac33972b517a2506f51292a32dad64b29abc03
7
- data.tar.gz: 2e99c3d93ae8cd9af232ffc26d214866f649cd2d295a553818e835e6e7b0ee3abd4f805741fefbfd85a910251451358309435fe3c6bd4bdc4419868cc667203c
6
+ metadata.gz: afbebeca0867745a569a658753409a46146d982f859f7967c8d8aa524407dd9534ab3ddcf54b5233002a8cedc33c6501efb813b60f99c38af8647583422cd467
7
+ data.tar.gz: 2b8cf8f0fc9d31d1caf7ff6bb964be78396a7d127c5268f818018d709470b23e4c10a91619a2f22ec13f6ba5495d5e41b89c7cfd51ec936ae375a50394dfcfcb
data/.bundle/config ADDED
@@ -0,0 +1,2 @@
1
+ ---
2
+ BUNDLE_PATH: "vendor/bundle"
data/.gitignore CHANGED
@@ -1,4 +1,3 @@
1
- /.bundle/
2
1
  /*.gem
3
2
  /.yardoc
4
3
  /debug.log
@@ -9,3 +8,4 @@
9
8
  /pkg/
10
9
  /spec/reports/
11
10
  /tmp/
11
+ /vendor/
data/.rubocop.yml CHANGED
@@ -33,7 +33,7 @@ Metrics/MethodLength:
33
33
  # But should think about this first.
34
34
  Style/BracesAroundHashParameters:
35
35
  Exclude:
36
- - 'spec/pages/**/*'
36
+ - 'spec/views/**/*'
37
37
 
38
38
  # NullDriverPageElement plays dirty tricks with @@variables to simulate
39
39
  # longer-lived data sources.
data/.rubocop_todo.yml CHANGED
@@ -1,28 +1,48 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2018-06-07 20:55:18 -0700 using RuboCop version 0.56.0.
3
+ # on 2018-07-02 00:08:22 -0700 using RuboCop version 0.56.0.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
+ # Offense count: 2
10
+ Lint/EmptyWhen:
11
+ Exclude:
12
+ - 'spec/web_browser_spec.rb'
13
+
9
14
  # Offense count: 1
15
+ Metrics/AbcSize:
16
+ Max: 22
17
+
18
+ # Offense count: 2
10
19
  # Configuration parameters: CountComments.
11
20
  Metrics/MethodLength:
12
- Max: 11
21
+ Max: 13
13
22
 
14
- # Offense count: 2
15
- Style/ClassVars:
23
+ # Offense count: 1
24
+ # Cop supports --auto-correct.
25
+ Style/BlockComments:
26
+ Exclude:
27
+ - 'spec/windows_spec.rb'
28
+
29
+ # Offense count: 9
30
+ # Cop supports --auto-correct.
31
+ # Configuration parameters: EnforcedStyle.
32
+ # SupportedStyles: braces, no_braces, context_dependent
33
+ Style/BracesAroundHashParameters:
16
34
  Exclude:
17
- - 'lib/rutl/driver/null_driver_page_element.rb'
18
- - 'lib/rutl/base_page.rb'
19
- - 'lib/rutl/null_driver/null_element.rb'
35
+ - 'spec/pages/**/*'
36
+ - 'spec/views/notepad/notepad.rb'
37
+ - 'spec/views/web/internet_login_error_view.rb'
38
+ - 'spec/views/web/internet_login_view.rb'
39
+ - 'spec/views/web/view1.rb'
20
40
 
21
41
  # Offense count: 4
22
42
  # Configuration parameters: AllowedVariables.
23
43
  Style/GlobalVars:
24
44
  Exclude:
25
- - 'lib/rutl/browser.rb'
45
+ - 'lib/rutl/application.rb'
26
46
  - 'lib/rutl/element/element.rb'
27
47
  - 'lib/rutl/element/element_context.rb'
28
48
  - 'lib/rutl/interface/null.rb'
@@ -30,7 +50,14 @@ Style/GlobalVars:
30
50
  # Offense count: 4
31
51
  Style/MethodMissingSuper:
32
52
  Exclude:
33
- - 'lib/rutl/browser.rb'
53
+ - 'lib/rutl/application.rb'
34
54
  - 'lib/rutl/element/element.rb'
35
55
  - 'lib/rutl/interface/base.rb'
36
- - 'lib/rutl/page.rb'
56
+ - 'lib/rutl/view.rb'
57
+
58
+ # Offense count: 1
59
+ # Cop supports --auto-correct.
60
+ # Configuration parameters: AllowAsExpressionSeparator.
61
+ Style/Semicolon:
62
+ Exclude:
63
+ - 'spec/hello.rb'
data/.travis.yml CHANGED
@@ -1,6 +1,7 @@
1
1
  sudo: required
2
2
  addons:
3
3
  chrome: stable
4
+ firefox: latest
4
5
  language: ruby
5
6
  rvm:
6
7
  - 2.3.1
data/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![TravisCI](https://api.travis-ci.org/drewcoo/rutl.svg)](https://travis-ci.org/drewcoo/rutl)
4
4
  [![CircleCI](https://circleci.com/gh/drewcoo/rutl.svg?style=shield)](https://circleci.com/gh/drewcoo/rutl)
5
+ [![AppVeyor](https://ci.appveyor.com/api/projects/status/09oni14ixl077pr2?svg=true)](https://ci.appveyor.com/project/drewcoo/rutl)
5
6
  [![Coverage Status](https://coveralls.io/repos/github/drewcoo/rutl/badge.svg?branch=master)](https://coveralls.io/github/drewcoo/rutl?branch=master)
6
7
  [![Gem Version](https://badge.fury.io/rb/rutl.svg)](https://badge.fury.io/rb/rutl)
7
8
  [![Codacy Badge](https://api.codacy.com/project/badge/Grade/f95d69f6bdd149e697cf63e842f71600)](https://www.codacy.com/app/drewcoo/rutl?utm_source=github.com&utm_medium=referral&utm_content=drewcoo/rutl&utm_campaign=Badge_Grade)
@@ -22,7 +23,7 @@ Framework goals:
22
23
 
23
24
  Add this line to your application's Gemfile:
24
25
 
25
- $ gem 'rutl'
26
+ $ gem rutl
26
27
 
27
28
  And then execute:
28
29
 
@@ -35,28 +36,30 @@ Or install it yourself as:
35
36
 
36
37
  ## Usage
37
38
 
39
+
38
40
  ### Page Objects
41
+
39
42
  Page objects are a common paradigm in browser testing. This framework uses the
40
43
  following convention for page classes:
41
- * must inherit from Rutl::BasePage (require rutl/base_page)
42
- * by default, the class should follow the naming convention ending with "Page" (optional?)
43
- * must have @url defined per page
44
+ * must inherit from `rutl::BasePage` (`require rutl/base_page`)
45
+ * by default, the class should follow the naming convention ending with `Page` (optional?)
46
+ * must have `@url` defined per page
44
47
  * must have a layout method such that
45
- * field types are defined by methods button, checkbox, link, and text (more tbd?)
48
+ * field types are defined by methods `button`, `checkbox`, `link`, and `text` (more tbd?)
46
49
  * field type is followed by name as a symbol (add support for string? tbd)
47
50
  * then a comma
48
51
  * hash of selectors
49
- * key is selector type as symbol (currently only :css)
52
+ * key is selector type as symbol (currently only `:css`)
50
53
  * value is string path
51
54
  * optional comma if there are destinations or error conditions
52
55
  * optional array of destination page or error condition classes if clicking the element causes transition
53
56
  * loaded? method returning boolean to determine when page is loaded
54
57
  * defaults to just checking url; overide as needed
55
- * go_to_here (better name?) method to navigate to the page if we can't just go to the url
58
+ * `go_to_here` (better name?) method to navigate to the page if we can't just go to the url
56
59
  * your own methods because it's a plain ol' Ruby class
57
60
 
58
61
 
59
- Example:
62
+ Example:
60
63
 
61
64
  ```ruby
62
65
  require 'rutl/base_page'
@@ -97,77 +100,87 @@ The framework loads and manages all the pages. You just have to interact with
97
100
  what you can see on whatever page you're on. Let's walk through this.
98
101
  * TBD: Does RUTL come with browser drivers? Browsers? What needs to be added?
99
102
  * We're using let! because:
100
- * it forces instantiation of "browser" every time
101
- * we include DefaultRspecToBrowser, defaulting missing methods to "browser"
103
+ * it forces instantiation of `browser` every time
104
+ * we `include DefaultRspecToBrowser`, defaulting missing methods to "browser"
102
105
  * thus the terse lines that follow
103
- * We didn't pass named param rutl_pages: to Browser so we must have done one of:
104
- * setting environment variable RUTL_PAGES
105
- * setting RUTL::PAGES
106
- * Browser's type: parameter currently supports :chrome, :firefox, and :null.
107
- * The first call to the browser is goto because it wasn't on a page.
108
- * Auto-created fields are named "#{friendly_name}_#{field_type}".
109
- * Getting and setting text fields is as easy as calling a String.
106
+ * We didn't pass named param `rutl_pages:` to `browser` so we must have done one of:
107
+ * setting environment variable `RUTL_PAGES`
108
+ * setting `RUTL::PAGES`
109
+ * Browser's `type:` parameter currently supports `:chrome`, `:firefox`, and `:null`.
110
+ * The first call to the browser is `goto` because it wasn't on a page.
111
+ * Auto-created fields are named `#{friendly_name}_#{field_type}`.
112
+ * Getting and setting text fields is as easy as calling a `String`.
110
113
  * When we call click, the framework polls for a next state.
111
114
  * We verify that the current page is an instance of the intended page.
112
- * Also note here that we have a matcher be_page which matches a page class.
115
+ * Also note here that we have a matcher `be_page` which matches a page class.
116
+
113
117
 
114
118
  ### RSpec Goodies
115
119
 
116
120
  The tests here are in RSpec and use some conventions that may be common if your tests are also RSpec.
117
121
 
122
+
118
123
  #### DefaultRspecToBrowser
124
+
119
125
  This is a module that allows us to skip writing `browser.` in front of everything.
120
126
  1. We assume that `browser` is defined.
121
127
  2. On method_missing, we try to send the method to `browser`.
122
128
 
123
129
  It lets us turn this:
124
- ```
125
- browser.field1_text = 'foo'
130
+ ```ruby
131
+ message = 'foo'
132
+ browser.field1_text = message
126
133
  browser.ok_button.click
127
- expect(browser.current_page).to eq(NextPage)
134
+ expect(browser.current_page).to be_page(NextPage)
128
135
  ```
129
136
  into this:
130
- ```
131
- field1_text = 'foo'
137
+ ```ruby
138
+ message = 'foo'
139
+ field1_text = message
132
140
  ok_button.click
133
- expect(current_page).to eq(NextPage)
141
+ expect(current_page).to be_page(NextPage)
134
142
  ```
135
- which means less boilerplate and it's easier to follow.
143
+ which means less boilerplate.
144
+ Because we insist on adding UI element type as part of the naming convention there's no confusion about which things are UI elements and which aren't. In this case, we don't mistake our variable "message" for a UI element.
136
145
 
137
146
  To use it:
138
- ```
147
+ ```ruby
139
148
  require 'rutl/rspec/default_rspec_to_browser'
140
149
  ```
141
150
 
151
+
142
152
  #### RSpec Matcher
143
153
 
144
154
  Currently the only has the `be_page` matcher.
145
155
 
146
156
  It lets us turn this:
147
- ```
157
+ ```ruby
148
158
  expect(browser.current_page).to be_instance_of(MyPage)
149
159
  ```
150
160
  into this:
151
- ```
161
+ ```ruby
152
162
  expect(browser.current_page).to be_page(MyPage)
153
163
  ```
154
164
  Both are acceptable but the second is more readable.
155
165
 
156
166
  To use it:
157
- ```
167
+ ```ruby
158
168
  require 'rutl/rspec/rutl_matchers'
159
169
  ```
160
170
 
171
+
161
172
  ### Auto-screenshotting
162
173
 
163
- If you have RUTL::SCREENSHOTS or ENV['SCREENSHOTS'] set to a directory, RUTL
174
+ If you have `RUTL::SCREENSHOTS` or `ENV['SCREENSHOTS']` set to a directory, RUTL
164
175
  will automatically take screenshots on page transitions.
165
176
  If you're using RSpec, they'll be automatically named something based on the
166
177
  RSpec description with an auto-incrementing number.
167
178
  If you're not using RSpec, that's not terribly useful but you can always have
168
179
  your tests screenshot anyway, just less magic.
169
180
 
181
+
170
182
  ## Roadmap
183
+
171
184
  Coming up soon in almost no order:
172
185
  * Handle other errors. Auto-screenshot on errors. Navigation errors. Unexpected exceptions?
173
186
  * A test framework should have better tests.
@@ -175,17 +188,29 @@ Coming up soon in almost no order:
175
188
  * Put more info in this readme.
176
189
  * Move bugs and would-be features to Github Issues instead of this readme and scattered through the code.
177
190
  * Make the framework make it easier to spot bugs in pages. Focus on exception-handling?
178
- * The webdriver gem should already include InternetExplorerDriver. Maybe run tests on AppVeyor.
179
- * Other browser drivers? Look at https://github.com/fnando/browser
180
- * Get this working with Appium:
181
- * Make TK app to test on desktops and test it.
191
+ * The webdriver gem should already include [InternetExplorerDriver](https://github.com/SeleniumHQ/selenium/wiki/InternetExplorerDriver). Maybe run tests on [AppVeyor](https://www.appveyor.com/).
192
+ * [Other browser drivers](https://github.com/fnando/browser)?
193
+ * Get this working with [Appium](https://appium.io/):
194
+ * Make [TK app](https://www.tutorialspoint.com/ruby/ruby_tk_guide.htm) to test on desktops and test it.
182
195
  * Can Ruby TK create accesible apps? Not in the simple demos.
183
196
  * Make Android example app and get this to work.
184
- * Corboba?
197
+ * [Cordova](https://cordova.apache.org/) or [React Native](https://facebook.github.io/react-native/) or maybe even [Flutter](https://flutter.io/)for app?
198
+ * Choose (default?) emulator. Many choices.
185
199
  * Same with iPhone.
186
- * Same Cordoba test app?
187
- * Documentation. RDoc?
200
+ * Where to build/test? [CircleCI](https://circleci.com/build-environments/#apple-platforms)?
201
+ * Same test app as Android.
202
+ * Are there decent alternatives yet to the simulator?
203
+ * Improve documentation.
204
+ * Add these things and treat as plugins?
205
+ * Security testing. See [OWASP](https://github.com/OWASP) stuff.
206
+ * Also OWASP mobile security testing guide.
207
+ * Avoid deeper pen testing. Leave it to other toolkits.
208
+ * Other toolkits? Accessibility?
209
+ * Support web proxy and integrate out of the box. Browsermob?
210
+ * Get HARs here for perf stuff.
211
+ * Also look at browser events and tie to HARs? (Always wanted to do that.)
188
212
  * Auto-screenshot support frameworks other than RSpec.
213
+ * Or just default them to screenshots at known view changes (links/buttons/other?) or errors.
189
214
  * Others?
190
215
  * Spidering page object maker. Or selector checker/fixer?
191
216
  * Possibly pair the null browser with auto-generated pages for ______?
@@ -210,7 +235,19 @@ Rubocop. I still have to tweak what I want it to complain about.
210
235
  bundle exec rubocop
211
236
  ```
212
237
 
213
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
238
+ To install this gem onto your local machine, run `bundle exec rake install`.
239
+
240
+ To release a new version, update the version number in `version.rb` like so
241
+ ```ruby
242
+ bundle exec gem bump -v [major|minor|patch|pre|release]
243
+ ```
244
+
245
+ and then run
246
+ ```ruby
247
+ bundle exec rake release
248
+ ```
249
+
250
+ which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
214
251
 
215
252
 
216
253
  ## Contributing
data/appveyor.yml ADDED
@@ -0,0 +1,48 @@
1
+ version: 1.0.{build}-{branch}
2
+
3
+ image:
4
+ # need an image for Win10+ for WinAppDriver
5
+ - Visual Studio 2017
6
+
7
+ cache:
8
+ - C:\Users\appveyor\AppData\Roaming\npm
9
+ - vendor/bundle
10
+ # Chocolatey MSIs - out of luck!
11
+
12
+ install:
13
+ - set PATH=C:\Ruby25-x64\bin;%PATH%
14
+ # the bundle has stuff for mulitple profiles mixed together
15
+ - bundle install
16
+ # Chome, obviously but calling it out in case I make multiple profiles.
17
+ - choco install googlechrome
18
+ # This one's for iedriver.
19
+ - reg import bin\ie.reg
20
+ - npm install -g appium
21
+ # Can't choco install WinAppDriver yet.
22
+ # Also, am currently hardcoding version number. When there's a new Appium/
23
+ # WinAppDriver pairing available this may break because the Appium will be
24
+ # too new.
25
+ - appveyor DownloadFile https://github.com/Microsoft/WinAppDriver/releases/download/v1.0/WindowsApplicationDriver.msi
26
+ - msiexec /i WindowsApplicationDriver.msi /quiet /qn /norestart /log install.log
27
+ # allow developer mode for non-UWP-stuffs including WinAppDriver
28
+ - reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" /t REG_DWORD /f /v "AllowDevelopmentWithoutDevLicense" /d "1"
29
+
30
+ build: off
31
+
32
+ before_test:
33
+ - ruby -v
34
+ - gem -v
35
+ - bundle -v
36
+ - bundle info rubocop
37
+ - npm -v
38
+ - ver
39
+ - dir
40
+
41
+ test_script:
42
+ - bundle exec rspec
43
+
44
+ artifacts:
45
+ - path: install.log
46
+ name: WAD installer log
47
+
48
+ - path: tmp\screenshots
data/bin/ie.reg ADDED
Binary file
@@ -0,0 +1,27 @@
1
+ # gem install win32-window --pre
2
+ require 'win32/window'
3
+
4
+ title = ARGV[0]
5
+ this_file = File.basename(__FILE__)
6
+
7
+ if ARGV.size.zero?
8
+ STDERR.puts "\n #{this_file.upcase} <window_title_substring>\n\n"
9
+ STDERR.puts 'Finds full title, pid, and window handle for windows matching'
10
+ STDERR.puts 'the title substring. For titles with spaces, wrap in quotes.'
11
+ exit 1
12
+ end
13
+
14
+ count = 0
15
+ Win32::Window.find(title: /#{title}/i).each do |window|
16
+ next if window.title.match(this_file)
17
+ puts if count > 0
18
+ puts "title \"#{window.title}\""
19
+ puts "pid #{window.pid}"
20
+ puts format('appTopLevelWindow 0x%08x', window.handle)
21
+ count += 1
22
+ end
23
+
24
+ if count.zero?
25
+ STDERR.puts "NO WINDOWS FOUND: \"#{title}\""
26
+ exit 1
27
+ end
@@ -0,0 +1,28 @@
1
+ #
2
+ # Tries to send any method to application.method instead.
3
+ #
4
+ # Sadly, Ruby doesn't allow this to work work with naked assignments. So
5
+ # foo_button.click # turns into application.foo_button.click
6
+ # bar_text == 'baz' # turns into application.bar_text == 'baz'
7
+ # but
8
+ # quux = 'quuux' # just stays quux = 'quuux'
9
+ #
10
+ module DefaultMethodObjectToApp
11
+ # rubocop:disable Style/MethodMissingSuper
12
+ def method_missing(method, *args, &block)
13
+ super unless respond_to_missing? method
14
+ if args.empty?
15
+ app.send(method)
16
+ else
17
+ app.send(method, *args, &block)
18
+ end
19
+ rescue ArgumentError
20
+ app.send(method)
21
+ end
22
+ # rubocop:enable Style/MethodMissingSuper
23
+
24
+ def respond_to_missing?(method, _include_private = false)
25
+ return false if method =~ /^app$/
26
+ app.respond_to?(method)
27
+ end
28
+ end