cypress-rails 0.8.0 → 0.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b714799f9b2c7cb3d97c1ae15730844d98d530eaaf2ae127aeff8604b4a1e53d
4
- data.tar.gz: '094933f5801cc70665318327dfc1b91a4982d4372aee7920a8ad4ab6af9c1b38'
3
+ metadata.gz: c08ef4f9087d66f0f04df9831568414e757aae3fb83baf6bfd85c0d7a3509312
4
+ data.tar.gz: aa4baeebd6d8035ca9b9fc6ba91b0c487e9cf3a385a25ee9da92c96e2fd4ce2c
5
5
  SHA512:
6
- metadata.gz: 3b92614020eb57eba1968e60f1aa6f938d9c3fffd7c19eb254dfaa9e4f1bc352535362e54a4823820376ff22d3a59eb204ca399729275aeb5ad2138d7a745d8c
7
- data.tar.gz: a0efc7383d3f055d07717ff2dabc46c212abdee68e7f38890fb3a1968c1277bbc5c0c0387a6353d20f99b8a4a2721f56a39226feb10a02d0e1703e75c889cc11
6
+ metadata.gz: 15cf818dd04eb1eb89853d2a14839dd54d25ed4c39b21a705fcae507c7cecb12813477913fab43e486a7f80f0bcc4df8cb18cafa0252d3a38c33608b8441c6b7
7
+ data.tar.gz: 2fa87db917ccc275d14c8dc28f67a55c13a375e13d6a9f25887fc9ad87989d18bb515b2eabab19ef58dcee6da9b098cf1ccabf97ee6a057649468d8f4f740245
@@ -7,14 +7,17 @@ jobs:
7
7
  runs-on: ubuntu-latest
8
8
 
9
9
  strategy:
10
+ fail-fast: false
10
11
  matrix:
11
12
  ruby-version: ['3.0', '3.1', '3.2', '3.3', '3.4']
12
13
 
13
14
  steps:
14
- - uses: actions/checkout@v4
15
+ - uses: actions/checkout@v7
15
16
  - uses: ruby/setup-ruby@v1
16
17
  with:
17
18
  ruby-version: ${{ matrix.ruby-version }}
19
+ rubygems: latest
20
+ bundler: latest
18
21
  bundler-cache: true
19
22
 
20
23
  - name: Run root unit tests and lint
@@ -23,26 +26,60 @@ jobs:
23
26
  bundle exec rake
24
27
 
25
28
  example-app-tests:
29
+ name: example-app-tests (${{ matrix.ruby-version }}, ${{ matrix.rails-version }}, transactional ${{ matrix.transactional-server }})
26
30
  runs-on: ubuntu-latest
27
31
 
28
32
  strategy:
29
33
  fail-fast: false
30
34
  matrix:
31
35
  ruby-version: ['3.0', '3.1', '3.2', '3.3', '3.4']
32
- rails-version: ['7.1', '7.2', '8.0']
36
+ rails-version: ['7.1', '7.2', '8.0', '8.1']
37
+ transactional-server: ['true']
33
38
  exclude:
34
39
  - ruby-version: '3.0'
35
40
  rails-version: '7.2'
36
41
  - ruby-version: '3.0'
37
42
  rails-version: '8.0'
43
+ - ruby-version: '3.0'
44
+ rails-version: '8.1'
45
+ - ruby-version: '3.1'
46
+ rails-version: '8.0'
38
47
  - ruby-version: '3.1'
48
+ rails-version: '8.1'
49
+ include:
50
+ - ruby-version: '3.4'
51
+ rails-version: '7.1'
52
+ transactional-server: 'false'
53
+ - ruby-version: '3.4'
54
+ rails-version: '7.2'
55
+ transactional-server: 'false'
56
+ - ruby-version: '3.4'
39
57
  rails-version: '8.0'
58
+ transactional-server: 'false'
59
+
60
+ services:
61
+ postgres:
62
+ image: postgres:18
63
+ env:
64
+ POSTGRES_PASSWORD: postgres
65
+ ports:
66
+ - 5432:5432
67
+ options: >-
68
+ --health-cmd pg_isready
69
+ --health-interval 10s
70
+ --health-timeout 5s
71
+ --health-retries 5
40
72
 
41
73
  env:
