testable 0.10.0 → 1.0.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 +4 -4
- data/.hound.yml +25 -4
- data/Gemfile +0 -2
- data/README.md +25 -2
- data/bin/console +0 -0
- data/bin/setup +0 -0
- data/examples/testable-info.rb +0 -0
- data/examples/testable-watir-context.rb +0 -0
- data/examples/testable-watir-datasetter.rb +0 -0
- data/examples/testable-watir-events.rb +0 -0
- data/examples/testable-watir-ready.rb +0 -0
- data/examples/testable-watir-test.rb +0 -0
- data/examples/testable-watir.rb +0 -0
- data/lib/testable.rb +67 -5
- data/lib/testable/attribute.rb +22 -0
- data/lib/testable/deprecator.rb +6 -0
- data/lib/testable/element.rb +60 -7
- data/lib/testable/errors.rb +14 -0
- data/lib/testable/extensions/core_ruby.rb +4 -0
- data/lib/testable/extensions/data_setter.rb +6 -4
- data/lib/testable/extensions/dom_observer.rb +2 -0
- data/lib/testable/locator.rb +46 -4
- data/lib/testable/logger.rb +7 -3
- data/lib/testable/region.rb +173 -0
- data/lib/testable/version.rb +6 -2
- data/testable.gemspec +1 -3
- metadata +5 -44
- data/examples/testable-capybara-context.rb +0 -64
- data/examples/testable-capybara-rspec.rb +0 -70
- data/examples/testable-capybara.rb +0 -46
- data/lib/testable/capybara/dsl.rb +0 -82
- data/lib/testable/capybara/node.rb +0 -30
- data/lib/testable/capybara/page.rb +0 -29
@@ -1,64 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
$LOAD_PATH << "./lib"
|
3
|
-
|
4
|
-
require "rspec"
|
5
|
-
include RSpec::Matchers
|
6
|
-
|
7
|
-
require "testable"
|
8
|
-
include Testable::Context
|
9
|
-
|
10
|
-
Capybara.configure do |config|
|
11
|
-
config.run_server = false
|
12
|
-
config.default_driver = :selenium
|
13
|
-
config.app_host = "https://veilus.herokuapp.com"
|
14
|
-
end
|
15
|
-
|
16
|
-
class HomePage < Testable::Page
|
17
|
-
element :login_form, "#open"
|
18
|
-
element :username, "#username"
|
19
|
-
element :password, "#password"
|
20
|
-
element :login, "#login-button"
|
21
|
-
|
22
|
-
def path
|
23
|
-
"/"
|
24
|
-
end
|
25
|
-
|
26
|
-
def login_as_admin
|
27
|
-
login_form.click
|
28
|
-
username.set "admin"
|
29
|
-
password.set "admin"
|
30
|
-
login.click
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
class Navigation < Testable::Node
|
35
|
-
elements :items, "a"
|
36
|
-
|
37
|
-
element :page_list, "#navlist"
|
38
|
-
element :overlord, "#overlord"
|
39
|
-
element :planets, "#planets"
|
40
|
-
element :warp, "#warp"
|
41
|
-
element :stardate, "#stardate"
|
42
|
-
end
|
43
|
-
|
44
|
-
class MenuItem < Testable::Node
|
45
|
-
components :items, Navigation, "#areas"
|
46
|
-
end
|
47
|
-
|
48
|
-
class LandingPage < Testable::Page
|
49
|
-
component :navigation, Navigation, "#areas"
|
50
|
-
element :logo, "#site-image"
|
51
|
-
end
|
52
|
-
|
53
|
-
on_visit(HomePage).login_as_admin
|
54
|
-
|
55
|
-
on(LandingPage) do |action|
|
56
|
-
action.navigation.page_list.click
|
57
|
-
puts action.navigation.overlord.text
|
58
|
-
puts action.navigation.items
|
59
|
-
puts action.navigation.items[0].text
|
60
|
-
expect(action.navigation).to have_items
|
61
|
-
expect(action.navigation.items[0].text).to eq("Home")
|
62
|
-
expect(action.navigation.items.count).to be(8)
|
63
|
-
action.navigation.overlord.click
|
64
|
-
end
|
@@ -1,70 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
$LOAD_PATH << "./lib"
|
3
|
-
|
4
|
-
# Run this with:
|
5
|
-
# rspec ./examples/testable-capybara-rspec.rb
|
6
|
-
|
7
|
-
require "rspec"
|
8
|
-
include RSpec::Matchers
|
9
|
-
|
10
|
-
require "testable"
|
11
|
-
include Testable::Context
|
12
|
-
|
13
|
-
require "capybara/rspec"
|
14
|
-
|
15
|
-
RSpec.configure do |config|
|
16
|
-
config.expose_dsl_globally = true
|
17
|
-
end
|
18
|
-
|
19
|
-
Capybara.configure do |config|
|
20
|
-
config.run_server = false
|
21
|
-
config.default_driver = :selenium
|
22
|
-
config.app_host = "https://veilus.herokuapp.com"
|
23
|
-
end
|
24
|
-
|
25
|
-
class HomePage < Testable::Page
|
26
|
-
element :login_form, "#open"
|
27
|
-
element :username, "#username"
|
28
|
-
element :password, "#password"
|
29
|
-
element :login, "#login-button"
|
30
|
-
|
31
|
-
def path
|
32
|
-
"/"
|
33
|
-
end
|
34
|
-
|
35
|
-
def login_as_admin
|
36
|
-
login_form.click
|
37
|
-
username.set "admin"
|
38
|
-
password.set "admin"
|
39
|
-
login.click
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
class Navigation < Testable::Node
|
44
|
-
elements :items, "a"
|
45
|
-
|
46
|
-
element :page_list, "#navlist"
|
47
|
-
element :overlord, "#overlord"
|
48
|
-
element :planets, "#planets"
|
49
|
-
element :warp, "#warp"
|
50
|
-
element :stardate, "#stardate"
|
51
|
-
end
|
52
|
-
|
53
|
-
class LandingPage < Testable::Page
|
54
|
-
component :navigation, Navigation, "#areas"
|
55
|
-
|
56
|
-
def go_to_overlord
|
57
|
-
navigation.page_list.click
|
58
|
-
navigation.overlord.click
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
feature "navigation" do
|
63
|
-
background do
|
64
|
-
on_visit(HomePage).login_as_admin
|
65
|
-
end
|
66
|
-
|
67
|
-
scenario "navigates to overlord" do
|
68
|
-
on(LandingPage).go_to_overlord
|
69
|
-
end
|
70
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
$LOAD_PATH << "./lib"
|
3
|
-
|
4
|
-
require "rspec"
|
5
|
-
include RSpec::Matchers
|
6
|
-
|
7
|
-
require "testable"
|
8
|
-
|
9
|
-
Capybara.configure do |config|
|
10
|
-
config.run_server = false
|
11
|
-
config.default_driver = :selenium
|
12
|
-
config.app_host = "https://veilus.herokuapp.com"
|
13
|
-
end
|
14
|
-
|
15
|
-
class HomePage < Testable::Page
|
16
|
-
element :login_form, "#open"
|
17
|
-
element :username, "#username"
|
18
|
-
element :password, "#password"
|
19
|
-
element :login, "#login-button"
|
20
|
-
|
21
|
-
def path
|
22
|
-
"/"
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
home_page = HomePage.visit
|
27
|
-
|
28
|
-
puts home_page.current?
|
29
|
-
expect(home_page).to be_current
|
30
|
-
|
31
|
-
puts home_page.find("article").text
|
32
|
-
|
33
|
-
puts home_page.login_form.inspect
|
34
|
-
|
35
|
-
puts home_page.has_login_form?
|
36
|
-
puts home_page.has_no_login_form?
|
37
|
-
|
38
|
-
expect(home_page).to have_login_form
|
39
|
-
|
40
|
-
# The next statement would (correctly) fail.
|
41
|
-
# expect(home_page).to have_no_login_form
|
42
|
-
|
43
|
-
home_page.login_form.click
|
44
|
-
home_page.username.set "admin"
|
45
|
-
home_page.password.set "admin"
|
46
|
-
home_page.login.click
|
@@ -1,82 +0,0 @@
|
|
1
|
-
module Testable
|
2
|
-
module DSL
|
3
|
-
# The DSL module is mixed into the Node class to provide the DSL for
|
4
|
-
# defining elements and components.
|
5
|
-
def self.included(caller)
|
6
|
-
caller.extend(ClassMethods)
|
7
|
-
end
|
8
|
-
|
9
|
-
module ClassMethods
|
10
|
-
# The ClassMethods provide a set of macro-like methods for wrapping
|
11
|
-
# HTML fragments in Node objects.
|
12
|
-
|
13
|
-
# Defines an element that wraps an HTML fragment.
|
14
|
-
def element(name, selector, options = {})
|
15
|
-
define_method(name.to_s) do
|
16
|
-
Node.new(node: @node.find(selector, options))
|
17
|
-
end
|
18
|
-
|
19
|
-
define_helpers(name, selector)
|
20
|
-
end
|
21
|
-
|
22
|
-
# Defines a collection of elements that wrap HTML fragments.
|
23
|
-
def elements(name, selector, options = {})
|
24
|
-
options = { minimum: 1 }.merge(options)
|
25
|
-
|
26
|
-
define_method(name.to_s) do
|
27
|
-
@node.all(selector, options).map do |node|
|
28
|
-
Node.new(node: node)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
define_helpers(name, selector)
|
33
|
-
end
|
34
|
-
|
35
|
-
# Defines a component that wraps an HTML fragment.
|
36
|
-
def component(name, klass, selector, options = {})
|
37
|
-
unless klass < Node
|
38
|
-
raise ArgumentError, 'Must be given a subclass of Node'
|
39
|
-
end
|
40
|
-
|
41
|
-
define_method(name.to_s) do
|
42
|
-
klass.new(node: @node.find(selector, options))
|
43
|
-
end
|
44
|
-
|
45
|
-
define_helpers(name, selector)
|
46
|
-
end
|
47
|
-
|
48
|
-
# Defines a collection of components that wrap HTML fragments.
|
49
|
-
def components(name, klass, selector, options = {})
|
50
|
-
unless klass < Node
|
51
|
-
raise ArgumentError, 'Must be given a subclass of Node'
|
52
|
-
end
|
53
|
-
|
54
|
-
options = { minimum: 1 }.merge(options)
|
55
|
-
|
56
|
-
define_method(name.to_s) do
|
57
|
-
@node.all(selector, options).map do |node|
|
58
|
-
klass.new(node: node)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
define_helpers(name, selector)
|
63
|
-
end
|
64
|
-
|
65
|
-
private
|
66
|
-
|
67
|
-
def define_helpers(name, selector)
|
68
|
-
define_existence_predicates(name, selector)
|
69
|
-
end
|
70
|
-
|
71
|
-
def define_existence_predicates(name, selector)
|
72
|
-
define_method("has_#{name}?") do
|
73
|
-
@node.has_selector?(selector)
|
74
|
-
end
|
75
|
-
|
76
|
-
define_method("has_no_#{name}?") do
|
77
|
-
@node.has_no_selector?(selector)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
require "testable/capybara/dsl"
|
2
|
-
|
3
|
-
module Testable
|
4
|
-
class Node
|
5
|
-
# The Node class represents a wrapped HTML page or fragment. It exposes all
|
6
|
-
# methods of the Cogent DSL, making sure that any Capybara API methods
|
7
|
-
# are passed to the node instance.
|
8
|
-
include DSL
|
9
|
-
|
10
|
-
attr_reader :node
|
11
|
-
|
12
|
-
# A Capybara node is being wrapped in a node instance.
|
13
|
-
def initialize(node:)
|
14
|
-
@node = node
|
15
|
-
end
|
16
|
-
|
17
|
-
# Any Capybara API calls will be sent to the node object.
|
18
|
-
def method_missing(name, *args, &block)
|
19
|
-
if @node.respond_to?(name)
|
20
|
-
@node.send(name, *args, &block)
|
21
|
-
else
|
22
|
-
super
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def respond_to_missing?(name, include_private = false)
|
27
|
-
@node.respond_to?(name) || super
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
require "capybara"
|
2
|
-
require "testable/capybara/node"
|
3
|
-
|
4
|
-
module Testable
|
5
|
-
class Page < Node
|
6
|
-
# The `Page` class wraps an HTML page with an application-specific API.
|
7
|
-
# This can be extended to define an API for manipulating the pages of
|
8
|
-
# the web application.
|
9
|
-
attr_reader :path
|
10
|
-
|
11
|
-
def self.visit
|
12
|
-
new.visit
|
13
|
-
end
|
14
|
-
|
15
|
-
def initialize(node: Capybara.current_session, path: nil)
|
16
|
-
@node = node
|
17
|
-
@path = path
|
18
|
-
end
|
19
|
-
|
20
|
-
def visit
|
21
|
-
@node.visit(path)
|
22
|
-
self
|
23
|
-
end
|
24
|
-
|
25
|
-
def current?
|
26
|
-
@node.current_path == path
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|