e2e 0.6.1 → 0.7.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 +4 -4
- data/.ruby-version +1 -0
- data/Appraisals +3 -0
- data/CHANGELOG.md +23 -0
- data/README.md +2 -0
- data/gemfiles/rails_7.0.gemfile +1 -0
- data/gemfiles/rails_7.0.gemfile.lock +90 -91
- data/gemfiles/rails_7.1.gemfile.lock +110 -100
- data/gemfiles/rails_7.2.gemfile.lock +110 -100
- data/gemfiles/rails_8.0.gemfile.lock +174 -164
- data/gemfiles/rails_8.1.gemfile.lock +176 -166
- data/lib/e2e/drivers/playwright.rb +34 -10
- data/lib/e2e/minitest.rb +1 -0
- data/lib/e2e/rails.rb +71 -10
- data/lib/e2e/rspec.rb +1 -0
- data/lib/e2e/server.rb +28 -3
- data/lib/e2e/version.rb +1 -1
- data/lib/e2e.rb +11 -1
- data/mise.toml +14 -0
- metadata +33 -3
data/lib/e2e/minitest.rb
CHANGED
data/lib/e2e/rails.rb
CHANGED
|
@@ -2,25 +2,86 @@
|
|
|
2
2
|
|
|
3
3
|
module E2E
|
|
4
4
|
module Rails
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
class << self
|
|
6
|
+
attr_accessor :shared_connection
|
|
7
|
+
attr_reader :shared_connection_enabled
|
|
8
|
+
|
|
9
|
+
def shared_connection_enabled?
|
|
10
|
+
@shared_connection_enabled
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def enable_shared_connection!
|
|
14
|
+
return unless defined?(ActiveRecord::Base)
|
|
15
|
+
return if @shared_connection_enabled
|
|
16
|
+
|
|
17
|
+
ActiveRecord::Base.singleton_class.prepend(ActiveRecordSharedConnection)
|
|
18
|
+
@shared_connection_enabled = true
|
|
19
|
+
# #connection (unlike #lease_connection/#with_connection, added in
|
|
20
|
+
# Rails 7.2) exists on every supported Rails version, so it's the only
|
|
21
|
+
# safe way to bootstrap the very first shared connection.
|
|
22
|
+
self.shared_connection = ActiveRecord::Base.connection
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Yields while the example thread is not holding a sticky AR lease.
|
|
26
|
+
# Needed when the pool has a single connection and the server thread
|
|
27
|
+
# must check it out during a blocking Playwright navigation/action.
|
|
28
|
+
def with_released_connection
|
|
29
|
+
return yield unless shared_connection_enabled?
|
|
30
|
+
return yield unless defined?(ActiveRecord::Base)
|
|
31
|
+
|
|
32
|
+
pool = ActiveRecord::Base.connection_pool
|
|
33
|
+
pool.release_connection if pool.active_connection?
|
|
34
|
+
yield
|
|
35
|
+
ensure
|
|
36
|
+
if shared_connection_enabled? && defined?(ActiveRecord::Base)
|
|
37
|
+
# Keep the shared handle pointing at a live leased connection for
|
|
38
|
+
# post-navigation assertions in the example thread.
|
|
39
|
+
self.shared_connection = ActiveRecord::Base.connection
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Shares one ActiveRecord connection between the example thread and the
|
|
45
|
+
# in-process server thread so transactional fixtures remain visible.
|
|
46
|
+
#
|
|
47
|
+
# Rails 7.2+/8 prefer +lease_connection+ / +with_connection+ over
|
|
48
|
+
# +connection+. Overriding only +connection+ (pre-0.7.1) left those
|
|
49
|
+
# APIs on the pool's thread-local lease and caused intermittent
|
|
50
|
+
# deadlocks: the example thread blocked in Playwright while holding
|
|
51
|
+
# the only connection, and the server sat idle in an open transaction.
|
|
8
52
|
module ActiveRecordSharedConnection
|
|
9
53
|
def connection
|
|
10
|
-
|
|
54
|
+
E2E::Rails.shared_connection || super
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# lease_connection/with_connection don't exist before Rails 7.2, so
|
|
58
|
+
# `super` isn't always callable -- fall back to the always-available
|
|
59
|
+
# #connection instead of blowing up with a NoMethodError.
|
|
60
|
+
def lease_connection
|
|
61
|
+
E2E::Rails.shared_connection || (defined?(super) ? super : connection)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def with_connection(prevent_permanent_checkout: false)
|
|
65
|
+
if (conn = E2E::Rails.shared_connection)
|
|
66
|
+
yield conn
|
|
67
|
+
elsif defined?(super)
|
|
68
|
+
super
|
|
69
|
+
else
|
|
70
|
+
yield connection
|
|
71
|
+
end
|
|
11
72
|
end
|
|
12
73
|
|
|
13
74
|
def shared_connection=(connection)
|
|
14
|
-
|
|
75
|
+
E2E::Rails.shared_connection = connection
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def shared_connection
|
|
79
|
+
E2E::Rails.shared_connection
|
|
15
80
|
end
|
|
16
81
|
end
|
|
17
82
|
end
|
|
18
83
|
end
|
|
19
84
|
|
|
20
|
-
# We only want to apply this when Rails is present and we want to enable it.
|
|
21
85
|
def E2E.enable_shared_connection!
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
ActiveRecord::Base.extend(E2E::Rails::ActiveRecordSharedConnection)
|
|
25
|
-
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
|
|
86
|
+
E2E::Rails.enable_shared_connection!
|
|
26
87
|
end
|
data/lib/e2e/rspec.rb
CHANGED
data/lib/e2e/server.rb
CHANGED
|
@@ -17,24 +17,44 @@ module E2E
|
|
|
17
17
|
|
|
18
18
|
def start
|
|
19
19
|
@thread = Thread.new do
|
|
20
|
-
|
|
21
|
-
Rackup::Handler::WEBrick.run(
|
|
20
|
+
webrick_handler.run(
|
|
22
21
|
@app,
|
|
23
22
|
Host: @host,
|
|
24
23
|
Port: @port,
|
|
25
24
|
AccessLog: [],
|
|
26
25
|
Logger: WEBrick::Log.new(nil, 0) # Silence logs
|
|
27
|
-
)
|
|
26
|
+
) do |server|
|
|
27
|
+
@webrick = server
|
|
28
|
+
end
|
|
28
29
|
end
|
|
29
30
|
wait_for_boot
|
|
30
31
|
end
|
|
31
32
|
|
|
33
|
+
def stop
|
|
34
|
+
@webrick&.shutdown
|
|
35
|
+
@thread&.join(5)
|
|
36
|
+
@thread = nil
|
|
37
|
+
@webrick = nil
|
|
38
|
+
end
|
|
39
|
+
|
|
32
40
|
def base_url
|
|
33
41
|
"http://#{@host}:#{@port}"
|
|
34
42
|
end
|
|
35
43
|
|
|
36
44
|
private
|
|
37
45
|
|
|
46
|
+
# rackup 2.x (the version paired with Rack 3) exposes Rackup::Handler.
|
|
47
|
+
# Older stacks that pin Rack 2.x (e.g. Rails 7.0/7.1 via this gem's own
|
|
48
|
+
# Appraisal matrix) resolve `rackup` down to its 1.x line, which has no
|
|
49
|
+
# Handler module at all -- there, the handler lives on Rack::Handler.
|
|
50
|
+
def webrick_handler
|
|
51
|
+
if defined?(Rackup::Handler)
|
|
52
|
+
Rackup::Handler.get(:webrick)
|
|
53
|
+
else
|
|
54
|
+
Rack::Handler.get(:webrick)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
38
58
|
def find_available_port
|
|
39
59
|
server = TCPServer.new("127.0.0.1", 0)
|
|
40
60
|
port = server.addr[1]
|
|
@@ -45,6 +65,11 @@ module E2E
|
|
|
45
65
|
def wait_for_boot
|
|
46
66
|
start_time = Time.now
|
|
47
67
|
loop do
|
|
68
|
+
if @thread && !@thread.alive?
|
|
69
|
+
@thread.join # re-raises whatever exception killed the server thread
|
|
70
|
+
raise "Server thread exited before boot completed"
|
|
71
|
+
end
|
|
72
|
+
|
|
48
73
|
socket = TCPSocket.new("127.0.0.1", @port)
|
|
49
74
|
socket.close
|
|
50
75
|
break
|
data/lib/e2e/version.rb
CHANGED
data/lib/e2e.rb
CHANGED
|
@@ -37,6 +37,11 @@ module E2E
|
|
|
37
37
|
srv
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
|
+
|
|
41
|
+
def stop_server!
|
|
42
|
+
@server&.stop
|
|
43
|
+
@server = nil
|
|
44
|
+
end
|
|
40
45
|
end
|
|
41
46
|
|
|
42
47
|
# Retry a block until it returns truthy or timeout is reached
|
|
@@ -61,7 +66,8 @@ module E2E
|
|
|
61
66
|
alert: "[role='alert'], [data-flash-type='alert'], [data-flash='alert'], .flash.alert, .flash-error, .alert"
|
|
62
67
|
}.freeze
|
|
63
68
|
|
|
64
|
-
attr_accessor :driver, :headless, :app, :browser_type, :wait_timeout, :flash_selectors
|
|
69
|
+
attr_accessor :driver, :headless, :app, :browser_type, :wait_timeout, :flash_selectors,
|
|
70
|
+
:navigation_timeout, :navigation_wait_until
|
|
65
71
|
|
|
66
72
|
def initialize
|
|
67
73
|
@driver = :playwright
|
|
@@ -69,6 +75,10 @@ module E2E
|
|
|
69
75
|
@headless = ENV.fetch("HEADLESS", "true") == "true"
|
|
70
76
|
@app = nil
|
|
71
77
|
@wait_timeout = 5
|
|
78
|
+
# Full "load" waits for every subframe (YouTube/Vimeo/etc.) and can hang
|
|
79
|
+
# navigations indefinitely when those resources never settle.
|
|
80
|
+
@navigation_wait_until = "domcontentloaded"
|
|
81
|
+
@navigation_timeout = 30
|
|
72
82
|
@flash_selectors = DEFAULT_FLASH_SELECTORS.dup
|
|
73
83
|
end
|
|
74
84
|
end
|
data/mise.toml
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
[tools]
|
|
2
|
+
ruby = "4.0.6"
|
|
3
|
+
|
|
4
|
+
[tasks.test]
|
|
5
|
+
description = "Run RSpec and Minitest suites"
|
|
6
|
+
run = "bundle exec rake spec test"
|
|
7
|
+
|
|
8
|
+
[tasks.lint]
|
|
9
|
+
description = "Run RuboCop"
|
|
10
|
+
run = "bundle exec rubocop"
|
|
11
|
+
|
|
12
|
+
[tasks.release]
|
|
13
|
+
description = "Build and publish the gem (rake release)"
|
|
14
|
+
run = "bundle exec rake release"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: e2e
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alexey Poimtsev
|
|
@@ -65,6 +65,20 @@ dependencies:
|
|
|
65
65
|
- - ">="
|
|
66
66
|
- !ruby/object:Gem::Version
|
|
67
67
|
version: '0'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: activerecord
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0'
|
|
75
|
+
type: :development
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0'
|
|
68
82
|
- !ruby/object:Gem::Dependency
|
|
69
83
|
name: appraisal
|
|
70
84
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -177,6 +191,20 @@ dependencies:
|
|
|
177
191
|
- - ">="
|
|
178
192
|
- !ruby/object:Gem::Version
|
|
179
193
|
version: '0'
|
|
194
|
+
- !ruby/object:Gem::Dependency
|
|
195
|
+
name: sqlite3
|
|
196
|
+
requirement: !ruby/object:Gem::Requirement
|
|
197
|
+
requirements:
|
|
198
|
+
- - ">="
|
|
199
|
+
- !ruby/object:Gem::Version
|
|
200
|
+
version: '0'
|
|
201
|
+
type: :development
|
|
202
|
+
prerelease: false
|
|
203
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
204
|
+
requirements:
|
|
205
|
+
- - ">="
|
|
206
|
+
- !ruby/object:Gem::Version
|
|
207
|
+
version: '0'
|
|
180
208
|
- !ruby/object:Gem::Dependency
|
|
181
209
|
name: standard
|
|
182
210
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -199,6 +227,7 @@ executables: []
|
|
|
199
227
|
extensions: []
|
|
200
228
|
extra_rdoc_files: []
|
|
201
229
|
files:
|
|
230
|
+
- ".ruby-version"
|
|
202
231
|
- Appraisals
|
|
203
232
|
- CHANGELOG.md
|
|
204
233
|
- LICENSE.txt
|
|
@@ -233,6 +262,7 @@ files:
|
|
|
233
262
|
- lib/generators/e2e/templates/minitest_test.rb.erb
|
|
234
263
|
- lib/generators/e2e/templates/rspec_test.rb.erb
|
|
235
264
|
- lib/generators/e2e/test_generator.rb
|
|
265
|
+
- mise.toml
|
|
236
266
|
- sig/e2e.rbs
|
|
237
267
|
homepage: https://github.com/alec-c4/e2e
|
|
238
268
|
licenses:
|
|
@@ -248,14 +278,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
248
278
|
requirements:
|
|
249
279
|
- - ">="
|
|
250
280
|
- !ruby/object:Gem::Version
|
|
251
|
-
version: 3.
|
|
281
|
+
version: 3.3.0
|
|
252
282
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
253
283
|
requirements:
|
|
254
284
|
- - ">="
|
|
255
285
|
- !ruby/object:Gem::Version
|
|
256
286
|
version: '0'
|
|
257
287
|
requirements: []
|
|
258
|
-
rubygems_version: 4.0.
|
|
288
|
+
rubygems_version: 4.0.18
|
|
259
289
|
specification_version: 4
|
|
260
290
|
summary: Unified E2E testing framework for Ruby.
|
|
261
291
|
test_files: []
|