42
74
  BUNDLE_GEMFILE: ${{ github.workspace }}/example/gemfiles/rails_${{ matrix.rails-version }}.gemfile
75
+ CYPRESS_RAILS_TRANSACTIONAL_SERVER: ${{ matrix.transactional-server }}
76
+ PGHOST: localhost
77
+ PGUSER: postgres
78
+ PGPASSWORD: postgres
43
79
 
44
80
  steps:
45
- - uses: actions/checkout@v4
81
+ - uses: actions/checkout@v7
82
+ - uses: actions/setup-node@v7
46
83
  - uses: ruby/setup-ruby@v1
47
84
  with:
48
85
  ruby-version: ${{ matrix.ruby-version }}
data/CHANGELOG.md CHANGED
@@ -1,7 +1,26 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 0.9.0
4
+
5
+ * **[Breaking]** Require Rails 7.1 or newer
6
+ * **[Breaking]** (relative to 0.8.0) Rename `after_reset_requested` back to
7
+ `after_state_reset`, and restore the transactional server as the default
8
+ behavior
9
+ * Bring back the transactional server (and `CYPRESS_RAILS_TRANSACTIONAL_SERVER`),
10
+ which 0.8.0 had removed. It didn't work reliably to have apps reset their own
11
+ state under cypress-rails' multi-threaded Puma server
12
+ * `/cypress_rails_reset_state` now resets before responding (returning `200`
13
+ instead of `202`), rather than deferring the reset to the next request
14
+
15
+ See [docs/changes-in-0.9.0.md](docs/changes-in-0.9.0.md) for a full comparison
16
+ with both 0.7.1 and 0.8.0.
17
+
3
18
  ## 0.8.0
4
19
 
20
+ (Avoid this version due to issues with resetting data during threaded requests.
21
+ 0.9.0 is almost entirely compatible with 0.7.1 while still bringing Rails 7.2+
22
+ compatibility, so the breaking changes in this version are for nothing.)
23
+
5
24
  * **[Breaking]** Remove `CYPRESS_RAILS_TRANSACTIONAL_SERVER`. cypress-rails no
6
25
  longer wraps the server in a transaction or resets it between tests -
7
26
  automatic Rails-version-specific transaction management proved unsustainable
data/README.md CHANGED
@@ -93,39 +93,35 @@ is a JavaScript-based tool and can't easily manipulate your Rails app directly,
93
93
  cypress-rails provides a number of hooks that you can use to manage your test
94
94
  data.
95
95
 
96
- cypress-rails itself has no opinion on *how* you reset your database between
97
- tests. Instead, cypress-rails gives you a hook (`after_reset_requested`) to run
98
- whatever database-cleaning approach fits your app, such as the
99
- [database_cleaner](https://github.com/DatabaseCleaner/database_cleaner) gem.
96
+ By default, cypress-rails runs your app inside a database transaction and rolls
97
+ it back between tests, much like a Rails system test. Every thread serving your
98
+ app shares that one transaction, so whatever your tests create is undone on the
99
+ next reset.
100
100
 
101
101
  Here's what a `config/initializers/cypress_rails.rb` initializer might look
102
- like, using `database_cleaner-active_record`'s transaction strategy:
102
+ like:
103
103
 
104
104
  ```ruby
105
105
  return unless Rails.env.test?
106
106
 
107
- require "database_cleaner/active_record"
108
- DatabaseCleaner.strategy = :transaction
109
-
110
107
  CypressRails.hooks.before_server_start do
111
- # Called once, before the server is started
112
- DatabaseCleaner.start
108
+ # Called once, before either the transaction or the server is started
109
+ end
110
+
111
+ CypressRails.hooks.after_transaction_start do
112
+ # Called after the transaction is started (at launch and after each reset)
113
113
  end
114
114
 
115
115
  CypressRails.hooks.after_server_start do
116
116
  # Called once, after the server has booted
117
117
  end
118
118
 
119
- CypressRails.hooks.after_reset_requested do
120
- # Triggered after `/cypress_rails_reset_state` is called - this is your
121
- # chance to actually reset the database
122
- DatabaseCleaner.clean
123
- DatabaseCleaner.start
119
+ CypressRails.hooks.after_state_reset do
120
+ # Triggered after `/cypress_rails_reset_state` is called
124
121
  end
125
122
 
126
123
  CypressRails.hooks.before_server_stop do
127
124
  # Called once, at_exit
128
- DatabaseCleaner.clean
129
125
  end
130
126
  ```
131
127
 
@@ -135,9 +131,17 @@ initializer](/example/config/initializers/cypress_rails_initializer.rb)
135
131
  in this repo.)
