capybara-ui 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.
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