Repository: phoenixframework/phoenix
Pull request #4698 (2022-02-23 11:19:27)

Generate channel case on demand


Patch:
diff --git a/installer/lib/mix/tasks/phx.new.ex b/installer/lib/mix/tasks/phx.new.ex
index b8f737cde..7e05988c2 100644
--- a/installer/lib/mix/tasks/phx.new.ex
+++ b/installer/lib/mix/tasks/phx.new.ex
@@ -33,7 +33,7 @@ defmodule Mix.Tasks.Phx.New do
 
     * `--no-assets` - do not generate the assets folder.
       When choosing this option, you will need to manually
-      handle JavaScript/CSS if building HTML apps.
+      handle JavaScript/CSS if building HTML apps
 
     * `--no-ecto` - do not generate Ecto files
 
diff --git a/installer/lib/phx_new/single.ex b/installer/lib/phx_new/single.ex
index abfb49fa0..eebe9d6ac 100644
--- a/installer/lib/phx_new/single.ex
+++ b/installer/lib/phx_new/single.ex
@@ -22,10 +22,8 @@ defmodule Phx.New.Single do
     {:eex,  "phx_single/README.md",                     :project, "README.md"},
     {:eex,  "phx_single/formatter.exs",                 :project, ".formatter.exs"},
     {:eex,  "phx_single/gitignore",                     :project, ".gitignore"},
-    {:eex,  "phx_test/support/channel_case.ex",         :project, "test/support/channel_case.ex"},
     {:eex,  "phx_test/support/conn_case.ex",            :project, "test/support/conn_case.ex"},
     {:eex,  "phx_single/test/test_helper.exs",          :project, "test/test_helper.exs"},
-    {:keep, "phx_test/channels",                        :project, "test/:lib_web_name/channels"},
     {:keep, "phx_test/controllers",                     :project, "test/:lib_web_name/controllers"},
     {:eex,  "phx_test/views/error_view_test.exs",       :project, "test/:lib_web_name/views/error_view_test.exs"},
   ]
diff --git a/installer/lib/phx_new/web.ex b/installer/lib/phx_new/web.ex
index 4723ac9f4..7c2b9d651 100644
--- a/installer/lib/phx_new/web.ex
+++ b/installer/lib/phx_new/web.ex
@@ -25,7 +25,6 @@ defmodule Phx.New.Web do
     {:keep, "phx_test/channels",                      :web, "test/:web_app/channels"},
     {:keep, "phx_test/controllers",                   :web, "test/:web_app/controllers"},
     {:eex,  "#{@pre}/test/test_helper.exs",           :web, "test/test_helper.exs"},
-    {:eex,  "phx_test/support/channel_case.ex",       :web, "test/support/channel_case.ex"},
     {:eex,  "phx_test/support/conn_case.ex",          :web, "test/support/conn_case.ex"},
     {:eex,  "phx_test/views/error_view_test.exs",     :web, "test/:web_app/views/error_view_test.exs"},
     {:eex,  "#{@pre}/formatter.exs",                  :web, ".formatter.exs"},
diff --git a/installer/templates/phx_ecto/data_case.ex b/installer/templates/phx_ecto/data_case.ex
index 336764c75..3ec498c66 100644
--- a/installer/templates/phx_ecto/data_case.ex
+++ b/installer/templates/phx_ecto/data_case.ex
@@ -28,10 +28,17 @@ defmodule <%= @app_module %>.DataCase do
   end
 
   setup tags do
-<%= @adapter_config[:test_setup] %>
+    <%= @app_module %>.DataCase.setup_sandbox(tags)
     :ok
   end
 
