rutl 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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