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 django.contrib.auth.models import User
|
||||
from django.utils import timezone
|
||||
|
||||
from bookmarks.models import Bookmark, parse_tag_string
|
||||
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.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.unread = False
|
||||
bookmark.title = netscape_bookmark.title
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
|
||||
import pyparsing as pp
|
||||
|
||||
|
@ -9,7 +8,7 @@ class NetscapeBookmark:
|
|||
href: str
|
||||
title: str
|
||||
description: str
|
||||
date_added: int
|
||||
date_added: str
|
||||
tag_string: str
|
||||
|
||||
|
||||
|
@ -17,8 +16,7 @@ def extract_bookmark_link(tag):
|
|||
href = tag[0].href
|
||||
title = tag[0].text
|
||||
tag_string = tag[0].tags
|
||||
date_added_string = tag[0].add_date if tag[0].add_date else datetime.now().timestamp()
|
||||
date_added = int(date_added_string)
|
||||
date_added = tag[0].add_date
|
||||
|
||||
return {
|
||||
'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.queries import query_bookmarks
|
||||
from bookmarks.services.exporter import export_netscape_html
|
||||
from bookmarks.services.importer import import_netscape_html
|
||||
from bookmarks.services import exporter
|
||||
from bookmarks.services import importer
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -55,11 +55,11 @@ def bookmark_import(request):
|
|||
|
||||
if import_file is None:
|
||||
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:
|
||||
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.'
|
||||
messages.success(request, success_msg, 'bookmark_import_success')
|
||||
if result.failed > 0:
|
||||
|
@ -78,7 +78,7 @@ def bookmark_export(request):
|
|||
# noinspection PyBroadException
|
||||
try:
|
||||
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['Content-Disposition'] = 'attachment; filename="bookmarks.html"'
|
||||
|
|
Loading…
Reference in a new issue