136
132
 
137
133
  The gem also provides a special route on the test server:
138
- `/cypress_rails_reset_state`. Each time it's called, cypress-rails will
139
- trigger any `after_reset_requested` hooks you've configured at the beginning
140
- of the next request received by the Rails app.
134
+ `/cypress_rails_reset_state`. Each time it's called, cypress-rails does two
135
+ things before responding:
136
+
137
+ * If `CYPRESS_RAILS_TRANSACTIONAL_SERVER` is enabled, roll back the transaction
138
+ and start a new one, resetting the database to how it was when the test run
139
+ started, then trigger any `after_transaction_start` hooks
140
+ * Trigger any `after_state_reset` hooks you've configured (regardless of the
141
+ transactional server setting)
142
+
143
+ If a hook raises an error, the request fails with a 500 status and the error
144
+ message, so the `cy.request` that triggered the reset fails too.
141
145
 
142
146
  This way, you can easily instruct the server to reset its test state from your
143
147
  Cypress tests like so:
@@ -151,6 +155,39 @@ beforeEach(() => {
151
155
  (Remember, in Cypress, `before` is a before-all hook and `beforeEach` is run
152
156
  between each test case!)
153
157
 
158
+ ### Turning off the transactional server
159
+
160
+ The transactional server funnels all of your app's database queries through a
161
+ single connection, one at a time, just like a Rails system test. If your tests
162
+ need your app to access the database concurrently, or your app does work that
163
+ can't happen inside a transaction, set `CYPRESS_RAILS_TRANSACTIONAL_SERVER=false`
164
+ and reset your data yourself in an `after_state_reset` hook. For example, with
165
+ [database_cleaner](https://github.com/DatabaseCleaner/database_cleaner) and
166
+ Rails fixtures:
167
+
168
+ ```ruby
169
+ CypressRails.hooks.after_state_reset do
170
+ DatabaseCleaner[:active_record].clean_with(:truncation)
171
+ ActiveRecord::FixtureSet.reset_cache
172
+ ActiveRecord::FixtureSet.create_fixtures(Rails.root.join("test/fixtures"), ["users", "posts"])
173
+ end
174
+ ```
175
+
176
+ A few things to watch out for:
177
+
178
+ * Don't use database_cleaner's `:transaction` strategy. It only opens a
179
+ transaction on one of the server's database connections, so requests served
180
+ on other connections save their changes for real, and those changes survive
181
+ the reset. (On SQLite, the open transaction also makes other connections'
182
+ writes fail with "database is locked" errors.)
183
+ * Don't set `DatabaseCleaner.strategy = ...` at the top of an initializer.
184
+ Before ActiveRecord has loaded, that assignment is silently ignored and
185
+ database_cleaner's default `:transaction` strategy is used instead.
186
+ * Truncation removes everything, including data loaded in
187
+ `before_server_start`, so rebuild whatever your tests need in the hook. Call
188
+ `ActiveRecord::FixtureSet.reset_cache` before reloading fixtures, or they'll
189
+ be skipped as already loaded.
190
+
154
191
  ## Configuration
155
192
 
156
193
  ### Environment variables
@@ -171,6 +208,12 @@ preferred environment variables project-wide using a tool like
171
208
  requests to the app (e.g. via `cy.visit()`). If you've customized your
172
209
  `baseUrl` setting (e.g. in `cypress.config.js`), you'll need to duplicate it with
173
210
  this environment variable
211
+ * **CYPRESS_RAILS_TRANSACTIONAL_SERVER** (default: `true`) when true, starts a
212
+ transaction before launching the server and rolls it back on every reset and
213
+ on exit, so anything done during `cypress open` or `cypress run` is undone
214
+ (similar to running a Rails system test). While it's enabled, all of the
215
+ server's database access shares one connection. See [Turning off the
216
+ transactional server](#turning-off-the-transactional-server)
174
217
  * **CYPRESS_RAILS_CYPRESS_OPTS** (default: _none_) any options you want to
175
218
  forward to the Cypress CLI when running its `open` or `run` commands.
176
219
 
@@ -196,32 +239,40 @@ $ CYPRESS_RAILS_CYPRESS_OPTS="--browser chromium" bin/rake cypress:run
196
239
  ### before_server_start
197
240
 
198
241
  Pass a block to `CypressRails.hooks.before_server_start` to register a hook that
199
- will execute before the server has been started. If you use Rails fixtures, it
200
- may make sense to load them here, so they don't need to be re-inserted for each
201
- request. This is also a good place to start whatever database-cleaning strategy
202
- you're using (e.g. `DatabaseCleaner.start`).
242
+ will execute before the server or any transaction has been started. If you use
243
+ Rails fixtures, it may make sense to load them here, so they persist across
244
+ resets instead of being re-inserted each time.
203
245
 
204
246
  ### after_server_start
205
247
 
206
248
  Pass a block to `CypressRails.hooks.after_server_start` to register a hook that
207
- will execute after the server has booted.
249
+ will execute after the server has booted (inside the transaction, if
250
+ `CYPRESS_RAILS_TRANSACTIONAL_SERVER` is enabled).
251
+
252
+ ### after_transaction_start
253
+
254
+ If there's any custom behavior or state management you want to do inside the
255
+ transaction (so that it's also rolled back each time a reset is triggered),
256
+ pass a block to `CypressRails.hooks.after_transaction_start`. It runs when the
257
+ server launches and after every reset, and only when
258
+ `CYPRESS_RAILS_TRANSACTIONAL_SERVER` is enabled.
208
259
 
209
- ### after_reset_requested
260
+ ### after_state_reset
210
261
 
211
262
  Every time the test server receives an HTTP request at
212
- `/cypress_rails_reset_state`, the `after_reset_requested` hook will be
213
- triggered at the start of the next request. This is where you should actually
214
- reset your database (e.g. `DatabaseCleaner.clean` followed by
215
- `DatabaseCleaner.start`) - cypress-rails does not reset any state on its own.
216
- To set up the hook, pass a block to `CypressRails.hooks.after_reset_requested`.
263
+ `/cypress_rails_reset_state`, the transaction will be rolled back and restarted
264
+ (if `CYPRESS_RAILS_TRANSACTIONAL_SERVER` is enabled) and then the
265
+ `after_state_reset` hook will be triggered, all before the request responds. To
266
+ set up the hook, pass a block to `CypressRails.hooks.after_state_reset`.
217
267
 
218
268
  ### before_server_stop
219
269
 
220
270
  In case you've made any permanent changes to your test database that could
221
271
  pollute other test suites or scripts, you can use the `before_server_stop` to
222
272
  (assuming everything exits gracefully) clean things up and restore the state
223
- of your test database. To set up the hook, pass a block to
224
- `CypressRails.hooks.before_server_stop`.
273
+ of your test database. If `CYPRESS_RAILS_TRANSACTIONAL_SERVER` is enabled, this
274
+ runs after the transaction has been rolled back. To set up the hook, pass a
275
+ block to `CypressRails.hooks.before_server_stop`.
225
276
 
226
277
  ## Configuring Rails
227
278
 
@@ -16,17 +16,19 @@ Gem::Specification.new do |spec|
16
16
  # Specify which files should be added to the gem when it is released.
17
17
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
18
18
  spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
19
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|example)/}) }
19
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|example|docs)/}) }
20
20
  end
