smartest 0.6.0.alpha1 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 52a400f8b0fb05816a1adae02b69ce475d81bd63ad3516dded34fc47b3efc516
4
- data.tar.gz: eeef5df2ac8161d3998fb942e7796ccfead8f7f8409b835c771fec4db7756137
3
+ metadata.gz: 60329ddc39f19de585b5eca7624d830188201867f12acc4c5d455086770c6e55
4
+ data.tar.gz: e3b94d9094456040638436153dea247c90a09df900f73fac8a446e230cf121e6
5
5
  SHA512:
6
- metadata.gz: 8336c21065222424824f95636730ab6ba1683fff0f711a3d37d180bebe6bac8cbf95be4c9bb8e0a794f0719fb5ba86102703d5af99902c1ab8461b5de0f6ab7c
7
- data.tar.gz: 067c9a2f862cf07035b50bc8783e92f919a68ec8000546b2ab96e0ed2bde7c8cb0b811d99f7e9bf8bb2983d85ac7883fd830a38f86930c5a688b6e800f459fb7
6
+ metadata.gz: 47ba0913bb68d3015905baa12677ed6ac2f812723935a546d0f6f9c0e0154776fb72a9e2844a77833743c97a8363066c7199c767022022b17f169415c48b9001
7
+ data.tar.gz: 86f5bdd1c49b6f461408c5ee21075a0a75406e8f6c139f6146871fcbd0dea6644129e63339602851f2a122ac075d6bcc7b96d95d69224e446dc5e6031c951cf9
data/CHANGELOG.md CHANGED
@@ -1,6 +1,19 @@
1
1
  # Changelog
2
2
 
3
- ## 0.6.0 (not published yet)
3
+ ## 0.6.1
4
+
5
+ ### Bug Fixes
6
+
7
+ - Fix Rails Docker scaffold friction in `smartest --init-rails` and the
8
+ generated Playwright fixtures so the Docker-based browser test setup works
9
+ out of the box.
10
+
11
+ ### Documentation
12
+
13
+ - Document fresh Rails database preparation for browser tests, including the
14
+ Docker-based workflow.
15
+
16
+ ## 0.6.0
4
17
 
5
18
  ### New Features
6
19
 
data/README.md CHANGED
@@ -256,15 +256,43 @@ smartest/matchers/playwright_matcher.rb
256
256
  smartest/example_rails_system_test.rb
257
257
  ```
258
258
 
259
- The generated fixture requires `smartest/rails` and starts
259
+ The generated fixture requires `smartest/rails`, loads `config/environment`
260
+ when `test_helper` requires the fixture file, and starts
260
261
  `Smartest::Rails::TestServer` against `Rails.application` in the same Ruby
261
- process as the test runner. `Smartest::Rails::TestServer` is only loaded by
262
- explicitly requiring `smartest/rails`; plain `require "smartest"` does not load
263
- Puma.
262
+ process as the test runner. Loading Rails during helper setup makes app
263
+ constants such as ActiveRecord models available inside test files and
264
+ `around_test` hooks before per-test fixtures are resolved. The generated
265
+ fixture forces `RAILS_ENV` and `RACK_ENV` to `test` before Rails boots.
266
+ `Smartest::Rails::TestServer` is only loaded by explicitly requiring
267
+ `smartest/rails`; plain `require "smartest"` does not load Puma.
268
+
269
+ This is aimed at local Rails system tests that combine Rails test data, stubs,
270
+ and Playwright browser assertions. It is not a Capybara compatibility layer or
271
+ the main choice for staging / production-like E2E suites; use Node.js
272
+ Playwright Test for that style of E2E testing.
264
273
 
265
274
  The generated `page` fixture uses a per-test Playwright browser context with
266
- `baseURL` set to the Rails server URL. Set `SMARTEST_RAILS_PORT` when you need a
267
- fixed port; otherwise the test server asks the OS for an available port.
275
+ `baseURL` set to the Rails server URL. Set
276
+ `SMARTEST_RAILS_TEST_SERVER_PORT` when you need a fixed port; otherwise the test
277
+ server asks the OS for an available port.
278
+
279
+ For Docker sidecar runs, initialize without installing browser binaries into
280
+ the Rails app container:
281
+
282
+ ```bash
283
+ SMARTEST_SKIP_BROWSER_DOWNLOAD=1 bundle exec smartest --init-rails
284
+ ```
285
+
286
+ At runtime, set `PLAYWRIGHT_WS_ENDPOINT`,
287
+ `SMARTEST_RAILS_TEST_SERVER_HOST`, `SMARTEST_RAILS_TEST_SERVER_PORT`, and
288
+ `SMARTEST_RAILS_BASE_URL` so the generated fixture connects to the Playwright
289
+ sidecar and gives the browser a Docker-network URL for Rails. These are usually
290
+ stable Docker topology settings, so put them in `compose.yml` instead of
291
+ repeating them on every `docker compose run` command.
292
+ For a Rails Compose service named `web`, use
293
+ `SMARTEST_RAILS_BASE_URL=http://web:4001`; replace `web` with your service name.
294
+ The generated Rails fixture sets `RAILS_ENV` and `RACK_ENV` to `test`, even if
295
+ the same service normally runs in development.
268
296
 
