capybara-ui 0.10.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/lib/capybara/ui.rb +33 -0
  3. data/lib/capybara/ui/assertions.rb +21 -0
  4. data/lib/{capybara-ui → capybara/ui}/capybara.rb +0 -0
  5. data/lib/capybara/ui/checkpoint.rb +113 -0
  6. data/lib/capybara/ui/conversions.rb +33 -0
  7. data/lib/capybara/ui/cucumber.rb +5 -0
  8. data/lib/capybara/ui/dsl.rb +109 -0
  9. data/lib/capybara/ui/instance_conversions.rb +21 -0
  10. data/lib/{capybara-ui → capybara/ui}/matchers.rb +4 -4
  11. data/lib/capybara/ui/optional_dependencies.rb +7 -0
  12. data/lib/capybara/ui/rails.rb +5 -0
  13. data/lib/capybara/ui/rails/role.rb +11 -0
  14. data/lib/capybara/ui/role.rb +21 -0
  15. data/lib/capybara/ui/text_table.rb +109 -0
  16. data/lib/capybara/ui/text_table/cell_text.rb +9 -0
  17. data/lib/capybara/ui/text_table/mapping.rb +42 -0
  18. data/lib/capybara/ui/text_table/transformations.rb +15 -0
  19. data/lib/capybara/ui/text_table/void_mapping.rb +10 -0
  20. data/lib/capybara/ui/version.rb +5 -0
  21. data/lib/capybara/ui/widgets.rb +63 -0
  22. data/lib/capybara/ui/widgets/check_box.rb +28 -0
  23. data/lib/capybara/ui/widgets/cucumber_methods.rb +75 -0
  24. data/lib/capybara/ui/widgets/document.rb +21 -0
  25. data/lib/capybara/ui/widgets/dsl.rb +49 -0
  26. data/lib/capybara/ui/widgets/field.rb +24 -0
  27. data/lib/capybara/ui/widgets/field_group.rb +331 -0
  28. data/lib/capybara/ui/widgets/form.rb +28 -0
  29. data/lib/capybara/ui/widgets/list.rb +202 -0
  30. data/lib/capybara/ui/widgets/list_item.rb +24 -0
  31. data/lib/capybara/ui/widgets/parts/container.rb +48 -0
  32. data/lib/capybara/ui/widgets/parts/struct.rb +119 -0
  33. data/lib/capybara/ui/widgets/radio_button.rb +64 -0
  34. data/lib/capybara/ui/widgets/select.rb +59 -0
  35. data/lib/capybara/ui/widgets/string_value.rb +45 -0
  36. data/lib/capybara/ui/widgets/table.rb +78 -0
  37. data/lib/capybara/ui/widgets/text_field.rb +29 -0
  38. data/lib/capybara/ui/widgets/widget.rb +394 -0
  39. data/lib/capybara/ui/widgets/widget/node_filter.rb +50 -0
  40. data/lib/capybara/ui/widgets/widget_class.rb +13 -0
  41. data/lib/capybara/ui/widgets/widget_name.rb +58 -0
  42. metadata +47 -43
  43. data/lib/capybara-ui.rb +0 -31
  44. data/lib/capybara-ui/assertions.rb +0 -19
  45. data/lib/capybara-ui/checkpoint.rb +0 -111
  46. data/lib/capybara-ui/conversions.rb +0 -31
  47. data/lib/capybara-ui/cucumber.rb +0 -5
  48. data/lib/capybara-ui/dsl.rb +0 -107
  49. data/lib/capybara-ui/instance_conversions.rb +0 -19
  50. data/lib/capybara-ui/optional_dependencies.rb +0 -5
  51. data/lib/capybara-ui/rails.rb +0 -5
  52. data/lib/capybara-ui/rails/role.rb +0 -9
  53. data/lib/capybara-ui/role.rb +0 -19
  54. data/lib/capybara-ui/text_table.rb +0 -107
  55. data/lib/capybara-ui/text_table/cell_text.rb +0 -7
  56. data/lib/capybara-ui/text_table/mapping.rb +0 -40
  57. data/lib/capybara-ui/text_table/transformations.rb +0 -13
  58. data/lib/capybara-ui/text_table/void_mapping.rb +0 -8
  59. data/lib/capybara-ui/version.rb +0 -3
  60. data/lib/capybara-ui/widgets.rb +0 -61
  61. data/lib/capybara-ui/widgets/check_box.rb +0 -26
  62. data/lib/capybara-ui/widgets/cucumber_methods.rb +0 -73
  63. data/lib/capybara-ui/widgets/document.rb +0 -19
  64. data/lib/capybara-ui/widgets/dsl.rb +0 -47
  65. data/lib/capybara-ui/widgets/field.rb +0 -22
  66. data/lib/capybara-ui/widgets/field_group.rb +0 -329
  67. data/lib/capybara-ui/widgets/form.rb +0 -26
  68. data/lib/capybara-ui/widgets/list.rb +0 -200
  69. data/lib/capybara-ui/widgets/list_item.rb +0 -22
  70. data/lib/capybara-ui/widgets/parts/container.rb +0 -46
  71. data/lib/capybara-ui/widgets/parts/struct.rb +0 -117
  72. data/lib/capybara-ui/widgets/radio_button.rb +0 -62
  73. data/lib/capybara-ui/widgets/select.rb +0 -57
  74. data/lib/capybara-ui/widgets/string_value.rb +0 -43
  75. data/lib/capybara-ui/widgets/table.rb +0 -76
  76. data/lib/capybara-ui/widgets/text_field.rb +0 -27
  77. data/lib/capybara-ui/widgets/widget.rb +0 -392
  78. data/lib/capybara-ui/widgets/widget/node_filter.rb +0 -48
  79. data/lib/capybara-ui/widgets/widget_class.rb +0 -11
  80. data/lib/capybara-ui/widgets/widget_name.rb +0 -56
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 23fc0acf5fe588ee3f45849a2874646086bd6ee5
4
- data.tar.gz: cc92aa9e22aa4c98962fe0f69cf932064199eb44
3
+ metadata.gz: 8569e04fe7e820a732b875283667700db0021f11
4
+ data.tar.gz: eab7f283b1ac93ceb0a1ff5db4d4319bf4f8b687
5
5
  SHA512:
