Repository: phoenixframework/phoenix
Pull request #4983 (2022-09-26 10:57:29)

Bump actions/cache from 2 to 3
[//]: # (dependabot-start)
⚠️  **Dependabot is rebasing this PR** ⚠️ 

Rebasing might not happen immediately, so don't worry if this takes some time.

Note: if you make any changes to this PR yourself, they will take precedence over the rebase.

---

[//]: # (dependabot-end)

Bumps [actions/cache](https://github.com/actions/cache) from 2 to 3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/actions/cache/releases">actions/cache's releases</a>.</em></p>
<blockquote>
<h2>v3.0.0</h2>
<ul>
<li>
<p>This change adds a minimum runner version(node12 -&gt; node16), which can break users using an out-of-date/fork of the runner. This would be most commonly affecting users on GHES 3.3 or before, as those runners do not support node16 actions and they can use actions from github.com via <a href="https://docs.github.com/en/enterprise-server@3.0/admin/github-actions/managing-access-to-actions-from-githubcom/enabling-automatic-access-to-githubcom-actions-using-github-connect">github connect</a> or manually copying the repo to their GHES instance.</p>
</li>
<li>
<p>Few dependencies and cache action usage examples have also been updated.</p>
</li>
</ul>
<h2>v2.1.7</h2>
<p>Support 10GB cache upload using the latest version <code>1.0.8</code> of <a href="https://www.npmjs.com/package/@actions/cache"><code>@actions/cache</code> </a></p>
<h2>v2.1.6</h2>
<ul>
<li>Catch unhandled &quot;bad file descriptor&quot; errors that sometimes occurs when the cache server returns non-successful response (<a href="https://github-redirect.dependabot.com/actions/cache/pull/596">actions/cache#596</a>)</li>
</ul>
<h2>v2.1.5</h2>
<ul>
<li>Fix permissions error seen when extracting caches with GNU tar that were previously created using BSD tar (<a href="https://github-redirect.dependabot.com/actions/cache/issues/527">actions/cache#527</a>)</li>
</ul>
<h2>v2.1.4</h2>
<ul>
<li>Make caching more verbose <a href="https://github-redirect.dependabot.com/actions/toolkit/pull/650">#650</a></li>
<li>Use GNU tar on macOS if available <a href="https://github-redirect.dependabot.com/actions/toolkit/pull/701">#701</a></li>
</ul>
<h2>v2.1.3</h2>
<ul>
<li>Upgrades <code>@actions/core</code> to v1.2.6 for <a href="https://github.com/advisories/GHSA-mfwh-5m23-j46w">CVE-2020-15228</a>. This action was not using the affected methods.</li>
<li>Fix error handling in <code>uploadChunk</code> where 400-level errors were not being detected and handled correctly</li>
</ul>
<h2>v2.1.2</h2>
<ul>
<li>Adds input to limit the chunk upload size, useful for self-hosted runners with slower upload speeds</li>
<li>No-op when executing on GHES</li>
</ul>
<h2>v2.1.1</h2>
<ul>
<li>Update <code>@actions/cache</code> package to <code>v1.0.2</code> which allows cache action to use posix format when taring files.</li>
</ul>
<h2>v2.1.0</h2>
<ul>
<li>Replaces the <code>http-client</code> with the Azure Storage SDK for NodeJS when downloading cache content from Azure.  This should help improve download performance and reliability as the SDK downloads files in 4 MB chunks, which can be parallelized and retried independently</li>
<li>Display download progress and speed</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/actions/cache/blob/main/RELEASES.md">actions/cache's changelog</a>.</em></p>
<blockquote>
<h1>Releases</h1>
<h3>3.0.0</h3>
<ul>
<li>Updated minimum runner version support from node 12 -&gt; node 16</li>
</ul>
<h3>3.0.1</h3>
<ul>
<li>Added support for caching from GHES 3.5.</li>
<li>Fixed download issue for files &gt; 2GB during restore.</li>
</ul>
<h3>3.0.2</h3>
<ul>
<li>Added support for dynamic cache size cap on GHES.</li>
</ul>
<h3>3.0.3</h3>
<ul>
<li>Fixed avoiding empty cache save when no files are available for caching. (<a href="https://github-redirect.dependabot.com/actions/cache/issues/624">issue</a>)</li>
</ul>
<h3>3.0.4</h3>
<ul>
<li>Fixed tar creation error while trying to create tar with path as <code>~/</code> home folder on <code>ubuntu-latest</code>. (<a href="https://github-redirect.dependabot.com/actions/cache/issues/689">issue</a>)</li>
</ul>
<h3>3.0.5</h3>
<ul>
<li>Removed error handling by consuming actions/cache 3.0 toolkit, Now cache server error handling will be done by toolkit. (<a href="https://github-redirect.dependabot.com/actions/cache/pull/834">PR</a>)</li>
</ul>
<h3>3.0.6</h3>
<ul>
<li>Fixed <a href="https://github-redirect.dependabot.com/actions/cache/issues/809">#809</a> - zstd -d: no such file or directory error</li>
<li>Fixed <a href="https://github-redirect.dependabot.com/actions/cache/issues/833">#833</a> - cache doesn't work with github workspace directory</li>
</ul>
<h3>3.0.7</h3>
<ul>
<li>Fixed <a href="https://github-redirect.dependabot.com/actions/cache/issues/810">#810</a> - download stuck issue. A new timeout is introduced in the download process to abort the download if it gets stuck and doesn't finish within an hour.</li>
</ul>
<h3>3.0.8</h3>
<ul>
<li>Fix zstd not working for windows on gnu tar in issues <a href="https://github-redirect.dependabot.com/actions/cache/issues/888">#888</a> and <a href="https://github-redirect.dependabot.com/actions/cache/issues/891">#891</a>.</li>
<li>Allowing users to provide a custom timeout as input for aborting download of a cache segment using an environment variable <code>SEGMENT_DOWNLOAD_TIMEOUT_MIN</code>. Default is 60 minutes.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/actions/cache/commit/fd5de65bc895cf536527842281bea11763fefd77"><code>fd5de65</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/actions/cache/issues/899">#899</a> from actions/kotewar/download-and-compression-fix</li>
<li><a href="https://github.com/actions/cache/commit/d49b6bb21d712fc1556f99339b8324b1603f7560"><code>d49b6bb</code></a> Updated actions/cache toolkit dep to v3.0.4</li>
<li><a href="https://github.com/actions/cache/commit/a7c34adf76222e77931dedbf4a45b2e4648ced19"><code>a7c34ad</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/actions/cache/issues/894">#894</a> from actions/kotewar/update-toolkit-version</li>
<li><a href="https://github.com/actions/cache/commit/83394c99b7089b29ee6c302fad5e940df48c472a"><code>83394c9</code></a> Updated cache version in license file</li>
<li><a href="https://github.com/actions/cache/commit/e839c25979e6ffdd90792d34de69d6a87d3016f6"><code>e839c25</code></a> Updated actions/cache version to 3.0.3</li>
<li><a href="https://github.com/actions/cache/commit/33a923d660988a68affcd47de6bd6744193223a6"><code>33a923d</code></a> Added release information</li>
<li><a href="https://github.com/actions/cache/commit/a404368986bb049d406166fc20afc01d032ad8a2"><code>a404368</code></a> Updated actions/cache version to 3.0.2</li>
<li><a href="https://github.com/actions/cache/commit/f4278025ab0f432ce369118909e46deec636f50c"><code>f427802</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/actions/cache/issues/887">#887</a> from actions/pdotl-version-patch</li>
<li><a href="https://github.com/actions/cache/commit/9916fe1701f098b95a05e7c2bacee7c5a022c553"><code>9916fe1</code></a> Update cache version in licences</li>
<li><a href="https://github.com/actions/cache/commit/318935ef66557a1906560e4e7d0069344a4b31bf"><code>318935e</code></a> Update README and RELEASES</li>
<li>Additional commits viewable in <a href="https://github.com/actions/cache/compare/v2...v3">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/cache&package-manager=github_actions&previous-version=2&new-version=3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index bc66afe19..d0746ec66 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -25,7 +25,7 @@ jobs:
 
     steps:
     - name: Checkout
-      uses: actions/checkout@v2
+      uses: actions/checkout@v3
 
     - name: Set up Elixir
       uses: erlef/setup-beam@v1
@@ -34,7 +34,7 @@ jobs:
         otp-version: ${{ matrix.otp }}
 
     - name: Restore deps and _build cache
-      uses: actions/cache@v2
+      uses: actions/cache@v3
       with:
         path: |
           deps
@@ -67,10 +67,10 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Checkout
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
 
       - name: Restore deps and _build cache
-        uses: actions/cache@v2
+        uses: actions/cache@v3
         with:
           path: |
             deps
@@ -85,7 +85,7 @@ jobs:
           node-version: 12.x
 
       - name: Restore npm cache
-        uses: actions/cache@v2
+        uses: actions/cache@v3
         with:
           path: ~/.npm
           key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
diff --git a/installer/templates/phx_web/components.ex b/installer/templates/phx_web/components.ex
index 897d4fe7f..b3dd2457a 100644
--- a/installer/templates/phx_web/components.ex
+++ b/installer/templates/phx_web/components.ex
@@ -24,7 +24,7 @@ defmodule <%= @web_namespace %>.Components do
         Are you sure?
         <:confirm>OK</:confirm>
         <:cancel>Cancel</:cancel>
-      <.modal>
+      </.modal>
 
   JS commands may be passed to the `:on_cancel` and `on_confirm` attributes
   for the caller to reactor to each button press, for example:
@@ -32,8 +32,8 @@ defmodule <%= @web_namespace %>.Components do
       <.modal id="confirm" on_confirm={JS.push("delete")} on_cancel={JS.navigate(~p"/posts")}>
         Are you sure you?
         <:confirm>OK</:confirm>
-        <:cancel>Cancel</:confirm>
-      <.modal>
+        <:cancel>Cancel</:cancel>
+      </.modal>
   """
   attr :id, :string, required: true
   attr :show, :boolean, default: false
@@ -126,10 +126,10 @@ defmodule <%= @web_namespace %>.Components do
   attr :id, :string, default: "flash", doc: "the optional id of flash container"
   attr :flash, :map, default: %{}, doc: "the map of flash messages to display"
   attr :title, :string, default: nil
-  attr :rest, :global
-  attr :kind, :atom, doc: "one of :info, :error used for styling and flash lookup"
+  attr :kind, :atom, values: [:info, :error], doc: "Used for styling and flash lookup"
   attr :autoshow, :boolean, default: true, doc: "whether to auto show the flash on mount"
   attr :close, :boolean, default: true, doc: "whether the flash can be closed"
+  attr :rest, :global, doc: "the aribtrary HTML attributes to add to the flash container"
 
   slot :inner_block, doc: "the optional inner block that renders the flash message"
 
@@ -171,12 +171,14 @@ defmodule <%= @web_namespace %>.Components do
         <.input field={{f, :username}} label="Username" />
         <:actions>
           <.button>Save</.button>
-        <:actions>
+        </:actions>
       </.simple_form>
   """
   attr :for, :any, default: nil, doc: "the datastructure for the form"
   attr :as, :any, default: nil, doc: "the server side parameter to collect all input under"
-  attr :rest, :global, doc: "the arbitrary HTML attributes to apply to the form tag"
+  attr :rest, :global,
+    include: ~w(autocomplete name rel action enctype method novalidate target),
+    doc: "the arbitrary HTML attributes to apply to the form tag"
 
   slot :inner_block, required: true
   slot :actions, doc: "the slot for form actions, such as a submit button"
@@ -204,7 +206,7 @@ defmodule <%= @web_namespace %>.Components do
   """
   attr :type, :string, default: nil
   attr :class, :string, default: nil
-  attr :rest, :global, doc: "the arbitrary HTML attributes to apply to the button tag"
+  attr :rest, :global, include: ~w(disabled form name value)
 
   slot :inner_block, required: true
 
@@ -242,13 +244,14 @@ defmodule <%= @web_namespace %>.Components do
 
   attr :type, :string,
     default: "text",
-    doc: ~s|one of "text", "textarea", "number" "email", "date", "time", "datetime", "select"|
+    values: ~w(checkbox color date datetime-local email file hidden month number password
+               range radio search tel text time url week)
 
   attr :value, :any
   attr :field, :any, doc: "a %Phoenix.HTML.Form{}/field name tuple, for example: {f, :email}"
   attr :errors, :list
-  attr :rest, :global, doc: "the arbitrary HTML attributes for the input tag"
-
+  attr :rest, :global, include: ~w(autocomplete checked disabled form max maxlength min minlength
+                                   multiple pattern placeholder readonly required size step)
   slot :inner_block
   slot :option, doc: "the slot for select input options"
 
@@ -283,7 +286,6 @@ defmodule <%= @web_namespace %>.Components do
       <select
         id={@id}
         name={@name}
-        autocomplete={@name}
         class="mt-1 block w-full py-2 px-3 border border-gray-300 bg-white rounded-md shadow-sm focus:outline-none focus:ring-zinc-500 focus:border-zinc-500 sm:text-sm"
         {@rest}
       >
diff --git a/lib/phoenix/endpoint/cowboy2_handler.ex b/lib/phoenix/endpoint/cowboy2_handler.ex
index cbedb17a8..727f944f2 100644
--- a/lib/phoenix/endpoint/cowboy2_handler.ex
+++ b/lib/phoenix/endpoint/cowboy2_handler.ex
@@ -24,25 +24,16 @@ defmodule Phoenix.Endpoint.Cowboy2Handler do
               cowboy_opts =
                 opts
                 |> Enum.flat_map(fn
-                  {:timeout, timeout} ->
-                    [idle_timeout: timeout]
-
-                  {:compress, _} = opt ->
-                    [opt]
-
-                  {:max_frame_size, _} = opt ->
-                    [opt]
-
-                  {:fullsweep_after, value} ->
-                    :erlang.process_flag(:fullsweep_after, value)
-                    []
-
-                  _other ->
-                    []
+                  {:timeout, timeout} -> [idle_timeout: timeout]
+                  {:compress, _} = opt -> [opt]
+                  {:max_frame_size, _} = opt -> [opt]
+                  _other -> []
                 end)
                 |> Map.new()
 
-              {:cowboy_websocket, copy_resp_headers(conn, req), [handler | state], cowboy_opts}
+              handler_opts = Keyword.take(opts, [:fullsweep_after])
+              triplet = {handler, handler_opts, state}
+              {:cowboy_websocket, copy_resp_headers(conn, req), triplet, cowboy_opts}
 
             {:error, %Plug.Conn{adapter: {@connection, req}} = conn} ->
               {:ok, copy_resp_headers(conn, req), {handler, opts}}
@@ -136,7 +127,11 @@ defmodule Phoenix.Endpoint.Cowboy2Handler do
 
   ## Websocket callbacks
 
-  def websocket_init([handler | state]) do
+  def websocket_init({handler, process_flags, state}) do
+    for {key, value} <- process_flags do
+      :erlang.process_flag(key, value)
+    end
+
     {:ok, state} = handler.init(state)
     {:ok, [handler | state]}
   end
diff --git a/lib/phoenix/verified_routes.ex b/lib/phoenix/verified_routes.ex
index 9af3117ba..65d2138c0 100644
--- a/lib/phoenix/verified_routes.ex
+++ b/lib/phoenix/verified_routes.ex
@@ -188,7 +188,7 @@ defmodule Phoenix.VerifiedRoutes do
       redirect(to: ~p"/users/#{@user}")
 
       ~H"""
-      <.link to={~p"/users??page=#{@page}"}>profile</.link>
+      <.link to={~p"/users?page=#{@page}"}>profile</.link>
 
       <.link to={~p"/users?#{@params}"}>profile</.link>
       """
@@ -642,7 +642,7 @@ defmodule Phoenix.VerifiedRoutes do
   end
 
   @doc false
-  def __encode_query__(dict) when is_list(dict) or is_map(dict) do
+  def __encode_query__(dict) when is_list(dict) or (is_map(dict) and not is_struct(dict)) do
     case Plug.Conn.Query.encode(dict, &to_param/1) do
       "" -> ""
       query_str -> query_str
diff --git a/priv/templates/phx.gen.auth/confirmation_live.ex b/priv/templates/phx.gen.auth/confirmation_live.ex
index 544d9d3df..f9924f2db 100644
--- a/priv/templates/phx.gen.auth/confirmation_live.ex
+++ b/priv/templates/phx.gen.auth/confirmation_live.ex
@@ -32,7 +32,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
       {:ok, _} ->
         {:noreply,
          socket
-         |> put_flash(:info, "User confirmed successfully.")
+         |> put_flash(:info, "<%= inspect schema.alias %> confirmed successfully.")
          |> redirect(to: ~p"/")}
 
       :error ->
@@ -47,7 +47,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
           %{} ->
             {:noreply,
              socket
-             |> put_flash(:error, "User confirmation link is invalid or it has expired.")
+             |> put_flash(:error, "<%= inspect schema.alias %> confirmation link is invalid or it has expired.")
              |> redirect(to: ~p"/")}
         end
     end
diff --git a/priv/templates/phx.gen.auth/login_live.ex b/priv/templates/phx.gen.auth/login_live.ex
index 76c559127..605f7272b 100644
--- a/priv/templates/phx.gen.auth/login_live.ex
+++ b/priv/templates/phx.gen.auth/login_live.ex
@@ -18,9 +18,9 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
       <.simple_form
         :let={f}
         id="login_form"
-        for={:user}
+        for={:<%= schema.singular %>}
         action={~p"<%= schema.route_prefix %>/log_in"}
-        as={:user}
+        as={:<%= schema.singular %>}
         phx-update="ignore"
       >
         <.input field={{f, :email}} type="email" label="Email" required />
diff --git a/priv/templates/phx.gen.auth/registration_live.ex b/priv/templates/phx.gen.auth/registration_live.ex
index b23e4e103..423d00511 100644
--- a/priv/templates/phx.gen.auth/registration_live.ex
+++ b/priv/templates/phx.gen.auth/registration_live.ex
@@ -27,7 +27,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
         phx-trigger-action={@trigger_submit}
         action={~p"<%= schema.route_prefix %>/log_in?_action=registered"}
         method="post"
-        as={:user}
+        as={:<%= schema.singular %>}
       >
         <%%= if @changeset.action == :insert do %>
           <.error message="Oops, something went wrong! Please check the errors below." />
diff --git a/priv/templates/phx.gen.live/components.ex b/priv/templates/phx.gen.live/components.ex
index 897d4fe7f..056b3edd0 100644
--- a/priv/templates/phx.gen.live/components.ex
+++ b/priv/templates/phx.gen.live/components.ex
@@ -24,7 +24,7 @@ defmodule <%= @web_namespace %>.Components do
         Are you sure?
         <:confirm>OK</:confirm>
         <:cancel>Cancel</:cancel>
-      <.modal>
+      </.modal>
 
   JS commands may be passed to the `:on_cancel` and `on_confirm` attributes
   for the caller to reactor to each button press, for example:
@@ -32,8 +32,8 @@ defmodule <%= @web_namespace %>.Components do
       <.modal id="confirm" on_confirm={JS.push("delete")} on_cancel={JS.navigate(~p"/posts")}>
         Are you sure you?
         <:confirm>OK</:confirm>
-        <:cancel>Cancel</:confirm>
-      <.modal>
+        <:cancel>Cancel</:cancel>
+      </.modal>
   """
   attr :id, :string, required: true
   attr :show, :boolean, default: false
@@ -171,7 +171,7 @@ defmodule <%= @web_namespace %>.Components do
         <.input field={{f, :username}} label="Username" />
         <:actions>
           <.button>Save</.button>
-        <:actions>
+        </:actions>
       </.simple_form>
   """
   attr :for, :any, default: nil, doc: "the datastructure for the form"


Test patch:
diff --git a/priv/templates/phx.gen.auth/confirmation_live_test.exs b/priv/templates/phx.gen.auth/confirmation_live_test.exs
index 75b907e14..22abeb500 100644
--- a/priv/templates/phx.gen.auth/confirmation_live_test.exs
+++ b/priv/templates/phx.gen.auth/confirmation_live_test.exs
@@ -33,7 +33,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
 
       assert {:ok, conn} = result
       assert Phoenix.Flash.get(conn.assigns.flash, :info) =~
-        "User confirmed successfully"
+        "<%= inspect schema.alias %> confirmed successfully"
 
       assert <%= inspect context.alias %>.get_<%= schema.singular %>!(<%= schema.singular %>.id).confirmed_at
       refute get_session(conn, :<%= schema.singular %>_token)
@@ -50,7 +50,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
 
       assert {:ok, conn} = result
       assert Phoenix.Flash.get(conn.assigns.flash, :error) =~
-        "User confirmation link is invalid or it has expired"
+        "<%= inspect schema.alias %> confirmation link is invalid or it has expired"
 
 
       # when logged in
@@ -81,7 +81,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
         |> follow_redirect(conn, ~p"/")
 
       assert Phoenix.Flash.get(conn.assigns.flash, :error) =~
-        "User confirmation link is invalid or it has expired"
+        "<%= inspect schema.alias %> confirmation link is invalid or it has expired"
 
       refute <%= inspect context.alias %>.get_<%= schema.singular %>!(<%= schema.singular %>.id).confirmed_at
     end
diff --git a/test/phoenix/verified_routes_test.exs b/test/phoenix/verified_routes_test.exs
index 4d10a41ac..b2d29e060 100644
--- a/test/phoenix/verified_routes_test.exs
+++ b/test/phoenix/verified_routes_test.exs
@@ -125,6 +125,10 @@ defmodule Phoenix.VerifiedRoutesTest do
 
     assert path(@endpoint, @router, ~p"/posts/bottom/#{dir}/#{id}?foo=bar") ==
              "/posts/bottom/asc/123?foo=bar"
+
+    # dynamic query params
+    assert ~p"/posts/1?other_post=#{id}" == "/posts/1?other_post=123"
+    assert ~p"/posts/1?other_post=#{struct}" == "/posts/1?other_post=post-123"
   end
 
   test "~p with dynamic string and static query params" do