From dfaa328af4bcd946f4997d11d060e7abe3ebdd5e Mon Sep 17 00:00:00 2001 From: Silas Date: Thu, 19 Aug 2021 22:35:12 -0400 Subject: [PATCH] get started on route for creating links, dividing steps into components --- .gitignore | 2 + Dockerfile | 19 +++ config/dev.exs | 22 +++- deployment.yaml | 75 ++++++++++++ lib/entendu/application.ex | 26 +++- lib/entendu/links.ex | 104 ++++++++++++++++ lib/entendu/links/link.ex | 18 +++ lib/entendu/user_from_auth.ex | 0 lib/entendu_web.ex | 1 + lib/entendu_web/live/link_live/for.ex | 13 ++ lib/entendu_web/live/link_live/for.html.leex | 4 + lib/entendu_web/live/link_live/index.ex | 46 ++++++++ .../live/link_live/index.html.leex | 37 ++++++ .../live/link_live/steps/step1_component.ex | 4 + .../link_live/steps/step1_component.html.leex | 3 + lib/entendu_web/live/live_helpers.ex | 23 ++++ lib/entendu_web/live/modal_component.ex | 26 ++++ lib/entendu_web/live/page_live.html.leex | 32 +---- lib/entendu_web/router.ex | 1 + mix.exs | 4 +- mix.lock | 2 + .../20210819214328_create_links.exs | 15 +++ test/entendu/links_test.exs | 66 +++++++++++ test/entendu_web/live/link_live_test.exs | 111 ++++++++++++++++++ 24 files changed, 618 insertions(+), 36 deletions(-) create mode 100644 Dockerfile create mode 100644 deployment.yaml create mode 100644 lib/entendu/links.ex create mode 100644 lib/entendu/links/link.ex create mode 100644 lib/entendu/user_from_auth.ex create mode 100644 lib/entendu_web/live/link_live/for.ex create mode 100644 lib/entendu_web/live/link_live/for.html.leex create mode 100644 lib/entendu_web/live/link_live/index.ex create mode 100644 lib/entendu_web/live/link_live/index.html.leex create mode 100644 lib/entendu_web/live/link_live/steps/step1_component.ex create mode 100644 lib/entendu_web/live/link_live/steps/step1_component.html.leex create mode 100644 lib/entendu_web/live/live_helpers.ex create mode 100644 lib/entendu_web/live/modal_component.ex create mode 100644 priv/repo/migrations/20210819214328_create_links.exs create mode 100644 test/entendu/links_test.exs create mode 100644 test/entendu_web/live/link_live_test.exs diff --git a/.gitignore b/.gitignore index af67fbc..d186e5b 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,5 @@ npm-debug.log # we ignore priv/static. You may want to comment # this depending on your deployment strategy. /priv/static/ + +dev.secret.exs \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..4ed395e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,19 @@ +FROM elixir:1.12.2-alpine + +WORKDIR /app + +ADD . /app + +EXPOSE 4000 +ENV PORT 4000 +ENV MIX_ENV dev + + +RUN mix local.hex --force && \ + mix local.rebar --force && \ + mix do deps.get, deps.compile && \ + mix do compile, phx.digest + + + +CMD ["mix", "phx.server"] \ No newline at end of file diff --git a/config/dev.exs b/config/dev.exs index 16e171d..32f7656 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -5,7 +5,7 @@ config :entendu, Entendu.Repo, username: "postgres", password: "postgres", database: "entendu_dev", - hostname: "localhost", + hostname: System.get_env("POSTGRES_HOST", "localhost"), show_sensitive_data_on_connection_error: true, pool_size: 10 @@ -16,7 +16,7 @@ config :entendu, Entendu.Repo, # watchers to your application. For example, we use it # with webpack to recompile .js and .css sources. config :entendu, EntenduWeb.Endpoint, - http: [port: 4000], + http: [port: System.get_env("PORT", "4000")], debug_errors: true, code_reloader: true, check_origin: false, @@ -74,3 +74,21 @@ config :phoenix, :stacktrace_depth, 20 # Initialize plugs at runtime for faster development compilation config :phoenix, :plug_init_mode, :runtime + +config :entendu, :enable_k8s, false + +# config :libcluster, +# topologies: [ +# k8s_example: [ +# strategy: Cluster.Strategy.Kubernetes, +# config: [ +# # For Elixir Releases, use System.get_env instead of the distillery env vars below. +# kubernetes_selector: System.get_env("LIBCLUSTER_KUBERNETES_SELECTOR"), +# kubernetes_node_basename: System.get_env("LIBCLUSTER_KUBERNETES_NODE_BASENAME") +# ] +# ] +# ] + +if File.exists?("config/dev.secret.exs") do + import_config "dev.secret.exs" +end diff --git a/deployment.yaml b/deployment.yaml new file mode 100644 index 0000000..2084715 --- /dev/null +++ b/deployment.yaml @@ -0,0 +1,75 @@ +--- +kind: Deployment +apiVersion: apps/v1 +metadata: + name: entendu + namespace: default +spec: + replicas: 4 + selector: + matchLabels: + app: entendu + + template: + metadata: + labels: + app: entendu + spec: + containers: + - name: phoenix-entendu + image: entendu:1.1.1 #alvises/phoenix-chat-example:libcluster-kube + ports: + - containerPort: 4000 + env: + - name: PORT + value: "4000" + - name: PHOENIX_ENTENDU_HOST + value: "localhost" + - name: ERLANG_COOKIE + value: "secret" + - name: MY_POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + # command: ["entendu"] + # args: [ + # "start" + # ] + command: ["elixir"] + args: [ + "--name", + "entendu@$(MY_POD_IP)", + "--cookie","$(ERLANG_COOKIE)", + "--no-halt", + "-S","mix", + "phx.server" + ] +--- +kind: Service +apiVersion: v1 + +metadata: + name: entendu-nodes + namespace: default +spec: + clusterIP: None + selector: + app: entendu + ports: + - name: epmd + port: 4369 +--- +kind: Service +apiVersion: v1 + +metadata: + name: entendu + namespace: default +spec: + type: LoadBalancer + selector: + app: entendu + ports: + - name: http + port: 8000 + targetPort: 4000 diff --git a/lib/entendu/application.ex b/lib/entendu/application.ex index 9b6f6ed..6236043 100644 --- a/lib/entendu/application.ex +++ b/lib/entendu/application.ex @@ -6,7 +6,29 @@ defmodule Entendu.Application do use Application def start(_type, _args) do - children = [ + # topologies = [ + # chat: [ + # strategy: Cluster.Strategy.Gossip + # ] + # ] + + topologies = [ + k8s_entendu: [ + strategy: Elixir.Cluster.Strategy.Kubernetes.DNS, + config: [ + service: "entendu-nodes", + application_name: "entendu" + ] + ] + ] + + children = case Application.get_env(:frayt_elixir, :enable_k8s) do + true -> [ + {Cluster.Supervisor, [topologies, [name: Entendu.ClusterSupervisor]]} + ] + _ -> [] + end + |> Kernel.++([ # Start the Ecto repository Entendu.Repo, # Start the Telemetry supervisor @@ -17,7 +39,7 @@ defmodule Entendu.Application do EntenduWeb.Endpoint # Start a worker by calling: Entendu.Worker.start_link(arg) # {Entendu.Worker, arg} - ] + ]) # See https://hexdocs.pm/elixir/Supervisor.html # for other strategies and supported options diff --git a/lib/entendu/links.ex b/lib/entendu/links.ex new file mode 100644 index 0000000..01fa9c0 --- /dev/null +++ b/lib/entendu/links.ex @@ -0,0 +1,104 @@ +defmodule Entendu.Links do + @moduledoc """ + The Links context. + """ + + import Ecto.Query, warn: false + alias Entendu.Repo + + alias Entendu.Links.Link + + @doc """ + Returns the list of links. + + ## Examples + + iex> list_links() + [%Link{}, ...] + + """ + def list_links do + Repo.all(Link) + end + + @doc """ + Gets a single link. + + Raises `Ecto.NoResultsError` if the Link does not exist. + + ## Examples + + iex> get_link!(123) + %Link{} + + iex> get_link!(456) + ** (Ecto.NoResultsError) + + """ + def get_link!(id), do: Repo.get!(Link, id) + + @doc """ + Creates a link. + + ## Examples + + iex> create_link(%{field: value}) + {:ok, %Link{}} + + iex> create_link(%{field: bad_value}) + {:error, %Ecto.Changeset{}} + + """ + def create_link(attrs \\ %{}) do + %Link{} + |> Link.changeset(attrs) + |> Repo.insert() + end + + @doc """ + Updates a link. + + ## Examples + + iex> update_link(link, %{field: new_value}) + {:ok, %Link{}} + + iex> update_link(link, %{field: bad_value}) + {:error, %Ecto.Changeset{}} + + """ + def update_link(%Link{} = link, attrs) do + link + |> Link.changeset(attrs) + |> Repo.update() + end + + @doc """ + Deletes a link. + + ## Examples + + iex> delete_link(link) + {:ok, %Link{}} + + iex> delete_link(link) + {:error, %Ecto.Changeset{}} + + """ + def delete_link(%Link{} = link) do + Repo.delete(link) + end + + @doc """ + Returns an `%Ecto.Changeset{}` for tracking link changes. + + ## Examples + + iex> change_link(link) + %Ecto.Changeset{data: %Link{}} + + """ + def change_link(%Link{} = link, attrs \\ %{}) do + Link.changeset(link, attrs) + end +end diff --git a/lib/entendu/links/link.ex b/lib/entendu/links/link.ex new file mode 100644 index 0000000..7eabc18 --- /dev/null +++ b/lib/entendu/links/link.ex @@ -0,0 +1,18 @@ +defmodule Entendu.Links.Link do + use Ecto.Schema + import Ecto.Changeset + + schema "links" do + field :burn_after_reading, :boolean, default: false + field :expires, :utc_datetime + + timestamps() + end + + @doc false + def changeset(link, attrs) do + link + |> cast(attrs, [:expires, :burn_after_reading]) + |> validate_required([:expires, :burn_after_reading]) + end +end diff --git a/lib/entendu/user_from_auth.ex b/lib/entendu/user_from_auth.ex new file mode 100644 index 0000000..e69de29 diff --git a/lib/entendu_web.ex b/lib/entendu_web.ex index 820ca43..be16f45 100644 --- a/lib/entendu_web.ex +++ b/lib/entendu_web.ex @@ -83,6 +83,7 @@ defmodule EntenduWeb do # Import LiveView helpers (live_render, live_component, live_patch, etc) import Phoenix.LiveView.Helpers + import EntenduWeb.LiveHelpers # Import basic rendering functionality (render, render_layout, etc) import Phoenix.View diff --git a/lib/entendu_web/live/link_live/for.ex b/lib/entendu_web/live/link_live/for.ex new file mode 100644 index 0000000..8ab29b3 --- /dev/null +++ b/lib/entendu_web/live/link_live/for.ex @@ -0,0 +1,13 @@ +defmodule EntenduWeb.LinkLive.For do + use EntenduWeb, :live_view + + @impl true + def mount(_params, _session, socket) do + {:ok, socket |> assign(:step, 1)} + end + + def handle_event("next_step", _, %{ assigns: %{ step: step } } = socket) do + socket = socket |> assign(:step, step + 1) + {:noreply, socket} + end +end diff --git a/lib/entendu_web/live/link_live/for.html.leex b/lib/entendu_web/live/link_live/for.html.leex new file mode 100644 index 0000000..41c7e79 --- /dev/null +++ b/lib/entendu_web/live/link_live/for.html.leex @@ -0,0 +1,4 @@ +