6
- metadata.gz: c7e1e9fe1f240f81740fd5069ed9a28fdadb8c0243cc46c614a6172cb6e88ed0e8e08ab58611093780b66eeea5356d5d6a5b8c7e1016ac897c77f49d078e24d5
7
- data.tar.gz: a7cb453961ba99e4ef31daf00e0016fc8c9b802a018efdf030191b99cfe13878d65651514d35e43e89bb504f04ddc45845a66612a0361a70b210a009807172e8
6
+ metadata.gz: 703a2e188f63c0e896b1a9df815dad5df846bcb30882d6618168b207b2f19a6736f84ddfe3c2751ed2cd92f536355c0320e0ea53de0964c562aa0704ac9db33d
7
+ data.tar.gz: cd41f9dd5368aba4585a365c321b399aa3c55c329990f68f66b4ebbd1181de4f98dc429c9d85f959176b559035db89e6003d8945ea4cfd0feeb8196d5d18a3cb
@@ -0,0 +1,33 @@
1
+ require 'chronic'
2
+ require 'nokogiri'
3
+ require 'capybara'
4
+
5
+ require 'capybara/ui/optional_dependencies'
6
+ require 'capybara/ui/conversions'
7
+ require 'capybara/ui/instance_conversions'
8
+ require 'capybara/ui/checkpoint'
9
+ require 'capybara/ui/widgets'
10
+ require 'capybara/ui/text_table'
11
+ require 'capybara/ui/text_table/mapping'
12
+ require 'capybara/ui/text_table/void_mapping'
13
+ require 'capybara/ui/text_table/transformations'
14
+ require 'capybara/ui/text_table/cell_text'
15
+ require 'capybara/ui/capybara'
16
+ require 'capybara/ui/dsl'
17
+
18
+ module Capybara
19
+ module UI
20
+ # An exception that signals that something is missing.
21
+ class Missing < StandardError; end
22
+ class MissingWidget < StandardError; end
23
+ class AmbiguousWidget < StandardError; end
24
+ class InvalidOption < StandardError; end
25
+ class InvalidRadioButton < StandardError; end
26
+
27
+ def deprecate(method, alternate_method, once=false)
28
+ @deprecation_notified ||= {}
29
+ warn "DEPRECATED: ##{method} is deprecated, please use ##{alternate_method} instead" unless once and @deprecation_notified[method]
30
+ @deprecation_notified[method] = true
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,21 @@
1
+ module Capybara
2
+ module UI
3
+ module Assertions
4
+ def assert_visible(role, widget_name, *args)
5
+ eventually do
6
+ assert role.see?(widget_name, *args)
7
+
8
+ true
9
+ end
10
+ end
11
+
12
+ def assert_not_visible(role, widget_name, *args)
13
+ eventually do
14
+ refute role.see?(widget_name, *args)
15
+
16
+ true
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
File without changes
@@ -0,0 +1,113 @@
1
+ module Capybara
2
+ module UI
3
+ # A point in time where some condition, or some set of conditions, should be
4
+ # verified.
5
+ #
6
+ # @see http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Base#synchronize-instance_method,
7
+ # which inspired this class.
8
+ class Checkpoint
9
+ class ConditionNotMet < StandardError; end
10
+
11
+ class << self
12
+ attr_accessor :rescuable_errors
13
+ end
14
+
15
+ self.rescuable_errors = [StandardError]
16
+
17
+ if defined?(RSpec)
18
+ require 'rspec/expectations'
19
+ self.rescuable_errors << RSpec::Expectations::ExpectationNotMetError
20
+ end
21
+
22
+ class Timer
23
+ class Frozen < StandardError; end
24
+
25
+ def initialize(duration)
26
+ @duration = duration
27
+ end
28
+
29
+ attr_reader :duration
30
+
31
+ def expired?
32
+ duration < elapsed
33
+ end
34
+
35
+ def elapsed
36
+ now - start_time
37
+ end
38
+
39
+ def start
40
+ @start_time = now
41
+ end
42
+
43
+ def tick
44
+ sleep tick_duration
45
+
46
+ raise Frozen, 'time appears to be frozen' if frozen?
47
+ end
48
+
49
+ protected
50
+
51
+ def now
52
+ Time.now
53
+ end
54
+
55
+ attr_reader :start_time
56
+
57
+ def frozen?
58
+ now == start_time
59
+ end
60
+
61
+ def tick_duration
62
+ 0.05
63
+ end
64
+ end
65
+
66
+ # Shortcut for instance level wait_for.
67
+ def self.wait_for(wait_time = Capybara.default_max_wait_time, &block)
68
+ new(wait_time).call(&block)
69
+ end
70
+
71
+ # Initializes a new Checkpoint.
72
+ #
73
+ # @param wait_time how long this checkpoint will wait for its conditions to
74
+ # be met, in seconds.
75
+ def initialize(wait_time = Capybara.default_max_wait_time)
76
+ @timer = Timer.new(wait_time)
77
+ end
78
+
79
+ # Executes +block+ repeatedly until it returns a "truthy" value or
80
+ # +wait_time+ expires.
81
+ #
82
+ # Swallows any StandardError or StandardError descendent until +wait_time+
83
+ # expires. If an exception is raised and the time has expired, that
84
+ # exception will be raised again.
85
+ #
86
+ # If the block does not return a "truthy" value until +wait_time+ expires,
87
+ # raises a Capybara::UI::Checkpoint::ConditionNotMet error.
88
+ #
89
+ # Returns whatever value is returned by the block.
90
+ def call(&condition)
91
+ timer.start
92
+
93
+ begin
94
+ yield or raise ConditionNotMet
95
+ rescue *rescuable_errors
96
+ raise if timer.expired?
97
+
98
+ timer.tick
99
+
100
+ retry
101
+ end
102
+ end
103
+
104
+ protected
105
+
106
+ def rescuable_errors
107
+ self.class.rescuable_errors
108
+ end
109
+
110
+ attr_reader :timer
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,33 @@
1
+ module Capybara
2
+ module UI
3
+ module Conversions
4
+ extend self
5
+
6
+ def Boolean(val)
7
+ case val
8
+ when 'yes', 'true', true
9
+ true
10
+ when 'no', 'false', false, nil, ''
11
+ false
12
+ else
13
+ raise ArgumentError, "can't convert #{val.inspect} to boolean"
14
+ end
15
+ end
16
+
17
+ def List(valstr, &block)
18
+ vs = valstr.strip.split(/\s*,\s*/)
19
+
20
+ block ? vs.map(&block) : vs
21
+ end
22
+
23
+ def Timeish(val)
24
+ raise ArgumentError, "can't convert nil to Timeish" if val.nil?
25
+
26
+ return val if Date === val || Time === val || DateTime === val
27
+
28
+ Chronic.parse(val) or
29
+ raise ArgumentError, "can't parse #{val.inspect} to Timeish"
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,5 @@
1
+ require 'capybara/cucumber'
2
+ require 'capybara/ui/rails'
3
+ require 'capybara/ui/matchers'
4
+
5
+ World(Capybara::UI::DSL)
@@ -0,0 +1,109 @@
1
+ module Capybara
2
+ module UI
3
+ module DSL
4
+ attr_writer :widget_lookup_scope
5
+
6
+ # Clicks the widget defined by +name+ and optional +args+.
7
+ #
8
+ # Makes no distinction between links or buttons.
9
+ #
10
+ # class MyWidget < Capybara::UI::Widget
11
+ # root { |text| ['.my-widget', text: text] }
12
+ # end
13
+ #
14
+ # # <a href="#one" class="my-widget">One</li>
15
+ # # <a href="#two" class="my-widget">Two</li> <!-- clicks this node -->
16
+ # click :my_widget, 'Two'
17
+ def click(name, *args)
18
+ widget(name, *args).click
19
+ end
20
+
21
+ # Hovers the widget defined by +name+ and optional +args+.
22
+ def hover(name, *args)
23
+ widget(name, *args).hover
24
+ end
25
+
26
+ # Double clicks the widget defined by +name+ and optional +args+.
27
+ def double_click(name, *args)
28
+ widget(name, *args).double_click
29
+ end
30
+
31
+ # Right clicks the widget defined by +name+ and optional +args+.
32
+ def right_click(name, *args)
33
+ widget(name, *args).right_click
34
+ end
35
+
36
+ # @return [Document] the current document with the class of the
37
+ # current object set as the widget lookup scope.
38
+ def document
39
+ Document.new(widget_lookup_scope)
40
+ end
41
+
42
+ # @return [Boolean] Whether one or more widgets exist in the current
43
+ # document.
44
+ def has_widget?(name, *args)
45
+ document.has_widget?(name, *args)
46
+ end
47
+
48
+ alias_method :widget?, :has_widget?
49
+
50
+ def visible?(name, *args)
51
+ document.visible?(name, *args)
52
+ end
53
+
54
+ def not_visible?(name, *args)
55
+ document.not_visible?(name, *args)
56
+ end
57
+
58
+ def set(name, fields)
59
+ widget(name).set fields
60
+ end
61
+
62
+ def submit(name, fields = {})
63
+ widget(name).submit_with fields
64
+ end
65
+
66
+ def value(name, *args)
67
+ widget(name, *args).value
68
+ end
69
+
70
+ def values(name, *args)
71
+ widgets(name, *args).map(&:value)
72
+ end
73
+
74
+ def visit(path)
75
+ Capybara.current_session.visit path
76
+ end
77
+
78
+ # Returns a widget instance for the given name.
79
+ #
80
+ # @param name [String, Symbol]
81
+ def widget(name, *args)
82
+ eventually { document.widget(name, *args) }
83
+ end
84
+
85
+ # Returns a list of widget instances for the given name.
86
+ #
87
+ # @param name [String, Symbol]
88
+ def widgets(name, *args)
89
+ document.widgets(name, *args)
90
+ end
91
+
92
+ def widget_lookup_scope
93
+ @widget_lookup_scope ||= default_widget_lookup_scope
94
+ end
95
+
96
+ # re-run one or more assertions until either they all pass,
97
+ # or Capybara::UI times out, which will result in a test failure.
98
+ def eventually(wait_time = Capybara.default_max_wait_time, &block)
99
+ Checkpoint.wait_for wait_time, &block
100
+ end
101
+
102
+ private
103
+
104
+ def default_widget_lookup_scope
105
+ Module === self ? self : self.class
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,21 @@
1
+ module Capybara
2
+ module UI
3
+ module InstanceConversions
4
+ def self.included(base)
5
+ base.send :include, Capybara::UI::Conversions
6
+ end
7
+
8
+ def to_boolean
9
+ Boolean(self)
10
+ end
11
+
12
+ def to_a
13
+ List(self)
14
+ end
15
+
16
+ def to_time
17
+ Timeish(self)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -2,9 +2,9 @@ begin
2
2
  require 'rspec/matchers'
