Skip to content

Commit

Permalink
Action Mailer Preview empty states
Browse files Browse the repository at this point in the history
When an application defines mailers without any corresponding previews,
requests to `GET /rails/mailers` return a page with a blank `<body>`
element.

This entirely empty page can be confusing, since it's difficult to
distinguish the "success" state with an empty list and a "failure" state
with swallowed errors.

Similarly, when an `ActionMailer::Preview` subclass is defined, but
doesn't declare any actions, the response contains a mostly empty page.

This commit renders empty-state messaging for both scenarios, and links
to the [Action Mailer Basics][] guides.

To effectively cover that behavior, this commit also expands the Mailer
Preview test coverage to utilize [rails-dom-testing][] assertions.

[Action Mailer Basics]: https://guides.rubyonrails.org/action_mailer_basics.html#previewing-emails
[rails-dom-testing]: http://github.com/rails/rails-dom-testing
  • Loading branch information
seanpdoyle committed Aug 4, 2023
1 parent a167350 commit c4b67ec
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 14 deletions.
4 changes: 2 additions & 2 deletions railties/lib/rails/mailers_controller.rb
Expand Up @@ -15,7 +15,7 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc:

def index
@previews = ActionMailer::Preview.all
@page_title = "Mailer Previews"
@page_title = "Action Mailer Previews"
end

def download
Expand All @@ -30,7 +30,7 @@ def download

def preview
if params[:path] == @preview.preview_name
@page_title = "Mailer Previews for #{@preview.preview_name}"
@page_title = "Action Mailer Previews for #{@preview.preview_name}"
render action: "mailer"
else
@email_action = File.basename(params[:path])
Expand Down
21 changes: 14 additions & 7 deletions railties/lib/rails/templates/rails/mailers/index.html.erb
@@ -1,8 +1,15 @@
<% @previews.each do |preview| %>
<h3><%= link_to preview.preview_name.titleize, url_for(controller: "rails/mailers", action: "preview", path: preview.preview_name) %></h3>
<ul>
<% preview.emails.each do |email| %>
<li><%= link_to email, url_for(controller: "rails/mailers", action: "preview", path: "#{preview.preview_name}/#{email}") %></li>
<% end %>
</ul>
<h1><%= @page_title %></h1>

<% if @previews.any? %>
<% @previews.each do |preview| %>
<h3><%= link_to preview.preview_name.titleize, url_for(controller: "rails/mailers", action: "preview", path: preview.preview_name) %></h3>
<ul>
<% preview.emails.each do |email| %>
<li><%= link_to email, url_for(controller: "rails/mailers", action: "preview", path: "#{preview.preview_name}/#{email}") %></li>
<% end %>
</ul>
<% end %>
<% else %>
<p>You have not defined any Action Mailer Previews.</p>
<p>Read <%= link_to "Action Mailer Basics", "https://guides.rubyonrails.org/action_mailer_basics.html#previewing-emails" %> to learn how to define your first.</p>
<% end %>
16 changes: 11 additions & 5 deletions railties/lib/rails/templates/rails/mailers/mailer.html.erb
@@ -1,6 +1,12 @@
<h3><%= @preview.preview_name.titleize %></h3>
<ul>
<% @preview.emails.each do |email| %>
<li><%= link_to email, url_for(controller: "rails/mailers", action: "preview", path: "#{@preview.preview_name}/#{email}") %></li>
<h1><%= @page_title %></h1>

<% if @preview.emails.any? %>
<ul>
<% @preview.emails.each do |email| %>
<li><%= link_to email, url_for(controller: "rails/mailers", action: "preview", path: "#{@preview.preview_name}/#{email}") %></li>
<% end %>
</ul>
<% else %>
<p>You have not defined any actions for <%= @preview %>.</p>
<p>Read <%= link_to "Action Mailer Basics", "https://guides.rubyonrails.org/action_mailer_basics.html#previewing-emails" %> to learn how to define your first.</p>
<% end %>
</ul>
68 changes: 68 additions & 0 deletions railties/test/application/mailer_previews_test.rb
Expand Up @@ -3,12 +3,14 @@
require "isolation/abstract_unit"
require "rack/test"
require "base64"
require "rails-dom-testing"

module ApplicationTests
class MailerPreviewsTest < ActiveSupport::TestCase
include ActiveSupport::Testing::Isolation
include Rack::Test::Methods
include ERB::Util
include Rails::Dom::Testing::Assertions

def setup
build_app
Expand Down Expand Up @@ -55,6 +57,18 @@ def teardown
assert_equal 200, last_response.status
end

test "request without mailer previews links to documentation" do
app("development")

get "/rails/mailers"
assert_select "title", text: "Action Mailer Previews"
assert_select "h1", text: "Action Mailer Previews"
assert_select "p", text: "You have not defined any Action Mailer Previews."
assert_select "p", text: "Read Action Mailer Basics to learn how to define your first." do
assert_select "a[href=?]", "https://guides.rubyonrails.org/action_mailer_basics.html#previewing-emails", text: "Action Mailer Basics"
end
end

test "mailer previews are loaded from the default preview_paths" do
mailer "notifier", <<-RUBY
class Notifier < ActionMailer::Base
Expand All @@ -81,6 +95,8 @@ def foo
app("development")

get "/rails/mailers"
assert_select "title", text: "Action Mailer Previews"
assert_select "h1", text: "Action Mailer Previews"
assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body
assert_match '<li><a href="/rails/mailers/notifier/foo">foo</a></li>', last_response.body
end
Expand Down Expand Up @@ -320,6 +336,54 @@ def foo
assert_no_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body
end

test "mailer without previews" do
mailer "notifier", <<-RUBY
class Notifier < ActionMailer::Base
end
RUBY

mailer_preview "notifier", <<-RUBY
class NotifierPreview < ActionMailer::Preview
end
RUBY

app("development")
get "/rails/mailers/notifier"

assert_predicate last_response, :ok?
assert_select "title", text: "Action Mailer Previews for notifier"
assert_select "h1", text: "Action Mailer Previews for notifier"
assert_select "p", text: "You have not defined any actions for NotifierPreview."
assert_select "p", text: "Read Action Mailer Basics to learn how to define your first." do
assert_select "a[href=?]", "https://guides.rubyonrails.org/action_mailer_basics.html#previewing-emails", text: "Action Mailer Basics"
end
end

test "mailer with previews" do
mailer "notifier", <<-RUBY
class Notifier < ActionMailer::Base
def foo
end
end
RUBY

mailer_preview "notifier", <<-RUBY
class NotifierPreview < ActionMailer::Preview
def foo
Notifier.foo
end
end
RUBY

app("development")
get "/rails/mailers/notifier"

assert_predicate last_response, :ok?
assert_select "title", text: "Action Mailer Previews for notifier"
assert_select "h1", text: "Action Mailer Previews for notifier"
assert_select "ul li a[href=?]", "/rails/mailers/notifier/foo"
end

test "mailer preview not found" do
app("development")
get "/rails/mailers/notifier"
Expand Down Expand Up @@ -967,6 +1031,10 @@ def build_app
app_dir "test/mailers/previews"
end

def document_root_element
Nokogiri::HTML5.parse(last_response.body)
end

def mailer(name, contents)
app_file("app/mailers/#{name}.rb", contents)
end
Expand Down

0 comments on commit c4b67ec

Please sign in to comment.