21
21
  spec.bindir = "exe"
22
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
23
  spec.require_paths = ["lib"]
24
24
 
25
- spec.add_dependency "railties", ">= 5.2.0"
25
+ spec.add_dependency "railties", ">= 7.1"
26
26
  spec.add_dependency "puma", ">= 3.8.0"
27
27
 
28
28
  spec.add_development_dependency "bundler"
29
29
  spec.add_development_dependency "rake", "~> 13.0"
30
30
  spec.add_development_dependency "minitest", "~> 5.0"
31
31
  spec.add_development_dependency "standard", ">= 0.2.0"
32
+ spec.add_development_dependency "activerecord"
33
+ spec.add_development_dependency "sqlite3"
32
34
  end
@@ -2,7 +2,7 @@ require_relative "env"
2
2
 
3
3
  module CypressRails
4
4
  class Config
5
- attr_accessor :rails_dir, :cypress_dir, :host, :port, :base_path, :cypress_cli_opts
5
+ attr_accessor :rails_dir, :cypress_dir, :host, :port, :base_path, :transactional_server, :cypress_cli_opts
6
6
 
7
7
  def initialize(
8
8
  rails_dir: Env.fetch("CYPRESS_RAILS_DIR", default: Dir.pwd),
@@ -10,6 +10,7 @@ module CypressRails
10
10
  host: Env.fetch("CYPRESS_RAILS_HOST", default: "127.0.0.1"),
11
11
  port: Env.fetch("CYPRESS_RAILS_PORT"),
12
12
  base_path: Env.fetch("CYPRESS_RAILS_BASE_PATH", default: "/"),
13
+ transactional_server: Env.fetch("CYPRESS_RAILS_TRANSACTIONAL_SERVER", type: :boolean, default: true),
13
14
  cypress_cli_opts: Env.fetch("CYPRESS_RAILS_CYPRESS_OPTS", default: "")
14
15
  )
