Coverage for catalog/tests/test_views.py: 100.00%

222 statements  

« prev     ^ index     » next       coverage.py v7.17.0, created at 2026-10-29 10:34 -0700

1import datetime 1a

2 

3from django.contrib.auth import get_user_model 1a

4from django.contrib.auth.models import Permission 1a

5from django.test import TestCase 1a

6from django.urls import resolve, reverse 1a

7from django.utils import timezone 1a

8 

9from ..models import Author, Book, BookInstance, Genre, Language 1a

10from ..views import index 1a

11 

12 

13class AuthorListViewTest(TestCase): 1a

14 def setUp(self): 1a

15 url = reverse("authors") 1a

16 self.response = self.client.get(url) 1a

17 

18 @classmethod 1a

19 def setUpTestData(cls): 1a

20 # Create authors for pagination tests 

21 number_of_authors = 13 1a

22 for author_id in range(number_of_authors): 1a

23 Author.objects.create( 1a

24 first_name=f"Django {author_id}", 

25 last_name=f"Wilkins {author_id}", 

26 ) 

27 

28 def test_view_url_exists_at_desired_location(self): 1a

29 response = self.client.get("/catalog/authors/") 1a

30 self.assertEqual(response.status_code, 200) 1a

31 

32 def test_view_url_accessible_by_name(self): 1a

33 self.assertEqual(self.response.status_code, 200) 1a

34 

35 def test_view_uses_correct_template(self): 1a

36 self.assertEqual(self.response.status_code, 200) 1a

37 self.assertTemplateUsed(self.response, "catalog/author_list.html") 1a

38 

39 def test_pagination_is_ten(self): 1a

40 self.assertEqual(self.response.status_code, 200) 1a

41 self.assertTrue("is_paginated" in self.response.context) 1a

42 self.assertTrue(self.response.context["is_paginated"] is True) 1a

43 self.assertEqual(len(self.response.context["author_list"]), 10) 1a

44 

45 def test_lists_all_authors(self): 1a

46 # Get second page and confirm it has (exactly) the remaining 3 items 

47 response = self.client.get(reverse("authors") + "?page=2") 1a

48 self.assertEqual(response.status_code, 200) 1a

49 self.assertTrue("is_paginated" in response.context) 1a

50 self.assertTrue(response.context["is_paginated"] is True) 1a

51 self.assertEqual(len(response.context["author_list"]), 3) 1a

52 

53 

54class LoanedBookInstancesByUserListViewTest(TestCase): 1a

55 def setUp(self): 1a

56 # Create two users 

57 test_user1 = get_user_model().objects.create_user( 1a

58 username="testuser1", password="1X<ISRUkw+tuK" 

59 ) 

60 test_user2 = get_user_model().objects.create_user( 1a

61 username="testuser2", password="2HJ1vRV0Z&3iD" 

62 ) 

63 

64 test_user1.save() 1a

65 test_user2.save() 1a

66 

67 # Create a book 

68 test_author = Author.objects.create(first_name="John", last_name="Smith") 1a

69 # test_genre = Genre.objects.create(name="Fantasy") 

70 Genre.objects.create(name="Fantasy") 1a

71 test_language = Language.objects.create(name="English") 1a

72 test_book = Book.objects.create( 1a

73 title="Book Title", 

74 summary="My book summary", 

75 isbn="ABCDEFG", 

76 author=test_author, 

77 language=test_language, 

78 ) 

79 # Create genre as a post-step 

80 genre_objects_for_book = Genre.objects.all() 1a

81 test_book.genre.set(genre_objects_for_book) 1a

82 test_book.save() 1a

83 

84 # Create 30 BookInstance objects 

85 number_of_book_copies = 30 1a

86 for book_copy in range(number_of_book_copies): 1a

87 return_date = timezone.now() + datetime.timedelta(days=book_copy % 5) 1a

88 if book_copy % 2: 1a

89 the_borrower = test_user1 1a

90 else: 

91 the_borrower = test_user2 1a

92 status = "m" 1a

93 BookInstance.objects.create( 1a

94 book=test_book, 

95 imprint="Unlikely Imprint, 2016", 

96 due_back=return_date, 

97 borrower=the_borrower, 

98 status=status, 

99 ) 

100 

