playwright-rails 0.0.1
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/.github/workflows/main.yml +21 -0
- data/.gitignore +8 -0
- data/.rubocop.yml +647 -0
- data/.tool-versions +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +100 -0
- data/LICENSE.txt +25 -0
- data/README.md +1 -0
- data/Rakefile +11 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/playwright-rails +17 -0
- data/lib/playwright-rails/config.rb +45 -0
- data/lib/playwright-rails/env.rb +14 -0
- data/lib/playwright-rails/finds_bin.rb +16 -0
- data/lib/playwright-rails/initializer_hooks.rb +53 -0
- data/lib/playwright-rails/launches_playwright.rb +63 -0
- data/lib/playwright-rails/manages_transactions.rb +79 -0
- data/lib/playwright-rails/open.rb +14 -0
- data/lib/playwright-rails/railtie.rb +12 -0
- data/lib/playwright-rails/rake.rb +13 -0
- data/lib/playwright-rails/resets_state.rb +20 -0
- data/lib/playwright-rails/run.rb +14 -0
- data/lib/playwright-rails/server/checker.rb +42 -0
- data/lib/playwright-rails/server/middleware.rb +67 -0
- data/lib/playwright-rails/server/puma.rb +31 -0
- data/lib/playwright-rails/server/timer.rb +24 -0
- data/lib/playwright-rails/server.rb +121 -0
- data/lib/playwright-rails/starts_rails_server.rb +34 -0
- data/lib/playwright-rails/tracks_resets.rb +26 -0
- data/lib/playwright-rails/version.rb +3 -0
- data/lib/playwright-rails.rb +11 -0
- data/playwright-rails.gemspec +32 -0
- metadata +162 -0
data/Gemfile.lock
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
playwright-rails (0.0.1)
|
5
|
+
puma (>= 6.1.1)
|
6
|
+
railties (>= 7.0.4.2)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
actionpack (7.0.4.2)
|
12
|
+
actionview (= 7.0.4.2)
|
13
|
+
activesupport (= 7.0.4.2)
|
14
|
+
rack (~> 2.0, >= 2.2.0)
|
15
|
+
rack-test (>= 0.6.3)
|
16
|
+
rails-dom-testing (~> 2.0)
|
17
|
+
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
18
|
+
actionview (7.0.4.2)
|
19
|
+
activesupport (= 7.0.4.2)
|
20
|
+
builder (~> 3.1)
|
21
|
+
erubi (~> 1.4)
|
22
|
+
rails-dom-testing (~> 2.0)
|
23
|
+
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
24
|
+
activesupport (7.0.4.2)
|
25
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
26
|
+
i18n (>= 1.6, < 2)
|
27
|
+
minitest (>= 5.1)
|
28
|
+
tzinfo (~> 2.0)
|
29
|
+
ast (2.4.2)
|
30
|
+
builder (3.2.4)
|
31
|
+
concurrent-ruby (1.2.2)
|
32
|
+
crass (1.0.6)
|
33
|
+
erubi (1.12.0)
|
34
|
+
i18n (1.12.0)
|
35
|
+
concurrent-ruby (~> 1.0)
|
36
|
+
loofah (2.19.1)
|
37
|
+
crass (~> 1.0.2)
|
38
|
+
nokogiri (>= 1.5.9)
|
39
|
+
method_source (1.0.0)
|
40
|
+
mini_portile2 (2.8.1)
|
41
|
+
minitest (5.15.0)
|
42
|
+
nio4r (2.5.8)
|
43
|
+
nokogiri (1.14.2)
|
44
|
+
mini_portile2 (~> 2.8.0)
|
45
|
+
racc (~> 1.4)
|
46
|
+
parallel (1.22.1)
|
47
|
+
parser (3.1.2.0)
|
48
|
+
ast (~> 2.4.1)
|
49
|
+
puma (6.1.1)
|
50
|
+
nio4r (~> 2.0)
|
51
|
+
racc (1.6.2)
|
52
|
+
rack (2.2.6.2)
|
53
|
+
rack-test (2.0.2)
|
54
|
+
rack (>= 1.3)
|
55
|
+
rails-dom-testing (2.0.3)
|
56
|
+
activesupport (>= 4.2.0)
|
57
|
+
nokogiri (>= 1.6)
|
58
|
+
rails-html-sanitizer (1.5.0)
|
59
|
+
loofah (~> 2.19, >= 2.19.1)
|
60
|
+
railties (7.0.4.2)
|
61
|
+
actionpack (= 7.0.4.2)
|
62
|
+
activesupport (= 7.0.4.2)
|
63
|
+
method_source
|
64
|
+
rake (>= 12.2)
|
65
|
+
thor (~> 1.0)
|
66
|
+
zeitwerk (~> 2.5)
|
67
|
+
rainbow (3.1.1)
|
68
|
+
rake (13.0.6)
|
69
|
+
regexp_parser (2.4.0)
|
70
|
+
rexml (3.2.5)
|
71
|
+
rubocop (1.29.1)
|
72
|
+
parallel (~> 1.10)
|
73
|
+
parser (>= 3.1.0.0)
|
74
|
+
rainbow (>= 2.2.2, < 4.0)
|
75
|
+
regexp_parser (>= 1.8, < 3.0)
|
76
|
+
rexml (>= 3.2.5, < 4.0)
|
77
|
+
rubocop-ast (>= 1.17.0, < 2.0)
|
78
|
+
ruby-progressbar (~> 1.7)
|
79
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
80
|
+
rubocop-ast (1.18.0)
|
81
|
+
parser (>= 3.1.1.0)
|
82
|
+
ruby-progressbar (1.11.0)
|
83
|
+
thor (1.2.1)
|
84
|
+
tzinfo (2.0.6)
|
85
|
+
concurrent-ruby (~> 1.0)
|
86
|
+
unicode-display_width (2.1.0)
|
87
|
+
zeitwerk (2.6.7)
|
88
|
+
|
89
|
+
PLATFORMS
|
90
|
+
ruby
|
91
|
+
|
92
|
+
DEPENDENCIES
|
93
|
+
bundler
|
94
|
+
minitest (~> 5.0)
|
95
|
+
playwright-rails!
|
96
|
+
rake (~> 13.0)
|
97
|
+
rubocop (< 2)
|
98
|
+
|
99
|
+
BUNDLED WITH
|
100
|
+
2.3.13
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2019-2020 Test Double, LLC
|
4
|
+
|
5
|
+
Portions of the PlaywrightRails::Server component:
|
6
|
+
Copyright (c) 2009-2018 Thomas Walpole, Jonas Nicklas
|
7
|
+
|
8
|
+
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
10
|
+
of this software and associated documentation files (the "Software"), to deal
|
11
|
+
in the Software without restriction, including without limitation the rights
|
12
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
13
|
+
copies of the Software, and to permit persons to whom the Software is
|
14
|
+
furnished to do so, subject to the following conditions:
|
15
|
+
|
16
|
+
The above copyright notice and this permission notice shall be included in
|
17
|
+
all copies or substantial portions of the Software.
|
18
|
+
|
19
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
20
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
21
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
22
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
23
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
24
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
25
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# playwright-rails
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "playwright-rails"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
ENV["RAILS_ENV"] ||= "test"
|
4
|
+
require "pathname"
|
5
|
+
require "playwright-rails"
|
6
|
+
require Pathname.new(PlaywrightRails::Config.new.dir).join("config/environment").to_s
|
7
|
+
|
8
|
+
command = ARGV[0]
|
9
|
+
case command
|
10
|
+
when "open"
|
11
|
+
PlaywrightRails::Open.new.call
|
12
|
+
when "run"
|
13
|
+
passed = PlaywrightRails::Run.new.call
|
14
|
+
exit 1 unless passed
|
15
|
+
else
|
16
|
+
PlaywrightRails::LaunchesPlaywright.new.call(ARGV.join(" "))
|
17
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative "env"
|
2
|
+
|
3
|
+
module PlaywrightRails
|
4
|
+
class Config
|
5
|
+
attr_accessor(
|
6
|
+
:dir,
|
7
|
+
:host,
|
8
|
+
:port,
|
9
|
+
:base_path,
|
10
|
+
:transactional_server,
|
11
|
+
:playwright_cli_opts,
|
12
|
+
)
|
13
|
+
|
14
|
+
def initialize(
|
15
|
+
dir: Env.fetch("PLAYWRIGHT_RAILS_DIR", default: Dir.pwd),
|
16
|
+
host: Env.fetch("PLAYWRIGHT_RAILS_HOST", default: "127.0.0.1"),
|
17
|
+
port: Env.fetch("PLAYWRIGHT_RAILS_PORT"),
|
18
|
+
base_path: Env.fetch("PLAYWRIGHT_RAILS_BASE_PATH", default: "/"),
|
19
|
+
transactional_server: Env.fetch("PLAYWRIGHT_RAILS_TRANSACTIONAL_SERVER", type: :boolean, default: true),
|
20
|
+
playwright_cli_opts: Env.fetch("PLAYWRIGHT_RAILS_PLAYWRIGHT_OPTS", default: "")
|
21
|
+
)
|
22
|
+
@dir = dir
|
23
|
+
@host = host
|
24
|
+
@port = port
|
25
|
+
@base_path = base_path
|
26
|
+
@transactional_server = transactional_server
|
27
|
+
@playwright_cli_opts = playwright_cli_opts
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
<<~DESC
|
32
|
+
|
33
|
+
playwright-rails configuration:
|
34
|
+
============================
|
35
|
+
PLAYWRIGHT_RAILS_DIR.....................#{dir.inspect}
|
36
|
+
PLAYWRIGHT_RAILS_HOST....................#{host.inspect}
|
37
|
+
PLAYWRIGHT_RAILS_PORT....................#{port.inspect}
|
38
|
+
PLAYWRIGHT_RAILS_BASE_PATH...............#{base_path.inspect}
|
39
|
+
PLAYWRIGHT_RAILS_TRANSACTIONAL_SERVER....#{transactional_server.inspect}
|
40
|
+
PLAYWRIGHT_RAILS_PLAYWRIGHT_OPTS............#{playwright_cli_opts.inspect}
|
41
|
+
|
42
|
+
DESC
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module PlaywrightRails
|
2
|
+
module Env
|
3
|
+
def self.fetch(name, type: :string, default: nil)
|
4
|
+
return default unless ENV.key?(name)
|
5
|
+
|
6
|
+
if type == :boolean
|
7
|
+
no_like_flag = ["", "0", "n", "no", "false"].include?(ENV.fetch(name))
|
8
|
+
!no_like_flag
|
9
|
+
else
|
10
|
+
ENV.fetch(name)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "pathname"
|
2
|
+
|
3
|
+
module PlaywrightRails
|
4
|
+
class FindsBin
|
5
|
+
LOCAL_PATH = "node_modules/.bin/playwright"
|
6
|
+
|
7
|
+
def call(dir = Dir.pwd)
|
8
|
+
local_path = Pathname.new(dir).join(LOCAL_PATH)
|
9
|
+
if File.exist?(local_path)
|
10
|
+
local_path
|
11
|
+
else
|
12
|
+
"playwright"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module PlaywrightRails
|
2
|
+
def self.hooks
|
3
|
+
InitializerHooks.instance
|
4
|
+
end
|
5
|
+
|
6
|
+
class InitializerHooks
|
7
|
+
def self.instance
|
8
|
+
@instance ||= new
|
9
|
+
end
|
10
|
+
|
11
|
+
def before_server_start(&blk)
|
12
|
+
register(:before_server_start, blk)
|
13
|
+
end
|
14
|
+
|
15
|
+
def after_server_start(&blk)
|
16
|
+
register(:after_server_start, blk)
|
17
|
+
end
|
18
|
+
|
19
|
+
def after_transaction_start(&blk)
|
20
|
+
register(:after_transaction_start, blk)
|
21
|
+
end
|
22
|
+
|
23
|
+
def after_state_reset(&blk)
|
24
|
+
register(:after_state_reset, blk)
|
25
|
+
end
|
26
|
+
|
27
|
+
def before_server_stop(&blk)
|
28
|
+
register(:before_server_stop, blk)
|
29
|
+
end
|
30
|
+
|
31
|
+
def reset!
|
32
|
+
@hooks = {}
|
33
|
+
end
|
34
|
+
|
35
|
+
def run(name)
|
36
|
+
return unless @hooks[name]
|
37
|
+
@hooks[name].each do |blk|
|
38
|
+
blk.call
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def register(name, blk)
|
45
|
+
@hooks[name] ||= []
|
46
|
+
@hooks[name] << blk
|
47
|
+
end
|
48
|
+
|
49
|
+
def initialize
|
50
|
+
reset!
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require_relative "finds_bin"
|
2
|
+
require_relative "config"
|
3
|
+
require_relative "initializer_hooks"
|
4
|
+
require_relative "manages_transactions"
|
5
|
+
require_relative "starts_rails_server"
|
6
|
+
|
7
|
+
module PlaywrightRails
|
8
|
+
class LaunchesPlaywright
|
9
|
+
def initialize
|
10
|
+
@initializer_hooks = InitializerHooks.instance
|
11
|
+
@manages_transactions = ManagesTransactions.instance
|
12
|
+
@starts_rails_server = StartsRailsServer.new
|
13
|
+
@finds_bin = FindsBin.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(command, config = Config.new)
|
17
|
+
puts config.to_s
|
18
|
+
@initializer_hooks.run(:before_server_start)
|
19
|
+
if config.transactional_server
|
20
|
+
@manages_transactions.begin_transaction
|
21
|
+
end
|
22
|
+
server = @starts_rails_server.call(
|
23
|
+
host: config.host,
|
24
|
+
port: config.port,
|
25
|
+
transactional_server: config.transactional_server,
|
26
|
+
)
|
27
|
+
bin = @finds_bin.call(config.dir)
|
28
|
+
|
29
|
+
set_exit_hooks!(config)
|
30
|
+
|
31
|
+
command = <<~EXEC
|
32
|
+
BASE_URL="http://#{server.host}:#{server.port}#{config.base_path}" "#{bin}" #{command} #{config.playwright_cli_opts}
|
33
|
+
EXEC
|
34
|
+
|
35
|
+
puts "\nLaunching Playwright…\n$ #{command}\n"
|
36
|
+
system command
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def set_exit_hooks!(config)
|
42
|
+
at_exit do
|
43
|
+
run_exit_hooks_if_necessary!(config)
|
44
|
+
end
|
45
|
+
Signal.trap("INT") do
|
46
|
+
puts "Exiting playwright-rails…"
|
47
|
+
exit
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def run_exit_hooks_if_necessary!(config)
|
52
|
+
@at_exit_hooks_have_fired ||= false # avoid warning
|
53
|
+
return if @at_exit_hooks_have_fired
|
54
|
+
|
55
|
+
if config.transactional_server
|
56
|
+
@manages_transactions.rollback_transaction
|
57
|
+
end
|
58
|
+
@initializer_hooks.run(:before_server_stop)
|
59
|
+
|
60
|
+
@at_exit_hooks_have_fired = true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require_relative "initializer_hooks"
|
2
|
+
|
3
|
+
module PlaywrightRails
|
4
|
+
class ManagesTransactions
|
5
|
+
def self.instance
|
6
|
+
@instance ||= new
|
7
|
+
end
|
8
|
+
|
9
|
+
def begin_transaction
|
10
|
+
@connections = gather_connections
|
11
|
+
@connections.each do |connection|
|
12
|
+
connection.begin_transaction joinable: false, _lazy: false
|
13
|
+
connection.pool.lock_thread = true
|
14
|
+
end
|
15
|
+
|
16
|
+
# When connections are established in the future, begin a transaction too
|
17
|
+
@connection_subscriber = ActiveSupport::Notifications.subscribe("!connection.active_record") { |_, _, _, _, payload|
|
18
|
+
if payload.key?(:spec_name) && (spec_name = payload[:spec_name])
|
19
|
+
setup_shared_connection_pool
|
20
|
+
|
21
|
+
begin
|
22
|
+
connection = ActiveRecord::Base.connection_handler.retrieve_connection(spec_name)
|
23
|
+
rescue ActiveRecord::ConnectionNotEstablished
|
24
|
+
connection = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
if connection && !@connections.include?(connection)
|
28
|
+
connection.begin_transaction joinable: false, _lazy: false
|
29
|
+
connection.pool.lock_thread = true
|
30
|
+
@connections << connection
|
31
|
+
end
|
32
|
+
end
|
33
|
+
}
|
34
|
+
|
35
|
+
@initializer_hooks.run(:after_transaction_start)
|
36
|
+
end
|
37
|
+
|
38
|
+
def rollback_transaction
|
39
|
+
return unless @connections.present?
|
40
|
+
|
41
|
+
ActiveSupport::Notifications.unsubscribe(@connection_subscriber) if @connection_subscriber
|
42
|
+
|
43
|
+
@connections.each do |connection|
|
44
|
+
connection.rollback_transaction if connection.transaction_open?
|
45
|
+
connection.pool.lock_thread = false
|
46
|
+
end
|
47
|
+
@connections.clear
|
48
|
+
|
49
|
+
@connections.each(&:clear_active_connections!)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def initialize
|
55
|
+
@initializer_hooks = InitializerHooks.instance
|
56
|
+
end
|
57
|
+
|
58
|
+
def gather_connections
|
59
|
+
setup_shared_connection_pool
|
60
|
+
|
61
|
+
ActiveRecord::Base.connection_handler.connection_pool_list.map(&:connection)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Shares the writing connection pool with connections on
|
65
|
+
# other handlers.
|
66
|
+
#
|
67
|
+
# In an application with a primary and replica the test fixtures
|
68
|
+
# need to share a connection pool so that the reading connection
|
69
|
+
# can see data in the open transaction on the writing connection.
|
70
|
+
def setup_shared_connection_pool
|
71
|
+
return unless ActiveRecord::TestFixtures.respond_to?(:setup_shared_connection_pool)
|
72
|
+
|
73
|
+
@legacy_saved_pool_configs ||= Hash.new { |hash, key| hash[key] = {} }
|
74
|
+
@saved_pool_configs ||= Hash.new { |hash, key| hash[key] = {} }
|
75
|
+
|
76
|
+
ActiveRecord::TestFixtures.instance_method(:setup_shared_connection_pool).bind(self).call
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative "launches_playwright"
|
2
|
+
require_relative "config"
|
3
|
+
|
4
|
+
module PlaywrightRails
|
5
|
+
class Open
|
6
|
+
def initialize
|
7
|
+
@launches_playwright = LaunchesPlaywright.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(config = Config.new)
|
11
|
+
@launches_playwright.call("open", config)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "pathname"
|
2
|
+
CLI = Pathname.new(File.dirname(__FILE__)).join("../../exe/playwright-rails")
|
3
|
+
|
4
|
+
desc "Open interactive Playwright app for developing tests"
|
5
|
+
task :"playwright:open" do
|
6
|
+
trap("SIGINT") {} # avoid traceback
|
7
|
+
system "#{CLI} open"
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "Run Playwright tests headlessly"
|
11
|
+
task :"playwright:run" do
|
12
|
+
abort unless system "#{CLI} run"
|
13
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative "config"
|
2
|
+
require_relative "manages_transactions"
|
3
|
+
require_relative "initializer_hooks"
|
4
|
+
|
5
|
+
module PlaywrightRails
|
6
|
+
class ResetsState
|
7
|
+
def initialize
|
8
|
+
@manages_transactions = ManagesTransactions.instance
|
9
|
+
@initializer_hooks = InitializerHooks.instance
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(transactional_server:)
|
13
|
+
if transactional_server
|
14
|
+
@manages_transactions.rollback_transaction
|
15
|
+
@manages_transactions.begin_transaction
|
16
|
+
end
|
17
|
+
@initializer_hooks.run(:after_state_reset)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative "launches_playwright"
|
2
|
+
require_relative "config"
|
3
|
+
|
4
|
+
module PlaywrightRails
|
5
|
+
class Run
|
6
|
+
def initialize
|
7
|
+
@launches_playwright = LaunchesPlaywright.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(config = Config.new)
|
11
|
+
@launches_playwright.call("test", config)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module PlaywrightRails
|
2
|
+
class Server
|
3
|
+
class Checker
|
4
|
+
TRY_HTTPS_ERRORS = [EOFError, Net::ReadTimeout, Errno::ECONNRESET].freeze
|
5
|
+
|
6
|
+
def initialize(host, port)
|
7
|
+
@host, @port = host, port
|
8
|
+
@ssl = false
|
9
|
+
end
|
10
|
+
|
11
|
+
def request(&block)
|
12
|
+
ssl? ? https_request(&block) : http_request(&block)
|
13
|
+
rescue *TRY_HTTPS_ERRORS
|
14
|
+
res = https_request(&block)
|
15
|
+
@ssl = true
|
16
|
+
res
|
17
|
+
end
|
18
|
+
|
19
|
+
def ssl?
|
20
|
+
@ssl
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def http_request(&block)
|
26
|
+
make_request(read_timeout: 2, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def https_request(&block)
|
30
|
+
make_request(**ssl_options, &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def make_request(**options, &block)
|
34
|
+
Net::HTTP.start(@host, @port, options.merge(max_retries: 0), &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
def ssl_options
|
38
|
+
{use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module PlaywrightRails
|
2
|
+
class Server
|
3
|
+
class Middleware
|
4
|
+
class Counter
|
5
|
+
def initialize
|
6
|
+
@value = []
|
7
|
+
@mutex = Mutex.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def increment(uri)
|
11
|
+
@mutex.synchronize { @value.push(uri) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def decrement(uri)
|
15
|
+
@mutex.synchronize { @value.delete_at(@value.index(uri) || @value.length) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def positive?
|
19
|
+
@mutex.synchronize { @value.length.positive? }
|
20
|
+
end
|
21
|
+
|
22
|
+
def value
|
23
|
+
@mutex.synchronize { @value.dup }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_reader :error
|
28
|
+
|
29
|
+
def initialize(app, server_errors, extra_middleware = [])
|
30
|
+
@app = app
|
31
|
+
@extended_app = extra_middleware.inject(@app) { |ex_app, klass|
|
32
|
+
klass.new(ex_app)
|
33
|
+
}
|
34
|
+
@counter = Counter.new
|
35
|
+
@server_errors = server_errors
|
36
|
+
end
|
37
|
+
|
38
|
+
def pending_requests
|
39
|
+
@counter.value
|
40
|
+
end
|
41
|
+
|
42
|
+
def pending_requests?
|
43
|
+
@counter.positive?
|
44
|
+
end
|
45
|
+
|
46
|
+
def clear_error
|
47
|
+
@error = nil
|
48
|
+
end
|
49
|
+
|
50
|
+
def call(env)
|
51
|
+
if env["PATH_INFO"] == "/__identify__"
|
52
|
+
[200, {}, [@app.object_id.to_s]]
|
53
|
+
else
|
54
|
+
@counter.increment(env["REQUEST_URI"])
|
55
|
+
begin
|
56
|
+
@extended_app.call(env)
|
57
|
+
rescue *@server_errors => e
|
58
|
+
@error ||= e
|
59
|
+
raise e
|
60
|
+
ensure
|
61
|
+
@counter.decrement(env["REQUEST_URI"])
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module PlaywrightRails
|
2
|
+
class Server
|
3
|
+
module Puma
|
4
|
+
def self.create(app, port, host)
|
5
|
+
require "rack/handler/puma"
|
6
|
+
|
7
|
+
# If we just run the Puma Rack handler it installs signal handlers which prevent us from being able to interrupt tests.
|
8
|
+
# Therefore construct and run the Server instance ourselves.
|
9
|
+
# Rack::Handler::Puma.run(app, { Host: host, Port: port, Threads: "0:4", workers: 0, daemon: false }.merge(options))
|
10
|
+
default_options = {Host: host, Port: port, Threads: "0:4", workers: 0, daemon: false}
|
11
|
+
options = default_options # .merge(options)
|
12
|
+
|
13
|
+
conf = Rack::Handler::Puma.config(app, options)
|
14
|
+
conf.clamp
|
15
|
+
logger = (defined?(::Puma::LogWriter) ? ::Puma::LogWriter : ::Puma::Events).stdio
|
16
|
+
|
17
|
+
puma_ver = Gem::Version.new(::Puma::Const::PUMA_VERSION)
|
18
|
+
require_relative "patches/puma_ssl" if (Gem::Version.new("4.0.0")...Gem::Version.new("4.1.0")).cover? puma_ver
|
19
|
+
|
20
|
+
logger.log "Starting Puma..."
|
21
|
+
logger.log "* Version #{::Puma::Const::PUMA_VERSION} , codename: #{::Puma::Const::CODE_NAME}"
|
22
|
+
logger.log "* Min threads: #{conf.options[:min_threads]}, max threads: #{conf.options[:max_threads]}"
|
23
|
+
|
24
|
+
::Puma::Server.new(conf.app, defined?(::Puma::LogWriter) ? nil : logger, conf.options).tap do |s|
|
25
|
+
s.binder.parse conf.options[:binds], s.respond_to?(:log_writer) ? s.log_writer : s.events
|
26
|
+
s.min_threads, s.max_threads = conf.options[:min_threads], conf.options[:max_threads] if s.respond_to?(:min_threads=)
|
27
|
+
end.run.join
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|