Skip to content

Lesson 7 — Testing Phlex views in Rails

Testing in a Rails context differs from the standalone Minitest approach in Module 3 in one important way: views and components that use Rails helpers (routes, link_to, current_user etc.) need a view context to render correctly.

Component unit tests

For components that don’t use Rails helpers, the Module 3 approach works unchanged:

1
2
3
4
5
6
7
8
9
# test/components/button_test.rb
require "test_helper"

class ButtonTest < ActiveSupport::TestCase
  test "renders primary button" do
    html = Components::Button.new(label: "Save").call
    assert_includes html, ">Save<"
  end
end

For components that use Rails helpers, provide a view context:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# test/test_helper.rb — add this helper module
module PhlexTestHelper
  def render(component)
    component.call(view_context: view_context)
  end

  def render_fragment(component)
    Nokogiri::HTML5.fragment(render(component))
  end

  def view_context
    controller = ApplicationController.new
    controller.request = ActionDispatch::TestRequest.create
    controller.view_context
  end
end

Include it in your test classes:

1
2
3
class ComponentTest < ActiveSupport::TestCase
  include PhlexTestHelper
end

View tests

Views are also just Ruby objects — test them the same way:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# test/views/boards/index_test.rb
require "test_helper"

class Views::Boards::IndexTest < ActiveSupport::TestCase
  include PhlexTestHelper

  test "shows empty state when no boards" do
    html = render Views::Boards::Index.new(boards: [])
    assert_includes html, "No boards yet"
  end

  test "renders board names" do
    boards = [
      Board.new(name: "Project Alpha"),
      Board.new(name: "Project Beta"),
    ]
    html = render Views::Boards::Index.new(boards: boards)
    assert_includes html, "Project Alpha"
    assert_includes html, "Project Beta"
  end
end

System tests

For full end-to-end testing with a browser, Rails system tests work exactly as normal — Phlex views are just HTML from the browser’s perspective:

1
2
3
4
5
6
7
8
9
# test/system/boards_test.rb
require "application_system_test_case"

class BoardsTest < ApplicationSystemTestCase
  test "visiting the boards index" do
    visit boards_url
    assert_selector "h1", text: "Your Boards"
  end
end

What to test at each level

Level What to test Tools
Component unit Props, variants, slots, type validation Minitest + Nokogiri
View unit Data rendering, empty states, conditional sections Minitest + Nokogiri
System User flows, navigation, form submission Capybara

The component and view unit tests are fast — no browser, no HTTP, just Ruby objects. Save system tests for the flows that matter most.

Exercise

Write unit tests for Views::Boards::Index:

  1. Empty state renders when boards: is empty
  2. Board names render when boards are present
  3. The “New Board” link is present

Module 4 summary

  • bundle add phlex-rails and rails generate phlex:install sets up the Views:: and Components:: namespaces with Zeitwerk autoloading
  • Remove all require_relative from component files — Zeitwerk handles loading
  • Two approaches: full Phlex (greenfield, all ERB deleted) or hybrid (ERB + Phlex components, best for migration)
  • Hybrid is a legitimate long-term architecture and the recommended migration path for existing apps
  • Three layout approaches: composition, inheritance via around_template, and legacy ERB compatibility — KanbanFlow uses around_template
  • layout false in ApplicationController disables Rails’ built-in layout system
  • Controllers render views explicitly: render Views::Boards::Index.new(boards:)
  • No implicit instance variables — data is passed through initialize
  • Rails helpers use adapters — include only what you need, starting with Phlex::Rails::Helpers::Routes
  • Never include Rails helper modules directly — use adapters or register_value_helper / register_output_helper
  • bin/dev runs Rails server and Tailwind watcher together
  • Component unit tests work as in Module 3; add a view context for components that use Rails helpers

KanbanFlow built this module

  • Components::Layouts::AppLayout — full application shell
  • Views::Boards::Index — board listing with empty state
  • Views::Boards::Show — placeholder
  • Components::EmptyState — reusable empty state component
  • All Phlex::UI components restyled with Tailwind