15
16
  @rails_dir = rails_dir
@@ -17,6 +18,7 @@ module CypressRails
17
18
  @host = host
18
19
  @port = port
19
20
  @base_path = base_path
21
+ @transactional_server = transactional_server
20
22
  @cypress_cli_opts = cypress_cli_opts
21
23
  end
22
24
 
@@ -30,6 +32,7 @@ module CypressRails
30
32
  CYPRESS_RAILS_HOST....................#{host.inspect}
31
33
  CYPRESS_RAILS_PORT....................#{port.inspect}
32
34
  CYPRESS_RAILS_BASE_PATH...............#{base_path.inspect}
35
+ CYPRESS_RAILS_TRANSACTIONAL_SERVER....#{transactional_server.inspect}
33
36
  CYPRESS_RAILS_CYPRESS_OPTS............#{cypress_cli_opts.inspect}
34
37
 
35
38
  DESC
@@ -16,8 +16,12 @@ module CypressRails
16
16
  register(:after_server_start, blk)
17
17
  end
18
18
 
19
- def after_reset_requested(&blk)
20
- register(:after_reset_requested, blk)
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)
21
25
  end
22
26
 
23
27
  def before_server_stop(&blk)
@@ -1,6 +1,7 @@
1
1
  require_relative "finds_bin"
2
2
  require_relative "config"
3
3
  require_relative "initializer_hooks"
4
+ require_relative "manages_transactions"
4
5
  require_relative "starts_rails_server"
5
6
 
6
7
  module CypressRails
@@ -14,9 +15,14 @@ module CypressRails
14
15
  def call(command, config)
15
16
  puts config
16
17
  @initializer_hooks.run(:before_server_start)
18
+ if config.transactional_server
19
+ ManagesTransactions.instance.begin_transaction
20
+ @initializer_hooks.run(:after_transaction_start)
21
+ end
17
22
  server = @starts_rails_server.call(
18
23
  host: config.host,
19
- port: config.port
24
+ port: config.port,
25
+ transactional_server: config.transactional_server
20
26
  )
21
27
  bin = @finds_bin.call(config.cypress_dir)
22
28
 
@@ -46,6 +52,13 @@ module CypressRails
46
52
  @at_exit_hooks_have_fired ||= false # avoid warning
47
53
  return if @at_exit_hooks_have_fired
48
54
 
55
+ if config.transactional_server
56
+ begin
57
+ ManagesTransactions.instance.rollback_transaction
58
+ rescue => e
59
+ warn e.full_message
60
+ end
61
+ end
49
62
  @initializer_hooks.run(:before_server_stop)
50
63
 
51
64
  @at_exit_hooks_have_fired = true