101 def test_redirect_if_not_logged_in(self): 1a

102 response = self.client.get(reverse("my-borrowed")) 1a

103 self.assertRedirects(response, "/accounts/login/?next=/catalog/mybooks/") 1a

104 

105 def test_logged_in_uses_correct_template(self): 1a

106 login = self.client.login( # noqa:F841 1a

107 username="testuser1", password="1X<ISRUkw+tuK" 

108 ) 

109 response = self.client.get(reverse("my-borrowed")) 1a

110 

111 # Check our user is logged in 

112 self.assertEqual(str(response.context["user"]), "testuser1") 1a

113 # Check that we got a response "success" 

114 self.assertEqual(response.status_code, 200) 1a

115 

116 # Check we used correct template 

117 self.assertTemplateUsed( 1a

118 response, "catalog/bookinstance_list_borrowed_user.html" 

119 ) 

120 

121 def test_only_borrowed_books_in_list(self): 1a

122 login = self.client.login( # noqa:F841 1a

123 username="testuser1", password="1X<ISRUkw+tuK" 

124 ) 

125 response = self.client.get(reverse("my-borrowed")) 1a

126 

127 # Check our user is logged in 

128 self.assertEqual(str(response.context["user"]), "testuser1") 1a

129 # Check that we got a response "success" 

130 self.assertEqual(response.status_code, 200) 1a

131 

132 # Check that initially we don't have any books in list (none on loan) 

133 self.assertTrue("bookinstance_list" in response.context) 1a

134 self.assertEqual(len(response.context["bookinstance_list"]), 0) 1a

135 

136 # Now change all books to be on loan 

137 get_ten_books = BookInstance.objects.all()[:10] 1a

138 

139 for copy in get_ten_books: 1a

140 copy.status = "o" 1a

141 copy.save() 1a

142 

143 # Check that now we have borrowed books in the list 

144 response = self.client.get(reverse("my-borrowed")) 1a

145 # Check our user is logged in 

146 self.assertEqual(str(response.context["user"]), "testuser1") 1a

147 # Check that we got a response "success" 

148 self.assertEqual(response.status_code, 200) 1a

149 

150 self.assertTrue("bookinstance_list" in response.context) 1a

151 

152 # Confirm all books belong to testuser1 and are on loan 

153 for bookitem in response.context["bookinstance_list"]: 1a

154 self.assertEqual(response.context["user"], bookitem.borrower) 1a

155 self.assertEqual(bookitem.status, "o") 1a

156 

157 def test_pages_paginated_to_ten(self): 1a

158 # Change all books to be on loan. 

159 # This should make 15 test user ones. 

160 for copy in BookInstance.objects.all(): 1a

161 copy.status = "o" 1a

162 copy.save() 1a

163 

164 login = self.client.login( # noqa:F841 1a

165 username="testuser1", password="1X<ISRUkw+tuK" 

166 ) 

167 response = self.client.get(reverse("my-borrowed")) 1a

168 

169 # Check our user is logged in 

170 self.assertEqual(str(response.context["user"]), "testuser1") 1a

171 # Check that we got a response "success" 

172 self.assertEqual(response.status_code, 200) 1a

173 

174 # Confirm that only 10 items are displayed due to pagination 

175 # (if pagination not enabled, there would be 15 returned) 

176 self.assertEqual(len(response.context["bookinstance_list"]), 10) 1a

177 

178 def test_pages_ordered_by_due_date(self): 1a

179 # Change all books to be on loan 

180 for copy in BookInstance.objects.all(): 1a

181 copy.status = "o" 1a

182 copy.save() 1a

183 

184 login = self.client.login( # noqa:F841 1a

185 username="testuser1", password="1X<ISRUkw+tuK" 

186 ) 

187 response = self.client.get(reverse("my-borrowed")) 1a

188 

189 # Check our user is logged in 

190 self.assertEqual(str(response.context["user"]), "testuser1") 1a

191 # Check that we got a response "success" 

192 self.assertEqual(response.status_code, 200) 1a

193 

194 # Confirm that of the items, only 10 are displayed due to pagination. 

195 self.assertEqual(len(response.context["bookinstance_list"]), 10) 1a

196 

197 last_date = 0 1a

