mirror of
https://github.com/sissbruecker/linkding
synced 2024-11-21 19:03:02 +00:00
Add settings view tests
This commit is contained in:
parent
9aa17d0528
commit
3e48b22095
11 changed files with 272 additions and 10 deletions
|
@ -3,6 +3,7 @@ from dataclasses import dataclass
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
from bookmarks.models import Bookmark, parse_tag_string
|
from bookmarks.models import Bookmark, parse_tag_string
|
||||||
from bookmarks.services.parser import parse, NetscapeBookmark
|
from bookmarks.services.parser import parse, NetscapeBookmark
|
||||||
|
@ -45,7 +46,10 @@ def _import_bookmark_tag(netscape_bookmark: NetscapeBookmark, user: User):
|
||||||
bookmark = _get_or_create_bookmark(netscape_bookmark.href, user)
|
bookmark = _get_or_create_bookmark(netscape_bookmark.href, user)
|
||||||
|
|
||||||
bookmark.url = netscape_bookmark.href
|
bookmark.url = netscape_bookmark.href
|
||||||
bookmark.date_added = datetime.utcfromtimestamp(int(netscape_bookmark.date_added)).astimezone()
|
if netscape_bookmark.date_added:
|
||||||
|
bookmark.date_added = datetime.utcfromtimestamp(int(netscape_bookmark.date_added)).astimezone()
|
||||||
|
else:
|
||||||
|
bookmark.date_added = timezone.now()
|
||||||
bookmark.date_modified = bookmark.date_added
|
bookmark.date_modified = bookmark.date_added
|
||||||
bookmark.unread = False
|
bookmark.unread = False
|
||||||
bookmark.title = netscape_bookmark.title
|
bookmark.title = netscape_bookmark.title
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
import pyparsing as pp
|
import pyparsing as pp
|
||||||
|
|
||||||
|
@ -9,7 +8,7 @@ class NetscapeBookmark:
|
||||||
href: str
|
href: str
|
||||||
title: str
|
title: str
|
||||||
description: str
|
description: str
|
||||||
date_added: int
|
date_added: str
|
||||||
tag_string: str
|
tag_string: str
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,8 +16,7 @@ def extract_bookmark_link(tag):
|
||||||
href = tag[0].href
|
href = tag[0].href
|
||||||
title = tag[0].text
|
title = tag[0].text
|
||||||
tag_string = tag[0].tags
|
tag_string = tag[0].tags
|
||||||
date_added_string = tag[0].add_date if tag[0].add_date else datetime.now().timestamp()
|
date_added = tag[0].add_date
|
||||||
date_added = int(date_added_string)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'href': href,
|
'href': href,
|
||||||
|
|
BIN
bookmarks/tests/resources/invalid_import_file.png
Normal file
BIN
bookmarks/tests/resources/invalid_import_file.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
20
bookmarks/tests/resources/simple_valid_import_file.html
Normal file
20
bookmarks/tests/resources/simple_valid_import_file.html
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<!DOCTYPE NETSCAPE-Bookmark-file-1>
|
||||||
|
|
||||||
|
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
|
||||||
|
|
||||||
|
<TITLE>Bookmarks</TITLE>
|
||||||
|
|
||||||
|
<H1>Bookmarks</H1>
|
||||||
|
|
||||||
|
<DL><p>
|
||||||
|
|
||||||
|
<DT><A HREF="https://example.com/1" ADD_DATE="1616337559" PRIVATE="0" TOREAD="0" TAGS="tag1">test title 1</A>
|
||||||
|
<DD>test description 1
|
||||||
|
|
||||||
|
<DT><A HREF="https://example.com/2" ADD_DATE="1616337559" PRIVATE="0" TOREAD="0" TAGS="tag2">test title 2</A>
|
||||||
|
<DD>test description 2
|
||||||
|
|
||||||
|
<DT><A HREF="https://example.com/3" ADD_DATE="1616337559" PRIVATE="0" TOREAD="0" TAGS="tag3">test title 3</A>
|
||||||
|
<DD>test description 3
|
||||||
|
|
||||||
|
</DL><p>
|
|
@ -0,0 +1,20 @@
|
||||||
|
<!DOCTYPE NETSCAPE-Bookmark-file-1>
|
||||||
|
|
||||||
|
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
|
||||||
|
|
||||||
|
<TITLE>Bookmarks</TITLE>
|
||||||
|
|
||||||
|
<H1>Bookmarks</H1>
|
||||||
|
|
||||||
|
<DL><p>
|
||||||
|
|
||||||
|
<DT><A HREF="https://example.com/1" ADD_DATE="invaliddate" PRIVATE="0" TOREAD="0" TAGS="tag1">test title 1</A>
|
||||||
|
<DD>test description 1
|
||||||
|
|
||||||
|
<DT><A HREF="https://example.com/2" ADD_DATE="1616337559" PRIVATE="0" TOREAD="0" TAGS="tag2">test title 2</A>
|
||||||
|
<DD>test description 2
|
||||||
|
|
||||||
|
<DT><A HREF="https://example.com/3" ADD_DATE="1616337559" PRIVATE="0" TOREAD="0" TAGS="tag3">test title 3</A>
|
||||||
|
<DD>test description 3
|
||||||
|
|
||||||
|
</DL><p>
|
40
bookmarks/tests/test_settings_api_view.py
Normal file
40
bookmarks/tests/test_settings_api_view.py
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.urls import reverse
|
||||||
|
from rest_framework.authtoken.models import Token
|
||||||
|
|
||||||
|
from bookmarks.tests.helpers import BookmarkFactoryMixin
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsApiViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||||
|
|
||||||
|
def setUp(self) -> None:
|
||||||
|
user = self.get_or_create_test_user()
|
||||||
|
self.client.force_login(user)
|
||||||
|
|
||||||
|
def test_should_render_successfully(self):
|
||||||
|
response = self.client.get(reverse('bookmarks:settings.api'))
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_should_check_authentication(self):
|
||||||
|
self.client.logout()
|
||||||
|
response = self.client.get(reverse('bookmarks:settings.api'), follow=True)
|
||||||
|
|
||||||
|
self.assertRedirects(response, reverse('login') + '?next=' + reverse('bookmarks:settings.api'))
|
||||||
|
|
||||||
|
def test_should_generate_api_token_if_not_exists(self):
|
||||||
|
self.assertEqual(Token.objects.count(), 0)
|
||||||
|
|
||||||
|
self.client.get(reverse('bookmarks:settings.api'))
|
||||||
|
|
||||||
|
self.assertEqual(Token.objects.count(), 1)
|
||||||
|
token = Token.objects.first()
|
||||||
|
self.assertEqual(token.user, self.user)
|
||||||
|
|
||||||
|
def test_should_not_generate_api_token_if_exists(self):
|
||||||
|
Token.objects.get_or_create(user=self.user)
|
||||||
|
self.assertEqual(Token.objects.count(), 1)
|
||||||
|
|
||||||
|
self.client.get(reverse('bookmarks:settings.api'))
|
||||||
|
|
||||||
|
self.assertEqual(Token.objects.count(), 1)
|
45
bookmarks/tests/test_settings_export_view.py
Normal file
45
bookmarks/tests/test_settings_export_view.py
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
from bookmarks.tests.helpers import BookmarkFactoryMixin
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsExportViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||||
|
|
||||||
|
def setUp(self) -> None:
|
||||||
|
user = self.get_or_create_test_user()
|
||||||
|
self.client.force_login(user)
|
||||||
|
|
||||||
|
def assertFormErrorHint(self, response, text: str):
|
||||||
|
self.assertContains(response, '<div class="has-error">')
|
||||||
|
self.assertContains(response, text)
|
||||||
|
|
||||||
|
def test_should_export_successfully(self):
|
||||||
|
self.setup_bookmark(tags=[self.setup_tag()])
|
||||||
|
self.setup_bookmark(tags=[self.setup_tag()])
|
||||||
|
self.setup_bookmark(tags=[self.setup_tag()])
|
||||||
|
|
||||||
|
response = self.client.get(
|
||||||
|
reverse('bookmarks:settings.export'),
|
||||||
|
follow=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(response['content-type'], 'text/plain; charset=UTF-8')
|
||||||
|
self.assertEqual(response['Content-Disposition'], 'attachment; filename="bookmarks.html"')
|
||||||
|
|
||||||
|
def test_should_check_authentication(self):
|
||||||
|
self.client.logout()
|
||||||
|
response = self.client.get(reverse('bookmarks:settings.export'), follow=True)
|
||||||
|
|
||||||
|
self.assertRedirects(response, reverse('login') + '?next=' + reverse('bookmarks:settings.export'))
|
||||||
|
|
||||||
|
def test_should_show_hint_when_export_raises_error(self):
|
||||||
|
with patch('bookmarks.services.exporter.export_netscape_html') as mock_export_netscape_html:
|
||||||
|
mock_export_netscape_html.side_effect = Exception('Nope')
|
||||||
|
response = self.client.get(reverse('bookmarks:settings.export'), follow=True)
|
||||||
|
|
||||||
|
self.assertTemplateUsed(response, 'settings/general.html')
|
||||||
|
self.assertFormErrorHint(response, 'An error occurred during bookmark export.')
|
36
bookmarks/tests/test_settings_general_view.py
Normal file
36
bookmarks/tests/test_settings_general_view.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
from bookmarks.tests.helpers import BookmarkFactoryMixin
|
||||||
|
from bookmarks.models import UserProfile
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||||
|
|
||||||
|
def setUp(self) -> None:
|
||||||
|
user = self.get_or_create_test_user()
|
||||||
|
self.client.force_login(user)
|
||||||
|
|
||||||
|
def test_should_render_successfully(self):
|
||||||
|
response = self.client.get(reverse('bookmarks:settings.general'))
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_should_check_authentication(self):
|
||||||
|
self.client.logout()
|
||||||
|
response = self.client.get(reverse('bookmarks:settings.general'), follow=True)
|
||||||
|
|
||||||
|
self.assertRedirects(response, reverse('login') + '?next=' + reverse('bookmarks:settings.general'))
|
||||||
|
|
||||||
|
def test_should_save_profile(self):
|
||||||
|
form_data = {
|
||||||
|
'theme': UserProfile.THEME_DARK,
|
||||||
|
'bookmark_date_display': UserProfile.BOOKMARK_DATE_DISPLAY_HIDDEN,
|
||||||
|
}
|
||||||
|
response = self.client.post(reverse('bookmarks:settings.general'), form_data)
|
||||||
|
|
||||||
|
self.user.profile.refresh_from_db()
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(self.user.profile.theme, form_data['theme'])
|
||||||
|
self.assertEqual(self.user.profile.bookmark_date_display, form_data['bookmark_date_display'])
|
77
bookmarks/tests/test_settings_import_view.py
Normal file
77
bookmarks/tests/test_settings_import_view.py
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
from bookmarks.tests.helpers import BookmarkFactoryMixin
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsImportViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||||
|
|
||||||
|
def setUp(self) -> None:
|
||||||
|
user = self.get_or_create_test_user()
|
||||||
|
self.client.force_login(user)
|
||||||
|
|
||||||
|
def assertFormSuccessHint(self, response, text: str):
|
||||||
|
self.assertContains(response, '<div class="has-success">')
|
||||||
|
self.assertContains(response, text)
|
||||||
|
|
||||||
|
def assertNoFormSuccessHint(self, response):
|
||||||
|
self.assertNotContains(response, '<div class="has-success">')
|
||||||
|
|
||||||
|
def assertFormErrorHint(self, response, text: str):
|
||||||
|
self.assertContains(response, '<div class="has-error">')
|
||||||
|
self.assertContains(response, text)
|
||||||
|
|
||||||
|
def assertNoFormErrorHint(self, response):
|
||||||
|
self.assertNotContains(response, '<div class="has-error">')
|
||||||
|
|
||||||
|
def test_should_import_successfully(self):
|
||||||
|
with open('bookmarks/tests/resources/simple_valid_import_file.html') as import_file:
|
||||||
|
response = self.client.post(
|
||||||
|
reverse('bookmarks:settings.import'),
|
||||||
|
{'import_file': import_file},
|
||||||
|
follow=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertRedirects(response, reverse('bookmarks:settings.general'))
|
||||||
|
self.assertFormSuccessHint(response, '3 bookmarks were successfully imported')
|
||||||
|
self.assertNoFormErrorHint(response)
|
||||||
|
|
||||||
|
def test_should_check_authentication(self):
|
||||||
|
self.client.logout()
|
||||||
|
response = self.client.get(reverse('bookmarks:settings.import'), follow=True)
|
||||||
|
|
||||||
|
self.assertRedirects(response, reverse('login') + '?next=' + reverse('bookmarks:settings.import'))
|
||||||
|
|
||||||
|
def test_should_show_hint_if_there_is_no_file(self):
|
||||||
|
response = self.client.post(
|
||||||
|
reverse('bookmarks:settings.import'),
|
||||||
|
follow=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertRedirects(response, reverse('bookmarks:settings.general'))
|
||||||
|
self.assertNoFormSuccessHint(response)
|
||||||
|
self.assertFormErrorHint(response, 'Please select a file to import.')
|
||||||
|
|
||||||
|
def test_should_show_hint_if_import_raises_exception(self):
|
||||||
|
with open('bookmarks/tests/resources/invalid_import_file.png', 'rb') as import_file:
|
||||||
|
response = self.client.post(
|
||||||
|
reverse('bookmarks:settings.import'),
|
||||||
|
{'import_file': import_file},
|
||||||
|
follow=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertRedirects(response, reverse('bookmarks:settings.general'))
|
||||||
|
self.assertNoFormSuccessHint(response)
|
||||||
|
self.assertFormErrorHint(response, 'An error occurred during bookmark import.')
|
||||||
|
|
||||||
|
def test_should_show_respective_hints_if_not_all_bookmarks_were_imported_successfully(self):
|
||||||
|
with open('bookmarks/tests/resources/simple_valid_import_file_with_one_invalid_bookmark.html') as import_file:
|
||||||
|
response = self.client.post(
|
||||||
|
reverse('bookmarks:settings.import'),
|
||||||
|
{'import_file': import_file},
|
||||||
|
follow=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertRedirects(response, reverse('bookmarks:settings.general'))
|
||||||
|
self.assertFormSuccessHint(response, '2 bookmarks were successfully imported')
|
||||||
|
self.assertFormErrorHint(response, '1 bookmarks could not be imported')
|
22
bookmarks/tests/test_settings_integrations_view.py
Normal file
22
bookmarks/tests/test_settings_integrations_view.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
from bookmarks.tests.helpers import BookmarkFactoryMixin
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsIntegrationsViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||||
|
|
||||||
|
def setUp(self) -> None:
|
||||||
|
user = self.get_or_create_test_user()
|
||||||
|
self.client.force_login(user)
|
||||||
|
|
||||||
|
def test_should_render_successfully(self):
|
||||||
|
response = self.client.get(reverse('bookmarks:settings.integrations'))
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_should_check_authentication(self):
|
||||||
|
self.client.logout()
|
||||||
|
response = self.client.get(reverse('bookmarks:settings.integrations'), follow=True)
|
||||||
|
|
||||||
|
self.assertRedirects(response, reverse('login') + '?next=' + reverse('bookmarks:settings.integrations'))
|
|
@ -9,8 +9,8 @@ from rest_framework.authtoken.models import Token
|
||||||
|
|
||||||
from bookmarks.models import UserProfileForm
|
from bookmarks.models import UserProfileForm
|
||||||
from bookmarks.queries import query_bookmarks
|
from bookmarks.queries import query_bookmarks
|
||||||
from bookmarks.services.exporter import export_netscape_html
|
from bookmarks.services import exporter
|
||||||
from bookmarks.services.importer import import_netscape_html
|
from bookmarks.services import importer
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -55,11 +55,11 @@ def bookmark_import(request):
|
||||||
|
|
||||||
if import_file is None:
|
if import_file is None:
|
||||||
messages.error(request, 'Please select a file to import.', 'bookmark_import_errors')
|
messages.error(request, 'Please select a file to import.', 'bookmark_import_errors')
|
||||||
return HttpResponseRedirect(reverse('bookmarks:settings.index'))
|
return HttpResponseRedirect(reverse('bookmarks:settings.general'))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
content = import_file.read().decode()
|
content = import_file.read().decode()
|
||||||
result = import_netscape_html(content, request.user)
|
result = importer.import_netscape_html(content, request.user)
|
||||||
success_msg = str(result.success) + ' bookmarks were successfully imported.'
|
success_msg = str(result.success) + ' bookmarks were successfully imported.'
|
||||||
messages.success(request, success_msg, 'bookmark_import_success')
|
messages.success(request, success_msg, 'bookmark_import_success')
|
||||||
if result.failed > 0:
|
if result.failed > 0:
|
||||||
|
@ -78,7 +78,7 @@ def bookmark_export(request):
|
||||||
# noinspection PyBroadException
|
# noinspection PyBroadException
|
||||||
try:
|
try:
|
||||||
bookmarks = query_bookmarks(request.user, '')
|
bookmarks = query_bookmarks(request.user, '')
|
||||||
file_content = export_netscape_html(bookmarks)
|
file_content = exporter.export_netscape_html(bookmarks)
|
||||||
|
|
||||||
response = HttpResponse(content_type='text/plain; charset=UTF-8')
|
response = HttpResponse(content_type='text/plain; charset=UTF-8')
|
||||||
response['Content-Disposition'] = 'attachment; filename="bookmarks.html"'
|
response['Content-Disposition'] = 'attachment; filename="bookmarks.html"'
|
||||||
|
|
Loading…
Reference in a new issue