@@ -0,0 +1,76 @@
1
+ module CypressRails
2
+ class ManagesTransactions
3
+ def self.instance
4
+ @instance ||= new
5
+ end
6
+
7
+ module MinitestLifecycle
8
+ def before_setup
9
+ end
10
+
11
+ def after_teardown
12
+ end
13
+ end
14
+
15
+ def begin_transaction
16
+ return unless defined?(ActiveRecord::TestFixtures)
17
+
18
+ # A connection this thread already holds wouldn't be the pinned one
19
+ release_connections_held_by_this_thread
20
+ on_owner_thread { fixtures.before_setup }
21
+ end
22
+
23
+ def rollback_transaction
24
+ return unless defined?(ActiveRecord::TestFixtures)
25
+
26
+ begin
27
+ on_owner_thread { fixtures.after_teardown }
28
+ ensure
29
+ release_connections_held_by_this_thread
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def initialize
36
+ @jobs = Queue.new
37
+ # Rails 7.1 keys a pinned connection to the thread that pinned it, and a
38
+ # Puma thread's end-of-request cleanup would check it back in, so a
39
+ # dedicated thread that never serves requests owns the transaction.
40
+ @owner = Thread.new do
41
+ loop do
42
+ job, result = @jobs.pop
43
+ begin
44
+ result << [:ok, job.call]
45
+ rescue Exception => e # standard:disable Lint/RescueException
46
+ result << [:error, e]
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ def on_owner_thread(&job)
53
+ result = Queue.new
54
+ @jobs << [job, result]
55
+ status, value = result.pop
56
+ raise value if status == :error
57
+ value
58
+ end
59
+
60
+ def release_connections_held_by_this_thread
61
+ ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
62
+ end
63
+
64
+ def fixtures
65
+ @fixtures ||= Class.new {
66
+ # Must be included before TestFixtures, or its hooks never run
67
+ include MinitestLifecycle
68
+ include ActiveRecord::TestFixtures
69
+
70
+ def name
71
+ "cypress-rails"
72
+ end
73
+ }.new
74
+ end
75
+ end
76
+ end
@@ -1,14 +1,43 @@
1
1
  require_relative "config"
2
2
  require_relative "initializer_hooks"
3
+ require_relative "manages_transactions"
3
4
 
4
5
  module CypressRails
5
6
  class ResetsState
6
- def initialize
7
- @initializer_hooks = InitializerHooks.instance
7
+ LOCK = Mutex.new
8
+
9
+ def initialize(
10
+ transactional_server:,
11
+ manages_transactions: nil,
12
+ initializer_hooks: InitializerHooks.instance,
13
+ wrap: ->(&block) { Rails.application.reloader.wrap(&block) }
14
+ )
15
+ @transactional_server = transactional_server
16
+ @manages_transactions = manages_transactions
17
+ @initializer_hooks = initializer_hooks
18
+ @wrap = wrap
8
19
  end
9
20
 
10
21
  def call
11
- @initializer_hooks.run(:after_reset_requested)
22
+ LOCK.synchronize do
23
+ if @transactional_server
24
+ # Outside the reloader: waiting on the owner thread while holding a
25
+ # reloader share could deadlock against a code reload
26
+ manages_transactions.rollback_transaction
27
+ manages_transactions.begin_transaction
28
+ end
29
+
30
+ @wrap.call do
31
+ @initializer_hooks.run(:after_transaction_start) if @transactional_server
32
+ @initializer_hooks.run(:after_state_reset)
33
+ end
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def manages_transactions
40
+ @manages_transactions ||= ManagesTransactions.instance
12
41
  end
13
42
  end
14
43
  end
@@ -23,7 +23,9 @@ module CypressRails
23
23
  host:,
24
24
  port:,
25
25
  reportable_errors: [Exception],
26
- extra_middleware: [])
26
+ extra_middleware: [],
27
+ initializer_hooks: InitializerHooks.instance,
28
+ puma: Puma)
27
29
  @app = app
28
30
  @extra_middleware = extra_middleware
29
31
  @server_thread = nil # suppress warnings
@@ -33,7 +35,8 @@ module CypressRails
33
35
  @port ||= Server.ports[port_key]
34
36
  @port ||= find_available_port(host)
35
37
  @checker = Checker.new(@host, @port)
36
- @initializer_hooks = InitializerHooks.instance
38
+ @initializer_hooks = initializer_hooks
39
+ @puma = puma
37
40
  end
38
41
 
39
42
  def reset_error!
@@ -72,7 +75,7 @@ module CypressRails
72
75
  Server.ports[port_key] = port
73
76
 
