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.
data/lib/e2e/minitest.rb CHANGED
@@ -44,4 +44,5 @@ end
44
44
 
45
45
  Minitest.after_run do
46
46
  E2E.session.quit if E2E.instance_variable_get(:@session)
47
+ E2E.stop_server!
47
48
  end
data/lib/e2e/rails.rb CHANGED
@@ -2,25 +2,86 @@
2
2
 
3
3
  module E2E
4
4
  module Rails
5
- # This module allows the test thread and the server thread to share the same
6
- # ActiveRecord connection. This is crucial for running tests in transactions
7
- # which is much faster than using truncation.
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
- @shared_connection || retrieve_connection
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
- @shared_connection = connection
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
- return unless defined?(ActiveRecord::Base)
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
@@ -33,5 +33,6 @@ RSpec.configure do |config|
33
33
 
34
34
  config.after(:suite) do
35
35
  E2E.session.quit if E2E.instance_variable_get(:@session)
36
+ E2E.stop_server!
36
37
  end
37
38
  end
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
- # Use Rackup handler for Rack 3 compatibility
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module E2E
4
- VERSION = "0.6.1"
4
+ VERSION = "0.7.1"
5
5
  end
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.6.1
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.2.0
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.10
288
+ rubygems_version: 4.0.18
259
289
  specification_version: 4
260
290
  summary: Unified E2E testing framework for Ruby.
261
291
  test_files: []