|
1 | | -from task_manager.statuses.models import Status |
2 | | -from task_manager.tasks.models import Task |
3 | 1 | import pytest |
4 | 2 | from django.contrib.auth import get_user_model |
| 3 | +from django.test import Client |
| 4 | +from django.urls import reverse |
| 5 | +from task_manager.tasks.models import Task |
| 6 | +from task_manager.statuses.models import Status |
| 7 | + |
5 | 8 | User = get_user_model() |
6 | 9 |
|
7 | 10 |
|
| 11 | +@pytest.fixture |
| 12 | +def status_new(db): |
| 13 | + return Status.objects.create(name="новый") |
| 14 | + |
| 15 | + |
8 | 16 | @pytest.fixture |
9 | 17 | def users(db): |
10 | | - pwd = "p12345678" |
11 | | - u1 = User.objects.create_user(username="user1", password=pwd) |
12 | | - u2 = User.objects.create_user(username="user2", password=pwd) |
13 | | - return {"u1": u1, "u2": u2, "pwd": pwd} |
| 18 | + password = "P@ssw0rd12345" |
| 19 | + u1 = User.objects.create_user( |
| 20 | + username="alice", password=password, first_name="Alice", last_name="A" |
| 21 | + ) |
| 22 | + u2 = User.objects.create_user( |
| 23 | + username="bob", password=password, first_name="Bob", last_name="B" |
| 24 | + ) |
| 25 | + return {"alice": u1, "bob": u2, "password": password} |
14 | 26 |
|
15 | 27 |
|
16 | 28 | @pytest.fixture |
17 | 29 | def auth_client(users): |
18 | | - from django.test import Client |
19 | 30 | c = Client() |
20 | | - c.login(username="user1", password=users["pwd"]) |
| 31 | + c.login(username="alice", password=users["password"]) |
21 | 32 | return c |
22 | 33 |
|
23 | 34 |
|
24 | | -@pytest.fixture |
25 | | -def status_new(db): |
26 | | - return Status.objects.create(name="новый") |
| 35 | +@pytest.mark.django_db |
| 36 | +def test_users_list_is_public(client, users): |
| 37 | + resp = client.get(reverse("list", current_app="users")) |
| 38 | + assert resp.status_code == 200 |
| 39 | + html = resp.content.decode() |
| 40 | + assert "alice" in html |
| 41 | + assert "bob" in html |
27 | 42 |
|
28 | 43 |
|
29 | 44 | @pytest.mark.django_db |
30 | | -def test_login_required(client): |
31 | | - r = client.get("/tasks/") |
| 45 | +def test_registration_get(client): |
| 46 | + r = client.get(reverse("create", current_app="users")) |
| 47 | + assert r.status_code == 200 |
| 48 | + html = r.content.decode() |
| 49 | + assert 'name="username"' in html |
| 50 | + assert 'name="password1"' in html |
| 51 | + assert 'name="password2"' in html |
| 52 | + |
| 53 | + |
| 54 | +@pytest.mark.django_db |
| 55 | +def test_registration_post_creates_user(client): |
| 56 | + data = { |
| 57 | + "username": "charlie", |
| 58 | + "first_name": "Charlie", |
| 59 | + "last_name": "C", |
| 60 | + "password1": "XyZ12345!xyZ", |
| 61 | + "password2": "XyZ12345!xyZ", |
| 62 | + } |
| 63 | + r = client.post(reverse("create", current_app="users"), data=data) |
32 | 64 | assert r.status_code in (302, 301) |
| 65 | + assert User.objects.filter(username="charlie").exists() |
33 | 66 |
|
34 | 67 |
|
35 | 68 | @pytest.mark.django_db |
36 | | -def test_list(auth_client, users, status_new): |
37 | | - Task.objects.create(name="Тестовая задача", description="Описание", |
38 | | - status=status_new, author=users["u1"]) |
39 | | - Task.objects.create(name="Вторая", description="Ещё одна", |
40 | | - status=status_new, author=users["u1"]) |
41 | | - r = auth_client.get("/tasks/") |
42 | | - assert r.status_code == 200 |
43 | | - html = r.content.decode() |
44 | | - assert "Тестовая задача" in html |
45 | | - assert "Вторая" in html |
| 69 | +def test_update_requires_auth_redirects(client, users): |
| 70 | + url = reverse("update", args=[users["alice"].pk], current_app="users") |
| 71 | + r = client.get(url) |
| 72 | + assert r.status_code in (302, 301) |
| 73 | + assert reverse("login") in r.url |
| 74 | + assert f"next={url}" in r.url |
46 | 75 |
|
47 | 76 |
|
48 | 77 | @pytest.mark.django_db |
49 | | -def test_create(auth_client, users, status_new): |
50 | | - resp = auth_client.post("/tasks/create/", data={ |
51 | | - "name": "Новая задача", |
52 | | - "description": "Что-то сделать", |
53 | | - "status": status_new.pk, |
54 | | - "executor": users["u2"].pk, |
55 | | - }) |
56 | | - assert resp.status_code in (302, 301) |
57 | | - assert Task.objects.filter(name="Новая задача", |
58 | | - status=status_new, |
59 | | - author=users["u1"]).exists() |
| 78 | +def test_user_can_update_self(auth_client, users): |
| 79 | + url = reverse("update", args=[users["alice"].pk], current_app="users") |
| 80 | + r_get = auth_client.get(url) |
| 81 | + assert r_get.status_code == 200 |
| 82 | + |
| 83 | + r_post = auth_client.post( |
| 84 | + url, |
| 85 | + data={"username": "alice_new", "first_name": "Al", "last_name": "A"}, |
| 86 | + ) |
| 87 | + assert r_post.status_code in (302, 301) |
| 88 | + |
| 89 | + users["alice"].refresh_from_db() |
| 90 | + assert users["alice"].username == "alice_new" |
| 91 | + assert users["alice"].first_name == "Al" |
60 | 92 |
|
61 | 93 |
|
62 | 94 | @pytest.mark.django_db |
63 | | -def test_update(auth_client, users, status_new): |
64 | | - t = Task.objects.create(name="Черновик", description="Описание", |
65 | | - status=status_new, author=users["u1"]) |
66 | | - resp = auth_client.post(f"/tasks/{t.pk}/update/", data={ |
67 | | - "name": "Изменено", |
68 | | - "description": "Новое описание", |
69 | | - "status": status_new.pk, |
70 | | - "executor": users["u2"].pk, |
71 | | - }) |
72 | | - assert resp.status_code in (302, 301) |
73 | | - t.refresh_from_db() |
74 | | - assert t.name == "Изменено" |
75 | | - assert t.description == "Новое описание" |
76 | | - assert t.executor == users["u2"] |
| 95 | +def test_user_cannot_update_other(auth_client, users): |
| 96 | + url = reverse("update", args=[users["bob"].pk], current_app="users") |
| 97 | + r = auth_client.post(url, data={"username": "bob_hacked"}) |
| 98 | + assert r.status_code in (302, 403, 404) |
| 99 | + users["bob"].refresh_from_db() |
| 100 | + assert users["bob"].username == "bob" |
77 | 101 |
|
78 | 102 |
|
79 | 103 | @pytest.mark.django_db |
80 | | -def test_view(auth_client, users, status_new): |
81 | | - t = Task.objects.create(name="Посмотреть", description="Детали", |
82 | | - status=status_new, author=users["u1"]) |
83 | | - r = auth_client.get(f"/tasks/{t.pk}/") |
84 | | - assert r.status_code == 200 |
85 | | - html = r.content.decode() |
86 | | - assert "Посмотреть" in html |
87 | | - assert "Детали" in html |
| 104 | +def test_delete_requires_auth_redirects(client, users): |
| 105 | + url = reverse("delete", args=[users["alice"].pk], current_app="users") |
| 106 | + r = client.get(url) |
| 107 | + assert r.status_code in (302, 301) |
| 108 | + assert reverse("login") in r.url |
88 | 109 |
|
89 | 110 |
|
90 | 111 | @pytest.mark.django_db |
91 | | -def test_delete(auth_client, users, status_new): |
92 | | - t = Task.objects.create(name="Удалить", description="Ненужная", |
93 | | - status=status_new, author=users["u1"]) |
94 | | - r_get = auth_client.get(f"/tasks/{t.pk}/delete/") |
| 112 | +def test_user_can_delete_self(users): |
| 113 | + c = Client() |
| 114 | + c.login(username="bob", password=users["password"]) |
| 115 | + url = reverse("delete", args=[users["bob"].pk], current_app="users") |
| 116 | + r_get = c.get(url) |
95 | 117 | assert r_get.status_code == 200 |
96 | | - r_post = auth_client.post(f"/tasks/{t.pk}/delete/") |
| 118 | + r_post = c.post(url) |
97 | 119 | assert r_post.status_code in (302, 301) |
98 | | - assert not Task.objects.filter(pk=t.pk).exists() |
| 120 | + assert not User.objects.filter(pk=users["bob"].pk).exists() |
| 121 | + |
| 122 | + |
| 123 | +@pytest.mark.django_db |
| 124 | +def test_user_cannot_delete_other(auth_client, users): |
| 125 | + url = reverse("delete", args=[users["bob"].pk], current_app="users") |
| 126 | + r = auth_client.post(url) |
| 127 | + assert r.status_code in (302, 403, 404) |
| 128 | + assert User.objects.filter(pk=users["bob"].pk).exists() |
99 | 129 |
|
100 | 130 |
|
101 | 131 | @pytest.mark.django_db |
102 | 132 | def test_only_author_can_delete(auth_client, users, status_new): |
103 | 133 | t = Task.objects.create( |
104 | | - name="Чужая задача", description="...", |
105 | | - status=status_new, author=users["u2"] |
| 134 | + name="Чужая задача", |
| 135 | + description="...", |
| 136 | + status=status_new, |
| 137 | + author=users["bob"], |
106 | 138 | ) |
107 | | - r = auth_client.post(f"/tasks/{t.pk}/delete/") |
| 139 | + r = auth_client.post(reverse("tasks:delete", args=[t.pk])) |
108 | 140 | assert r.status_code in (302, 301) |
109 | 141 | assert Task.objects.filter(pk=t.pk).exists() |
110 | 142 |
|
111 | | - from django.test import Client |
112 | 143 | c = Client() |
113 | | - c.login(username="user2", password=users["pwd"]) |
114 | | - r2 = c.post(f"/tasks/{t.pk}/delete/") |
| 144 | + c.login(username="bob", password=users["password"]) |
| 145 | + r2 = c.post(reverse("tasks:delete", args=[t.pk])) |
115 | 146 | assert r2.status_code in (302, 301) |
116 | 147 | assert not Task.objects.filter(pk=t.pk).exists() |
| 148 | + |
| 149 | + |
| 150 | +@pytest.mark.django_db |
| 151 | +def test_user_with_tasks_cannot_be_deleted(users, status_new): |
| 152 | + Task.objects.create( |
| 153 | + name="Тестовая", |
| 154 | + description="Проверка", |
| 155 | + status=status_new, |
| 156 | + author=users["bob"], |
| 157 | + ) |
| 158 | + |
| 159 | + c = Client() |
| 160 | + c.login(username="bob", password=users["password"]) |
| 161 | + url = reverse("delete", args=[users["bob"].pk], current_app="users") |
| 162 | + r = c.post(url) |
| 163 | + assert r.status_code in (302, 301) |
| 164 | + assert User.objects.filter(pk=users["bob"].pk).exists() |
0 commit comments