3
3
  require 'rspec/version'
4
4
 
5
- unless Gem::Version.new(RSpec::Version::STRING) >= Gem::Version.new(CapybaraUI::OptionalDependencies::RSPEC_VERSION)
5
+ unless Gem::Version.new(RSpec::Version::STRING) >= Gem::Version.new(Capybara::UI::OptionalDependencies::RSPEC_VERSION)
6
6
  raise LoadError,
7
- "requires RSpec version #{CapybaraUI::OptionalDependencies::RSPEC_VERSION} or later. " \
7
+ "requires RSpec version #{Capybara::UI::OptionalDependencies::RSPEC_VERSION} or later. " \
8
8
  "You have #{RSpec::Version::STRING}."
9
9
  end
10
10
 
@@ -12,7 +12,7 @@ begin
12
12
  match do |role|
13
13
  begin
14
14
  eventually { role.see?(widget_name, *args) }
15
- rescue CapybaraUI::Checkpoint::ConditionNotMet
15
+ rescue Capybara::UI::Checkpoint::ConditionNotMet
16
16
  false
17
17
  end
18
18
  end
@@ -20,7 +20,7 @@ begin
20
20
  match_when_negated do |role|
21
21
  begin
22
22
  eventually { !role.see?(widget_name, *args) }
23
- rescue CapybaraUI::Checkpoint::ConditionNotMet
23
+ rescue Capybara::UI::Checkpoint::ConditionNotMet
24
24
  false