269
297
  Run the generated Rails browser example with:
270
298
 
@@ -160,11 +160,15 @@ module Smartest
160
160
  end
161
161
 
162
162
  def install_dependencies
163
- install_commands.each do |command|
164
- @output.puts "run #{command.join(" ")}"
165
- next if @command_runner.call(command, chdir: @root)
163
+ commands = install_commands
166
164
 
167
- raise "command failed: #{command.join(" ")}"
165
+ with_unbundled_env do
166
+ commands.each do |command|
167
+ @output.puts "run #{command.join(" ")}"
168
+ next if @command_runner.call(command, chdir: @root)
169
+
170
+ raise "command failed: #{command.join(" ")}"
171
+ end
168
172
  end
169
173
  end
170
174
 
@@ -179,5 +183,15 @@ module Smartest
179
183
  def run_system_command(command, chdir:)
180
184
  system(*command, chdir: chdir)
181
185
  end
186
+
187
+ def with_unbundled_env(&block)
188
+ require "bundler"
189
+
190
+ if Bundler.respond_to?(:with_unbundled_env)
191
+ Bundler.with_unbundled_env(&block)
192
+ else
193
+ Bundler.with_clean_env(&block)
194
+ end
195
+ end
182
196
  end
183
197
  end
@@ -10,15 +10,19 @@ module Smartest
10
10
  require 'smartest/rails'
11
11
  require "playwright"
12
12
 
13
- class RailsSystemFixture < Smartest::Fixture
14
- suite_fixture :rails_server do
15
- # Set the environment before loading config/environment so the test
16
- # server cannot boot against the development database by default.
17
- ENV["RAILS_ENV"] ||= "test"
18
- ENV["RACK_ENV"] ||= ENV["RAILS_ENV"]
19
- require_relative "../../config/environment"
13
+ # Force the test environment and load Rails while test_helper is required
14
+ # so app constants are available before per-test fixtures are resolved.
15
+ ENV["RAILS_ENV"] = "test"
16
+ ENV["RACK_ENV"] = "test"
17
+ require_relative "../../config/environment"
20
18
 
21
- server = Smartest::Rails::TestServer.new(app: Rails.application)
19
+ class RailsSystemTestFixture < Smartest::Fixture
20
+ suite_fixture :rails_server do
21
+ server = Smartest::Rails::TestServer.new(
22
+ app: Rails.application,
23
+ host: ENV["SMARTEST_RAILS_TEST_SERVER_HOST"],
24
+ port: ENV["SMARTEST_RAILS_TEST_SERVER_PORT"],
25
+ )
22
26
  server.start
23
27
  server.wait_for_ready
24
28
 
@@ -31,36 +35,34 @@ module Smartest
31
35
  end
32
36
 
33
37
  suite_fixture :base_url do |rails_server:|
34
- rails_server.base_url
38
+ ENV.fetch("SMARTEST_RAILS_BASE_URL", rails_server.base_url)
35
39
  end
36
40
 
37
- suite_fixture :playwright do
38
- runtime = Playwright.create(
39
- playwright_cli_executable_path: "./node_modules/.bin/playwright",
40
- )
41
- on_teardown { runtime.stop }
42
- runtime.playwright
43
- end
41
+ suite_fixture :browser do
42
+ ws_endpoint = ENV["PLAYWRIGHT_WS_ENDPOINT"]
44
43
 