Create Link

+ +<%= live_component @socket, EntenduWeb.LinkLive.For.Step1Component, id: "step1", test: "test" %> +On Step: <%= @step %> diff --git a/lib/entendu_web/live/link_live/index.ex b/lib/entendu_web/live/link_live/index.ex new file mode 100644 index 0000000..62df978 --- /dev/null +++ b/lib/entendu_web/live/link_live/index.ex @@ -0,0 +1,46 @@ +defmodule EntenduWeb.LinkLive.Index do + use EntenduWeb, :live_view + + alias Entendu.Links + alias Entendu.Links.Link + + @impl true + def mount(_params, _session, socket) do + {:ok, assign(socket, :links, list_links())} + end + + @impl true + def handle_params(params, _url, socket) do + {:noreply, apply_action(socket, socket.assigns.live_action, params)} + end + + defp apply_action(socket, :edit, %{"id" => id}) do + socket + |> assign(:page_title, "Edit Link") + |> assign(:link, Links.get_link!(id)) + end + + defp apply_action(socket, :new, _params) do + socket + |> assign(:page_title, "New Link") + |> assign(:link, %Link{}) + end + + defp apply_action(socket, :index, _params) do + socket + |> assign(:page_title, "Listing Links") + |> assign(:link, nil) + end + + @impl true + def handle_event("delete", %{"id" => id}, socket) do + link = Links.get_link!(id) + {:ok, _} = Links.delete_link(link) + + {:noreply, assign(socket, :links, list_links())} + end + + defp list_links do + Links.list_links() + end +end diff --git a/lib/entendu_web/live/link_live/index.html.leex b/lib/entendu_web/live/link_live/index.html.leex new file mode 100644 index 0000000..39a842f --- /dev/null +++ b/lib/entendu_web/live/link_live/index.html.leex @@ -0,0 +1,37 @@ +

