rutl 0.1.4 → 0.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 44ba7a05dd473a09ac45ecafc02d9e11f0a74e26d0e8eb5909e315226066e0ca
4
- data.tar.gz: 6a272e4fc1afb2d1111b90604ceb3443cc89fd49c703ff417ab56fd9f609573b
3
+ metadata.gz: 100c19d4e865873162c8b2d6fef35433cfad509517fe33947f3620b8ec3e1501
4
+ data.tar.gz: c89348d198df34fb5574dff6ca684df5d7b9509726a6aa6524990ebe86549b8f
5
5
  SHA512:
6
- metadata.gz: 58227d7b2a1dd426ced4d42a826081ad71b638b6f212a16c5905ef57d0fb28ea4689b0240233dbfbb8d42701460c3bf91354cb088414693047836dcf30fb56ce
7
- data.tar.gz: c4acf6148162ef28b3f7704ea6885a6acd81b9bfb0dbff26fb87a6294f943fa5a1e6bcdeb3aaa8668bf597fa0d452620a90587aadf6cd71ea3b4670f5f3281a1
6
+ metadata.gz: 8bc3dcf1eb98a2f2359fd631b31550f722704b975a13eeab7bd348fe4f691f0433e12ccd446967aaf8bc77138252c005d025f6c59bafcf3a3ae66dbabf12277f
7
+ data.tar.gz: 95c3525a9dfdf0981584e6d7040c1a781229f824d7581b935c0fa8a56e9704151140a5be9aa101d0c6f720021ce0ce476e340ad158cde17495d8cd42cfd649e8
data/.rubocop.yml CHANGED
@@ -1,3 +1,6 @@
1
+ # The exclusions here and in source code are intentional decisions to not
2
+ # follow Rubocop's advice. Anything that should be fiex but isn't is in
3
+ # .rubocop_todo.yml
1
4
  inherit_from: .rubocop_todo.yml
2
5
 
3
6
  require: rubocop-rspec
@@ -14,3 +17,28 @@ AllCops:
14
17
  DisplayCopNames: true
15
18
  DisplayStyleGuide: true
16
19
  ExtraDetails: true
20
+
21
+ # Metrics/BlockLength, Metrics/MethodLength
22
+ # don't apply to the spec files. They naturally have long swaths of code.
23
+ # And the gemspec is special.
24
+ Metrics/BlockLength:
25
+ Exclude:
26
+ - 'rutl.gemspec'
27
+ - 'spec/*_spec.rb'
28
+ Metrics/MethodLength:
29
+ Exclude:
30
+ - 'spec/*_spec.rb'
31
+
32
+ # TODO: Change this setting? Ideally, I should force braces on the *Page files.
33
+ # But should think about this first.
34
+ Style/BracesAroundHashParameters:
35
+ Exclude:
36
+ - 'spec/pages/**/*'
37
+
38
+ # NullDriverPageElement plays dirty tricks with @@variables to simulate
39
+ # longer-lived data sources.
40
+ # And BasePage does @@loaded_pages.
41
+ Style/ClassVars:
42
+ Exclude:
43
+ - 'lib/rutl/driver/null_driver_page_element.rb'
44
+ - 'lib/rutl/base_page.rb'
data/.rubocop_todo.yml CHANGED
@@ -1,36 +1,11 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2018-06-03 15:06:48 -0700 using RuboCop version 0.56.0.
3
+ # on 2018-06-04 00:16:13 -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: 3
10
- # Configuration parameters: CountComments, ExcludedMethods.
11
- Metrics/BlockLength:
12
- Max: 74
13
-
14
- # Offense count: 3
15
- # Configuration parameters: CountComments.
16
- Metrics/MethodLength:
17
- Max: 13
18
-
19
- # Offense count: 4
20
- # Cop supports --auto-correct.
21
- # Configuration parameters: EnforcedStyle.
22
- # SupportedStyles: braces, no_braces, context_dependent
23
- Style/BracesAroundHashParameters:
24
- Exclude:
25
- - 'spec/pages/internet_login_page.rb'
26
- - 'spec/pages/page1.rb'
27
-
28
- # Offense count: 3
29
- Style/ClassVars:
30
- Exclude:
31
- - 'lib/rutl/base_page.rb'
32
- - 'lib/rutl/driver/null_driver_page_element.rb'
33
-
34
9
  # Offense count: 4