45
- suite_fixture :browser do |playwright:|
46
- browser_type = case ENV["BROWSER"]
47
- when "firefox"
48
- :firefox
49
- when "webkit"
50
- :webkit
51
- else
52
- :chromium
53
- end
44
+ if ws_endpoint && !ws_endpoint.empty?
45
+ playwright_execution = Playwright.connect_to_browser_server(
46
+ ws_endpoint,
47
+ browser_type: selected_browser_type.to_s,
48
+ )
49
+ on_teardown { playwright_execution.stop }
54
50
 
55
- launch_options = {}
56
- launch_options[:headless] = !%w[0 false].include?(ENV["HEADLESS"])
57
- if (slow_mo = ENV["SLOW_MO"].to_i) > 0
58
- launch_options[:slowMo] = slow_mo
51
+ playwright_execution.browser
52
+ else
53
+ playwright_execution = Playwright.create(
54
+ playwright_cli_executable_path: ENV.fetch(
55
+ "PLAYWRIGHT_CLI_EXECUTABLE_PATH",
56
+ "./node_modules/.bin/playwright",
57
+ )
58
+ )
59
+ on_teardown { playwright_execution.stop }
60
+
61
+ playwright = playwright_execution.playwright
62
+ browser = playwright.public_send(selected_browser_type).launch(**browser_launch_options)
63
+ on_teardown { browser.close }
64
+ browser
59
65
  end
60
-
61
- browser = playwright.send(browser_type).launch(**launch_options)
62
- on_teardown { browser.close }
63
- browser
64
66
  end
65
67
 
66
68
  fixture :browser_context do |base_url:, browser:|
@@ -74,6 +76,29 @@ module Smartest
74
76
  on_teardown { page.close }
75
77
  page
76
78
  end
79
+
80
+ private
81
+
82
+ def selected_browser_type
83
+ case ENV.fetch("BROWSER", "chromium")
84
+ when "firefox"
85
+ :firefox
86
+ when "webkit"
87
+ :webkit
88
+ else
89
+ :chromium
90
+ end
91
+ end
92
+
93
+ def browser_launch_options
94
+ launch_options = {}
95
+ launch_options[:headless] = !%w[0 false].include?(ENV.fetch("HEADLESS", "true"))
96
+ if (slow_mo = ENV.fetch("SLOW_MO", "0").to_i) > 0
97
+ launch_options[:slowMo] = slow_mo
98
+ end
99
+
100
+ launch_options
101
+ end
77
102
  end
78
103
  RUBY
79
104
 
@@ -156,7 +181,7 @@ module Smartest
156
181
 
157
182
  def ensure_rails_registered(contents)
158
183
  missing_lines = []
159
- missing_lines << " use_fixture RailsSystemFixture\n" unless contents.include?("use_fixture RailsSystemFixture")
184
+ missing_lines << " use_fixture RailsSystemTestFixture\n" unless contents.include?("use_fixture RailsSystemTestFixture")
160
185
  missing_lines << " use_matcher PlaywrightMatcher\n" unless contents.include?("use_matcher PlaywrightMatcher")
161
186
  return contents if missing_lines.empty?
162
187
 
@@ -186,11 +211,19 @@ module Smartest
186
211
  end
187
212
 
188
213
  def install_dependencies
189
- install_commands.each do |command|
190
- @output.puts "run #{command.join(" ")}"
191
- next if @command_runner.call(command, chdir: @root)
214
+ commands = install_commands
215
+
216
+ with_unbundled_env do
217
+ commands.each do |command|
218
+ @output.puts "run #{command.join(" ")}"
219
+ next if @command_runner.call(command, chdir: @root)
192
220
 
193
- raise "command failed: #{command.join(" ")}"
221
+ raise "command failed: #{command.join(" ")}"
222
+ end
223
+ end
224
+
225
+ if skip_browser_download?
226
+ @output.puts "skip ./node_modules/.bin/playwright install (SMARTEST_SKIP_BROWSER_DOWNLOAD=1)"
194
227
  end
195
228
  end
196
229
 
