Repository: phoenixframework/phoenix
Pull request #5382 (2023-03-24 05:00:49)

Change Hero Icons to Heroicons
Use the spelling that is used by the Tailwind/Heroicons team: https://tailwindcss.com/docs/stroke-width#setting-the-stroke-width


Patch:
diff --git a/.gitignore b/.gitignore
index 5d4b3de37..459b4dbf2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@
 /doc/
 /node_modules/
 /tmp/
+/cover/
 
 /assets/node_modules/
 
diff --git a/guides/asset_management.md b/guides/asset_management.md
index 6088e3a16..9a4ddaa92 100644
--- a/guides/asset_management.md
+++ b/guides/asset_management.md
@@ -89,55 +89,54 @@ $ yarn add ../deps/phoenix ../deps/phoenix_html ../deps/phoenix_live_view
 Next, add a custom JavaScript build script. We'll call the example `assets/build.js`:
 
 ```js
-const esbuild = require('esbuild')
+const esbuild = require("esbuild");
 
-const args = process.argv.slice(2)
-const watch = args.includes('--watch')
-const deploy = args.includes('--deploy')
+const args = process.argv.slice(2);
+const watch = args.includes('--watch');
+const deploy = args.includes('--deploy');
 
 const loader = {
   // Add loaders for images/fonts/etc, e.g. { '.svg': 'file' }
-}
+};
 
 const plugins = [
   // Add and configure plugins here
-]
+];
 
+// Define esbuild options
 let opts = {
-  entryPoints: ['js/app.js'],
+  entryPoints: ["js/app.js"],
   bundle: true,
-  target: 'es2017',
-  outdir: '../priv/static/assets',
-  logLevel: 'info',
-  loader,
-  plugins
-}
-
-if (watch) {
-  opts = {
-    ...opts,
-    watch,
-    sourcemap: 'inline'
-  }
-}
+  logLevel: "info",
+  target: "es2017",
+  outdir: "../priv/static/assets",
+  external: ["*.css", "fonts/*", "images/*"],
+  loader: loader,
+  plugins: plugins,
+};
 
 if (deploy) {
   opts = {
     ...opts,
-    minify: true
-  }
+    minify: true,
+  };
 }
 
-const promise = esbuild.build(opts)
-
 if (watch) {
-  promise.then(_result => {
-    process.stdin.on('close', () => {
-      process.exit(0)
+  opts = {
+    ...opts,
+    sourcemap: "inline",
+  };
+  esbuild
+    .context(opts)
+    .then((ctx) => {
+      ctx.watch();
     })
-
-    process.stdin.resume()
-  })
+    .catch((_error) => {
+      process.exit(1);
+    });
+} else {
+  esbuild.build(opts);
 }
 ```
 
diff --git a/guides/components.md b/guides/components.md
index e62c3ef6c..4fa8e65a2 100644
--- a/guides/components.md
+++ b/guides/components.md
@@ -4,7 +4,7 @@
 
 > **Requirement**: This guide expects that you have gone through the [request life-cycle guide](request_lifecycle.html).
 
