Repository: phoenixframework/phoenix
Pull request #4011 (2020-10-03 20:43:13)

Remove extraneous line break in Community docs
The line break made the second line in the paragraph be interpreted as a separate bulleted list item rather than a continuation of the link on the first line.

The live page: https://hexdocs.pm/phoenix/community.html


Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a22513428..6eec7ec51 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -15,9 +15,11 @@ jobs:
           - elixir: 1.9.4
             otp: 20.3.8.26
           - elixir: 1.10.4
-            otp: 21.3.8.17
-          - elixir: 1.10.4
-            otp: 23.0.3
+            otp: 23.1.1
+          - elixir: 1.11.0
+            otp: 21.3.8.18
+          - elixir: 1.11.0
+            otp: 23.1.1
     steps:
       - uses: actions/checkout@v2.3.1
       - name: Install Dependencies
@@ -43,15 +45,17 @@ jobs:
       fail-fast: false
       matrix:
         include:
-          # Can't run integration tests before OTP 20.2 due to incompatiblity with cowlib.
+          # Can't run integration tests before OTP 21 due to incompatiblity with cowlib.
           #
           # See https://github.com/phoenixframework/phoenix/issues/3903
           - elixir: 1.9.4
-            otp: 21.2.7
-          - elixir: 1.10.4
             otp: 21.3.8.17
           - elixir: 1.10.4
-            otp: 23.0.3
+            otp: 21.3.8.17
+          - elixir: 1.11.0
+            otp: 21.3.8.18
+          - elixir: 1.11.0
+            otp: 23.1.1
     steps:
       - uses: actions/checkout@v2.3.1
       - name: Install Dependencies
@@ -59,9 +63,12 @@ jobs:
           mix local.rebar --force
           mix local.hex --force
           apk add --no-progress --update git
-          mix deps.get
+      - name: Install dependencies
+        run: mix deps.get
+        working-directory: integration_test
       - name: Run integration tests
-        run: mix test.integration
+        run: mix test
+        working-directory: integration_test
 
   npm_test:
     runs-on: ubuntu-latest
diff --git a/.gitignore b/.gitignore
index b0e95da35..c4228d701 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,4 +11,7 @@
 /installer/doc
 /installer/deps
 
+/integration_test/_build
+/integration_test/deps
+
 erl_crash.dump