+  @doc """
+  Sets up the sandbox based on the test tags.
+  """
+  def setup_sandbox(tags) do
+<%= @adapter_config[:test_setup] %>
+  end
+
   @doc """
   A helper that transforms changeset errors into a map of messages.
 
diff --git a/installer/templates/phx_web/channels/user_socket.ex b/installer/templates/phx_web/channels/user_socket.ex
deleted file mode 100644
index 95e1d5c7d..000000000
--- a/installer/templates/phx_web/channels/user_socket.ex
+++ /dev/null
@@ -1,35 +0,0 @@
-defmodule <%= @web_namespace %>.UserSocket do
-  use Phoenix.Socket
-
-  ## Channels
-  # channel "room:*", <%= @web_namespace %>.RoomChannel
-
-  # Socket params are passed from the client and can
-  # be used to verify and authenticate a user. After
-  # verification, you can put default assigns into
-  # the socket that will be set for all channels, ie
-  #
-  #     {:ok, assign(socket, :user_id, verified_user_id)}
-  #
-  # To deny connection, return `:error`.
-  #
-  # See `Phoenix.Token` documentation for examples in
-  # performing token verification on connect.
-  @impl true
-  def connect(_params, socket, _connect_info) do
-    {:ok, socket}
-  end
-
-  # Socket IDs are topics that allow you to identify all sockets for a given user:
-  #
-  #     def id(socket), do: "user_socket:#{socket.assigns.user_id}"
-  #
-  # Would allow you to broadcast a "disconnect" event and terminate
-  # all active sockets and channels for a given user:
-  #
-  #     <%= @endpoint_module %>.broadcast("user_socket:#{user.id}", "disconnect", %{})
-  #
-  # Returning `nil` makes this socket anonymous.
-  @impl true
-  def id(_socket), do: nil
-end
diff --git a/lib/mix/tasks/phx.gen.channel.ex b/lib/mix/tasks/phx.gen.channel.ex
index 1700e8b3d..2068140a9 100644
--- a/lib/mix/tasks/phx.gen.channel.ex
+++ b/lib/mix/tasks/phx.gen.channel.ex
@@ -35,17 +35,25 @@ defmodule Mix.Tasks.Phx.Gen.Channel do
     [channel_name] = validate_args!(args)
     context_app = Mix.Phoenix.context_app()
     web_prefix = Mix.Phoenix.web_path(context_app)
-    test_prefix = Mix.Phoenix.web_test_path(context_app)
+    web_test_prefix = Mix.Phoenix.web_test_path(context_app)
     binding = Mix.Phoenix.inflect(channel_name)
     binding = Keyword.put(binding, :module, "#{binding[:web_module]}.#{binding[:scoped]}")
 
     Mix.Phoenix.check_module_name_availability!(binding[:module] <> "Channel")
 
+    test_path = Path.join(web_test_prefix, "channels/#{binding[:path]}_channel_test.exs")
+    case_path = Path.join(Path.dirname(web_test_prefix), "support/channel_case.ex")
+
+    maybe_case = if File.exists?(case_path) do
+      []
+    else
+      [{:eex, "channel_case.ex", case_path}]
+    end
+
     Mix.Phoenix.copy_from(paths(), "priv/templates/phx.gen.channel", binding, [
       {:eex, "channel.ex", Path.join(web_prefix, "channels/#{binding[:path]}_channel.ex")},
-      {:eex, "channel_test.exs",
-       Path.join(test_prefix, "channels/#{binding[:path]}_channel_test.exs")}
-    ])
+      {:eex, "channel_test.exs", test_path}
+    ] ++ maybe_case)
 
     user_socket_path = Mix.Phoenix.web_path(context_app, "channels/user_socket.ex")
 


Test patch:
diff --git a/installer/templates/phx_test/support/conn_case.ex b/installer/templates/phx_test/support/conn_case.ex
index 3aa04c089..b74c3756a 100644
--- a/installer/templates/phx_test/support/conn_case.ex
+++ b/installer/templates/phx_test/support/conn_case.ex
@@ -32,7 +32,7 @@ defmodule <%= @web_namespace %>.ConnCase do
   end<%= if @ecto do %>
 
   setup tags do
-<%= @adapter_config[:test_setup] %>
+    <%= @app_module %>.DataCase.setup_sandbox(tags)
     {:ok, conn: Phoenix.ConnTest.build_conn()}
   end<% else %>
 
diff --git a/installer/test/phx_new_test.exs b/installer/test/phx_new_test.exs
index 1928d8648..5ca178917 100644
--- a/installer/test/phx_new_test.exs
+++ b/installer/test/phx_new_test.exs
@@ -511,8 +511,7 @@ defmodule Mix.Tasks.Phx.NewTest do
       assert_file "custom_path/config/runtime.exs", [~r/url: database_url/]
       assert_file "custom_path/lib/custom_path/repo.ex", "Ecto.Adapters.Postgres"
 
-      assert_file "custom_path/test/support/conn_case.ex", "Ecto.Adapters.SQL.Sandbox.start_owner"
-      assert_file "custom_path/test/support/channel_case.ex", "Ecto.Adapters.SQL.Sandbox.start_owner"
+      assert_file "custom_path/test/support/conn_case.ex", "DataCase.setup_sandbox(tags)"
       assert_file "custom_path/test/support/data_case.ex", "Ecto.Adapters.SQL.Sandbox.start_owner"
     end
   end
@@ -528,8 +527,7 @@ defmodule Mix.Tasks.Phx.NewTest do
       assert_file "custom_path/config/runtime.exs", [~r/url: database_url/]
       assert_file "custom_path/lib/custom_path/repo.ex", "Ecto.Adapters.MyXQL"
 
-      assert_file "custom_path/test/support/conn_case.ex", "Ecto.Adapters.SQL.Sandbox.start_owner"
-      assert_file "custom_path/test/support/channel_case.ex", "Ecto.Adapters.SQL.Sandbox.start_owner"
+      assert_file "custom_path/test/support/conn_case.ex", "DataCase.setup_sandbox(tags)"
       assert_file "custom_path/test/support/data_case.ex", "Ecto.Adapters.SQL.Sandbox.start_owner"
     end
   end
@@ -545,8 +543,7 @@ defmodule Mix.Tasks.Phx.NewTest do
       assert_file "custom_path/config/runtime.exs", [~r/database: database_path/]
       assert_file "custom_path/lib/custom_path/repo.ex", "Ecto.Adapters.SQLite3"
 
-      assert_file "custom_path/test/support/conn_case.ex", "Ecto.Adapters.SQL.Sandbox.start_owner"
-      assert_file "custom_path/test/support/channel_case.ex", "Ecto.Adapters.SQL.Sandbox.start_owner"
+      assert_file "custom_path/test/support/conn_case.ex", "DataCase.setup_sandbox(tags)"
       assert_file "custom_path/test/support/data_case.ex", "Ecto.Adapters.SQL.Sandbox.start_owner"
 
       assert_file "custom_path/.gitignore", "*.db"
@@ -565,8 +562,7 @@ defmodule Mix.Tasks.Phx.NewTest do
       assert_file "custom_path/config/runtime.exs", [~r/url: database_url/]
       assert_file "custom_path/lib/custom_path/repo.ex", "Ecto.Adapters.Tds"
 
-      assert_file "custom_path/test/support/conn_case.ex", "Ecto.Adapters.SQL.Sandbox.start_owner"
-      assert_file "custom_path/test/support/channel_case.ex", "Ecto.Adapters.SQL.Sandbox.start_owner"
+      assert_file "custom_path/test/support/conn_case.ex", "DataCase.setup_sandbox(tags)"
       assert_file "custom_path/test/support/data_case.ex", "Ecto.Adapters.SQL.Sandbox.start_owner"
     end
   end
diff --git a/installer/test/phx_new_umbrella_test.exs b/installer/test/phx_new_umbrella_test.exs
index b65ec0b16..8b0401b4c 100644
--- a/installer/test/phx_new_umbrella_test.exs
+++ b/installer/test/phx_new_umbrella_test.exs
@@ -503,8 +503,7 @@ defmodule Mix.Tasks.Phx.New.UmbrellaTest do
       assert_file root_path(app, "config/test.exs"), [~r/username: "postgres"/, ~r/password: "postgres"/, ~r/hostname: "localhost"/]
       assert_file root_path(app, "config/runtime.exs"), [~r/url: database_url/]
 
-      assert_file web_path(app, "test/support/conn_case.ex"), "Ecto.Adapters.SQL.Sandbox.start_owner"
-      assert_file web_path(app, "test/support/channel_case.ex"), "Ecto.Adapters.SQL.Sandbox.start_owner"
+      assert_file web_path(app, "test/support/conn_case.ex"), "DataCase.setup_sandbox(tags)"
     end
   end
 
@@ -521,8 +520,7 @@ defmodule Mix.Tasks.Phx.New.UmbrellaTest do
       assert_file root_path(app, "config/test.exs"), [~r/username: "root"/, ~r/password: ""/]
       assert_file root_path(app, "config/runtime.exs"), [~r/url: database_url/]
 
-      assert_file web_path(app, "test/support/conn_case.ex"), "Ecto.Adapters.SQL.Sandbox.start_owner"
-      assert_file web_path(app, "test/support/channel_case.ex"), "Ecto.Adapters.SQL.Sandbox.start_owner"
+      assert_file web_path(app, "test/support/conn_case.ex"), "DataCase.setup_sandbox(tags)"
     end
   end
 
@@ -539,8 +537,7 @@ defmodule Mix.Tasks.Phx.New.UmbrellaTest do
       assert_file root_path(app, "config/test.exs"), [~r/database: .*_test.db/]
       assert_file root_path(app, "config/runtime.exs"), [~r/database: database_path/]
 
-      assert_file web_path(app, "test/support/conn_case.ex"), "Ecto.Adapters.SQL.Sandbox.start_owner"
-      assert_file web_path(app, "test/support/channel_case.ex"), "Ecto.Adapters.SQL.Sandbox.start_owner"
+      assert_file web_path(app, "test/support/conn_case.ex"), "DataCase.setup_sandbox(tags)"
 
       assert_file root_path(app, ".gitignore"), "*.db"
       assert_file root_path(app, ".gitignore"), "*.db-*"
@@ -560,8 +557,7 @@ defmodule Mix.Tasks.Phx.New.UmbrellaTest do
       assert_file root_path(app, "config/test.exs"), [~r/username: "sa"/, ~r/password: "some!Password"/]
       assert_file root_path(app, "config/runtime.exs"), [~r/url: database_url/]
 
-      assert_file web_path(app, "test/support/conn_case.ex"), "Ecto.Adapters.SQL.Sandbox.start_owner"
-      assert_file web_path(app, "test/support/channel_case.ex"), "Ecto.Adapters.SQL.Sandbox.start_owner"
+      assert_file web_path(app, "test/support/conn_case.ex"), "DataCase.setup_sandbox(tags)"
     end
   end
 
diff --git a/installer/templates/phx_test/support/channel_case.ex b/priv/templates/phx.gen.channel/channel_case.ex
similarity index 72%
rename from installer/templates/phx_test/support/channel_case.ex
rename to priv/templates/phx.gen.channel/channel_case.ex
index eca31714a..f0dd5f9bd 100644
--- a/installer/templates/phx_test/support/channel_case.ex
+++ b/priv/templates/phx.gen.channel/channel_case.ex
@@ -1,4 +1,4 @@
-defmodule <%= @web_namespace %>.ChannelCase do
+defmodule <%= web_module %>.ChannelCase do
   @moduledoc """
   This module defines the test case to be used by
   channel tests.