@@ -198,12 +231,26 @@ module Smartest
198
231
  commands = [["bundle", "install"]]
199
232
  commands << ["npm", "init", "--yes"] unless File.exist?(File.join(@root, "package.json"))
200
233
  commands << ["npm", "install", "playwright", "--save-dev"]
201
- commands << ["./node_modules/.bin/playwright", "install"]
234
+ commands << ["./node_modules/.bin/playwright", "install"] unless skip_browser_download?
202
235
  commands
203
236
  end
204
237
 
238
+ def skip_browser_download?
239
+ %w[1 true].include?(ENV.fetch("SMARTEST_SKIP_BROWSER_DOWNLOAD", "false"))
240
+ end
241
+
205
242
  def run_system_command(command, chdir:)
206
243
  system(*command, chdir: chdir)
207
244
  end
245
+
246
+ def with_unbundled_env(&block)
247
+ require "bundler"
248
+
249
+ if Bundler.respond_to?(:with_unbundled_env)
250
+ Bundler.with_unbundled_env(&block)
251
+ else
252
+ Bundler.with_clean_env(&block)
253
+ end
254
+ end
208
255
  end
209
256
  end
@@ -9,15 +9,14 @@ require_relative "../smartest"
9
9
  module Smartest
10
10
  module Rails
11
11
  class TestServer
12
- DEFAULT_HOST = "127.0.0.1"
13
12
  DEFAULT_READY_TIMEOUT = 10
14
13
 
15
14
  attr_reader :host, :port
16
15
 
17
- def initialize(app:, host: DEFAULT_HOST, port: nil)
16
+ def initialize(app:, host: nil, port: nil)
18
17
  @app = app
19
- @host = host
20
- @requested_port = port || ENV["SMARTEST_RAILS_PORT"]&.to_i || 0
18
+ @host = host || "127.0.0.1"
19
+ @requested_port = port ? port.to_i : 0
21
20
  @server = Puma::Server.new(@app)
22
21
  @port = bind_tcp_listener
23
22
  @thread = nil
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Smartest
4
- VERSION = "0.6.0.alpha1"
4
+ VERSION = "0.6.1"
5
5
  end
@@ -9,6 +9,8 @@ require "open3"
9
9
  require "tmpdir"
10
10
 
11
11
  module SmartestSelfTest
12
+ ENV_MISSING = Object.new.freeze
13
+
12
14
  module_function
13
15
 
14
16
  def test_case(name, block)
@@ -40,6 +42,20 @@ module SmartestSelfTest
40
42
  else
41
43
  raise Smartest::AssertionFailed, "expected #{expected_error}, but nothing was raised"
42
44
  end
45
+
46
+ def with_env(values)
47
+ previous_values = {}
48
+ values.each do |key, value|
49
+ previous_values[key] = ENV.fetch(key, ENV_MISSING)
50
+ value.nil? ? ENV.delete(key) : ENV[key] = value
51
+ end
52
+
53
+ yield
54
+ ensure
55
+ previous_values.each do |key, value|
56
+ value.equal?(ENV_MISSING) ? ENV.delete(key) : ENV[key] = value
57
+ end
58
+ end
43
59
  end
44
60
 
45
61
  class SelfTestRegisteredFixture < Smartest::Fixture
