-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
More Code Examples from the Programming Phoenix book #42
Changes from 16 commits
a2f798d
68adc2b
e2065b3
dffbb51
a034625
14bfa97
63efdf3
e83b58f
f11e96d
fca2449
cd0cb73
30d637c
cb701c6
147514c
69fcb56
f2a17a2
08f92dc
09e9092
0ab4581
c7075e1
eebd057
aaf3cda
837db9e
5860104
96c9f64
db72acb
27c4a11
954fab8
873465a
0dc090e
b2e0da3
b0ea31b
cfe5333
7d222ef
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# run this test using the following command: | ||
# elixir -e "ExUnit.start()" -r basic-test.exs | ||
|
||
defmodule MyTest do | ||
use ExUnit.Case, async: true | ||
|
||
setup do | ||
# run some tedious setup code | ||
:ok | ||
end | ||
|
||
test "pass" do | ||
assert true | ||
end | ||
|
||
test "fail" do | ||
refute false | ||
end | ||
end | ||
|
||
|
||
# thanks to @shouston3 in | ||
# https://github.com/dwyl/learn-phoenix-framework/issues/34#issuecomment-280930167 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
defmodule Rumbl.Repo.Migrations.CreateVideo do | ||
use Ecto.Migration | ||
|
||
def change do | ||
create table(:videos) do | ||
add :url, :string | ||
add :title, :string | ||
add :description, :text | ||
add :user_id, references(:users, on_delete: :nothing) | ||
|
||
timestamps() | ||
end | ||
create index(:videos, [:user_id]) | ||
|
||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
defmodule Rumbl.Repo.Migrations.CreateCategory do | ||
use Ecto.Migration | ||
|
||
def change do | ||
create table(:categories) do | ||
add :name, :string, null: false | ||
|
||
timestamps() # function call parenthesis not in book! | ||
end | ||
|
||
create unique_index(:categories, [:name]) | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
defmodule Rumbl.Repo.Migrations.AddCategoryIdToVideo do | ||
use Ecto.Migration | ||
|
||
def change do | ||
alter table(:videos) do | ||
add :category_id, references(:categories) | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,3 +9,11 @@ | |
# | ||
# We recommend using the bang functions (`insert!`, `update!` | ||
# and so on) as they will fail if something goes wrong. | ||
|
||
alias Rumbl.Repo | ||
alias Rumbl.Category | ||
|
||
for category <- ~w(Action Drama Romance Comedy Sci-fi) do | ||
Repo.insert!(%Category{name: category}) || | ||
Repo.insert!(%Category{name: category}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think these should be different, I have:
instead There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Shouston3 good shout. please feel free to edit the file in PR. 👍 |
||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
defmodule Rumb.AuthTest do | ||
use Rumbl.ConnCase | ||
alias Rumbl.Auth | ||
|
||
setup %{conn: conn} do | ||
conn = | ||
conn | ||
|> bypass_through(Rumbl.Router, :browser) | ||
|> get("/") | ||
|
||
{:ok, %{conn: conn}} | ||
end | ||
|
||
test "authenticate_user halts when no current_user exists", %{conn: conn} do | ||
conn = Auth.authenticate_user(conn, []) | ||
assert conn.halted | ||
end | ||
|
||
test "authenticate_user continues when the current_user exists", | ||
%{conn: conn} do | ||
|
||
conn = | ||
conn | ||
|> assign(:current_user, %Rumbl.User{}) | ||
|> Auth.authenticate_user([]) | ||
refute conn.halted | ||
end | ||
|
||
test "login puts the user in the session", %{conn: conn} do | ||
login_conn = | ||
conn | ||
|> Auth.login(%Rumbl.User{id: 123}) | ||
|> send_resp(:ok, "") | ||
|
||
next_conn = get(login_conn, "/") | ||
assert get_session(next_conn, :user_id) == 123 | ||
end | ||
|
||
test "logout drops the session", %{conn: conn} do | ||
logout_conn = | ||
conn | ||
|> put_session(:user_id, 123) | ||
|> Auth.logout() | ||
|> send_resp(:ok, "") | ||
|
||
next_conn = get(logout_conn, "/") | ||
refute get_session(next_conn, :user_id) | ||
end | ||
|
||
test "call places user from session into assigns", %{conn: conn} do | ||
user = insert_user() | ||
conn = | ||
conn | ||
|> put_session(:user_id, user.id) | ||
|> Auth.call(Repo) | ||
|
||
assert conn.assigns.current_user.id == user.id | ||
end | ||
|
||
test "call with no session sets current_user assign to nil", %{conn: conn} do | ||
conn = Auth.call(conn, Repo) | ||
assert conn.assigns.current_user == nil | ||
end | ||
|
||
test "login with a valid username and pass", %{conn: conn} do | ||
user = insert_user(username: "me", password: "secret") | ||
{:ok, conn} = | ||
Auth.login_by_username_and_pass(conn, "me", "secret", repo: Repo) | ||
|
||
assert conn.assigns.current_user.id == user.id | ||
end | ||
|
||
test "login with a not found user", %{conn: conn} do | ||
assert {:error, :not_found, _conn} = | ||
Auth.login_by_username_and_pass(conn, "me", "secret", repo: Repo) | ||
end | ||
|
||
test "login with password missmatch", %{conn: conn} do | ||
_ = insert_user(username: "me", password: "secrete") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "secrete" typo There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah, worth fixing. thanks. 👍 |
||
assert {:error, :unauthorized, _conn} = | ||
Auth.login_by_username_and_pass(conn, "me", "wrong", repo: Repo) | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,66 +1,89 @@ | ||
defmodule Rumbl.VideoControllerTest do | ||
use Rumbl.ConnCase | ||
|
||
alias Rumbl.Video | ||
@valid_attrs %{description: "some content", title: "some content", url: "some content"} | ||
@invalid_attrs %{} | ||
|
||
test "lists all entries on index", %{conn: conn} do | ||
conn = get conn, video_path(conn, :index) | ||
assert html_response(conn, 200) =~ "Listing videos" | ||
setup %{conn: conn} = config do | ||
if username = config[:login_as] do | ||
user = insert_user(username: username) | ||
conn = assign(conn, :current_user, user) | ||
{:ok, conn: conn, user: user} | ||
else | ||
:ok | ||
end | ||
end | ||
|
||
test "renders form for new resources", %{conn: conn} do | ||
conn = get conn, video_path(conn, :new) | ||
assert html_response(conn, 200) =~ "New video" | ||
test "requires user authentication on all actions", %{conn: conn} do | ||
Enum.each([ | ||
get(conn, video_path(conn, :new)), | ||
get(conn, video_path(conn, :index)), | ||
get(conn, video_path(conn, :show, "123")), | ||
get(conn, video_path(conn, :edit, "123")), | ||
put(conn, video_path(conn, :update, "123", %{})), | ||
post(conn, video_path(conn, :create, %{})), | ||
delete(conn, video_path(conn, :delete, "123")), | ||
], fn conn -> | ||
assert html_response(conn, 302) | ||
assert conn.halted | ||
end) | ||
end | ||
|
||
test "creates resource and redirects when data is valid", %{conn: conn} do | ||
conn = post conn, video_path(conn, :create), video: @valid_attrs | ||
assert redirected_to(conn) == video_path(conn, :index) | ||
assert Repo.get_by(Video, @valid_attrs) | ||
end | ||
# setup do | ||
# user = insert_user(username: "max") | ||
# conn = assign(build_conn, :current_user, user) | ||
# {:ok, conn: conn, user: user} | ||
# end | ||
|
||
test "does not create resource and renders errors when data is invalid", %{conn: conn} do | ||
conn = post conn, video_path(conn, :create), video: @invalid_attrs | ||
assert html_response(conn, 200) =~ "New video" | ||
end | ||
@tag login_as: "max" | ||
test "lists all user's video on index", %{conn: conn, user: user} do | ||
user_video = insert_video(user, title: "funny cats") | ||
other_video = insert_video(insert_user(username: "other"), | ||
title: "another video") | ||
|
||
test "shows chosen resource", %{conn: conn} do | ||
video = Repo.insert! %Video{} | ||
conn = get conn, video_path(conn, :show, video) | ||
assert html_response(conn, 200) =~ "Show video" | ||
conn = get conn, video_path(conn, :index) | ||
assert html_response(conn, 200) =~ ~r/Listing videos/ | ||
assert String.contains?(conn.resp_body, user_video.title) | ||
refute String.contains?(conn.resp_body, other_video.title) | ||
end | ||
|
||
test "renders page not found when id is nonexistent", %{conn: conn} do | ||
assert_error_sent 404, fn -> | ||
get conn, video_path(conn, :show, -1) | ||
end | ||
end | ||
alias Rumbl.Video | ||
@valid_attrs %{url: "http://youtu.be", title: "vid", description: "a vid"} | ||
@invalid_attrs %{title: "invalid"} | ||
|
||
test "renders form for editing chosen resource", %{conn: conn} do | ||
video = Repo.insert! %Video{} | ||
conn = get conn, video_path(conn, :edit, video) | ||
assert html_response(conn, 200) =~ "Edit video" | ||
end | ||
defp video_count(query), do: Repo.one(from v in query, select: count(v.id)) | ||
|
||
test "updates chosen resource and redirects when data is valid", %{conn: conn} do | ||
video = Repo.insert! %Video{} | ||
conn = put conn, video_path(conn, :update, video), video: @valid_attrs | ||
assert redirected_to(conn) == video_path(conn, :show, video) | ||
assert Repo.get_by(Video, @valid_attrs) | ||
@tag login_as: "max" | ||
test "creates user video and redirects", %{conn: conn, user: user} do | ||
conn = post conn, video_path(conn, :create), video: @valid_attrs | ||
# assert redirected_to(conn) = video_path(conn, :index) # see: https://github.com/dwyl/learn-phoenix-framework/issues/40 | ||
assert Repo.get_by!(Video, @valid_attrs).user_id == user.id | ||
end | ||
|
||
test "does not update chosen resource and renders errors when data is invalid", %{conn: conn} do | ||
video = Repo.insert! %Video{} | ||
conn = put conn, video_path(conn, :update, video), video: @invalid_attrs | ||
assert html_response(conn, 200) =~ "Edit video" | ||
@tag login_as: "max" | ||
test "does not create video and renders errors when invalid", %{conn: conn} do | ||
count_before = video_count(Video) | ||
conn = post conn, video_path(conn, :create), video: @invalid_attrs | ||
assert html_response(conn, 200) =~ "check the errors" | ||
assert video_count(Video) == count_before | ||
end | ||
|
||
test "deletes chosen resource", %{conn: conn} do | ||
video = Repo.insert! %Video{} | ||
conn = delete conn, video_path(conn, :delete, video) | ||
assert redirected_to(conn) == video_path(conn, :index) | ||
refute Repo.get(Video, video.id) | ||
@tag login_as: "max" | ||
test "authorizes actions against access by other users", | ||
%{user: owner, conn: conn} do | ||
|
||
video = insert_video(owner, @valid_attrs) | ||
non_owner = insert_user(username: "sneaky") # https://youtu.be/_YQpbzQ6gzs?t=2m48s | ||
conn = assign(conn, :current_user, non_owner) | ||
|
||
assert_error_sent :not_found, fn -> | ||
get(conn, video_path(conn, :show, video)) | ||
end | ||
assert_error_sent :not_found, fn -> | ||
get(conn, video_path(conn, :edit, video)) | ||
end | ||
assert_error_sent :not_found, fn -> | ||
put(conn, video_path(conn, :update, video, video: @valid_attrs)) | ||
end | ||
assert_error_sent :not_found, fn -> | ||
delete(conn, video_path(conn, :delete, video)) | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
defmodule Rumbl.CategoryRepoTest do | ||
use Rumbl.ModelCase | ||
alias Rumbl.Category | ||
|
||
test "alphabetical/1 orders by name" do | ||
Repo.insert!(%Category{name: "c"}) | ||
Repo.insert!(%Category{name: "a"}) | ||
Repo.insert!(%Category{name: "b"}) | ||
|
||
query = Category |> Category.alphabetical() | ||
query = from c in query, select: c.name | ||
assert Repo.all(query) == ~w(a b c) | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
defmodule Rumbl.CategoryTest do | ||
use Rumbl.ModelCase | ||
|
||
alias Rumbl.Category | ||
|
||
@valid_attrs %{name: "some content"} | ||
@invalid_attrs %{} | ||
|
||
test "changeset with valid attributes" do | ||
changeset = Category.changeset(%Category{}, @valid_attrs) | ||
assert changeset.valid? | ||
end | ||
|
||
test "changeset with invalid attributes" do | ||
changeset = Category.changeset(%Category{}, @invalid_attrs) | ||
refute changeset.valid? | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
defmodule Rumbl.UserRepoTest do | ||
use Rumbl.ModelCase | ||
alias Rumbl.User | ||
|
||
@valid_attrs %{name: "A User", username: "eva"} | ||
|
||
test "converts unique_constraint on username to error" do | ||
insert_user(username: "eric") | ||
attrs = Map.put(@valid_attrs, :username, "eric") | ||
changeset = User.changeset(%User{}, attrs) | ||
|
||
assert {:error, changeset} = Repo.insert(changeset) | ||
assert username: "has already been taken" in changeset.errors | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice 👍