testable 0.6.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.hound.yml +25 -4
- data/Gemfile +0 -2
- data/README.md +25 -2
- data/lib/testable.rb +67 -6
- 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 +2 -5
- metadata +10 -58
- 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
|