Archived
- add uv configuration for the backend - update frontend to make auth work - add new auth endpoints - add bookmars feat - add reader feat
167 lines
4.9 KiB
Python
167 lines
4.9 KiB
Python
"""Tests for the annotations app – Bookmarks & Notes API."""
|
||
|
||
import pytest
|
||
from django.urls import reverse
|
||
from rest_framework import status
|
||
from rest_framework.test import APIClient
|
||
|
||
from apps.annotations.models import Bookmark, Note
|
||
from apps.books.models import Book, EBook
|
||
from apps.users.models import User
|
||
|
||
|
||
@pytest.fixture
|
||
def api_client() -> APIClient:
|
||
return APIClient()
|
||
|
||
|
||
@pytest.fixture
|
||
def user() -> User:
|
||
return User.objects.create_user(
|
||
username="testuser",
|
||
email="test@example.com",
|
||
password="testpass123",
|
||
)
|
||
|
||
|
||
@pytest.fixture
|
||
def other_user() -> User:
|
||
return User.objects.create_user(
|
||
username="other",
|
||
email="other@example.com",
|
||
password="testpass123",
|
||
)
|
||
|
||
|
||
@pytest.fixture
|
||
def auth_client(api_client: APIClient, user: User) -> APIClient:
|
||
api_client.force_authenticate(user=user)
|
||
return api_client
|
||
|
||
|
||
@pytest.fixture
|
||
def book() -> Book:
|
||
return Book.objects.create(
|
||
title="Test Book",
|
||
author="Test Author",
|
||
total_pages=300,
|
||
)
|
||
|
||
|
||
@pytest.fixture
|
||
def ebook(user: User) -> EBook:
|
||
return EBook.objects.create(
|
||
user=user,
|
||
title="Test Ebook",
|
||
author="Test Author",
|
||
format="epub",
|
||
)
|
||
|
||
|
||
@pytest.fixture
|
||
def bookmark(auth_client, user: User, ebook: EBook) -> Bookmark:
|
||
return Bookmark.objects.create(
|
||
user=user,
|
||
ebook=ebook,
|
||
epub_cfi="epubcfi(/6/4!/4/2,/1:0,/1:10)",
|
||
chapter_index=2,
|
||
chapter_title="Chapter 3",
|
||
page=3,
|
||
location_text="important passage",
|
||
content="",
|
||
)
|
||
|
||
|
||
@pytest.fixture
|
||
def note(auth_client, user: User, book: Book) -> Note:
|
||
return Note.objects.create(
|
||
user=user,
|
||
book=book,
|
||
page=15,
|
||
location_text="highlighted section",
|
||
content="This is my note about this section.",
|
||
)
|
||
|
||
|
||
class TestBookmarkList:
|
||
url = reverse("bookmark-list")
|
||
|
||
def test_list_requires_auth(self, api_client: APIClient):
|
||
response = api_client.get(self.url)
|
||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
||
|
||
def test_list_returns_user_bookmarks_only(
|
||
self, auth_client: APIClient, user: User, other_user: User, ebook: EBook
|
||
):
|
||
Bookmark.objects.create(
|
||
user=user,
|
||
ebook=ebook,
|
||
epub_cfi="epubcfi(/6/4!/4/2,/1:0,/1:5)",
|
||
chapter_index=0,
|
||
page=1,
|
||
)
|
||
other_ebook = EBook.objects.create(user=other_user, title="Other", format="epub")
|
||
Bookmark.objects.create(
|
||
user=other_user,
|
||
ebook=other_ebook,
|
||
epub_cfi="epubcfi(/6/4!/4/2,/2:0,/2:5)",
|
||
chapter_index=0,
|
||
page=1,
|
||
)
|
||
response = auth_client.get(self.url)
|
||
assert response.status_code == status.HTTP_200_OK
|
||
results = response.data["results"]
|
||
assert len(results) == 1
|
||
|
||
def test_filter_by_ebook(self, auth_client: APIClient, bookmark: Bookmark, ebook: EBook):
|
||
response = auth_client.get(self.url, {"ebook": str(ebook.id)})
|
||
assert response.status_code == status.HTTP_200_OK
|
||
assert len(response.data["results"]) == 1
|
||
|
||
|
||
class TestBookmarkCreate:
|
||
url = reverse("bookmark-list")
|
||
|
||
def test_create_marker(self, auth_client: APIClient, ebook: EBook):
|
||
data = {
|
||
"ebook": ebook.id,
|
||
"epub_cfi": "epubcfi(/6/4!/4/2,/1:0,/1:20)",
|
||
"chapter_index": 1,
|
||
"chapter_title": "Chapter 2",
|
||
"location_text": "Selected text",
|
||
"content": "My thought",
|
||
}
|
||
response = auth_client.post(self.url, data, format="json")
|
||
assert response.status_code == status.HTTP_201_CREATED
|
||
assert response.data["content"] == "My thought"
|
||
assert response.data["ebook"] == ebook.id
|
||
|
||
def test_create_bookmark_only_empty_content(self, auth_client: APIClient, ebook: EBook):
|
||
data = {
|
||
"ebook": ebook.id,
|
||
"epub_cfi": "epubcfi(/6/4!/4/2,/3:0,/3:8)",
|
||
"chapter_index": 0,
|
||
"location_text": "Quote only",
|
||
"content": "",
|
||
}
|
||
response = auth_client.post(self.url, data, format="json")
|
||
assert response.status_code == status.HTTP_201_CREATED
|
||
assert response.data["content"] == ""
|
||
|
||
def test_duplicate_cfi_rejected(self, auth_client: APIClient, bookmark: Bookmark, ebook: EBook):
|
||
data = {
|
||
"ebook": ebook.id,
|
||
"epub_cfi": bookmark.epub_cfi,
|
||
"chapter_index": 0,
|
||
"location_text": "dup",
|
||
}
|
||
response = auth_client.post(self.url, data, format="json")
|
||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||
|
||
|
||
class TestBookmarkDetail:
|
||
def test_delete_bookmark(self, auth_client: APIClient, bookmark: Bookmark):
|
||
url = reverse("bookmark-detail", args=[str(bookmark.id)])
|
||
response = auth_client.delete(url)
|
||
assert response.status_code == status.HTTP_204_NO_CONTENT
|