Add sort option to bookmark list (#522)

* Rename BookmarkFilters to BookmarkSearch

* Refactor queries to accept BookmarkSearch

* Sort query by data added and title

* Ensure pagination respects search parameters

* Ensure tag cloud respects search parameters

* Ensure user select respects search parameters

* Ensure return url respects search options

* Fix passing search options to user select

* Fix BookmarkSearch initialization

* Extract common search form logic

* Ensure partial update respects search options

* Add sort UI

* Use custom ICU collation when sorting with SQLite

* Support sort in API
This commit is contained in:
Sascha Ißbrücker
2023-09-01 22:48:21 +02:00
committed by GitHub
parent 0c50906056
commit 0975914a86
35 changed files with 1026 additions and 361 deletions

View File

@@ -29,7 +29,7 @@ class BookmarkFactoryMixin:
tags=None,
user: User = None,
url: str = '',
title: str = '',
title: str = None,
description: str = '',
notes: str = '',
website_title: str = '',
@@ -38,7 +38,7 @@ class BookmarkFactoryMixin:
favicon_file: str = '',
added: datetime = None,
):
if not title:
if title is None:
title = get_random_string(length=32)
if tags is None:
tags = []
@@ -81,6 +81,7 @@ class BookmarkFactoryMixin:
with_tags: bool = False,
user: User = None):
user = user or self.get_or_create_test_user()
bookmarks = []
if not prefix:
if archived:
@@ -105,7 +106,11 @@ class BookmarkFactoryMixin:
if with_tags:
tag_name = f'{tag_prefix} {i}{suffix}'
tags = [self.setup_tag(name=tag_name)]
self.setup_bookmark(url=url, title=title, is_archived=archived, shared=shared, tags=tags, user=user)
bookmark = self.setup_bookmark(url=url, title=title, is_archived=archived, shared=shared, tags=tags,
user=user)
bookmarks.append(bookmark)
return bookmarks
def get_numbered_bookmark(self, title: str):
return Bookmark.objects.get(title=title)
@@ -128,6 +133,9 @@ class BookmarkFactoryMixin:
user.profile.save()
return user
def get_random_string(self, length: int = 32):
return get_random_string(length=length)
class HtmlTestMixin:
def make_soup(self, html: str):

View File

