rails-jsdom 0.1.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.
@@ -0,0 +1,186 @@
1
+ module RailsJsdom
2
+ # An element on the page, returned by TestHelper#find, TestHelper#all,
3
+ # TestHelper#first, TestHelper#find_field, TestHelper#find_button and
4
+ # TestHelper#find_link.
5
+ #
6
+ # An element refers to a node in the live page. Actions on it settle the
7
+ # page like the TestHelper actions. Once the node leaves the page, for
8
+ # example after a navigation, using the element raises RailsJsdom::Error.
9
+ #
10
+ # item = find("#cart li", text: "Mug")
11
+ # item.find_button("Remove").click
12
+ # assert_equal "2", find_field("Quantity").value
13
+ class Element
14
+ def self.action(name) # :nodoc:
15
+ define_method(name) { perform(name) }
16
+ end
17
+
18
+ def self.read(name, from: name.to_s.delete_suffix("?")) # :nodoc:
19
+ define_method(name) { description.fetch(from) }
20
+ end
21
+
22
+ def self.scoped_helper(name) # :nodoc:
23
+ define_method(name) do |*arguments, **options|
24
+ @test.within(self) { @test.public_send(name, *arguments, **options) }
25
+ end
26
+ end
27
+
28
+ private_class_method :action, :read, :scoped_helper
29
+
30
+ attr_reader :handle # :nodoc:
31
+
32
+ def initialize(test, handle) # :nodoc:
33
+ @test = test
34
+ @handle = handle
35
+ end
36
+
37
+ ##
38
+ # Clicks the element.
39
+ action :click
40
+
41
+ ##
42
+ # Moves the pointer over the element. See TestHelper#hover.
43
+ action :hover
44
+
45
+ ##
46
+ # Double-clicks the element. See TestHelper#double_click.
47
+ action :double_click
48
+
49
+ ##
50
+ # Right-clicks the element. See TestHelper#right_click.
51
+ action :right_click
52
+
53
+ ##
54
+ # Selects this `option` in its select.
55
+ action :select_option
56
+
57
+ ##
58
+ # Deselects this `option` in a select that allows multiple options.
59
+ action :unselect_option
60
+
61
+ # Sets the element's value: text for a text-like field or a
62
+ # `contenteditable` element, `true` or `false` for a checkbox, `true` to
63
+ # select a radio button.
64
+ def set(value)
65
+ perform(:set, value: value)
66
+ end
67
+
68
+ # Focuses the element and types `keys` into it. See TestHelper#send_keys.
69
+ def send_keys(*keys)
70
+ perform(:send_keys, keys: RailsJsdom.keys(keys))
71
+ end
72
+
73
+ ##
74
+ # The visible text of the element.
75
+ read :text
76
+
77
+ ##
78
+ # The current value of a field, or `nil` for an element without one.
79
+ read :value
80
+
81
+ ##
82
+ # The element's tag name, such as `"button"`.
83
+ read :tag_name, from: "tag"
84
+
85
+ ##
86
+ # Whether a checkbox or radio button is checked.
87
+ read :checked?
88
+
89
+ ##
90
+ # Whether an `option` is selected.
91
+ read :selected?
92
+
93
+ ##
94
+ # Whether the element is disabled.
95
+ read :disabled?
96
+
97
+ ##
98
+ # Whether the element is visible: neither it nor an ancestor is hidden.
99
+ read :visible?
100
+
101
+ # The value of the attribute `name`, or the current value for `:value`.
102
+ def [](name)
103
+ name.to_s == "value" ? value : description.fetch("attributes")[name.to_s]
104
+ end
105
+
106
+ ##
107
+ # Like TestHelper#find, searching inside this element.
108
+ scoped_helper :find
109
+
110
+ ##
111
+ # Like TestHelper#all, searching inside this element.
112
+ scoped_helper :all
113
+
114
+ ##
115
+ # Like TestHelper#first, searching inside this element.
116
+ scoped_helper :first
117
+
118
+ ##
119
+ # Like TestHelper#find_field, searching inside this element.
120
+ scoped_helper :find_field
121
+
122
+ ##
123
+ # Like TestHelper#find_button, searching inside this element.
124
+ scoped_helper :find_button
125
+
126
+ ##
127
+ # Like TestHelper#find_link, searching inside this element.
128
+ scoped_helper :find_link
129
+
130
+ ##
131
+ # Like TestHelper#assert_text, for the text inside this element.
132
+ scoped_helper :assert_text
133
+
134
+ ##
135
+ # Like TestHelper#assert_no_text, for the text inside this element.
136
+ scoped_helper :assert_no_text
137
+
138
+ ##
139
+ # Like TestHelper#assert_selector, inside this element.
140
+ scoped_helper :assert_selector
141
+
142
+ ##
143
+ # Like TestHelper#assert_no_selector, inside this element.
144
+ scoped_helper :assert_no_selector
145
+
146
+ ##
147
+ # Like TestHelper#has_text?, for the text inside this element.
148
+ scoped_helper :has_text?
149
+
150
+ ##
151
+ # Like TestHelper#has_no_text?, for the text inside this element.
152
+ scoped_helper :has_no_text?
153
+
154
+ ##
155
+ # Like TestHelper#has_selector?, inside this element.
156
+ scoped_helper :has_selector?
157
+
158
+ ##
159
+ # Like TestHelper#has_no_selector?, inside this element.
160
+ scoped_helper :has_no_selector?
161
+
162
+ # Two elements are equal when they refer to the same node.
163
+ def ==(other)
164
+ other.is_a?(Element) && other.handle == handle
165
+ end
166
+ alias_method :eql?, :==
167
+
168
+ def hash # :nodoc:
169
+ handle.hash
170
+ end
171
+
172
+ def inspect # :nodoc:
173
+ "#<RailsJsdom::Element #{handle}>"
174
+ end
175
+
176
+ private
177
+
178
+ def perform(action, **options)
179
+ @test.rails_jsdom_element(handle, action.to_s, **options)
180
+ end
181
+
182
+ def description
183
+ @test.rails_jsdom_read(handle)
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,33 @@
1
+ require "active_support/core_ext/module/delegation"
2
+
3
+ module RailsJsdom
4
+ # The object behind TestHelper#page, for tests written as
5
+ # `page.has_css?(...)` or `page.find(...)`. Every TestHelper method can be
6
+ # called on it.
7
+ #
8
+ # assert page.has_css?(".cart-item", count: 2)
9
+ # page.find("#menu").click
10
+ class Page
11
+ delegate(*TestHelper.public_instance_methods - [ :page ], to: :@test)
12
+
13
+ def initialize(test) # :nodoc:
14
+ @test = test
15
+ end
16
+
17
+ # The HTML of the whole page.
18
+ def body
19
+ @test.rails_jsdom_page_snapshot.fetch("html")
20
+ end
21
+ alias_method :html, :body
22
+
23
+ # The page title.
24
+ def title
25
+ @test.rails_jsdom_page_snapshot.fetch("title")
26
+ end
27
+
28
+ # The visible text of the page, or of the current TestHelper#within scope.
29
+ def text
30
+ @test.page_text
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,76 @@
1
+ module RailsJsdom
2
+ class Query # :nodoc:
3
+ DISABLED_BY_DEFAULT = %w[field button].freeze
4
+
5
+ attr_reader :strategy, :locator
6
+
7
+ def self.like?(actual, expected)
8
+ expected.is_a?(Regexp) ? actual.match?(expected) : actual.include?(expected.to_s)
9
+ end
10
+
11
+ def self.same?(actual, expected)
12
+ expected.is_a?(Regexp) ? actual.match?(expected) : actual == expected.to_s
13
+ end
14
+
15
+ def initialize(strategy, locator, text: nil, exact_text: nil, visible: true, with: nil, checked: nil, unchecked: nil, disabled: nil, href: nil, type: nil)
16
+ @strategy = strategy
17
+ @locator = locator
18
+ @visible = visible
19
+ disabled = false if disabled.nil? && DISABLED_BY_DEFAULT.include?(strategy)
20
+ @filters = { text: text, exact_text: exact_text, with: with, checked: checked, unchecked: unchecked, disabled: disabled, href: href, type: type }.compact
21
+ end
22
+
23
+ def message
24
+ { command: "query", strategy: strategy, locator: locator }
25
+ end
26
+
27
+ def filter(descriptors)
28
+ descriptors.select { |descriptor| visible?(descriptor) && matches?(comparable_values(descriptor)) }
29
+ end
30
+
31
+ def description
32
+ [ "#{strategy} #{locator.inspect}", *@filters.map { |name, expected| "#{name}: #{expected.inspect}" } ].join(", ")
33
+ end
34
+
35
+ private
36
+
37
+ def visible?(descriptor)
38
+ case @visible
39
+ when true
40
+ descriptor.fetch("visible")
41
+ when :hidden
42
+ !descriptor.fetch("visible")
43
+ else
44
+ true
45
+ end
46
+ end
47
+
48
+ def matches?(values)
49
+ @filters.all? { |name, expected| satisfies?(name, expected, values.fetch(name)) }
50
+ end
51
+
52
+ def satisfies?(name, expected, actual)
53
+ case name
54
+ when :text
55
+ Query.like?(actual, expected)
56
+ when :checked, :unchecked, :disabled
57
+ expected == :all || actual == expected
58
+ else
59
+ Query.same?(actual, expected)
60
+ end
61
+ end
62
+
63
+ def comparable_values(descriptor)
64
+ {
65
+ text: descriptor.fetch(@visible == true ? "text" : "all_text"),
66
+ exact_text: descriptor.fetch("text"),
67
+ with: descriptor.fetch("value").to_s,
68
+ checked: descriptor.fetch("checked"),
69
+ unchecked: !descriptor.fetch("checked"),
70
+ disabled: descriptor.fetch("disabled"),
71
+ href: descriptor.fetch("attributes")["href"].to_s,
72
+ type: descriptor.fetch("type")
73
+ }
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,3 @@
1
+ "use strict"
2
+
3
+ require("./runtime").start(process)