Repository: phoenixframework/phoenix
Pull request #5428 (2023-04-20 17:35:37)

Update listings in testing controllers guide
 to match a phoenix 1.7.2 project


Patch:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 22f49c5a1..3a0c4a57d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -14,7 +14,7 @@ Use the issues tracker for:
 Please **do not** use the issue tracker for personal support requests nor feature requests. Support requests should be sent to:
 
 * The [phoenix-talk mailing list](https://groups.google.com/group/phoenix-talk) (closed in favor of forum, but archive is still online)
-* [The Phoenix subforum on the Elixir forum](https://elixirforum.com/c/phoenix-forum)
+* [The Phoenix subforum on the Elixir Forum](https://elixirforum.com/c/phoenix-forum)
 * **[#elixir](irc://irc.libera.chat/elixir)** on [Libera](https://libera.chat/) IRC
 
 Development issues can be discussed on the [phoenix-core mailing list](https://groups.google.com/group/phoenix-core).
diff --git a/README.md b/README.md
index db46c1536..06e3b1ff3 100644
--- a/README.md
+++ b/README.md
@@ -83,7 +83,7 @@ npm install
 
   [1]: https://web.libera.chat/?channels=#elixir
   [2]: https://libera.chat/
-  [3]: https://elixir-slackin.herokuapp.com/
+  [3]: https://elixir-lang.slack.com/join/shared_invite/zt-1f13hz7mb-N4KGjF523ONLCcHfb8jYgA#/shared-invite/email
   [4]: https://github.com/phoenixframework/phoenix/issues
   [5]: https://elixirforum.com/c/phoenix-forum
   [6]: https://groups.google.com/group/phoenix-core
diff --git a/guides/deployment/gigalixir.md b/guides/deployment/gigalixir.md
index 5cdf45d50..48667955d 100644
--- a/guides/deployment/gigalixir.md
+++ b/guides/deployment/gigalixir.md
@@ -189,4 +189,4 @@ For custom domains, scaling, jobs and other features, see the [Gigalixir Documen
 
 See [Troubleshooting](https://gigalixir.readthedocs.io/en/latest/troubleshooting.html)
 
-Also, don't hesitate to email [help@gigalixir.com](mailto:help@gigalixir.com) or [request an invitation](https://elixir-slackin.herokuapp.com/) and join the #gigalixir channel on [Slack](https://elixir-lang.slack.com).
+Also, don't hesitate to email [help@gigalixir.com](mailto:help@gigalixir.com) or [request an invitation](https://elixir-lang.slack.com/join/shared_invite/zt-1f13hz7mb-N4KGjF523ONLCcHfb8jYgA#/shared-invite/email) and join the #gigalixir channel on [Slack](https://elixir-lang.slack.com).
diff --git a/guides/howto/using_ssl.md b/guides/howto/using_ssl.md
index 93183c75c..8af2f7456 100644
--- a/guides/howto/using_ssl.md
+++ b/guides/howto/using_ssl.md
@@ -4,7 +4,7 @@ To prepare an application to serve requests over SSL, we need to add a little bi
 
 The configuration consists of a new `https:` key for our endpoint whose value is a keyword list of port, path to the key file, and path to the cert (PEM) file. If we add the `otp_app:` key whose value is the name of our application, Plug will begin to look for them at the root of our application. We can then put those files in our `priv` directory and set the paths to `priv/our_keyfile.key` and `priv/our_cert.crt`.
 
-Here's an example configuration from `config/prod.exs`.
+Here's an example configuration from `config/runtime.exs`.
 
 ```elixir
 import Config
diff --git a/guides/introduction/community.md b/guides/introduction/community.md
index 9cc142369..b6f0b52a5 100644
--- a/guides/introduction/community.md
+++ b/guides/introduction/community.md
@@ -6,7 +6,7 @@ There are a number of places to connect with community members at all experience
 
   * We're on Libera IRC in the [\#elixir](https://web.libera.chat/?channels=#elixir) channel.
 
-  * [Request an invitation](https://elixir-slackin.herokuapp.com/) and join the #phoenix channel on [Slack](https://elixir-lang.slack.com).
+  * [Request an invitation](https://elixir-lang.slack.com/join/shared_invite/zt-1f13hz7mb-N4KGjF523ONLCcHfb8jYgA#/shared-invite/email) and join the #phoenix channel on [Slack](https://elixir-lang.slack.com).
 
   * Feel free to join and check out the #phoenix channel on [Discord](https://discord.gg/elixir).
 
diff --git a/guides/routing.md b/guides/routing.md
index 34bb02ef2..b2690a591 100644
--- a/guides/routing.md
+++ b/guides/routing.md
@@ -519,7 +519,7 @@ defmodule HelloWeb.Router do
 end
 ```
 
-The above assumes there is a plug called `MyApp.Authentication` that performs authentication and is now part of the `:auth` pipeline.
+The above assumes there is a plug called `HelloWeb.Authentication` that performs authentication and is now part of the `:auth` pipeline.
 
 Note that pipelines themselves are plugs, so we can plug a pipeline inside another pipeline. For example, we could rewrite the `review_checks` pipeline above to automatically invoke `browser`, simplifying the downstream pipeline call:
 
diff --git a/installer/templates/phx_web/controllers/page_html/home.html.heex b/installer/templates/phx_web/controllers/page_html/home.html.heex
index 3c8152790..3a5917f9f 100644
--- a/installer/templates/phx_web/controllers/page_html/home.html.heex
+++ b/installer/templates/phx_web/controllers/page_html/home.html.heex
@@ -159,22 +159,7 @@
               >
                 <path d="M8 13.833c3.866 0 7-2.873 7-6.416C15 3.873 11.866 1 8 1S1 3.873 1 7.417c0 1.081.292 2.1.808 2.995.606 1.05.806 2.399.086 3.375l-.208.283c-.285.386-.01.905.465.85.852-.098 2.048-.318 3.137-.81a3.717 3.717 0 0 1 1.91-.318c.263.027.53.041.802.041Z" />
               </svg>
-              Discuss on the Elixir forum
-            </a>
-          </div>
-          <div>
-            <a
-              href="https://elixir-slackin.herokuapp.com"
-              class="group -mx-2 -my-0.5 inline-flex items-center gap-3 rounded-lg px-2 py-0.5 hover:bg-zinc-50 hover:text-zinc-900"
-            >
-              <svg
-                viewBox="0 0 16 16"
-                aria-hidden="true"
-                class="h-4 w-4 fill-zinc-400 group-hover:fill-zinc-600"
-              >
-                <path d="M3.95 9.85a1.47 1.47 0 1 1-2.94 0 1.47 1.47 0 0 1 1.47-1.472h1.47v1.471Zm.735 0a1.47 1.47 0 1 1 2.94 0v3.678a1.47 1.47 0 1 1-2.94 0V9.85ZM6.156 3.942a1.47 1.47 0 0 1-1.47-1.472 1.47 1.47 0 1 1 2.94 0v1.472h-1.47Zm0 .747c.813 0 1.47.658 1.47 1.471a1.47 1.47 0 0 1-1.47 1.472H2.47A1.47 1.47 0 0 1 1 6.16 1.47 1.47 0 0 1 2.47 4.69h3.686ZM12.048 6.16a1.47 1.47 0 1 1 2.94 0 1.47 1.47 0 0 1-1.47 1.472h-1.47V6.16Zm-.735 0a1.47 1.47 0 1 1-2.94 0V2.47a1.47 1.47 0 1 1 2.94 0v3.69ZM9.843 12.057c.813 0 1.47.657 1.47 1.471a1.47 1.47 0 1 1-2.94 0v-1.471h1.47Zm0-.736a1.47 1.47 0 0 1-1.47-1.472 1.47 1.47 0 0 1 1.47-1.471h3.686c.813 0 1.47.658 1.47 1.471a1.47 1.47 0 0 1-1.47 1.472H9.843Z" />
-              </svg>
-              Join our Slack channel
+              Discuss on the Elixir Forum
             </a>
           </div>
           <div>
diff --git a/lib/phoenix/code_reloader.ex b/lib/phoenix/code_reloader.ex
index 9aeb034fe..931a7ccc5 100644
--- a/lib/phoenix/code_reloader.ex
+++ b/lib/phoenix/code_reloader.ex
@@ -30,17 +30,22 @@ defmodule Phoenix.CodeReloader do
   applications from library dependencies.
 
   This function is a no-op and returns `:ok` if Mix is not available.
+
+  ## Options
+
+    * `:reloadable_args` - additional CLI args to pass to the compiler tasks
+
   """
-  @spec reload(module) :: :ok | {:error, binary()}
-  def reload(endpoint) do
-    if Code.ensure_loaded?(Mix.Project), do: reload!(endpoint), else: :ok
+  @spec reload(module, keyword) :: :ok | {:error, binary()}
+  def reload(endpoint, opts \\ []) do
+    if Code.ensure_loaded?(Mix.Project), do: reload!(endpoint, opts), else: :ok
   end
 
   @doc """
   Same as `reload/1` but it will raise if Mix is not available.
   """
-  @spec reload!(module) :: :ok | {:error, binary()}
-  defdelegate reload!(endpoint), to: Phoenix.CodeReloader.Server
+  @spec reload!(module, keyword) :: :ok | {:error, binary()}
+  defdelegate reload!(endpoint, opts), to: Phoenix.CodeReloader.Server
 
   @doc """
   Synchronizes with the code server if it is alive.
diff --git a/lib/phoenix/code_reloader/proxy.ex b/lib/phoenix/code_reloader/proxy.ex
index fc203606f..2ada872bf 100644
--- a/lib/phoenix/code_reloader/proxy.ex
+++ b/lib/phoenix/code_reloader/proxy.ex
@@ -8,18 +8,26 @@ defmodule Phoenix.CodeReloader.Proxy do
     GenServer.start(__MODULE__, :ok)
   end
 
+  def diagnostics(proxy, diagnostics) do
+    GenServer.cast(proxy, {:diagnostics, diagnostics})
+  end
+
   def stop(proxy) do
-    GenServer.call(proxy, :stop)
+    GenServer.call(proxy, :stop, :infinity)
   end
 
   ## Callbacks
 
   def init(:ok) do
-    {:ok, ""}
+    {:ok, []}
+  end
+
+  def handle_cast({:diagnostics, diagnostics}, output) do
+    {:noreply, diagnostics |> Enum.map(&diagnostic_to_chars/1) |> Enum.reverse(output)}
   end
 
   def handle_call(:stop, _from, output) do
-    {:stop, :normal, output, output}
+    {:stop, :normal, Enum.reverse(output), output}
   end
 
   def handle_info(msg, output) do
@@ -47,6 +55,18 @@ defmodule Phoenix.CodeReloader.Proxy do
 
   defp put_chars(from, reply, chars, output) do
     send(Process.group_leader(), {:io_request, from, reply, {:put_chars, chars}})
-    {:noreply, output <> IO.chardata_to_string(chars)}
+    {:noreply, [chars | output]}
   end
+
+  defp diagnostic_to_chars(%{severity: :error, message: "**" <> _ = message}) do
+    "\n#{message}\n"
+  end
+
+  defp diagnostic_to_chars(%{severity: severity, message: message, file: file, position: position}) do
+    "\n#{severity}: #{message}\n  #{Path.relative_to_cwd(file)}#{position(position)}\n"
+  end
+
+  defp position({line, col}), do: ":#{line}:#{col}"
+  defp position(line) when is_integer(line) and line > 0, do: ":#{line}"
+  defp position(_), do: ""
 end
diff --git a/lib/phoenix/code_reloader/server.ex b/lib/phoenix/code_reloader/server.ex
index 64f467b46..525c1e637 100644
--- a/lib/phoenix/code_reloader/server.ex
+++ b/lib/phoenix/code_reloader/server.ex
@@ -13,8 +13,8 @@ defmodule Phoenix.CodeReloader.Server do
     GenServer.call(__MODULE__, :check_symlinks, :infinity)
   end
 
-  def reload!(endpoint) do
-    GenServer.call(__MODULE__, {:reload!, endpoint}, :infinity)
+  def reload!(endpoint, opts) do
+    GenServer.call(__MODULE__, {:reload!, endpoint, opts}, :infinity)
   end
 
   def sync do
@@ -58,9 +58,10 @@ defmodule Phoenix.CodeReloader.Server do
     {:reply, :ok, %{state | check_symlinks: false}}
   end
 
-  def handle_call({:reload!, endpoint}, from, state) do
+  def handle_call({:reload!, endpoint, opts}, from, state) do
     compilers = endpoint.config(:reloadable_compilers)
-    reloadable_apps = endpoint.config(:reloadable_apps) || default_reloadable_apps()
+    apps = endpoint.config(:reloadable_apps) || default_reloadable_apps()
+    args = Keyword.get(opts, :reloadable_args, [])
 
     # We do a backup of the endpoint in case compilation fails.
     # If so we can bring it back to finish the request handling.
@@ -70,7 +71,7 @@ defmodule Phoenix.CodeReloader.Server do
     {res, out} =
       proxy_io(fn ->
         try do
-          mix_compile(Code.ensure_loaded(Mix.Task), compilers, reloadable_apps, state.timestamp)
+          mix_compile(Code.ensure_loaded(Mix.Task), compilers, apps, args, state.timestamp)
         catch
           :exit, {:shutdown, 1} ->
             :error
@@ -159,7 +160,7 @@ defmodule Phoenix.CodeReloader.Server do
 
   defp all_waiting(acc, endpoint) do
     receive do
-      {:"$gen_call", from, {:reload!, ^endpoint}} -> all_waiting([from | acc], endpoint)
+      {:"$gen_call", from, {:reload!, ^endpoint, _}} -> all_waiting([from | acc], endpoint)
     after
       0 -> acc
     end
@@ -174,7 +175,7 @@ defmodule Phoenix.CodeReloader.Server do
     defp purge_protocols(_path), do: :ok
   end
 
-  defp mix_compile({:module, Mix.Task}, compilers, apps_to_reload, timestamp) do
+  defp mix_compile({:module, Mix.Task}, compilers, apps_to_reload, compile_args, timestamp) do
     config = Mix.Project.config()
     path = Mix.Project.consolidation_path(config)
 
@@ -183,8 +184,8 @@ defmodule Phoenix.CodeReloader.Server do
       purge_protocols(path)
     end
 
-    mix_compile_deps(Mix.Dep.cached(), apps_to_reload, compilers, timestamp, path)
-    mix_compile_project(config[:app], apps_to_reload, compilers, timestamp, path)
+    mix_compile_deps(Mix.Dep.cached(), apps_to_reload, compile_args, compilers, timestamp, path)
+    mix_compile_project(config[:app], apps_to_reload, compile_args, compilers, timestamp, path)
 
     if config[:consolidate_protocols] do
       Code.prepend_path(path)
@@ -193,30 +194,30 @@ defmodule Phoenix.CodeReloader.Server do
     :ok
   end
 
-  defp mix_compile({:error, _reason}, _, _, _) do
+  defp mix_compile({:error, _reason}, _, _, _, _) do
     raise "the Code Reloader is enabled but Mix is not available. If you want to " <>
             "use the Code Reloader in production or inside an escript, you must add " <>
             ":mix to your applications list. Otherwise, you must disable code reloading " <>
             "in such environments"
   end
 
-  defp mix_compile_deps(deps, apps_to_reload, compilers, timestamp, path) do
+  defp mix_compile_deps(deps, apps_to_reload, compile_args, compilers, timestamp, path) do
     for dep <- deps, dep.app in apps_to_reload do
       Mix.Dep.in_dependency(dep, fn _ ->
-        mix_compile_unless_stale_config(compilers, timestamp, path)
+        mix_compile_unless_stale_config(compilers, compile_args, timestamp, path)
       end)
     end
   end
 
-  defp mix_compile_project(nil, _, _, _, _), do: :ok
+  defp mix_compile_project(nil, _, _, _, _, _), do: :ok
 
-  defp mix_compile_project(app, apps_to_reload, compilers, timestamp, path) do
+  defp mix_compile_project(app, apps_to_reload, compile_args, compilers, timestamp, path) do
     if app in apps_to_reload do
-      mix_compile_unless_stale_config(compilers, timestamp, path)
+      mix_compile_unless_stale_config(compilers, compile_args, timestamp, path)
     end
   end
 
-  defp mix_compile_unless_stale_config(compilers, timestamp, path) do
+  defp mix_compile_unless_stale_config(compilers, compile_args, timestamp, path) do
     manifests = Mix.Tasks.Compile.Elixir.manifests()
     configs = Mix.Project.config_files()
     config = Mix.Project.config()
@@ -229,7 +230,7 @@ defmodule Phoenix.CodeReloader.Server do
           purge_modules(Path.join(Mix.Project.app_path(config), "ebin"))
         end
 
-        mix_compile(compilers, config, path)
+        mix_compile(compilers, compile_args, config, path)
 
       files ->
         raise """
@@ -243,7 +244,7 @@ defmodule Phoenix.CodeReloader.Server do
     end
   end
 
-  defp mix_compile(compilers, config, consolidation_path) do
+  defp mix_compile(compilers, compile_args, config, consolidation_path) do
     all = config[:compilers] || Mix.compilers()
 
     compilers =
@@ -255,7 +256,7 @@ defmodule Phoenix.CodeReloader.Server do
     # We call build_structure mostly for Windows so new
     # assets in priv are copied to the build directory.
     Mix.Project.build_structure(config)
-    args = ["--purge-consolidation-path-if-stale", consolidation_path]
+    args = ["--purge-consolidation-path-if-stale", consolidation_path | compile_args]
     result = run_compilers(compilers, args, [])
 
     cond do
@@ -301,8 +302,8 @@ defmodule Phoenix.CodeReloader.Server do
   defp run_compilers([compiler | compilers], args, acc) do
     with {status, diagnostics} <- Mix.Task.run("compile.#{compiler}", args) do
       # Diagnostics are written to stderr and therefore not captured,
-      # so we print them to the group leader here
-      Enum.each(diagnostics, &print_diagnostic/1)
+      # so we send them to the group leader here
+      Proxy.diagnostics(Process.group_leader(), diagnostics)
       {status, diagnostics}
     end
     |> case do
@@ -319,16 +320,4 @@ defmodule Phoenix.CodeReloader.Server do
       :noop
     end
   end
-
-  defp print_diagnostic(%{severity: :error, message: "**" <> _ = message}) do
-    IO.write("\n#{message}\n")
-  end
-
-  defp print_diagnostic(%{severity: severity, message: message, file: file, position: position}) do
-    IO.write("\n#{severity}: #{message}\n  #{Path.relative_to_cwd(file)}#{position(position)}\n")
-  end
-
-  defp position({line, col}), do: ":#{line}:#{col}"
-  defp position(line) when is_integer(line) and line > 0, do: ":#{line}"
-  defp position(_), do: ""
 end
diff --git a/lib/phoenix/controller.ex b/lib/phoenix/controller.ex
index 5cc2d1315..f2f9be3f6 100644
--- a/lib/phoenix/controller.ex
+++ b/lib/phoenix/controller.ex
@@ -307,7 +307,7 @@ defmodule Phoenix.Controller do
 
         def call(conn, {:error, :unauthorized}) do
           conn
-          |> put_status(403)
+          |> put_status(:forbidden)
           |> put_view(MyErrorView)
           |> render(:"403")
         end
diff --git a/lib/phoenix/socket/transport.ex b/lib/phoenix/socket/transport.ex
index e5a99a7ce..d2e8595bb 100644
--- a/lib/phoenix/socket/transport.ex
+++ b/lib/phoenix/socket/transport.ex
@@ -291,8 +291,12 @@ defmodule Phoenix.Socket.Transport do
   Runs the code reloader if enabled.
   """
   def code_reload(conn, endpoint, opts) do
-    reload? = Keyword.get(opts, :code_reloader, endpoint.config(:code_reloader))
-    reload? && Phoenix.CodeReloader.reload(endpoint)
+    if Keyword.get(opts, :code_reloader, endpoint.config(:code_reloader)) do
+      # If the WebSocket reconnects, then often the page has already been reloaded
+      # and we don't want to print warnings twice, so we disable all warnings.
+      Phoenix.CodeReloader.reload(endpoint, reloadable_args: ~w(--no-all-warnings))
+    end
+
     conn
   end
 


Test patch:
diff --git a/guides/testing/testing_controllers.md b/guides/testing/testing_controllers.md
index 1303513f4..b406dd1be 100644
--- a/guides/testing/testing_controllers.md
+++ b/guides/testing/testing_controllers.md
@@ -20,15 +20,17 @@ If you open up `test/hello_web/controllers/post_controller_test.exs`, you will f
 defmodule HelloWeb.PostControllerTest do
   use HelloWeb.ConnCase
 
-  alias Hello.Blog
+  import Hello.BlogFixtures
 
   @create_attrs %{body: "some body", title: "some title"}
   @update_attrs %{body: "some updated body", title: "some updated title"}
   @invalid_attrs %{body: nil, title: nil}
-
-  def fixture(:post) do
-    {:ok, post} = Blog.create_post(@create_attrs)
-    post
+  
+  describe "index" do
+    test "lists all posts", %{conn: conn} do
+      conn = get(conn, ~p"/posts")
+      assert html_response(conn, 200) =~ "Listing Posts"
+    end
   end
 
   ...
@@ -43,7 +45,7 @@ The first describe block is for the `index` action. The action itself is impleme
 ```elixir
 def index(conn, _params) do
   posts = Blog.list_posts()
-  render(conn, "index.html", posts: posts)
+  render(conn, :index, posts: posts)
 end
 ```
 
@@ -75,7 +77,7 @@ def create(conn, %{"post" => post_params}) do
       |> redirect(to: ~p"/posts/#{post}")
 
     {:error, %Ecto.Changeset{} = changeset} ->
-      render(conn, "new.html", changeset: changeset)
+      render(conn, :new, changeset: changeset)
   end
 end
 ```
@@ -91,7 +93,7 @@ describe "create post" do
     assert redirected_to(conn) == ~p"/posts/#{id}"
 
     conn = get(conn, ~p"/posts/#{id}")
-    assert html_response(conn, 200) =~ "Show Post"
+    assert html_response(conn, 200) =~ "Post #{id}"
   end
 
   test "renders errors when data is invalid", %{conn: conn} do
@@ -154,6 +156,7 @@ The test is written like this:
     test "deletes chosen post", %{conn: conn, post: post} do
       conn = delete(conn, ~p"/posts/#{post}")
       assert redirected_to(conn) == ~p"/posts"
+
       assert_error_sent 404, fn ->
         get(conn, ~p"/posts/#{post}")
       end
@@ -161,7 +164,7 @@ The test is written like this:
   end
 
   defp create_post(_) do
-    post = fixture(:post)
+    post = post_fixture()
     %{post: post}
   end
 ```
@@ -190,7 +193,7 @@ This pretty much mimics how Phoenix handles exceptions. For example, when we acc
 ```elixir
 def show(conn, %{"id" => id}) do
   post = Blog.get_post!(id)
-  render(conn, "show.html", post: post)
+  render(conn, :show, post: post)
 end
 ```
 
@@ -220,19 +223,19 @@ $ mix phx.gen.json News Article articles title body
 
 We chose a very similar concept to the Blog context <-> Post schema, except we are using a different name, so we can study these concepts in isolation.
 
-After you run the command above, do not forget to follow the final steps output by the generator. Once all is done, we should run `mix test` and now have 33 passing tests:
+After you run the command above, do not forget to follow the final steps output by the generator. Once all is done, we should run `mix test` and now have 35 passing tests:
 
 ```console
 $ mix test
 ................
 
 Finished in 0.6 seconds
-33 tests, 0 failures
+35 tests, 0 failures
 
 Randomized with seed 618478
 ```
 
-You may have noticed that this time the scaffold controller has generated fewer tests. Previously it generated 16 (we went from 3 to 19) and now it generated 14 (we went from 19 to 33). That's because JSON APIs do not need to expose the `new` and `edit` actions. We can see this is the case in the resource we have added to the router at the end of the `mix phx.gen.json` command:
+You may have noticed that this time the scaffold controller has generated fewer tests. Previously it generated 16 (we went from 5 to 21) and now it generated 14 (we went from 21 to 35). That's because JSON APIs do not need to expose the `new` and `edit` actions. We can see this is the case in the resource we have added to the router at the end of the `mix phx.gen.json` command:
 
 ```elixir
 resources "/articles", ArticleController, except: [:new, :edit]
@@ -259,16 +262,17 @@ The action gets all articles and renders the index template. Since we are talkin
 
 ```elixir
 defmodule HelloWeb.ArticleJSON do
+  alias Hello.News.Article
 
   def index(%{articles: articles}) do
-    %{data: for(article <- article, do: data(article))}
+    %{data: for(article <- articles, do: data(article))}
   end
 
   def show(%{article: article}) do
-    %{data: data(article)
+    %{data: data(article)}
   end
 
-  defp data(article) do
+  defp data(%Article{} = article) do
     %{
       id: article.id,
       title: article.title,
@@ -285,7 +289,7 @@ Let's take a look at the test for the `index` action then:
 ```elixir
 describe "index" do
   test "lists all articles", %{conn: conn} do
-    conn = get(conn, ~p"/articles")
+    conn = get(conn, ~p"/api/articles")
     assert json_response(conn, 200)["data"] == []
   end
 end
@@ -304,7 +308,7 @@ def create(conn, %{"article" => article_params}) do
   with {:ok, %Article{} = article} <- News.create_article(article_params) do
     conn
     |> put_status(:created)
-    |> put_resp_header("location", ~p"/articles/#{article}")
+    |> put_resp_header("location", ~p"/api/articles/#{article}")
     |> render(:show, article: article)
   end
 end
@@ -315,15 +319,15 @@ As we can see, it checks if an article could be created. If so, it sets the stat
 This is precisely what the first test for the `create` action verifies:
 
 ```elixir
-describe "create" do
+describe "create article" do
   test "renders article when data is valid", %{conn: conn} do
     conn = post(conn, ~p"/articles", article: @create_attrs)
     assert %{"id" => id} = json_response(conn, 201)["data"]
 
-    conn = get(conn, ~p"/articles/#{id}")
+    conn = get(conn, ~p"/api/articles/#{id}")
 
     assert %{
-             "id" => id,
+             "id" => ^id,
              "body" => "some body",
              "title" => "some title"
            } = json_response(conn, 200)["data"]
@@ -332,7 +336,7 @@ describe "create" do
 
 The test uses `post/2` to create a new article and then we verify that the article returned a JSON response, with status 201, and that it had a "data" key in it. We pattern match the "data" on `%{"id" => id}`, which allows us to extract the ID of the new article. Then we perform a `get/2` request on the `show` route and verify that the article was successfully created.
 
-Inside `describe "create"`, we will find another test, which handles the failure scenario. Can you spot the failure scenario in the `create` action? Let's recap it:
+Inside `describe "create article"`, we will find another test, which handles the failure scenario. Can you spot the failure scenario in the `create` action? Let's recap it:
 
 ```elixir
 def create(conn, %{"article" => article_params}) do
@@ -363,7 +367,7 @@ defmodule HelloWeb.FallbackController do
   def call(conn, {:error, :not_found}) do
     conn
     |> put_status(:not_found)
-    |> put_view(json: HelloWeb.ErrorJSON)
+    |> put_view(html: HelloWeb.ErrorHTML, json: HelloWeb.ErrorJSON)
     |> render(:"404")
   end
 end
@@ -375,7 +379,7 @@ With this in mind, let's look at our second test for `create`:
 
 ```elixir
 test "renders errors when data is invalid", %{conn: conn} do
-  conn = post(conn, ~p"/articles", article: @invalid_attrs)
+  conn = post(conn, ~p"/api/articles", article: @invalid_attrs)
   assert json_response(conn, 422)["errors"] != %{}
 end
 ```
@@ -407,17 +411,17 @@ describe "delete article" do
   setup [:create_article]
 
   test "deletes chosen article", %{conn: conn, article: article} do
-    conn = delete(conn, ~p"/articles/#{article}")
+    conn = delete(conn, ~p"/api/articles/#{article}")
     assert response(conn, 204)
 
     assert_error_sent 404, fn ->
-      get(conn, ~p"/articles/#{article}")
+      get(conn, ~p"/api/articles/#{article}")
     end
   end
 end
 
 defp create_article(_) do
-  article = fixture(:article)
+  article = article_fixture()
   %{article: article}
 end
 ```
diff --git a/test/phoenix/code_reloader_test.exs b/test/phoenix/code_reloader_test.exs
index fc80efc2d..70b5d0cfe 100644
--- a/test/phoenix/code_reloader_test.exs
+++ b/test/phoenix/code_reloader_test.exs
@@ -3,13 +3,8 @@ defmodule Phoenix.CodeReloaderTest do
   use RouterHelper
 
   defmodule Endpoint do
-    def config(:reloadable_compilers) do
-      [:unknown_compiler, :elixir]
-    end
-
-    def config(:reloadable_apps) do
-      nil
-    end
+    def config(:reloadable_compilers), do: [:unknown_compiler, :elixir]
+    def config(:reloadable_apps), do: nil
   end
 
   def reload(_) do
@@ -48,7 +43,7 @@ defmodule Phoenix.CodeReloaderTest do
            |> Phoenix.CodeReloader.call(opts)
     assert conn.state == :unset
 
-    assert_receive {:trace, ^pid, :receive, {_, _, {:reload!, Endpoint}}}
+    assert_receive {:trace, ^pid, :receive, {_, _, {:reload!, Endpoint, _}}}
   end
 
   test "renders compilation error on failure" do