198 for copy in response.context["bookinstance_list"]: 1a

199 if last_date == 0: 1a

200 last_date = copy.due_back 1a

201 else: 

202 self.assertTrue(last_date <= copy.due_back) 1a

203 

204 

205class RenewBookInstancesViewTest(TestCase): 1a

206 def setUp(self): 1a

207 # Create a user 

208 test_user1 = get_user_model().objects.create_user( 1a

209 username="testuser1", password="1X<ISRUkw+tuK" 

210 ) 

211 test_user1.save() 1a

212 

213 test_user2 = get_user_model().objects.create_user( 1a

214 username="testuser2", password="2HJ1vRV0Z&3iD" 

215 ) 

216 test_user2.save() 1a

217 permission = Permission.objects.get(name="Set book as returned") 1a

218 test_user2.user_permissions.add(permission) 1a

219 test_user2.save() 1a

220 

221 # Create a book 

222 test_author = Author.objects.create(first_name="John", last_name="Smith") 1a

223 test_genre = Genre.objects.create(name="Fantasy") # noqa:F841 1a

224 test_language = Language.objects.create(name="English") 1a

225 test_book = Book.objects.create( 1a

226 title="Book Title", 

227 summary="My book summary", 

228 isbn="ABCDEFG", 

229 author=test_author, 

230 language=test_language, 

231 ) 

232 # Create genre as a post-step 

233 genre_objects_for_book = Genre.objects.all() 1a

234 test_book.genre.set(genre_objects_for_book) 1a

235 test_book.save() 1a

236 

237 # Create a BookInstance object for test_user1 

238 return_date = datetime.date.today() + datetime.timedelta(days=5) 1a

239 self.test_bookinstance1 = BookInstance.objects.create( 1a

240 book=test_book, 

241 imprint="Unlikely Imprint, 2016", 

242 due_back=return_date, 

243 borrower=test_user1, 

244 status="o", 

245 ) 

246 

247 # Create a BookInstance object for test_user2 

248 return_date = datetime.date.today() + datetime.timedelta(days=5) 1a

249 self.test_bookinstance2 = BookInstance.objects.create( 1a

250 book=test_book, 

251 imprint="Unlikely Imprint, 2016", 

252 due_back=return_date, 

253 borrower=test_user2, 

254 status="o", 

255 ) 

256 

257 def test_redirect_if_not_logged_in(self): 1a

258 response = self.client.get( 1a

259 reverse( 

260 "renew-book-librarian", 

261 kwargs={"pk": self.test_bookinstance1.pk}, 

262 ) 

263 ) 

264 # Manually check redirect (Can't use assertRedirect, 

265 # because the redirect URL is unpredictable) 

266 self.assertEqual(response.status_code, 302) 1a

267 self.assertTrue(response.url.startswith("/accounts/login/")) 1a

268 

269 def test_forbidden_if_logged_in_but_not_correct_permission(self): 1a

270 login = self.client.login( # noqa:F841 1a

271 username="testuser1", password="1X<ISRUkw+tuK" 

272 ) 

273 response = self.client.get( 1a

274 reverse( 

275 "renew-book-librarian", 

276 kwargs={"pk": self.test_bookinstance1.pk}, 

277 ) 

278 ) 

279 self.assertEqual(response.status_code, 403) 1a

280 

281 def test_logged_in_with_permission_borrowed_book(self): 1a

282 login = self.client.login( # noqa:F841 1a

283 username="testuser2", password="2HJ1vRV0Z&3iD" 

284 ) 

285 response = self.client.get( 1a

286 reverse( 

287 "renew-book-librarian", 

288 kwargs={"pk": self.test_bookinstance2.pk}, 

289 ) 

290 ) 

291 

292 # Check that it lets us login - this is our book and we have 

293 # the right permissions. 

294 self.assertEqual(response.status_code, 200) 1a

295 

296 def test_logged_in_with_permission_another_users_borrowed_book(self): 1a

297 login = self.client.login( # noqa:F841 1a

298 username="testuser2", password="2HJ1vRV0Z&3iD" 

299 ) 

300 response = self.client.get( 1a

301 reverse( 

302 "renew-book-librarian", 

303 kwargs={"pk": self.test_bookinstance1.pk}, 

304 ) 

305 ) 

306 

307 # Check that it lets us login. We're a librarian, so we can 

308 # view any users book 

309 self.assertEqual(response.status_code, 200) 1a

310 

311 def test_uses_correct_template(self): 1a

312 login = self.client.login( # noqa:F841 1a

313 username="testuser2", password="2HJ1vRV0Z&3iD" 

314 ) 

315 response = self.client.get( 1a

316 reverse( 

317 "renew-book-librarian", 

318 kwargs={"pk": self.test_bookinstance1.pk}, 

319 ) 

320 ) 

321 self.assertEqual(response.status_code, 200) 1a

322 

323 # Check we used correct template 

324 self.assertTemplateUsed(response, "catalog/book_renew_librarian.html") 1a

325 

326 def test_form_renewal_date_initially_has_date_three_weeks_in_future(self): 1a

327 login = self.client.login( # noqa:F841 1a

328 username="testuser2", password="2HJ1vRV0Z&3iD" 

329 ) 

330 response = self.client.get( 1a

331 reverse( 

332 "renew-book-librarian", 

333 kwargs={"pk": self.test_bookinstance1.pk}, 

334 ) 

335 ) 

336 self.assertEqual(response.status_code, 200) 1a

337 

338 date_3_weeks_in_future = datetime.date.today() + datetime.timedelta(weeks=3) 1a

339 self.assertEqual( 1a

340 response.context["form"].initial["renewal_date"], 

341 date_3_weeks_in_future, 

342 ) 

343 

344 """ 1a

345 def test_form_invalid_renewal_date_past(self): 

346 login = self.client.login( # noqa:F841 

347 username="testuser2", password="2HJ1vRV0Z&3iD" 

348 ) 

349 

350 date_in_past = datetime.date.today() - datetime.timedelta(weeks=1) 

351 response = self.client.post( 

352 reverse( 

353 "renew-book-librarian", 

354 kwargs={"pk": self.test_bookinstance1.pk}, 

355 ), 

356 {"renewal_date": date_in_past}, 

357 ) 

358 self.assertEqual(response.status_code, 200) 

359 self.assertFormError( 

360 response, "form", "renewal_date", "Invalid date - renewal in past" 

361 ) 

362 

363 def test_form_invalid_renewal_date_future(self): 

364 login = self.client.login( # noqa:F841 

365 username="testuser2", password="2HJ1vRV0Z&3iD" 

366 ) 

367 

368 invalid_date_in_future = datetime.date.today() + datetime.timedelta(weeks=5) 

369 response = self.client.post( 

370 reverse( 

371 "renew-book-librarian", 

372 kwargs={"pk": self.test_bookinstance1.pk}, 

373 ), 

374 {"renewal_date": invalid_date_in_future}, 

375 ) 

376 self.assertEqual(response.status_code, 200) 

377 self.assertFormError( 

378 response, 

379 "form", 

380 "renewal_date", 

381 "Invalid date - renewal more than 4 weeks ahead", 

382 ) 

383 """ 

384 

385 def test_redirects_to_all_borrowed_book_list_on_success(self): 1a

386 login = self.client.login( # noqa:F841 1a

387 username="testuser2", password="2HJ1vRV0Z&3iD" 

388 ) 

389 valid_date_in_future = datetime.date.today() + datetime.timedelta(weeks=2) 1a

390 response = self.client.post( 1a

391 reverse( 

392 "renew-book-librarian", 

393 kwargs={"pk": self.test_bookinstance1.pk}, 

394 ), 

395 {"renewal_date": valid_date_in_future}, 

396 ) 

397 self.assertRedirects(response, reverse("all-borrowed")) 1a

398 

399 def test_HTTP404_for_invalid_book_if_logged_in(self): 1a

400 import uuid 1a

401 

402 test_uid = uuid.uuid4() # unlikely UID to match our bookinstance! 1a

403 login = self.client.login( # noqa:F841 1a

404 username="testuser2", password="2HJ1vRV0Z&3iD" 

405 ) 

406 response = self.client.get( 1a

407 reverse("renew-book-librarian", kwargs={"pk": test_uid}) 

408 ) 

409 self.assertEqual(response.status_code, 404) 1a

410 

411 

412class AuthorCreateViewTest(TestCase): 1a

