After 'mix phx.gen.live Items Item items name:string description:string info:string amount:integer factor:float type:string'
This commit is contained in:
147
lib/generic_rest_server/items.ex
Normal file
147
lib/generic_rest_server/items.ex
Normal file
@ -0,0 +1,147 @@
|
||||
defmodule GenericRestServer.Items do
|
||||
@moduledoc """
|
||||
The Items context.
|
||||
"""
|
||||
|
||||
import Ecto.Query, warn: false
|
||||
alias GenericRestServer.Repo
|
||||
|
||||
alias GenericRestServer.Items.Item
|
||||
alias GenericRestServer.Accounts.Scope
|
||||
|
||||
@doc """
|
||||
Subscribes to scoped notifications about any item changes.
|
||||
|
||||
The broadcasted messages match the pattern:
|
||||
|
||||
* {:created, %Item{}}
|
||||
* {:updated, %Item{}}
|
||||
* {:deleted, %Item{}}
|
||||
|
||||
"""
|
||||
def subscribe_items(%Scope{} = scope) do
|
||||
key = scope.user.id
|
||||
|
||||
Phoenix.PubSub.subscribe(GenericRestServer.PubSub, "user:#{key}:items")
|
||||
end
|
||||
|
||||
defp broadcast_item(%Scope{} = scope, message) do
|
||||
key = scope.user.id
|
||||
|
||||
Phoenix.PubSub.broadcast(GenericRestServer.PubSub, "user:#{key}:items", message)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns the list of items.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> list_items(scope)
|
||||
[%Item{}, ...]
|
||||
|
||||
"""
|
||||
def list_items(%Scope{} = scope) do
|
||||
Repo.all_by(Item, user_id: scope.user.id)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a single item.
|
||||
|
||||
Raises `Ecto.NoResultsError` if the Item does not exist.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> get_item!(scope, 123)
|
||||
%Item{}
|
||||
|
||||
iex> get_item!(scope, 456)
|
||||
** (Ecto.NoResultsError)
|
||||
|
||||
"""
|
||||
def get_item!(%Scope{} = scope, id) do
|
||||
Repo.get_by!(Item, id: id, user_id: scope.user.id)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Creates a item.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> create_item(scope, %{field: value})
|
||||
{:ok, %Item{}}
|
||||
|
||||
iex> create_item(scope, %{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def create_item(%Scope{} = scope, attrs) do
|
||||
with {:ok, item = %Item{}} <-
|
||||
%Item{}
|
||||
|> Item.changeset(attrs, scope)
|
||||
|> Repo.insert() do
|
||||
broadcast_item(scope, {:created, item})
|
||||
{:ok, item}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Updates a item.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> update_item(scope, item, %{field: new_value})
|
||||
{:ok, %Item{}}
|
||||
|
||||
iex> update_item(scope, item, %{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def update_item(%Scope{} = scope, %Item{} = item, attrs) do
|
||||
true = item.user_id == scope.user.id
|
||||
|
||||
with {:ok, item = %Item{}} <-
|
||||
item
|
||||
|> Item.changeset(attrs, scope)
|
||||
|> Repo.update() do
|
||||
broadcast_item(scope, {:updated, item})
|
||||
{:ok, item}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Deletes a item.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> delete_item(scope, item)
|
||||
{:ok, %Item{}}
|
||||
|
||||
iex> delete_item(scope, item)
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def delete_item(%Scope{} = scope, %Item{} = item) do
|
||||
true = item.user_id == scope.user.id
|
||||
|
||||
with {:ok, item = %Item{}} <-
|
||||
Repo.delete(item) do
|
||||
broadcast_item(scope, {:deleted, item})
|
||||
{:ok, item}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns an `%Ecto.Changeset{}` for tracking item changes.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> change_item(scope, item)
|
||||
%Ecto.Changeset{data: %Item{}}
|
||||
|
||||
"""
|
||||
def change_item(%Scope{} = scope, %Item{} = item, attrs \\ %{}) do
|
||||
true = item.user_id == scope.user.id
|
||||
|
||||
Item.changeset(item, attrs, scope)
|
||||
end
|
||||
end
|
||||
26
lib/generic_rest_server/items/item.ex
Normal file
26
lib/generic_rest_server/items/item.ex
Normal file
@ -0,0 +1,26 @@
|
||||
defmodule GenericRestServer.Items.Item do
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
|
||||
@primary_key {:id, :binary_id, autogenerate: true}
|
||||
@foreign_key_type :binary_id
|
||||
schema "items" do
|
||||
field :name, :string
|
||||
field :description, :string
|
||||
field :info, :string
|
||||
field :amount, :integer
|
||||
field :factor, :float
|
||||
field :type, :string
|
||||
field :user_id, :binary_id
|
||||
|
||||
timestamps(type: :utc_datetime)
|
||||
end
|
||||
|
||||
@doc false
|
||||
def changeset(item, attrs, user_scope) do
|
||||
item
|
||||
|> cast(attrs, [:name, :description, :info, :amount, :factor, :type])
|
||||
|> validate_required([:name, :description, :info, :amount, :factor, :type])
|
||||
|> put_change(:user_id, user_scope.user.id)
|
||||
end
|
||||
end
|
||||
103
lib/generic_rest_server_web/live/item_live/form.ex
Normal file
103
lib/generic_rest_server_web/live/item_live/form.ex
Normal file
@ -0,0 +1,103 @@
|
||||
defmodule GenericRestServerWeb.ItemLive.Form do
|
||||
use GenericRestServerWeb, :live_view
|
||||
|
||||
alias GenericRestServer.Items
|
||||
alias GenericRestServer.Items.Item
|
||||
|
||||
@impl true
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<Layouts.app flash={@flash} current_scope={@current_scope}>
|
||||
<.header>
|
||||
{@page_title}
|
||||
<:subtitle>Use this form to manage item records in your database.</:subtitle>
|
||||
</.header>
|
||||
|
||||
<.form for={@form} id="item-form" phx-change="validate" phx-submit="save">
|
||||
<.input field={@form[:name]} type="text" label="Name" />
|
||||
<.input field={@form[:description]} type="text" label="Description" />
|
||||
<.input field={@form[:info]} type="text" label="Info" />
|
||||
<.input field={@form[:amount]} type="number" label="Amount" />
|
||||
<.input field={@form[:factor]} type="number" label="Factor" step="any" />
|
||||
<.input field={@form[:type]} type="text" label="Type" />
|
||||
<footer>
|
||||
<.button phx-disable-with="Saving..." variant="primary">Save Item</.button>
|
||||
<.button navigate={return_path(@current_scope, @return_to, @item)}>Cancel</.button>
|
||||
</footer>
|
||||
</.form>
|
||||
</Layouts.app>
|
||||
"""
|
||||
end
|
||||
|
||||
@impl true
|
||||
def mount(params, _session, socket) do
|
||||
{:ok,
|
||||
socket
|
||||
|> assign(:return_to, return_to(params["return_to"]))
|
||||
|> apply_action(socket.assigns.live_action, params)}
|
||||
end
|
||||
|
||||
defp return_to("show"), do: "show"
|
||||
defp return_to(_), do: "index"
|
||||
|
||||
defp apply_action(socket, :edit, %{"id" => id}) do
|
||||
item = Items.get_item!(socket.assigns.current_scope, id)
|
||||
|
||||
socket
|
||||
|> assign(:page_title, "Edit Item")
|
||||
|> assign(:item, item)
|
||||
|> assign(:form, to_form(Items.change_item(socket.assigns.current_scope, item)))
|
||||
end
|
||||
|
||||
defp apply_action(socket, :new, _params) do
|
||||
item = %Item{user_id: socket.assigns.current_scope.user.id}
|
||||
|
||||
socket
|
||||
|> assign(:page_title, "New Item")
|
||||
|> assign(:item, item)
|
||||
|> assign(:form, to_form(Items.change_item(socket.assigns.current_scope, item)))
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("validate", %{"item" => item_params}, socket) do
|
||||
changeset = Items.change_item(socket.assigns.current_scope, socket.assigns.item, item_params)
|
||||
{:noreply, assign(socket, form: to_form(changeset, action: :validate))}
|
||||
end
|
||||
|
||||
def handle_event("save", %{"item" => item_params}, socket) do
|
||||
save_item(socket, socket.assigns.live_action, item_params)
|
||||
end
|
||||
|
||||
defp save_item(socket, :edit, item_params) do
|
||||
case Items.update_item(socket.assigns.current_scope, socket.assigns.item, item_params) do
|
||||
{:ok, item} ->
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:info, "Item updated successfully")
|
||||
|> push_navigate(
|
||||
to: return_path(socket.assigns.current_scope, socket.assigns.return_to, item)
|
||||
)}
|
||||
|
||||
{:error, %Ecto.Changeset{} = changeset} ->
|
||||
{:noreply, assign(socket, form: to_form(changeset))}
|
||||
end
|
||||
end
|
||||
|
||||
defp save_item(socket, :new, item_params) do
|
||||
case Items.create_item(socket.assigns.current_scope, item_params) do
|
||||
{:ok, item} ->
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:info, "Item created successfully")
|
||||
|> push_navigate(
|
||||
to: return_path(socket.assigns.current_scope, socket.assigns.return_to, item)
|
||||
)}
|
||||
|
||||
{:error, %Ecto.Changeset{} = changeset} ->
|
||||
{:noreply, assign(socket, form: to_form(changeset))}
|
||||
end
|
||||
end
|
||||
|
||||
defp return_path(_scope, "index", _item), do: ~p"/items"
|
||||
defp return_path(_scope, "show", item), do: ~p"/items/#{item}"
|
||||
end
|
||||
78
lib/generic_rest_server_web/live/item_live/index.ex
Normal file
78
lib/generic_rest_server_web/live/item_live/index.ex
Normal file
@ -0,0 +1,78 @@
|
||||
defmodule GenericRestServerWeb.ItemLive.Index do
|
||||
use GenericRestServerWeb, :live_view
|
||||
|
||||
alias GenericRestServer.Items
|
||||
|
||||
@impl true
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<Layouts.app flash={@flash} current_scope={@current_scope}>
|
||||
<.header>
|
||||
Listing Items
|
||||
<:actions>
|
||||
<.button variant="primary" navigate={~p"/items/new"}>
|
||||
<.icon name="hero-plus" /> New Item
|
||||
</.button>
|
||||
</:actions>
|
||||
</.header>
|
||||
|
||||
<.table
|
||||
id="items"
|
||||
rows={@streams.items}
|
||||
row_click={fn {_id, item} -> JS.navigate(~p"/items/#{item}") end}
|
||||
>
|
||||
<:col :let={{_id, item}} label="Name">{item.name}</:col>
|
||||
<:col :let={{_id, item}} label="Description">{item.description}</:col>
|
||||
<:col :let={{_id, item}} label="Info">{item.info}</:col>
|
||||
<:col :let={{_id, item}} label="Amount">{item.amount}</:col>
|
||||
<:col :let={{_id, item}} label="Factor">{item.factor}</:col>
|
||||
<:col :let={{_id, item}} label="Type">{item.type}</:col>
|
||||
<:action :let={{_id, item}}>
|
||||
<div class="sr-only">
|
||||
<.link navigate={~p"/items/#{item}"}>Show</.link>
|
||||
</div>
|
||||
<.link navigate={~p"/items/#{item}/edit"}>Edit</.link>
|
||||
</:action>
|
||||
<:action :let={{id, item}}>
|
||||
<.link
|
||||
phx-click={JS.push("delete", value: %{id: item.id}) |> hide("##{id}")}
|
||||
data-confirm="Are you sure?"
|
||||
>
|
||||
Delete
|
||||
</.link>
|
||||
</:action>
|
||||
</.table>
|
||||
</Layouts.app>
|
||||
"""
|
||||
end
|
||||
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
if connected?(socket) do
|
||||
Items.subscribe_items(socket.assigns.current_scope)
|
||||
end
|
||||
|
||||
{:ok,
|
||||
socket
|
||||
|> assign(:page_title, "Listing Items")
|
||||
|> stream(:items, list_items(socket.assigns.current_scope))}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("delete", %{"id" => id}, socket) do
|
||||
item = Items.get_item!(socket.assigns.current_scope, id)
|
||||
{:ok, _} = Items.delete_item(socket.assigns.current_scope, item)
|
||||
|
||||
{:noreply, stream_delete(socket, :items, item)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info({type, %GenericRestServer.Items.Item{}}, socket)
|
||||
when type in [:created, :updated, :deleted] do
|
||||
{:noreply, stream(socket, :items, list_items(socket.assigns.current_scope), reset: true)}
|
||||
end
|
||||
|
||||
defp list_items(current_scope) do
|
||||
Items.list_items(current_scope)
|
||||
end
|
||||
end
|
||||
69
lib/generic_rest_server_web/live/item_live/show.ex
Normal file
69
lib/generic_rest_server_web/live/item_live/show.ex
Normal file
@ -0,0 +1,69 @@
|
||||
defmodule GenericRestServerWeb.ItemLive.Show do
|
||||
use GenericRestServerWeb, :live_view
|
||||
|
||||
alias GenericRestServer.Items
|
||||
|
||||
@impl true
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<Layouts.app flash={@flash} current_scope={@current_scope}>
|
||||
<.header>
|
||||
Item {@item.id}
|
||||
<:subtitle>This is a item record from your database.</:subtitle>
|
||||
<:actions>
|
||||
<.button navigate={~p"/items"}>
|
||||
<.icon name="hero-arrow-left" />
|
||||
</.button>
|
||||
<.button variant="primary" navigate={~p"/items/#{@item}/edit?return_to=show"}>
|
||||
<.icon name="hero-pencil-square" /> Edit item
|
||||
</.button>
|
||||
</:actions>
|
||||
</.header>
|
||||
|
||||
<.list>
|
||||
<:item title="Name">{@item.name}</:item>
|
||||
<:item title="Description">{@item.description}</:item>
|
||||
<:item title="Info">{@item.info}</:item>
|
||||
<:item title="Amount">{@item.amount}</:item>
|
||||
<:item title="Factor">{@item.factor}</:item>
|
||||
<:item title="Type">{@item.type}</:item>
|
||||
</.list>
|
||||
</Layouts.app>
|
||||
"""
|
||||
end
|
||||
|
||||
@impl true
|
||||
def mount(%{"id" => id}, _session, socket) do
|
||||
if connected?(socket) do
|
||||
Items.subscribe_items(socket.assigns.current_scope)
|
||||
end
|
||||
|
||||
{:ok,
|
||||
socket
|
||||
|> assign(:page_title, "Show Item")
|
||||
|> assign(:item, Items.get_item!(socket.assigns.current_scope, id))}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info(
|
||||
{:updated, %GenericRestServer.Items.Item{id: id} = item},
|
||||
%{assigns: %{item: %{id: id}}} = socket
|
||||
) do
|
||||
{:noreply, assign(socket, :item, item)}
|
||||
end
|
||||
|
||||
def handle_info(
|
||||
{:deleted, %GenericRestServer.Items.Item{id: id}},
|
||||
%{assigns: %{item: %{id: id}}} = socket
|
||||
) do
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:error, "The current item was deleted.")
|
||||
|> push_navigate(to: ~p"/items")}
|
||||
end
|
||||
|
||||
def handle_info({type, %GenericRestServer.Items.Item{}}, socket)
|
||||
when type in [:created, :updated, :deleted] do
|
||||
{:noreply, socket}
|
||||
end
|
||||
end
|
||||
@ -54,6 +54,11 @@ defmodule GenericRestServerWeb.Router do
|
||||
on_mount: [{GenericRestServerWeb.UserAuth, :require_authenticated}] do
|
||||
live "/users/settings", UserLive.Settings, :edit
|
||||
live "/users/settings/confirm-email/:token", UserLive.Settings, :confirm_email
|
||||
|
||||
live "/items", ItemLive.Index, :index
|
||||
live "/items/new", ItemLive.Form, :new
|
||||
live "/items/:id", ItemLive.Show, :show
|
||||
live "/items/:id/edit", ItemLive.Form, :edit
|
||||
end
|
||||
|
||||
post "/users/update-password", UserSessionController, :update_password
|
||||
|
||||
20
priv/repo/migrations/20260421112128_create_items.exs
Normal file
20
priv/repo/migrations/20260421112128_create_items.exs
Normal file
@ -0,0 +1,20 @@
|
||||
defmodule GenericRestServer.Repo.Migrations.CreateItems do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
create table(:items, primary_key: false) do
|
||||
add :id, :binary_id, primary_key: true
|
||||
add :name, :string
|
||||
add :description, :string
|
||||
add :info, :string
|
||||
add :amount, :integer
|
||||
add :factor, :float
|
||||
add :type, :string
|
||||
add :user_id, references(:users, type: :binary_id, on_delete: :delete_all)
|
||||
|
||||
timestamps(type: :utc_datetime)
|
||||
end
|
||||
|
||||
create index(:items, [:user_id])
|
||||
end
|
||||
end
|
||||
101
test/generic_rest_server/items_test.exs
Normal file
101
test/generic_rest_server/items_test.exs
Normal file
@ -0,0 +1,101 @@
|
||||
defmodule GenericRestServer.ItemsTest do
|
||||
use GenericRestServer.DataCase
|
||||
|
||||
alias GenericRestServer.Items
|
||||
|
||||
describe "items" do
|
||||
alias GenericRestServer.Items.Item
|
||||
|
||||
import GenericRestServer.AccountsFixtures, only: [user_scope_fixture: 0]
|
||||
import GenericRestServer.ItemsFixtures
|
||||
|
||||
@invalid_attrs %{info: nil, name: nil, type: nil, description: nil, amount: nil, factor: nil}
|
||||
|
||||
test "list_items/1 returns all scoped items" do
|
||||
scope = user_scope_fixture()
|
||||
other_scope = user_scope_fixture()
|
||||
item = item_fixture(scope)
|
||||
other_item = item_fixture(other_scope)
|
||||
assert Items.list_items(scope) == [item]
|
||||
assert Items.list_items(other_scope) == [other_item]
|
||||
end
|
||||
|
||||
test "get_item!/2 returns the item with given id" do
|
||||
scope = user_scope_fixture()
|
||||
item = item_fixture(scope)
|
||||
other_scope = user_scope_fixture()
|
||||
assert Items.get_item!(scope, item.id) == item
|
||||
assert_raise Ecto.NoResultsError, fn -> Items.get_item!(other_scope, item.id) end
|
||||
end
|
||||
|
||||
test "create_item/2 with valid data creates a item" do
|
||||
valid_attrs = %{info: "some info", name: "some name", type: "some type", description: "some description", amount: 42, factor: 120.5}
|
||||
scope = user_scope_fixture()
|
||||
|
||||
assert {:ok, %Item{} = item} = Items.create_item(scope, valid_attrs)
|
||||
assert item.info == "some info"
|
||||
assert item.name == "some name"
|
||||
assert item.type == "some type"
|
||||
assert item.description == "some description"
|
||||
assert item.amount == 42
|
||||
assert item.factor == 120.5
|
||||
assert item.user_id == scope.user.id
|
||||
end
|
||||
|
||||
test "create_item/2 with invalid data returns error changeset" do
|
||||
scope = user_scope_fixture()
|
||||
assert {:error, %Ecto.Changeset{}} = Items.create_item(scope, @invalid_attrs)
|
||||
end
|
||||
|
||||
test "update_item/3 with valid data updates the item" do
|
||||
scope = user_scope_fixture()
|
||||
item = item_fixture(scope)
|
||||
update_attrs = %{info: "some updated info", name: "some updated name", type: "some updated type", description: "some updated description", amount: 43, factor: 456.7}
|
||||
|
||||
assert {:ok, %Item{} = item} = Items.update_item(scope, item, update_attrs)
|
||||
assert item.info == "some updated info"
|
||||
assert item.name == "some updated name"
|
||||
assert item.type == "some updated type"
|
||||
assert item.description == "some updated description"
|
||||
assert item.amount == 43
|
||||
assert item.factor == 456.7
|
||||
end
|
||||
|
||||
test "update_item/3 with invalid scope raises" do
|
||||
scope = user_scope_fixture()
|
||||
other_scope = user_scope_fixture()
|
||||
item = item_fixture(scope)
|
||||
|
||||
assert_raise MatchError, fn ->
|
||||
Items.update_item(other_scope, item, %{})
|
||||
end
|
||||
end
|
||||
|
||||
test "update_item/3 with invalid data returns error changeset" do
|
||||
scope = user_scope_fixture()
|
||||
item = item_fixture(scope)
|
||||
assert {:error, %Ecto.Changeset{}} = Items.update_item(scope, item, @invalid_attrs)
|
||||
assert item == Items.get_item!(scope, item.id)
|
||||
end
|
||||
|
||||
test "delete_item/2 deletes the item" do
|
||||
scope = user_scope_fixture()
|
||||
item = item_fixture(scope)
|
||||
assert {:ok, %Item{}} = Items.delete_item(scope, item)
|
||||
assert_raise Ecto.NoResultsError, fn -> Items.get_item!(scope, item.id) end
|
||||
end
|
||||
|
||||
test "delete_item/2 with invalid scope raises" do
|
||||
scope = user_scope_fixture()
|
||||
other_scope = user_scope_fixture()
|
||||
item = item_fixture(scope)
|
||||
assert_raise MatchError, fn -> Items.delete_item(other_scope, item) end
|
||||
end
|
||||
|
||||
test "change_item/2 returns a item changeset" do
|
||||
scope = user_scope_fixture()
|
||||
item = item_fixture(scope)
|
||||
assert %Ecto.Changeset{} = Items.change_item(scope, item)
|
||||
end
|
||||
end
|
||||
end
|
||||
125
test/generic_rest_server_web/live/item_live_test.exs
Normal file
125
test/generic_rest_server_web/live/item_live_test.exs
Normal file
@ -0,0 +1,125 @@
|
||||
defmodule GenericRestServerWeb.ItemLiveTest do
|
||||
use GenericRestServerWeb.ConnCase
|
||||
|
||||
import Phoenix.LiveViewTest
|
||||
import GenericRestServer.ItemsFixtures
|
||||
|
||||
@create_attrs %{info: "some info", name: "some name", type: "some type", description: "some description", amount: 42, factor: 120.5}
|
||||
@update_attrs %{info: "some updated info", name: "some updated name", type: "some updated type", description: "some updated description", amount: 43, factor: 456.7}
|
||||
@invalid_attrs %{info: nil, name: nil, type: nil, description: nil, amount: nil, factor: nil}
|
||||
|
||||
setup :register_and_log_in_user
|
||||
|
||||
defp create_item(%{scope: scope}) do
|
||||
item = item_fixture(scope)
|
||||
|
||||
%{item: item}
|
||||
end
|
||||
|
||||
describe "Index" do
|
||||
setup [:create_item]
|
||||
|
||||
test "lists all items", %{conn: conn, item: item} do
|
||||
{:ok, _index_live, html} = live(conn, ~p"/items")
|
||||
|
||||
assert html =~ "Listing Items"
|
||||
assert html =~ item.name
|
||||
end
|
||||
|
||||
test "saves new item", %{conn: conn} do
|
||||
{:ok, index_live, _html} = live(conn, ~p"/items")
|
||||
|
||||
assert {:ok, form_live, _} =
|
||||
index_live
|
||||
|> element("a", "New Item")
|
||||
|> render_click()
|
||||
|> follow_redirect(conn, ~p"/items/new")
|
||||
|
||||
assert render(form_live) =~ "New Item"
|
||||
|
||||
assert form_live
|
||||
|> form("#item-form", item: @invalid_attrs)
|
||||
|> render_change() =~ "can't be blank"
|
||||
|
||||
assert {:ok, index_live, _html} =
|
||||
form_live
|
||||
|> form("#item-form", item: @create_attrs)
|
||||
|> render_submit()
|
||||
|> follow_redirect(conn, ~p"/items")
|
||||
|
||||
html = render(index_live)
|
||||
assert html =~ "Item created successfully"
|
||||
assert html =~ "some name"
|
||||
end
|
||||
|
||||
test "updates item in listing", %{conn: conn, item: item} do
|
||||
{:ok, index_live, _html} = live(conn, ~p"/items")
|
||||
|
||||
assert {:ok, form_live, _html} =
|
||||
index_live
|
||||
|> element("#items-#{item.id} a", "Edit")
|
||||
|> render_click()
|
||||
|> follow_redirect(conn, ~p"/items/#{item}/edit")
|
||||
|
||||
assert render(form_live) =~ "Edit Item"
|
||||
|
||||
assert form_live
|
||||
|> form("#item-form", item: @invalid_attrs)
|
||||
|> render_change() =~ "can't be blank"
|
||||
|
||||
assert {:ok, index_live, _html} =
|
||||
form_live
|
||||
|> form("#item-form", item: @update_attrs)
|
||||
|> render_submit()
|
||||
|> follow_redirect(conn, ~p"/items")
|
||||
|
||||
html = render(index_live)
|
||||
assert html =~ "Item updated successfully"
|
||||
assert html =~ "some updated name"
|
||||
end
|
||||
|
||||
test "deletes item in listing", %{conn: conn, item: item} do
|
||||
{:ok, index_live, _html} = live(conn, ~p"/items")
|
||||
|
||||
assert index_live |> element("#items-#{item.id} a", "Delete") |> render_click()
|
||||
refute has_element?(index_live, "#items-#{item.id}")
|
||||
end
|
||||
end
|
||||
|
||||
describe "Show" do
|
||||
setup [:create_item]
|
||||
|
||||
test "displays item", %{conn: conn, item: item} do
|
||||
{:ok, _show_live, html} = live(conn, ~p"/items/#{item}")
|
||||
|
||||
assert html =~ "Show Item"
|
||||
assert html =~ item.name
|
||||
end
|
||||
|
||||
test "updates item and returns to show", %{conn: conn, item: item} do
|
||||
{:ok, show_live, _html} = live(conn, ~p"/items/#{item}")
|
||||
|
||||
assert {:ok, form_live, _} =
|
||||
show_live
|
||||
|> element("a", "Edit")
|
||||
|> render_click()
|
||||
|> follow_redirect(conn, ~p"/items/#{item}/edit?return_to=show")
|
||||
|
||||
assert render(form_live) =~ "Edit Item"
|
||||
|
||||
assert form_live
|
||||
|> form("#item-form", item: @invalid_attrs)
|
||||
|> render_change() =~ "can't be blank"
|
||||
|
||||
assert {:ok, show_live, _html} =
|
||||
form_live
|
||||
|> form("#item-form", item: @update_attrs)
|
||||
|> render_submit()
|
||||
|> follow_redirect(conn, ~p"/items/#{item}")
|
||||
|
||||
html = render(show_live)
|
||||
assert html =~ "Item updated successfully"
|
||||
assert html =~ "some updated name"
|
||||
end
|
||||
end
|
||||
end
|
||||
24
test/support/fixtures/items_fixtures.ex
Normal file
24
test/support/fixtures/items_fixtures.ex
Normal file
@ -0,0 +1,24 @@
|
||||
defmodule GenericRestServer.ItemsFixtures do
|
||||
@moduledoc """
|
||||
This module defines test helpers for creating
|
||||
entities via the `GenericRestServer.Items` context.
|
||||
"""
|
||||
|
||||
@doc """
|
||||
Generate a item.
|
||||
"""
|
||||
def item_fixture(scope, attrs \\ %{}) do
|
||||
attrs =
|
||||
Enum.into(attrs, %{
|
||||
amount: 42,
|
||||
description: "some description",
|
||||
factor: 120.5,
|
||||
info: "some info",
|
||||
name: "some name",
|
||||
type: "some type"
|
||||
})
|
||||
|
||||
{:ok, item} = GenericRestServer.Items.create_item(scope, attrs)
|
||||
item
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user