74
77
  @server_thread = Thread.new {
75
- Puma.create(middleware, port, host)
78
+ @puma.create(middleware, port, host)
76
79
  }
77
80
 
78
81
  timer = Timer.new(60)
@@ -80,8 +83,10 @@ module CypressRails
80
83
  raise "Rack application timed out during boot" if timer.expired?
81
84
 
82
85
  @server_thread.join(0.1)
83
- @initializer_hooks.run(:after_server_start)
84
86
  end
87
+
88
+ # Once the server is up, so slow hooks don't count against the timeout
89
+ @initializer_hooks.run(:after_server_start)
85
90
  end
86
91
 
87
92
  self
@@ -1,28 +1,26 @@
1
- require_relative "tracks_resets"
1
+ require_relative "resets_state"
2
2
  require_relative "server"
3
3
 
4
4
  module CypressRails
5
5
  class StartsRailsServer
6
- def call(host:, port:)
7
- configure_rails_to_run_our_state_reset_on_every_request!
8
- app = create_rack_app
6
+ def call(host:, port:, transactional_server:)
7
+ app = create_rack_app(transactional_server)
9
8
  Server.new(app, host: host, port: port).tap do |server|
10
9
  server.boot
11
10
  end
12
11
  end
13
12
 
14
- def configure_rails_to_run_our_state_reset_on_every_request!
15
- Rails.application.executor.to_run do
16
- TracksResets.instance.reset_state_if_needed
17
- end
18
- end
19
-
20
- def create_rack_app
13
+ def create_rack_app(transactional_server)
21
14
  Rack::Builder.new do
22
15
  map "/cypress_rails_reset_state" do
23
16
  run lambda { |env|
24
- TracksResets.instance.reset_needed!
25
- [202, {"Content-Type" => "text/plain"}, ["Accepted"]]
17
+ begin
18
+ ResetsState.new(transactional_server: transactional_server).call
19
+ [200, {"content-type" => "text/plain"}, ["Reset"]]
20
+ rescue => e
21
+ warn e.full_message
22
+ [500, {"content-type" => "text/plain"}, ["#{e.class}: #{e.message}"]]
23
+ end
26
24
  }
27
25
  end
28
26
  map "/" do
@@ -1,3 +1,3 @@
1
1
  module CypressRails
2
- VERSION = "0.8.0"
2
+ VERSION = "0.9.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cypress-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Searls
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: 5.2.0
18
+ version: '7.1'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: 5.2.0
25
+ version: '7.1'
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: puma
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -93,6 +93,34 @@ dependencies:
93
93
  - - ">="
94
94
  - !ruby/object:Gem::Version
95
95
  version: 0.2.0
96
+ - !ruby/object:Gem::Dependency
97
+ name: activerecord
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: sqlite3
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ type: :development
118
+ prerelease: false
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
96
124
  email:
97
125
  - searls@gmail.com
98
126
  executables:
@@ -120,6 +148,7 @@ files:
120
148
  - lib/cypress-rails/init.rb
121
149
  - lib/cypress-rails/initializer_hooks.rb
122
150
  - lib/cypress-rails/launches_cypress.rb
151
+ - lib/cypress-rails/manages_transactions.rb
123
152
  - lib/cypress-rails/open.rb
124
153
  - lib/cypress-rails/railtie.rb
125
154
  - lib/cypress-rails/rake.rb
@@ -131,7 +160,6 @@ files:
131
160
  - lib/cypress-rails/server/puma.rb
132
161
  - lib/cypress-rails/server/timer.rb
133
162
  - lib/cypress-rails/starts_rails_server.rb
134
- - lib/cypress-rails/tracks_resets.rb
135
163
  - lib/cypress-rails/version.rb
136
164
  - script/test
137
165
  - script/test_example_app
@@ -1,26 +0,0 @@
1
- require_relative "resets_state"
2
-
3
- module CypressRails
4
- class TracksResets
5
- def self.instance
6
- @instance ||= new
7
- end
8
-
9
- def reset_needed!
10
- @reset_needed = true
11
- end
12
-
13
- def reset_state_if_needed
14
- if @reset_needed
15
- ResetsState.new.call
16
- @reset_needed = false
17
- end
18
- end
19
-
20
- private
21
-
22
- def initialize
23
- @reset_needed = false
24
- end
25
- end
26
- end