25
25
  end
26
26
  end
@@ -0,0 +1,7 @@
1
+ module Capybara
2
+ module UI
3
+ module OptionalDependencies
4
+ RSPEC_VERSION = '3.0'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ require 'action_dispatch/testing/integration'
2
+
3
+ require 'capybara/ui/rails/role'
4
+ require 'capybara/ui'
5
+ require 'capybara/ui/role'
@@ -0,0 +1,11 @@
1
+ module Capybara
2
+ module UI
3
+ module Rails
4
+ class Role < ActionDispatch::IntegrationTest
5
+ def initialize
6
+ super self.class.name
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ module Capybara
2
+ module UI
3
+ class Role < Capybara::UI::Rails::Role
4
+ extend Widgets::DSL
5
+
6
+ include Capybara::UI::DSL
7
+
8
+ def see?(name, *args)
9
+ if respond_to?("see_#{name}?")
10
+ send("see_#{name}?", *args)
11
+ else
12
+ visible?(name, *args)
13
+ end
14
+ end
15
+
16
+ def inspect
17
+ self.class.name
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,109 @@
1
+ module Capybara
2
+ module UI
3
+ class TextTable
4
+ extend Forwardable
5
+
6
+ include Enumerable
7
+ include Conversions
8
+
9
+ class << self
10
+ def Array(table)
11
+ new(table).to_a
12
+ end
13
+
14
+ def Hash(table)
15
+ new(table).to_h
16
+ end
17
+
18
+ def map(name, options = {}, &block)
19
+ case name
20
+ when :*
21
+ set_default_mapping options, &block
22
+ else
23
+ set_mapping name, options, &block
24
+ end
25
+ end
26
+
27
+ def mappings
28
+ @mappings ||= Hash.
29
+ new { |h, k| h[k] = Mapping.new }.
30
+ merge(with_parent_mappings)
31
+ end
32
+
33
+ def skip(name)
34
+ case name
35
+ when :*
36
+ set_default_mapping VoidMapping
37
+ else
38
+ raise ArgumentError, "can't convert #{name.inspect} to name"
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def set_default_mapping(options, &block)
45
+ case options
46
+ when Hash
47
+ @mappings = Hash.
48
+ new { |h, k|
49
+ h[k] = Mapping.new(key_transformer: options[:to],
50
+ value_transformer: block) }.
51
+ merge(mappings)
52
+ when Class
53
+ @mappings = Hash.new { |h, k| h[k] = options.new }.merge(mappings)
54
+ else
55
+ raise ArgumentError, "can't convert #{options.inspect} to mapping"
56
+ end
57
+ end
58
+
59
+ def set_mapping(name, options, &block)
60
+ mappings[name] = Mapping.
61
+ new(key: options[:to], value_transformer: block)
62
+ end
63
+
64
+ def with_parent_mappings
65
+ if superclass.respond_to?(:mappings)
66
+ superclass.send(:mappings).dup
67
+ else
68
+ {}
69
+ end
70
+ end
71
+ end
72
+
73
+ def_delegators 'self.class', :mappings
74
+
75
+ def initialize(table)
76
+ self.table = table
77
+ end
78
+
79
+ def each(&block)
80
+ rows.each(&block)
81
+ end
82
+
83
+ def rows
84
+ @rows ||= table.hashes.map { |h| new_row(h) }
85
+ end
86
+
87
+ def single_row
88
+ @single_row ||= new_row(table.rows_hash)
89
+ end
90
+
91
+ alias_method :to_a, :rows
92
+ alias_method :to_h, :single_row
93
+
94
+ private
95
+
96
+ attr_accessor :table
97
+
98
+ def new_row(hash)
99
+ hash.each_with_object({}) { |(k, v), h|
100
+ mapping_for(k).set(self, h, k, CellText.new(v))
101
+ }
102
+ end
103
+
104
+ def mapping_for(header)
105
+ mappings[header]
106
+ end
107
+ end
108
+ end
109
+ end