2021-07-16 06:09:15 +12:00
|
|
|
defmodule AshPhoenix.FormTest do
|
|
|
|
use ExUnit.Case
|
|
|
|
import Phoenix.HTML.Form, only: [form_for: 2, inputs_for: 2]
|
2022-07-08 14:22:30 +12:00
|
|
|
import ExUnit.CaptureLog
|
2021-07-16 06:09:15 +12:00
|
|
|
|
|
|
|
alias AshPhoenix.Form
|
2021-11-11 09:11:22 +13:00
|
|
|
alias AshPhoenix.Test.{Api, Comment, OtherApi, Post, PostWithDefault}
|
2021-07-16 06:09:15 +12:00
|
|
|
alias Phoenix.HTML.FormData
|
|
|
|
|
2022-05-21 02:59:23 +12:00
|
|
|
describe "validate_opts" do
|
2022-05-22 18:08:43 +12:00
|
|
|
test "errors are not set on the parent and list child form" do
|
2022-05-21 02:59:23 +12:00
|
|
|
form =
|
|
|
|
Post
|
|
|
|
|> Form.for_create(:create,
|
|
|
|
api: Api,
|
|
|
|
forms: [
|
|
|
|
comments: [
|
|
|
|
type: :list,
|
|
|
|
resource: Comment,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.add_form([:comments], validate_opts: [errors: false])
|
|
|
|
|> form_for("action")
|
|
|
|
|
|
|
|
assert form.errors == []
|
|
|
|
assert Form.errors(form.source, for_path: [:comments, 0]) == []
|
|
|
|
end
|
2022-05-22 18:08:43 +12:00
|
|
|
|
2022-07-08 14:22:30 +12:00
|
|
|
test "unknown errors produce warnings" do
|
|
|
|
form =
|
|
|
|
Post
|
|
|
|
|> Form.for_create(:create,
|
|
|
|
api: Api,
|
|
|
|
params: %{"text" => "bar"},
|
|
|
|
forms: [
|
|
|
|
comments: [
|
|
|
|
type: :list,
|
|
|
|
resource: Comment,
|
|
|
|
create_action: :create_with_unknown_error
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.add_form([:comments], params: %{"text" => "foo"}, validate_opts: [errors: true])
|
|
|
|
|> form_for("action")
|
|
|
|
|
|
|
|
assert capture_log(fn ->
|
|
|
|
Form.errors(form.source, for_path: [:comments, 0]) == []
|
|
|
|
end) =~
|
|
|
|
"Unhandled error in form submission for AshPhoenix.Test.Comment.create_with_unknown_error"
|
|
|
|
end
|
|
|
|
|
2022-08-17 14:16:47 +12:00
|
|
|
test "update_form marks touched by default" do
|
|
|
|
form =
|
|
|
|
Post
|
|
|
|
|> Form.for_create(:create,
|
|
|
|
api: Api,
|
|
|
|
params: %{"text" => "bar"},
|
|
|
|
forms: [
|
|
|
|
comments: [
|
|
|
|
type: :list,
|
|
|
|
resource: Comment,
|
|
|
|
create_action: :create_with_unknown_error
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.add_form([:comments], params: %{"text" => "foo"})
|
|
|
|
|> Form.update_form([:comments, 0], & &1)
|
|
|
|
|
|
|
|
assert MapSet.member?(form.touched_forms, "comments")
|
|
|
|
end
|
|
|
|
|
2022-05-22 18:08:43 +12:00
|
|
|
test "errors are not set on the parent and single child form" do
|
|
|
|
form =
|
|
|
|
Comment
|
|
|
|
|> Form.for_create(:create,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
type: :single,
|
|
|
|
resource: Post,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.add_form([:post], validate_opts: [errors: false])
|
|
|
|
|> form_for("action")
|
|
|
|
|
|
|
|
assert form.errors == []
|
|
|
|
assert Form.errors(form.source, for_path: [:post]) == []
|
|
|
|
end
|
2022-05-21 02:59:23 +12:00
|
|
|
end
|
|
|
|
|
2022-12-21 16:18:55 +13:00
|
|
|
describe "clear_value/1" do
|
|
|
|
test "it clears attributes" do
|
|
|
|
form =
|
|
|
|
Post
|
|
|
|
|> Form.for_create(:create)
|
|
|
|
|> Form.validate(%{"text" => "text"})
|
|
|
|
|
|
|
|
assert Form.value(form, :text) == "text"
|
2023-01-06 06:39:42 +13:00
|
|
|
assert form.source.attributes == %{text: "text"}
|
|
|
|
assert form.source.params == %{"text" => "text"}
|
|
|
|
assert form.params == %{"text" => "text"}
|
2022-12-21 16:18:55 +13:00
|
|
|
|
|
|
|
form = Form.clear_value(form, :text)
|
2023-01-06 06:39:42 +13:00
|
|
|
|
2022-12-21 16:18:55 +13:00
|
|
|
assert Form.value(form, :text) == nil
|
2023-01-06 06:39:42 +13:00
|
|
|
assert form.source.attributes == %{}
|
|
|
|
assert form.source.params == %{}
|
|
|
|
assert form.params == %{}
|
|
|
|
end
|
|
|
|
|
|
|
|
test "it clears arguments" do
|
|
|
|
form =
|
|
|
|
Post
|
|
|
|
|> Form.for_create(:create)
|
|
|
|
|> Form.validate(%{"excerpt" => "text"})
|
|
|
|
|
|
|
|
assert Form.value(form, :excerpt) == "text"
|
|
|
|
assert form.source.arguments == %{excerpt: "text"}
|
|
|
|
assert form.source.params == %{"excerpt" => "text"}
|
|
|
|
assert form.params == %{"excerpt" => "text"}
|
|
|
|
|
|
|
|
form = Form.clear_value(form, :excerpt)
|
|
|
|
|
|
|
|
assert Form.value(form, :excerpt) == nil
|
|
|
|
assert form.source.arguments == %{}
|
|
|
|
assert form.source.params == %{}
|
|
|
|
assert form.params == %{}
|
2022-12-21 16:18:55 +13:00
|
|
|
end
|
2023-01-06 07:51:03 +13:00
|
|
|
|
|
|
|
test "it clears multiple fields" do
|
|
|
|
form =
|
|
|
|
Post
|
|
|
|
|> Form.for_create(:create)
|
|
|
|
|> Form.validate(%{"excerpt" => "text", "text" => "text"})
|
|
|
|
|
|
|
|
assert Form.value(form, :excerpt) == "text"
|
|
|
|
assert Form.value(form, :text) == "text"
|
|
|
|
|
|
|
|
assert form.source.attributes == %{text: "text"}
|
|
|
|
assert form.source.arguments == %{excerpt: "text"}
|
|
|
|
assert form.source.params == %{"excerpt" => "text", "text" => "text"}
|
|
|
|
assert form.params == %{"excerpt" => "text", "text" => "text"}
|
|
|
|
|
|
|
|
form = Form.clear_value(form, [:excerpt, :text])
|
|
|
|
|
|
|
|
assert Form.value(form, :text) == nil
|
|
|
|
assert Form.value(form, :excerpt) == nil
|
|
|
|
|
|
|
|
assert form.params == %{}
|
|
|
|
assert form.source.arguments == %{}
|
|
|
|
assert form.source.attributes == %{}
|
|
|
|
assert form.source.params == %{}
|
|
|
|
end
|
2022-12-21 16:18:55 +13:00
|
|
|
end
|
|
|
|
|
2021-07-16 06:09:15 +12:00
|
|
|
describe "form_for fields" do
|
|
|
|
test "it should show simple field values" do
|
|
|
|
form =
|
|
|
|
Post
|
|
|
|
|> Form.for_create(:create)
|
|
|
|
|> Form.validate(%{"text" => "text"})
|
|
|
|
|> form_for("action")
|
|
|
|
|
|
|
|
assert FormData.input_value(form.source, form, :text) == "text"
|
|
|
|
end
|
2021-07-19 04:28:47 +12:00
|
|
|
|
|
|
|
test "it sets the default id of a form" do
|
|
|
|
assert Form.for_create(Post, :create).id == "form"
|
|
|
|
assert Form.for_create(Post, :create, as: "post").id == "post"
|
|
|
|
end
|
2021-07-16 06:09:15 +12:00
|
|
|
end
|
|
|
|
|
2022-05-10 07:45:57 +12:00
|
|
|
test "a read will validate attributes" do
|
|
|
|
form =
|
|
|
|
Post
|
|
|
|
|> Form.for_read(:read)
|
|
|
|
|> Form.validate(%{"text" => [1, 2, 3]})
|
|
|
|
|> form_for("action")
|
|
|
|
|
|
|
|
assert form.errors[:text] == {"is invalid", []}
|
|
|
|
end
|
|
|
|
|
2021-11-13 16:10:33 +13:00
|
|
|
test "validation errors are attached to fields" do
|
2021-11-11 09:11:22 +13:00
|
|
|
form = Form.for_create(PostWithDefault, :create, api: Api)
|
2021-11-13 15:22:55 +13:00
|
|
|
form = AshPhoenix.Form.validate(form, %{"text" => ""}, errors: form.submitted_once?)
|
|
|
|
{:error, form} = Form.submit(form, params: %{"text" => ""})
|
2021-11-11 09:11:22 +13:00
|
|
|
assert %{errors: [text: {"is required", []}]} = form_for(form, "foo")
|
|
|
|
assert form.valid? == false
|
|
|
|
end
|
|
|
|
|
2023-02-21 12:32:04 +13:00
|
|
|
test "blank form values unset - helps support dead view forms" do
|
|
|
|
form =
|
2023-07-19 16:35:29 +12:00
|
|
|
Form.for_create(PostWithDefault, :create,
|
|
|
|
api: Api,
|
|
|
|
exclude_fields_if_empty: [:text, :title]
|
|
|
|
)
|
2023-02-21 12:32:04 +13:00
|
|
|
|
|
|
|
{:ok, post} = Form.submit(form, params: %{"title" => "", "text" => "bar"})
|
|
|
|
assert post.text == "bar"
|
|
|
|
assert post.title == nil
|
|
|
|
end
|
|
|
|
|
|
|
|
test "blank nested form values unset - helps support dead view forms" do
|
|
|
|
form =
|
|
|
|
Comment
|
|
|
|
|> Form.for_create(:create,
|
|
|
|
api: Api,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
resource: PostWithDefault,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
],
|
|
|
|
exclude_fields_if_empty: [post: [:title, :description]]
|
|
|
|
)
|
|
|
|
|> Form.add_form(:post)
|
|
|
|
|
|
|
|
{:ok, comment} =
|
|
|
|
Form.submit(form,
|
|
|
|
params: %{"text" => "comment", "post" => %{"title" => "", "text" => "bar"}}
|
|
|
|
)
|
|
|
|
|
|
|
|
post = comment.post
|
|
|
|
assert post.text == "bar"
|
|
|
|
assert post.title == nil
|
|
|
|
end
|
|
|
|
|
2022-10-10 16:22:13 +13:00
|
|
|
test "phoenix forms are accepted as input in some cases" do
|
|
|
|
form = Form.for_create(PostWithDefault, :create, api: Api)
|
|
|
|
form = AshPhoenix.Form.validate(form, %{"text" => ""}, errors: form.submitted_once?)
|
|
|
|
form = form_for(form, "foo")
|
|
|
|
# This simply shouldn't raise
|
|
|
|
AshPhoenix.Form.params(form)
|
|
|
|
end
|
|
|
|
|
2023-03-06 11:23:43 +13:00
|
|
|
test "a phoenix form is returned in cases where a phoenix form is passed in" do
|
2022-10-10 16:22:13 +13:00
|
|
|
form = Form.for_create(PostWithDefault, :create, api: Api)
|
|
|
|
form = AshPhoenix.Form.validate(form, %{"text" => ""}, errors: form.submitted_once?)
|
|
|
|
form = form_for(form, "foo")
|
|
|
|
|
2023-03-06 11:23:43 +13:00
|
|
|
assert %Phoenix.HTML.Form{} = AshPhoenix.Form.validate(form, %{})
|
2022-10-10 16:22:13 +13:00
|
|
|
end
|
|
|
|
|
2022-09-21 17:24:52 +12:00
|
|
|
test "it supports forms with data and a `type: :append_and_remove`" do
|
2022-03-22 15:24:19 +13:00
|
|
|
post =
|
|
|
|
Post
|
|
|
|
|> Ash.Changeset.new(%{text: "post"})
|
|
|
|
|> Api.create!()
|
|
|
|
|
|
|
|
comment =
|
|
|
|
Comment
|
|
|
|
|> Ash.Changeset.new(%{text: "comment"})
|
2022-09-21 17:24:52 +12:00
|
|
|
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|
2022-03-22 15:24:19 +13:00
|
|
|
|> Api.create!()
|
|
|
|
|
|
|
|
form =
|
|
|
|
post
|
|
|
|
|> Form.for_update(:update_with_replace,
|
|
|
|
api: Api,
|
|
|
|
forms: [
|
|
|
|
comments: [
|
|
|
|
read_resource: Comment,
|
|
|
|
type: :list,
|
|
|
|
read_action: :read,
|
|
|
|
data: [comment]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
2022-03-22 15:34:50 +13:00
|
|
|
assert [comment_form] = inputs_for(form_for(form, "blah"), :comments)
|
2022-03-22 15:24:19 +13:00
|
|
|
|
|
|
|
assert Phoenix.HTML.Form.input_value(comment_form, :text) == "comment"
|
2022-03-22 15:42:34 +13:00
|
|
|
|
|
|
|
form = Form.validate(form, %{"comments" => [%{"id" => comment.id}]})
|
|
|
|
|
2022-10-07 15:33:36 +13:00
|
|
|
comment_id = comment.id
|
|
|
|
|
|
|
|
assert %{"comments" => [%{"id" => ^comment_id}]} = Form.params(form)
|
2022-03-22 15:24:19 +13:00
|
|
|
end
|
|
|
|
|
2022-06-29 14:22:38 +12:00
|
|
|
test "ignoring a form filters it from the parameters" do
|
|
|
|
post =
|
|
|
|
Post
|
|
|
|
|> Ash.Changeset.new(%{text: "post"})
|
|
|
|
|> Api.create!()
|
|
|
|
|
|
|
|
comment =
|
|
|
|
Comment
|
|
|
|
|> Ash.Changeset.new(%{text: "comment"})
|
2022-09-21 17:24:52 +12:00
|
|
|
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|
2022-06-29 14:22:38 +12:00
|
|
|
|> Api.create!()
|
|
|
|
|
|
|
|
form =
|
|
|
|
post
|
|
|
|
|> Form.for_update(:update_with_replace,
|
|
|
|
api: Api,
|
|
|
|
forms: [
|
|
|
|
comments: [
|
|
|
|
read_resource: Comment,
|
|
|
|
type: :list,
|
|
|
|
read_action: :read,
|
|
|
|
data: [comment]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [comment_form] = inputs_for(form_for(form, "blah"), :comments)
|
|
|
|
|
|
|
|
assert Phoenix.HTML.Form.input_value(comment_form, :text) == "comment"
|
|
|
|
|
|
|
|
form = Form.validate(form, %{"comments" => [%{"id" => comment.id, "_ignore" => "true"}]})
|
|
|
|
|
2022-10-07 15:33:36 +13:00
|
|
|
assert %{"comments" => []} = Form.params(form)
|
2022-06-29 14:22:38 +12:00
|
|
|
|
|
|
|
form = Form.validate(form, %{"comments" => [%{"id" => comment.id, "_ignore" => "false"}]})
|
|
|
|
|
2022-10-07 15:33:36 +13:00
|
|
|
comment_id = comment.id
|
|
|
|
assert %{"comments" => [%{"id" => ^comment_id, "_ignore" => "false"}]} = Form.params(form)
|
2022-06-29 14:28:44 +12:00
|
|
|
|
|
|
|
form = Form.validate(form, %{"comments" => [%{"id" => comment.id, "_ignore" => "true"}]})
|
|
|
|
|
2022-10-07 15:33:36 +13:00
|
|
|
assert %{"comments" => []} = Form.params(form)
|
2022-06-29 14:22:38 +12:00
|
|
|
end
|
|
|
|
|
2021-11-07 05:15:50 +13:00
|
|
|
describe "the .changed? field is updated as data changes" do
|
2021-11-07 07:12:53 +13:00
|
|
|
test "it is false for a create form with no changes" do
|
2021-11-07 05:15:50 +13:00
|
|
|
form =
|
|
|
|
Post
|
|
|
|
|> Form.for_create(:create)
|
|
|
|
|> Form.validate(%{})
|
|
|
|
|
2021-11-07 07:12:53 +13:00
|
|
|
refute form.changed?
|
2021-11-07 05:15:50 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
test "it is false by default for update forms" do
|
|
|
|
post =
|
|
|
|
Post
|
|
|
|
|> Ash.Changeset.new(%{text: "post"})
|
|
|
|
|> Api.create!()
|
|
|
|
|
|
|
|
form =
|
|
|
|
post
|
|
|
|
|> Form.for_update(:update)
|
|
|
|
|> Form.validate(%{})
|
|
|
|
|
|
|
|
refute form.changed?
|
|
|
|
end
|
|
|
|
|
|
|
|
test "it is true when a change is made" do
|
|
|
|
post =
|
|
|
|
Post
|
|
|
|
|> Ash.Changeset.new(%{text: "post"})
|
|
|
|
|> Api.create!()
|
|
|
|
|
|
|
|
form =
|
|
|
|
post
|
|
|
|
|> Form.for_update(:update)
|
|
|
|
|> Form.validate(%{text: "post1"})
|
|
|
|
|
|
|
|
assert form.changed?
|
|
|
|
end
|
|
|
|
|
|
|
|
test "it goes back to false if the change is unmade" do
|
|
|
|
post =
|
|
|
|
Post
|
|
|
|
|> Ash.Changeset.new(%{text: "post"})
|
|
|
|
|> Api.create!()
|
|
|
|
|
|
|
|
form =
|
|
|
|
post
|
|
|
|
|> Form.for_update(:update)
|
|
|
|
|> Form.validate(%{text: "post1"})
|
|
|
|
|
|
|
|
assert form.changed?
|
|
|
|
|
|
|
|
form =
|
|
|
|
form
|
|
|
|
|> Form.validate(%{text: "post"})
|
|
|
|
|
|
|
|
refute form.changed?
|
|
|
|
end
|
2021-11-07 07:12:53 +13:00
|
|
|
|
|
|
|
test "adding a form causes changed? to be true on the root form, but not the nested form" do
|
|
|
|
form =
|
|
|
|
Comment
|
|
|
|
|> Form.for_create(:create,
|
|
|
|
api: Api,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
resource: Post,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
2021-11-08 22:47:12 +13:00
|
|
|
|> Form.add_form(:post)
|
2021-11-07 07:12:53 +13:00
|
|
|
|
|
|
|
assert form.changed?
|
|
|
|
refute form.forms[:post].changed?
|
|
|
|
end
|
|
|
|
|
|
|
|
test "removing a form that was there prior marks the form as changed" do
|
|
|
|
post =
|
|
|
|
Post
|
|
|
|
|> Ash.Changeset.new(%{text: "post"})
|
|
|
|
|> Api.create!()
|
|
|
|
|
|
|
|
comment =
|
|
|
|
Comment
|
|
|
|
|> Ash.Changeset.new(%{text: "comment"})
|
2022-09-21 17:24:52 +12:00
|
|
|
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|
2021-11-07 07:12:53 +13:00
|
|
|
|> Api.create!()
|
|
|
|
|
|
|
|
# Check the persisted post.comments count after create
|
|
|
|
post = Post |> Api.get!(post.id) |> Api.load!(:comments)
|
|
|
|
assert Enum.count(post.comments) == 1
|
|
|
|
|
|
|
|
form =
|
|
|
|
post
|
|
|
|
|> Form.for_update(:update,
|
|
|
|
api: Api,
|
|
|
|
forms: [
|
|
|
|
comments: [
|
|
|
|
resource: Comment,
|
|
|
|
type: :list,
|
|
|
|
data: [comment],
|
|
|
|
create_action: :create,
|
|
|
|
update_action: :update
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
refute form.changed?
|
|
|
|
|
|
|
|
form = Form.remove_form(form, [:comments, 0])
|
|
|
|
|
|
|
|
assert form.changed?
|
|
|
|
end
|
|
|
|
|
2022-10-07 15:33:36 +13:00
|
|
|
test "generated forms have default values even with no server round-trips" do
|
|
|
|
post =
|
|
|
|
Post
|
|
|
|
|> Ash.Changeset.new(%{text: "post"})
|
|
|
|
|> Api.create!()
|
|
|
|
|
|
|
|
comment =
|
|
|
|
Comment
|
|
|
|
|> Ash.Changeset.new(%{text: "comment"})
|
|
|
|
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|
|
|
|
|> Api.create!()
|
|
|
|
|
|
|
|
# Check the persisted post.comments count after create
|
|
|
|
post = Post |> Api.get!(post.id) |> Api.load!(:comments)
|
|
|
|
assert Enum.count(post.comments) == 1
|
|
|
|
|
|
|
|
form =
|
|
|
|
post
|
|
|
|
|> Form.for_update(:update,
|
|
|
|
api: Api,
|
|
|
|
forms: [
|
|
|
|
comments: [
|
|
|
|
resource: Comment,
|
|
|
|
type: :list,
|
|
|
|
data: [comment],
|
|
|
|
create_action: :create,
|
|
|
|
update_action: :update
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
form = AshPhoenix.Form.add_form(form, :comments)
|
|
|
|
|
|
|
|
assert AshPhoenix.Form.params(form) == %{
|
|
|
|
"_form_type" => "update",
|
|
|
|
"_touched" => "comments",
|
|
|
|
"comments" => [
|
|
|
|
%{
|
|
|
|
"_form_type" => "update",
|
|
|
|
"_touched" => "_form_type,id",
|
|
|
|
"id" => post.comments |> Enum.at(0) |> Map.get(:id)
|
|
|
|
},
|
|
|
|
%{"_form_type" => "create", "_touched" => "_form_type"}
|
|
|
|
],
|
|
|
|
"id" => post.id
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2022-05-17 14:37:36 +12:00
|
|
|
test "removing a non-existant form should not change touched_forms" do
|
|
|
|
form =
|
|
|
|
Post
|
|
|
|
|> Form.for_create(:create, api: Api, forms: [auto?: true])
|
|
|
|
|> AshPhoenix.Form.remove_form([:author])
|
|
|
|
|
|
|
|
assert MapSet.member?(form.touched_forms, "author") == false
|
|
|
|
end
|
|
|
|
|
2021-11-07 07:12:53 +13:00
|
|
|
test "removing a form that was added does not mark the form as changed" do
|
|
|
|
post =
|
|
|
|
Post
|
|
|
|
|> Ash.Changeset.new(%{text: "post"})
|
|
|
|
|> Api.create!()
|
|
|
|
|
|
|
|
comment =
|
|
|
|
Comment
|
|
|
|
|> Ash.Changeset.new(%{text: "comment"})
|
2022-09-21 17:24:52 +12:00
|
|
|
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|
2021-11-07 07:12:53 +13:00
|
|
|
|> Api.create!()
|
|
|
|
|
|
|
|
# Check the persisted post.comments count after create
|
|
|
|
post = Post |> Api.get!(post.id) |> Api.load!(:comments)
|
|
|
|
assert Enum.count(post.comments) == 1
|
|
|
|
|
|
|
|
form =
|
|
|
|
post
|
|
|
|
|> Form.for_update(:update,
|
|
|
|
api: Api,
|
|
|
|
forms: [
|
|
|
|
comments: [
|
|
|
|
resource: Comment,
|
|
|
|
type: :list,
|
|
|
|
data: [comment],
|
|
|
|
create_action: :create,
|
|
|
|
update_action: :update
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
refute form.changed?
|
|
|
|
|
|
|
|
form = Form.add_form(form, [:comments])
|
|
|
|
|
|
|
|
assert form.changed?
|
|
|
|
|
|
|
|
form = Form.remove_form(form, [:comments, 1])
|
|
|
|
|
|
|
|
refute form.changed?
|
|
|
|
end
|
2021-11-07 05:15:50 +13:00
|
|
|
end
|
|
|
|
|
2021-07-16 06:09:15 +12:00
|
|
|
describe "errors" do
|
|
|
|
test "errors are not set on the form without validating" do
|
|
|
|
form =
|
|
|
|
Post
|
|
|
|
|> Form.for_create(:create)
|
|
|
|
|> form_for("action")
|
|
|
|
|
|
|
|
assert form.errors == []
|
|
|
|
end
|
|
|
|
|
|
|
|
test "errors are set on the form according to changeset errors on validate" do
|
|
|
|
form =
|
|
|
|
Post
|
|
|
|
|> Form.for_create(:create)
|
|
|
|
|> Form.validate(%{})
|
|
|
|
|> form_for("action")
|
|
|
|
|
|
|
|
assert form.errors == [{:text, {"is required", []}}]
|
|
|
|
end
|
|
|
|
|
|
|
|
test "nested errors are set on the appropriate form after submit" do
|
|
|
|
form =
|
|
|
|
Comment
|
|
|
|
|> Form.for_create(:create,
|
2021-07-19 11:20:25 +12:00
|
|
|
api: Api,
|
2021-07-16 06:09:15 +12:00
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
resource: Post,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.add_form(:post, params: %{})
|
|
|
|
|> Form.validate(%{"text" => "text", "post" => %{}})
|
2021-07-19 11:20:25 +12:00
|
|
|
|> Form.submit(force?: true)
|
2021-07-16 06:09:15 +12:00
|
|
|
|> elem(1)
|
|
|
|
|> form_for("action")
|
|
|
|
|
|
|
|
assert form.errors == []
|
|
|
|
|
2021-07-17 10:23:07 +12:00
|
|
|
assert hd(inputs_for(form, :post)).errors == [{:text, {"is required", []}}]
|
2021-07-16 06:09:15 +12:00
|
|
|
end
|
|
|
|
|
2021-08-02 05:18:37 +12:00
|
|
|
test "relationship source data is retained, so that it can be properly removed" do
|
|
|
|
post =
|
|
|
|
Post
|
|
|
|
|> Ash.Changeset.new(%{text: "post"})
|
|
|
|
|> Api.create!()
|
|
|
|
|
|
|
|
comment =
|
|
|
|
Comment
|
|
|
|
|> Ash.Changeset.new(%{text: "comment"})
|
2022-09-21 17:24:52 +12:00
|
|
|
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|
2021-08-02 05:18:37 +12:00
|
|
|
|> Api.create!()
|
|
|
|
|
|
|
|
comment = Comment |> Api.get!(comment.id)
|
|
|
|
|
|
|
|
comment
|
|
|
|
|> Api.load!(:post)
|
|
|
|
|> Form.for_update(:update,
|
|
|
|
api: Api,
|
|
|
|
forms: [
|
|
|
|
auto?: true
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.remove_form([:post])
|
|
|
|
|> Form.submit!(params: %{"text" => "text", "post" => %{"text" => "new_post"}})
|
|
|
|
|
|
|
|
assert [%{text: "new_post"}] = Api.read!(Post)
|
|
|
|
end
|
|
|
|
|
2021-07-17 11:58:14 +12:00
|
|
|
test "nested errors are set on the appropriate form after submit, even if no submit actually happens" do
|
|
|
|
form =
|
|
|
|
Comment
|
|
|
|
|> Form.for_create(:create,
|
2021-07-19 11:20:25 +12:00
|
|
|
api: Api,
|
2021-07-17 11:58:14 +12:00
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
resource: Post,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.add_form(:post, params: %{})
|
2021-07-19 11:20:25 +12:00
|
|
|
|> Form.submit(params: %{"text" => "text", "post" => %{}})
|
2021-07-17 11:58:14 +12:00
|
|
|
|> elem(1)
|
|
|
|
|> form_for("action")
|
|
|
|
|
|
|
|
assert form.errors == []
|
|
|
|
|
|
|
|
assert hd(inputs_for(form, :post)).errors == [{:text, {"is required", []}}]
|
|
|
|
end
|
|
|
|
|
2021-07-22 13:52:04 +12:00
|
|
|
test "nested errors can be fetched with `Form.errors/2`" do
|
|
|
|
form =
|
|
|
|
Comment
|
|
|
|
|> Form.for_create(:create,
|
|
|
|
api: Api,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
resource: Post,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.add_form(:post, params: %{})
|
|
|
|
|> Form.validate(%{"text" => "text", "post" => %{}})
|
|
|
|
|> Form.submit(force?: true)
|
|
|
|
|> elem(1)
|
|
|
|
|> form_for("action")
|
|
|
|
|
|
|
|
assert Form.errors(form.source, for_path: [:post]) == [{:text, "is required"}]
|
|
|
|
|
|
|
|
assert Form.errors(form.source, for_path: [:post], format: :raw) == [
|
|
|
|
{:text, {"is required", []}}
|
|
|
|
]
|
|
|
|
|
|
|
|
assert Form.errors(form.source, for_path: [:post], format: :plaintext) == [
|
|
|
|
"text: is required"
|
|
|
|
]
|
|
|
|
|
|
|
|
assert Form.errors(form.source, for_path: :all) == %{[:post] => [{:text, "is required"}]}
|
|
|
|
end
|
|
|
|
|
|
|
|
test "errors can be fetched with `Form.errors/2`" do
|
|
|
|
form =
|
|
|
|
Comment
|
|
|
|
|> Form.for_create(:create,
|
|
|
|
api: Api,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
resource: Post,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.add_form(:post, params: %{})
|
|
|
|
|> Form.validate(%{"post" => %{"text" => "text"}})
|
|
|
|
|> Form.submit(force?: true)
|
|
|
|
|> elem(1)
|
|
|
|
|> form_for("action")
|
|
|
|
|
|
|
|
assert Form.errors(form.source) == [{:text, "is required"}]
|
|
|
|
|
|
|
|
assert Form.errors(form.source, format: :raw) == [
|
|
|
|
{:text, {"is required", []}}
|
|
|
|
]
|
|
|
|
|
|
|
|
assert Form.errors(form.source, format: :plaintext) == [
|
|
|
|
"text: is required"
|
|
|
|
]
|
|
|
|
end
|
|
|
|
|
2022-05-18 03:06:31 +12:00
|
|
|
test "nested forms submit empty values when they have been touched, even if not included in future params" do
|
2021-07-16 06:09:15 +12:00
|
|
|
form =
|
|
|
|
Comment
|
|
|
|
|> Form.for_create(:create,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
resource: Post,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.add_form(:post, params: %{})
|
|
|
|
|> Form.validate(%{"text" => "text"})
|
|
|
|
|
2022-10-07 15:33:36 +13:00
|
|
|
assert %{"text" => "text", "post" => nil} = Form.params(form)
|
2021-07-16 06:09:15 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
test "nested forms submit empty list values when not present in input params" do
|
|
|
|
form =
|
|
|
|
Comment
|
|
|
|
|> Form.for_create(:create,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
type: :list,
|
|
|
|
resource: Post,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.add_form(:post, params: %{})
|
|
|
|
|> Form.validate(%{"text" => "text"})
|
|
|
|
|
2021-08-04 14:59:04 +12:00
|
|
|
assert Form.value(form, :text) == "text"
|
|
|
|
|
2022-10-07 15:33:36 +13:00
|
|
|
assert %{
|
|
|
|
"text" => "text",
|
|
|
|
"post" => [],
|
|
|
|
"_form_type" => "create",
|
|
|
|
"_touched" => "_form_type,_touched,post,text"
|
|
|
|
} = Form.params(form)
|
2021-07-16 06:09:15 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
test "nested errors are set on the appropriate form after submit for many to many relationships" do
|
|
|
|
form =
|
|
|
|
Post
|
|
|
|
|> Form.for_create(:create,
|
2021-07-19 11:20:25 +12:00
|
|
|
api: Api,
|
2021-07-16 06:09:15 +12:00
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
type: :list,
|
|
|
|
for: :linked_posts,
|
|
|
|
resource: Post,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.add_form(:post, params: %{})
|
|
|
|
|> Form.validate(%{"text" => "text", "post" => [%{}]})
|
2021-07-19 11:20:25 +12:00
|
|
|
|> Form.submit(force?: true)
|
2021-07-16 06:09:15 +12:00
|
|
|
|> elem(1)
|
|
|
|
|> form_for("action")
|
|
|
|
|
|
|
|
assert form.errors == []
|
|
|
|
|
|
|
|
assert [nested_form] = inputs_for(form, :post)
|
|
|
|
assert nested_form.errors == [{:text, {"is required", []}}]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "data" do
|
|
|
|
test "it uses the provided data to create forms even without input" do
|
|
|
|
post1_id = Ash.UUID.generate()
|
|
|
|
post2_id = Ash.UUID.generate()
|
|
|
|
|
|
|
|
form =
|
|
|
|
Comment
|
|
|
|
|> Form.for_create(
|
|
|
|
:create,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
type: :list,
|
|
|
|
data: [%Post{id: post1_id}, %Post{id: post2_id}],
|
|
|
|
update_action: :update,
|
|
|
|
forms: [
|
|
|
|
comments: [
|
|
|
|
type: :list,
|
|
|
|
resource: Comment,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
2022-08-16 04:31:07 +12:00
|
|
|
|> form_for("foo")
|
2021-07-16 06:09:15 +12:00
|
|
|
|
2022-08-16 04:31:07 +12:00
|
|
|
assert Enum.count(inputs_for(form, :post)) == 2
|
2021-07-16 06:09:15 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
test "a function can be used to derive the data from the data of the parent form" do
|
|
|
|
post1_id = Ash.UUID.generate()
|
|
|
|
post2_id = Ash.UUID.generate()
|
|
|
|
comment_id = Ash.UUID.generate()
|
|
|
|
|
|
|
|
form =
|
|
|
|
Comment
|
|
|
|
|> Form.for_create(
|
|
|
|
:create,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
type: :list,
|
|
|
|
data: [
|
|
|
|
%Post{id: post1_id, comments: [%Comment{id: comment_id}]},
|
|
|
|
%Post{id: post2_id, comments: []}
|
|
|
|
],
|
|
|
|
update_action: :update,
|
|
|
|
forms: [
|
|
|
|
comments: [
|
|
|
|
data: &(&1.comments || []),
|
|
|
|
type: :list,
|
|
|
|
resource: Comment,
|
|
|
|
create_action: :create,
|
|
|
|
update_action: :update
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.validate(%{
|
|
|
|
"text" => "text",
|
|
|
|
"post" => %{
|
|
|
|
"0" => %{"id" => post1_id, "comments" => %{"0" => %{"id" => comment_id}}},
|
|
|
|
"1" => %{"id" => post2_id}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2022-10-07 15:33:36 +13:00
|
|
|
assert %{
|
2021-07-16 06:09:15 +12:00
|
|
|
"post" => [
|
2022-10-07 15:33:36 +13:00
|
|
|
%{"comments" => [%{"id" => ^comment_id}], "id" => ^post1_id},
|
|
|
|
%{"id" => ^post2_id}
|
2021-07-16 06:09:15 +12:00
|
|
|
],
|
|
|
|
"text" => "text"
|
2022-10-07 15:33:36 +13:00
|
|
|
} = Form.params(form)
|
2021-07-16 06:09:15 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "submit" do
|
|
|
|
test "it runs the action with the params" do
|
|
|
|
assert {:ok, %{text: "text"}} =
|
|
|
|
Post
|
2021-07-19 11:20:25 +12:00
|
|
|
|> Form.for_create(:create, api: Api)
|
2021-07-16 06:09:15 +12:00
|
|
|
|> Form.validate(%{text: "text"})
|
2021-07-19 11:20:25 +12:00
|
|
|
|> Form.submit()
|
2021-07-16 06:09:15 +12:00
|
|
|
end
|
2021-07-19 16:58:46 +12:00
|
|
|
|
|
|
|
test "it raises an appropriate error when the incorrect api is configured" do
|
2023-05-01 14:48:04 +12:00
|
|
|
assert_raise Ash.Error.Invalid.ResourceNotAllowed,
|
2023-05-01 15:03:12 +12:00
|
|
|
~r/Resource `AshPhoenix.Test.Post` is not accepted by AshPhoenix.Test.OtherApi/,
|
2021-07-19 16:58:46 +12:00
|
|
|
fn ->
|
|
|
|
Post
|
|
|
|
|> Form.for_create(:create, api: OtherApi)
|
|
|
|
|> Form.validate(%{text: "text"})
|
|
|
|
|> Form.submit()
|
|
|
|
end
|
|
|
|
end
|
2021-07-16 06:09:15 +12:00
|
|
|
end
|
|
|
|
|
2022-12-16 10:40:24 +13:00
|
|
|
describe "prepare_source" do
|
|
|
|
test "it runs on initial create" do
|
|
|
|
form =
|
|
|
|
Post
|
|
|
|
|> Form.for_create(:create,
|
|
|
|
api: Api,
|
|
|
|
prepare_source: &Ash.Changeset.put_context(&1, :foo, :bar)
|
|
|
|
)
|
|
|
|
|
|
|
|
assert form.source.context.foo == :bar
|
|
|
|
end
|
|
|
|
|
|
|
|
test "it is preserved on validate create" do
|
|
|
|
form =
|
|
|
|
Post
|
|
|
|
|> Form.for_create(:create,
|
|
|
|
api: Api,
|
|
|
|
prepare_source: &Ash.Changeset.put_context(&1, :foo, :bar)
|
|
|
|
)
|
|
|
|
|> Form.validate(%{text: "text"})
|
|
|
|
|
|
|
|
assert form.source.context.foo == :bar
|
|
|
|
end
|
|
|
|
|
|
|
|
test "it is preserved through to submit" do
|
|
|
|
result =
|
|
|
|
Post
|
|
|
|
|> Form.for_create(:create,
|
|
|
|
api: Api,
|
|
|
|
prepare_source: fn changeset ->
|
|
|
|
Ash.Changeset.before_action(
|
|
|
|
changeset,
|
|
|
|
&Ash.Changeset.force_change_attribute(&1, :title, "special_title")
|
|
|
|
)
|
|
|
|
end
|
|
|
|
)
|
|
|
|
|> Form.validate(%{text: "text"})
|
|
|
|
|> Form.submit!()
|
|
|
|
|
|
|
|
assert result.title == "special_title"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-07-16 06:09:15 +12:00
|
|
|
describe "params" do
|
|
|
|
test "it includes nested forms, and honors their `for` configuration" do
|
|
|
|
form =
|
|
|
|
Comment
|
|
|
|
|> Form.for_create(:create,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
type: :list,
|
|
|
|
resource: Post,
|
|
|
|
create_action: :create,
|
|
|
|
forms: [
|
|
|
|
comments: [
|
|
|
|
type: :list,
|
|
|
|
resource: Comment,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
],
|
|
|
|
other_post: [
|
|
|
|
type: :single,
|
|
|
|
for: :for_posts,
|
|
|
|
resource: Post,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.add_form("form[post]", params: %{"text" => "post_text"})
|
|
|
|
|> Form.add_form("form[other_post]", params: %{"text" => "post_text"})
|
|
|
|
|> Form.add_form("form[post][0][comments]", params: %{"text" => "post_text"})
|
|
|
|
|> Form.validate(%{
|
|
|
|
"text" => "text",
|
|
|
|
"post" => [%{"comments" => [%{"text" => "post_text"}], "text" => "post_text"}],
|
|
|
|
"other_post" => %{"text" => "post_text"}
|
|
|
|
})
|
|
|
|
|
2021-08-12 10:48:52 +12:00
|
|
|
assert %{
|
2021-07-16 06:09:15 +12:00
|
|
|
"text" => "text",
|
|
|
|
"post" => [%{"comments" => [%{"text" => "post_text"}], "text" => "post_text"}],
|
|
|
|
"for_posts" => %{"text" => "post_text"}
|
2021-08-12 10:48:52 +12:00
|
|
|
} = Form.params(form)
|
2021-07-16 06:09:15 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-10-28 16:43:20 +13:00
|
|
|
test "it properly retains form order" do
|
|
|
|
form =
|
|
|
|
Comment
|
|
|
|
|> Form.for_create(:create,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
type: :list,
|
|
|
|
resource: Post,
|
|
|
|
create_action: :create,
|
|
|
|
forms: [
|
|
|
|
comments: [
|
|
|
|
type: :list,
|
|
|
|
resource: Comment,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
],
|
|
|
|
other_post: [
|
|
|
|
type: :single,
|
|
|
|
for: :for_posts,
|
|
|
|
resource: Post,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.add_form("form[post]", params: %{"text" => "post_text"})
|
|
|
|
|> Form.add_form("form[post][0][comments]", params: %{"text" => "0"})
|
|
|
|
|> Form.add_form("form[post][0][comments]", params: %{"text" => "1"})
|
|
|
|
|> Form.add_form("form[post][0][comments]", params: %{"text" => "2"})
|
|
|
|
|> Form.add_form("form[post][0][comments]", params: %{"text" => "3"})
|
|
|
|
|> Form.add_form("form[post][0][comments]", params: %{"text" => "4"})
|
|
|
|
|> Form.add_form("form[post][0][comments]", params: %{"text" => "5"})
|
|
|
|
|> Form.add_form("form[post][0][comments]", params: %{"text" => "6"})
|
|
|
|
|> Form.add_form("form[post][0][comments]", params: %{"text" => "7"})
|
|
|
|
|> Form.add_form("form[post][0][comments]", params: %{"text" => "8"})
|
|
|
|
|> Form.add_form("form[post][0][comments]", params: %{"text" => "9"})
|
|
|
|
|> Form.add_form("form[post][0][comments]", params: %{"text" => "10"})
|
|
|
|
|> Form.add_form("form[post][0][comments]", params: %{"text" => "11"})
|
|
|
|
|
|
|
|
assert %{
|
|
|
|
"post" => [
|
|
|
|
%{
|
|
|
|
"comments" => [
|
|
|
|
%{"text" => "0"},
|
|
|
|
%{"text" => "1"},
|
|
|
|
%{"text" => "2"},
|
|
|
|
%{"text" => "3"},
|
|
|
|
%{"text" => "4"},
|
|
|
|
%{"text" => "5"},
|
|
|
|
%{"text" => "6"},
|
|
|
|
%{"text" => "7"},
|
|
|
|
%{"text" => "8"},
|
|
|
|
%{"text" => "9"},
|
|
|
|
%{"text" => "10"},
|
|
|
|
%{"text" => "11"}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
} = Form.params(form)
|
|
|
|
end
|
|
|
|
|
2021-07-16 06:09:15 +12:00
|
|
|
describe "`inputs_for` with no configuration" do
|
|
|
|
test "it should raise an error" do
|
|
|
|
form =
|
|
|
|
Post
|
|
|
|
|> Form.for_create(:create)
|
|
|
|
|> Form.validate(%{text: "text"})
|
|
|
|
|> form_for("action")
|
|
|
|
|
|
|
|
assert_raise AshPhoenix.Form.NoFormConfigured, fn ->
|
|
|
|
inputs_for(form, :post) == []
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "inputs_for` relationships" do
|
2021-07-19 14:07:54 +12:00
|
|
|
test "it should name the fields correctly on `for_update`" do
|
|
|
|
post_id = Ash.UUID.generate()
|
|
|
|
comment_id = Ash.UUID.generate()
|
|
|
|
|
|
|
|
comment = %Comment{
|
|
|
|
text: "text",
|
|
|
|
post: %Post{
|
|
|
|
id: post_id,
|
|
|
|
text: "Some text",
|
|
|
|
comments: [%Comment{id: comment_id}]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
form =
|
|
|
|
comment
|
|
|
|
|> Form.for_update(:update,
|
|
|
|
as: "comment",
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
data: comment.post,
|
|
|
|
type: :single,
|
|
|
|
resource: Post,
|
|
|
|
update_action: :update,
|
|
|
|
create_action: :create,
|
|
|
|
forms: [
|
|
|
|
comments: [
|
|
|
|
data: & &1.comments,
|
|
|
|
type: :list,
|
|
|
|
resource: Comment,
|
|
|
|
update_action: :update,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
comments_form =
|
|
|
|
form
|
|
|
|
|> form_for("action")
|
|
|
|
|> inputs_for(:post)
|
|
|
|
|> hd()
|
|
|
|
|> inputs_for(:comments)
|
|
|
|
|> hd()
|
|
|
|
|
|
|
|
assert comments_form.name == "comment[post][comments][0]"
|
|
|
|
end
|
|
|
|
|
2021-07-16 06:09:15 +12:00
|
|
|
test "the `type: :single` option should create a form without integer paths" do
|
|
|
|
form =
|
|
|
|
Comment
|
|
|
|
|> Form.for_create(:create,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
resource: Post,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.add_form(:post, params: %{text: "post_text"})
|
|
|
|
|> Form.validate(%{"text" => "text", "post" => %{"text" => "post_text"}})
|
|
|
|
|> form_for("action")
|
|
|
|
|
|
|
|
assert %Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Post}} =
|
2021-07-17 10:23:07 +12:00
|
|
|
related_form = hd(inputs_for(form, :post))
|
2021-07-16 06:09:15 +12:00
|
|
|
|
|
|
|
assert related_form.name == "form[post]"
|
|
|
|
|
|
|
|
assert FormData.input_value(related_form.source, related_form, :text) == "post_text"
|
|
|
|
end
|
|
|
|
|
|
|
|
test "it should show nothing in `inputs_for` by default" do
|
|
|
|
form =
|
|
|
|
Comment
|
|
|
|
|> Form.for_create(:create,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
type: :list,
|
|
|
|
resource: Post,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.validate(%{"text" => "text"})
|
|
|
|
|> form_for("action")
|
|
|
|
|
|
|
|
assert inputs_for(form, :post) == []
|
|
|
|
end
|
|
|
|
|
|
|
|
test "when a value has been appended to the relationship, a form is created" do
|
|
|
|
form =
|
|
|
|
Comment
|
|
|
|
|> Form.for_create(:create,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
type: :list,
|
|
|
|
resource: Post,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.add_form(:post, params: %{text: "post_text"})
|
|
|
|
|> form_for("action")
|
|
|
|
|
|
|
|
assert [
|
|
|
|
%Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Post}} =
|
|
|
|
related_form
|
|
|
|
] = inputs_for(form, :post)
|
|
|
|
|
|
|
|
assert FormData.input_value(related_form.source, related_form, :text) == "post_text"
|
|
|
|
end
|
|
|
|
|
|
|
|
test "a query path can be used when manipulating forms" do
|
|
|
|
form =
|
|
|
|
Comment
|
|
|
|
|> Form.for_create(:create,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
type: :list,
|
|
|
|
resource: Post,
|
|
|
|
create_action: :create,
|
|
|
|
forms: [
|
|
|
|
comments: [
|
|
|
|
type: :list,
|
|
|
|
resource: Comment,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.add_form("form[post]", params: %{text: "post_text"})
|
|
|
|
|> Form.add_form("form[post][0][comments]", params: %{text: "post_text"})
|
|
|
|
|> form_for("action")
|
|
|
|
|
|
|
|
assert [
|
|
|
|
%Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Post}} =
|
|
|
|
post_form
|
|
|
|
] = inputs_for(form, :post)
|
|
|
|
|
|
|
|
assert [
|
|
|
|
%Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Comment}}
|
|
|
|
] = inputs_for(post_form, :comments)
|
|
|
|
end
|
|
|
|
|
|
|
|
test "list values get an index in their name and id" do
|
|
|
|
form =
|
|
|
|
Comment
|
|
|
|
|> Form.for_create(:create,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
type: :list,
|
|
|
|
resource: Post,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.add_form(:post, params: %{text: "post_text0"})
|
|
|
|
|> Form.add_form(:post, params: %{text: "post_text1"})
|
|
|
|
|> Form.add_form(:post, params: %{text: "post_text2"})
|
|
|
|
|
|
|
|
assert [
|
|
|
|
%Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Post}} =
|
|
|
|
form_0,
|
|
|
|
%Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Post}} =
|
|
|
|
form_1,
|
|
|
|
%Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Post}} =
|
|
|
|
form_2
|
|
|
|
] = inputs_for(form_for(form, "action"), :post)
|
|
|
|
|
|
|
|
assert form_0.name == "form[post][0]"
|
|
|
|
assert form_0.id == "form_post_0"
|
|
|
|
|
|
|
|
assert form_1.name == "form[post][1]"
|
|
|
|
assert form_1.id == "form_post_1"
|
|
|
|
|
|
|
|
assert form_2.name == "form[post][2]"
|
|
|
|
assert form_2.id == "form_post_2"
|
|
|
|
end
|
|
|
|
|
|
|
|
test "when a value has been removed from the relationship, the form is removed" do
|
|
|
|
form =
|
|
|
|
Comment
|
|
|
|
|> Form.for_create(:create,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
type: :list,
|
|
|
|
resource: Post,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.add_form(:post, params: %{text: "post_text0"})
|
|
|
|
|> Form.add_form(:post, params: %{text: "post_text1"})
|
|
|
|
|> Form.add_form(:post, params: %{text: "post_text2"})
|
|
|
|
|
|
|
|
assert [
|
|
|
|
%Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Post}},
|
|
|
|
%Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Post}},
|
|
|
|
%Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Post}}
|
|
|
|
] = inputs_for(form_for(form, "action"), :post)
|
|
|
|
|
|
|
|
form =
|
|
|
|
form
|
|
|
|
|> Form.remove_form([:post, 0])
|
|
|
|
|> Form.remove_form([:post, 1])
|
|
|
|
|
|
|
|
assert [
|
|
|
|
%Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Post}} =
|
|
|
|
related_form
|
|
|
|
] = inputs_for(form_for(form, "action"), :post)
|
|
|
|
|
|
|
|
assert FormData.input_value(related_form.source, related_form, :text) == "post_text1"
|
|
|
|
end
|
|
|
|
|
|
|
|
test "when all values have been removed from a relationship, the empty list remains" do
|
|
|
|
form =
|
|
|
|
Comment
|
|
|
|
|> Form.for_create(:create,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
type: :list,
|
|
|
|
resource: Post,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.add_form(:post, params: %{text: "post_text0"})
|
|
|
|
|> Form.add_form(:post, params: %{text: "post_text1"})
|
|
|
|
|> Form.add_form(:post, params: %{text: "post_text2"})
|
|
|
|
|
|
|
|
assert [
|
|
|
|
%Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Post}},
|
|
|
|
%Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Post}},
|
|
|
|
%Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Post}}
|
|
|
|
] = inputs_for(form_for(form, "action"), :post)
|
|
|
|
|
|
|
|
form =
|
|
|
|
form
|
|
|
|
|> Form.remove_form([:post, 0])
|
|
|
|
|> Form.remove_form([:post, 0])
|
|
|
|
|> Form.remove_form([:post, 0])
|
|
|
|
|> Form.validate(%{})
|
|
|
|
|
|
|
|
assert [] = inputs_for(form_for(form, "action"), :post)
|
2022-10-07 15:33:36 +13:00
|
|
|
assert %{"post" => []} = Form.params(form)
|
2021-07-16 06:09:15 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
test "when all values have been removed from an existing relationship, the empty list remains" do
|
|
|
|
post1_id = Ash.UUID.generate()
|
|
|
|
post2_id = Ash.UUID.generate()
|
|
|
|
comment = %Comment{text: "text", post: [%Post{id: post1_id}, %Post{id: post2_id}]}
|
|
|
|
|
|
|
|
form =
|
|
|
|
comment
|
2022-05-29 13:20:54 +12:00
|
|
|
|> Form.for_update(:update,
|
2021-07-16 06:09:15 +12:00
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
data: comment.post,
|
|
|
|
type: :list,
|
|
|
|
resource: Post,
|
|
|
|
create_action: :create,
|
|
|
|
update_action: :update
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.add_form(:post, params: %{text: "post_text3"})
|
|
|
|
|
|
|
|
assert [
|
|
|
|
%Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Post}},
|
|
|
|
%Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Post}},
|
|
|
|
%Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Post}}
|
|
|
|
] = inputs_for(form_for(form, "action"), :post)
|
|
|
|
|
|
|
|
form =
|
|
|
|
form
|
|
|
|
|> Form.remove_form([:post, 0])
|
|
|
|
|> Form.remove_form([:post, 0])
|
|
|
|
|> Form.remove_form([:post, 0])
|
|
|
|
|> Form.validate(%{})
|
|
|
|
|
2022-10-07 15:33:36 +13:00
|
|
|
assert %{"post" => []} = Form.params(form)
|
2021-07-16 06:09:15 +12:00
|
|
|
end
|
2021-07-17 10:23:07 +12:00
|
|
|
|
2021-07-20 17:54:36 +12:00
|
|
|
test "when all values have been removed from an existing `:single` relationship, the empty list remains" do
|
|
|
|
post_id = Ash.UUID.generate()
|
|
|
|
comment_2 = %Comment{text: "text"}
|
|
|
|
|
|
|
|
comment = %Comment{text: "text", post: %Post{id: post_id, comments: [comment_2]}}
|
|
|
|
|
|
|
|
form =
|
|
|
|
comment
|
|
|
|
|> Form.for_update(:update,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
data: & &1.post,
|
|
|
|
type: :single,
|
|
|
|
resource: Post,
|
|
|
|
update_action: :update,
|
|
|
|
create_action: :create,
|
|
|
|
forms: [
|
|
|
|
comments: [
|
|
|
|
type: :list,
|
|
|
|
resource: Comment,
|
|
|
|
data: & &1.comments,
|
|
|
|
create_action: :create,
|
|
|
|
update_action: :update
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [%Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Post}}] =
|
|
|
|
form
|
|
|
|
|> form_for("action")
|
|
|
|
|> inputs_for(:post)
|
|
|
|
|
|
|
|
form =
|
|
|
|
form
|
|
|
|
|> Form.remove_form([:post, :comments, 0])
|
2021-08-12 10:48:52 +12:00
|
|
|
# This is added by the hidden fields helper, so we add it here to simulate that.
|
|
|
|
|> Form.validate(%{"post" => %{"_touched" => "comments"}})
|
2021-07-20 17:54:36 +12:00
|
|
|
|
2021-08-12 10:48:52 +12:00
|
|
|
assert %{"post" => %{"comments" => []}} = Form.params(form)
|
2021-07-20 17:54:36 +12:00
|
|
|
end
|
|
|
|
|
2021-07-20 14:55:05 +12:00
|
|
|
test "remaining forms are reindexed after a form has been removed" do
|
|
|
|
post1_id = Ash.UUID.generate()
|
|
|
|
post2_id = Ash.UUID.generate()
|
|
|
|
post3_id = Ash.UUID.generate()
|
|
|
|
|
|
|
|
comment = %Comment{
|
|
|
|
text: "text",
|
|
|
|
post: [%Post{id: post1_id}, %Post{id: post2_id}, %Post{id: post3_id}]
|
|
|
|
}
|
|
|
|
|
|
|
|
form =
|
|
|
|
comment
|
2022-05-29 13:20:54 +12:00
|
|
|
|> Form.for_update(:update,
|
2021-07-20 14:55:05 +12:00
|
|
|
forms: [
|
|
|
|
posts: [
|
|
|
|
data: comment.post,
|
|
|
|
type: :list,
|
|
|
|
resource: Post,
|
|
|
|
create_action: :create,
|
|
|
|
update_action: :update
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.remove_form([:posts, 1])
|
|
|
|
|
|
|
|
assert [
|
|
|
|
%Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Post}} =
|
|
|
|
form_0,
|
|
|
|
%Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Post}} =
|
|
|
|
form_1
|
|
|
|
] = inputs_for(form_for(form, "action"), :posts)
|
|
|
|
|
|
|
|
assert form_0.name == "form[posts][0]"
|
|
|
|
assert form_0.id == "form_posts_0"
|
|
|
|
|
|
|
|
assert form_1.name == "form[posts][1]"
|
|
|
|
assert form_1.id == "form_posts_1"
|
|
|
|
end
|
|
|
|
|
2021-07-17 10:23:07 +12:00
|
|
|
test "when `:single`, `inputs_for` generates a list of one single item" do
|
|
|
|
post_id = Ash.UUID.generate()
|
|
|
|
comment = %Comment{text: "text", post: %Post{id: post_id, text: "Some text"}}
|
|
|
|
|
|
|
|
form =
|
|
|
|
comment
|
|
|
|
|> Form.for_update(:update,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
data: comment.post,
|
|
|
|
type: :single,
|
|
|
|
resource: Post,
|
|
|
|
update_action: :update
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
|
|
|
assert [%Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Post}}] =
|
|
|
|
inputs_for(form_for(form, "action"), :post)
|
|
|
|
end
|
2021-07-18 07:57:27 +12:00
|
|
|
|
2021-07-19 14:07:54 +12:00
|
|
|
test "it creates nested forms for single resources" do
|
2021-07-18 07:57:27 +12:00
|
|
|
post_id = Ash.UUID.generate()
|
2021-07-18 08:06:15 +12:00
|
|
|
comment_id = Ash.UUID.generate()
|
|
|
|
|
|
|
|
comment = %Comment{
|
|
|
|
text: "text",
|
|
|
|
post: %Post{
|
|
|
|
id: post_id,
|
|
|
|
text: "Some text",
|
|
|
|
comments: [%Comment{id: comment_id}]
|
|
|
|
}
|
|
|
|
}
|
2021-07-18 07:57:27 +12:00
|
|
|
|
|
|
|
form =
|
|
|
|
comment
|
|
|
|
|> Form.for_update(:update,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
data: comment.post,
|
|
|
|
type: :single,
|
|
|
|
resource: Post,
|
|
|
|
update_action: :update,
|
|
|
|
create_action: :create,
|
|
|
|
forms: [
|
|
|
|
comments: [
|
|
|
|
data: & &1.comments,
|
|
|
|
type: :list,
|
|
|
|
resource: Comment,
|
|
|
|
update_action: :update,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
2021-07-18 08:06:15 +12:00
|
|
|
assert [%Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Comment}}] =
|
2021-07-18 07:57:27 +12:00
|
|
|
form
|
|
|
|
|> form_for("action")
|
|
|
|
|> inputs_for(:post)
|
|
|
|
|> hd()
|
|
|
|
|> inputs_for(:comments)
|
|
|
|
end
|
2021-07-20 15:42:11 +12:00
|
|
|
|
|
|
|
test "it `add_form`s for nested single resources" do
|
|
|
|
post_id = Ash.UUID.generate()
|
|
|
|
|
|
|
|
comment = %Comment{
|
|
|
|
text: "text",
|
|
|
|
post: %Post{
|
|
|
|
id: post_id,
|
|
|
|
text: "Some text",
|
|
|
|
comments: []
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
form =
|
|
|
|
comment
|
|
|
|
|> Form.for_update(:update,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
data: comment.post,
|
|
|
|
type: :single,
|
|
|
|
resource: Post,
|
|
|
|
update_action: :update,
|
|
|
|
create_action: :create,
|
|
|
|
forms: [
|
|
|
|
comments: [
|
|
|
|
type: :list,
|
|
|
|
resource: Comment,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.add_form([:post, :comments])
|
|
|
|
|
|
|
|
assert [%Phoenix.HTML.Form{source: %AshPhoenix.Form{resource: AshPhoenix.Test.Comment}}] =
|
|
|
|
form
|
|
|
|
|> form_for("action")
|
|
|
|
|> inputs_for(:post)
|
|
|
|
|> hd()
|
|
|
|
|> inputs_for(:comments)
|
|
|
|
end
|
2021-07-20 17:00:44 +12:00
|
|
|
|
|
|
|
test "it `remove_form`s for nested single resources" do
|
|
|
|
post_id = Ash.UUID.generate()
|
|
|
|
|
|
|
|
comment = %Comment{
|
|
|
|
text: "text",
|
|
|
|
post: %Post{
|
|
|
|
id: post_id,
|
|
|
|
text: "Some text",
|
|
|
|
comments: []
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
form =
|
|
|
|
comment
|
|
|
|
|> Form.for_update(:update,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
data: comment.post,
|
|
|
|
type: :single,
|
|
|
|
resource: Post,
|
|
|
|
update_action: :update,
|
|
|
|
create_action: :create,
|
|
|
|
forms: [
|
|
|
|
comments: [
|
|
|
|
type: :list,
|
|
|
|
resource: Comment,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|> Form.add_form([:post, :comments])
|
|
|
|
|> Form.remove_form([:post, :comments, 0])
|
|
|
|
|
|
|
|
assert [] =
|
|
|
|
form
|
|
|
|
|> form_for("action")
|
|
|
|
|> inputs_for(:post)
|
|
|
|
|> hd()
|
|
|
|
|> inputs_for(:comments)
|
|
|
|
end
|
2022-05-14 12:45:07 +12:00
|
|
|
|
|
|
|
test "when `remove_form`ing an existing `:single` relationship, a nil value is included in the params - if the form has been touched" do
|
|
|
|
post =
|
|
|
|
Post
|
|
|
|
|> Ash.Changeset.new(%{text: "post"})
|
|
|
|
|> Ash.Changeset.set_argument(:author, %{email: "nigel@elixir-lang.org"})
|
|
|
|
|> Api.create!()
|
|
|
|
|
|
|
|
form =
|
|
|
|
post
|
|
|
|
|> Form.for_update(:update, api: Api, forms: [auto?: true])
|
2022-05-18 03:06:31 +12:00
|
|
|
|> Form.remove_form([:author])
|
2022-05-14 12:45:07 +12:00
|
|
|
|
|
|
|
params =
|
|
|
|
form
|
|
|
|
|> Form.params()
|
|
|
|
|
2022-05-18 03:06:31 +12:00
|
|
|
assert %{"author" => nil} = params
|
2022-05-14 12:45:07 +12:00
|
|
|
end
|
2022-05-18 02:39:46 +12:00
|
|
|
|
|
|
|
test "when add_forming a required argument, the added form should be valid without needing to manually validate it" do
|
|
|
|
form =
|
|
|
|
Post
|
|
|
|
|> Form.for_create(:create_author_required, api: Api, forms: [auto?: true])
|
|
|
|
|> Form.validate(%{"text" => "foo"})
|
|
|
|
|> Form.add_form([:author], params: %{"email" => "james@foo.com"})
|
|
|
|
|
|
|
|
assert form.valid? == true
|
|
|
|
end
|
2021-07-16 06:09:15 +12:00
|
|
|
end
|
2021-08-05 16:45:09 +12:00
|
|
|
|
|
|
|
describe "issue #259" do
|
|
|
|
test "updating should not duplicate nested resources" do
|
|
|
|
post =
|
|
|
|
Post
|
|
|
|
|> Ash.Changeset.new(%{text: "post"})
|
|
|
|
|> Api.create!()
|
|
|
|
|
|
|
|
comment =
|
|
|
|
Comment
|
|
|
|
|> Ash.Changeset.new(%{text: "comment"})
|
2022-09-21 17:24:52 +12:00
|
|
|
|> Ash.Changeset.manage_relationship(:post, post, type: :append_and_remove)
|
2021-08-05 16:45:09 +12:00
|
|
|
|> Api.create!()
|
|
|
|
|
|
|
|
# Check the persisted post.comments count after create
|
|
|
|
post = Post |> Api.get!(post.id) |> Api.load!(:comments)
|
|
|
|
assert Enum.count(post.comments) == 1
|
|
|
|
|
|
|
|
# Grab the persisted comment
|
|
|
|
comment = Comment |> Api.get!(comment.id) |> Api.load!(post: [:comments])
|
|
|
|
|
|
|
|
form =
|
|
|
|
comment
|
|
|
|
|> Form.for_update(:update,
|
|
|
|
as: "comment",
|
|
|
|
api: Api,
|
|
|
|
forms: [
|
|
|
|
post: [
|
|
|
|
data: & &1.post,
|
|
|
|
type: :single,
|
|
|
|
resource: Post,
|
|
|
|
update_action: :update,
|
|
|
|
create_action: :create,
|
|
|
|
forms: [
|
|
|
|
comments: [
|
|
|
|
data: & &1.comments,
|
|
|
|
type: :list,
|
|
|
|
resource: Comment,
|
|
|
|
update_action: :update,
|
|
|
|
create_action: :create
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
)
|
|
|
|
|
2021-08-05 18:07:36 +12:00
|
|
|
updated_comment =
|
2021-08-05 16:45:09 +12:00
|
|
|
form
|
2021-08-05 18:07:36 +12:00
|
|
|
|> AshPhoenix.Form.submit!(
|
2021-08-05 16:45:09 +12:00
|
|
|
params: %{
|
|
|
|
"post" => %{
|
|
|
|
"id" => post.id,
|
|
|
|
"text" => "text",
|
|
|
|
"comments" => %{
|
|
|
|
"0" => %{
|
|
|
|
"id" => comment.id,
|
|
|
|
"text" => comment.text
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert Enum.count(updated_comment.post.comments) == 1
|
|
|
|
|
|
|
|
# now, check the persisted post
|
|
|
|
persisted_post = Post |> Api.get!(post.id) |> Api.load!(:comments)
|
|
|
|
assert Enum.count(persisted_post.comments) == 1
|
|
|
|
end
|
|
|
|
end
|
2021-07-16 06:09:15 +12:00
|
|
|
end
|