35
10
  # Configuration parameters: AllowedVariables.
36
11
  Style/GlobalVars:
@@ -40,30 +15,9 @@ Style/GlobalVars:
40
15
  - 'lib/rutl/interface/elements/element_context.rb'
41
16
  - 'lib/rutl/interface/null_interface.rb'
42
17
 
43
- # Offense count: 1
44
- # Cop supports --auto-correct.
45
- Style/IfUnlessModifier:
46
- Exclude:
47
- - 'lib/rutl/interface/elements/element_context.rb'
48
-
49
- # Offense count: 4
18
+ # Offense count: 3
50
19
  Style/MethodMissingSuper:
51
20
  Exclude:
52
21
  - 'lib/rutl/base_page.rb'
53
22
  - 'lib/rutl/browser.rb'
54
23
  - 'lib/rutl/interface/base_interface.rb'
55
- - 'spec/spec_helper.rb'
56
-
57
- # Offense count: 1
58
- # Cop supports --auto-correct.
59
- # Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, IgnoreClassMethods, Whitelist.
60
- # Whitelist: to_ary, to_a, to_c, to_enum, to_h, to_hash, to_i, to_int, to_io, to_open, to_path, to_proc, to_r, to_regexp, to_str, to_s, to_sym
61
- Style/TrivialAccessors:
62
- Exclude:
63
- - 'lib/rutl/base_page.rb'
64
-
65
- # Offense count: 15
66
- # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
67
- # URISchemes: http, https
68
- Metrics/LineLength:
69
- Max: 223
data/README.md CHANGED
@@ -17,13 +17,12 @@ Framework goals:
17
17
  * Secondary-ish goal: Make fake browser to test the framework faster.
18
18
  * Tertiary-ish: Stop calling browser "fake" because I'm sick of that word. Null!
19
19
 
20
+
20
21
  ## Installation
21
22
 
22
23
  Add this line to your application's Gemfile:
23
24
 
24
- ```ruby
25
- gem 'rutl'
26
- ```
25
+ $ gem 'rutl'
27
26
 
28
27
  And then execute:
29
28
 
@@ -33,36 +32,159 @@ Or install it yourself as:
33
32
 
34
33
  $ gem install rutl
35
34
 
35
+
36
36
  ## Usage
37
37
 
