Driving and reading the editor from a LiveView test.
The editor's container carries phx-update="ignore" — ProseMirror owns
that subtree — so it is invisible to render_change/2: there is no input
to fill and no text to assert on. What the server sees is the hidden
input the hook writes the document into, and a test has to write it
itself.
Doing that by hand is three lines of JSON encoding and parameter nesting at every call site, and getting the nesting wrong fails as "the form ignored the change" rather than as a mistake. This is those three lines.
import Coelho.LiveViewTest
test "the intro is saved", %{conn: conn} do
{:ok, view, _html} = live(conn, ~p"/portal/edit")
type(view, "page[intro_doc]", paragraph("bonjour"))
assert document(view, "page[intro_doc]") == paragraph("bonjour")
endNothing here needs the browser: it writes what the hook would have written, and reads what the server rendered back.
Summary
Functions
The document an editor is currently holding, decoded.
The parameters a change carrying this document would arrive with.
Posts a document as the editor would, and returns the rendered result.
Types
Functions
The document an editor is currently holding, decoded.
Read off the hidden input the server rendered, which is where the
editor's state is visible from Elixir. Returns nil when there is no
such input, and the raw string when it does not hold a document — which
is what a rejected document comes back as, so that the writer can fix it
rather than lose it.
The parameters a change carrying this document would arrive with.
type/4 sends these; this is for a test that has its own way of sending —
a render_submit, a render_hook, a controller post. The nesting is
the browser's: page[intro_doc] becomes
%{"page" => %{"intro_doc" => json}}, which is what Plug.Conn.Query
reads back and what a form expects to see.
params("page[intro_doc]", document, %{"page" => %{"title" => "Été"}})
#=> %{"page" => %{"intro_doc" => "{…}", "title" => "Été"}}
Posts a document as the editor would, and returns the rendered result.
name is the hidden input's name — "page[intro_doc]" — or the
%Phoenix.HTML.FormField{} it was rendered from. The document is encoded
and nested into parameters the same way a browser would nest them.
Options
:event— thephx-changeevent to send,"validate"by default:params— the form's other fields, merged into the parameters as a browser would send them, which means nested the way the form nests them:params: %{"post" => %{"title" => "t"}}, not%{"title" => "t"}. A changeset wanting a title reports the title when a change arrives without one, so this is how the document under test stays the thing under test — and a title merged at the top level never reacheshandle_event("validate", %{"post" => params}, …)at all
There used to be a :form option here, sending the change through
Phoenix.LiveViewTest.form/3 instead. It cannot work for this field and
never could: form/3 refuses a hidden input whose value differs from
the one that was rendered, and an editor's field is hidden and differs by
definition — that is what typing is. It raised
value for hidden "post[body]" must be one of […] at every call. Pass
the other fields through :params.