nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: phoenixframework/phoenix
Pull request #6184 (2025-04-10 16:55:16)

Do not show ANSI escape codes on exception pages
The code reloader capture the output of mix compile tasks and shows it directly on the exception page. When the output includes ANSI escapes for coloring they are left as is:

<img width="1512" alt="image" src="https://github.com/user-attachments/assets/2e7616e2-2669-437b-8aee-7bbc01a30df0" />

This adds a simple regex pass to remove them.

SteffenDE: I'd love to see them actually rendered in color on the error page. In theory, something like this should work: https://github.com/drudru/ansi_up/blob/main/ansi_up.js

(not sure if we really want to do that though)
jonatanklosko: Not sure if it's vendoring in this amount of JS, but it's up to you! Another complexity is that we would need a different set of colors per each theme.

Given that this hasn't been reported thus far, I suspect the ANSI usage is pretty rare for errors anyway.

cc @josevalim
josevalim: Vendoring JS is not a problem but I am worried about finding colors that work nicely for both. Although the Elixir built-in ANSI colors should look good both on black and white backgrounds.
josevalim: Well, let's merge this, it is definitely a fix, we can swap up by the JS library in another PR if we want to go down that path!

Patch:
diff --git a/lib/phoenix/code_reloader.ex b/lib/phoenix/code_reloader.ex
index 0910f784c..69a335869 100644
--- a/lib/phoenix/code_reloader.ex
+++ b/lib/phoenix/code_reloader.ex
@@ -330,6 +330,11 @@ defmodule Phoenix.CodeReloader do
   defp format_output(output) do
     output
     |> String.trim()
+    |> remove_ansi_escapes()
     |> Plug.HTML.html_escape()
   end
