isomorfeus-puppetmaster 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.
- checksums.yaml +7 -0
- data/README.md +191 -0
- data/lib/isomorfeus-puppetmaster.rb +43 -0
- data/lib/isomorfeus/puppetmaster.rb +62 -0
- data/lib/isomorfeus/puppetmaster/console_message.rb +19 -0
- data/lib/isomorfeus/puppetmaster/cookie.rb +46 -0
- data/lib/isomorfeus/puppetmaster/document.rb +160 -0
- data/lib/isomorfeus/puppetmaster/driver/jsdom.rb +370 -0
- data/lib/isomorfeus/puppetmaster/driver/jsdom_document.rb +908 -0
- data/lib/isomorfeus/puppetmaster/driver/jsdom_node.rb +836 -0
- data/lib/isomorfeus/puppetmaster/driver/puppeteer.rb +401 -0
- data/lib/isomorfeus/puppetmaster/driver/puppeteer_document.rb +944 -0
- data/lib/isomorfeus/puppetmaster/driver/puppeteer_node.rb +866 -0
- data/lib/isomorfeus/puppetmaster/driver_registration.rb +19 -0
- data/lib/isomorfeus/puppetmaster/dsl.rb +40 -0
- data/lib/isomorfeus/puppetmaster/errors.rb +90 -0
- data/lib/isomorfeus/puppetmaster/iframe.rb +17 -0
- data/lib/isomorfeus/puppetmaster/node.rb +241 -0
- data/lib/isomorfeus/puppetmaster/node/checkbox.rb +17 -0
- data/lib/isomorfeus/puppetmaster/node/content_editable.rb +18 -0
- data/lib/isomorfeus/puppetmaster/node/filechooser.rb +9 -0
- data/lib/isomorfeus/puppetmaster/node/input.rb +21 -0
- data/lib/isomorfeus/puppetmaster/node/radiobutton.rb +13 -0
- data/lib/isomorfeus/puppetmaster/node/select.rb +36 -0
- data/lib/isomorfeus/puppetmaster/node/textarea.rb +7 -0
- data/lib/isomorfeus/puppetmaster/request.rb +17 -0
- data/lib/isomorfeus/puppetmaster/response.rb +26 -0
- data/lib/isomorfeus/puppetmaster/rspec/features.rb +23 -0
- data/lib/isomorfeus/puppetmaster/rspec/matcher_proxies.rb +80 -0
- data/lib/isomorfeus/puppetmaster/rspec/matchers.rb +164 -0
- data/lib/isomorfeus/puppetmaster/rspec/matchers/base.rb +98 -0
- data/lib/isomorfeus/puppetmaster/rspec/matchers/become_closed.rb +33 -0
- data/lib/isomorfeus/puppetmaster/rspec/matchers/compound.rb +88 -0
- data/lib/isomorfeus/puppetmaster/rspec/matchers/have_current_path.rb +29 -0
- data/lib/isomorfeus/puppetmaster/rspec/matchers/have_selector.rb +69 -0
- data/lib/isomorfeus/puppetmaster/rspec/matchers/have_text.rb +33 -0
- data/lib/isomorfeus/puppetmaster/rspec/matchers/have_title.rb +29 -0
- data/lib/isomorfeus/puppetmaster/rspec/matchers/match_selector.rb +27 -0
- data/lib/isomorfeus/puppetmaster/rspec/matchers/match_style.rb +38 -0
- data/lib/isomorfeus/puppetmaster/self_forwardable.rb +31 -0
- data/lib/isomorfeus/puppetmaster/server.rb +128 -0
- data/lib/isomorfeus/puppetmaster/server/checker.rb +40 -0
- data/lib/isomorfeus/puppetmaster/server/middleware.rb +60 -0
- data/lib/isomorfeus/puppetmaster/server_registration.rb +37 -0
- data/lib/isomorfeus/puppetmaster/version.rb +3 -0
- metadata +282 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Capybara
|
4
|
+
module RSpecMatchers
|
5
|
+
module Matchers
|
6
|
+
class BecomeClosed
|
7
|
+
def initialize(options)
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def matches?(window)
|
12
|
+
@window = window
|
13
|
+
@wait_time = Capybara::Queries::BaseQuery.wait(@options, window.session.config.default_max_wait_time)
|
14
|
+
timer = Capybara::Helpers.timer(expire_in: @wait_time)
|
15
|
+
while window.exists?
|
16
|
+
return false if timer.expired?
|
17
|
+
|
18
|
+
sleep 0.01
|
19
|
+
end
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
def failure_message
|
24
|
+
"expected #{@window.inspect} to become closed after #{@wait_time} seconds"
|
25
|
+
end
|
26
|
+
|
27
|
+
def failure_message_when_negated
|
28
|
+
"expected #{@window.inspect} not to become closed after #{@wait_time} seconds"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
if defined?(::RSpec::Expectations::Version)
|
4
|
+
module Capybara
|
5
|
+
module RSpecMatchers
|
6
|
+
module Matchers
|
7
|
+
module Compound
|
8
|
+
include ::RSpec::Matchers::Composable
|
9
|
+
|
10
|
+
def and(matcher)
|
11
|
+
And.new(self, matcher)
|
12
|
+
end
|
13
|
+
|
14
|
+
def and_then(matcher)
|
15
|
+
::RSpec::Matchers::BuiltIn::Compound::And.new(self, matcher)
|
16
|
+
end
|
17
|
+
|
18
|
+
def or(matcher)
|
19
|
+
Or.new(self, matcher)
|
20
|
+
end
|
21
|
+
|
22
|
+
class CapybaraEvaluator
|
23
|
+
def initialize(actual)
|
24
|
+
@actual = actual
|
25
|
+
@match_results = Hash.new { |hsh, matcher| hsh[matcher] = matcher.matches?(@actual) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def matcher_matches?(matcher)
|
29
|
+
@match_results[matcher]
|
30
|
+
end
|
31
|
+
|
32
|
+
def reset
|
33
|
+
@match_results.clear
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# @api private
|
38
|
+
module Synchronizer
|
39
|
+
def match(_expected, actual)
|
40
|
+
@evaluator = CapybaraEvaluator.new(actual)
|
41
|
+
syncer = sync_element(actual)
|
42
|
+
begin
|
43
|
+
syncer.synchronize do
|
44
|
+
@evaluator.reset
|
45
|
+
raise ::Capybara::ElementNotFound unless synchronized_match?
|
46
|
+
|
47
|
+
true
|
48
|
+
end
|
49
|
+
rescue StandardError
|
50
|
+
false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def sync_element(el)
|
55
|
+
if el.respond_to? :synchronize
|
56
|
+
el
|
57
|
+
elsif el.respond_to? :current_scope
|
58
|
+
el.current_scope
|
59
|
+
else
|
60
|
+
Capybara.string(el)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class And < ::RSpec::Matchers::BuiltIn::Compound::And
|
66
|
+
include Synchronizer
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def synchronized_match?
|
71
|
+
[matcher_1_matches?, matcher_2_matches?].all?
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class Or < ::RSpec::Matchers::BuiltIn::Compound::Or
|
76
|
+
include Synchronizer
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def synchronized_match?
|
81
|
+
[matcher_1_matches?, matcher_2_matches?].any?
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'capybara/rspec/matchers/base'
|
4
|
+
|
5
|
+
module Capybara
|
6
|
+
module RSpecMatchers
|
7
|
+
module Matchers
|
8
|
+
class HaveCurrentPath < WrappedElementMatcher
|
9
|
+
def element_matches?(el)
|
10
|
+
el.assert_current_path(*@args)
|
11
|
+
end
|
12
|
+
|
13
|
+
def element_does_not_match?(el)
|
14
|
+
el.assert_no_current_path(*@args)
|
15
|
+
end
|
16
|
+
|
17
|
+
def description
|
18
|
+
"have current path #{current_path.inspect}"
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def current_path
|
24
|
+
@args.first
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'capybara/rspec/matchers/base'
|
4
|
+
|
5
|
+
module Capybara
|
6
|
+
module RSpecMatchers
|
7
|
+
module Matchers
|
8
|
+
class HaveSelector < WrappedElementMatcher
|
9
|
+
def element_matches?(el)
|
10
|
+
el.assert_selector(*@args, &@filter_block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def element_does_not_match?(el)
|
14
|
+
el.assert_no_selector(*@args, &@filter_block)
|
15
|
+
end
|
16
|
+
|
17
|
+
def description
|
18
|
+
"have #{query.description}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def query
|
22
|
+
@query ||= Capybara::Queries::SelectorQuery.new(*session_query_args, &@filter_block)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class HaveAllSelectors < WrappedElementMatcher
|
27
|
+
def element_matches?(el)
|
28
|
+
el.assert_all_of_selectors(*@args, &@filter_block)
|
29
|
+
end
|
30
|
+
|
31
|
+
def does_not_match?(_actual)
|
32
|
+
raise ArgumentError, 'The have_all_selectors matcher does not support use with not_to/should_not'
|
33
|
+
end
|
34
|
+
|
35
|
+
def description
|
36
|
+
'have all selectors'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class HaveNoSelectors < WrappedElementMatcher
|
41
|
+
def element_matches?(el)
|
42
|
+
el.assert_none_of_selectors(*@args, &@filter_block)
|
43
|
+
end
|
44
|
+
|
45
|
+
def does_not_match?(_actual)
|
46
|
+
raise ArgumentError, 'The have_none_of_selectors matcher does not support use with not_to/should_not'
|
47
|
+
end
|
48
|
+
|
49
|
+
def description
|
50
|
+
'have no selectors'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class HaveAnySelectors < WrappedElementMatcher
|
55
|
+
def element_matches?(el)
|
56
|
+
el.assert_any_of_selectors(*@args, &@filter_block)
|
57
|
+
end
|
58
|
+
|
59
|
+
def does_not_match?(_actual)
|
60
|
+
el.assert_none_of_selectors(*@args, &@filter_block)
|
61
|
+
end
|
62
|
+
|
63
|
+
def description
|
64
|
+
'have any selectors'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'capybara/rspec/matchers/base'
|
4
|
+
|
5
|
+
module Capybara
|
6
|
+
module RSpecMatchers
|
7
|
+
module Matchers
|
8
|
+
class HaveText < WrappedElementMatcher
|
9
|
+
def element_matches?(el)
|
10
|
+
el.assert_text(*@args)
|
11
|
+
end
|
12
|
+
|
13
|
+
def element_does_not_match?(el)
|
14
|
+
el.assert_no_text(*@args)
|
15
|
+
end
|
16
|
+
|
17
|
+
def description
|
18
|
+
"text #{format(text)}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def format(content)
|
22
|
+
content.inspect
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def text
|
28
|
+
@args[0].is_a?(Symbol) ? @args[1] : @args[0]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'capybara/rspec/matchers/base'
|
4
|
+
|
5
|
+
module Capybara
|
6
|
+
module RSpecMatchers
|
7
|
+
module Matchers
|
8
|
+
class HaveTitle < WrappedElementMatcher
|
9
|
+
def element_matches?(el)
|
10
|
+
el.assert_title(*@args)
|
11
|
+
end
|
12
|
+
|
13
|
+
def element_does_not_match?(el)
|
14
|
+
el.assert_no_title(*@args)
|
15
|
+
end
|
16
|
+
|
17
|
+
def description
|
18
|
+
"have title #{title.inspect}"
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def title
|
24
|
+
@args.first
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'capybara/rspec/matchers/have_selector'
|
4
|
+
|
5
|
+
module Capybara
|
6
|
+
module RSpecMatchers
|
7
|
+
module Matchers
|
8
|
+
class MatchSelector < HaveSelector
|
9
|
+
def element_matches?(el)
|
10
|
+
el.assert_matches_selector(*@args, &@filter_block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def element_does_not_match?(el)
|
14
|
+
el.assert_not_matches_selector(*@args, &@filter_block)
|
15
|
+
end
|
16
|
+
|
17
|
+
def description
|
18
|
+
"match #{query.description}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def query
|
22
|
+
@query ||= Capybara::Queries::MatchQuery.new(*session_query_args, &@filter_block)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'capybara/rspec/matchers/base'
|
4
|
+
|
5
|
+
module Capybara
|
6
|
+
module RSpecMatchers
|
7
|
+
module Matchers
|
8
|
+
class MatchStyle < WrappedElementMatcher
|
9
|
+
def element_matches?(el)
|
10
|
+
el.assert_matches_style(*@args)
|
11
|
+
end
|
12
|
+
|
13
|
+
def does_not_match?(_actual)
|
14
|
+
raise ArgumentError, 'The match_style matcher does not support use with not_to/should_not'
|
15
|
+
end
|
16
|
+
|
17
|
+
def description
|
18
|
+
'match style'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module Capybara
|
26
|
+
module RSpecMatchers
|
27
|
+
module Matchers
|
28
|
+
##
|
29
|
+
# @deprecated
|
30
|
+
class HaveStyle < MatchStyle
|
31
|
+
def initialize(*args, &filter_block)
|
32
|
+
warn 'HaveStyle matcher is deprecated, please use the MatchStyle matcher instead'
|
33
|
+
super
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Isomorfeus
|
2
|
+
module Puppetmaster
|
3
|
+
module SelfForwardable
|
4
|
+
def self.extended(base)
|
5
|
+
base.define_singleton_method(:document_forward) do |methods|
|
6
|
+
methods.each do |method|
|
7
|
+
define_method(method) do |*args, &block|
|
8
|
+
@driver.send("document_#{method}", self, *args, &block)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
base.define_singleton_method(:frame_forward) do |methods|
|
14
|
+
methods.each do |method|
|
15
|
+
define_method(method) do |*args|
|
16
|
+
@driver.send("frame_#{method}", self, *args)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
base.define_singleton_method(:node_forward) do |methods|
|
22
|
+
methods.each do |method|
|
23
|
+
define_method(method) do |*args|
|
24
|
+
@driver.send("node_#{method}", self, *args)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module Isomorfeus
|
2
|
+
module Puppetmaster
|
3
|
+
class Server
|
4
|
+
class Timer
|
5
|
+
def initialize(expire_in:)
|
6
|
+
@start = current
|
7
|
+
@expire_in = expire_in
|
8
|
+
end
|
9
|
+
|
10
|
+
def expired?
|
11
|
+
raise Isomorfeus::Puppetmaster::FrozenInTime, 'Time appears to be frozen. Puppetmaster does not work with libraries which freeze time, consider using time travelling instead' if stalled?
|
12
|
+
|
13
|
+
current - @start >= @expire_in
|
14
|
+
end
|
15
|
+
|
16
|
+
def stalled?
|
17
|
+
@start == current
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
if defined?(Process::CLOCK_MONOTONIC)
|
23
|
+
def current; Process.clock_gettime Process::CLOCK_MONOTONIC; end
|
24
|
+
else
|
25
|
+
def current; Time.now.to_f; end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class << self
|
30
|
+
def ports
|
31
|
+
@ports ||= {}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_reader :app, :port, :host
|
36
|
+
|
37
|
+
def initialize(app,
|
38
|
+
port: Isomorfeus::Puppetmaster.server_port,
|
39
|
+
host: Isomorfeus::Puppetmaster.server_host,
|
40
|
+
extra_middleware: [])
|
41
|
+
@app = app
|
42
|
+
@extra_middleware = extra_middleware
|
43
|
+
@server_thread = nil # suppress warnings
|
44
|
+
@host = host
|
45
|
+
@port = port
|
46
|
+
@port ||= Isomorfeus::Puppetmaster::Server.ports[port_key]
|
47
|
+
@port ||= find_available_port(host)
|
48
|
+
@checker = Isomorfeus::Puppetmaster::Server::Checker.new(@host, @port)
|
49
|
+
end
|
50
|
+
|
51
|
+
def reset_error!
|
52
|
+
middleware.clear_error
|
53
|
+
end
|
54
|
+
|
55
|
+
def error
|
56
|
+
middleware.error
|
57
|
+
end
|
58
|
+
|
59
|
+
def using_ssl?
|
60
|
+
@checker.ssl?
|
61
|
+
end
|
62
|
+
|
63
|
+
def scheme
|
64
|
+
using_ssl? ? 'https' : 'http'
|
65
|
+
end
|
66
|
+
|
67
|
+
def responsive?
|
68
|
+
return false if @server_thread&.join(0)
|
69
|
+
|
70
|
+
res = @checker.request { |http| http.get('/__identify__') }
|
71
|
+
|
72
|
+
return res.body == app.object_id.to_s if res.is_a?(Net::HTTPSuccess) || res.is_a?(Net::HTTPRedirection)
|
73
|
+
rescue SystemCallError, Net::ReadTimeout, OpenSSL::SSL::SSLError
|
74
|
+
false
|
75
|
+
end
|
76
|
+
|
77
|
+
def wait_for_pending_requests
|
78
|
+
timer = Isomorfeus::Puppetmaster::Server::Timer.new(expire_in: 60)
|
79
|
+
while pending_requests?
|
80
|
+
raise 'Requests did not finish in 60 seconds' if timer.expired?
|
81
|
+
|
82
|
+
sleep 0.01
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def boot
|
87
|
+
unless responsive?
|
88
|
+
Isomorfeus::Puppetmaster::Server.ports[port_key] = port
|
89
|
+
|
90
|
+
@server_thread = Thread.new do
|
91
|
+
Isomorfeus::Puppetmaster.server.call(middleware, port, host)
|
92
|
+
end
|
93
|
+
|
94
|
+
timer = Isomorfeus::Puppetmaster::Server::Timer.new(expire_in: 60)
|
95
|
+
until responsive?
|
96
|
+
raise 'Rack application timed out during boot' if timer.expired?
|
97
|
+
|
98
|
+
@server_thread.join(0.1)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
self
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def middleware
|
108
|
+
@middleware ||= ::Isomorfeus::Puppetmaster::Server::Middleware.new(app, @extra_middleware)
|
109
|
+
end
|
110
|
+
|
111
|
+
def port_key
|
112
|
+
app.object_id
|
113
|
+
end
|
114
|
+
|
115
|
+
def pending_requests?
|
116
|
+
middleware.pending_requests?
|
117
|
+
end
|
118
|
+
|
119
|
+
def find_available_port(host)
|
120
|
+
server = TCPServer.new(host, 0)
|
121
|
+
server.addr[1]
|
122
|
+
ensure
|
123
|
+
server&.close
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|