413 """Test case for the AuthorCreate view.""" 

414 

415 def setUp(self): 1a

416 # Create a user 

417 test_user1 = get_user_model().objects.create_user( 1a

418 username="testuser1", password="1X<ISRUkw+tuK" 

419 ) 

420 test_user2 = get_user_model().objects.create_user( 1a

421 username="testuser2", password="2HJ1vRV0Z&3iD" 

422 ) 

423 

424 test_user1.save() 1a

425 test_user2.save() 1a

426 

427 permission = Permission.objects.get(name="Set book as returned") 1a

428 test_user2.user_permissions.add(permission) 1a

429 test_user2.save() 1a

430 

431 # Create an author 

432 test_author = Author.objects.create( # noqa:F841 1a

433 first_name="John", last_name="Smith" 

434 ) 

435 

436 def test_redirect_if_not_logged_in(self): 1a

437 response = self.client.get(reverse("author-create")) 1a

438 self.assertRedirects(response, "/accounts/login/?next=/catalog/author/create/") 1a

439 

440 def test_forbidden_if_logged_in_but_not_correct_permission(self): 1a

441 login = self.client.login( # noqa:F841 1a

442 username="testuser1", password="1X<ISRUkw+tuK" 

443 ) 

444 response = self.client.get(reverse("author-create")) 1a

445 self.assertEqual(response.status_code, 403) 1a

446 

447 def test_logged_in_with_permission(self): 1a

448 login = self.client.login( # noqa:F841 1a

449 username="testuser2", password="2HJ1vRV0Z&3iD" 

450 ) 

451 response = self.client.get(reverse("author-create")) 1a

452 self.assertEqual(response.status_code, 200) 1a

453 

454 def test_uses_correct_template(self): 1a

455 login = self.client.login( # noqa:F841 1a

456 username="testuser2", password="2HJ1vRV0Z&3iD" 

457 ) 

458 response = self.client.get(reverse("author-create")) 1a

459 self.assertEqual(response.status_code, 200) 1a

460 self.assertTemplateUsed(response, "catalog/author_create.html") 1a

461 

462 def test_form_date_of_birth_initially_set_to_expected_date(self): 1a

463 login = self.client.login( # noqa:F841 1a

464 username="testuser2", password="2HJ1vRV0Z&3iD" 

465 ) 

466 response = self.client.get(reverse("author-create")) 1a

467 self.assertEqual(response.status_code, 200) 1a

468 

469 expected_initial_date = datetime.date(1882, 2, 2) 1a

470 response_date = response.context["form"].initial["date_of_birth"] 1a

471 response_date = datetime.datetime.strptime(response_date, "%d/%m/%Y").date() 1a

472 self.assertEqual(response_date, expected_initial_date) 1a

473 

474 def test_redirects_to_detail_view_on_success(self): 1a

475 login = self.client.login( # noqa:F841 1a

476 username="testuser2", password="2HJ1vRV0Z&3iD" 

477 ) 

478 response = self.client.post( 1a

479 reverse("author-create"), 

480 {"first_name": "Christian Name", "last_name": "Surname"}, 

481 ) 

482 # Manually check redirect because we don't know what author was created 

483 self.assertEqual(response.status_code, 302) 1a

484 self.assertTrue(response.url.startswith("/catalog/author/")) 1a

485 

486 

487class IndexTests(TestCase): 1a

488 def setUp(self): 1a

489 url = reverse("index") 1a

490 self.response = self.client.get(url) 1a

491 

492 def test_index_status_code(self): 1a

493 self.assertEqual(self.response.status_code, 200) 1a

494 

495 def test_index_url_name(self): 1a

496 self.assertEqual(self.response.status_code, 200) 1a

497 

498 def test_index_contains_correct_html(self): 1a

499 self.assertContains(self.response, "Catalog contents") 1a

500 

501 def test_index_does_not_contain_incorrect_html(self): 1a

502 self.assertNotContains(self.response, "About Page") 1a

503 

504 def test_index_template(self): 1a

505 self.assertTemplateUsed(self.response, "index.html") 1a

506 

507 def test_index_page_url_resolves_index(self): 1a

508 view = resolve("/catalog/") 1a

509 self.assertEqual(view.func.__name__, index.__name__) 1a