38
- TODO: Write usage instructions here
38
+ ### Page Objects
39
+ Page objects are a common paradigm in browser testing. This framework uses the
40
+ 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 have a layout method such that
45
+ * field types are defined by methods button, checkbox, link, and text (more tbd?)
46
+ * field type is followed by name as a symbol (add support for string? tbd)
47
+ * then a comma
48
+ * hash of selectors
49
+ * key is selector type as symbol (currently only :css)
50
+ * value is string path
51
+ * optional comma if there are destinations or error conditions
52
+ * optional array of destination page or error condition classes if clicking the element causes transition
53
+ * loaded? method returning boolean to determine when page is loaded
54
+ * 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
56
+ * your own methods because it's a plain ol' Ruby class
57
+
58
+
59
+ Example:
60
+
61
+ ```ruby
62
+ require 'rutl/base_page'
63
+
64
+ class MyPage < BasePage
65
+ @url = 'https://url.string.com/page.html'
66
+
67
+ def layout
68
+ text :username, { css: 'some_css_input#username' }
69
+ text :password, { css: 'css#to_password_field' }
70
+ button :log_me_in, { css: 'button#login' }, [SomeOtherPage, LoginFailurePage]
71
+ link :refresh, { css: 'link_css_to_refresh_page' }, [MyPage]
72
+ end
73
+ end
74
+ ```
75
+
76
+ And here's some example RSpec:
77
+
78
+ ```ruby
79
+ require 'spec_helper'
80
+
81
+ RSpec.describe MyTest do
82
+ let!(:browser) do
83
+ Browser.new(type: :firefox)
84
+ end
85
+
86
+ it 'logs in' do
87
+ goto(MyPage)
88
+ username_text = 'drew'
89
+ password_text = 's3cr3T!'
90
+ log_me_in_button.click
91
+ expect(current_page).to be_page(SomeOtherPage)
92
+ end
93
+ end
94
+ ```
95
+
96
+ The framework loads and manages all the pages. You just have to interact with
97
+ what you can see on whatever page you're on. Let's walk through this.
98
+ * TBD: Does RUTL come with browser drivers? Browsers? What needs to be added?
99
+ * We're using let! because:
100
+ * it forces instantiation of "browser" every time
101
+ * we include DefaultRspecToBrowser, defaulting missing methods to "browser"
102
+ * 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.
110
+ * When we call click, the framework polls for a next state.
111
+ * 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.
113
+
114
+ ### RSpec Goodies
115
+
116
+ The tests here are in RSpec and use some conventions that may be common if your tests are also RSpec.
117
+
118
+ #### DefaultRspecToBrowser
119
+ This is a module that allows us to skip writing `browser.` in front of everything.
120
+ 1. We assume that `browser` is defined.
121
+ 2. On method_missing, we try to send the method to `browser`.
122
+
123
+ It lets us turn this:
124
+ ```
125
+ browser.field1_text = 'foo'
126
+ browser.ok_button.click
127
+ expect(browser.current_page).to eq(NextPage)
128
+ ```
129
+ into this:
130
+ ```
131
+ field1_text = 'foo'
132
+ ok_button.click
133
+ expect(current_page).to eq(NextPage)
134
+ ```
135
+ which means less boilerplate and it's easier to follow.
136
+
137
+ To use it:
138
+ ```
139
+ require 'rutl/rspec/default_rspec_to_browser'
140
+ ```
141
+
142
+ #### RSpec Matcher
143
+
144
+ Currently the only has the `be_page` matcher.
145
+
146
+ It lets us turn this:
147
+ ```
148
+ expect(browser.current_page).to be_instance_of(MyPage)
149
+ ```
150
+ into this:
151
+ ```
152
+ expect(browser.current_page).to be_page(MyPage)
153
+ ```
154
+ Both are acceptable but the second is more readable.
155
+
156
+ To use it:
157
+ ```
158
+ require 'rutl/rspec/rutl_matchers'
159
+ ```
160
+
39
161
 
40
162
  ## Roadmap
41
163
  Coming up soon in almost no order:
42
- * A test framework should have better tests. Goes with next bullet.
43
- * Flesh out null interface/driver. Make them do what a real browser does.
44
- * Restructure tests to handle fake browsers and real browsers. Same structure?
45
- * Make this work with pages files in some other location so we can use it as a gem.
164
+ * A test framework should have better tests.
46
165
  * Put more info in this readme.
47
166
  * Take screenshots.
48
167
  * Diff screenshots. Make this smart so we don't have to be experts.
168
+ * Move bugs and would-be features to Github Issues instead of this readme and scattered through the code.
169
+ * Make the framework make it easier to spot bugs in pages. Focus on exception-handling?
49
170
  * The webdriver gem should already include InternetExplorerDriver. Maybe run tests on AppVeyor.
50
171
  * Other browser drivers? Look at https://github.com/fnando/browser
51
172
  * Get this working with Appium:
52
173
  * Make TK app to test on desktops and test it.
53
- * Can Ruby TK create accesible apps?
174
+ * Can Ruby TK create accesible apps? Not in the simple demos.
54
175
  * Make Android example app and get this to work.
55
176
  * Corboba?
56
177
  * Same with iPhone.
57
178
  * Same Cordoba test app?
58
179
  * Others?
59
- * Spidering page object maker.
180
+ * Spidering page object maker. Or selector checker/fixer?
60
181
  * Possibly pair the null browser with auto-generated pages for ______?
61
182
  * Call rutl.rb properly.
62
183
  * Optional install of test resources based on machine type.
63
184
  * Instructions about machine installs to help people using gem.
64
185
  * Pair with some kind of VM, Docker container, AMI, or something.
65
186
 
187
+
66
188
  ## Development
67
189
 
68
190
  Set everything up:
@@ -75,10 +197,13 @@ Set everything up:
75
197
  Great! You've checked out the code, installed everything and run the tests.
76
198
 
77
199
  Rubocop. I still have to tweak what I want it to complain about.
78
- `bundle exec rubocop`
200
+ ```ruby
201
+ bundle exec rubocop
202
+ ```
79
203
 
80
204
  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).
81
205
 
206
+
82
207
  ## Contributing
83
208
 
84
209
  Bug reports and pull requests are welcome on GitHub at https://github.com/drewcoo/rutl.
@@ -0,0 +1,22 @@
1
+ #
2
+ # Currently not in use.
3
+ # Should go in its own file, too.
4
+ #
5
+ module DefaultRspecToBrowser
6
+ # rubocop:disable Style/MethodMissingSuper
7
+ def method_missing(method, *args, &block)
8
+ if args.empty?
9
+ browser.send(method)
10
+ else
11
+ browser.send(method, *args, &block)
12
+ end
13
+ rescue ArgumentError
14
+ browser.send(method)
15
+ end
16
+ # rubocop:enable Style/MethodMissingSuper
17
+
18
+ def respond_to_missing?(method, _include_private = false)
19
+ return false if method =~ /browser/
20
+ browser.respond_to?(method)
21
+ end
22
+ end
@@ -0,0 +1,8 @@
1
+ #
2
+ # Additional RSpec matchers specific to this framework go here.
3
+ #
4
+ RSpec::Matchers.define :be_page do |expected|
5
+ match do |actual|
6
+ actual.is_a?(expected) && expected.ancestors.include?(BasePage)
7
+ end
8
+ end
@@ -9,6 +9,7 @@ class BasePage
9
9
  # BUGBUG: Kludgy. What do I really want to do here?
10
10
  # Make it easy to define a page's default url and
11
11
  # also matchers for page urls for pages with variable urls?
12
+ # rubocop:disable Style/TrivialAccessors
12
13
  def self.url
13
14
  @url
14
15
  end
@@ -16,6 +17,7 @@ class BasePage
16
17
  def url
17
18
  self.class.url
18
19
  end
20
+ # rubocop:enable Style/TrivialAccessors
19
21
 
20
22
  @@loaded_pages = []
21
23
 
@@ -29,6 +31,12 @@ class BasePage
29
31
  @@loaded_pages << self.class
30
32
  end
31
33
 
34
+ def go_to_here
35
+ # Ovveride this in base page to have something more
36
+ # complicated than this.
37
+ @interface.driver.navigate.to(url)
38
+ end
39
+
32
40
  # Written by Browser and only used internally.
33
41
  attr_writer :interface
34
42
 
@@ -40,6 +48,9 @@ class BasePage
40
48
  # to the current class where that method creates an instance
41
49
  # of klass.
42
50
  # context is an ElementContext
51
+ #
52
+ # As it is, this seems silly to break into pieces for Rubocop.
53
+ # rubocop:disable Metrics/MethodLength
43
54
  def add_method(context:, klass:, name:, setter: false)
44
55
  name = "#{name}_#{klass.downcase}"
45
56
  constant = Module.const_get(klass.capitalize)
@@ -55,11 +66,15 @@ class BasePage
55
66
  end
56
67
  end
57
68
  end
69
+ # rubocop:enable Metrics/MethodLength
58
70
 
59
71
  # This creates a new element instance whenever it's called.
60
72
  # Because of that we can't keep state in any element objects.
61
73
  # That seems like a good thing, actually.
62
74
  # Called by layout method on pages.
75
+ #
76
+ # Hard to make shorter.
77
+ # rubocop:disable Metrics/MethodLength
63
78
  def method_missing(element, *args, &_block)