@@ -1,3 +1,4 @@
import urllib.parse
from typing import List
from django.contrib.auth.models import User
@@ -55,6 +56,21 @@ class BookmarkArchivedViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin
for tag in tags:
self.assertTrue(tag.name in selected_tags.text, msg=f'Selected tags do not contain: {tag.name}')
def assertEditLink(self, response, url):
html = response.content.decode()
self.assertInHTML(f'''
<a href="{url}">Edit</a>
''', html)
def assertBulkActionForm(self, response, url: str):
html = collapse_whitespace(response.content.decode())
needle = collapse_whitespace(f'''
<form class="bookmark-actions"
action="{url}"
method="post" autocomplete="off">
''')
self.assertIn(needle, html)
def test_should_list_archived_and_user_owned_bookmarks(self):
other_user = User.objects.create_user('otheruser', 'otheruser@example.com', 'password123')
visible_bookmarks = [
@@ -219,6 +235,61 @@ class BookmarkArchivedViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin
self.assertVisibleBookmarks(response, visible_bookmarks, '_self')
def test_edit_link_return_url_respects_search_options(self):
bookmark = self.setup_bookmark(title='foo', is_archived=True)
edit_url = reverse('bookmarks:edit', args=[bookmark.id])
base_url = reverse('bookmarks:archived')
# without query params
return_url = urllib.parse.quote(base_url)
url = f'{edit_url}?return_url={return_url}'
response = self.client.get(base_url)
self.assertEditLink(response, url)
# with query
url_params = '?q=foo'
return_url = urllib.parse.quote(base_url + url_params)
url = f'{edit_url}?return_url={return_url}'
response = self.client.get(base_url + url_params)
self.assertEditLink(response, url)
# with query and sort and page
url_params = '?q=foo&sort=title_asc&page=2'
return_url = urllib.parse.quote(base_url + url_params)
url = f'{edit_url}?return_url={return_url}'
response = self.client.get(base_url + url_params)
self.assertEditLink(response, url)
def test_bulk_edit_respects_search_options(self):
action_url = reverse('bookmarks:archived.action')
base_url = reverse('bookmarks:archived')
# without params
return_url = urllib.parse.quote_plus(base_url)
url = f'{action_url}?return_url={return_url}'
response = self.client.get(base_url)
self.assertBulkActionForm(response, url)
# with query
url_params = '?q=foo'
return_url = urllib.parse.quote_plus(base_url + url_params)
url = f'{action_url}?q=foo&return_url={return_url}'
response = self.client.get(base_url + url_params)
self.assertBulkActionForm(response, url)
# with query and sort
url_params = '?q=foo&sort=title_asc'
return_url = urllib.parse.quote_plus(base_url + url_params)
url = f'{action_url}?q=foo&sort=title_asc&return_url={return_url}'
response = self.client.get(base_url + url_params)
self.assertBulkActionForm(response, url)
def test_allowed_bulk_actions(self):
url = reverse('bookmarks:archived')
response = self.client.get(url)

View File

@@ -1,5 +1,5 @@
from typing import List
import urllib.parse
from typing import List
from django.contrib.auth.models import User
from django.test import TestCase
@@ -56,6 +56,21 @@ class BookmarkIndexViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
for tag in tags:
self.assertTrue(tag.name in selected_tags.text, msg=f'Selected tags do not contain: {tag.name}')
def assertEditLink(self, response, url):
html = response.content.decode()
self.assertInHTML(f'''
<a href="{url}">Edit</a>
''', html)
def assertBulkActionForm(self, response, url: str):
html = collapse_whitespace(response.content.decode())
needle = collapse_whitespace(f'''
<form class="bookmark-actions"
action="{url}"
method="post" autocomplete="off">
''')
self.assertIn(needle, html)
def test_should_list_unarchived_and_user_owned_bookmarks(self):
other_user = User.objects.create_user('otheruser', 'otheruser@example.com', 'password123')
visible_bookmarks = [
@@ -220,30 +235,60 @@ class BookmarkIndexViewTestCase(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
self.assertVisibleBookmarks(response, visible_bookmarks, '_self')
def test_edit_link_return_url_should_contain_query_params(self):
def test_edit_link_return_url_respects_search_options(self):
bookmark = self.setup_bookmark(title='foo')
edit_url = reverse('bookmarks:edit', args=[bookmark.id])
base_url = reverse('bookmarks:index')
# without query params
url = reverse('bookmarks:index')
response = self.client.get(url)
html = response.content.decode()
edit_url = reverse('bookmarks:edit', args=[bookmark.id])
return_url = urllib.parse.quote_plus(url)
return_url = urllib.parse.quote(base_url)
url = f'{edit_url}?return_url={return_url}'
self.assertInHTML(f'''
<a href="{edit_url}?return_url={return_url}">Edit</a>
''', html)
response = self.client.get(base_url)
self.assertEditLink(response, url)
# with query params
url = reverse('bookmarks:index') + '?q=foo&user=user'
response = self.client.get(url)
html = response.content.decode()
edit_url = reverse('bookmarks:edit', args=[bookmark.id])
return_url = urllib.parse.quote_plus(url)
# with query
url_params = '?q=foo'
return_url = urllib.parse.quote(base_url + url_params)
url = f'{edit_url}?return_url={return_url}'
self.assertInHTML(f'''
<a href="{edit_url}?return_url={return_url}">Edit</a>
''', html)
response = self.client.get(base_url + url_params)
self.assertEditLink(response, url)
# with query and sort and page
url_params = '?q=foo&sort=title_asc&page=2'
return_url = urllib.parse.quote(base_url + url_params)
url = f'{edit_url}?return_url={return_url}'
response = self.client.get(base_url + url_params)
self.assertEditLink(response, url)
def test_bulk_edit_respects_search_options(self):
action_url = reverse('bookmarks:index.action')
base_url = reverse('bookmarks:index')
# without params
return_url = urllib.parse.quote_plus(base_url)
url = f'{action_url}?return_url={return_url}'
response = self.client.get(base_url)
self.assertBulkActionForm(response, url)
# with query
url_params = '?q=foo'
return_url = urllib.parse.quote_plus(base_url + url_params)
url = f'{action_url}?q=foo&return_url={return_url}'
response = self.client.get(base_url + url_params)
self.assertBulkActionForm(response, url)
# with query and sort
url_params = '?q=foo&sort=title_asc'
return_url = urllib.parse.quote_plus(base_url + url_params)
url = f'{action_url}?q=foo&sort=title_asc&return_url={return_url}'
response = self.client.get(base_url + url_params)
self.assertBulkActionForm(response, url)
def test_allowed_bulk_actions(self):
url = reverse('bookmarks:index')

View File

@@ -0,0 +1,58 @@
from django.test import TestCase
from bookmarks.models import BookmarkSearch, BookmarkSearchForm
from bookmarks.tests.helpers import BookmarkFactoryMixin
class BookmarkSearchFormTest(TestCase, BookmarkFactoryMixin):
def test_initial_values(self):
# no params
search = BookmarkSearch()
form = BookmarkSearchForm(search)
self.assertEqual(form['q'].initial, '')
self.assertEqual(form['sort'].initial, BookmarkSearch.SORT_ADDED_DESC)
self.assertEqual(form['user'].initial, '')
# with params
search = BookmarkSearch(q='search query', sort=BookmarkSearch.SORT_ADDED_ASC, user='user123')
form = BookmarkSearchForm(search)
self.assertEqual(form['q'].initial, 'search query')
self.assertEqual(form['sort'].initial, BookmarkSearch.SORT_ADDED_ASC)
self.assertEqual(form['user'].initial, 'user123')
def test_user_options(self):
users = [
self.setup_user('user1'),
self.setup_user('user2'),
self.setup_user('user3'),
]
search = BookmarkSearch()
form = BookmarkSearchForm(search, users=users)
self.assertCountEqual(form['user'].field.choices, [
('', 'Everyone'),
('user1', 'user1'),
('user2', 'user2'),
('user3', 'user3'),
])
def test_hidden_fields(self):
# no modified params
search = BookmarkSearch()
form = BookmarkSearchForm(search)
self.assertEqual(len(form.hidden_fields()), 0)
# some modified params
search = BookmarkSearch(q='search query', sort=BookmarkSearch.SORT_ADDED_ASC)
form = BookmarkSearchForm(search)
self.assertCountEqual(form.hidden_fields(), [form['q'], form['sort']])
# all modified params
search = BookmarkSearch(q='search query', sort=BookmarkSearch.SORT_ADDED_ASC, user='user123')
form = BookmarkSearchForm(search)
self.assertCountEqual(form.hidden_fields(), [form['q'], form['sort'], form['user']])
# some modified params are editable fields
search = BookmarkSearch(q='search query', sort=BookmarkSearch.SORT_ADDED_ASC, user='user123')
form = BookmarkSearchForm(search, editable_fields=['q', 'user'])
self.assertCountEqual(form.hidden_fields(), [form['sort']])

View File

@@ -0,0 +1,59 @@
from unittest.mock import Mock
from bookmarks.models import BookmarkSearch
from django.test import TestCase
class BookmarkSearchModelTest(TestCase):
def test_from_request(self):
# no params
mock_request = Mock()
mock_request.GET = {}
search = BookmarkSearch.from_request(mock_request)
self.assertEqual(search.q, '')
self.assertEqual(search.sort, BookmarkSearch.SORT_ADDED_DESC)
self.assertEqual(search.user, '')
# some params
mock_request.GET = {
'q': 'search query',
'user': 'user123',
}
bookmark_search = BookmarkSearch.from_request(mock_request)
self.assertEqual(bookmark_search.q, 'search query')
self.assertEqual(bookmark_search.sort, BookmarkSearch.SORT_ADDED_DESC)
self.assertEqual(bookmark_search.user, 'user123')
# all params
mock_request.GET = {
'q': 'search query',
'user': 'user123',
'sort': BookmarkSearch.SORT_TITLE_ASC
}
search = BookmarkSearch.from_request(mock_request)
self.assertEqual(search.q, 'search query')
self.assertEqual(search.user, 'user123')
self.assertEqual(search.sort, BookmarkSearch.SORT_TITLE_ASC)
def test_modified_params(self):
# no params
bookmark_search = BookmarkSearch()
modified_params = bookmark_search.modified_params
self.assertEqual(len(modified_params), 0)
# params are default values
bookmark_search = BookmarkSearch(q='', sort=BookmarkSearch.SORT_ADDED_DESC, user='')
modified_params = bookmark_search.modified_params
self.assertEqual(len(modified_params), 0)
# some modified params
bookmark_search = BookmarkSearch(q='search query', sort=BookmarkSearch.SORT_ADDED_ASC)
modified_params = bookmark_search.modified_params
self.assertCountEqual(modified_params, ['q', 'sort'])
# all modified params
bookmark_search = BookmarkSearch(q='search query', sort=BookmarkSearch.SORT_ADDED_ASC, user='user123')
modified_params = bookmark_search.modified_params
self.assertCountEqual(modified_params, ['q', 'sort', 'user'])

View File

@@ -2,7 +2,7 @@ from django.db.models import QuerySet
from django.template import Template, RequestContext
from django.test import TestCase, RequestFactory
from bookmarks.models import BookmarkFilters, Tag
from bookmarks.models import BookmarkSearch, Tag
from bookmarks.tests.helpers import BookmarkFactoryMixin
@@ -12,31 +12,43 @@ class BookmarkSearchTagTest(TestCase, BookmarkFactoryMixin):
request = rf.get(url)
request.user = self.get_or_create_test_user()
request.user_profile = self.get_or_create_test_user().profile
filters = BookmarkFilters(request)
search = BookmarkSearch.from_request(request)
context = RequestContext(request, {
'request': request,
'filters': filters,
'search': search,
'tags': tags,
})
template_to_render = Template(
'{% load bookmarks %}'
'{% bookmark_search filters tags %}'
'{% bookmark_search search tags %}'
)
return template_to_render.render(context)
def test_render_hidden_inputs_for_filter_params(self):
# Should render hidden inputs if query param exists
url = '/test?q=foo&user=john'
def assertHiddenInput(self, html: str, name: str, value: str = None):
needle = f'<input type="hidden" name="{name}"'
if value is not None:
needle += f' value="{value}"'
self.assertIn(needle, html)
def assertNoHiddenInput(self, html: str, name: str):
needle = f'<input type="hidden" name="{name}"'
self.assertNotIn(needle, html)
def test_hidden_inputs(self):
# Without params
url = '/test'
rendered_template = self.render_template(url)
self.assertInHTML('''
<input type="hidden" name="user" value="john">
''', rendered_template)
self.assertNoHiddenInput(rendered_template, 'user')
self.assertNoHiddenInput(rendered_template, 'q')
self.assertNoHiddenInput(rendered_template, 'sort')
# Should not render hidden inputs if query param does not exist
url = '/test?q=foo'
# With params
url = '/test?q=foo&user=john&sort=title_asc'
rendered_template = self.render_template(url)
self.assertInHTML('''
<input type="hidden" name="user" value="john">
''', rendered_template, count=0)
self.assertHiddenInput(rendered_template, 'user', 'john')
self.assertNoHiddenInput(rendered_template, 'q')
self.assertNoHiddenInput(rendered_template, 'sort')

View File

@@ -1,3 +1,4 @@
import urllib.parse
from typing import List
from django.contrib.auth.models import User
@@ -45,24 +46,25 @@ class BookmarkSharedViewTestCase(TestCase, BookmarkFactoryMixin):
def assertVisibleUserOptions(self, response, users: List[User]):
html = response.content.decode()
self.assertContains(response, 'data-is-user-option', count=len(users))
user_options = [
'<option value="" selected="">Everyone</option>'
]
for user in users:
self.assertInHTML(f'''
<option value="{user.username}" data-is-user-option>
{user.username}
</option>
''', html)
user_options.append(f'<option value="{user.username}">{user.username}</option>')
user_select_html = f'''
<select name="user" class="form-select" required="" id="id_user">
{''.join(user_options)}
</select>
'''
def assertInvisibleUserOptions(self, response, users: List[User]):
self.assertInHTML(user_select_html, html)
def assertEditLink(self, response, url):
html = response.content.decode()
for user in users:
self.assertInHTML(f'''
<option value="{user.username}" data-is-user-option>
{user.username}
</option>
''', html, count=0)
self.assertInHTML(f'''
<a href="{url}">Edit</a>
''', html)
def test_should_list_shared_bookmarks_from_all_users_that_have_sharing_enabled(self):
self.authenticate()
@@ -267,41 +269,33 @@ class BookmarkSharedViewTestCase(TestCase, BookmarkFactoryMixin):
def test_should_list_users_with_shared_bookmarks_if_sharing_is_enabled(self):
self.authenticate()
expected_visible_users = [
self.setup_user(enable_sharing=True),
self.setup_user(enable_sharing=True),
self.setup_user(name='user_a', enable_sharing=True),
self.setup_user(name='user_b', enable_sharing=True),
]
self.setup_bookmark(shared=True, user=expected_visible_users[0])
self.setup_bookmark(shared=True, user=expected_visible_users[1])
expected_invisible_users = [
self.setup_user(enable_sharing=True),
self.setup_user(enable_sharing=False),
]
self.setup_bookmark(shared=False, user=expected_invisible_users[0])
self.setup_bookmark(shared=True, user=expected_invisible_users[1])
self.setup_bookmark(shared=False, user=self.setup_user(enable_sharing=True))
self.setup_bookmark(shared=True, user=self.setup_user(enable_sharing=False))
response = self.client.get(reverse('bookmarks:shared'))
self.assertVisibleUserOptions(response, expected_visible_users)
self.assertInvisibleUserOptions(response, expected_invisible_users)
def test_should_list_only_users_with_publicly_shared_bookmarks_without_login(self):
# users with public sharing enabled
expected_visible_users = [
self.setup_user(enable_sharing=True, enable_public_sharing=True),
self.setup_user(enable_sharing=True, enable_public_sharing=True),
self.setup_user(name='user_a', enable_sharing=True, enable_public_sharing=True),
self.setup_user(name='user_b', enable_sharing=True, enable_public_sharing=True),
]
self.setup_bookmark(shared=True, user=expected_visible_users[0])
self.setup_bookmark(shared=True, user=expected_visible_users[1])
expected_invisible_users = [
self.setup_user(enable_sharing=True),
self.setup_user(enable_sharing=True),
]
self.setup_bookmark(shared=True, user=expected_invisible_users[0])
self.setup_bookmark(shared=True, user=expected_invisible_users[1])
# users with public sharing disabled
self.setup_bookmark(shared=True, user=self.setup_user(enable_sharing=True))
self.setup_bookmark(shared=True, user=self.setup_user(enable_sharing=True))
response = self.client.get(reverse('bookmarks:shared'))
self.assertVisibleUserOptions(response, expected_visible_users)
self.assertInvisibleUserOptions(response, expected_invisible_users)
def test_should_open_bookmarks_in_new_page_by_default(self):
self.authenticate()
@@ -334,3 +328,44 @@ class BookmarkSharedViewTestCase(TestCase, BookmarkFactoryMixin):
response = self.client.get(reverse('bookmarks:shared'))
self.assertVisibleBookmarks(response, visible_bookmarks, '_self')
def test_edit_link_return_url_respects_search_options(self):
self.authenticate()
user = self.get_or_create_test_user()
user.profile.enable_sharing = True
user.profile.save()
bookmark = self.setup_bookmark(title='foo', shared=True, user=user)
edit_url = reverse('bookmarks:edit', args=[bookmark.id])
base_url = reverse('bookmarks:shared')
# without query params
return_url = urllib.parse.quote(base_url)
url = f'{edit_url}?return_url={return_url}'
response = self.client.get(base_url)
self.assertEditLink(response, url)
# with query
url_params = '?q=foo'
return_url = urllib.parse.quote(base_url + url_params)
url = f'{edit_url}?return_url={return_url}'
response = self.client.get(base_url + url_params)
self.assertEditLink(response, url)
# with query and user
url_params = f'?q=foo&user={user.username}'
return_url = urllib.parse.quote(base_url + url_params)
url = f'{edit_url}?return_url={return_url}'
response = self.client.get(base_url + url_params)
self.assertEditLink(response, url)
# with query and sort and page
url_params = '?q=foo&sort=title_asc&page=2'
return_url = urllib.parse.quote(base_url + url_params)
url = f'{edit_url}?return_url={return_url}'
response = self.client.get(base_url + url_params)
self.assertEditLink(response, url)

View File

@@ -15,15 +15,6 @@ from bookmarks.tests.helpers import LinkdingApiTestCase, BookmarkFactoryMixin
class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
def setUp(self) -> None:
self.tag1 = self.setup_tag()
self.tag2 = self.setup_tag()
self.bookmark1 = self.setup_bookmark(tags=[self.tag1, self.tag2], notes='Test notes')
self.bookmark2 = self.setup_bookmark()
self.bookmark3 = self.setup_bookmark(tags=[self.tag2])
self.archived_bookmark1 = self.setup_bookmark(is_archived=True, tags=[self.tag1, self.tag2])
self.archived_bookmark2 = self.setup_bookmark(is_archived=True)
def authenticate(self):
self.api_token = Token.objects.get_or_create(user=self.get_or_create_test_user())[0]
self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.api_token.key)
@@ -56,29 +47,64 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
def test_list_bookmarks(self):
self.authenticate()
bookmarks = self.setup_numbered_bookmarks(5)
response = self.get(reverse('bookmarks:bookmark-list'), expected_status_code=status.HTTP_200_OK)
self.assertBookmarkListEqual(response.data['results'], [self.bookmark1, self.bookmark2, self.bookmark3])
self.assertBookmarkListEqual(response.data['results'], bookmarks)
def test_list_bookmarks_does_not_return_archived_bookmarks(self):
self.authenticate()
bookmarks = self.setup_numbered_bookmarks(5)
self.setup_numbered_bookmarks(5, archived=True)
response = self.get(reverse('bookmarks:bookmark-list'), expected_status_code=status.HTTP_200_OK)
self.assertBookmarkListEqual(response.data['results'], bookmarks)
def test_list_bookmarks_should_filter_by_query(self):
self.authenticate()
search_value = self.get_random_string()
bookmarks = self.setup_numbered_bookmarks(5, prefix=search_value)
self.setup_numbered_bookmarks(5)
response = self.get(reverse('bookmarks:bookmark-list') + '?q=#' + self.tag1.name,
response = self.get(reverse('bookmarks:bookmark-list') + '?q=' + search_value,
expected_status_code=status.HTTP_200_OK)
self.assertBookmarkListEqual(response.data['results'], [self.bookmark1])
self.assertBookmarkListEqual(response.data['results'], bookmarks)
def test_list_bookmarks_should_respect_sort(self):
self.authenticate()
bookmarks = self.setup_numbered_bookmarks(5)
bookmarks.reverse()
response = self.get(reverse('bookmarks:bookmark-list') + '?sort=title_desc',
expected_status_code=status.HTTP_200_OK)
self.assertBookmarkListEqual(response.data['results'], bookmarks)
def test_list_archived_bookmarks_does_not_return_unarchived_bookmarks(self):
self.authenticate()
self.setup_numbered_bookmarks(5)
archived_bookmarks = self.setup_numbered_bookmarks(5, archived=True)
response = self.get(reverse('bookmarks:bookmark-archived'), expected_status_code=status.HTTP_200_OK)
self.assertBookmarkListEqual(response.data['results'], [self.archived_bookmark1, self.archived_bookmark2])
self.assertBookmarkListEqual(response.data['results'], archived_bookmarks)
def test_list_archived_bookmarks_should_filter_by_query(self):
self.authenticate()
search_value = self.get_random_string()
archived_bookmarks = self.setup_numbered_bookmarks(5, archived=True, prefix=search_value)
self.setup_numbered_bookmarks(5, archived=True)
response = self.get(reverse('bookmarks:bookmark-archived') + '?q=#' + self.tag1.name,
response = self.get(reverse('bookmarks:bookmark-archived') + '?q=' + search_value,
expected_status_code=status.HTTP_200_OK)
self.assertBookmarkListEqual(response.data['results'], [self.archived_bookmark1])
self.assertBookmarkListEqual(response.data['results'], archived_bookmarks)
def test_list_archived_bookmarks_should_respect_sort(self):
self.authenticate()
bookmarks = self.setup_numbered_bookmarks(5, archived=True)
bookmarks.reverse()
response = self.get(reverse('bookmarks:bookmark-archived') + '?sort=title_desc',
expected_status_code=status.HTTP_200_OK)
self.assertBookmarkListEqual(response.data['results'], bookmarks)
def test_list_shared_bookmarks(self):
self.authenticate()
@@ -158,6 +184,16 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
expected_status_code=status.HTTP_200_OK)
self.assertBookmarkListEqual(response.data['results'], expected_bookmarks)
def test_list_shared_bookmarks_should_respect_sort(self):
self.authenticate()
user = self.setup_user(enable_sharing=True)
bookmarks = self.setup_numbered_bookmarks(5, shared=True, user=user)
bookmarks.reverse()
response = self.get(reverse('bookmarks:bookmark-shared') + '?sort=title_desc',
expected_status_code=status.HTTP_200_OK)
self.assertBookmarkListEqual(response.data['results'], bookmarks)
def test_create_bookmark(self):
self.authenticate()
@@ -295,34 +331,38 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
def test_get_bookmark(self):
self.authenticate()
bookmark = self.setup_bookmark()
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
url = reverse('bookmarks:bookmark-detail', args=[bookmark.id])
response = self.get(url, expected_status_code=status.HTTP_200_OK)
self.assertBookmarkListEqual([response.data], [self.bookmark1])
self.assertBookmarkListEqual([response.data], [bookmark])
def test_update_bookmark(self):
self.authenticate()
bookmark = self.setup_bookmark()
data = {'url': 'https://example.com/'}
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
data = {'url': 'https://example.com/updated'}
url = reverse('bookmarks:bookmark-detail', args=[bookmark.id])
self.put(url, data, expected_status_code=status.HTTP_200_OK)
updated_bookmark = Bookmark.objects.get(id=self.bookmark1.id)
updated_bookmark = Bookmark.objects.get(id=bookmark.id)
self.assertEqual(updated_bookmark.url, data['url'])
def test_update_bookmark_fails_without_required_fields(self):
self.authenticate()
bookmark = self.setup_bookmark()
data = {'title': 'https://example.com/'}
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
url = reverse('bookmarks:bookmark-detail', args=[bookmark.id])
self.put(url, data, expected_status_code=status.HTTP_400_BAD_REQUEST)
def test_update_bookmark_with_minimal_payload_clears_all_fields(self):
self.authenticate()
bookmark = self.setup_bookmark()
data = {'url': 'https://example.com/'}
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
url = reverse('bookmarks:bookmark-detail', args=[bookmark.id])
self.put(url, data, expected_status_code=status.HTTP_200_OK)
updated_bookmark = Bookmark.objects.get(id=self.bookmark1.id)
updated_bookmark = Bookmark.objects.get(id=bookmark.id)
self.assertEqual(updated_bookmark.url, data['url'])
self.assertEqual(updated_bookmark.title, '')
self.assertEqual(updated_bookmark.description, '')
@@ -331,112 +371,119 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
def test_update_bookmark_unread_flag(self):
self.authenticate()
bookmark = self.setup_bookmark()
data = {'url': 'https://example.com/', 'unread': True}
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
url = reverse('bookmarks:bookmark-detail', args=[bookmark.id])
self.put(url, data, expected_status_code=status.HTTP_200_OK)
updated_bookmark = Bookmark.objects.get(id=self.bookmark1.id)
updated_bookmark = Bookmark.objects.get(id=bookmark.id)
self.assertEqual(updated_bookmark.unread, True)
def test_update_bookmark_shared_flag(self):
self.authenticate()
bookmark = self.setup_bookmark()
data = {'url': 'https://example.com/', 'shared': True}
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
url = reverse('bookmarks:bookmark-detail', args=[bookmark.id])
self.put(url, data, expected_status_code=status.HTTP_200_OK)
updated_bookmark = Bookmark.objects.get(id=self.bookmark1.id)
updated_bookmark = Bookmark.objects.get(id=bookmark.id)
self.assertEqual(updated_bookmark.shared, True)
def test_patch_bookmark(self):
self.authenticate()
bookmark = self.setup_bookmark()
data = {'url': 'https://example.com'}
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
url = reverse('bookmarks:bookmark-detail', args=[bookmark.id])
self.patch(url, data, expected_status_code=status.HTTP_200_OK)
self.bookmark1.refresh_from_db()
self.assertEqual(self.bookmark1.url, data['url'])
bookmark.refresh_from_db()
self.assertEqual(bookmark.url, data['url'])
data = {'title': 'Updated title'}
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
url = reverse('bookmarks:bookmark-detail', args=[bookmark.id])
self.patch(url, data, expected_status_code=status.HTTP_200_OK)
self.bookmark1.refresh_from_db()
self.assertEqual(self.bookmark1.title, data['title'])
bookmark.refresh_from_db()
self.assertEqual(bookmark.title, data['title'])
data = {'description': 'Updated description'}
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
url = reverse('bookmarks:bookmark-detail', args=[bookmark.id])
self.patch(url, data, expected_status_code=status.HTTP_200_OK)
self.bookmark1.refresh_from_db()
self.assertEqual(self.bookmark1.description, data['description'])
bookmark.refresh_from_db()
self.assertEqual(bookmark.description, data['description'])
data = {'notes': 'Updated notes'}
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
url = reverse('bookmarks:bookmark-detail', args=[bookmark.id])
self.patch(url, data, expected_status_code=status.HTTP_200_OK)
self.bookmark1.refresh_from_db()
self.assertEqual(self.bookmark1.notes, data['notes'])
bookmark.refresh_from_db()
self.assertEqual(bookmark.notes, data['notes'])
data = {'unread': True}
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
url = reverse('bookmarks:bookmark-detail', args=[bookmark.id])
self.patch(url, data, expected_status_code=status.HTTP_200_OK)
self.bookmark1.refresh_from_db()
self.assertTrue(self.bookmark1.unread)
bookmark.refresh_from_db()
self.assertTrue(bookmark.unread)
data = {'unread': False}
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
url = reverse('bookmarks:bookmark-detail', args=[bookmark.id])
self.patch(url, data, expected_status_code=status.HTTP_200_OK)
self.bookmark1.refresh_from_db()
self.assertFalse(self.bookmark1.unread)
bookmark.refresh_from_db()
self.assertFalse(bookmark.unread)
data = {'shared': True}
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
url = reverse('bookmarks:bookmark-detail', args=[bookmark.id])
self.patch(url, data, expected_status_code=status.HTTP_200_OK)
self.bookmark1.refresh_from_db()
self.assertTrue(self.bookmark1.shared)
bookmark.refresh_from_db()
self.assertTrue(bookmark.shared)
data = {'shared': False}
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
url = reverse('bookmarks:bookmark-detail', args=[bookmark.id])
self.patch(url, data, expected_status_code=status.HTTP_200_OK)
self.bookmark1.refresh_from_db()
self.assertFalse(self.bookmark1.shared)
bookmark.refresh_from_db()
self.assertFalse(bookmark.shared)
data = {'tag_names': ['updated-tag-1', 'updated-tag-2']}
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
url = reverse('bookmarks:bookmark-detail', args=[bookmark.id])
self.patch(url, data, expected_status_code=status.HTTP_200_OK)
self.bookmark1.refresh_from_db()
tag_names = [tag.name for tag in self.bookmark1.tags.all()]
bookmark.refresh_from_db()
tag_names = [tag.name for tag in bookmark.tags.all()]
self.assertListEqual(tag_names, ['updated-tag-1', 'updated-tag-2'])
def test_patch_with_empty_payload_does_not_modify_bookmark(self):
self.authenticate()
bookmark = self.setup_bookmark()
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
url = reverse('bookmarks:bookmark-detail', args=[bookmark.id])
self.patch(url, {}, expected_status_code=status.HTTP_200_OK)
updated_bookmark = Bookmark.objects.get(id=self.bookmark1.id)
self.assertEqual(updated_bookmark.url, self.bookmark1.url)
self.assertEqual(updated_bookmark.title, self.bookmark1.title)
self.assertEqual(updated_bookmark.description, self.bookmark1.description)
self.assertListEqual(updated_bookmark.tag_names, self.bookmark1.tag_names)
updated_bookmark = Bookmark.objects.get(id=bookmark.id)
self.assertEqual(updated_bookmark.url, bookmark.url)
self.assertEqual(updated_bookmark.title, bookmark.title)
self.assertEqual(updated_bookmark.description, bookmark.description)
self.assertListEqual(updated_bookmark.tag_names, bookmark.tag_names)
def test_delete_bookmark(self):
self.authenticate()
bookmark = self.setup_bookmark()
url = reverse('bookmarks:bookmark-detail', args=[self.bookmark1.id])
url = reverse('bookmarks:bookmark-detail', args=[bookmark.id])
self.delete(url, expected_status_code=status.HTTP_204_NO_CONTENT)
self.assertEqual(len(Bookmark.objects.filter(id=self.bookmark1.id)), 0)
self.assertEqual(len(Bookmark.objects.filter(id=bookmark.id)), 0)
def test_archive(self):
self.authenticate()
bookmark = self.setup_bookmark()
url = reverse('bookmarks:bookmark-archive', args=[self.bookmark1.id])
url = reverse('bookmarks:bookmark-archive', args=[bookmark.id])
self.post(url, expected_status_code=status.HTTP_204_NO_CONTENT)
bookmark = Bookmark.objects.get(id=self.bookmark1.id)
bookmark = Bookmark.objects.get(id=bookmark.id)
self.assertTrue(bookmark.is_archived)
def test_unarchive(self):
self.authenticate()
bookmark = self.setup_bookmark(is_archived=True)
url = reverse('bookmarks:bookmark-unarchive', args=[self.archived_bookmark1.id])
url = reverse('bookmarks:bookmark-unarchive', args=[bookmark.id])
self.post(url, expected_status_code=status.HTTP_204_NO_CONTENT)
bookmark = Bookmark.objects.get(id=self.archived_bookmark1.id)
bookmark = Bookmark.objects.get(id=bookmark.id)
self.assertFalse(bookmark.is_archived)
def test_check_returns_no_bookmark_if_url_is_not_bookmarked(self):
@@ -509,6 +556,8 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
def test_can_only_access_own_bookmarks(self):
self.authenticate()
self.setup_bookmark()
self.setup_bookmark(is_archived=True)
other_user = User.objects.create_user('otheruser', 'otheruser@example.com', 'password123')
inaccessible_bookmark = self.setup_bookmark(user=other_user)
@@ -517,11 +566,11 @@ class BookmarksApiTestCase(LinkdingApiTestCase, BookmarkFactoryMixin):
url = reverse('bookmarks:bookmark-list')
response = self.get(url, expected_status_code=status.HTTP_200_OK)
self.assertEqual(len(response.data['results']), 3)
self.assertEqual(len(response.data['results']), 1)
url = reverse('bookmarks:bookmark-archived')
response = self.get(url, expected_status_code=status.HTTP_200_OK)
self.assertEqual(len(response.data['results']), 2)
self.assertEqual(len(response.data['results']), 1)
url = reverse('bookmarks:bookmark-detail', args=[inaccessible_bookmark.id])
self.get(url, expected_status_code=status.HTTP_404_NOT_FOUND)

View File

@@ -55,7 +55,7 @@ class BookmarkListTemplateTest(TestCase, BookmarkFactoryMixin):
# Edit link
edit_url = reverse('bookmarks:edit', args=[bookmark.id])
self.assertInHTML(f'''
<a href="{edit_url}?return_url=%2Fbookmarks">Edit</a>
<a href="{edit_url}?return_url=/bookmarks">Edit</a>
''', html, count=count)
# Archive link
self.assertInHTML(f'''

View File

@@ -113,9 +113,9 @@ class PaginationTagTest(TestCase, BookmarkFactoryMixin):
self.assertPageLink(rendered_template, page_number, page_number == current_page, expected_occurrences)
self.assertTruncationIndicators(rendered_template, 1)
def test_extend_existing_query(self):
rendered_template = self.render_template(100, 10, 2, url='/test?q=cake')
self.assertPrevLink(rendered_template, 1, href='?q=cake&page=1')
self.assertPageLink(rendered_template, 1, False, href='?q=cake&page=1')
self.assertPageLink(rendered_template, 2, True, href='?q=cake&page=2')
self.assertNextLink(rendered_template, 3, href='?q=cake&page=3')
def test_respects_search_parameters(self):
rendered_template = self.render_template(100, 10, 2, url='/test?q=cake&sort=title_asc&page=2')
self.assertPrevLink(rendered_template, 1, href='?q=cake&sort=title_asc&page=1')
self.assertPageLink(rendered_template, 1, False, href='?q=cake&sort=title_asc&page=1')
self.assertPageLink(rendered_template, 2, True, href='?q=cake&sort=title_asc&page=2')
self.assertNextLink(rendered_template, 3, href='?q=cake&sort=title_asc&page=3')

View File

@@ -3,9 +3,10 @@ import operator
from django.contrib.auth import get_user_model
from django.db.models import QuerySet
from django.test import TestCase
from django.utils import timezone
from bookmarks import queries
from bookmarks.models import Bookmark, UserProfile
from bookmarks.models import Bookmark, BookmarkSearch, UserProfile
from bookmarks.tests.helpers import BookmarkFactoryMixin, random_sentence
from bookmarks.utils import unique
@@ -163,7 +164,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
def test_query_bookmarks_should_return_all_for_empty_query(self):
self.setup_bookmark_search_data()
query = queries.query_bookmarks(self.user, self.profile, '')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query=''))
self.assertQueryResult(query, [
self.other_bookmarks,
self.term1_bookmarks,
@@ -178,7 +179,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
def test_query_bookmarks_should_search_single_term(self):
self.setup_bookmark_search_data()
query = queries.query_bookmarks(self.user, self.profile, 'term1')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='term1'))
self.assertQueryResult(query, [
self.term1_bookmarks,
self.term1_term2_bookmarks,
@@ -188,35 +189,35 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
def test_query_bookmarks_should_search_multiple_terms(self):
self.setup_bookmark_search_data()
query = queries.query_bookmarks(self.user, self.profile, 'term2 term1')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='term2 term1'))
self.assertQueryResult(query, [self.term1_term2_bookmarks])
def test_query_bookmarks_should_search_single_tag(self):
self.setup_bookmark_search_data()
query = queries.query_bookmarks(self.user, self.profile, '#tag1')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='#tag1'))
self.assertQueryResult(query, [self.tag1_bookmarks, self.tag1_tag2_bookmarks, self.term1_tag1_bookmarks])
def test_query_bookmarks_should_search_multiple_tags(self):
self.setup_bookmark_search_data()
query = queries.query_bookmarks(self.user, self.profile, '#tag1 #tag2')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='#tag1 #tag2'))
self.assertQueryResult(query, [self.tag1_tag2_bookmarks])
def test_query_bookmarks_should_search_multiple_tags_ignoring_casing(self):
self.setup_bookmark_search_data()
query = queries.query_bookmarks(self.user, self.profile, '#Tag1 #TAG2')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='#Tag1 #TAG2'))
self.assertQueryResult(query, [self.tag1_tag2_bookmarks])
def test_query_bookmarks_should_search_terms_and_tags_combined(self):
self.setup_bookmark_search_data()
query = queries.query_bookmarks(self.user, self.profile, 'term1 #tag1')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='term1 #tag1'))
self.assertQueryResult(query, [self.term1_tag1_bookmarks])
@@ -226,7 +227,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.profile.tag_search = UserProfile.TAG_SEARCH_STRICT
self.profile.save()
query = queries.query_bookmarks(self.user, self.profile, 'tag1')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='tag1'))
self.assertQueryResult(query, [self.tag1_as_term_bookmarks])
def test_query_bookmarks_in_lax_mode_should_search_tags_as_terms(self):
@@ -235,7 +236,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.profile.tag_search = UserProfile.TAG_SEARCH_LAX
self.profile.save()
query = queries.query_bookmarks(self.user, self.profile, 'tag1')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='tag1'))
self.assertQueryResult(query, [
self.tag1_bookmarks,
self.tag1_as_term_bookmarks,
@@ -243,17 +244,17 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.term1_tag1_bookmarks
])
query = queries.query_bookmarks(self.user, self.profile, 'tag1 term1')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='tag1 term1'))
self.assertQueryResult(query, [
self.term1_tag1_bookmarks,
])
query = queries.query_bookmarks(self.user, self.profile, 'tag1 tag2')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='tag1 tag2'))
self.assertQueryResult(query, [
self.tag1_tag2_bookmarks,
])
query = queries.query_bookmarks(self.user, self.profile, 'tag1 #tag2')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='tag1 #tag2'))
self.assertQueryResult(query, [
self.tag1_tag2_bookmarks,
])
@@ -261,28 +262,28 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
def test_query_bookmarks_should_return_no_matches(self):
self.setup_bookmark_search_data()
query = queries.query_bookmarks(self.user, self.profile, 'term3')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='term3'))
self.assertQueryResult(query, [])
query = queries.query_bookmarks(self.user, self.profile, 'term1 term3')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='term1 term3'))
self.assertQueryResult(query, [])
query = queries.query_bookmarks(self.user, self.profile, 'term1 #tag2')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='term1 #tag2'))
self.assertQueryResult(query, [])
query = queries.query_bookmarks(self.user, self.profile, '#tag3')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='#tag3'))
self.assertQueryResult(query, [])
# Unused tag
query = queries.query_bookmarks(self.user, self.profile, '#unused_tag1')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='#unused_tag1'))
self.assertQueryResult(query, [])
# Unused tag combined with tag that is used
query = queries.query_bookmarks(self.user, self.profile, '#tag1 #unused_tag1')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='#tag1 #unused_tag1'))
self.assertQueryResult(query, [])
# Unused tag combined with term that is used
query = queries.query_bookmarks(self.user, self.profile, 'term1 #unused_tag1')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='term1 #unused_tag1'))
self.assertQueryResult(query, [])
def test_query_bookmarks_should_not_return_archived_bookmarks(self):
@@ -292,7 +293,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark(is_archived=True)
self.setup_bookmark(is_archived=True)
query = queries.query_bookmarks(self.user, self.profile, '')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query=''))
self.assertQueryResult(query, [[bookmark1, bookmark2]])
@@ -303,7 +304,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark()
self.setup_bookmark()
query = queries.query_archived_bookmarks(self.user, self.profile, '')
query = queries.query_archived_bookmarks(self.user, self.profile, BookmarkSearch(query=''))
self.assertQueryResult(query, [[bookmark1, bookmark2]])
@@ -318,7 +319,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark(user=other_user)
self.setup_bookmark(user=other_user)
query = queries.query_bookmarks(self.user, self.profile, '')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query=''))
self.assertQueryResult(query, [owned_bookmarks])
@@ -333,7 +334,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark(is_archived=True, user=other_user)
self.setup_bookmark(is_archived=True, user=other_user)
query = queries.query_archived_bookmarks(self.user, self.profile, '')
query = queries.query_archived_bookmarks(self.user, self.profile, BookmarkSearch(query=''))
self.assertQueryResult(query, [owned_bookmarks])
@@ -343,7 +344,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark(tags=[tag])
self.setup_bookmark(tags=[tag])
query = queries.query_bookmarks(self.user, self.profile, '!untagged')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='!untagged'))
self.assertCountEqual(list(query), [untagged_bookmark])
def test_query_bookmarks_untagged_should_be_combinable_with_search_terms(self):
@@ -352,7 +353,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark(title='term2')
self.setup_bookmark(tags=[tag])
query = queries.query_bookmarks(self.user, self.profile, '!untagged term1')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='!untagged term1'))
self.assertCountEqual(list(query), [untagged_bookmark])
def test_query_bookmarks_untagged_should_not_be_combinable_with_tags(self):
@@ -361,7 +362,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark(tags=[tag])
self.setup_bookmark(tags=[tag])
query = queries.query_bookmarks(self.user, self.profile, f'!untagged #{tag.name}')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query=f'!untagged #{tag.name}'))
self.assertCountEqual(list(query), [])
def test_query_archived_bookmarks_untagged_should_return_untagged_bookmarks_only(self):
@@ -370,7 +371,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark(is_archived=True, tags=[tag])
self.setup_bookmark(is_archived=True, tags=[tag])
query = queries.query_archived_bookmarks(self.user, self.profile, '!untagged')
query = queries.query_archived_bookmarks(self.user, self.profile, BookmarkSearch(query='!untagged'))
self.assertCountEqual(list(query), [untagged_bookmark])
def test_query_archived_bookmarks_untagged_should_be_combinable_with_search_terms(self):
@@ -379,7 +380,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark(is_archived=True, title='term2')
self.setup_bookmark(is_archived=True, tags=[tag])
query = queries.query_archived_bookmarks(self.user, self.profile, '!untagged term1')
query = queries.query_archived_bookmarks(self.user, self.profile, BookmarkSearch(query='!untagged term1'))
self.assertCountEqual(list(query), [untagged_bookmark])
def test_query_archived_bookmarks_untagged_should_not_be_combinable_with_tags(self):
@@ -388,7 +389,8 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark(is_archived=True, tags=[tag])
self.setup_bookmark(is_archived=True, tags=[tag])
query = queries.query_archived_bookmarks(self.user, self.profile, f'!untagged #{tag.name}')
query = queries.query_archived_bookmarks(self.user, self.profile,
BookmarkSearch(query=f'!untagged #{tag.name}'))
self.assertCountEqual(list(query), [])
def test_query_bookmarks_unread_should_return_unread_bookmarks_only(self):
@@ -401,7 +403,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark()
self.setup_bookmark()
query = queries.query_bookmarks(self.user, self.profile, '!unread')
query = queries.query_bookmarks(self.user, self.profile, BookmarkSearch(query='!unread'))
self.assertCountEqual(list(query), unread_bookmarks)
def test_query_archived_bookmarks_unread_should_return_unread_bookmarks_only(self):
@@ -414,13 +416,13 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark(is_archived=True)
self.setup_bookmark(is_archived=True)
query = queries.query_archived_bookmarks(self.user, self.profile, '!unread')
query = queries.query_archived_bookmarks(self.user, self.profile, BookmarkSearch(query='!unread'))
self.assertCountEqual(list(query), unread_bookmarks)
def test_query_bookmark_tags_should_return_all_tags_for_empty_query(self):
self.setup_tag_search_data()
query = queries.query_bookmark_tags(self.user, self.profile, '')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query=''))
self.assertQueryResult(query, [
self.get_tags_from_bookmarks(self.other_bookmarks),
@@ -435,7 +437,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
def test_query_bookmark_tags_should_search_single_term(self):
self.setup_tag_search_data()
query = queries.query_bookmark_tags(self.user, self.profile, 'term1')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='term1'))
self.assertQueryResult(query, [
self.get_tags_from_bookmarks(self.term1_bookmarks),
@@ -446,7 +448,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
def test_query_bookmark_tags_should_search_multiple_terms(self):
self.setup_tag_search_data()
query = queries.query_bookmark_tags(self.user, self.profile, 'term2 term1')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='term2 term1'))
self.assertQueryResult(query, [
self.get_tags_from_bookmarks(self.term1_term2_bookmarks),
@@ -455,7 +457,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
def test_query_bookmark_tags_should_search_single_tag(self):
self.setup_tag_search_data()
query = queries.query_bookmark_tags(self.user, self.profile, '#tag1')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='#tag1'))
self.assertQueryResult(query, [
self.get_tags_from_bookmarks(self.tag1_bookmarks),
@@ -466,7 +468,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
def test_query_bookmark_tags_should_search_multiple_tags(self):
self.setup_tag_search_data()
query = queries.query_bookmark_tags(self.user, self.profile, '#tag1 #tag2')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='#tag1 #tag2'))
self.assertQueryResult(query, [
self.get_tags_from_bookmarks(self.tag1_tag2_bookmarks),
@@ -475,7 +477,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
def test_query_bookmark_tags_should_search_multiple_tags_ignoring_casing(self):
self.setup_tag_search_data()
query = queries.query_bookmark_tags(self.user, self.profile, '#Tag1 #TAG2')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='#Tag1 #TAG2'))
self.assertQueryResult(query, [
self.get_tags_from_bookmarks(self.tag1_tag2_bookmarks),
@@ -484,7 +486,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
def test_query_bookmark_tags_should_search_term_and_tag_combined(self):
self.setup_tag_search_data()
query = queries.query_bookmark_tags(self.user, self.profile, 'term1 #tag1')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='term1 #tag1'))
self.assertQueryResult(query, [
self.get_tags_from_bookmarks(self.term1_tag1_bookmarks),
@@ -496,7 +498,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.profile.tag_search = UserProfile.TAG_SEARCH_STRICT
self.profile.save()
query = queries.query_bookmark_tags(self.user, self.profile, 'tag1')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='tag1'))
self.assertQueryResult(query, self.get_tags_from_bookmarks(self.tag1_as_term_bookmarks))
def test_query_bookmark_tags_in_lax_mode_should_search_tags_as_terms(self):
@@ -505,7 +507,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.profile.tag_search = UserProfile.TAG_SEARCH_LAX
self.profile.save()
query = queries.query_bookmark_tags(self.user, self.profile, 'tag1')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='tag1'))
self.assertQueryResult(query, [
self.get_tags_from_bookmarks(self.tag1_bookmarks),
self.get_tags_from_bookmarks(self.tag1_as_term_bookmarks),
@@ -513,17 +515,17 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.get_tags_from_bookmarks(self.term1_tag1_bookmarks)
])
query = queries.query_bookmark_tags(self.user, self.profile, 'tag1 term1')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='tag1 term1'))
self.assertQueryResult(query, [
self.get_tags_from_bookmarks(self.term1_tag1_bookmarks),
])
query = queries.query_bookmark_tags(self.user, self.profile, 'tag1 tag2')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='tag1 tag2'))
self.assertQueryResult(query, [
self.get_tags_from_bookmarks(self.tag1_tag2_bookmarks),
])
query = queries.query_bookmark_tags(self.user, self.profile, 'tag1 #tag2')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='tag1 #tag2'))
self.assertQueryResult(query, [
self.get_tags_from_bookmarks(self.tag1_tag2_bookmarks),
])
@@ -531,28 +533,28 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
def test_query_bookmark_tags_should_return_no_matches(self):
self.setup_tag_search_data()
query = queries.query_bookmark_tags(self.user, self.profile, 'term3')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='term3'))
self.assertQueryResult(query, [])
query = queries.query_bookmark_tags(self.user, self.profile, 'term1 term3')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='term1 term3'))
self.assertQueryResult(query, [])
query = queries.query_bookmark_tags(self.user, self.profile, 'term1 #tag2')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='term1 #tag2'))
self.assertQueryResult(query, [])
query = queries.query_bookmark_tags(self.user, self.profile, '#tag3')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='#tag3'))
self.assertQueryResult(query, [])
# Unused tag
query = queries.query_bookmark_tags(self.user, self.profile, '#unused_tag1')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='#unused_tag1'))
self.assertQueryResult(query, [])
# Unused tag combined with tag that is used
query = queries.query_bookmark_tags(self.user, self.profile, '#tag1 #unused_tag1')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='#tag1 #unused_tag1'))
self.assertQueryResult(query, [])
# Unused tag combined with term that is used
query = queries.query_bookmark_tags(self.user, self.profile, 'term1 #unused_tag1')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='term1 #unused_tag1'))
self.assertQueryResult(query, [])
def test_query_bookmark_tags_should_return_tags_for_unarchived_bookmarks_only(self):
@@ -562,7 +564,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark()
self.setup_bookmark(is_archived=True, tags=[tag2])
query = queries.query_bookmark_tags(self.user, self.profile, '')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query=''))
self.assertQueryResult(query, [[tag1]])
@@ -572,7 +574,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark(tags=[tag])
self.setup_bookmark(tags=[tag])
query = queries.query_bookmark_tags(self.user, self.profile, '')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query=''))
self.assertQueryResult(query, [[tag]])
@@ -583,7 +585,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark()
self.setup_bookmark(is_archived=True, tags=[tag2])
query = queries.query_archived_bookmark_tags(self.user, self.profile, '')
query = queries.query_archived_bookmark_tags(self.user, self.profile, BookmarkSearch(query=''))
self.assertQueryResult(query, [[tag2]])
@@ -593,7 +595,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark(is_archived=True, tags=[tag])
self.setup_bookmark(is_archived=True, tags=[tag])
query = queries.query_archived_bookmark_tags(self.user, self.profile, '')
query = queries.query_archived_bookmark_tags(self.user, self.profile, BookmarkSearch(query=''))
self.assertQueryResult(query, [[tag]])
@@ -608,7 +610,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark(user=other_user, tags=[self.setup_tag(user=other_user)])
self.setup_bookmark(user=other_user, tags=[self.setup_tag(user=other_user)])
query = queries.query_bookmark_tags(self.user, self.profile, '')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query=''))
self.assertQueryResult(query, [self.get_tags_from_bookmarks(owned_bookmarks)])
@@ -623,7 +625,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark(is_archived=True, user=other_user, tags=[self.setup_tag(user=other_user)])
self.setup_bookmark(is_archived=True, user=other_user, tags=[self.setup_tag(user=other_user)])
query = queries.query_archived_bookmark_tags(self.user, self.profile, '')
query = queries.query_archived_bookmark_tags(self.user, self.profile, BookmarkSearch(query=''))
self.assertQueryResult(query, [self.get_tags_from_bookmarks(owned_bookmarks)])
@@ -634,13 +636,13 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark(title='term1', tags=[tag])
self.setup_bookmark(tags=[tag])
query = queries.query_bookmark_tags(self.user, self.profile, '!untagged')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='!untagged'))
self.assertCountEqual(list(query), [])
query = queries.query_bookmark_tags(self.user, self.profile, '!untagged term1')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query='!untagged term1'))
self.assertCountEqual(list(query), [])
query = queries.query_bookmark_tags(self.user, self.profile, f'!untagged #{tag.name}')
query = queries.query_bookmark_tags(self.user, self.profile, BookmarkSearch(query=f'!untagged #{tag.name}'))
self.assertCountEqual(list(query), [])
def test_query_archived_bookmark_tags_untagged_should_never_return_any_tags(self):
@@ -650,13 +652,14 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark(is_archived=True, title='term1', tags=[tag])
self.setup_bookmark(is_archived=True, tags=[tag])
query = queries.query_archived_bookmark_tags(self.user, self.profile, '!untagged')
query = queries.query_archived_bookmark_tags(self.user, self.profile, BookmarkSearch(query='!untagged'))
self.assertCountEqual(list(query), [])
query = queries.query_archived_bookmark_tags(self.user, self.profile, '!untagged term1')
query = queries.query_archived_bookmark_tags(self.user, self.profile, BookmarkSearch(query='!untagged term1'))
self.assertCountEqual(list(query), [])
query = queries.query_archived_bookmark_tags(self.user, self.profile, f'!untagged #{tag.name}')
query = queries.query_archived_bookmark_tags(self.user, self.profile,
BookmarkSearch(query=f'!untagged #{tag.name}'))
self.assertCountEqual(list(query), [])
def test_query_shared_bookmarks(self):
@@ -679,14 +682,14 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark(user=user4, shared=True, tags=[tag]),
# Should return shared bookmarks from all users
query_set = queries.query_shared_bookmarks(None, self.profile, '', False)
query_set = queries.query_shared_bookmarks(None, self.profile, BookmarkSearch(query=''), False)
self.assertQueryResult(query_set, [shared_bookmarks])
# Should respect search query
query_set = queries.query_shared_bookmarks(None, self.profile, 'test title', False)
query_set = queries.query_shared_bookmarks(None, self.profile, BookmarkSearch(query='test title'), False)
self.assertQueryResult(query_set, [[shared_bookmarks[0]]])
query_set = queries.query_shared_bookmarks(None, self.profile, '#' + tag.name, False)
query_set = queries.query_shared_bookmarks(None, self.profile, BookmarkSearch(query=f'#{tag.name}'), False)
self.assertQueryResult(query_set, [[shared_bookmarks[2]]])
def test_query_publicly_shared_bookmarks(self):
@@ -696,7 +699,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
bookmark1 = self.setup_bookmark(user=user1, shared=True)
self.setup_bookmark(user=user2, shared=True)
query_set = queries.query_shared_bookmarks(None, self.profile, '', True)
query_set = queries.query_shared_bookmarks(None, self.profile, BookmarkSearch(query=''), True)
self.assertQueryResult(query_set, [[bookmark1]])
def test_query_shared_bookmark_tags(self):
@@ -720,7 +723,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark(user=user3, shared=False, tags=[self.setup_tag(user=user3)]),
self.setup_bookmark(user=user4, shared=True, tags=[self.setup_tag(user=user4)]),
query_set = queries.query_shared_bookmark_tags(None, self.profile, '', False)
query_set = queries.query_shared_bookmark_tags(None, self.profile, BookmarkSearch(query=''), False)
self.assertQueryResult(query_set, [shared_tags])
@@ -734,7 +737,7 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark(user=user1, shared=True, tags=[tag1]),
self.setup_bookmark(user=user2, shared=True, tags=[tag2]),
query_set = queries.query_shared_bookmark_tags(None, self.profile, '', True)
query_set = queries.query_shared_bookmark_tags(None, self.profile, BookmarkSearch(query=''), True)
self.assertQueryResult(query_set, [[tag1]])
@@ -759,11 +762,11 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark(user=users_without_shared_bookmarks[2], shared=True),
# Should return users with shared bookmarks
query_set = queries.query_shared_bookmark_users(self.profile, '', False)
query_set = queries.query_shared_bookmark_users(self.profile, BookmarkSearch(query=''), False)
self.assertQueryResult(query_set, [users_with_shared_bookmarks])
# Should respect search query
query_set = queries.query_shared_bookmark_users(self.profile, 'test title', False)
query_set = queries.query_shared_bookmark_users(self.profile, BookmarkSearch(query='test title'), False)
self.assertQueryResult(query_set, [[users_with_shared_bookmarks[0]]])
def test_query_publicly_shared_bookmark_users(self):
@@ -773,5 +776,91 @@ class QueriesTestCase(TestCase, BookmarkFactoryMixin):
self.setup_bookmark(user=user1, shared=True)
self.setup_bookmark(user=user2, shared=True)
query_set = queries.query_shared_bookmark_users(self.profile, '', True)
query_set = queries.query_shared_bookmark_users(self.profile, BookmarkSearch(query=''), True)
self.assertQueryResult(query_set, [[user1]])
def test_sorty_by_date_added_asc(self):
search = BookmarkSearch(sort=BookmarkSearch.SORT_ADDED_ASC)
bookmarks = [
self.setup_bookmark(added=timezone.datetime(2020, 1, 1, tzinfo=timezone.utc)),
self.setup_bookmark(added=timezone.datetime(2021, 2, 1, tzinfo=timezone.utc)),
self.setup_bookmark(added=timezone.datetime(2022, 3, 1, tzinfo=timezone.utc)),
self.setup_bookmark(added=timezone.datetime(2023, 4, 1, tzinfo=timezone.utc)),
self.setup_bookmark(added=timezone.datetime(2022, 5, 1, tzinfo=timezone.utc)),
self.setup_bookmark(added=timezone.datetime(2021, 6, 1, tzinfo=timezone.utc)),
self.setup_bookmark(added=timezone.datetime(2020, 7, 1, tzinfo=timezone.utc)),
]
sorted_bookmarks = sorted(bookmarks, key=lambda b: b.date_added)
query = queries.query_bookmarks(self.user, self.profile, search)
self.assertEqual(list(query), sorted_bookmarks)
def test_sorty_by_date_added_desc(self):
search = BookmarkSearch(sort=BookmarkSearch.SORT_ADDED_DESC)
bookmarks = [
self.setup_bookmark(added=timezone.datetime(2020, 1, 1, tzinfo=timezone.utc)),
self.setup_bookmark(added=timezone.datetime(2021, 2, 1, tzinfo=timezone.utc)),
self.setup_bookmark(added=timezone.datetime(2022, 3, 1, tzinfo=timezone.utc)),
self.setup_bookmark(added=timezone.datetime(2023, 4, 1, tzinfo=timezone.utc)),
self.setup_bookmark(added=timezone.datetime(2022, 5, 1, tzinfo=timezone.utc)),
self.setup_bookmark(added=timezone.datetime(2021, 6, 1, tzinfo=timezone.utc)),
self.setup_bookmark(added=timezone.datetime(2020, 7, 1, tzinfo=timezone.utc)),
]
sorted_bookmarks = sorted(bookmarks, key=lambda b: b.date_added, reverse=True)
query = queries.query_bookmarks(self.user, self.profile, search)
self.assertEqual(list(query), sorted_bookmarks)
def setup_title_sort_data(self):
# lots of combinations to test effective title logic
bookmarks = [
self.setup_bookmark(title='a_1_1'),
self.setup_bookmark(title='A_1_2'),
self.setup_bookmark(title='b_1_1'),
self.setup_bookmark(title='B_1_2'),
self.setup_bookmark(title='', website_title='a_2_1'),
self.setup_bookmark(title='', website_title='A_2_2'),
self.setup_bookmark(title='', website_title='b_2_1'),
self.setup_bookmark(title='', website_title='B_2_2'),
self.setup_bookmark(title='', website_title='', url='a_3_1'),
self.setup_bookmark(title='', website_title='', url='A_3_2'),
self.setup_bookmark(title='', website_title='', url='b_3_1'),
self.setup_bookmark(title='', website_title='', url='B_3_2'),
self.setup_bookmark(title='a_4_1', website_title='0'),
self.setup_bookmark(title='A_4_2', website_title='0'),
self.setup_bookmark(title='b_4_1', website_title='0'),
self.setup_bookmark(title='B_4_2', website_title='0'),
self.setup_bookmark(title='a_5_1', url='0'),
self.setup_bookmark(title='A_5_2', url='0'),
self.setup_bookmark(title='b_5_1', url='0'),
self.setup_bookmark(title='B_5_2', url='0'),
self.setup_bookmark(title='', website_title='a_6_1', url='0'),
self.setup_bookmark(title='', website_title='A_6_2', url='0'),
self.setup_bookmark(title='', website_title='b_6_1', url='0'),
self.setup_bookmark(title='', website_title='B_6_2', url='0'),
self.setup_bookmark(title='a_7_1', website_title='0', url='0'),
self.setup_bookmark(title='A_7_2', website_title='0', url='0'),
self.setup_bookmark(title='b_7_1', website_title='0', url='0'),
self.setup_bookmark(title='B_7_2', website_title='0', url='0'),
]
return bookmarks
def test_sort_by_title_asc(self):
search = BookmarkSearch(sort=BookmarkSearch.SORT_TITLE_ASC)
bookmarks = self.setup_title_sort_data()
sorted_bookmarks = sorted(bookmarks, key=lambda b: b.resolved_title.lower())
query = queries.query_bookmarks(self.user, self.profile, search)
self.assertEqual(list(query), sorted_bookmarks)
def test_sort_by_title_desc(self):
search = BookmarkSearch(sort=BookmarkSearch.SORT_TITLE_DESC)
bookmarks = self.setup_title_sort_data()
sorted_bookmarks = sorted(bookmarks, key=lambda b: b.resolved_title.lower(), reverse=True)
query = queries.query_bookmarks(self.user, self.profile, search)
self.assertEqual(list(query), sorted_bookmarks)

View File

@@ -101,6 +101,18 @@ class TagCloudTemplateTest(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
],
])
def test_tag_url_respects_search_options(self):
tag = self.setup_tag(name='tag1')
self.setup_bookmark(tags=[tag], title='term1')
rendered_template = self.render_template(url='/test?q=term1&sort=title_asc&page=2')
self.assertInHTML('''
<a href="?q=term1+%23tag1&sort=title_asc&page=2" class="mr-2" data-is-tag-item>
<span class="highlight-char">t</span><span>ag1</span>
</a>
''', rendered_template)
def test_selected_tags(self):
tags = [
self.setup_tag(name='tag1'),
@@ -191,7 +203,7 @@ class TagCloudTemplateTest(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
</a>
''', rendered_template, count=1)
def test_selected_tag_url_keeps_other_search_terms(self):
def test_selected_tag_url_keeps_other_query_terms(self):
tag = self.setup_tag(name='tag1')
self.setup_bookmark(tags=[tag], title='term1', description='term2')
@@ -204,6 +216,19 @@ class TagCloudTemplateTest(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
</a>
''', rendered_template)
def test_selected_tag_url_respects_search_options(self):
tag = self.setup_tag(name='tag1')
self.setup_bookmark(tags=[tag], title='term1', description='term2')
rendered_template = self.render_template(url='/test?q=term1 %23tag1 term2&sort=title_asc&page=2')
self.assertInHTML('''
<a href="?q=term1+term2&sort=title_asc&page=2"
class="text-bold mr-2">
<span>-tag1</span>
</a>
''', rendered_template)
def test_selected_tags_are_excluded_from_groups(self):
tags = [
self.setup_tag(name='tag1'),

View File

@@ -2,7 +2,7 @@ from django.db.models import QuerySet
from django.template import Template, RequestContext
from django.test import TestCase, RequestFactory
from bookmarks.models import BookmarkFilters, User
from bookmarks.models import BookmarkSearch, User
from bookmarks.tests.helpers import BookmarkFactoryMixin
@@ -12,32 +12,42 @@ class UserSelectTagTest(TestCase, BookmarkFactoryMixin):
request = rf.get(url)
request.user = self.get_or_create_test_user()
request.user_profile = self.get_or_create_test_user().profile
filters = BookmarkFilters(request)
search = BookmarkSearch.from_request(request)
context = RequestContext(request, {
'request': request,
'filters': filters,
'search': search,
'users': users,
})
template_to_render = Template(
'{% load bookmarks %}'
'{% user_select filters users %}'
'{% user_select search users %}'
)
return template_to_render.render(context)
def assertUserOption(self, html: str, user: User, selected: bool = False):
self.assertInHTML(f'''
<option value="{user.username}"
{'selected' if selected else ''}
data-is-user-option>
<option value="{user.username}" {'selected' if selected else ''}>
{user.username}
</option>
''', html)
def assertHiddenInput(self, html: str, name: str, value: str = None):
needle = f'<input type="hidden" name="{name}"'
if value is not None:
needle += f' value="{value}"'
self.assertIn(needle, html)
def assertNoHiddenInput(self, html: str, name: str):
needle = f'<input type="hidden" name="{name}"'
self.assertNotIn(needle, html)
def test_empty_option(self):
rendered_template = self.render_template('/test')
self.assertInHTML(f'''
<option value="">Everyone</option>
<option value="" selected="">Everyone</option>
''', rendered_template)
def test_render_user_options(self):
@@ -60,19 +70,19 @@ class UserSelectTagTest(TestCase, BookmarkFactoryMixin):
self.assertUserOption(rendered_template, user1, True)
def test_render_hidden_inputs_for_filter_params(self):
# Should render hidden inputs if query param exists
url = '/test?q=foo&user=john'
def test_hidden_inputs(self):
# Without params
url = '/test'
rendered_template = self.render_template(url)
self.assertInHTML('''
<input type="hidden" name="q" value="foo">
''', rendered_template)
self.assertNoHiddenInput(rendered_template, 'user')
self.assertNoHiddenInput(rendered_template, 'q')
self.assertNoHiddenInput(rendered_template, 'sort')
# Should not render hidden inputs if query param does not exist
url = '/test?user=john'
# With params
url = '/test?q=foo&user=john&sort=title_asc'
rendered_template = self.render_template(url)
self.assertInHTML('''
<input type="hidden" name="q" value="foo">
''', rendered_template, count=0)
self.assertNoHiddenInput(rendered_template, 'user')
self.assertHiddenInput(rendered_template, 'q', 'foo')
self.assertHiddenInput(rendered_template, 'sort', 'title_asc')