{
  "version": "https://jsonfeed.org/version/1",
  "title": "Capybra on enumerator.dev",
  "icon": "<no value>",
  "home_page_url": "https://enumerator.dev/",
  "feed_url": "https://enumerator.dev/feed.json",
  "items": [
      {
        "id": "https://enumerator.dev/end-to-end-tests-with-minitest-and-rails/",
        "title": "End To End Tests with Minitest and Rails",
        "content_html": "<p>willow.camp has a small system test suite that runs on CI. It used to use the out-of-the-box settings that come with Rails: Capybara, Selenium, etc.</p>\n<p>I noticed a flaky test on CI, which launched a journey to replace Selenium with Cuprite.</p>\n<h2 id=\"fixing-the-flaky-test\">Fixing the Flaky Test</h2>\n<p>I worked through the flaky test with Claude Code, and as Claude was running the tests, I noticed this pop-up from Chrome.</p>\n<blockquote>\n<p>A data breach on a site or app exposed your password&hellip;</p>\n</blockquote>\n<p>I don&rsquo;t use Chrome very often, so this jumped out at me. Of course, I use the oh-so-secret password &ldquo;password&rdquo; in my test suite, and Chrome flagged it as unsafe.</p>\n<p>Disabling password leak detection fixed this for me.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-fallback\" data-lang=\"fallback\"><span class=\"line\"><span class=\"cl\">browser_options: { &#34;disable-features&#34;: &#34;PasswordLeakDetection&#34; }\n</span></span></code></pre></div><p>But I still got timeouts on CI that looked like the tests were running before the browser was ready.</p>\n<p>Waiting for CI is a bit painful. You can see my hilariously bad Git history with Claude&rsquo;s gleeful overconfidence:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-fallback\" data-lang=\"fallback\"><span class=\"line\"><span class=\"cl\">* 0c514d1 - nosandbox (15 minutes ago) &lt;Cassia Scheffer&gt;\n</span></span><span class=\"line\"><span class=\"cl\">...\n</span></span><span class=\"line\"><span class=\"cl\">* 57ac55b - bump timeout to 30 sec for ci (21 minutes ago)\n</span></span><span class=\"line\"><span class=\"cl\">* 9d6e86e - rewirite cuprite/capybara configs (26 minutes ago)\n</span></span><span class=\"line\"><span class=\"cl\">* 39f3238 - fix: simplify Cuprite configuration following best practices (10 hours ago)\n</span></span><span class=\"line\"><span class=\"cl\">* 68bfd53 - fix: simplify Cuprite configuration and fix CI timeout issues (24 hours ago)\n</span></span><span class=\"line\"><span class=\"cl\">* cebfae7 - fix: resolve Cuprite websocket timeout issues in CI (24 hours ago)\n</span></span><span class=\"line\"><span class=\"cl\">* dc288b7 - fix: make Cuprite configuration more robust for CI environments (24 hours ago)\n</span></span><span class=\"line\"><span class=\"cl\">...\n</span></span><span class=\"line\"><span class=\"cl\">* e5bb4df - fix: increase Cuprite timeout and add CI-specific settings for GitHub Acti&gt;\n</span></span><span class=\"line\"><span class=\"cl\">...\n</span></span><span class=\"line\"><span class=\"cl\">* cb36eaa - feat: migrate system tests from Selenium to Cuprite (35 hours ago)\n</span></span><span class=\"line\"><span class=\"cl\">* 39f0ff1 - disable selenium chrome password detection (35 hours ago)\n</span></span></code></pre></div><h3 id=\"that-looks-bad-cassia-why-would-you-let-claude-do-that\">That Looks Bad, Cassia. Why Would You Let Claude Do That!?</h3>\n<p>Because Claude is faster at making mistakes than I am, and I am tired of waiting for CI. Making mistakes quickly means speedier feedback. So I sent Claude off on a fool&rsquo;s errand to help me learn from the mistakes I would otherwise have made myself.</p>\n<p>In the meantime, I read the <a href=\"https://evilmartians.com/chronicles/system-of-a-test-setting-up-end-to-end-rails-testing#dockerizing-system-tests\">Evil Martians article</a> about better system tests.</p>\n<h2 id=\"using-cuprite-in-rails-with-minitest\">Using Cuprite in Rails with Minitest</h2>\n<p>The Evil Martians article on system tests uses RSpec, but willow.camp uses Minitest. Here&rsquo;s what I had to change to make it work with Minitest.</p>\n<h3 id=\"1-precompileassets-becomes-a-module-and-gets-called-when-setup-runs\">1. PrecompileAssets becomes a module and gets called when setup runs.</h3>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-rb\" data-lang=\"rb\"><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Precompile assets before running tests to avoid timeouts.</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Do not precompile if webpack-dev-server is running (NOTE: MUST be launched with RAILS_ENV=test)</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">module</span> <span class=\"nn\">PrecompileAssets</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"k\">def</span> <span class=\"nc\">self</span><span class=\"o\">.</span><span class=\"nf\">setup</span>\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"c1\"># Check if we&#39;re running system tests by looking at the test files being loaded</span>\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">running_system_tests</span> <span class=\"o\">=</span> <span class=\"nb\">caller</span><span class=\"o\">.</span><span class=\"n\">any?</span> <span class=\"p\">{</span> <span class=\"o\">|</span><span class=\"n\">line</span><span class=\"o\">|</span> <span class=\"n\">line</span><span class=\"o\">.</span><span class=\"n\">include?</span><span class=\"p\">(</span><span class=\"s2\">&#34;test/system&#34;</span><span class=\"p\">)</span> <span class=\"p\">}</span> <span class=\"o\">||</span>\n</span></span><span class=\"line\"><span class=\"cl\">      <span class=\"no\">ARGV</span><span class=\"o\">.</span><span class=\"n\">any?</span> <span class=\"p\">{</span> <span class=\"o\">|</span><span class=\"n\">arg</span><span class=\"o\">|</span> <span class=\"n\">arg</span><span class=\"o\">.</span><span class=\"n\">include?</span><span class=\"p\">(</span><span class=\"s2\">&#34;test/system&#34;</span><span class=\"p\">)</span> <span class=\"p\">}</span> <span class=\"o\">||</span>\n</span></span><span class=\"line\"><span class=\"cl\">      <span class=\"no\">ENV</span><span class=\"o\">[</span><span class=\"s2\">&#34;RAILS_TEST_TYPE&#34;</span><span class=\"o\">]</span> <span class=\"o\">==</span> <span class=\"s2\">&#34;system&#34;</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">unless</span> <span class=\"n\">running_system_tests</span>\n</span></span><span class=\"line\"><span class=\"cl\">      <span class=\"nb\">puts</span> <span class=\"s2\">&#34;</span><span class=\"se\">\\n</span><span class=\"s2\">🚀️️  No system test selected. Skip assets compilation.</span><span class=\"se\">\\n</span><span class=\"s2\">&#34;</span>\n</span></span><span class=\"line\"><span class=\"cl\">      <span class=\"k\">return</span>\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">end</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"nb\">puts</span> <span class=\"s2\">&#34;</span><span class=\"se\">\\n</span><span class=\"s2\">🐢  Precompiling assets.</span><span class=\"se\">\\n</span><span class=\"s2\">&#34;</span>\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">original_stdout</span> <span class=\"o\">=</span> <span class=\"vg\">$stdout</span><span class=\"o\">.</span><span class=\"n\">clone</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"n\">start</span> <span class=\"o\">=</span> <span class=\"no\">Time</span><span class=\"o\">.</span><span class=\"n\">current</span>\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">begin</span>\n</span></span><span class=\"line\"><span class=\"cl\">      <span class=\"vg\">$stdout</span><span class=\"o\">.</span><span class=\"n\">reopen</span><span class=\"p\">(</span><span class=\"no\">File</span><span class=\"o\">.</span><span class=\"n\">new</span><span class=\"p\">(</span><span class=\"no\">File</span><span class=\"o\">::</span><span class=\"no\">Constants</span><span class=\"o\">::</span><span class=\"no\">NULL</span><span class=\"p\">,</span> <span class=\"s2\">&#34;w&#34;</span><span class=\"p\">))</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\">      <span class=\"nb\">require</span> <span class=\"s2\">&#34;rake&#34;</span>\n</span></span><span class=\"line\"><span class=\"cl\">      <span class=\"no\">Rails</span><span class=\"o\">.</span><span class=\"n\">application</span><span class=\"o\">.</span><span class=\"n\">load_tasks</span>\n</span></span><span class=\"line\"><span class=\"cl\">      <span class=\"no\">Rake</span><span class=\"o\">::</span><span class=\"no\">Task</span><span class=\"o\">[</span><span class=\"s2\">&#34;assets:precompile&#34;</span><span class=\"o\">].</span><span class=\"n\">invoke</span>\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">ensure</span>\n</span></span><span class=\"line\"><span class=\"cl\">      <span class=\"vg\">$stdout</span><span class=\"o\">.</span><span class=\"n\">reopen</span><span class=\"p\">(</span><span class=\"n\">original_stdout</span><span class=\"p\">)</span>\n</span></span><span class=\"line\"><span class=\"cl\">      <span class=\"nb\">puts</span> <span class=\"s2\">&#34;Finished in </span><span class=\"si\">#{</span><span class=\"p\">(</span><span class=\"no\">Time</span><span class=\"o\">.</span><span class=\"n\">current</span> <span class=\"o\">-</span> <span class=\"n\">start</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">round</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">)</span><span class=\"si\">}</span><span class=\"s2\"> seconds&#34;</span>\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">end</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"k\">end</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\"># Run the setup when this file is loaded</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"no\">PrecompileAssets</span><span class=\"o\">.</span><span class=\"n\">setup</span> <span class=\"k\">if</span> <span class=\"n\">defined?</span><span class=\"p\">(</span><span class=\"no\">Rails</span><span class=\"p\">)</span>\n</span></span></code></pre></div><h3 id=\"2-betterrailssystemtests-becomes-a-moduel\">2. BetterRailsSystemTests Becomes a Moduel</h3>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-rb\" data-lang=\"rb\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">module</span> <span class=\"nn\">BetterRailsSystemTests</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"c1\"># Make failure screenshots compatible with multi-session setup.</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"k\">def</span> <span class=\"nf\">take_screenshot</span>\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">return</span> <span class=\"k\">super</span> <span class=\"k\">unless</span> <span class=\"no\">Capybara</span><span class=\"o\">.</span><span class=\"n\">last_used_session</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"no\">Capybara</span><span class=\"o\">.</span><span class=\"n\">using_session</span><span class=\"p\">(</span><span class=\"no\">Capybara</span><span class=\"o\">.</span><span class=\"n\">last_used_session</span><span class=\"p\">)</span> <span class=\"p\">{</span> <span class=\"k\">super</span> <span class=\"p\">}</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"k\">end</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end</span>\n</span></span></code></pre></div><h3 id=\"3-modules-are-included-in-applicationsystemtestcase\">3. Modules are included in ApplicationSystemTestCase</h3>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-rb\" data-lang=\"rb\"><span class=\"line\"><span class=\"cl\"><span class=\"nb\">require</span> <span class=\"s2\">&#34;test_helper&#34;</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"nb\">require</span> <span class=\"s2\">&#34;capybara/cuprite&#34;</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"n\">require_relative</span> <span class=\"s2\">&#34;system/system_helper&#34;</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">class</span> <span class=\"nc\">ApplicationSystemTestCase</span> <span class=\"o\">&lt;</span> <span class=\"no\">ActionDispatch</span><span class=\"o\">::</span><span class=\"no\">SystemTestCase</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"kp\">include</span> <span class=\"no\">BetterRailsSystemTests</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"kp\">include</span> <span class=\"no\">CupriteHelpers</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"n\">driven_by</span> <span class=\"no\">Capybara</span><span class=\"o\">.</span><span class=\"n\">javascript_driver</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"k\">def</span> <span class=\"nf\">setup</span>\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">super</span>\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"c1\"># Use JS driver always</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"c1\"># Store original host for cleanup</span>\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"vi\">@original_host</span> <span class=\"o\">=</span> <span class=\"no\">Rails</span><span class=\"o\">.</span><span class=\"n\">application</span><span class=\"o\">.</span><span class=\"n\">default_url_options</span><span class=\"o\">[</span><span class=\"ss\">:host</span><span class=\"o\">]</span>\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"c1\"># Make urls in mailers contain the correct server host.</span>\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"c1\"># This is required for testing links in emails (e.g., via capybara-email).</span>\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"no\">Rails</span><span class=\"o\">.</span><span class=\"n\">application</span><span class=\"o\">.</span><span class=\"n\">default_url_options</span><span class=\"o\">[</span><span class=\"ss\">:host</span><span class=\"o\">]</span> <span class=\"o\">=</span> <span class=\"no\">Capybara</span><span class=\"o\">.</span><span class=\"n\">server_host</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"k\">end</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"k\">def</span> <span class=\"nf\">teardown</span>\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"c1\"># Restore original host</span>\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"no\">Rails</span><span class=\"o\">.</span><span class=\"n\">application</span><span class=\"o\">.</span><span class=\"n\">default_url_options</span><span class=\"o\">[</span><span class=\"ss\">:host</span><span class=\"o\">]</span> <span class=\"o\">=</span> <span class=\"vi\">@original_host</span>\n</span></span><span class=\"line\"><span class=\"cl\">    <span class=\"k\">super</span>\n</span></span><span class=\"line\"><span class=\"cl\">  <span class=\"k\">end</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">end</span>\n</span></span></code></pre></div><h2 id=\"flakiness-still-included-on-ci\">Flakiness Still Included on CI</h2>\n<p>I still see a bit of system test flakiness on CI, but far less than before. I am running on the default GitHub Actions runner, which is pretty small. So there&rsquo;s a good chance that the flakiness is due to low resources on the machine. So far, tests have consistently passed when I run these on my M1 MacBook Air.</p>\n<p>I&rsquo;ll dig into these flaky tests another day! But this looks like an improvement overall to me!</p>\n",
        "date_published": "2025-08-13T22:27:26+00:00",
        "url": "https://enumerator.dev/end-to-end-tests-with-minitest-and-rails/",
        "tags": ["willow-camp","rails","capybra","minitest"]
      }
  ]
}