64
79
  name, selectors, rest = args
65
80
  context = ElementContext.new(destinations: rest,
@@ -76,6 +91,7 @@ class BasePage
76
91
  raise "#{element} NOT FOUND WITH ARGS #{args}!!!"
77
92
  end
78
93
  end
94
+ # rubocop:enable Metrics/MethodLength
79
95
 
80
96
  def respond_to_missing?(*args)
81
97
  # Is this right at all???
data/lib/rutl/browser.rb CHANGED
@@ -11,12 +11,15 @@ class Browser
11
11
 
12
12
  attr_reader :interface
13
13
 
14
- def initialize(interface_type:, page_object_dir: 'spec/pages')
14
+ def initialize(type:, rutl_pages: RUTL::PAGES || ENV['RUTL_PAGES'])
15
+ if rutl_pages.nil? || rutl_pages.empty?
16
+ raise "Set RUTL::PAGES or ENV['RUTL_PAGES'] or pass dir as rutl_pages:"
17
+ end
15
18
  # This is kind of evil. Figure out how to ditch the $ variable.
16
19
  $browser = self
17
20
  @interface = nil
18
- @interface = load_interface(interface_type)
19
- @interface.pages = load_pages(dir: page_object_dir)
21
+ @interface = load_interface(type)
22
+ @interface.pages = load_pages(dir: rutl_pages)
20
23
  end
21
24
 
22
25
  def load_interface(type)
@@ -30,7 +30,7 @@ class NullDriverPageElement
30
30
  def attribute(attr)
31
31
  case attr.to_sym
32
32
  when :value
33
- @@variables[@location]
33
+ @@variables[@location] || ''
34
34
  else
35
35
  raise ArgumentError, "Attribute unknown: #{attr}"
36
36
  end
@@ -15,7 +15,8 @@ class BaseInterface
15
15
  end
16
16
 
17
17
  def goto(page)
18
- @driver.navigate.to find_page(page).url
18
+ raise 'expect Page class' unless page.ancestors.include?(BasePage)
19
+ find_page(page).go_to_here
19
20
  end
20
21
 
21
22
  def current_page
@@ -5,6 +5,7 @@ require 'rutl/interface/base_interface'
5
5
  # Small interface for Chrome browser.
6
6
  #
7
7
  class ChromeInterface < BaseInterface
8
+ # rubocop:disable Metrics/MethodLength
8
9
  def initialize
9
10
  @logged_in = true
10
11
  options = Selenium::WebDriver::Chrome::Options.new
@@ -20,6 +21,7 @@ class ChromeInterface < BaseInterface
20
21
  @driver = Selenium::WebDriver.for :chrome, options: options
21
22
  super
22
23
  end
24
+ # rubocop:enable Metrics/MethodLength
23
25
 
24
26
  def current_page
25
27
  url = @driver.current_url
data/lib/rutl/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RUTL
2
- VERSION = '0.1.4'.freeze
2
+ VERSION = '0.2.0'.freeze
3
3
  end
data/lib/rutl.rb CHANGED
@@ -6,5 +6,8 @@ require 'rutl/version'
6
6
  # desktop UI testing, turning the UI into an API via its DSL.
7
7
  #
8
8
  module RUTL
9
- # Your code goes here...
9
+ # Should define RUTL::PAGES directory for your code
10
+ # or set ENV['RUTL_PAGES']
11
+ # or Browser intialize will raise.
12
+ PAGES = nil
10
13
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rutl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Drew Cooper
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-06-04 00:00:00.000000000 Z
11
+ date: 2018-06-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -185,6 +185,8 @@ files:
185
185
  - Rakefile
186
186
  - bin/console
187
187
  - bin/setup
188
+ - lib/rspec/default_rspec_to_browser.rb
189
+ - lib/rspec/rutl_matchers.rb
188
190
  - lib/rutl.rb
189
191
  - lib/rutl/base_page.rb
190
192
  - lib/rutl/browser.rb