@@ -2167,6 +2183,49 @@ test("cli browser init generator creates Playwright scaffold and installation co
2167
2183
  end
2168
2184
  end
2169
2185
 
2186
+ test("cli browser init generator runs installation commands outside the current Bundler environment") do
2187
+ require "bundler"
2188
+
2189
+ Dir.mktmpdir do |dir|
2190
+ File.write(File.join(dir, "Gemfile"), <<~RUBY)
2191
+ source "https://rubygems.org"
2192
+
2193
+ gem "smartest"
2194
+ RUBY
2195
+
2196
+ command_environments = []
2197
+ output = StringIO.new
2198
+ generator = Smartest::InitBrowserGenerator.new(
2199
+ root: dir,
2200
+ output: output,
2201
+ command_runner: ->(_command, chdir:) {
2202
+ command_environments << {
2203
+ bundle_gemfile: ENV["BUNDLE_GEMFILE"],
2204
+ bundle_bin_path: ENV["BUNDLE_BIN_PATH"],
2205
+ rubyopt: ENV["RUBYOPT"]
2206
+ }
2207
+ true
2208
+ }
2209
+ )
2210
+
2211
+ SmartestSelfTest.with_env(
2212
+ "BUNDLE_GEMFILE" => File.join(dir, "Gemfile"),
2213
+ "BUNDLE_BIN_PATH" => "/tmp/smartest-self-test-bundle",
2214
+ "RUBYOPT" => "-rbundler/setup -W0"
2215
+ ) do
2216
+ status = generator.run
2217
+ expect(status).to eq(0)
2218
+ end
2219
+
2220
+ expect(command_environments.length).to eq(4)
2221
+ expect(command_environments.all? do |environment|
2222
+ environment[:bundle_gemfile].nil? &&
2223
+ environment[:bundle_bin_path].nil? &&
2224
+ !environment[:rubyopt].to_s.include?("bundler/setup")
2225
+ end).to eq(true)
2226
+ end
2227
+ end
2228
+
2170
2229
  test("cli browser init generator skips npm init when package.json already exists") do
2171
2230
  Dir.mktmpdir do |dir|
2172
2231
  File.write(File.join(dir, "Gemfile"), <<~RUBY)
@@ -2230,7 +2289,7 @@ test("smartest rails helper is loaded only by explicit require") do
2230
2289
  end
2231
2290
  end
2232
2291
 
2233
- test("smartest rails test server wraps puma with env port and lifecycle") do
2292
+ test("smartest rails test server wraps puma with explicit arguments and lifecycle") do
2234
2293
  lib_path = File.expand_path("../lib", __dir__)
2235
2294
 
2236
2295
  Dir.mktmpdir do |dir|
@@ -2269,25 +2328,32 @@ test("smartest rails test server wraps puma with env port and lifecycle") do
2269
2328
  RUBY
2270
2329
 
2271
2330
  stdout, stderr, status = Open3.capture3(
2272
- { "RUBYLIB" => "#{dir}:#{lib_path}", "SMARTEST_RAILS_PORT" => "4567" },
2331
+ {
2332
+ "RUBYLIB" => "#{dir}:#{lib_path}",
2333
+ "SMARTEST_RAILS_TEST_SERVER_HOST" => "0.0.0.0",
2334
+ "SMARTEST_RAILS_TEST_SERVER_PORT" => "9876",
2335
+ "SMARTEST_RAILS_BASE_URL" => "http://app:9876"
2336
+ },
2273
2337
  "ruby",
2274
2338
  "-e",
2275
2339
  <<~'RUBY'
2276
2340
  require "smartest/rails"
2277
2341
 
2278
- server = Smartest::Rails::TestServer.new(app: Object.new)
2342
+ server = Smartest::Rails::TestServer.new(app: Object.new, port: "4567")
2343
+ default_port_server = Smartest::Rails::TestServer.new(app: Object.new)
2279
2344
  thread = server.start
2280
2345
  server.stop
2281
2346
  server.wait_for_stopped
2282
2347
 
2283
2348
  puts server.base_url
2349
+ puts default_port_server.base_url
2284
2350
  puts thread.is_a?(Thread)
2285
2351
  RUBY
2286
2352
  )
2287
2353
 
2288
2354
  expect(status.success?).to eq(true)
2289
2355
  expect(stderr).to eq("")
2290
- expect(stdout).to eq("http://127.0.0.1:4567\ntrue\n")
2356
+ expect(stdout).to eq("http://127.0.0.1:4567\nhttp://127.0.0.1:4321\ntrue\n")
2291
2357
  end
2292
2358
  end
2293
2359
 
@@ -2316,14 +2382,42 @@ test("cli rails init generator creates Rails browser scaffold and installation c
2316
2382
  expect(status).to eq(0)
2317
2383
  rails_fixture = File.read(File.join(dir, "smartest/fixtures/rails_system_fixture.rb"))
2318
2384
  expect(rails_fixture).to include("require 'smartest/rails'")
2319
- expect(rails_fixture).to include("class RailsSystemFixture < Smartest::Fixture")
2385
+ expect(rails_fixture).to include("class RailsSystemTestFixture < Smartest::Fixture")
2320
2386
  expect(rails_fixture).to include("suite_fixture :rails_server")
2321
- expect(rails_fixture).to include("server cannot boot against the development database")
2387
+ expect(rails_fixture).to include('ENV["RAILS_ENV"] = "test"')
2388
+ expect(rails_fixture).to include('ENV["RACK_ENV"] = "test"')
2389
+ expect(rails_fixture).not_to include('ENV["RAILS_ENV"] ||=')
2390
+ expect(rails_fixture).to include("constants are available before per-test fixtures are resolved")
2322
2391
  expect(rails_fixture).to include('require_relative "../../config/environment"')
2323
- expect(rails_fixture).to include("Smartest::Rails::TestServer.new(app: Rails.application)")
2392
+ expect(rails_fixture.index('require_relative "../../config/environment"') < rails_fixture.index("class RailsSystemTestFixture")).to eq(true)
2393
+ expect(rails_fixture).to include("Smartest::Rails::TestServer.new(")
2394
+ expect(rails_fixture).to include('host: ENV["SMARTEST_RAILS_TEST_SERVER_HOST"]')
2395
+ expect(rails_fixture).not_to include("bind_host:")
2396
+ expect(rails_fixture).to include('port: ENV["SMARTEST_RAILS_TEST_SERVER_PORT"]')
2397
+ expect(rails_fixture).not_to include("public_base_url")
2324
2398
  expect(rails_fixture).not_to include("SmartestRailsTestServer")
2325
2399
  expect(rails_fixture).not_to include("Puma::Server")
2326
2400
  expect(rails_fixture).to include("suite_fixture :base_url")
2401
+ expect(rails_fixture).to include('ENV.fetch("SMARTEST_RAILS_BASE_URL", rails_server.base_url)')
2402
+ expect(rails_fixture).not_to include("rails_test_server_port")
2403
+ expect(rails_fixture).not_to include("SMARTEST_RAILS_PORT")
2404
+ expect(rails_fixture).to include('ws_endpoint = ENV["PLAYWRIGHT_WS_ENDPOINT"]')
2405
+ expect(rails_fixture).not_to include("suite_fixture :playwright_execution")
2406
+ expect(rails_fixture).not_to include("suite_fixture :playwright do")
2407
+ expect(rails_fixture).not_to include("Playwright.connect_to_playwright_server")
2408
+ expect(rails_fixture).not_to include("rescue NotImplementedError")
2409
+ expect(rails_fixture).to include("playwright_execution = Playwright.connect_to_browser_server(")
2410
+ expect(rails_fixture).to include("browser_type: selected_browser_type.to_s")
2411
+ expect(rails_fixture).to include("playwright_execution.browser")
2412
+ expect(rails_fixture).to include('ENV.fetch(')
2413
+ expect(rails_fixture).to include('"PLAYWRIGHT_CLI_EXECUTABLE_PATH"')
2414
+ expect(rails_fixture).to include("suite_fixture :browser do")
2415
+ expect(rails_fixture).to include("playwright_execution = Playwright.create(")
2416
+ expect(rails_fixture).to include("on_teardown { playwright_execution.stop }")
2417
+ expect(rails_fixture).to include("playwright = playwright_execution.playwright")
2418
+ expect(rails_fixture).to include("playwright.public_send(selected_browser_type).launch(**browser_launch_options)")
2419
+ expect(rails_fixture).to include("def selected_browser_type")
2420
+ expect(rails_fixture).to include("def browser_launch_options")
2327
2421
  expect(rails_fixture).to include("fixture :browser_context do |base_url:, browser:|")
2328
2422
  expect(rails_fixture).to include("context = browser.new_context(baseURL: base_url)")
2329
2423
  expect(rails_fixture).to include("fixture :page do |browser_context:|")
@@ -2334,7 +2428,7 @@ test("cli rails init generator creates Rails browser scaffold and installation c
2334
2428
  expect(example_test).to include("expect(response.status).to be_between(200, 599)")
2335
2429
 
2336
2430
  helper_contents = File.read(File.join(dir, "smartest/test_helper.rb"))
2337
- expect(helper_contents).to include("use_matcher PredicateMatcher\n use_fixture RailsSystemFixture\n use_matcher PlaywrightMatcher\n suite.run")
2431
+ expect(helper_contents).to include("use_matcher PredicateMatcher\n use_fixture RailsSystemTestFixture\n use_matcher PlaywrightMatcher\n suite.run")
2338
2432
  expect(helper_contents).not_to include("Smartest::SimpleStub")
2339
2433
 
2340
2434
  gemfile_contents = File.read(File.join(dir, "Gemfile"))
@@ -2351,6 +2445,150 @@ test("cli rails init generator creates Rails browser scaffold and installation c
2351
2445
  end
2352
2446
  end
2353
2447
 
2448
+ test("cli rails init generator forces Rails test environment when the generated fixture is required") do
2449
+ Dir.mktmpdir do |dir|
2450
+ FileUtils.mkdir_p(File.join(dir, "config"))
2451
+ File.write(File.join(dir, "Gemfile"), <<~RUBY)
2452
+ source "https://rubygems.org"
2453
+
2454
+ gem "rails"
2455
+ gem "smartest"
2456
+ RUBY
2457
+ File.write(File.join(dir, "config/environment.rb"), <<~RUBY)
2458
+ raise "RAILS_ENV was not set before loading Rails" unless ENV["RAILS_ENV"] == "test"
2459
+ raise "RACK_ENV was not set before loading Rails" unless ENV["RACK_ENV"] == "test"
2460
+
2461
+ class User
2462
+ end
2463
+ RUBY
2464
+
2465
+ stub_dir = File.join(dir, "stub_load_path")
2466
+ FileUtils.mkdir_p(File.join(stub_dir, "smartest"))
2467
+ File.write(File.join(stub_dir, "smartest/rails.rb"), <<~RUBY)
2468
+ module Smartest
2469
+ class Fixture
2470
+ def self.suite_fixture(*)
2471
+ end
2472
+
2473
+ def self.fixture(*)
2474
+ end
2475
+ end
2476
+
2477
+ module Rails
2478
+ end
2479
+ end
2480
+ RUBY
2481
+ File.write(File.join(stub_dir, "playwright.rb"), "")
2482
+
2483
+ generator = Smartest::InitRailsGenerator.new(
2484
+ root: dir,
2485
+ output: StringIO.new,
2486
+ command_runner: ->(_command, chdir:) { true }
2487
+ )
2488
+ generator.run
2489
+
2490
+ stdout, stderr, status = Open3.capture3(
2491
+ {
2492
+ "RUBYLIB" => stub_dir,
2493
+ "RAILS_ENV" => "development",
2494
+ "RACK_ENV" => "development"
2495
+ },
2496
+ "ruby",
2497
+ "-e",
2498
+ <<~RUBY
2499
+ require #{File.join(dir, "smartest/fixtures/rails_system_fixture").inspect}
2500
+ puts User.name
2501
+ RUBY
2502
+ )
2503
+
2504
+ expect(status.success?).to eq(true)
2505
+ expect(stderr).to eq("")
2506
+ expect(stdout).to eq("User\n")
2507
+ end
2508
+ end
2509
+
2510
+ test("cli rails init generator runs installation commands outside the current Bundler environment") do
2511
+ require "bundler"
2512
+
2513
+ Dir.mktmpdir do |dir|
2514
+ File.write(File.join(dir, "Gemfile"), <<~RUBY)
2515
+ source "https://rubygems.org"
2516
+
2517
+ gem "rails"
2518
+ gem "smartest"
2519
+ RUBY
2520
+
2521
+ command_environments = []
2522
+ output = StringIO.new
2523
+ generator = Smartest::InitRailsGenerator.new(
2524
+ root: dir,
2525
+ output: output,
2526
+ command_runner: ->(_command, chdir:) {
2527
+ command_environments << {
2528
+ bundle_gemfile: ENV["BUNDLE_GEMFILE"],
2529
+ bundle_bin_path: ENV["BUNDLE_BIN_PATH"],
2530
+ rubyopt: ENV["RUBYOPT"]
2531
+ }
2532
+ true
2533
+ }
2534
+ )
2535
+
2536
+ SmartestSelfTest.with_env(
2537
+ "BUNDLE_GEMFILE" => File.join(dir, "Gemfile"),
2538
+ "BUNDLE_BIN_PATH" => "/tmp/smartest-self-test-bundle",
2539
+ "RUBYOPT" => "-rbundler/setup -W0"
2540
+ ) do
2541
+ status = generator.run
2542
+ expect(status).to eq(0)
2543
+ end
2544
+
2545
+ expect(command_environments.length).to eq(4)
2546
+ expect(command_environments.all? do |environment|
2547
+ environment[:bundle_gemfile].nil? &&
2548
+ environment[:bundle_bin_path].nil? &&
2549
+ !environment[:rubyopt].to_s.include?("bundler/setup")
2550
+ end).to eq(true)
2551
+ end
2552
+ end
2553
+
2554
+ test("cli rails init generator skips browser install when requested by environment") do
2555
+ SmartestSelfTest.with_env("SMARTEST_SKIP_BROWSER_DOWNLOAD" => "1") do
2556
+ Dir.mktmpdir do |dir|
2557
+ File.write(File.join(dir, "Gemfile"), <<~RUBY)
2558
+ source "https://rubygems.org"
2559
+
2560
+ gem "rails"
2561
+ gem "smartest"
2562
+ RUBY
2563
+
2564
+ commands = []
2565
+ output = StringIO.new
2566
+ generator = Smartest::InitRailsGenerator.new(
2567
+ root: dir,
2568
+ output: output,
2569
+ command_runner: ->(command, chdir:) {
2570
+ commands << [command, chdir]
2571
+ true
2572
+ }
2573
+ )
2574
+
2575
+ status = generator.run
2576
+
2577
+ expect(status).to eq(0)
2578
+ expect(commands).to eq(
2579
+ [
2580
+ [["bundle", "install"], dir],
2581
+ [["npm", "init", "--yes"], dir],
2582
+ [["npm", "install", "playwright", "--save-dev"], dir]
2583
+ ]
2584
+ )
2585
+ expect(output.string).to include("skip ./node_modules/.bin/playwright install (SMARTEST_SKIP_BROWSER_DOWNLOAD=1)")
2586
+ expect(File.exist?(File.join(dir, "smartest/fixtures/rails_system_fixture.rb"))).to eq(true)
2587
+ expect(File.exist?(File.join(dir, "smartest/example_rails_system_test.rb"))).to eq(true)
2588
+ end
2589
+ end
2590
+ end
2591
+
2354
2592
  test("cli rails init generator skips duplicate registration and dependencies") do
2355
2593
  Dir.mktmpdir do |dir|
2356
2594
  FileUtils.mkdir_p(File.join(dir, "smartest/fixtures"))
@@ -2367,7 +2605,7 @@ test("cli rails init generator skips duplicate registration and dependencies") d
2367
2605
 
2368
2606
  around_suite do |suite|
2369
2607
  use_matcher PredicateMatcher
2370
- use_fixture RailsSystemFixture
2608
+ use_fixture RailsSystemTestFixture
2371
2609
  use_matcher PlaywrightMatcher
2372
2610
  suite.run
2373
2611
  end
@@ -2388,7 +2626,7 @@ test("cli rails init generator skips duplicate registration and dependencies") d
2388
2626
 
2389
2627
  expect(status).to eq(0)
2390
2628
  helper_contents = File.read(File.join(dir, "smartest/test_helper.rb"))
2391
- expect(helper_contents.scan("use_fixture RailsSystemFixture").length).to eq(1)
2629
+ expect(helper_contents.scan("use_fixture RailsSystemTestFixture").length).to eq(1)
2392
2630
  expect(helper_contents.scan("use_matcher PlaywrightMatcher").length).to eq(1)
2393
2631
  expect(helper_contents).not_to include("Smartest::SimpleStub")
2394
2632
  expect(commands).to eq(
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smartest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0.alpha1
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yusuke Iwaki
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-05-07 00:00:00.000000000 Z
11
+ date: 2026-05-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -103,9 +103,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
103
103
  version: '2.7'
104
104
  required_rubygems_version: !ruby/object:Gem::Requirement
105
105
  requirements:
106
- - - ">"
106
+ - - ">="
107
107
  - !ruby/object:Gem::Version
108
- version: 1.3.1
108
+ version: '0'
109
109
  requirements: []
110
110
  rubygems_version: 3.4.19
111
111
  signing_key: