diff --git a/lib/tilex/posts.ex b/lib/tilex/posts.ex
index e1b80a17..e55e1479 100644
--- a/lib/tilex/posts.ex
+++ b/lib/tilex/posts.ex
@@ -44,6 +44,10 @@ defmodule Tilex.Posts do
end
end
+ def delete_post(post) do
+ Repo.delete(post)
+ end
+
def published(query \\ Post) do
from(p in query, where: not is_nil(p.published_at) and p.published_at <= fragment("now()"))
end
diff --git a/lib/tilex_web/controllers/post_controller.ex b/lib/tilex_web/controllers/post_controller.ex
index cfac74fb..8fd1d099 100644
--- a/lib/tilex_web/controllers/post_controller.ex
+++ b/lib/tilex_web/controllers/post_controller.ex
@@ -11,12 +11,12 @@ defmodule TilexWeb.PostController do
alias Tilex.Posts
plug(:load_channels when action in [:new, :create, :edit, :update])
- plug(:extract_slug when action in [:show, :edit, :update])
+ plug(:extract_slug when action in [:show, :edit, :update, :delete])
plug(
Guardian.Plug.EnsureAuthenticated,
[error_handler: __MODULE__]
- when action in ~w(new create edit update)a
+ when action in ~w(new create edit update delete)a
)
@behaviour Guardian.Plug.ErrorHandler
@@ -196,6 +196,30 @@ defmodule TilexWeb.PostController do
end
end
+ def delete(conn, _params) do
+ current_user = Guardian.Plug.current_resource(conn)
+
+ post =
+ case current_user.admin do
+ false -> assoc(current_user, :posts)
+ true -> Post
+ end
+ |> Repo.get_by!(slug: conn.assigns.slug)
+ |> Repo.preload([:developer])
+
+ case Posts.delete_post(post) do
+ {:ok, _post} ->
+ conn
+ |> put_flash(:info, "Post deleted successfully")
+ |> redirect(to: Routes.developer_path(conn, :show, post.developer))
+
+ {:error, _changeset} ->
+ conn
+ |> put_flash(:error, "Failed to delete post")
+ |> redirect(to: Routes.post_path(conn, :show, post))
+ end
+ end
+
defp load_channels(conn, _) do
query =
Channel
diff --git a/lib/tilex_web/templates/shared/post.html.eex b/lib/tilex_web/templates/shared/post.html.eex
index 0b058cfc..6d1f4c94 100644
--- a/lib/tilex_web/templates/shared/post.html.eex
+++ b/lib/tilex_web/templates/shared/post.html.eex
@@ -45,6 +45,9 @@
<%= link("edit", to: Routes.post_path(@conn, :edit, @post), class: "post__permalink") %>
+
+ <%= link("delete", to: Routes.post_path(@conn, :delete, @post), method: :delete, class: "post__delete-link", data: [confirm: "Are you sure you want to delete this post?"]) %>
+
<% end %>
<%= link to: "#", class: "js-like-action post__like-link", id: @post.slug do %>
diff --git a/mix.exs b/mix.exs
index 52333114..fd681b7f 100644
--- a/mix.exs
+++ b/mix.exs
@@ -67,7 +67,7 @@ defmodule Tilex.Mixfile do
{:tzdata, "~> 1.1.0"},
{:ueberauth_google, "~> 0.5"},
{:usage_rules, "~> 0.1", only: [:dev]},
- {:wallaby, "~>0.30.1", [runtime: false, only: :test]}
+ {:wallaby, "~>0.30.1", runtime: false, only: :test}
]
end
diff --git a/mix.lock b/mix.lock
index 3fc31787..58a90315 100644
--- a/mix.lock
+++ b/mix.lock
@@ -14,12 +14,12 @@
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
"cowlib": {:hex, :cowlib, "2.16.0", "54592074ebbbb92ee4746c8a8846e5605052f29309d3a873468d76cdf932076f", [:make, :rebar3], [], "hexpm", "7f478d80d66b747344f0ea7708c187645cfcc08b11aa424632f78e25bf05db51"},
"credo": {:hex, :credo, "1.7.13", "126a0697df6b7b71cd18c81bc92335297839a806b6f62b61d417500d1070ff4e", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "47641e6d2bbff1e241e87695b29f617f1a8f912adea34296fb10ecc3d7e9e84f"},
- "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"},
+ "db_connection": {:hex, :db_connection, "2.8.1", "9abdc1e68c34c6163f6fb96a96532272d13ad7ca45262156ae8b7ec6d9dc4bec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a61a3d489b239d76f326e03b98794fb8e45168396c925ef25feb405ed09da8fd"},
"decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"},
"decorator": {:hex, :decorator, "1.4.0", "a57ac32c823ea7e4e67f5af56412d12b33274661bb7640ec7fc882f8d23ac419", [:mix], [], "hexpm", "0a07cedd9083da875c7418dea95b78361197cf2bf3211d743f6f7ce39656597f"},
"earmark": {:hex, :earmark, "1.4.48", "5f41e579d85ef812351211842b6e005f6e0cef111216dea7d4b9d58af4608434", [:mix], [], "hexpm", "a461a0ddfdc5432381c876af1c86c411fd78a25790c75023c7a4c035fdc858f9"},
"ecto": {:hex, :ecto, "3.13.4", "27834b45d58075d4a414833d9581e8b7bb18a8d9f264a21e42f653d500dbeeb5", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5ad7d1505685dfa7aaf86b133d54f5ad6c42df0b4553741a1ff48796736e88b2"},
- "ecto_sql": {:hex, :ecto_sql, "3.12.0", "73cea17edfa54bde76ee8561b30d29ea08f630959685006d9c6e7d1e59113b7d", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dc9e4d206f274f3947e96142a8fdc5f69a2a6a9abb4649ef5c882323b6d512f0"},
+ "ecto_sql": {:hex, :ecto_sql, "3.13.2", "a07d2461d84107b3d037097c822ffdd36ed69d1cf7c0f70e12a3d1decf04e2e1", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.13.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "539274ab0ecf1a0078a6a72ef3465629e4d6018a3028095dc90f60a19c371717"},
"esbuild": {:hex, :esbuild, "0.8.1", "0cbf919f0eccb136d2eeef0df49c4acf55336de864e63594adcea3814f3edf41", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "25fc876a67c13cb0a776e7b5d7974851556baeda2085296c14ab48555ea7560f"},
"eternal": {:hex, :eternal, "1.2.2", "d1641c86368de99375b98d183042dd6c2b234262b8d08dfd72b9eeaafc2a1abd", [:mix], [], "hexpm", "2c9fe32b9c3726703ba5e1d43a1d255a4f3f2d8f8f9bc19f094c7cb1a7a9e782"},
"expo": {:hex, :expo, "1.1.0", "f7b9ed7fb5745ebe1eeedf3d6f29226c5dd52897ac67c0f8af62a07e661e5c75", [:mix], [], "hexpm", "fbadf93f4700fb44c331362177bdca9eeb8097e8b0ef525c9cc501cb9917c960"},
@@ -32,7 +32,7 @@
"hackney": {:hex, :hackney, "1.25.0", "390e9b83f31e5b325b9f43b76e1a785cbdb69b5b6cd4e079aa67835ded046867", [:rebar3], [{:certifi, "~> 2.15.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.4", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "7209bfd75fd1f42467211ff8f59ea74d6f2a9e81cbcee95a56711ee79fd6b1d4"},
"hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"},
"html_sanitize_ex": {:hex, :html_sanitize_ex, "1.4.3", "67b3d9fa8691b727317e0cc96b9b3093be00ee45419ffb221cdeee88e75d1360", [:mix], [{:mochiweb, "~> 2.15 or ~> 3.1", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm", "87748d3c4afe949c7c6eb7150c958c2bcba43fc5b2a02686af30e636b74bccb7"},
- "httpoison": {:hex, :httpoison, "2.2.1", "87b7ed6d95db0389f7df02779644171d7319d319178f6680438167d7b69b1f3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "51364e6d2f429d80e14fe4b5f8e39719cacd03eb3f9a9286e61e216feac2d2df"},
+ "httpoison": {:hex, :httpoison, "2.2.3", "a599d4b34004cc60678999445da53b5e653630651d4da3d14675fedc9dd34bd6", [:mix], [{:hackney, "~> 1.21", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "fa0f2e3646d3762fdc73edb532104c8619c7636a6997d20af4003da6cfc53e53"},
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"igniter": {:hex, :igniter, "0.6.30", "83a466369ebb8fe009e0823c7bf04314dc545122c2d48f896172fc79df33e99d", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:owl, "~> 0.11", [hex: :owl, repo: "hexpm", optional: false]}, {:phx_new, "~> 1.7", [hex: :phx_new, repo: "hexpm", optional: true]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, ">= 1.1.1 and < 2.0.0-0", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "76a14d5b7f850bb03b5243088c3649d54a2e52e34a2aa1104dee23cf50a8bae0"},
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
@@ -52,7 +52,7 @@
"parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
"peri": {:hex, :peri, "0.6.0", "0758aa037f862f7a3aa0823cb82195916f61a8071f6eaabcff02103558e61a70", [:mix], [{:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:stream_data, "~> 1.1", [hex: :stream_data, repo: "hexpm", optional: true]}], "hexpm", "b27f118f3317fbc357c4a04b3f3c98561efdd8865edd4ec0e24fd936c7ff36c8"},
"phoenix": {:hex, :phoenix, "1.6.16", "e5bdd18c7a06da5852a25c7befb72246de4ddc289182285f8685a40b7b5f5451", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e15989ff34f670a96b95ef6d1d25bad0d9c50df5df40b671d8f4a669e050ac39"},
- "phoenix_ecto": {:hex, :phoenix_ecto, "4.6.2", "3b83b24ab5a2eb071a20372f740d7118767c272db386831b2e77638c4dcc606d", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "3f94d025f59de86be00f5f8c5dd7b5965a3298458d21ab1c328488be3b5fcd59"},
+ "phoenix_ecto": {:hex, :phoenix_ecto, "4.6.5", "c4ef322acd15a574a8b1a08eff0ee0a85e73096b53ce1403b6563709f15e1cea", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "26ec3208eef407f31b748cadd044045c6fd485fbff168e35963d2f9dfff28d4b"},
"phoenix_html": {:hex, :phoenix_html, "3.3.4", "42a09fc443bbc1da37e372a5c8e6755d046f22b9b11343bf885067357da21cb3", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0249d3abec3714aff3415e7ee3d9786cb325be3151e6c4b3021502c585bf53fb"},
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.4", "4508e481f791ce62ec6a096e13b061387158cbeefacca68c6c1928e1305e23ed", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "2984aae96994fbc5c61795a73b8fb58153b41ff934019cfb522343d2d3817d59"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.6.1", "05df733a09887a005ed0d69a7fc619d376aea2730bf64ce52ac51ce716cc1ef0", [:mix], [{:file_system, "~> 0.2.10 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "74273843d5a6e4fef0bbc17599f33e3ec63f08e69215623a0cd91eea4288e5a0"},
@@ -63,7 +63,7 @@
"plug": {:hex, :plug, "1.18.1", "5067f26f7745b7e31bc3368bc1a2b818b9779faa959b49c934c17730efc911cf", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "57a57db70df2b422b564437d2d33cf8d33cd16339c1edb190cd11b1a3a546cc2"},
"plug_cowboy": {:hex, :plug_cowboy, "2.7.4", "729c752d17cf364e2b8da5bdb34fb5804f56251e88bb602aff48ae0bd8673d11", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "9b85632bd7012615bae0a5d70084deb1b25d2bcbb32cab82d1e9a1e023168aa3"},
"plug_crypto": {:hex, :plug_crypto, "1.2.5", "918772575e48e81e455818229bf719d4ab4181fcbf7f85b68a35620f78d89ced", [:mix], [], "hexpm", "26549a1d6345e2172eb1c233866756ae44a9609bd33ee6f99147ab3fd87fd842"},
- "postgrex": {:hex, :postgrex, "0.19.1", "73b498508b69aded53907fe48a1fee811be34cc720e69ef4ccd568c8715495ea", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "8bac7885a18f381e091ec6caf41bda7bb8c77912bb0e9285212829afe5d8a8f8"},
+ "postgrex": {:hex, :postgrex, "0.21.1", "2c5cc830ec11e7a0067dd4d623c049b3ef807e9507a424985b8dcf921224cd88", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "27d8d21c103c3cc68851b533ff99eef353e6a0ff98dc444ea751de43eb48bdac"},
"ranch": {:hex, :ranch, "2.2.0", "25528f82bc8d7c6152c57666ca99ec716510fe0925cb188172f41ce93117b1b0", [:make, :rebar3], [], "hexpm", "fa0b99a1780c80218a4197a59ea8d3bdae32fbff7e88527d7d8a4787eff4f8e7"},
"req": {:hex, :req, "0.5.15", "662020efb6ea60b9f0e0fac9be88cd7558b53fe51155a2d9899de594f9906ba9", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "a6513a35fad65467893ced9785457e91693352c70b58bbc045b47e5eb2ef0c53"},
"rewrite": {:hex, :rewrite, "1.2.0", "80220eb14010e175b67c939397e1a8cdaa2c32db6e2e0a9d5e23e45c0414ce21", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}, {:text_diff, "~> 0.1", [hex: :text_diff, repo: "hexpm", optional: false]}], "hexpm", "a1cd702bbb9d51613ab21091f04a386d750fc6f4516b81900df082d78b2d8c50"},
@@ -75,7 +75,7 @@
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.2", "2caabe9344ec17eafe5403304771c3539f3b6e2f7fb6a6f602558c825d0d0bfb", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9b43db0dc33863930b9ef9d27137e78974756f5f198cae18409970ed6fa5b561"},
"telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"},
- "tesla": {:hex, :tesla, "1.12.1", "fe2bf4250868ee72e5d8b8dfa408d13a00747c41b7237b6aa3b9a24057346681", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, ">= 1.0.0", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.2", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "2391efc6243d37ead43afd0327b520314c7b38232091d4a440c1212626fdd6e7"},
+ "tesla": {:hex, :tesla, "1.15.3", "3a2b5c37f09629b8dcf5d028fbafc9143c0099753559d7fe567eaabfbd9b8663", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, ">= 1.0.0", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.21", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.2", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:mox, "~> 1.0", [hex: :mox, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "98bb3d4558abc67b92fb7be4cd31bb57ca8d80792de26870d362974b58caeda7"},
"text_diff": {:hex, :text_diff, "0.1.0", "1caf3175e11a53a9a139bc9339bd607c47b9e376b073d4571c031913317fecaa", [:mix], [], "hexpm", "d1ffaaecab338e49357b6daa82e435f877e0649041ace7755583a0ea3362dbd7"},
"tidewave": {:hex, :tidewave, "0.5.0", "8f278d7eb2d0af36ae6d4f73a5872bd066815bd57b57401125187ba901f095a4", [:mix], [{:circular_buffer, "~> 0.4 or ~> 1.0", [hex: :circular_buffer, repo: "hexpm", optional: false]}, {:igniter, "~> 0.6", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix_live_reload, ">= 1.6.1", [hex: :phoenix_live_reload, repo: "hexpm", optional: true]}, {:plug, "~> 1.17", [hex: :plug, repo: "hexpm", optional: false]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "9a1eb5d2f12ff4912328dfbfe652c27fded462c6ed6fd11814ee28d3e9d016b4"},
"timex": {:hex, :timex, "3.7.11", "bb95cb4eb1d06e27346325de506bcc6c30f9c6dea40d1ebe390b262fad1862d1", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.20", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "8b9024f7efbabaf9bd7aa04f65cf8dcd7c9818ca5737677c7b76acbc6a94d1aa"},
@@ -85,6 +85,6 @@
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.1", "a48703a25c170eedadca83b11e88985af08d35f37c6f664d6dcfb106a97782fc", [:rebar3], [], "hexpm", "b3a917854ce3ae233619744ad1e0102e05673136776fb2fa76234f3e03b23642"},
"unsafe": {:hex, :unsafe, "1.0.2", "23c6be12f6c1605364801f4b47007c0c159497d0446ad378b5cf05f1855c0581", [:mix], [], "hexpm", "b485231683c3ab01a9cd44cb4a79f152c6f3bb87358439c6f68791b85c2df675"},
"usage_rules": {:hex, :usage_rules, "0.1.25", "bad5b2cbd45da053423051a752f35ae5249e33ec90c83d0f1ac1be3d90ad9bde", [:mix], [{:igniter, ">= 0.6.6 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}], "hexpm", "406598fa133a424d0a8b2d21eb86b8c6e345626d822d7247cdb408a5c3dbe66a"},
- "wallaby": {:hex, :wallaby, "0.30.9", "51d60682092c3c428c63b656b818e2258202b9f9a31ec37230659647ae20325b", [:mix], [{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}, {:httpoison, "~> 0.12 or ~> 1.0 or ~> 2.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix_ecto, ">= 3.0.0", [hex: :phoenix_ecto, repo: "hexpm", optional: true]}, {:web_driver_client, "~> 0.2.0", [hex: :web_driver_client, repo: "hexpm", optional: false]}], "hexpm", "62e3ccb89068b231b50ed046219022020516d44f443eebef93a19db4be95b808"},
+ "wallaby": {:hex, :wallaby, "0.30.11", "93b635bb3d01b11b5a80f83a5d9be59e87ccc8c8390136b7c526dd4fc7e485e3", [:mix], [{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}, {:httpoison, "~> 0.12 or ~> 1.0 or ~> 2.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix_ecto, ">= 3.0.0", [hex: :phoenix_ecto, repo: "hexpm", optional: true]}, {:web_driver_client, "~> 0.2.0", [hex: :web_driver_client, repo: "hexpm", optional: false]}], "hexpm", "407b50972e3827ce77e3b8292c36dcbd6b21b6837cc4f12ee8767e92a72610ac"},
"web_driver_client": {:hex, :web_driver_client, "0.2.0", "63b76cd9eb3b0716ec5467a0f8bead73d3d9612e63f7560d21357f03ad86e31a", [:mix], [{:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:tesla, "~> 1.3", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "83cc6092bc3e74926d1c8455f0ce927d5d1d36707b74d9a65e38c084aab0350f"},
}
diff --git a/test/controllers/post_controller_test.exs b/test/controllers/post_controller_test.exs
index 13c9f465..afea16b0 100644
--- a/test/controllers/post_controller_test.exs
+++ b/test/controllers/post_controller_test.exs
@@ -1,7 +1,10 @@
defmodule Tilex.PostControllerTest do
use TilexWeb.ConnCase, async: true
- alias Tilex.Factory
+
alias Tilex.Auth
+ alias Tilex.Blog.Post
+ alias Tilex.Factory
+ alias Tilex.Repo
test "lists all entries on index", %{conn: conn} do
conn = get(conn, Routes.post_path(conn, :index))
@@ -55,7 +58,7 @@ defmodule Tilex.PostControllerTest do
post(conn, Routes.post_path(conn, :create, params))
til =
- Tilex.Blog.Post
+ Post
|> Tilex.Repo.all()
|> List.first()
@@ -79,7 +82,7 @@ defmodule Tilex.PostControllerTest do
post(conn, Routes.post_path(conn, :create, params))
til =
- Tilex.Blog.Post
+ Post
|> Tilex.Repo.all()
|> List.first()
@@ -102,7 +105,7 @@ defmodule Tilex.PostControllerTest do
post(conn, Routes.post_path(conn, :create, params))
til =
- Tilex.Blog.Post
+ Post
|> Tilex.Repo.all()
|> List.first()
@@ -133,7 +136,7 @@ defmodule Tilex.PostControllerTest do
put(conn, Routes.post_path(conn, :update, til.slug, params))
til =
- Tilex.Blog.Post
+ Post
|> Tilex.Repo.get(til.id)
assert til.title == "New Title"
@@ -162,7 +165,7 @@ defmodule Tilex.PostControllerTest do
put(conn, Routes.post_path(conn, :update, til.slug, params))
til =
- Tilex.Blog.Post
+ Post
|> Tilex.Repo.get(til.id)
assert til.title == "New Title"
@@ -190,18 +193,82 @@ defmodule Tilex.PostControllerTest do
put(conn, Routes.post_path(conn, :update, til.slug, params))
til =
- Tilex.Blog.Post
+ Post
|> Tilex.Repo.get(til.id)
assert til.title == "New Title"
assert til.max_likes == 1
end
+
+ test "author can delete their own post", %{
+ conn: conn,
+ current_user: current_user
+ } do
+ post = Factory.insert!(:post, developer: current_user)
+
+ conn = delete(conn, Routes.post_path(conn, :delete, post.slug))
+
+ assert redirected_to(conn) == Routes.developer_path(conn, :show, current_user)
+ assert get_flash(conn, :info) == "Post deleted successfully"
+ assert Repo.all(Post) == []
+ end
+
+ test "author cannot delete another developer's post", %{
+ conn: conn
+ } do
+ other_user = Factory.insert!(:developer, username: "other-dev")
+ post = Factory.insert!(:post, developer: other_user)
+ post_id = post.id
+
+ assert_raise Ecto.NoResultsError, fn ->
+ delete(conn, Routes.post_path(conn, :delete, post.slug))
+ end
+
+ assert [%Post{id: ^post_id}] = Repo.all(Post)
+ end
end
- defp authenticated_conn(%{conn: conn}) do
- current_user = Factory.insert!(:developer, email: "current@example.com", username: "current")
- channel = Factory.insert!(:channel, name: "git")
+ describe "when authenticated as admin" do
+ setup :authenticated_admin_conn
+ test "admin can delete any post", %{
+ conn: conn,
+ current_user: _admin
+ } do
+ other_user = Factory.insert!(:developer, username: "other-dev")
+ post = Factory.insert!(:post, developer: other_user)
+
+ conn = delete(conn, Routes.post_path(conn, :delete, post.slug))
+
+ assert redirected_to(conn) == Routes.developer_path(conn, :show, other_user)
+ assert get_flash(conn, :info) == "Post deleted successfully"
+ assert Repo.all(Post) == []
+ end
+ end
+
+ test "unauthenticated user cannot delete post", %{conn: conn} do
+ post = Factory.insert!(:post)
+ post_id = post.id
+
+ conn = delete(conn, Routes.post_path(conn, :delete, post.slug))
+
+ assert html_response(conn, 302)
+ assert get_flash(conn, :info) == "Authentication required"
+ assert [%Post{id: ^post_id}] = Repo.all(Post)
+ end
+
+ defp authenticated_conn(context) do
+ Factory.insert!(:developer, email: "current@example.com", username: "current")
+ |> do_authenticated_conn(context)
+ end
+
+ defp authenticated_admin_conn(context) do
+ Factory.insert!(:developer, email: "admin@example.com", username: "admin", admin: true)
+ |> do_authenticated_conn(context)
+ end
+
+ defp do_authenticated_conn(current_user, %{conn: conn}) do
+ channel = Factory.insert!(:channel, name: "git")
conn = Auth.Guardian.Plug.sign_in(conn, current_user)
{:ok, conn: conn, current_user: current_user, channel: channel}
end
diff --git a/test/features/admin_edits_post_test.exs b/test/features/admin_edits_post_test.exs
index 5cb359fc..0d70cdf1 100644
--- a/test/features/admin_edits_post_test.exs
+++ b/test/features/admin_edits_post_test.exs
@@ -1,10 +1,10 @@
defmodule AdminEditsPostTest do
- use Tilex.IntegrationCase, async: true
+ use Tilex.IntegrationCase, async: false
alias Tilex.Integration.Pages.PostForm
alias Tilex.Integration.Pages.PostShowPage
- test "fills out form and updates post from post show", %{session: session} do
+ feature "fills out form and updates post from post show", %{session: session} do
Factory.insert!(:channel, name: "phoenix")
developer = Factory.insert!(:developer, %{username: "luke-skywalker"})
admin = Factory.insert!(:developer, %{admin: true, username: "darth-vader"})
@@ -29,7 +29,7 @@ defmodule AdminEditsPostTest do
|> PostShowPage.ensure_page_loaded("Even Awesomer Post!")
end
- test "enters a title that is too long", %{session: session} do
+ feature "enters a title that is too long", %{session: session} do
Factory.insert!(:channel, name: "phoenix")
developer = Factory.insert!(:developer)
diff --git a/test/features/developer_creates_post_test.exs b/test/features/developer_creates_post_test.exs
index 3dda3b45..e7064a14 100644
--- a/test/features/developer_creates_post_test.exs
+++ b/test/features/developer_creates_post_test.exs
@@ -7,8 +7,7 @@ defmodule DeveloperCreatesPostTest do
alias Tilex.Integration.Pages.PostShowPage
alias Tilex.Integration.Pages.PostForm
- test "fills out form and save", %{session: session} do
- Ecto.Adapters.SQL.Sandbox.allow(Tilex.Repo, self(), Process.whereis(Tilex.Notifications))
+ feature "fills out form and save", %{session: session} do
Factory.insert!(:channel, name: "phoenix")
developer = Factory.insert!(:developer)
@@ -48,8 +47,7 @@ defmodule DeveloperCreatesPostTest do
|> Navigation.ensure_heading("TODAY I LEARNED")
end
- test "fills out form and save & publish", %{session: session} do
- Ecto.Adapters.SQL.Sandbox.allow(Tilex.Repo, self(), Process.whereis(Tilex.Notifications))
+ feature "fills out form and save & publish", %{session: session} do
Factory.insert!(:channel, name: "phoenix")
developer = Factory.insert!(:developer)
@@ -88,7 +86,7 @@ defmodule DeveloperCreatesPostTest do
|> Navigation.ensure_heading("TODAY I LEARNED")
end
- test "cancels submission", %{session: session} do
+ feature "cancels submission", %{session: session} do
developer = Factory.insert!(:developer)
session
@@ -99,7 +97,7 @@ defmodule DeveloperCreatesPostTest do
|> IndexPage.ensure_page_loaded()
end
- test "fails to enter things", %{session: session} do
+ feature "fails to enter things", %{session: session} do
developer = Factory.insert!(:developer)
session
@@ -113,7 +111,7 @@ defmodule DeveloperCreatesPostTest do
|> CreatePostPage.expect_form_has_error("Channel can't be blank")
end
- test "enters a title that is too long", %{session: session} do
+ feature "enters a title that is too long", %{session: session} do
Factory.insert!(:channel, name: "phoenix")
developer = Factory.insert!(:developer)
@@ -131,7 +129,7 @@ defmodule DeveloperCreatesPostTest do
|> CreatePostPage.expect_form_has_error("Title should be at most 50 character(s)")
end
- test "enters a body that is too long", %{session: session} do
+ feature "enters a body that is too long", %{session: session} do
Factory.insert!(:channel, name: "phoenix")
developer = Factory.insert!(:developer)
@@ -149,7 +147,7 @@ defmodule DeveloperCreatesPostTest do
|> CreatePostPage.expect_form_has_error("Body should be at most 200 word(s)")
end
- test "enters markdown code into the body", %{session: session} do
+ feature "enters markdown code into the body", %{session: session} do
Factory.insert!(:channel, name: "phoenix")
developer = Factory.insert!(:developer)
@@ -166,7 +164,7 @@ defmodule DeveloperCreatesPostTest do
assert find(session, Query.css("strong", text: "bold powerup"))
end
- test "views parsed markdown preview", %{session: session} do
+ feature "views parsed markdown preview", %{session: session} do
Factory.insert!(:channel, name: "phoenix")
developer = Factory.insert!(:developer)
diff --git a/test/features/developer_deletes_post_test.exs b/test/features/developer_deletes_post_test.exs
new file mode 100644
index 00000000..7ccfb1d2
--- /dev/null
+++ b/test/features/developer_deletes_post_test.exs
@@ -0,0 +1,47 @@
+defmodule DeveloperDeletesPostTest do
+ use Tilex.IntegrationCase, async: false
+
+ alias Tilex.Blog.Post
+ alias Tilex.Integration.Pages.PostShowPage
+ alias Tilex.Repo
+
+ feature "developer can delete their own post", %{session: session} do
+ developer = Factory.insert!(:developer)
+ post = Factory.insert!(:post, developer: developer)
+
+ session
+ |> sign_in(developer)
+ |> PostShowPage.navigate(post)
+ |> click_and_confirm(Query.link("delete"))
+ |> assert_flash(:info, "Post deleted successfully")
+ |> assert_path(developer_path(TilexWeb.Endpoint, :show, developer))
+
+ assert Repo.all(Post) == []
+ end
+
+ feature "admin can delete other developer's post", %{session: session} do
+ developer = Factory.insert!(:developer, username: "regular-dev")
+ admin = Factory.insert!(:developer, username: "admin-user", admin: true)
+ post = Factory.insert!(:post, developer: developer)
+
+ session
+ |> sign_in(admin)
+ |> PostShowPage.navigate(post)
+ |> click_and_confirm(Query.link("delete"))
+ |> assert_flash(:info, "Post deleted successfully")
+ |> assert_path(developer_path(TilexWeb.Endpoint, :show, developer))
+
+ assert Repo.all(Post) == []
+ end
+
+ feature "non-owner cannot see delete button", %{session: session} do
+ developer = Factory.insert!(:developer, username: "post-owner")
+ other_developer = Factory.insert!(:developer, username: "other-dev")
+ post = Factory.insert!(:post, developer: developer)
+
+ session
+ |> sign_in(other_developer)
+ |> PostShowPage.navigate(post)
+ |> refute_has(Query.link("delete"))
+ end
+end
diff --git a/test/features/developer_edits_post_test.exs b/test/features/developer_edits_post_test.exs
index 644d9b79..d61dcd74 100644
--- a/test/features/developer_edits_post_test.exs
+++ b/test/features/developer_edits_post_test.exs
@@ -1,10 +1,10 @@
defmodule DeveloperEditsPostTest do
- use Tilex.IntegrationCase, async: true
+ use Tilex.IntegrationCase, async: false
alias Tilex.Integration.Pages.PostForm
alias Tilex.Integration.Pages.PostShowPage
- test "fills out form and updates post from post show", %{session: session} do
+ feature "fills out form and updates post from post show", %{session: session} do
Factory.insert!(:channel, name: "phoenix")
developer = Factory.insert!(:developer)
diff --git a/test/features/developer_edits_profile_test.exs b/test/features/developer_edits_profile_test.exs
index 909e226d..de423b39 100644
--- a/test/features/developer_edits_profile_test.exs
+++ b/test/features/developer_edits_profile_test.exs
@@ -1,7 +1,7 @@
defmodule DeveloperEditsProfileTest do
use Tilex.IntegrationCase, async: false
- test "fills out form and updates post from post show", %{session: session} do
+ feature "fills out form and updates post from post show", %{session: session} do
developer = Factory.insert!(:developer, email: "fine@sixdollareggs.com")
sign_in(session, developer)
diff --git a/test/features/developer_sees_navigation_bar_test.exs b/test/features/developer_sees_navigation_bar_test.exs
index f7640555..43785da3 100644
--- a/test/features/developer_sees_navigation_bar_test.exs
+++ b/test/features/developer_sees_navigation_bar_test.exs
@@ -1,10 +1,10 @@
defmodule DeveloperSeesNavigationBarTest do
- use Tilex.IntegrationCase, async: true
+ use Tilex.IntegrationCase, async: false
alias Tilex.Integration.Pages.Navigation
describe "when developer is not authenticated" do
- test "there is no link on admin navbar", %{session: session} do
+ feature "there is no link on admin navbar", %{session: session} do
link_texts =
session
|> visit("/")
@@ -17,7 +17,7 @@ defmodule DeveloperSeesNavigationBarTest do
describe "when developer is authenticated" do
setup [:authenticated_developer]
- test "there are links on admin navbar", %{session: session} do
+ feature "there are links on admin navbar", %{session: session} do
link_texts =
session
|> visit("/")
diff --git a/test/features/developer_signs_out_test.exs b/test/features/developer_signs_out_test.exs
index a5102f94..769e152d 100644
--- a/test/features/developer_signs_out_test.exs
+++ b/test/features/developer_signs_out_test.exs
@@ -1,7 +1,7 @@
defmodule Features.DeveloperSignsOutTest do
- use Tilex.IntegrationCase, async: true
+ use Tilex.IntegrationCase, async: false
- test "signs out and sees a flash message", %{:session => session} do
+ feature "signs out and sees a flash message", %{:session => session} do
developer = Factory.insert!(:developer)
session
diff --git a/test/features/developer_views_stats_test.exs b/test/features/developer_views_stats_test.exs
index f6199771..aaa826c2 100644
--- a/test/features/developer_views_stats_test.exs
+++ b/test/features/developer_views_stats_test.exs
@@ -1,5 +1,5 @@
defmodule Features.DeveloperViewsStatsTest do
- use Tilex.IntegrationCase, async: true
+ use Tilex.IntegrationCase, async: false
def format_stats_date(%Date{year: year, day: day, month: month}) do
day_s = String.pad_leading(Integer.to_string(day), 2, "0")
@@ -8,7 +8,7 @@ defmodule Features.DeveloperViewsStatsTest do
"#{month_s}-#{day_s}-#{year}"
end
- test "sees total number of posts by channel", %{session: session} do
+ feature "sees total number of posts by channel", %{session: session} do
developer = Factory.insert!(:developer)
phoenix_channel = Factory.insert!(:channel, name: "phoenix")
other_channel = Factory.insert!(:channel, name: "other")
@@ -70,7 +70,7 @@ defmodule Features.DeveloperViewsStatsTest do
assert text_without_newlines(other_channel) =~ "#other 3 posts"
end
- test "does not see sees til activity chart", %{session: session} do
+ feature "does not see sees til activity chart", %{session: session} do
developer = Factory.insert!(:developer)
session
diff --git a/test/features/robot_sees_sitemap.exs b/test/features/robot_sees_sitemap.exs
index 7f32bc7b..b907153b 100644
--- a/test/features/robot_sees_sitemap.exs
+++ b/test/features/robot_sees_sitemap.exs
@@ -1,7 +1,7 @@
defmodule RobotSeesSitemap do
- use Tilex.IntegrationCase, async: true
+ use Tilex.IntegrationCase, async: false
- test "And sees posts", %{session: session} do
+ feature "And sees posts", %{session: session} do
post = Factory.insert!(:post, title: "Klaus and Greta")
visit(session, "/sitemap.xml")
diff --git a/test/features/visitor_searches_posts_test.exs b/test/features/visitor_searches_posts_test.exs
index f41eb835..4beec071 100644
--- a/test/features/visitor_searches_posts_test.exs
+++ b/test/features/visitor_searches_posts_test.exs
@@ -1,5 +1,5 @@
defmodule VisiorSearchesPosts do
- use Tilex.IntegrationCase, async: true
+ use Tilex.IntegrationCase, async: false
def fill_in_search(session, query) do
session
@@ -12,7 +12,7 @@ defmodule VisiorSearchesPosts do
|> click(Query.button("Search"))
end
- test "with no found posts", %{session: session} do
+ feature "with no found posts", %{session: session} do
Factory.insert!(:post, title: "elixir is awesome")
fill_in_search(session, "ruby on rails")
search_result_header = get_text(session, "#search")
@@ -20,7 +20,7 @@ defmodule VisiorSearchesPosts do
assert search_result_header == "0 posts about ruby on rails"
end
- test "with 2 found posts", %{session: session} do
+ feature "with 2 found posts", %{session: session} do
["Elixir Rules", "Because JavaScript", "Hashrocket Rules"]
|> Enum.each(&Factory.insert!(:post, title: &1))
@@ -36,7 +36,7 @@ defmodule VisiorSearchesPosts do
refute body =~ ~r/Because JavaScript/
end
- test "with paginated query results", %{session: session} do
+ feature "with paginated query results", %{session: session} do
max_posts_on_page = Application.get_env(:tilex, :page_size)
1..(max_posts_on_page * 2)
diff --git a/test/features/visitor_views_channel_test.exs b/test/features/visitor_views_channel_test.exs
index ec03a8a8..7741875b 100644
--- a/test/features/visitor_views_channel_test.exs
+++ b/test/features/visitor_views_channel_test.exs
@@ -1,7 +1,7 @@
defmodule Features.VisitorViewsChannelTest do
- use Tilex.IntegrationCase, async: true
+ use Tilex.IntegrationCase, async: false
- test "sees associated posts", %{session: session} do
+ feature "sees associated posts", %{session: session} do
target_channel = Factory.insert!(:channel, name: "phoenix")
other_channel = Factory.insert!(:channel, name: "other")
@@ -22,7 +22,7 @@ defmodule Features.VisitorViewsChannelTest do
assert page_title(session) == "Phoenix - Today I Learned"
end
- test "the page has a list of paginated posts", %{session: session} do
+ feature "the page has a list of paginated posts", %{session: session} do
channel = Factory.insert!(:channel, name: "smalltalk")
{:ok, inserted_at} = DateTime.from_naive(~N[2019-06-28 16:05:47], "Etc/UTC")
diff --git a/test/features/visitor_views_developer_test.exs b/test/features/visitor_views_developer_test.exs
index 2c6a8b26..807e5f23 100644
--- a/test/features/visitor_views_developer_test.exs
+++ b/test/features/visitor_views_developer_test.exs
@@ -1,9 +1,9 @@
defmodule Features.VisitorViewsDeveloper do
- use Tilex.IntegrationCase, async: true
+ use Tilex.IntegrationCase, async: false
alias TilexWeb.Endpoint
- test "and sees the developer's posts", %{session: session} do
+ feature "and sees the developer's posts", %{session: session} do
developer = Factory.insert!(:developer, username: "makinpancakes")
post = Factory.insert!(:post, developer: developer)
@@ -19,7 +19,7 @@ defmodule Features.VisitorViewsDeveloper do
assert page_title(session) == "makinpancakes - Today I Learned"
end
- test "and sees a prolific developer's posts", %{session: session} do
+ feature "and sees a prolific developer's posts", %{session: session} do
developer = Factory.insert!(:developer, username: "banjocardhush")
Factory.insert_list!(:post, 7, developer: developer)
@@ -30,7 +30,7 @@ defmodule Features.VisitorViewsDeveloper do
assert page_header =~ ~r/7 posts by banjocardhush/
end
- test "and sees the developer's twitter when set", %{session: session} do
+ feature "and sees the developer's twitter when set", %{session: session} do
developer = Factory.insert!(:developer, twitter_handle: "makinbaconpancakes")
visit(session, developer_path(Endpoint, :show, developer))
diff --git a/test/features/visitor_views_error_page_test.exs b/test/features/visitor_views_error_page_test.exs
index 01305209..d146994c 100644
--- a/test/features/visitor_views_error_page_test.exs
+++ b/test/features/visitor_views_error_page_test.exs
@@ -1,8 +1,8 @@
defmodule VisitorViewsErrorPageTest do
- use Tilex.IntegrationCase, async: true
+ use Tilex.IntegrationCase, async: false
describe "pages early rejected by url rule" do
- test "shows not found error page", %{session: session} do
+ feature "shows not found error page", %{session: session} do
session = visit(session, "/some-page.php")
assert page_title(session) == "Not Found - Today I Learned"
@@ -13,7 +13,7 @@ defmodule VisitorViewsErrorPageTest do
end
describe "channel not found" do
- test "shows not found error page", %{session: session} do
+ feature "shows not found error page", %{session: session} do
session = visit(session, "/missing-channel")
assert page_title(session) == "Not Found - Today I Learned"
diff --git a/test/features/visitor_views_post_test.exs b/test/features/visitor_views_post_test.exs
index 940addfc..cce59b13 100644
--- a/test/features/visitor_views_post_test.exs
+++ b/test/features/visitor_views_post_test.exs
@@ -4,7 +4,7 @@ defmodule VisitorViewsPostTest do
alias TilexWeb.Endpoint
alias Tilex.Integration.Pages.PostShowPage
- test "the page shows a post", %{session: session} do
+ feature "the page shows a post", %{session: session} do
Application.put_env(:tilex, :date_display_tz, "")
developer = Factory.insert!(:developer)
@@ -45,7 +45,7 @@ defmodule VisitorViewsPostTest do
assert path =~ post.slug
end
- test "the page shows a post with the correct timezone if given", %{session: session} do
+ feature "the page shows a post with the correct timezone if given", %{session: session} do
Application.put_env(:tilex, :date_display_tz, "America/Chicago")
developer = Factory.insert!(:developer)
@@ -66,7 +66,7 @@ defmodule VisitorViewsPostTest do
assert post_date(session) == "February 1, 2018"
end
- test "and sees marketing copy, if it exists", %{session: session} do
+ feature "and sees marketing copy, if it exists", %{session: session} do
marketing_channel = Factory.insert!(:channel, name: "elixir")
post_in_marketing_channel = Factory.insert!(:post, channel: marketing_channel)
@@ -80,7 +80,7 @@ defmodule VisitorViewsPostTest do
assert copy =~ String.slice(marketing_content, 0, 10)
end
- test "and sees a special slug", %{session: session} do
+ feature "and sees a special slug", %{session: session} do
post = Factory.insert!(:post, title: "Super Sluggable Title")
url =
@@ -102,7 +102,7 @@ defmodule VisitorViewsPostTest do
assert url =~ "#{post.slug}-alternate-also-cool-title"
end
- test "and sees a channel specific twitter card and a post specific twitter description", %{
+ feature "and sees a channel specific twitter card and a post specific twitter description", %{
session: session
} do
popular_channel = Factory.insert!(:channel, name: "command-line")
@@ -132,7 +132,7 @@ defmodule VisitorViewsPostTest do
refute twitter_description =~ "Another sentence"
end
- test "and sees a post specific twitter description WITHOUT markdown", %{
+ feature "and sees a post specific twitter description WITHOUT markdown", %{
session: session
} do
popular_channel = Factory.insert!(:channel, name: "command-line")
@@ -151,7 +151,7 @@ defmodule VisitorViewsPostTest do
refute twitter_description =~ "Another sentence"
end
- test "and clicks 'like' for that post", %{session: session} do
+ feature "and clicks 'like' for that post", %{session: session} do
Tilex.DateTimeMock.start_link([])
developer = Factory.insert!(:developer)
post = Factory.insert!(:post, title: "A special post", developer: developer, likes: 1)
@@ -184,7 +184,7 @@ defmodule VisitorViewsPostTest do
assert post.max_likes == 2
end
- test "sees raw markdown version", %{session: session} do
+ feature "sees raw markdown version", %{session: session} do
title = "A special post"
body = """
@@ -218,7 +218,7 @@ defmodule VisitorViewsPostTest do
""")
end
- test "via the random url", %{session: session} do
+ feature "via the random url", %{session: session} do
post = Factory.insert!(:post)
session
@@ -233,7 +233,7 @@ defmodule VisitorViewsPostTest do
assert page_title(session) == "#{post.title} - Today I Learned"
end
- test "via the random by channel url", %{session: session} do
+ feature "via the random by channel url", %{session: session} do
post = Factory.insert!(:post)
session
diff --git a/test/features/visitor_views_rss_feed_test.exs b/test/features/visitor_views_rss_feed_test.exs
index f8357da4..3d4dd607 100644
--- a/test/features/visitor_views_rss_feed_test.exs
+++ b/test/features/visitor_views_rss_feed_test.exs
@@ -1,12 +1,12 @@
defmodule VisitorViewsRSSFeed do
- use Tilex.IntegrationCase, async: true
+ use Tilex.IntegrationCase, async: false
- test "via the legacy atom query parameter", %{session: session} do
+ feature "via the legacy atom query parameter", %{session: session} do
visit(session, "/?format=atom")
assert current_path(session) == "/rss"
end
- test "via an alternate RSS query parameter", %{session: session} do
+ feature "via an alternate RSS query parameter", %{session: session} do
visit(session, "/?format=rss")
assert current_path(session) == "/rss"
end
diff --git a/test/features/visitor_views_stats_test.exs b/test/features/visitor_views_stats_test.exs
index 5bcf82d7..3e19f6e5 100644
--- a/test/features/visitor_views_stats_test.exs
+++ b/test/features/visitor_views_stats_test.exs
@@ -1,7 +1,7 @@
defmodule Features.VisitorViewsStatsTest do
- use Tilex.IntegrationCase, async: true
+ use Tilex.IntegrationCase, async: false
- test "sees total number of posts by channel", %{session: session} do
+ feature "sees total number of posts by channel", %{session: session} do
target_channel = Factory.insert!(:channel, name: "phoenix")
other_channel = Factory.insert!(:channel, name: "other")
@@ -24,7 +24,7 @@ defmodule Features.VisitorViewsStatsTest do
assert text_without_newlines(phoenix_channel) =~ "#phoenix 1 post"
end
- test "sees most liked and hottest tils", %{session: session} do
+ feature "sees most liked and hottest tils", %{session: session} do
posts = [
"Controllers",
"Views",
@@ -64,7 +64,7 @@ defmodule Features.VisitorViewsStatsTest do
assert text_without_newlines(insert_mode) =~ "Controllers #phoenix • 1 like"
end
- test "sees til activity", %{session: session} do
+ feature "sees til activity", %{session: session} do
dt = fn {_y, _m, _d} = date ->
{date, {12, 0, 0}}
|> NaiveDateTime.from_erl!()
@@ -112,7 +112,7 @@ defmodule Features.VisitorViewsStatsTest do
)
end
- test "sees total number of posts by developer", %{session: session} do
+ feature "sees total number of posts by developer", %{session: session} do
developer = Factory.insert!(:developer, username: "makinpancakes")
Factory.insert!(:post, developer: developer)
diff --git a/test/features/visitor_visits_homepage_test.exs b/test/features/visitor_visits_homepage_test.exs
index e1191baf..c9817ad5 100644
--- a/test/features/visitor_visits_homepage_test.exs
+++ b/test/features/visitor_visits_homepage_test.exs
@@ -1,13 +1,13 @@
defmodule VisitorVisitsHomepageTest do
- use Tilex.IntegrationCase, async: true
+ use Tilex.IntegrationCase, async: false
- test "the page does not have a Create Post link", %{session: session} do
+ feature "the page does not have a Create Post link", %{session: session} do
visit(session, "/")
refute has?(session, Query.link("Create Post"))
end
- test "the page has the appropriate branding", %{session: session} do
+ feature "the page has the appropriate branding", %{session: session} do
header_text =
session
|> visit("/")
@@ -19,7 +19,7 @@ defmodule VisitorVisitsHomepageTest do
assert page_title(session) == "Hashrocket - Today I Learned"
end
- test "the page has a list of posts", %{session: session} do
+ feature "the page has a list of posts", %{session: session} do
channel = Factory.insert!(:channel, name: "smalltalk")
Factory.insert!(
@@ -44,7 +44,7 @@ defmodule VisitorVisitsHomepageTest do
assert post_footer =~ ~r/#smalltalk/i
end
- test "the page has a list of paginated posts", %{session: session} do
+ feature "the page has a list of paginated posts", %{session: session} do
Factory.insert_list!(:post, 5 + 1)
visit(session, "/")
diff --git a/test/support/integration_case.ex b/test/support/integration_case.ex
index fd856938..85d4961f 100644
--- a/test/support/integration_case.ex
+++ b/test/support/integration_case.ex
@@ -1,23 +1,28 @@
defmodule Tilex.IntegrationCase do
use ExUnit.CaseTemplate
+ alias Wallaby.Browser
+ alias Wallaby.Element
+ alias Wallaby.Query
+
using do
quote do
- use Wallaby.DSL
- alias Wallaby.Query
- alias Wallaby.Element
+ use Wallaby.Feature
- alias Tilex.Blog.Channel
- alias Tilex.Factory
- alias Tilex.Blog.Post
- alias Tilex.Repo
- alias TilexWeb.Endpoint
import Ecto
import Ecto.Changeset
import Ecto.Query
-
- import TilexWeb.Router.Helpers
+ import Tilex.IntegrationCase
import Tilex.WallabyTestHelpers
+ import TilexWeb.Router.Helpers
+
+ alias Tilex.Blog.Channel
+ alias Tilex.Blog.Post
+ alias Tilex.Factory
+ alias Tilex.Repo
+ alias TilexWeb.Endpoint
+ alias Wallaby.Element
+ alias Wallaby.Query
def sign_in(session, developer) do
visit(session, "/admin?id=#{developer.id}")
@@ -27,13 +32,64 @@ defmodule Tilex.IntegrationCase do
developer = Factory.insert!(:developer, admin: true, username: "Rock Teer")
[session: sign_in(session, developer), developer: developer]
end
+
+ setup do
+ Ecto.Adapters.SQL.Sandbox.allow(Tilex.Repo, self(), Process.whereis(Tilex.Notifications))
+ end
end
end
- setup tags do
- Tilex.DataCase.setup_sandbox(tags)
- metadata = Phoenix.Ecto.SQL.Sandbox.metadata_for(Tilex.Repo, self())
- {:ok, session} = Wallaby.start_session(metadata: metadata)
- {:ok, session: session}
+ def click_and_confirm(session, query) do
+ Browser.accept_confirm(session, &Browser.click(&1, query))
+ session
+ end
+
+ def assert_path(session, path) do
+ retry!(session, fn ->
+ assert Browser.current_path(session) == path
+ session
+ end)
+ end
+
+ def assert_contains(session, query, expected_text) do
+ retry!(session, fn ->
+ texts = session |> Browser.all(query) |> Enum.map(&Element.text/1)
+
+ assert Enum.any?(texts, &String.contains?(&1, expected_text)),
+ "Unable to find contains text: '#{expected_text}', instead found '#{texts}'"
+
+ session
+ end)
+ end
+
+ def assert_texts(session, query, expected_texts) do
+ retry!(session, fn ->
+ texts = session |> Browser.all(query) |> Enum.map(&Element.text/1)
+
+ assert texts == expected_texts,
+ "Unable to find text: '#{expected_texts}', instead found '#{texts}'"
+
+ session
+ end)
+ end
+
+ def assert_flash(session, level, message) when level in [:info, :success] do
+ assert_contains(session, Query.css(".alert-#{level}"), message)
+ end
+
+ @waits [10, 20, 30, 50, 80, 130]
+ def retry!(session, func, waits \\ @waits) do
+ func.()
+ session
+ rescue
+ error ->
+ case waits do
+ [] ->
+ reraise(error, __STACKTRACE__)
+
+ [wait | waits] ->
+ Process.sleep(wait)
+ retry!(session, func, waits)
+ end
end
end