-The Phoenix endpoint pipeline takes a request, routes it to a controller, and calls a view module to render a template. The view interface from the controller is simple – the controller calls a view function with the connections assigns, and the functions job is to return a HEEx template. We call any function that accepts an `assigns` parameter and returns a HEEx template to be a *function component*. Function components are defined with the help of the [`Phoenix.Component`](https://hexdocs.pm/phoenix_live_view/Phoenix.Component.html) module.
+The Phoenix endpoint pipeline takes a request, routes it to a controller, and calls a view module to render a template. The view interface from the controller is simple – the controller calls a view function with the connections assigns, and the function's job is to return a HEEx template. We call any function that accepts an `assigns` parameter and returns a HEEx template a *function component*. Function components are defined with the help of the [`Phoenix.Component`](https://hexdocs.pm/phoenix_live_view/Phoenix.Component.html) module.
 
 Function components are the essential building block for any kind of markup-based template rendering you'll perform in Phoenix. They serve as a shared abstraction for the standard MVC controller-based applications, LiveView applications, layouts, and smaller UI definitions you'll use throughout other templates.
 
@@ -219,9 +219,9 @@ In a new Phoenix application, you will also find a `core_components.ex` module i
 
 If you look inside `def html` in `HelloWeb` placed at `lib/hello_web.ex`, you will see that `CoreComponents` are automatically imported into all HTML views via `use HelloWeb, :html`. This is also the reason why `CoreComponents` itself performs `use Phoenix.Component` instead `use HelloWeb, :html` at the top: doing the latter would cause a deadlock as we would try to import `CoreComponents` into itself.
 
-CoreComponents also play an important role in Phoenix code generators, as the code generator assume those components are available in order to quickly scaffold your application. In case you want to learn more about all of these pieces, you may:
+CoreComponents also play an important role in Phoenix code generators, as the code generators assume those components are available in order to quickly scaffold your application. In case you want to learn more about all of these pieces, you may:
 
-  * Exploring the generated `CoreComponents` module to learn more from practical examples
+  * Explore the generated `CoreComponents` module to learn more from practical examples
 
   * Read the official documentation for [`Phoenix.Component`](https://hexdocs.pm/phoenix_live_view/Phoenix.Component.html)
 
diff --git a/guides/json_and_apis.md b/guides/json_and_apis.md
index e831f682c..e5f6aa247 100644
--- a/guides/json_and_apis.md
+++ b/guides/json_and_apis.md
@@ -258,7 +258,7 @@ With this knowledge in hand, we can explore the `FallbackController` (`lib/hello
     conn
     |> put_status(:unprocessable_entity)
     |> put_view(json: HelloWeb.ChangesetJSON)
-    |> render("error.json", changeset: changeset)
+    |> render(:error, changeset: changeset)
   end
 ```
 
@@ -272,7 +272,7 @@ defmodule HelloWeb.ChangesetJSON do
   def error(%{changeset: changeset}) do
     # When encoded, the changeset returns its errors
     # as a JSON object. So we just pass it forward.
-    %{errors: Ecto.Changeset.traverse_errors(changeset, &HelloWeb.CoreComponents.translate_error/1)}
+    %{errors: Ecto.Changeset.traverse_errors(changeset, &translate_error/1)}
   end
 end
 ```
@@ -316,12 +316,22 @@ mix help phx.new
 The output should contain the following:
 
 ```text
-  • --no-assets - do not generate the assets folder
+  • --no-assets - equivalent to --no-esbuild and --no-tailwind
+  • --no-dashboard - do not include Phoenix.LiveDashboard
   • --no-ecto - do not generate Ecto files
-  • --no-html - do not generate HTML views
+  • --no-esbuild - do not include esbuild dependencies and
+    assets. We do not recommend setting this option, unless for API
+    only applications, as doing so requires you to manually add and
+    track JavaScript dependencies
   • --no-gettext - do not generate gettext files
-  • --no-dashboard - do not include Phoenix.LiveDashboard
+  • --no-html - do not generate HTML views
+  • --no-live - comment out LiveView socket setup in
+    assets/js/app.js. Automatically disabled if --no-html is given
   • --no-mailer - do not generate Swoosh mailer files
+  • --no-tailwind - do not include tailwind dependencies and
+    assets. The generated markup will still include Tailwind CSS
+    classes, those are left-in as reference for the subsequent
+    styling of your layout and components
 ```
 
 The `--no-html` is the obvious one we want to use when creating any Phoenix application for an API in order to leave out all the unnecessary HTML scaffolding. You may also pass `--no-assets`, if you don't want any of the asset management bit, `--no-gettext` if you don't support internationalization, and so on.
diff --git a/guides/mix_tasks.md b/guides/mix_tasks.md
index 810e15fff..16035a673 100644
--- a/guides/mix_tasks.md
+++ b/guides/mix_tasks.md
@@ -408,8 +408,10 @@ Before we run this task let's inspect the contents of two directories in our hel
 First `priv/static/` which should look similar to this:
 
 ```console
-├── images
-│   └── phoenix.png
+├── assets
+│   ├── app.css
+│   └── app.js
+├── favicon.ico
 └── robots.txt
 ```
 
@@ -417,11 +419,12 @@ And then `assets/` which should look similar to this:
 
 ```console
 ├── css
-│   └── app.css
+│   └── app.css
 ├── js
-│   └── app.js
+│   └── app.js
+├── tailwind.config.js
 └── vendor
-    └── phoenix.js
+    └── topbar.js
 ```
 
 All of these files are our static assets. Now let's run the `mix phx.digest` task.
diff --git a/guides/plug.md b/guides/plug.md
index 16774d093..469a9b0e5 100644
--- a/guides/plug.md
+++ b/guides/plug.md
@@ -116,7 +116,7 @@ defmodule HelloWeb.Router do
 
 In the [`init/1`] callback, we pass a default locale to use if none is present in the params. We also use pattern matching to define multiple [`call/2`] function heads to validate the locale in the params, and fall back to `"en"` if there is no match. The [`assign/3`] is a part of the `Plug.Conn` module and it's how we store values in the `conn` data structure.
 
-To see the assign in action, go to the template in `lib/hello_web/components/layouts/home.html.heex` and add the following code after the closing of the `</h1>` tag:
+To see the assign in action, go to the template in `lib/hello_web/controllers/page_html/home.html.heex` and add the following code after the closing of the `</h1>` tag:
 
 ```heex
 <p>Locale: <%= @locale %></p>
diff --git a/installer/templates/phx_assets/heroicons/UPGRADE.md b/installer/templates/phx_assets/heroicons/UPGRADE.md
index d8fdb1cf9..5a140b982 100644
--- a/installer/templates/phx_assets/heroicons/UPGRADE.md
+++ b/installer/templates/phx_assets/heroicons/UPGRADE.md
@@ -3,4 +3,4 @@ where your `HERO_VSN` export is your desired version:
 
     export HERO_VSN="2.0.16" ; \
       curl -L "https://github.com/tailwindlabs/heroicons/archive/refs/tags/v${HERO_VSN}.tar.gz" | \
-      tar -xv --strip-components=1 heroicons-${HERO_VSN}/optimized
+      tar -xvz --strip-components=1 heroicons-${HERO_VSN}/optimized
diff --git a/installer/templates/phx_single/config/dev.exs b/installer/templates/phx_single/config/dev.exs
index ae2699692..94b6e6573 100644
--- a/installer/templates/phx_single/config/dev.exs
+++ b/installer/templates/phx_single/config/dev.exs
@@ -4,8 +4,8 @@ import Config
 # debugging and code reloading.
 #
 # The watchers configuration can be used to run external
-# watchers to your application. For example, we use it
-# with esbuild to bundle .js and .css sources.
+# watchers to your application. For example, we can use it
+# to bundle .js and .css sources.
 config :<%= @app_name %>, <%= @endpoint_module %>,
   # Binding to loopback ipv4 address prevents access from other machines.
   # Change to `ip: {0, 0, 0, 0}` to allow access from other machines.
diff --git a/installer/templates/phx_umbrella/apps/app_name_web/config/dev.exs b/installer/templates/phx_umbrella/apps/app_name_web/config/dev.exs
index a01f32588..64a5e9723 100644
--- a/installer/templates/phx_umbrella/apps/app_name_web/config/dev.exs
+++ b/installer/templates/phx_umbrella/apps/app_name_web/config/dev.exs
@@ -2,8 +2,8 @@
 # debugging and code reloading.
 #
 # The watchers configuration can be used to run external
-# watchers to your application. For example, we use it
-# with esbuild to bundle .js and .css sources.
+# watchers to your application. For example, we can use it
+# to bundle .js and .css sources.
 config :<%= @web_app_name %>, <%= @endpoint_module %>,
   # Binding to loopback ipv4 address prevents access from other machines.
   # Change to `ip: {0, 0, 0, 0}` to allow access from other machines.
diff --git a/installer/templates/phx_web/components/core_components.ex b/installer/templates/phx_web/components/core_components.ex
index 4481f3ad9..d5623ac44 100644
--- a/installer/templates/phx_web/components/core_components.ex
+++ b/installer/templates/phx_web/components/core_components.ex
@@ -537,9 +537,9 @@ defmodule <%= @web_namespace %>.CoreComponents do
   end
 
   @doc """
-  Renders a [Hero Icon](https://heroicons.com).
+  Renders a [Heroicon](https://heroicons.com).
 
-  Hero icons come in three styles – outline, solid, and mini.
+  Heroicons come in three styles – outline, solid, and mini.
   By default, the outline style is used, but solid an mini may
   be applied by using the `-solid` and `-mini` suffix.
 
diff --git a/lib/mix/tasks/phx.gen.live.ex b/lib/mix/tasks/phx.gen.live.ex
index d5d5de772..600611937 100644
--- a/lib/mix/tasks/phx.gen.live.ex
+++ b/lib/mix/tasks/phx.gen.live.ex
@@ -36,7 +36,7 @@ defmodule Mix.Tasks.Phx.Gen.Live do
     * a helpers module in `lib/app_web/live/live_helpers.ex` with a modal
 
   After file generation is complete, there will be output regarding required
-  updates to the lib/app_web/router.ex file.
+  updates to the `lib/app_web/router.ex` file.
 
       Add the live routes to your browser scope in lib/app_web/router.ex:
 
@@ -86,6 +86,8 @@ defmodule Mix.Tasks.Phx.Gen.Live do
   to yourself. You can use the `--no-context` and `--no-schema` flags
   for file generation control.
 
+      mix phx.gen.live Accounts User users --no-context --no-schema
+
   You can also change the table name or configure the migrations to
   use binary ids for primary keys, see `mix help phx.gen.schema` for more
   information.
diff --git a/lib/phoenix/controller.ex b/lib/phoenix/controller.ex
index d730bbb3c..b51ba0349 100644
--- a/lib/phoenix/controller.ex
+++ b/lib/phoenix/controller.ex
@@ -506,7 +506,7 @@ defmodule Phoenix.Controller do
     end
   end
 
-  @invalid_local_url_chars ["\\"]
+  @invalid_local_url_chars ["\\", "\%"]
   defp validate_local_url("//" <> _ = to), do: raise_invalid_url(to)
 
   defp validate_local_url("/" <> _ = to) do
@@ -755,7 +755,7 @@ defmodule Phoenix.Controller do
 
   Raises `Plug.Conn.AlreadySentError` if `conn` is already sent.
   """
-  @spec put_root_layout(Plug.Conn.t(), [{format :: atom, layout}]) ::
+  @spec put_root_layout(Plug.Conn.t(), [{format :: atom, layout}] | false) ::
           Plug.Conn.t()
   def put_root_layout(%Plug.Conn{state: state} = conn, layout) do
     if state in @unsent do
diff --git a/lib/phoenix/endpoint.ex b/lib/phoenix/endpoint.ex
index 247f7704f..7af9c3991 100644
--- a/lib/phoenix/endpoint.ex
+++ b/lib/phoenix/endpoint.ex
@@ -837,16 +837,16 @@ defmodule Phoenix.Endpoint do
     * `:user_agent` - the value of the "user-agent" request header
 
     * `{:session, session_config}` - the session information from `Plug.Conn`.
-      The `session_config` is an exact copy of the arguments given to `Plug.Session`.
-      This requires the "_csrf_token" to be given as request parameter with
-      the value of `URI.encode_www_form(Plug.CSRFProtection.get_csrf_token())`
-      when connecting to the socket. It can also be a MFA to allow loading
-      config in runtime `{MyAppWeb.Auth, :get_session_config, []}`. Otherwise
-      the session will be `nil`.
-
-      `session_config` may take a `:csrf_token_key` option
-      which is useful when using `:protect_from_forgery` with a custom
-      `:session_key`. If not given, it defaults to `"_csrf_token"`.
+      The `session_config` is typically an exact copy of the arguments given
+      to `Plug.Session`. In order to validate the session, the "_csrf_token"
+      must be given as request parameter when connecting the socket with the
+      value of `URI.encode_www_form(Plug.CSRFProtection.get_csrf_token())`.
+      The CSRF token request parameter can be modified via the `:csrf_token_key`
+      option.
+
+      Additionally, `session_config` may be a MFA, such as
+      `{MyAppWeb.Auth, :get_session_config, []}`, to allow loading config in
+      runtime.
 
   Arbitrary keywords may also appear following the above valid keys, which
   is useful for passing custom connection information to the socket.
diff --git a/lib/phoenix/endpoint/supervisor.ex b/lib/phoenix/endpoint/supervisor.ex
index f468cc0ad..d1e66a113 100644
--- a/lib/phoenix/endpoint/supervisor.ex
+++ b/lib/phoenix/endpoint/supervisor.ex
@@ -309,10 +309,14 @@ defmodule Phoenix.Endpoint.Supervisor do
   """
   def warmup(endpoint) do
     warmup_persistent(endpoint)
-    warmup_static(endpoint, cache_static_manifest(endpoint))
-    true
-  rescue
-    _ -> false
+
+    try do
+      if manifest = cache_static_manifest(endpoint) do
+        warmup_static(endpoint, manifest)
+      end
+    rescue
+      e -> Logger.error("Could not warm up static assets: #{Exception.message(e)}")
+    end
   end
 
   defp warmup_persistent(endpoint) do
@@ -347,14 +351,9 @@ defmodule Phoenix.Endpoint.Supervisor do
 
     {scheme, port} =
       cond do
-        https ->
-          {"https", https[:port]}
-
-        http ->
-          {"http", http[:port]}
-
-        true ->
-          {"http", 80}
+        https -> {"https", https[:port] || 443}
+        http -> {"http", http[:port] || 80}
+        true -> {"http", 80}
       end
 
     scheme = url[:scheme] || scheme
@@ -382,8 +381,7 @@ defmodule Phoenix.Endpoint.Supervisor do
   end
 
   defp warmup_static(_endpoint, _manifest) do
-    raise ArgumentError,
-          "expected warmup_static/2 to include 'latest' and 'digests' keys in manifest"
+    raise ArgumentError, "expected cache manifest to include 'latest' and 'digests' keys"
   end
 
   defp static_cache(digests, value, true) do
@@ -411,14 +409,13 @@ defmodule Phoenix.Endpoint.Supervisor do
       if File.exists?(outer) do
         outer |> File.read!() |> Phoenix.json_library().decode!()
       else
-        Logger.error(
-          "Could not find static manifest at #{inspect(outer)}. " <>
-            "Run \"mix phx.digest\" after building your static files " <>
-            "or remove the \"cache_static_manifest\" configuration from your config files."
-        )
+        raise ArgumentError,
+              "could not find static manifest at #{inspect(outer)}. " <>
+                "Run \"mix phx.digest\" after building your static files " <>
+                "or remove the \"cache_static_manifest\" configuration from your config files."
       end
     else
-      %{}
+      nil
     end
   end
 
diff --git a/lib/phoenix/verified_routes.ex b/lib/phoenix/verified_routes.ex
index f3a7b8587..089b49114 100644
--- a/lib/phoenix/verified_routes.ex
+++ b/lib/phoenix/verified_routes.ex
@@ -302,7 +302,7 @@ defmodule Phoenix.VerifiedRoutes do
   @doc ~S'''
   Generates the router url with route verification.
 
-  See `sigil_p/1` for more information.
+  See `sigil_p/2` for more information.
 
   Warns when the provided path does not match against the router specified
   in `use Phoenix.VerifiedRoutes` or the `@router` module attribute.
diff --git a/priv/templates/phx.gen.live/core_components.ex b/priv/templates/phx.gen.live/core_components.ex
index 4481f3ad9..d5623ac44 100644
--- a/priv/templates/phx.gen.live/core_components.ex
+++ b/priv/templates/phx.gen.live/core_components.ex
@@ -537,9 +537,9 @@ defmodule <%= @web_namespace %>.CoreComponents do
   end
 
   @doc """
-  Renders a [Hero Icon](https://heroicons.com).
+  Renders a [Heroicon](https://heroicons.com).
 
-  Hero icons come in three styles – outline, solid, and mini.
+  Heroicons come in three styles – outline, solid, and mini.
   By default, the outline style is used, but solid an mini may
   be applied by using the `-solid` and `-mini` suffix.
 


Test patch:
diff --git a/priv/templates/phx.gen.auth/auth_test.exs b/priv/templates/phx.gen.auth/auth_test.exs
index 3e2d8853d..ef8c12ee9 100644
--- a/priv/templates/phx.gen.auth/auth_test.exs
+++ b/priv/templates/phx.gen.auth/auth_test.exs
@@ -118,7 +118,7 @@ defmodule <%= inspect auth_module %>Test do
   end
 
   describe "on_mount: mount_current_<%= schema.singular %>" do
-    test "assigns current_<%= schema.singular %> based on a valid <%= schema.singular %>_token ", %{conn: conn, <%= schema.singular %>: <%= schema.singular %>} do
+    test "assigns current_<%= schema.singular %> based on a valid <%= schema.singular %>_token", %{conn: conn, <%= schema.singular %>: <%= schema.singular %>} do
       <%= schema.singular %>_token = <%= inspect context.alias %>.generate_<%= schema.singular %>_session_token(<%= schema.singular %>)
       session = conn |> put_session(:<%= schema.singular %>_token, <%= schema.singular %>_token) |> get_session()
 
@@ -128,7 +128,7 @@ defmodule <%= inspect auth_module %>Test do
       assert updated_socket.assigns.current_<%= schema.singular %>.id == <%= schema.singular %>.id
     end
 
-    test "assigns nil to current_<%= schema.singular %> assign if there isn't a valid <%= schema.singular %>_token ", %{conn: conn} do
+    test "assigns nil to current_<%= schema.singular %> assign if there isn't a valid <%= schema.singular %>_token", %{conn: conn} do
       <%= schema.singular %>_token = "invalid_token"
       session = conn |> put_session(:<%= schema.singular %>_token, <%= schema.singular %>_token) |> get_session()
 
@@ -149,7 +149,7 @@ defmodule <%= inspect auth_module %>Test do
   end
 
   describe "on_mount: ensure_authenticated" do
-    test "authenticates current_<%= schema.singular %> based on a valid <%= schema.singular %>_token ", %{conn: conn, <%= schema.singular %>: <%= schema.singular %>} do
+    test "authenticates current_<%= schema.singular %> based on a valid <%= schema.singular %>_token", %{conn: conn, <%= schema.singular %>: <%= schema.singular %>} do
       <%= schema.singular %>_token = <%= inspect context.alias %>.generate_<%= schema.singular %>_session_token(<%= schema.singular %>)
       session = conn |> put_session(:<%= schema.singular %>_token, <%= schema.singular %>_token) |> get_session()
 
@@ -159,7 +159,7 @@ defmodule <%= inspect auth_module %>Test do
       assert updated_socket.assigns.current_<%= schema.singular %>.id == <%= schema.singular %>.id
     end
 
-    test "redirects to login page if there isn't a valid <%= schema.singular %>_token ", %{conn: conn} do
+    test "redirects to login page if there isn't a valid <%= schema.singular %>_token", %{conn: conn} do
       <%= schema.singular %>_token = "invalid_token"
       session = conn |> put_session(:<%= schema.singular %>_token, <%= schema.singular %>_token) |> get_session()
 
@@ -172,7 +172,7 @@ defmodule <%= inspect auth_module %>Test do
       assert updated_socket.assigns.current_<%= schema.singular %> == nil
     end
 
-    test "redirects to login page if there isn't a <%= schema.singular %>_token ", %{conn: conn} do
+    test "redirects to login page if there isn't a <%= schema.singular %>_token", %{conn: conn} do
       session = conn |> get_session()
 
       socket = %LiveView.Socket{
@@ -199,7 +199,7 @@ defmodule <%= inspect auth_module %>Test do
                )
     end
 
-    test "Don't redirect is there is no authenticated <%= schema.singular %>", %{conn: conn} do
+    test "doesn't redirect if there is no authenticated <%= schema.singular %>", %{conn: conn} do
       session = conn |> get_session()
 
       assert {:cont, _updated_socket} =
diff --git a/test/phoenix/controller/controller_test.exs b/test/phoenix/controller/controller_test.exs
index 49e683339..a99ea49d5 100644
--- a/test/phoenix/controller/controller_test.exs
+++ b/test/phoenix/controller/controller_test.exs
@@ -378,6 +378,14 @@ defmodule Phoenix.Controller.ControllerTest do
       assert_raise ArgumentError, ~r/unsafe/, fn ->
         redirect(conn(:get, "/"), to: "/\\example.com")
       end
+
+      assert_raise ArgumentError, ~r/expects a path/, fn ->
+        redirect(conn(:get, "/"), to: "//\\example.com")
+      end
+
+      assert_raise ArgumentError, ~r/unsafe/, fn ->
+        redirect(conn(:get, "/"), to: "/%09/example.com")
+      end
     end
 
     test "with :external" do
diff --git a/test/phoenix/endpoint/supervisor_test.exs b/test/phoenix/endpoint/supervisor_test.exs
index 8527b93f2..f4d3c71e6 100644
--- a/test/phoenix/endpoint/supervisor_test.exs
+++ b/test/phoenix/endpoint/supervisor_test.exs
@@ -7,7 +7,7 @@ defmodule Phoenix.Endpoint.SupervisorTest do
     def config(:https), do: [port: 443]
     def config(:http), do: false
     def config(:url), do: [host: "example.com"]
-    def config(:static_url), do: nil
+    def config(_), do: nil
   end
 
   defmodule HTTPEndpoint do
@@ -15,7 +15,7 @@ defmodule Phoenix.Endpoint.SupervisorTest do
     def config(:https), do: false
     def config(:http), do: [port: 80]
     def config(:url), do: [host: "example.com"]
-    def config(:static_url), do: nil
+    def config(_), do: nil
   end
 
   defmodule HTTPEnvVarEndpoint do
@@ -23,21 +23,22 @@ defmodule Phoenix.Endpoint.SupervisorTest do
     def config(:https), do: false
     def config(:http), do: [port: {:system, "PHOENIX_PORT"}]
     def config(:url), do: [host: {:system, "PHOENIX_HOST"}]
-    def config(:static_url), do: nil
+    def config(_), do: nil
   end
 
   defmodule URLEndpoint do
     def config(:https), do: false
     def config(:http), do: false
     def config(:url), do: [host: "example.com", port: 678, scheme: "random"]
-    def config(:static_url), do: nil
+    def config(_), do: nil
   end
 
   defmodule StaticURLEndpoint do
     def config(:https), do: false
-    def config(:http), do: false
+    def config(:http), do: []
     def config(:url), do: []
     def config(:static_url), do: [host: "static.example.com"]
+    def config(_), do: nil
   end
 
   defmodule ServerEndpoint do