diff --git a/guides/introduction/community.md b/guides/introduction/community.md
index 90a564083..47dfa7804 100644
--- a/guides/introduction/community.md
+++ b/guides/introduction/community.md
@@ -38,8 +38,7 @@ There are a number of places to connect with community members at all experience
 
   * [The Complete Elixir and Phoenix Bootcamp Master Functional Programming Techniques with Elixir and Phoenix while Learning to Build Compelling Web Applications (by Stephen Grider - 2017)](https://www.udemy.com/the-complete-elixir-and-phoenix-bootcamp-and-tutorial/)
 
-  * [Discover Elixir & Phoenix (by Tristan Edwards
- - 2017)](https://www.ludu.co/course/discover-elixir-phoenix)
+  * [Discover Elixir & Phoenix (by Tristan Edwards - 2017)](https://www.ludu.co/course/discover-elixir-phoenix)
 
   * [Phoenix Framework Tutorial (by Tensor Programming - 2017)](https://www.youtube.com/watch?v=irDC1nWKhZ8&index=6&list=PLJbE2Yu2zumAgKjSPyFtvYjP5LqgzafQq)
 
diff --git a/installer/templates/phx_single/mix.exs b/installer/templates/phx_single/mix.exs
index b27c6cbf6..ce8ccf21a 100644
--- a/installer/templates/phx_single/mix.exs
+++ b/installer/templates/phx_single/mix.exs
@@ -45,7 +45,7 @@ defmodule <%= app_module %>.MixProject do
       {:floki, ">= 0.27.0", only: :test},<% end %>
       {:phoenix_html, "~> 2.11"},
       {:phoenix_live_reload, "~> 1.2", only: :dev},<% end %><%= if dashboard do %>
-      {:phoenix_live_dashboard, "~> 0.2"},<% end %>
+      {:phoenix_live_dashboard, "~> 0.3 or ~> 0.2.9"},<% end %>
       {:telemetry_metrics, "~> 0.4"},
       {:telemetry_poller, "~> 0.4"},<%= if gettext do %>
       {:gettext, "~> 0.11"},<% end %>
diff --git a/installer/templates/phx_umbrella/apps/app_name_web/mix.exs b/installer/templates/phx_umbrella/apps/app_name_web/mix.exs
index 62124dcab..372977296 100644
--- a/installer/templates/phx_umbrella/apps/app_name_web/mix.exs
+++ b/installer/templates/phx_umbrella/apps/app_name_web/mix.exs
@@ -43,7 +43,7 @@ defmodule <%= web_namespace %>.MixProject do
       {:floki, ">= 0.27.0", only: :test},<% end %>
       {:phoenix_html, "~> 2.11"},
       {:phoenix_live_reload, "~> 1.2", only: :dev},<% end %><%= if dashboard do %>
-      {:phoenix_live_dashboard, "~> 0.2"},<% end %>
+      {:phoenix_live_dashboard, "~> 0.3 or ~> 0.2.9"},<% end %>
       {:telemetry_metrics, "~> 0.4"},
       {:telemetry_poller, "~> 0.4"},<%= if gettext do %>
       {:gettext, "~> 0.11"},<% end %><%= if app_name != web_app_name do %>
diff --git a/lib/mix/phoenix/schema.ex b/lib/mix/phoenix/schema.ex
index 85c0dd60b..6c94f563e 100644
--- a/lib/mix/phoenix/schema.ex
+++ b/lib/mix/phoenix/schema.ex
@@ -175,6 +175,47 @@ defmodule Mix.Phoenix.Schema do
     |> Enum.into(%{}, fn {k, t} -> {k, type_to_default(k, t, action)} end)
   end
 
+  @doc """
+  Converts the given value to map format when it is a date, time, datetime or naive_datetime.
+
+  Since `form_component.html.eex` generated by the live generator uses selects for dates and/or
+  times, fixtures must use map format for those fields in order to submit the live form.
+  """
+  def live_form_value(%Date{} = date), do: %{day: date.day, month: date.month, year: date.year}
+
+  def live_form_value(%Time{} = time), do: %{hour: time.hour, minute: time.minute}
+
+  def live_form_value(%NaiveDateTime{} = naive),
+    do: %{
+      day: naive.day,
+      month: naive.month,
+      year: naive.year,
+      hour: naive.hour,
+      minute: naive.minute
+    }
+
+  def live_form_value(%DateTime{} = naive),
+    do: %{
+      day: naive.day,
+      month: naive.month,
+      year: naive.year,
+      hour: naive.hour,
+      minute: naive.minute
+    }
+
+  def live_form_value(value), do: value
+
+  @doc """
+  Build an invalid value for `@invalid_attrs` which is nil by default.
+
+  * In case the value is a list, this will return an empty array.
+  * In case the value is date, datetime, naive_datetime or time, the value.
+  """
+  def invalid_form_value(value) when is_list(value), do: []
+  def invalid_form_value(%{day: _day, month: _month, year: _year} = value), do: value
+  def invalid_form_value(%{hour: _hour, minute: _minute} = value), do: value
+  def invalid_form_value(_value), do: nil
+
   @doc """
   Returns the string value for use in EEx templates.
   """
@@ -200,6 +241,8 @@ defmodule Mix.Phoenix.Schema do
     {String.to_atom(key), {String.to_atom(comp), String.to_atom(value)}}
   end
 
+  @one_day_in_seconds 24 * 3600
+
   defp type_to_default(key, t, :create) do
     case t do
         {:array, _}     -> []
@@ -209,15 +252,15 @@ defmodule Mix.Phoenix.Schema do
         :boolean        -> true
         :map            -> %{}
         :text           -> "some #{key}"
-        :date           -> ~D[2010-04-17]
+        :date           -> Date.add(Date.utc_today(), -1)
         :time           -> ~T[14:00:00]
         :time_usec      -> ~T[14:00:00.000000]
         :uuid           -> "7488a646-e31f-11e4-aace-600308960662"
-        :utc_datetime   -> ~U[2010-04-17T14:00:00Z]
-        :utc_datetime_usec -> ~U[2010-04-17T14:00:00.000000Z]
-        :naive_datetime -> ~N[2010-04-17 14:00:00]
-        :naive_datetime_usec -> ~N[2010-04-17 14:00:00.000000]
-        _               -> "some #{key}"
+        :utc_datetime   -> DateTime.add(build_utc_datetime(), -@one_day_in_seconds)
+        :utc_datetime_usec -> DateTime.add(build_utc_datetime_usec(), -@one_day_in_seconds)
+        :naive_datetime -> NaiveDateTime.add(build_utc_naive_datetime(), -@one_day_in_seconds)
+        :naive_datetime_usec -> NaiveDateTime.add(build_utc_naive_datetime_usec(), -@one_day_in_seconds)
+        _  -> "some #{key}"
     end
   end
   defp type_to_default(key, t, :update) do
@@ -229,18 +272,30 @@ defmodule Mix.Phoenix.Schema do
         :boolean        -> false
         :map            -> %{}
         :text           -> "some updated #{key}"
-        :date           -> ~D[2011-05-18]
+        :date           -> Date.utc_today()
         :time           -> ~T[15:01:01]
         :time_usec      -> ~T[15:01:01.000000]
         :uuid           -> "7488a646-e31f-11e4-aace-600308960668"
-        :utc_datetime   -> ~U[2011-05-18T15:01:01Z]
-        :utc_datetime_usec   -> ~U[2011-05-18T15:01:01.000000Z]
-        :naive_datetime -> ~N[2011-05-18 15:01:01]
-        :naive_datetime_usec -> ~N[2011-05-18 15:01:01.000000]
+        :utc_datetime   -> build_utc_datetime()
+        :utc_datetime_usec -> build_utc_datetime_usec()
+        :naive_datetime -> build_utc_naive_datetime()
+        :naive_datetime_usec -> build_utc_naive_datetime_usec()
         _               -> "some updated #{key}"
     end
   end
 
+  defp build_utc_datetime_usec,
+    do: %{DateTime.utc_now() | second: 0, microsecond: {0, 6}}
+
+  defp build_utc_datetime,
+    do: DateTime.truncate(build_utc_datetime_usec(), :second)
+
+  defp build_utc_naive_datetime_usec,
+    do: %{NaiveDateTime.utc_now() | second: 0, microsecond: {0, 6}}
+
+  defp build_utc_naive_datetime,
+    do: NaiveDateTime.truncate(build_utc_naive_datetime_usec(), :second)
+
   defp validate_attr!({name, :datetime}), do: validate_attr!({name, :naive_datetime})
   defp validate_attr!({name, :array}) do
     Mix.raise """
@@ -292,7 +347,6 @@ defmodule Mix.Phoenix.Schema do
 
   defp string_attr(types) do
     Enum.find_value(types, fn
-      {key, {_col, :string}} -> key
       {key, :string} -> key
       _ -> false
     end)
diff --git a/lib/mix/tasks/phx.gen.context.ex b/lib/mix/tasks/phx.gen.context.ex
index 984bb40fd..6b6bdeb3d 100644
--- a/lib/mix/tasks/phx.gen.context.ex
+++ b/lib/mix/tasks/phx.gen.context.ex
@@ -254,6 +254,7 @@ defmodule Mix.Tasks.Phx.Gen.Context do
     """
   end
 
+  def prompt_for_code_injection(%Context{generate?: false}), do: :ok
   def prompt_for_code_injection(%Context{} = context) do
     if Context.pre_existing?(context) do
       function_count = Context.function_count(context)
diff --git a/lib/phoenix/controller.ex b/lib/phoenix/controller.ex
index a5485e4f8..1bc1f09af 100644
--- a/lib/phoenix/controller.ex
+++ b/lib/phoenix/controller.ex
@@ -1464,13 +1464,17 @@ defmodule Phoenix.Controller do
       "/users/123?existing=param"
 
   See `current_path/2` to override the default parameters.
+
+  The path is normalized based on the `conn.script_name` and
+  `conn.path_info`. For example, "/foo//bar/" will become "/foo/bar".
+  If you want the original path, use `conn.request_path` instead.
   """
   def current_path(%Plug.Conn{query_string: ""} = conn) do
-    conn.request_path
+    normalized_request_path(conn)
   end
 
   def current_path(%Plug.Conn{query_string: query_string} = conn) do
-    conn.request_path <> "?" <> query_string
+    normalized_request_path(conn) <> "?" <> query_string
   end
 
   @doc """
@@ -1493,12 +1497,19 @@ defmodule Phoenix.Controller do
       iex> current_path(conn, %{})
       "/users/123"
 
+  The path is normalized based on the `conn.script_name` and
+  `conn.path_info`. For example, "/foo//bar/" will become "/foo/bar".
+  If you want the original path, use `conn.request_path` instead.
   """
   def current_path(%Plug.Conn{} = conn, params) when params == %{} do
-    conn.request_path
+    normalized_request_path(conn)
   end
   def current_path(%Plug.Conn{} = conn, params) do
-    conn.request_path <> "?" <> Plug.Conn.Query.encode(params)
+    normalized_request_path(conn) <> "?" <> Plug.Conn.Query.encode(params)
+  end
+
+  defp normalized_request_path(%{path_info: info, script_name: script}) do
+    "/" <> Enum.join(script ++ info, "/")
   end
 
   @doc """
diff --git a/mix.exs b/mix.exs
index 655a2cc81..d3ed848b7 100644
--- a/mix.exs
+++ b/mix.exs
@@ -28,7 +28,6 @@ defmodule Phoenix.MixProject do
         ]
       ],
       elixirc_paths: elixirc_paths(Mix.env()),
-      test_paths: test_paths(System.get_env("TEST_SUITE")),
       name: "Phoenix",
       docs: docs(),
       aliases: aliases(),
@@ -195,8 +194,7 @@ defmodule Phoenix.MixProject do
 
   defp aliases do
     [
-      docs: ["docs", &generate_js_docs/1],
-      "test.integration": [&start_integration_test/1]
+      docs: ["docs", &generate_js_docs/1]
     ]
   end
 
@@ -204,26 +202,4 @@ defmodule Phoenix.MixProject do
     Mix.Task.run("app.start")
     System.cmd("npm", ["run", "docs"], cd: "assets")
   end
-
-  defp test_paths("integration"), do: ["integration_test"]
-  defp test_paths(_), do: ["test"]
-
-  defp start_integration_test(args) do
-    mix_cmd_with_status_check(
-      ["test", ansi_option() | args],
-      env: [{"TEST_SUITE", "integration"}]
-    )
-  end
-
-  defp ansi_option do
-    if IO.ANSI.enabled?(), do: "--color", else: "--no-color"
-  end
-
-  defp mix_cmd_with_status_check(args, opts) when is_list(opts) do
-    {_, res} = System.cmd("mix", args, [into: IO.binstream(:stdio, :line)] ++ opts)
-
-    if res > 0 do
-      System.at_exit(fn _ -> exit({:shutdown, 1}) end)
-    end
-  end
 end
diff --git a/priv/templates/phx.gen.live/form_component.html.leex b/priv/templates/phx.gen.live/form_component.html.leex
index 42284c929..babdec5a7 100644
--- a/priv/templates/phx.gen.live/form_component.html.leex
+++ b/priv/templates/phx.gen.live/form_component.html.leex
@@ -10,5 +10,7 @@
   <%= input %>
   <%= error %>
 <% end %>
-  <%%= submit "Save", phx_disable_with: "Saving..." %>
+  <div>
+    <%%= submit "Save", phx_disable_with: "Saving..." %>
+  </div>
 </form>


Test patch:
diff --git a/integration_test/README.md b/integration_test/README.md
new file mode 100644
index 000000000..c1f1b3059
--- /dev/null
+++ b/integration_test/README.md
@@ -0,0 +1,25 @@
+## Phoenix Integration Tests
+
+This project contains integration tests for phoenix's generated projects.
+
+## Running tests
+
+To install dependencies, run:
+
+    $ mix deps.get
+
+Then run the tests with:
+
+    $ mix test
+
+## How tests are written
+
+In order to have consistent, repeatable builds, all dependencies for all phoenix
+project variations are listed in `mix.exs` and locked via `mix.lock`. If a
+dependency version needs to be updated, it can be updated with `mix.exs` or
+using `mix deps.update <dep name>`.
+
+It is also important to note that dependencies are initially compiled with
+`MIX_ENV=test` and then copied to `_build/dev_` to improve test speed.
+Therefore, dependencies should not be listed in `mix.exs` with an `only: <env>`
+option.
diff --git a/integration_test/mix.exs b/integration_test/mix.exs
new file mode 100644
index 000000000..83cd136b1
--- /dev/null
+++ b/integration_test/mix.exs
@@ -0,0 +1,46 @@
+defmodule Phoenix.Integration.MixProject do
+  use Mix.Project
+
+  def project do
+    [
+      app: :phoenix_integration,
+      version: "0.1.0",
+      elixir: "~> 1.9",
+      elixirc_paths: elixirc_paths(Mix.env()),
+      start_permanent: Mix.env() == :prod,
+      deps: deps()
+    ]
+  end
+
+  defp elixirc_paths(:test), do: ["lib", "test/support"]
+  defp elixirc_paths(_), do: ["lib"]
+
+  def application do
+    [
+      extra_applications: [:logger]
+    ]
+  end
+
+  # IMPORTANT: Dependencies are initially compiled with `MIX_ENV=test` and then
+  # copied to `_build/dev` to save time. Any dependencies with `only: :dev` set
+  # will not be copied.
+  defp deps do
+    [
+      {:phx_new, path: "../installer"},
+      {:phoenix, path: "../", override: true},
+      {:phoenix_ecto, "~> 4.1"},
+      {:ecto_sql, "~> 3.4.4"},
+      {:postgrex, ">= 0.0.0"},
+      {:phoenix_live_view, "~> 0.14.0"},
+      {:floki, ">= 0.27.0"},
+      {:phoenix_html, "~> 2.11"},
+      {:phoenix_live_reload, "~> 1.2"},
+      {:phoenix_live_dashboard, "~> 0.3 or ~> 0.2.9"},
+      {:telemetry_metrics, "~> 0.4"},
+      {:telemetry_poller, "~> 0.4"},
+      {:gettext, "~> 0.11"},
+      {:jason, "~> 1.0"},
+      {:plug_cowboy, "~> 2.0"}
+    ]
+  end
+end
diff --git a/integration_test/mix.lock b/integration_test/mix.lock
new file mode 100644
index 000000000..6cf42d5c3
--- /dev/null
+++ b/integration_test/mix.lock
@@ -0,0 +1,29 @@
+%{
+  "connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm", "4a0850c9be22a43af9920a71ab17c051f5f7d45c209e40269a1938832510e4d9"},
+  "cowboy": {:hex, :cowboy, "2.8.0", "f3dc62e35797ecd9ac1b50db74611193c29815401e53bac9a5c0577bd7bc667d", [:rebar3], [{:cowlib, "~> 2.9.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "4643e4fba74ac96d4d152c75803de6fad0b3fa5df354c71afdd6cbeeb15fac8a"},
+  "cowlib": {:hex, :cowlib, "2.9.1", "61a6c7c50cf07fdd24b2f45b89500bb93b6686579b069a89f88cb211e1125c78", [:rebar3], [], "hexpm", "e4175dc240a70d996156160891e1c62238ede1729e45740bdd38064dad476170"},
+  "db_connection": {:hex, :db_connection, "2.2.2", "3bbca41b199e1598245b716248964926303b5d4609ff065125ce98bcd368939e", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm", "642af240d8a8affb93b4ba5a6fcd2bbcbdc327e1a524b825d383711536f8070c"},
+  "decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
+  "ecto": {:hex, :ecto, "3.4.6", "08f7afad3257d6eb8613309af31037e16c36808dfda5a3cd0cb4e9738db030e4", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6f13a9e2a62e75c2dcfc7207bfc65645ab387af8360db4c89fee8b5a4bf3f70b"},
+  "ecto_sql": {:hex, :ecto_sql, "3.4.5", "30161f81b167d561a9a2df4329c10ae05ff36eca7ccc84628f2c8b9fa1e43323", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0 or ~> 0.4.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.0", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "31990c6a3579b36a3c0841d34a94c275e727de8b84f58509da5f1b2032c98ac2"},
+  "file_system": {:hex, :file_system, "0.2.9", "545b9c9d502e8bfa71a5315fac2a923bd060fd9acb797fe6595f54b0f975fd32", [:mix], [], "hexpm", "3cf87a377fe1d93043adeec4889feacf594957226b4f19d5897096d6f61345d8"},
+  "floki": {:hex, :floki, "0.29.0", "b1710d8c93a2f860dc2d7adc390dd808dc2fb8f78ee562304457b75f4c640881", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "008585ce64b9f74c07d32958ec9866f4b8a124bf4da1e2941b28e41384edaaad"},
+  "gettext": {:hex, :gettext, "0.18.2", "7df3ea191bb56c0309c00a783334b288d08a879f53a7014341284635850a6e55", [:mix], [], "hexpm", "f9f537b13d4fdd30f3039d33cb80144c3aa1f8d9698e47d7bcbcc8df93b1f5c5"},
+  "html_entities": {:hex, :html_entities, "0.5.1", "1c9715058b42c35a2ab65edc5b36d0ea66dd083767bef6e3edb57870ef556549", [:mix], [], "hexpm", "30efab070904eb897ff05cd52fa61c1025d7f8ef3a9ca250bc4e6513d16c32de"},
+  "jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"},
+  "mime": {:hex, :mime, "1.4.0", "5066f14944b470286146047d2f73518cf5cca82f8e4815cf35d196b58cf07c47", [:mix], [], "hexpm", "75fa42c4228ea9a23f70f123c74ba7cece6a03b1fd474fe13f6a7a85c6ea4ff6"},
+  "phoenix_ecto": {:hex, :phoenix_ecto, "4.2.1", "13f124cf0a3ce0f1948cf24654c7b9f2347169ff75c1123f44674afee6af3b03", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 2.15", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "478a1bae899cac0a6e02be1deec7e2944b7754c04e7d4107fc5a517f877743c0"},
+  "phoenix_html": {:hex, :phoenix_html, "2.14.2", "b8a3899a72050f3f48a36430da507dd99caf0ac2d06c77529b1646964f3d563e", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "58061c8dfd25da5df1ea0ca47c972f161beb6c875cd293917045b92ffe1bf617"},
+  "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.2.9", "ac43a73561a4010fd2a52289a2f570829e2be5d5ea408a5af99dbed8793439e7", [:mix], [{:phoenix_html, "~> 2.14.1 or ~> 2.15", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.14.3", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.4.0 or ~> 0.5.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "f7cd3265a53d2bcd2e541a7d3c55f5a22e07bf6070b1d4adabd81791885190f7"},
+  "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.2.4", "940c0344b1d66a2e46eef02af3a70e0c5bb45a4db0bf47917add271b76cd3914", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "38f9308357dea4cc77f247e216da99fcb0224e05ada1469167520bed4cb8cccd"},
+  "phoenix_live_view": {:hex, :phoenix_live_view, "0.14.7", "e05ca2e57974bb99eb54fed88b04754a622e54cf7e832db3c868bd06e0b99ff2", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.5.3", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 0.5", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "899224a704221ab0019200da61019dea699763e12daa24d69edd79bc228fe5a5"},
+  "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.0.0", "a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm", "c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"},
+  "plug": {:hex, :plug, "1.10.4", "41eba7d1a2d671faaf531fa867645bd5a3dce0957d8e2a3f398ccff7d2ef017f", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ad1e233fe73d2eec56616568d260777b67f53148a999dc2d048f4eb9778fe4a0"},
+  "plug_cowboy": {:hex, :plug_cowboy, "2.3.0", "149a50e05cb73c12aad6506a371cd75750c0b19a32f81866e1a323dda9e0e99d", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bc595a1870cef13f9c1e03df56d96804db7f702175e4ccacdb8fc75c02a7b97e"},
+  "plug_crypto": {:hex, :plug_crypto, "1.1.2", "bdd187572cc26dbd95b87136290425f2b580a116d3fb1f564216918c9730d227", [:mix], [], "hexpm", "6b8b608f895b6ffcfad49c37c7883e8df98ae19c6a28113b02aa1e9c5b22d6b5"},
+  "postgrex": {:hex, :postgrex, "0.15.6", "a464c72010a56e3214fe2b99c1a76faab4c2bb0255cabdef30dea763a3569aa2", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "f99268325ac8f66ffd6c4964faab9e70fbf721234ab2ad238c00f9530b8cdd55"},
+  "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm", "451d8527787df716d99dc36162fca05934915db0b6141bbdac2ea8d3c7afc7d7"},
+  "telemetry": {:hex, :telemetry, "0.4.2", "2808c992455e08d6177322f14d3bdb6b625fbcfd233a73505870d8738a2f4599", [:rebar3], [], "hexpm", "2d1419bd9dda6a206d7b5852179511722e2b18812310d304620c7bd92a13fcef"},
+  "telemetry_metrics": {:hex, :telemetry_metrics, "0.5.0", "1b796e74add83abf844e808564275dfb342bcc930b04c7577ab780e262b0d998", [:mix], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "31225e6ce7a37a421a0a96ec55244386aec1c190b22578bd245188a4a33298fd"},
+  "telemetry_poller": {:hex, :telemetry_poller, "0.5.1", "21071cc2e536810bac5628b935521ff3e28f0303e770951158c73eaaa01e962a", [:rebar3], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4cab72069210bc6e7a080cec9afffad1b33370149ed5d379b81c7c5f0c663fd4"},
+}
diff --git a/integration_test/code_generation/app_with_defaults_test.exs b/integration_test/test/code_generation/app_with_defaults_test.exs
similarity index 86%
rename from integration_test/code_generation/app_with_defaults_test.exs
rename to integration_test/test/code_generation/app_with_defaults_test.exs
index 3fcb64be4..f6a3a7995 100644
--- a/integration_test/code_generation/app_with_defaults_test.exs
+++ b/integration_test/test/code_generation/app_with_defaults_test.exs
@@ -1,5 +1,3 @@
-Code.require_file("../support/code_generator_case.exs", __DIR__)
-
 defmodule Phoenix.Integration.CodeGeneration.AppWithDefaultsTest do
   use Phoenix.Integration.CodeGeneratorCase, async: true
 
diff --git a/integration_test/code_generation/app_with_no_options_test.exs b/integration_test/test/code_generation/app_with_no_options_test.exs
similarity index 89%
rename from integration_test/code_generation/app_with_no_options_test.exs
rename to integration_test/test/code_generation/app_with_no_options_test.exs
index 65858f505..34094a02b 100644
--- a/integration_test/code_generation/app_with_no_options_test.exs
+++ b/integration_test/test/code_generation/app_with_no_options_test.exs
@@ -1,5 +1,3 @@
-Code.require_file("../support/code_generator_case.exs", __DIR__)
-
 defmodule Phoenix.Integration.CodeGeneration.AppWithNoOptionsTest do
   use Phoenix.Integration.CodeGeneratorCase, async: true
 
diff --git a/integration_test/code_generation/umbrella_app_with_defaults_test.exs b/integration_test/test/code_generation/umbrella_app_with_defaults_test.exs
similarity index 86%
rename from integration_test/code_generation/umbrella_app_with_defaults_test.exs
rename to integration_test/test/code_generation/umbrella_app_with_defaults_test.exs
index 6fcb20f21..d1eafa4a5 100644
--- a/integration_test/code_generation/umbrella_app_with_defaults_test.exs
+++ b/integration_test/test/code_generation/umbrella_app_with_defaults_test.exs
@@ -1,5 +1,3 @@
-Code.require_file("../support/code_generator_case.exs", __DIR__)
-
 defmodule Phoenix.Integration.CodeGeneration.UmbrellaAppWithDefaultsTest do
   use Phoenix.Integration.CodeGeneratorCase, async: true
 
diff --git a/integration_test/support/code_generator_case.exs b/integration_test/test/support/code_generator_case.ex
similarity index 87%
rename from integration_test/support/code_generator_case.exs
rename to integration_test/test/support/code_generator_case.ex
index 0580e1fae..d99443909 100644
--- a/integration_test/support/code_generator_case.exs
+++ b/integration_test/test/support/code_generator_case.ex
@@ -10,12 +10,17 @@ defmodule Phoenix.Integration.CodeGeneratorCase do
   def generate_phoenix_app(tmp_dir, app_name, opts \\ [])
       when is_binary(app_name) and is_list(opts) do
     app_path = Path.expand(app_name, tmp_dir)
-    installer_root = Path.expand("../../installer", __DIR__)
+    integration_test_root_path = Path.expand("../../", __DIR__)
     app_root_path = get_app_root_path(tmp_dir, app_name, opts)
 
-    mix_run!(["phx.new", app_path, "--dev", "--no-install"] ++ opts, installer_root)
+    mix_run!(["phx.new", app_path, "--dev", "--no-install"] ++ opts, integration_test_root_path)
 
-    mix_run!(~w(deps.get), app_root_path)
+    for path <- ~w(mix.lock deps _build) do
+      File.cp_r!(
+        Path.join(integration_test_root_path, path),
+        Path.join(app_root_path, path)
+      )
+    end
 
     app_root_path
   end
@@ -69,7 +74,7 @@ defmodule Phoenix.Integration.CodeGeneratorCase do
   end
 
   defp installer_tmp_path do
-    Path.expand("../../installer/tmp", __DIR__)
+    Path.expand("../../../installer/tmp", __DIR__)
   end
 
   defp get_app_root_path(tmp_dir, app_name, opts) do
diff --git a/integration_test/test/test_helper.exs b/integration_test/test/test_helper.exs
new file mode 100644
index 000000000..837fc8c8b
--- /dev/null
+++ b/integration_test/test/test_helper.exs
@@ -0,0 +1,10 @@
+# Copy _build/test to _build/dev so it only has to be compiled once
+File.rm_rf!(Path.expand("../_build/dev", __DIR__))
+
+File.cp_r!(
+  Path.expand("../_build/test", __DIR__),
+  Path.expand("../_build/dev", __DIR__)
+)
+
+ExUnit.configure(timeout: 180_000)
+ExUnit.start()
diff --git a/integration_test/test_helper.exs b/integration_test/test_helper.exs
deleted file mode 100644
index 141158fc2..000000000
--- a/integration_test/test_helper.exs
+++ /dev/null
@@ -1,8 +0,0 @@
-Code.require_file("./support/code_generator_case.exs", __DIR__)
-
-# Compile installer app up front so multiple test cases
-# don't try to compile it at the same time.
-Phoenix.Integration.CodeGeneratorCase.mix_run!(["do", "deps.get,", "compile"], "./installer")
-
-ExUnit.configure(max_cases: 2, timeout: 180_000)
-ExUnit.start()
diff --git a/priv/templates/phx.gen.live/live_test.exs b/priv/templates/phx.gen.live/live_test.exs
index 2c5609e0a..84bf9e3ac 100644
--- a/priv/templates/phx.gen.live/live_test.exs
+++ b/priv/templates/phx.gen.live/live_test.exs
@@ -4,9 +4,9 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
   import Phoenix.LiveViewTest
   import <%= inspect context.module %>Fixtures
 
-  @create_attrs <%= inspect schema.params.create %>
-  @update_attrs <%= inspect schema.params.update %>
-  @invalid_attrs <%= inspect for {key, _} <- schema.params.create, into: %{}, do: {key, nil} %>
+  @create_attrs <%= inspect for {key, value} <- schema.params.create, into: %{}, do: {key, Mix.Phoenix.Schema.live_form_value(value)} %>
+  @update_attrs <%= inspect for {key, value} <- schema.params.update, into: %{}, do: {key, Mix.Phoenix.Schema.live_form_value(value)} %>
+  @invalid_attrs <%= inspect for {key, value} <- schema.params.create, into: %{}, do: {key, value |> Mix.Phoenix.Schema.live_form_value() |> Mix.Phoenix.Schema.invalid_form_value()} %>
 
   defp create_<%= schema.singular %>(_) do
     <%= schema.singular %> = <%= schema.singular %>_fixture()
@@ -16,7 +16,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
   describe "Index" do
     setup [:create_<%= schema.singular %>]
 
-    test "lists all <%= schema.plural %>", %{conn: conn, <%= schema.singular %>: <%= schema.singular %>} do
+    test "lists all <%= schema.plural %>", <%= if schema.string_attr do %>%{conn: conn, <%= schema.singular %>: <%= schema.singular %>}<% else %>%{conn: conn}<% end %> do
       {:ok, _index_live, html} = live(conn, Routes.<%= schema.route_helper %>_index_path(conn, :index))
 
       assert html =~ "Listing <%= schema.human_plural %>"<%= if schema.string_attr do %>
diff --git a/test/mix/phoenix_test.exs b/test/mix/phoenix_test.exs
index 3c22e66a1..f6d69f687 100644
--- a/test/mix/phoenix_test.exs
+++ b/test/mix/phoenix_test.exs
@@ -76,14 +76,76 @@ defmodule Mix.PhoenixTest do
       admin: true,
       meta: %{},
       name: "some name",
-      date_of_birth: ~D[2010-04-17],
+      date_of_birth: Date.add(Date.utc_today(), -1),
       happy_hour: ~T[14:00:00],
       happy_hour_usec: ~T[14:00:00.000000],
-      joined: ~N[2010-04-17 14:00:00],
-      joined_utc: ~U[2010-04-17 14:00:00Z],
-      joined_utc_usec: ~U[2010-04-17 14:00:00.000000Z],
+      joined: NaiveDateTime.truncate(build_utc_naive_datetime(), :second),
+      joined_utc: DateTime.truncate(build_utc_datetime(), :second),
+      joined_utc_usec: build_utc_datetime(),
       token: "7488a646-e31f-11e4-aace-600308960662",
       other: "some other"
     }
   end
+
+  @one_day_in_seconds 24 * 3600
+
+  defp build_utc_datetime, 
+    do: DateTime.add(%{DateTime.utc_now() | second: 0, microsecond: {0, 6}}, -@one_day_in_seconds)
+
+  defp build_utc_naive_datetime, 
+    do: NaiveDateTime.add(%{NaiveDateTime.utc_now() | second: 0, microsecond: {0, 6}}, -@one_day_in_seconds)
+
+  test "live_form_value/1" do
+    assert Mix.Phoenix.Schema.live_form_value(~D[2020-10-09]) == %{day: 9, month: 10, year: 2020}
+    assert Mix.Phoenix.Schema.live_form_value(~T[14:00:00]) == %{hour: 14, minute: 00}
+    assert Mix.Phoenix.Schema.live_form_value(~N[2020-10-09 14:00:00]) == %{
+             day: 9,
+             month: 10,
+             year: 2020,
+             hour: 14,
+             minute: 00
+           }
+
+    assert Mix.Phoenix.Schema.live_form_value(~U[2020-10-09T14:00:00Z]) == %{
+             day: 9,
+             month: 10,
+             year: 2020,
+             hour: 14,
+             minute: 00
+           }
+
+    assert Mix.Phoenix.Schema.live_form_value(:value) == :value 
+  end
+
+  test "invalid_form_value/1" do
+    assert ~D[2020-10-09]
+           |> Mix.Phoenix.Schema.live_form_value()
+           |> Mix.Phoenix.Schema.invalid_form_value() == %{day: 9, month: 10, year: 2020}
+
+    assert ~T[14:00:00]
+           |> Mix.Phoenix.Schema.live_form_value()
+           |> Mix.Phoenix.Schema.invalid_form_value() == %{hour: 14, minute: 00}
+
+    assert ~N[2020-10-09 14:00:00]
+           |> Mix.Phoenix.Schema.live_form_value()
+           |> Mix.Phoenix.Schema.invalid_form_value() == %{
+             day: 9,
+             month: 10,
+             year: 2020,
+             hour: 14,
+             minute: 00
+           }
+
+    assert ~U[2020-10-09T14:00:00Z]
+           |> Mix.Phoenix.Schema.live_form_value()
+           |> Mix.Phoenix.Schema.invalid_form_value() == %{
+             day: 9,
+             month: 10,
+             year: 2020,
+             hour: 14,
+             minute: 00
+           }
+
+    assert Mix.Phoenix.Schema.invalid_form_value(:value) == nil
+  end
 end
diff --git a/test/mix/tasks/phx.gen.html_test.exs b/test/mix/tasks/phx.gen.html_test.exs
index e6127115f..9b5299073 100644
--- a/test/mix/tasks/phx.gen.html_test.exs
+++ b/test/mix/tasks/phx.gen.html_test.exs
@@ -35,6 +35,10 @@ defmodule Mix.Tasks.Phx.Gen.HtmlTest do
   end
 
   test "generates html resource and handles existing contexts", config do
+    one_day_in_seconds = 24 * 3600
+    naive_datetime = %{NaiveDateTime.utc_now() | second: 0, microsecond: {0, 6}} 
+    datetime = %{DateTime.utc_now() | second: 0, microsecond: {0, 6}}
+
     in_tmp_project config.test, fn ->
       Gen.Html.run(~w(Blog Post posts title slug:unique votes:integer cost:decimal
                       tags:array:text popular:boolean drafted_at:datetime
@@ -52,19 +56,19 @@ defmodule Mix.Tasks.Phx.Gen.HtmlTest do
       assert_file "test/phoenix/blog_test.exs", fn file ->
         assert file =~ "alarm: ~T[15:01:01]"
         assert file =~ "alarm_usec: ~T[15:01:01.000000]"
-        assert file =~ "announcement_date: ~D[2010-04-17]"
-        assert file =~ "deleted_at: ~N[2010-04-17 14:00:00]"
-        assert file =~ "deleted_at_usec: ~N[2010-04-17 14:00:00.000000]"
+        assert file =~ "announcement_date: #{Date.utc_today() |> Date.add(-1) |> inspect()}"
+        assert file =~ "deleted_at: #{naive_datetime |> NaiveDateTime.add(-one_day_in_seconds) |> NaiveDateTime.truncate(:second) |> inspect()}"
+        assert file =~ "deleted_at_usec: #{naive_datetime |> NaiveDateTime.add(-one_day_in_seconds) |> inspect()}"
         assert file =~ "cost: \"120.5\""
-        assert file =~ "published_at: ~U[2010-04-17 14:00:00Z]"
-        assert file =~ "published_at_usec: ~U[2010-04-17 14:00:00.000000Z]"
+        assert file =~ "published_at: #{datetime |> DateTime.add(-one_day_in_seconds) |> DateTime.truncate(:second) |> inspect()}"
+        assert file =~ "published_at_usec: #{datetime |> DateTime.add(-one_day_in_seconds) |> inspect()}"
         assert file =~ "weight: 120.5"
 
-        assert file =~ "assert post.announcement_date == ~D[2011-05-18]"
-        assert file =~ "assert post.deleted_at == ~N[2011-05-18 15:01:01]"
-        assert file =~ "assert post.deleted_at_usec == ~N[2011-05-18 15:01:01.000000]"
-        assert file =~ "assert post.published_at == ~U[2011-05-18 15:01:01Z]"
-        assert file =~ "assert post.published_at_usec == ~U[2011-05-18 15:01:01.000000Z]"
+        assert file =~ "assert post.announcement_date == #{inspect(Date.utc_today())}"
+        assert file =~ "assert post.deleted_at == #{naive_datetime |> NaiveDateTime.truncate(:second) |> inspect()}"
+        assert file =~ "assert post.deleted_at_usec == #{inspect(naive_datetime)}"
+        assert file =~ "assert post.published_at == #{datetime |> DateTime.truncate(:second) |> inspect()}"
+        assert file =~ "assert post.published_at_usec == #{inspect(datetime)}"
         assert file =~ "assert post.alarm == ~T[15:01:01]"
         assert file =~ "assert post.alarm_usec == ~T[15:01:01.000000]"
         assert file =~ "assert post.cost == Decimal.new(\"120.5\")"
@@ -255,6 +259,31 @@ defmodule Mix.Tasks.Phx.Gen.HtmlTest do
     end
   end
 
+  test "with --no-context no warning is emitted when context exists", config do
+    in_tmp_project config.test, fn ->
+      Gen.Html.run(~w(Blog Post posts title:string))
+
+      assert_file "lib/phoenix/blog.ex"
+      assert_file "lib/phoenix/blog/post.ex"
+
+      Gen.Html.run(~w(Blog Comment comments title:string --no-context))
+      refute_received {:mix_shell, :info, ["You are generating into an existing context" <> _]}
+
+      assert_file "test/phoenix_web/controllers/comment_controller_test.exs", fn file ->
+        assert file =~ "defmodule PhoenixWeb.CommentControllerTest"
+      end
+
+      assert_file "lib/phoenix_web/controllers/comment_controller.ex", fn file ->
+        assert file =~ "defmodule PhoenixWeb.CommentController"
+        assert file =~ "use PhoenixWeb, :controller"
+      end
+
+      assert_file "lib/phoenix_web/views/comment_view.ex", fn file ->
+        assert file =~ "defmodule PhoenixWeb.CommentView"
+      end
+    end
+  end
+
   test "with --no-schema skips schema file generation", config do
     in_tmp_project config.test, fn ->
       Gen.Html.run(~w(Blog Comment comments title:string --no-schema))
diff --git a/test/mix/tasks/phx.gen.json_test.exs b/test/mix/tasks/phx.gen.json_test.exs
index 39dec3351..492e51119 100644
--- a/test/mix/tasks/phx.gen.json_test.exs
+++ b/test/mix/tasks/phx.gen.json_test.exs
@@ -35,6 +35,16 @@ defmodule Mix.Tasks.Phx.Gen.JsonTest do
   end
 
   test "generates json resource", config do
+    one_day_in_seconds = 24 * 3600
+
+    naive_datetime =
+      %{NaiveDateTime.utc_now() | second: 0, microsecond: {0, 6}}
+      |> NaiveDateTime.add(-one_day_in_seconds)
+
+    datetime = 
+      %{DateTime.utc_now() | second: 0, microsecond: {0, 6}}
+      |> DateTime.add(-one_day_in_seconds)
+
     in_tmp_project config.test, fn ->
      Gen.Json.run(~w(Blog Post posts title slug:unique votes:integer cost:decimal
                      tags:array:text popular:boolean drafted_at:datetime
@@ -58,20 +68,19 @@ defmodule Mix.Tasks.Phx.Gen.JsonTest do
       assert_file "test/phoenix_web/controllers/post_controller_test.exs", fn file ->
         assert file =~ "defmodule PhoenixWeb.PostControllerTest"
         assert file =~ """
-
               assert %{
                        "id" => id,
                        "alarm" => "14:00:00",
                        "alarm_usec" => "14:00:00.000000",
-                       "announcement_date" => "2010-04-17",
+                       "announcement_date" => "#{Date.add(Date.utc_today(), -1)}",
                        "cost" => "120.5",
-                       "deleted_at" => "2010-04-17T14:00:00",
-                       "deleted_at_usec" => "2010-04-17T14:00:00.000000",
-                       "drafted_at" => "2010-04-17T14:00:00",
+                       "deleted_at" => "#{naive_datetime |> NaiveDateTime.truncate(:second) |> NaiveDateTime.to_iso8601()}",
+                       "deleted_at_usec" => "#{NaiveDateTime.to_iso8601(naive_datetime)}",
+                       "drafted_at" => "#{datetime |> NaiveDateTime.truncate(:second) |> NaiveDateTime.to_iso8601()}",
                        "params" => %{},
                        "popular" => true,
-                       "published_at" => "2010-04-17T14:00:00Z",
-                       "published_at_usec" => "2010-04-17T14:00:00.000000Z",
+                       "published_at" => "#{datetime |> DateTime.truncate(:second) |> DateTime.to_iso8601()}",
+                       "published_at_usec" => "#{DateTime.to_iso8601(datetime)}",
                        "secret" => "7488a646-e31f-11e4-aace-600308960662",
                        "slug" => "some slug",
                        "tags" => [],
@@ -163,6 +172,31 @@ defmodule Mix.Tasks.Phx.Gen.JsonTest do
     end
   end
 
+  test "with --no-context no warning is emitted when context exists", config do
+    in_tmp_project config.test, fn ->
+      Gen.Json.run(~w(Blog Post posts title:string))
+
+      assert_file "lib/phoenix/blog.ex"
+      assert_file "lib/phoenix/blog/post.ex"
+
+      Gen.Json.run(~w(Blog Comment comments title:string --no-context))
+      refute_received {:mix_shell, :info, ["You are generating into an existing context" <> _]}
+
+      assert_file "test/phoenix_web/controllers/comment_controller_test.exs", fn file ->
+        assert file =~ "defmodule PhoenixWeb.CommentControllerTest"
+      end
+
+      assert_file "lib/phoenix_web/controllers/comment_controller.ex", fn file ->
+        assert file =~ "defmodule PhoenixWeb.CommentController"
+        assert file =~ "use PhoenixWeb, :controller"
+      end
+
+      assert_file "lib/phoenix_web/views/comment_view.ex", fn file ->
+        assert file =~ "defmodule PhoenixWeb.CommentView"
+      end
+    end
+  end
+
   test "with --no-schema skips schema file generation", config do
     in_tmp_project config.test, fn ->
       Gen.Json.run(~w(Blog Comment comments title:string --no-schema))
diff --git a/test/mix/tasks/phx.gen.live_test.exs b/test/mix/tasks/phx.gen.live_test.exs
index 5afd2625b..5aefc4bcb 100644
--- a/test/mix/tasks/phx.gen.live_test.exs
+++ b/test/mix/tasks/phx.gen.live_test.exs
@@ -285,6 +285,26 @@ defmodule Mix.Tasks.Phx.Gen.LiveTest do
     end
   end
 
+  test "with --no-context does not emit warning when context exists", config do
+    in_tmp_live_project config.test, fn ->
+      Gen.Live.run(~w(Blog Post posts title:string))
+
+      assert_file "lib/phoenix/blog.ex"
+      assert_file "lib/phoenix/blog/post.ex"
+
+      Gen.Live.run(~w(Blog Comment comments title:string --no-context))
+      refute_received {:mix_shell, :info, ["You are generating into an existing context" <> _]}
+
+      assert_file "lib/phoenix_web/live/comment_live/index.ex"
+      assert_file "lib/phoenix_web/live/comment_live/show.ex"
+      assert_file "lib/phoenix_web/live/comment_live/form_component.ex"
+
+      assert_file "lib/phoenix_web/live/comment_live/index.html.leex"
+      assert_file "lib/phoenix_web/live/comment_live/show.html.leex"
+      assert_file "lib/phoenix_web/live/comment_live/form_component.html.leex"
+      assert_file "test/phoenix_web/live/comment_live_test.exs"
+    end
+  end
 
   test "with same singular and plural", config do
     in_tmp_live_project config.test, fn ->
diff --git a/test/phoenix/controller/controller_test.exs b/test/phoenix/controller/controller_test.exs
index 9d3761f46..97ecf081b 100644
--- a/test/phoenix/controller/controller_test.exs
+++ b/test/phoenix/controller/controller_test.exs
@@ -641,6 +641,9 @@ defmodule Phoenix.Controller.ControllerTest do
 
       conn = build_conn_for_path("/foo?one=1&two=2")
       assert current_path(conn) == "/foo?one=1&two=2"
+
+      conn = build_conn_for_path("/foo//bar/")
+      assert current_path(conn) == "/foo/bar"
     end
 
     test "current_path/2 allows custom query params" do