Repository: sissbruecker/linkding
Pull request #663 (2024-03-24 10:52:00)

Add option for showing bookmark description as separate block


Patch:
diff --git a/bookmarks/migrations/0027_userprofile_bookmark_description_display_and_more.py b/bookmarks/migrations/0027_userprofile_bookmark_description_display_and_more.py
new file mode 100644
index 0000000..917fbba
--- /dev/null
+++ b/bookmarks/migrations/0027_userprofile_bookmark_description_display_and_more.py
@@ -0,0 +1,27 @@
+# Generated by Django 5.0.2 on 2024-03-23 21:48
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("bookmarks", "0026_userprofile_custom_css"),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name="userprofile",
+            name="bookmark_description_display",
+            field=models.CharField(
+                choices=[("inline", "Inline"), ("separate", "Separate")],
+                default="inline",
+                max_length=10,
+            ),
+        ),
+        migrations.AddField(
+            model_name="userprofile",
+            name="bookmark_description_max_lines",
+            field=models.IntegerField(default=1),
+        ),
+    ]
diff --git a/bookmarks/models.py b/bookmarks/models.py
index 8714283..126353e 100644
--- a/bookmarks/models.py
+++ b/bookmarks/models.py
@@ -278,6 +278,12 @@ class UserProfile(models.Model):
         (BOOKMARK_DATE_DISPLAY_ABSOLUTE, "Absolute"),
         (BOOKMARK_DATE_DISPLAY_HIDDEN, "Hidden"),
     ]
+    BOOKMARK_DESCRIPTION_DISPLAY_INLINE = "inline"
+    BOOKMARK_DESCRIPTION_DISPLAY_SEPARATE = "separate"
+    BOOKMARK_DESCRIPTION_DISPLAY_CHOICES = [
+        (BOOKMARK_DESCRIPTION_DISPLAY_INLINE, "Inline"),
+        (BOOKMARK_DESCRIPTION_DISPLAY_SEPARATE, "Separate"),
+    ]
     BOOKMARK_LINK_TARGET_BLANK = "_blank"
     BOOKMARK_LINK_TARGET_SELF = "_self"
     BOOKMARK_LINK_TARGET_CHOICES = [
@@ -308,6 +314,16 @@ class UserProfile(models.Model):
         blank=False,
         default=BOOKMARK_DATE_DISPLAY_RELATIVE,
     )