Listing Links

+ +<%= if @live_action in [:new, :edit] do %> + <%= live_modal @socket, EntenduWeb.LinkLive.FormComponent, + id: @link.id || :new, + title: @page_title, + action: @live_action, + link: @link, + return_to: Routes.link_index_path(@socket, :index) %> +<% end %> + + + + + + + + + + + + <%= for link <- @links do %> + + + + + + + <% end %> + +
ExpiresBurn after reading
+ +<%= live_patch "New Link", to: Routes.link_index_path(@socket, :new) %> diff --git a/lib/entendu_web/live/link_live/steps/step1_component.ex b/lib/entendu_web/live/link_live/steps/step1_component.ex new file mode 100644 index 0000000..8bd000f --- /dev/null +++ b/lib/entendu_web/live/link_live/steps/step1_component.ex @@ -0,0 +1,4 @@ +defmodule EntenduWeb.LinkLive.For.Step1Component do + use EntenduWeb, :live_component + +end diff --git a/lib/entendu_web/live/link_live/steps/step1_component.html.leex b/lib/entendu_web/live/link_live/steps/step1_component.html.leex new file mode 100644 index 0000000..36dc1be --- /dev/null +++ b/lib/entendu_web/live/link_live/steps/step1_component.html.leex @@ -0,0 +1,3 @@ +This is step 1. <%= @test %> + + diff --git a/lib/entendu_web/live/live_helpers.ex b/lib/entendu_web/live/live_helpers.ex new file mode 100644 index 0000000..ff5df47 --- /dev/null +++ b/lib/entendu_web/live/live_helpers.ex @@ -0,0 +1,23 @@ +defmodule EntenduWeb.LiveHelpers do + import Phoenix.LiveView.Helpers + + @doc """ + Renders a component inside the `EntenduWeb.ModalComponent` component. + + The rendered modal receives a `:return_to` option to properly update + the URL when the modal is closed. + + ## Examples + + <%= live_modal @socket, EntenduWeb.LinkLive.FormComponent, + id: @link.id || :new, + action: @live_action, + link: @link, + return_to: Routes.link_index_path(@socket, :index) %> + """ + def live_modal(socket, component, opts) do + path = Keyword.fetch!(opts, :return_to) + modal_opts = [id: :modal, return_to: path, component: component, opts: opts] + live_component(socket, EntenduWeb.ModalComponent, modal_opts) + end +end diff --git a/lib/entendu_web/live/modal_component.ex b/lib/entendu_web/live/modal_component.ex new file mode 100644 index 0000000..e122fe0 --- /dev/null +++ b/lib/entendu_web/live/modal_component.ex @@ -0,0 +1,26 @@ +defmodule EntenduWeb.ModalComponent do + use EntenduWeb, :live_component + + @impl true + def render(assigns) do + ~L""" +
+ +
+ <%= live_patch raw("×"), to: @return_to, class: "phx-modal-close" %> + <%= live_component @socket, @component, @opts %> +
+
+ """ + end + + @impl true + def handle_event("close", _, socket) do + {:noreply, push_patch(socket, to: socket.assigns.return_to)} + end +end diff --git a/lib/entendu_web/live/page_live.html.leex b/lib/entendu_web/live/page_live.html.leex index 52509c2..ee59e54 100644 --- a/lib/entendu_web/live/page_live.html.leex +++ b/lib/entendu_web/live/page_live.html.leex @@ -14,35 +14,5 @@
- - + Links
diff --git a/lib/entendu_web/router.ex b/lib/entendu_web/router.ex index 6fd80e5..8855bcd 100644 --- a/lib/entendu_web/router.ex +++ b/lib/entendu_web/router.ex @@ -18,6 +18,7 @@ defmodule EntenduWeb.Router do pipe_through :browser live "/", PageLive, :index + live "/for", LinkLive.For end # Other scopes may use custom stacks. diff --git a/mix.exs b/mix.exs index 05888f8..5696c69 100644 --- a/mix.exs +++ b/mix.exs @@ -46,7 +46,9 @@ defmodule Entendu.MixProject do {:telemetry_poller, "~> 0.4"}, {:gettext, "~> 0.11"}, {:jason, "~> 1.0"}, - {:plug_cowboy, "~> 2.0"} + {:plug_cowboy, "~> 2.0"}, + {:libcluster, "~> 3.2"}, + {:ueberauth, "~> 0.6.3"} ] end diff --git a/mix.lock b/mix.lock index c9daee7..ed168fb 100644 --- a/mix.lock +++ b/mix.lock @@ -12,6 +12,7 @@ "gettext": {:hex, :gettext, "0.18.2", "7df3ea191bb56c0309c00a783334b288d08a879f53a7014341284635850a6e55", [:mix], [], "hexpm", "f9f537b13d4fdd30f3039d33cb80144c3aa1f8d9698e47d7bcbcc8df93b1f5c5"}, "html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"}, "jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"}, + "libcluster": {:hex, :libcluster, "3.3.0", "f7d45ff56d88e9fb4c30aee662480cbab69ebc0e7f7da4ad8d01b1e4f7492da8", [:mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "ecdcdc88334ec8eb18b10a13a1d5f22a3319a970b5b1e66cfe71c7719a4ab6cc"}, "mime": {:hex, :mime, "2.0.1", "0de4c81303fe07806ebc2494d5321ce8fb4df106e34dd5f9d787b637ebadc256", [:mix], [], "hexpm", "7a86b920d2aedce5fb6280ac8261ac1a739ae6c1a1ad38f5eadf910063008942"}, "phoenix": {:hex, :phoenix, "1.5.10", "3ee7d5c17ff9626d72d374d8fc8909bf00f4323fd15549fbe3abbbd38b5299c8", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f9c2eaa5a8fe5a412610c6aa84ccdb6f3e92f333d4df7fbaeb0d5a157dbfb48d"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.3.0", "2c69a452c2e0ee8c93345ae1cdc1696ef4877ff9cbb15c305def41960c3c4ebf", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "0ac491924217550c8f42c81c1f390b5d81517d12ceaf9abf3e701156760a848e"}, @@ -28,4 +29,5 @@ "telemetry": {:hex, :telemetry, "0.4.3", "a06428a514bdbc63293cd9a6263aad00ddeb66f608163bdec7c8995784080818", [:rebar3], [], "hexpm", "eb72b8365ffda5bed68a620d1da88525e326cb82a75ee61354fc24b844768041"}, "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"}, "telemetry_poller": {:hex, :telemetry_poller, "0.5.1", "21071cc2e536810bac5628b935521ff3e28f0303e770951158c73eaaa01e962a", [:rebar3], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4cab72069210bc6e7a080cec9afffad1b33370149ed5d379b81c7c5f0c663fd4"}, + "ueberauth": {:hex, :ueberauth, "0.6.3", "d42ace28b870e8072cf30e32e385579c57b9cc96ec74fa1f30f30da9c14f3cc0", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "afc293d8a1140d6591b53e3eaf415ca92842cb1d32fad3c450c6f045f7f91b60"}, } diff --git a/priv/repo/migrations/20210819214328_create_links.exs b/priv/repo/migrations/20210819214328_create_links.exs new file mode 100644 index 0000000..eff42b5 --- /dev/null +++ b/priv/repo/migrations/20210819214328_create_links.exs @@ -0,0 +1,15 @@ +defmodule Entendu.Repo.Migrations.CreateLinks do + use Ecto.Migration + + def change do + create table(:links, primary_key: false) do + add :id, :binary_id, primary_key: true + add :expires, :utc_datetime + add :burn_after_reading, :boolean, default: false, null: false + add :content, :text + + timestamps() + end + + end +end diff --git a/test/entendu/links_test.exs b/test/entendu/links_test.exs new file mode 100644 index 0000000..2d52a86 --- /dev/null +++ b/test/entendu/links_test.exs @@ -0,0 +1,66 @@ +defmodule Entendu.LinksTest do + use Entendu.DataCase + + alias Entendu.Links + + describe "links" do + alias Entendu.Links.Link + + @valid_attrs %{burn_after_reading: true, expires: "2010-04-17T14:00:00Z"} + @update_attrs %{burn_after_reading: false, expires: "2011-05-18T15:01:01Z"} + @invalid_attrs %{burn_after_reading: nil, expires: nil} + + def link_fixture(attrs \\ %{}) do + {:ok, link} = + attrs + |> Enum.into(@valid_attrs) + |> Links.create_link() + + link + end + + test "list_links/0 returns all links" do + link = link_fixture() + assert Links.list_links() == [link] + end + + test "get_link!/1 returns the link with given id" do + link = link_fixture() + assert Links.get_link!(link.id) == link + end + + test "create_link/1 with valid data creates a link" do + assert {:ok, %Link{} = link} = Links.create_link(@valid_attrs) + assert link.burn_after_reading == true + assert link.expires == DateTime.from_naive!(~N[2010-04-17T14:00:00Z], "Etc/UTC") + end + + test "create_link/1 with invalid data returns error changeset" do + assert {:error, %Ecto.Changeset{}} = Links.create_link(@invalid_attrs) + end + + test "update_link/2 with valid data updates the link" do + link = link_fixture() + assert {:ok, %Link{} = link} = Links.update_link(link, @update_attrs) + assert link.burn_after_reading == false + assert link.expires == DateTime.from_naive!(~N[2011-05-18T15:01:01Z], "Etc/UTC") + end + + test "update_link/2 with invalid data returns error changeset" do + link = link_fixture() + assert {:error, %Ecto.Changeset{}} = Links.update_link(link, @invalid_attrs) + assert link == Links.get_link!(link.id) + end + + test "delete_link/1 deletes the link" do + link = link_fixture() + assert {:ok, %Link{}} = Links.delete_link(link) + assert_raise Ecto.NoResultsError, fn -> Links.get_link!(link.id) end + end + + test "change_link/1 returns a link changeset" do + link = link_fixture() + assert %Ecto.Changeset{} = Links.change_link(link) + end + end +end diff --git a/test/entendu_web/live/link_live_test.exs b/test/entendu_web/live/link_live_test.exs new file mode 100644 index 0000000..98fd9ca --- /dev/null +++ b/test/entendu_web/live/link_live_test.exs @@ -0,0 +1,111 @@ +defmodule EntenduWeb.LinkLiveTest do + use EntenduWeb.ConnCase + + import Phoenix.LiveViewTest + + alias Entendu.Links + + @create_attrs %{burn_after_reading: true, expires: "2010-04-17T14:00:00Z"} + @update_attrs %{burn_after_reading: false, expires: "2011-05-18T15:01:01Z"} + @invalid_attrs %{burn_after_reading: nil, expires: nil} + + defp fixture(:link) do + {:ok, link} = Links.create_link(@create_attrs) + link + end + + defp create_link(_) do + link = fixture(:link) + %{link: link} + end + + describe "Index" do + setup [:create_link] + + test "lists all links", %{conn: conn, link: link} do + {:ok, _index_live, html} = live(conn, Routes.link_index_path(conn, :index)) + + assert html =~ "Listing Links" + end + + test "saves new link", %{conn: conn} do + {:ok, index_live, _html} = live(conn, Routes.link_index_path(conn, :index)) + + assert index_live |> element("a", "New Link") |> render_click() =~ + "New Link" + + assert_patch(index_live, Routes.link_index_path(conn, :new)) + + assert index_live + |> form("#link-form", link: @invalid_attrs) + |> render_change() =~ "can't be blank" + + {:ok, _, html} = + index_live + |> form("#link-form", link: @create_attrs) + |> render_submit() + |> follow_redirect(conn, Routes.link_index_path(conn, :index)) + + assert html =~ "Link created successfully" + end + + test "updates link in listing", %{conn: conn, link: link} do + {:ok, index_live, _html} = live(conn, Routes.link_index_path(conn, :index)) + + assert index_live |> element("#link-#{link.id} a", "Edit") |> render_click() =~ + "Edit Link" + + assert_patch(index_live, Routes.link_index_path(conn, :edit, link)) + + assert index_live + |> form("#link-form", link: @invalid_attrs) + |> render_change() =~ "can't be blank" + + {:ok, _, html} = + index_live + |> form("#link-form", link: @update_attrs) + |> render_submit() + |> follow_redirect(conn, Routes.link_index_path(conn, :index)) + + assert html =~ "Link updated successfully" + end + + test "deletes link in listing", %{conn: conn, link: link} do + {:ok, index_live, _html} = live(conn, Routes.link_index_path(conn, :index)) + + assert index_live |> element("#link-#{link.id} a", "Delete") |> render_click() + refute has_element?(index_live, "#link-#{link.id}") + end + end + + describe "Show" do + setup [:create_link] + + test "displays link", %{conn: conn, link: link} do + {:ok, _show_live, html} = live(conn, Routes.link_show_path(conn, :show, link)) + + assert html =~ "Show Link" + end + + test "updates link within modal", %{conn: conn, link: link} do + {:ok, show_live, _html} = live(conn, Routes.link_show_path(conn, :show, link)) + + assert show_live |> element("a", "Edit") |> render_click() =~ + "Edit Link" + + assert_patch(show_live, Routes.link_show_path(conn, :edit, link)) + + assert show_live + |> form("#link-form", link: @invalid_attrs) + |> render_change() =~ "can't be blank" + + {:ok, _, html} = + show_live + |> form("#link-form", link: @update_attrs) + |> render_submit() + |> follow_redirect(conn, Routes.link_show_path(conn, :show, link)) + + assert html =~ "Link updated successfully" + end + end +end