+
+  defp remove_ansi_escapes(text) do
+    Regex.replace(~r/\e\[[0-9;]*[a-zA-Z]/, text, "")
+  end
 end


Test patch:
diff --git a/test/phoenix/code_reloader_test.exs b/test/phoenix/code_reloader_test.exs
index 36f2911e2..38426af4e 100644
--- a/test/phoenix/code_reloader_test.exs
+++ b/test/phoenix/code_reloader_test.exs
@@ -8,7 +8,7 @@ defmodule Phoenix.CodeReloaderTest do
   end
 
   def reload(_, _) do
-    {:error, "oops"}
+    {:error, "oops \e[31merror"}
   end
 
   @tag :capture_log
@@ -59,7 +59,7 @@ defmodule Phoenix.CodeReloaderTest do
 
     assert conn.state == :sent
     assert conn.status == 500
-    assert conn.resp_body =~ "oops"
+    assert conn.resp_body =~ "oops error"
     assert conn.resp_body =~ "CompileError"
     assert conn.resp_body =~ "Compilation error"
   end
Repository: phoenixframework/phoenix
Pull request #6199 (2025-04-16 12:46:19)

phx.gen.auth: Replace `utc_now/0 + truncate/1` with `utc_now/1`
We can do that because new apps require Elixir 1.15+.



Patch:
diff --git a/priv/templates/phx.gen.auth/schema.ex b/priv/templates/phx.gen.auth/schema.ex
index dae8f1cbe..1ee64e0e6 100644
--- a/priv/templates/phx.gen.auth/schema.ex
+++ b/priv/templates/phx.gen.auth/schema.ex
@@ -113,9 +113,9 @@ defmodule <%= inspect schema.module %> do
   """
   def confirm_changeset(<%= schema.singular %>) do
     <%= case schema.timestamp_type do %>
-    <% :naive_datetime -> %>now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
-    <% :utc_datetime -> %>now = DateTime.utc_now() |> DateTime.truncate(:second)
-    <% :utc_datetime_usec -> %>now = DateTime.utc_now() |> DateTime.truncate(:microsecond)
+    <% :naive_datetime -> %>now = NaiveDateTime.utc_now(:second)
+    <% :utc_datetime -> %>now = DateTime.utc_now(:second)
+    <% :utc_datetime_usec -> %>now = DateTime.utc_now(:microsecond)
     <% end %>change(<%= schema.singular %>, confirmed_at: now)
   end
 


Test patch:
diff --git a/test/mix/tasks/phx.gen.auth_test.exs b/test/mix/tasks/phx.gen.auth_test.exs
index 59bb70f98..d228feb81 100644
--- a/test/mix/tasks/phx.gen.auth_test.exs
+++ b/test/mix/tasks/phx.gen.auth_test.exs
@@ -822,7 +822,7 @@ defmodule Mix.Tasks.Phx.Gen.AuthTest do
         assert_file("lib/my_app/accounts/user.ex", fn file ->
           assert file =~ "field :confirmed_at, :utc_datetime"
           assert file =~ "timestamps(type: :utc_datetime)"
-          assert file =~ "now = DateTime.utc_now() |> DateTime.truncate(:second)"
+          assert file =~ "now = DateTime.utc_now(:second)"
         end)
 
         assert_file("lib/my_app/accounts/user_token.ex", fn file ->
Repository: phoenixframework/phoenix_html
Pull request #112 (2016-09-16 15:18:33)

Allow the submit to take a `do` option
This utilizes the `content_tag` option for taking a `do` block. The primary use case we're looking to cover is putting an SVG inside the button such as:

```elixir
<%= submit do %>
  <%= content_tag(:svg) %>
<% end %>
```


Patch:
diff --git a/lib/phoenix_html/form.ex b/lib/phoenix_html/form.ex
index 989b5de..8a0ab68 100644
--- a/lib/phoenix_html/form.ex
+++ b/lib/phoenix_html/form.ex
@@ -226,7 +226,6 @@ defmodule Phoenix.HTML.Form do
       character to force the browser to use UTF-8 as the charset. When set to
       false, this is disabled.
 
-
   See `Phoenix.HTML.Tag.form_tag/2` for more information on the
   options above.
   """
@@ -525,7 +524,16 @@ defmodule Phoenix.HTML.Form do
       #=> <button type="submit">Submit</button>
 
   """
-  def submit(value, opts \\ []) do
+  def submit([do: _] = block_option), do: submit([], block_option)
+
+  def submit(_, opts \\ [])
+  def submit(opts, [do: _] = block_option) do
+    opts = Keyword.put_new(opts, :type, "submit")
+
+    content_tag(:button, opts, block_option)
+  end
+
+  def submit(value, opts) do
     opts = Keyword.put_new(opts, :type, "submit")
 
     content_tag(:button, html_escape(value), opts)


Test patch:
diff --git a/test/phoenix_html/form_test.exs b/test/phoenix_html/form_test.exs
index 5cb8281..bede042 100644
--- a/test/phoenix_html/form_test.exs
+++ b/test/phoenix_html/form_test.exs
@@ -318,6 +318,12 @@ defmodule Phoenix.HTML.FormTest do
 
     assert safe_to_string(submit("Submit", class: "btn")) ==
           ~s(<button class="btn" type="submit">Submit</button>)
+
+    assert safe_to_string(submit([class: "btn"], do: "Submit")) ==
+          ~s(<button class="btn" type="submit">Submit</button>)
+
+    assert safe_to_string(submit(do: "Submit")) ==
+          ~s(<button type="submit">Submit</button>)
   end
 
   ## reset/2
Repository: phoenixframework/phoenix_html
Pull request #161 (2017-06-24 12:39:19)

Fix ArgumentError in Phoenix.HTML.Form.textarea/3
Passing a type other than binary to `Phoenix.HTML.Form.textarea/3` as the `value` option raises an error:

```
** (ArgumentError) lists in Phoenix.HTML and templates may only contain integers representing bytes, binaries or other lists, got invalid entry: ...
```

**Expected behavior:** the function should accept any data structure that implements the `Phoenix.HTML.Safe` protocol.

This seems like an easy fix to me, but I might be missing something important, so any feedback is appreciated :smiley:


Patch:
diff --git a/lib/phoenix_html/form.ex b/lib/phoenix_html/form.ex
index 63316c0..308c779 100644
--- a/lib/phoenix_html/form.ex
+++ b/lib/phoenix_html/form.ex
@@ -557,7 +557,7 @@ defmodule Phoenix.HTML.Form do
       |> Keyword.put_new(:name, input_name(form, field))
 
     {value, opts} = Keyword.pop(opts, :value, input_value(form, field) || "")
-    content_tag(:textarea, html_escape(["\n", value]), opts)
+    content_tag(:textarea, ["\n", html_escape(value)], opts)
   end
 
   @doc """


Test patch:
diff --git a/test/phoenix_html/form_test.exs b/test/phoenix_html/form_test.exs
index f6d03c2..8423006 100644
--- a/test/phoenix_html/form_test.exs
+++ b/test/phoenix_html/form_test.exs
@@ -129,6 +129,11 @@ defmodule Phoenix.HTML.FormTest do
            ~s(<textarea id="key" name="search[key][]">\nfoo</textarea>)
   end
 
+  test "textarea/3 with non-binary type" do
+    assert safe_form(&textarea(&1, :key, value: :atom_value)) ==
+           ~s(<textarea id="search_key" name="search[key]">\natom_value</textarea>)
+  end
+
   ## number_input/3
 
   test "number_input/3" do
Repository: phoenixframework/phoenix_html
Pull request #245 (2019-01-05 09:30:43)

escape backticks in javascript_escape/1
At the time of the implementation of the javascript_escape function backticks weren't an issue as the string interpolation syntax was not broadly supported in javascript. This is now widely used and thus will introduce a vulnerability of XSS attacks.


Patch:
diff --git a/lib/phoenix_html.ex b/lib/phoenix_html.ex
index 7d494e5..55e0ea3 100644
--- a/lib/phoenix_html.ex
+++ b/lib/phoenix_html.ex
@@ -193,7 +193,7 @@ defmodule Phoenix.HTML do
   defp javascript_escape(<<"\r\n", t::binary>>, acc),
     do: javascript_escape(t, <<acc::binary, ?\\, ?n>>)
 
-  defp javascript_escape(<<h, t::binary>>, acc) when h in [?", ?', ?\\],
+  defp javascript_escape(<<h, t::binary>>, acc) when h in [?", ?', ?\\, ?`],
     do: javascript_escape(t, <<acc::binary, ?\\, h>>)
 
   defp javascript_escape(<<h, t::binary>>, acc) when h in [?\r, ?\n],


Test patch:
diff --git a/test/phoenix_html_test.exs b/test/phoenix_html_test.exs
index e336b5e..3fe9ce6 100644
--- a/test/phoenix_html_test.exs
+++ b/test/phoenix_html_test.exs
@@ -15,6 +15,7 @@ defmodule Phoenix.HTMLTest do
     assert javascript_escape("\\Double backslash") == "\\\\Double backslash"
     assert javascript_escape("\"Double quote\"") == "\\\"Double quote\\\""
     assert javascript_escape("'Single quote'") == "\\'Single quote\\'"
+    assert javascript_escape("`Backtick`") == "\\`Backtick\\`"
     assert javascript_escape("New line\r") == "New line\\n"
     assert javascript_escape("New line\n") == "New line\\n"
     assert javascript_escape("New line\r\n") == "New line\\n"
Repository: phoenixframework/phoenix_html
Pull request #261 (2019-06-06 03:03:32)

updated datetime_local_input to format default form value if if no value is explicitly set
Fix an issue with datetime_local_input, the date_time does not get formatted if the value is not explicitly set.


Patch:
diff --git a/lib/phoenix_html/form.ex b/lib/phoenix_html/form.ex
index ecf49b9..d4d925a 100644
--- a/lib/phoenix_html/form.ex
+++ b/lib/phoenix_html/form.ex
@@ -698,14 +698,8 @@ defmodule Phoenix.HTML.Form do
   See `text_input/3` for example and docs.
   """
   def datetime_local_input(form, field, opts \\ []) do
-    opts =
-      case Keyword.fetch(opts, :value) do
-        {:ok, value} ->
-          Keyword.put(opts, :value, datetime_local_input_value(value))
-
-        :error ->
-          opts
-      end
+    value = Keyword.get(opts, :value, input_value(form, field))
+    opts = Keyword.put(opts, :value, datetime_local_input_value(value))
 
     generic_input(:"datetime-local", form, field, opts)
   end


Test patch:
diff --git a/test/phoenix_html/form_test.exs b/test/phoenix_html/form_test.exs
index e381102..d43cdf2 100644
--- a/test/phoenix_html/form_test.exs
+++ b/test/phoenix_html/form_test.exs
@@ -39,7 +39,8 @@ defmodule Phoenix.HTML.FormTest do
         "hour" => "2",
         "minute" => "11",
         "second" => "13"
-      }
+      },
+      "naive_datetime" => ~N[2000-01-01 10:00:42]
     }
   end
 
@@ -549,6 +550,9 @@ defmodule Phoenix.HTML.FormTest do
     assert safe_to_string(datetime_local_input(:search, :key)) ==
              ~s(<input id="search_key" name="search[key]" type="datetime-local">)
 
+    assert safe_form(&datetime_local_input(&1, :naive_datetime)) ==
+             ~s(<input id="search_naive_datetime" name="search[naive_datetime]" type="datetime-local" value="2000-01-01T10:00">)
+              
     assert safe_to_string(
              datetime_local_input(:search, :key, value: "foo", id: "key", name: "search[key][]")
            ) == ~s(<input id="key" name="search[key][]" type="datetime-local" value="foo">)
Repository: phoenixframework/phoenix_html
Pull request #265 (2019-07-26 13:09:54)

Add :srcset option to img_tag helper
For responsive `<img>`s, alternate files can be supplied by the `srcset` attribute.

```html
<img src="/logo.png" srcset="/logo.png 1x, /logo-2x.png 2x">
```

This pull request supports stringifying `srcset` values from a map or list.

```elixir
img_tag("/logo.png", srcset: %{"/logo.png" => "1x", "/logo-2x.png" => "2x"})
img_tag("/logo.png", srcset: [{"/logo.png", "1x"}, {"/logo-2x.png", "2x"}])
```

Support for stringifying `sizes` was considered because the algorithm is identical, but `sizes` is likely hard-coded whereas `srcset` is generated from multiple `Routes.static_path`s.

```html
<img src="/logo.png"
  srcset="/logo-100.png 100w, /logo-200.png 200w"
   sizes="(min-width: 100px) 50vw, 100vw">
```

So simply passing `sizes: "(min-width: 100px) 50vw, 100vw"` here would work.


Patch:
diff --git a/lib/phoenix_html/tag.ex b/lib/phoenix_html/tag.ex
index 8bc5680..90e3a3e 100644
--- a/lib/phoenix_html/tag.ex
+++ b/lib/phoenix_html/tag.ex
@@ -311,8 +311,32 @@ defmodule Phoenix.HTML.Tag do
       img_tag(Routes.static_path(@conn, "/logo.png"))
       <img src="/logo-123456.png?vsn=d">
 
+  For responsive images, pass a map, list or string through `:srcset`.
+
+      img_tag("/logo.png", srcset: %{"/logo.png" => "1x", "/logo-2x.png" => "2x"})
+      <img src="/logo.png" srcset="/logo.png 1x, /logo-2x.png 2x">
+
+      img_tag("/logo.png", srcset: ["/logo.png", {"/logo-2x.png", "2x"}])
+      <img src="/logo.png" srcset="/logo.png, /logo-2x.png 2x">
+
   """
   def img_tag(src, opts \\ []) do
+    opts =
+      case Keyword.pop(opts, :srcset) do
+        {nil, opts} -> opts
+        {srcset, opts} -> [srcset: stringify_srcset(srcset)] ++ opts
+      end
+
     tag(:img, Keyword.put_new(opts, :src, src))
   end
+
+  defp stringify_srcset(srcset) when is_map(srcset) or is_list(srcset) do
+    Enum.map_join(srcset, ", ", fn
+      {src, descriptor} -> "#{src} #{descriptor}"
+      default -> default
+    end)
+  end
+
+  defp stringify_srcset(srcset) when is_binary(srcset),
+    do: srcset
 end


Test patch:
diff --git a/test/phoenix_html/tag_test.exs b/test/phoenix_html/tag_test.exs
index f7c9ff2..b90ecb6 100644
--- a/test/phoenix_html/tag_test.exs
+++ b/test/phoenix_html/tag_test.exs
@@ -92,6 +92,16 @@ defmodule Phoenix.HTML.TagTest do
 
     assert img_tag("user.png", class: "big") |> safe_to_string() ==
              ~s(<img class="big" src="user.png">)
+
+    assert img_tag("user.png", srcset: %{"big.png" => "2x", "small.png" => "1x"})
+           |> safe_to_string() ==
+             ~s(<img src="user.png" srcset="big.png 2x, small.png 1x">)
+
+    assert img_tag("user.png", srcset: [{"big.png", "2x"}, "small.png"]) |> safe_to_string() ==
+             ~s(<img src="user.png" srcset="big.png 2x, small.png">)
+
+    assert img_tag("user.png", srcset: "big.png 2x, small.png") |> safe_to_string() ==
+             ~s[<img src="user.png" srcset="big.png 2x, small.png">]
   end
 
   test "form_tag for get" do
Repository: phoenixframework/phoenix_html
Pull request #290 (2020-02-11 06:26:36)

Disable hidden input for disabled checkboxes
When a checkbox is disabled, it doesn't send its value when the form is submitted - but the still-active hidden input DOES. The result is that a disabled checkbox will always submit as its unchecked value (`"false"` by default).

See also https://github.com/rails/rails/issues/1953 where a similar helper function had the same bug with the same fix.

Not 100% certain about the formatting on the change in `form.ex`; that's what running `mix format` gave me but there's a bunch of other files that that wants to change as well...


Patch:
diff --git a/lib/phoenix_html/form.ex b/lib/phoenix_html/form.ex
index 87eaf7f..7568aad 100644
--- a/lib/phoenix_html/form.ex
+++ b/lib/phoenix_html/form.ex
@@ -1014,7 +1014,12 @@ defmodule Phoenix.HTML.Form do
 
     if hidden_input do
       html_escape([
-        tag(:input, name: Keyword.get(opts, :name), type: "hidden", value: unchecked_value),
+        tag(:input,
+          name: Keyword.get(opts, :name),
+          type: "hidden",
+          value: unchecked_value,
+          disabled: Keyword.get(opts, :disabled, false)
+        ),
         tag(:input, [value: checked_value] ++ opts)
       ])
     else


Test patch:
diff --git a/test/phoenix_html/form_test.exs b/test/phoenix_html/form_test.exs
index 33d3a55..e8288eb 100644
--- a/test/phoenix_html/form_test.exs
+++ b/test/phoenix_html/form_test.exs
@@ -748,6 +748,10 @@ defmodule Phoenix.HTML.FormTest do
              ~s(<input name="search[key]" type="hidden" value="false">) <>
                ~s(<input id="search_key" name="search[key]" type="checkbox" value="true" checked>)
 
+    assert safe_to_string(checkbox(:search, :key, checked: true, disabled: true)) ==
+             ~s(<input name="search[key]" type="hidden" value="false" disabled>) <>
+               ~s(<input id="search_key" name="search[key]" type="checkbox" value="true" checked disabled>)
+
     assert safe_to_string(checkbox(:search, :key, value: "true", checked: false)) ==
              ~s(<input name="search[key]" type="hidden" value="false">) <>
                ~s(<input id="search_key" name="search[key]" type="checkbox" value="true">)
Repository: phoenixframework/phoenix_html
Pull request #306 (2020-06-25 14:33:26)

Prefix form id when it is present in form_for/3
This commit will prefix the form id in its inputs id as form_for/4 does.

It avoid issues when having multiple forms on the same page, you can see more info about it here:

https://github.com/phoenixframework/phoenix_live_view/issues/1014

feliperenan: We also need to apply this patch in `phoenix_ecto`.

https://github.com/phoenixframework/phoenix_ecto/blob/master/lib/phoenix_ecto/html.ex#L11

Patch:
diff --git a/lib/phoenix_html/form_data.ex b/lib/phoenix_html/form_data.ex
index c3f54d9..f538e45 100644
--- a/lib/phoenix_html/form_data.ex
+++ b/lib/phoenix_html/form_data.ex
@@ -52,11 +52,12 @@ defimpl Phoenix.HTML.FormData, for: [Plug.Conn, Atom] do
   def to_form(conn_or_atom, opts) do
     {name, params, opts} = name_params_and_opts(conn_or_atom, opts)
     {errors, opts} = Keyword.pop(opts, :errors, [])
+    {id, opts} = Keyword.pop(opts, :id)
 
     %Phoenix.HTML.Form{
       source: conn_or_atom,
       impl: __MODULE__,
-      id: name,
+      id: id || name,
       name: name,
       params: params,
       data: %{},


Test patch:
diff --git a/test/phoenix_html/form_test.exs b/test/phoenix_html/form_test.exs
index 827fab7..221cafc 100644
--- a/test/phoenix_html/form_test.exs
+++ b/test/phoenix_html/form_test.exs
@@ -67,7 +67,7 @@ defmodule Phoenix.HTML.FormTest do
     end
   end
 
-  describe "form_for/3 with atomm" do
+  describe "form_for/3 with atom" do
     test "without options" do
       form = form_for(:search, "/", [])
       assert %Phoenix.HTML.Form{} = form
@@ -89,6 +89,32 @@ defmodule Phoenix.HTML.FormTest do
       assert contents =~ ~s(<input name="_method" type="hidden" value="put">)
       refute contents =~ ~s(</form>)
     end
+
+    test "with id prefix the form id in the input id" do
+      form = form_for(:search, "/", id: "form_id")
+      assert %Phoenix.HTML.Form{} = form
+
+      contents =
+        form
+        |> text_input(:name)
+        |> html_escape()
+        |> safe_to_string()
+
+      assert contents =~ ~s(<input id="form_id_name" name="search[name]" type="text">)
+    end
+
+    test "without id prefix the form name in the input id" do
+      form = form_for(:search, "/")
+      assert %Phoenix.HTML.Form{} = form
+
+      contents =
+        form
+        |> text_input(:name)
+        |> html_escape()
+        |> safe_to_string()
+
+      assert contents =~ ~s(<input id="search_name" name="search[name]" type="text">)
+    end
   end
 
   describe "form_for/4 with connection" do
@@ -261,6 +287,18 @@ defmodule Phoenix.HTML.FormTest do
 
       assert form =~ ~s(<span class="errors">Field error message!</span>)
     end
+
+    test "with id prefix the form id in the input id" do
+      form =
+        safe_to_string(
+          form_for(:search, "/", [params: search_params(), id: "form_id"], fn f ->
+            text_input(f, :key)
+          end)
+        )
+
+      assert form =~
+               ~s(<input id="form_id_key" name="search[key]" type="text" value="value">)
+    end
   end
 
   describe "inputs_for/3" do
Repository: phoenixframework/phoenix_html
Pull request #307 (2020-06-26 12:39:13)

Ensure form still have id when present
The last commit takes the ID from the opts so the form will never render the ID anymore. This commit fix that and ensure id will be preset with tests.



Patch:
diff --git a/lib/phoenix_html/form_data.ex b/lib/phoenix_html/form_data.ex
index f538e45..6fbeeda 100644
--- a/lib/phoenix_html/form_data.ex
+++ b/lib/phoenix_html/form_data.ex
@@ -52,12 +52,12 @@ defimpl Phoenix.HTML.FormData, for: [Plug.Conn, Atom] do
   def to_form(conn_or_atom, opts) do
     {name, params, opts} = name_params_and_opts(conn_or_atom, opts)
     {errors, opts} = Keyword.pop(opts, :errors, [])
-    {id, opts} = Keyword.pop(opts, :id)
+    id = Keyword.get(opts, :id) || name
 
     %Phoenix.HTML.Form{
       source: conn_or_atom,
       impl: __MODULE__,
-      id: id || name,
+      id: id,
       name: name,
       params: params,
       data: %{},


Test patch:
diff --git a/test/phoenix_html/form_test.exs b/test/phoenix_html/form_test.exs
index 221cafc..4e26ca3 100644
--- a/test/phoenix_html/form_test.exs
+++ b/test/phoenix_html/form_test.exs
@@ -94,25 +94,37 @@ defmodule Phoenix.HTML.FormTest do
       form = form_for(:search, "/", id: "form_id")
       assert %Phoenix.HTML.Form{} = form
 
-      contents =
+      form_content =
+        form
+        |> html_escape()
+        |> safe_to_string()
+
+      input_content =
         form
         |> text_input(:name)
         |> html_escape()
         |> safe_to_string()
 
-      assert contents =~ ~s(<input id="form_id_name" name="search[name]" type="text">)
+      assert form_content  =~ ~s(<form action="/" id="form_id" method="post">)
+      assert input_content =~ ~s(<input id="form_id_name" name="search[name]" type="text">)
     end
 
     test "without id prefix the form name in the input id" do
       form = form_for(:search, "/")
       assert %Phoenix.HTML.Form{} = form
 
+      form_content =
+        form
+        |> html_escape()
+        |> safe_to_string()
+
       contents =
         form
         |> text_input(:name)
         |> html_escape()
         |> safe_to_string()
 
+      assert form_content  =~ ~s(<form action="/" method="post">)
       assert contents =~ ~s(<input id="search_name" name="search[name]" type="text">)
     end
   end