+    bookmark_description_display = models.CharField(
+        max_length=10,
+        choices=BOOKMARK_DESCRIPTION_DISPLAY_CHOICES,
+        blank=False,
+        default=BOOKMARK_DESCRIPTION_DISPLAY_INLINE,
+    )
+    bookmark_description_max_lines = models.IntegerField(
+        null=False,
+        default=1,
+    )
     bookmark_link_target = models.CharField(
         max_length=10,
         choices=BOOKMARK_LINK_TARGET_CHOICES,
@@ -341,6 +357,8 @@ class UserProfileForm(forms.ModelForm):
         fields = [
             "theme",
             "bookmark_date_display",
+            "bookmark_description_display",
+            "bookmark_description_max_lines",
             "bookmark_link_target",
             "web_archive_integration",
             "tag_search",
diff --git a/bookmarks/styles/bookmark-page.scss b/bookmarks/styles/bookmark-page.scss
index c0909cf..2efd822 100644
--- a/bookmarks/styles/bookmark-page.scss
+++ b/bookmarks/styles/bookmark-page.scss
@@ -175,7 +175,16 @@ li[ld-bookmark-item] {
 
   .description {
     color: $gray-color-dark;
+  }
+
+  .description.separate {
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+    -webkit-line-clamp: var(--ld-bookmark-description-max-lines, 1);
+    overflow: hidden;
+  }
 
+  .tags {
     a, a:visited:hover {
       color: $alternative-color;
     }
diff --git a/bookmarks/templates/bookmarks/bookmark_list.html b/bookmarks/templates/bookmarks/bookmark_list.html
index c5b6c0a..1abca54 100644
--- a/bookmarks/templates/bookmarks/bookmark_list.html
+++ b/bookmarks/templates/bookmarks/bookmark_list.html
@@ -6,6 +6,7 @@
   {% include 'bookmarks/empty_bookmarks.html' %}
 {% else %}
   <ul class="bookmark-list{% if bookmark_list.show_notes %} show-notes{% endif %}"
+      style="--ld-bookmark-description-max-lines:{{ bookmark_list.description_max_lines }};"
       data-bookmarks-total="{{ bookmark_list.bookmarks_total }}">
     {% for bookmark_item in bookmark_list.items %}
       <li ld-bookmark-item{% if bookmark_item.css_classes %} class="{{ bookmark_item.css_classes }}"{% endif %}>
@@ -14,11 +15,11 @@
           <i class="form-icon"></i>
         </label>
         <div class="title">
-          <a href="{{ bookmark_item.url }}" target="{{ bookmark_list.link_target }}" rel="noopener" >
+          <a href="{{ bookmark_item.url }}" target="{{ bookmark_list.link_target }}" rel="noopener">
             {% if bookmark_item.favicon_file and bookmark_list.show_favicons %}
               <img src="{% static bookmark_item.favicon_file %}" alt="">
             {% endif %}
-              <span>{{ bookmark_item.title }}</span>
+            <span>{{ bookmark_item.title }}</span>
           </a>
         </div>
         {% if bookmark_list.show_url %}
@@ -29,19 +30,34 @@
             </a>
           </div>
         {% endif %}
-        <div class="description truncate">
+        {% if bookmark_list.description_display == 'inline' %}
+          <div class="description inline truncate">
+            {% if bookmark_item.tag_names %}
+              <span class="tags">
+                {% for tag_name in bookmark_item.tag_names %}
+                  <a href="?{% add_tag_to_query tag_name %}">{{ tag_name|hash_tag }}</a>
+                {% endfor %}
+              </span>
+            {% endif %}
+            {% if bookmark_item.tag_names and bookmark_item.description %} | {% endif %}
+            {% if bookmark_item.description %}
+              <span>{{ bookmark_item.description }}</span>
+            {% endif %}
+          </div>
+        {% else %}
+          {% if bookmark_item.description %}
+            <div class="description separate">
+              {{ bookmark_item.description }}
+            </div>
+          {% endif %}
           {% if bookmark_item.tag_names %}
-            <span>
+            <div class="tags">
               {% for tag_name in bookmark_item.tag_names %}
                 <a href="?{% add_tag_to_query tag_name %}">{{ tag_name|hash_tag }}</a>
               {% endfor %}
-            </span>
-          {% endif %}
-          {% if bookmark_item.tag_names and bookmark_item.description %} | {% endif %}
-          {% if bookmark_item.description %}
-            <span>{{ bookmark_item.description }}</span>
+            </div>
           {% endif %}
-        </div>
+        {% endif %}
         {% if bookmark_item.notes %}
           <div class="notes bg-gray text-gray-dark">
             <div class="notes-content">
diff --git a/bookmarks/templates/settings/general.html b/bookmarks/templates/settings/general.html
index 823f0b1..a8ff541 100644
--- a/bookmarks/templates/settings/general.html
+++ b/bookmarks/templates/settings/general.html
@@ -29,6 +29,22 @@
             be hidden.
           </div>
         </div>
+        <div class="form-group">
+          <label for="{{ form.bookmark_description_display.id_for_label }}" class="form-label">Bookmark
+            description</label>
+          {{ form.bookmark_description_display|add_class:"form-select width-25 width-sm-100" }}
+          <div class="form-input-hint">
+            Whether to show bookmark descriptions and tags in the same line, or as separate blocks.
+          </div>
+        </div>
+        <div
+            class="form-group {% if request.user_profile.bookmark_description_display == 'inline' %}d-hide{% endif %}">
+          <label for="{{ form.bookmark_description_max_lines.id_for_label }}" class="form-label">Bookmark description max lines</label>
+          {{ form.bookmark_description_max_lines|add_class:"form-input width-25 width-sm-100" }}
+          <div class="form-input-hint">
+            Limits the number of lines that are displayed for the bookmark description.
+          </div>
+        </div>
         <div class="form-group">
           <label for="{{ form.display_url.id_for_label }}" class="form-checkbox">
             {{ form.display_url }}
@@ -124,18 +140,18 @@
               href="{% url 'bookmarks:shared' %}">shared bookmarks page</a>.
           </div>
         </div>
-      <div class="form-group">
-        <details {% if form.custom_css.value %}open{% endif %}>
-          <summary>Custom CSS</summary>
-          <label for="{{ form.custom_css.id_for_label }}" class="text-assistive">Custom CSS</label>
-          <div class="mt-2">
-            {{ form.custom_css|add_class:"form-input custom-css"|attr:"rows:6" }}
+        <div class="form-group">
+          <details {% if form.custom_css.value %}open{% endif %}>
+            <summary>Custom CSS</summary>
+            <label for="{{ form.custom_css.id_for_label }}" class="text-assistive">Custom CSS</label>
+            <div class="mt-2">
+              {{ form.custom_css|add_class:"form-input custom-css"|attr:"rows:6" }}
+            </div>
+          </details>
+          <div class="form-input-hint">
+            Allows to add custom CSS to the page.
           </div>
-        </details>
-        <div class="form-input-hint">
-          Allows to add custom CSS to the page.
         </div>
-      </div>
         <div class="form-group">
           <input type="submit" name="update_profile" value="Save" class="btn btn-primary mt-2">
           {% if update_profile_success_message %}
@@ -195,10 +211,6 @@
     <section class="content-area">
       <h2>Export</h2>
       <p>Export all bookmarks in Netscape HTML format.</p>
-      <p>
-        Note that exporting bookmark notes is currently not supported due to limitations of the format.
-        For proper backups please use a database backup as described in the documentation.
-      </p>
       <a class="btn btn-primary" href="{% url 'bookmarks:settings.export' %}">Download (.html)</a>
       {% if export_error %}
         <div class="has-error">
@@ -237,10 +249,12 @@
   </div>
 
   <script>
-    // Automatically disable public bookmark sharing if bookmark sharing is disabled
     const enableSharing = document.getElementById("{{ form.enable_sharing.id_for_label }}");
     const enablePublicSharing = document.getElementById("{{ form.enable_public_sharing.id_for_label }}");
+    const bookmarkDescriptionDisplay = document.getElementById("{{ form.bookmark_description_display.id_for_label }}");
+    const bookmarkDescriptionMaxLines = document.getElementById("{{ form.bookmark_description_max_lines.id_for_label }}");
 
+    // Automatically disable public bookmark sharing if bookmark sharing is disabled
     function updatePublicSharing() {
       if (enableSharing.checked) {
         enablePublicSharing.disabled = false;
@@ -252,6 +266,18 @@
 
     updatePublicSharing();
     enableSharing.addEventListener("change", updatePublicSharing);
+
+    // Automatically hide the bookmark description max lines input if the description display is set to inline
+    function updateBookmarkDescriptionMaxLines() {
+      if (bookmarkDescriptionDisplay.value === "inline") {
+        bookmarkDescriptionMaxLines.closest(".form-group").classList.add("d-hide");
+      } else {
+        bookmarkDescriptionMaxLines.closest(".form-group").classList.remove("d-hide");
+      }
+    }
+
+    updateBookmarkDescriptionMaxLines();
+    bookmarkDescriptionDisplay.addEventListener("change", updateBookmarkDescriptionMaxLines);
   </script>
 
 {% endblock %}
diff --git a/bookmarks/views/partials/contexts.py b/bookmarks/views/partials/contexts.py
index 700a74d..8a6a79c 100644
--- a/bookmarks/views/partials/contexts.py
+++ b/bookmarks/views/partials/contexts.py
@@ -96,6 +96,8 @@ class BookmarkListContext:
         )
         self.link_target = user_profile.bookmark_link_target
         self.date_display = user_profile.bookmark_date_display
+        self.description_display = user_profile.bookmark_description_display
+        self.description_max_lines = user_profile.bookmark_description_max_lines
         self.show_url = user_profile.display_url
         self.show_favicons = user_profile.enable_favicons
         self.show_notes = user_profile.permanent_notes


Test patch:
diff --git a/bookmarks/e2e/e2e_test_settings_general.py b/bookmarks/e2e/e2e_test_settings_general.py
index cdbf192..3b480c5 100644
--- a/bookmarks/e2e/e2e_test_settings_general.py
+++ b/bookmarks/e2e/e2e_test_settings_general.py
@@ -2,6 +2,7 @@ from django.urls import reverse
 from playwright.sync_api import sync_playwright, expect
 
 from bookmarks.e2e.helpers import LinkdingE2ETestCase
+from bookmarks.models import UserProfile
 
 
 class SettingsGeneralE2ETestCase(LinkdingE2ETestCase):
@@ -39,3 +40,49 @@ class SettingsGeneralE2ETestCase(LinkdingE2ETestCase):
             expect(enable_sharing).not_to_be_checked()
             expect(enable_public_sharing).not_to_be_checked()
             expect(enable_public_sharing).to_be_disabled()
+
+    def test_should_not_show_bookmark_description_max_lines_when_display_inline(self):
+        profile = self.get_or_create_test_user().profile
+        profile.bookmark_description_display = (
+            UserProfile.BOOKMARK_DESCRIPTION_DISPLAY_INLINE
+        )
+        profile.save()
+
+        with sync_playwright() as p:
+            browser = self.setup_browser(p)
+            page = browser.new_page()
+            page.goto(self.live_server_url + reverse("bookmarks:settings.general"))
+
+            max_lines = page.get_by_label("Bookmark description max lines")
+            expect(max_lines).to_be_hidden()
+
+    def test_should_show_bookmark_description_max_lines_when_display_separate(self):
+        profile = self.get_or_create_test_user().profile
+        profile.bookmark_description_display = (
+            UserProfile.BOOKMARK_DESCRIPTION_DISPLAY_SEPARATE
+        )
+        profile.save()
+
+        with sync_playwright() as p:
+            browser = self.setup_browser(p)
+            page = browser.new_page()
+            page.goto(self.live_server_url + reverse("bookmarks:settings.general"))
+
+            max_lines = page.get_by_label("Bookmark description max lines")
+            expect(max_lines).to_be_visible()
+
+    def test_should_update_bookmark_description_max_lines_when_changing_display(self):
+        with sync_playwright() as p:
+            browser = self.setup_browser(p)
+            page = browser.new_page()
+            page.goto(self.live_server_url + reverse("bookmarks:settings.general"))
+
+            max_lines = page.get_by_label("Bookmark description max lines")
+            expect(max_lines).to_be_hidden()
+
+            display = page.get_by_label("Bookmark description", exact=True)
+            display.select_option("separate")
+            expect(max_lines).to_be_visible()
+
+            display.select_option("inline")
+            expect(max_lines).to_be_hidden()
diff --git a/bookmarks/tests/test_bookmarks_list_template.py b/bookmarks/tests/test_bookmarks_list_template.py
index f80dc25..64e9d93 100644
--- a/bookmarks/tests/test_bookmarks_list_template.py
+++ b/bookmarks/tests/test_bookmarks_list_template.py
@@ -10,11 +10,11 @@ from django.utils import timezone, formats
 
 from bookmarks.middlewares import UserProfileMiddleware
 from bookmarks.models import Bookmark, UserProfile, User
-from bookmarks.tests.helpers import BookmarkFactoryMixin, collapse_whitespace
+from bookmarks.tests.helpers import BookmarkFactoryMixin, HtmlTestMixin
 from bookmarks.views.partials import contexts
 
 
-class BookmarkListTemplateTest(TestCase, BookmarkFactoryMixin):
+class BookmarkListTemplateTest(TestCase, BookmarkFactoryMixin, HtmlTestMixin):
 
     def assertBookmarksLink(
         self, html: str, bookmark: Bookmark, link_target: str = "_blank"
@@ -241,6 +241,172 @@ class BookmarkListTemplateTest(TestCase, BookmarkFactoryMixin):
         user.profile.save()
         return bookmark
 
+    def inline_bookmark_description_test(self, bookmark):
+        html = self.render_template()
+        soup = self.make_soup(html)
+
+        has_description = bool(bookmark.description)
+        has_tags = len(bookmark.tags.all()) > 0
+
+        # inline description block exists
+        description = soup.select_one(".description.inline.truncate")
+        self.assertIsNotNone(description)
+
+        # separate description block does not exist
+        separate_description = soup.select_one(".description.separate")
+        self.assertIsNone(separate_description)
+
+        # one direct child element per description or tags
+        children = description.find_all(recursive=False)
+        expected_child_count = (
+            0 + (1 if has_description else 0) + (1 if has_tags else 0)
+        )
+        self.assertEqual(len(children), expected_child_count)
+
+        # has separator between description and tags
+        if has_description and has_tags:
+            self.assertTrue("|" in description.text)
+
+        # contains description text
+        if has_description:
+            description_text = description.find("span", text=bookmark.description)
+            self.assertIsNotNone(description_text)
+
+        if not has_tags:
+            # no tags element
+            tags = soup.select_one(".tags")
+            self.assertIsNone(tags)
+        else:
+            # tags element exists
+            tags = soup.select_one(".tags")
+            self.assertIsNotNone(tags)
+
+            # one link for each tag
+            tag_links = tags.find_all("a")
+            self.assertEqual(len(tag_links), len(bookmark.tags.all()))
+
+            for tag in bookmark.tags.all():
+                tag_link = tags.find("a", text=f"#{tag.name}")
+                self.assertIsNotNone(tag_link)
+                self.assertEqual(tag_link["href"], f"?q=%23{tag.name}")
+
+    def test_inline_bookmark_description(self):
+        profile = self.get_or_create_test_user().profile
+        profile.bookmark_description_display = (
+            UserProfile.BOOKMARK_DESCRIPTION_DISPLAY_INLINE
+        )
+        profile.save()
+
+        # no description, no tags
+        bookmark = self.setup_bookmark(description="")
+        self.inline_bookmark_description_test(bookmark)
+
+        # with description, no tags
+        bookmark = self.setup_bookmark(description="Test description")
+        self.inline_bookmark_description_test(bookmark)
+
+        # no description, with tags
+        Bookmark.objects.all().delete()
+        bookmark = self.setup_bookmark(
+            description="", tags=[self.setup_tag(), self.setup_tag(), self.setup_tag()]
+        )
+        self.inline_bookmark_description_test(bookmark)
+
+        # with description, with tags
+        Bookmark.objects.all().delete()
+        bookmark = self.setup_bookmark(
+            description="Test description",
+            tags=[self.setup_tag(), self.setup_tag(), self.setup_tag()],
+        )
+        self.inline_bookmark_description_test(bookmark)
+
+    def separate_bookmark_description_test(self, bookmark):
+        html = self.render_template()
+        soup = self.make_soup(html)
+
+        has_description = bool(bookmark.description)
+        has_tags = len(bookmark.tags.all()) > 0
+
+        # inline description block does not exist
+        inline_description = soup.select_one(".description.inline")
+        self.assertIsNone(inline_description)
+
+        if not has_description:
+            # no description element
+            description = soup.select_one(".description")
+            self.assertIsNone(description)
+        else:
+            # contains description text
+            description = soup.select_one(".description.separate")
+            self.assertIsNotNone(description)
+            self.assertEqual(description.text.strip(), bookmark.description)
+
+        if not has_tags:
+            # no tags element
+            tags = soup.select_one(".tags")
+            self.assertIsNone(tags)
+        else:
+            # tags element exists
+            tags = soup.select_one(".tags")
+            self.assertIsNotNone(tags)
+
+            # one link for each tag
+            tag_links = tags.find_all("a")
+            self.assertEqual(len(tag_links), len(bookmark.tags.all()))
+
+            for tag in bookmark.tags.all():
+                tag_link = tags.find("a", text=f"#{tag.name}")
+                self.assertIsNotNone(tag_link)
+                self.assertEqual(tag_link["href"], f"?q=%23{tag.name}")
+
+    def test_separate_bookmark_description(self):
+        profile = self.get_or_create_test_user().profile
+        profile.bookmark_description_display = (
+            UserProfile.BOOKMARK_DESCRIPTION_DISPLAY_SEPARATE
+        )
+        profile.save()
+
+        # no description, no tags
+        bookmark = self.setup_bookmark(description="")
+        self.separate_bookmark_description_test(bookmark)
+
+        # with description, no tags
+        bookmark = self.setup_bookmark(description="Test description")
+        self.separate_bookmark_description_test(bookmark)
+
+        # no description, with tags
+        Bookmark.objects.all().delete()
+        bookmark = self.setup_bookmark(
+            description="", tags=[self.setup_tag(), self.setup_tag(), self.setup_tag()]
+        )
+        self.separate_bookmark_description_test(bookmark)
+
+        # with description, with tags
+        Bookmark.objects.all().delete()
+        bookmark = self.setup_bookmark(
+            description="Test description",
+            tags=[self.setup_tag(), self.setup_tag(), self.setup_tag()],
+        )
+        self.separate_bookmark_description_test(bookmark)
+
+    def test_bookmark_description_max_lines(self):
+        self.setup_bookmark()
+        html = self.render_template()
+        soup = self.make_soup(html)
+        bookmark_list = soup.select_one("ul.bookmark-list")
+        style = bookmark_list["style"]
+        self.assertIn("--ld-bookmark-description-max-lines:1;", style)
+
+        profile = self.get_or_create_test_user().profile
+        profile.bookmark_description_max_lines = 3
+        profile.save()
+
+        html = self.render_template()
+        soup = self.make_soup(html)
+        bookmark_list = soup.select_one("ul.bookmark-list")
+        style = bookmark_list["style"]
+        self.assertIn("--ld-bookmark-description-max-lines:3;", style)
+
     def test_should_respect_absolute_date_setting(self):
         bookmark = self.setup_date_format_test(
             UserProfile.BOOKMARK_DATE_DISPLAY_ABSOLUTE
@@ -539,9 +705,11 @@ class BookmarkListTemplateTest(TestCase, BookmarkFactoryMixin):
 
     def test_notes_are_hidden_initially_by_default(self):
         self.setup_bookmark(notes="Test note")
-        html = collapse_whitespace(self.render_template())
+        html = self.render_template()
+        soup = self.make_soup(html)
+        bookmark_list = soup.select_one("ul.bookmark-list.show-notes")
 
-        self.assertIn('<ul class="bookmark-list" data-bookmarks-total="1">', html)
+        self.assertIsNone(bookmark_list)
 
     def test_notes_are_hidden_initially_with_permanent_notes_disabled(self):
         profile = self.get_or_create_test_user().profile
@@ -549,9 +717,11 @@ class BookmarkListTemplateTest(TestCase, BookmarkFactoryMixin):
         profile.save()
 
         self.setup_bookmark(notes="Test note")
-        html = collapse_whitespace(self.render_template())
+        html = self.render_template()
+        soup = self.make_soup(html)
+        bookmark_list = soup.select_one("ul.bookmark-list.show-notes")
 
-        self.assertIn('<ul class="bookmark-list" data-bookmarks-total="1">', html)
+        self.assertIsNone(bookmark_list)
 
     def test_notes_are_visible_initially_with_permanent_notes_enabled(self):
         profile = self.get_or_create_test_user().profile
@@ -559,11 +729,11 @@ class BookmarkListTemplateTest(TestCase, BookmarkFactoryMixin):
         profile.save()
 
         self.setup_bookmark(notes="Test note")
-        html = collapse_whitespace(self.render_template())
+        html = self.render_template()
+        soup = self.make_soup(html)
+        bookmark_list = soup.select_one("ul.bookmark-list.show-notes")
 
-        self.assertIn(
-            '<ul class="bookmark-list show-notes" data-bookmarks-total="1">', html
-        )
+        self.assertIsNotNone(bookmark_list)
 
     def test_toggle_notes_is_visible_by_default(self):
         self.setup_bookmark(notes="Test note")
diff --git a/bookmarks/tests/test_settings_general_view.py b/bookmarks/tests/test_settings_general_view.py
index f9ed787..61058e9 100644
--- a/bookmarks/tests/test_settings_general_view.py
+++ b/bookmarks/tests/test_settings_general_view.py
@@ -24,6 +24,8 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin):
         form_data = {
             "theme": UserProfile.THEME_AUTO,
             "bookmark_date_display": UserProfile.BOOKMARK_DATE_DISPLAY_RELATIVE,
+            "bookmark_description_display": UserProfile.BOOKMARK_DESCRIPTION_DISPLAY_INLINE,
+            "bookmark_description_max_lines": 1,
             "bookmark_link_target": UserProfile.BOOKMARK_LINK_TARGET_BLANK,
             "web_archive_integration": UserProfile.WEB_ARCHIVE_INTEGRATION_DISABLED,
             "enable_sharing": False,
@@ -56,6 +58,8 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin):
             "update_profile": "",
             "theme": UserProfile.THEME_DARK,
             "bookmark_date_display": UserProfile.BOOKMARK_DATE_DISPLAY_HIDDEN,
+            "bookmark_description_display": UserProfile.BOOKMARK_DESCRIPTION_DISPLAY_SEPARATE,
+            "bookmark_description_max_lines": 3,
             "bookmark_link_target": UserProfile.BOOKMARK_LINK_TARGET_SELF,
             "web_archive_integration": UserProfile.WEB_ARCHIVE_INTEGRATION_ENABLED,
             "enable_sharing": True,
@@ -76,6 +80,14 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin):
         self.assertEqual(
             self.user.profile.bookmark_date_display, form_data["bookmark_date_display"]
         )
+        self.assertEqual(
+            self.user.profile.bookmark_description_display,
+            form_data["bookmark_description_display"],
+        )
+        self.assertEqual(
+            self.user.profile.bookmark_description_max_lines,
+            form_data["bookmark_description_max_lines"],
+        )
         self.assertEqual(
             self.user.profile.bookmark_link_target, form_data["bookmark_link_target"]
         )