@@ -11,7 +11,7 @@ defmodule <%= @web_namespace %>.ChannelCase do
   we enable the SQL sandbox, so changes done to the database
   are reverted at the end of every test. If you are using
   PostgreSQL, you can even run database tests asynchronously
-  by setting `use <%= @web_namespace %>.ChannelCase, async: true`, although
+  by setting `use <%= web_module %>.ChannelCase, async: true`, although
   this option is not recommended for other databases.
   """
 
@@ -21,15 +21,15 @@ defmodule <%= @web_namespace %>.ChannelCase do
     quote do
       # Import conveniences for testing with channels
       import Phoenix.ChannelTest
-      import <%= @web_namespace %>.ChannelCase
+      import <%= web_module %>.ChannelCase
 
       # The default endpoint for testing
-      @endpoint <%= @endpoint_module %>
+      @endpoint <%= web_module %>.Endpoint
     end
-  end<%= if @ecto do %>
+  end<%= if Code.ensure_loaded?(Ecto.Adapters.SQL) do %>
 
   setup tags do
-<%= @adapter_config[:test_setup] %>
+    <%= base %>.DataCase.setup_sandbox(tags)
     :ok
   end<% else %>
 
diff --git a/test/mix/tasks/phx.gen.channel_test.exs b/test/mix/tasks/phx.gen.channel_test.exs
index fb1fa7365..5f20b7b77 100644
--- a/test/mix/tasks/phx.gen.channel_test.exs
+++ b/test/mix/tasks/phx.gen.channel_test.exs
@@ -3,6 +3,9 @@ Code.require_file("../../../installer/test/mix_helper.exs", __DIR__)
 defmodule PhoenixWeb.DupChannel do
 end
 
+defmodule Ecto.Adapters.SQL do
+end
+
 defmodule Mix.Tasks.Phx.Gen.ChannelTest do
   use ExUnit.Case
   import MixHelper
@@ -31,6 +34,12 @@ defmodule Mix.Tasks.Phx.Gen.ChannelTest do
         assert file =~ ~S|{:noreply, socket}|
       end)
 
+      assert_file("test/support/channel_case.ex", fn file ->
+        assert file =~ ~S|defmodule PhoenixWeb.ChannelCase|
+        assert file =~ ~S|@endpoint PhoenixWeb.Endpoint|
+        assert file =~ ~S|Phoenix.DataCase.setup_sandbox|
+      end)
+
       assert_file("test/phoenix_web/channels/room_channel_test.exs", fn file ->
         assert file =~ ~S|defmodule PhoenixWeb.RoomChannelTest|
         assert file =~ ~S|use PhoenixWeb.ChannelCase|
@@ -130,6 +139,12 @@ defmodule Mix.Tasks.Phx.Gen.ChannelTest do
         assert file =~ ~S|use PhoenixWeb, :channel|
       end)
 
+      assert_file("test/support/channel_case.ex", fn file ->
+        assert file =~ ~S|defmodule PhoenixWeb.ChannelCase|
+        assert file =~ ~S|@endpoint PhoenixWeb.Endpoint|
+        assert file =~ ~S|Phoenix.DataCase.setup_sandbox|
+      end)
+
       assert_file("test/phoenix/channels/room_channel_test.exs", fn file ->
         assert file =~ ~S|defmodule PhoenixWeb.RoomChannelTest|
         assert file =~ ~S|subscribe_and_join(PhoenixWeb.RoomChannel|