2023-08-21 21:12:00 +00:00
|
|
|
from typing import List
|
|
|
|
|
|
|
|
from django.urls import reverse
|
|
|
|
from playwright.sync_api import sync_playwright, expect
|
|
|
|
|
|
|
|
from bookmarks.e2e.helpers import LinkdingE2ETestCase
|
|
|
|
|
|
|
|
|
|
|
|
class BookmarkPagePartialUpdatesE2ETestCase(LinkdingE2ETestCase):
|
|
|
|
def setup_fixture(self):
|
|
|
|
profile = self.get_or_create_test_user().profile
|
|
|
|
profile.enable_sharing = True
|
|
|
|
profile.save()
|
|
|
|
|
|
|
|
# create a number of bookmarks with different states / visibility to
|
|
|
|
# verify correct data is loaded on update
|
|
|
|
self.setup_numbered_bookmarks(3, with_tags=True)
|
|
|
|
self.setup_numbered_bookmarks(3, with_tags=True, archived=True)
|
2024-01-27 10:29:16 +00:00
|
|
|
self.setup_numbered_bookmarks(
|
|
|
|
3,
|
|
|
|
shared=True,
|
|
|
|
prefix="Joe's Bookmark",
|
|
|
|
user=self.setup_user(enable_sharing=True),
|
|
|
|
)
|
2023-08-21 21:12:00 +00:00
|
|
|
|
|
|
|
def assertVisibleBookmarks(self, titles: List[str]):
|
2024-01-27 10:29:16 +00:00
|
|
|
bookmark_tags = self.page.locator("li[ld-bookmark-item]")
|
2023-08-21 21:12:00 +00:00
|
|
|
expect(bookmark_tags).to_have_count(len(titles))
|
|
|
|
|
|
|
|
for title in titles:
|
|
|
|
matching_tag = bookmark_tags.filter(has_text=title)
|
|
|
|
expect(matching_tag).to_be_visible()
|
|
|
|
|
|
|
|
def assertVisibleTags(self, titles: List[str]):
|
2024-01-27 10:29:16 +00:00
|
|
|
tag_tags = self.page.locator(".tag-cloud .unselected-tags a")
|
2023-08-21 21:12:00 +00:00
|
|
|
expect(tag_tags).to_have_count(len(titles))
|
|
|
|
|
|
|
|
for title in titles:
|
|
|
|
matching_tag = tag_tags.filter(has_text=title)
|
|
|
|
expect(matching_tag).to_be_visible()
|
|
|
|
|
|
|
|
def test_partial_update_respects_query(self):
|
2024-01-27 10:29:16 +00:00
|
|
|
self.setup_numbered_bookmarks(5, prefix="foo")
|
|
|
|
self.setup_numbered_bookmarks(5, prefix="bar")
|
2023-08-21 21:12:00 +00:00
|
|
|
|
|
|
|
with sync_playwright() as p:
|
2024-01-27 10:29:16 +00:00
|
|
|
url = reverse("bookmarks:index") + "?q=foo"
|
2023-08-21 21:12:00 +00:00
|
|
|
self.open(url, p)
|
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
self.assertVisibleBookmarks(["foo 1", "foo 2", "foo 3", "foo 4", "foo 5"])
|
2023-08-21 21:12:00 +00:00
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
self.locate_bookmark("foo 2").get_by_text("Archive").click()
|
|
|
|
self.assertVisibleBookmarks(["foo 1", "foo 3", "foo 4", "foo 5"])
|
2023-08-21 21:12:00 +00:00
|
|
|
|
2023-09-01 20:48:21 +00:00
|
|
|
def test_partial_update_respects_sort(self):
|
2024-01-27 10:29:16 +00:00
|
|
|
self.setup_numbered_bookmarks(5, prefix="foo")
|
2023-09-01 20:48:21 +00:00
|
|
|
|
|
|
|
with sync_playwright() as p:
|
2024-01-27 10:29:16 +00:00
|
|
|
url = reverse("bookmarks:index") + "?sort=title_asc"
|
2023-09-01 20:48:21 +00:00
|
|
|
page = self.open(url, p)
|
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
first_item = page.locator("li[ld-bookmark-item]").first
|
|
|
|
expect(first_item).to_contain_text("foo 1")
|
2023-09-01 20:48:21 +00:00
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
first_item.get_by_text("Archive").click()
|
2023-09-01 20:48:21 +00:00
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
first_item = page.locator("li[ld-bookmark-item]").first
|
|
|
|
expect(first_item).to_contain_text("foo 2")
|
2023-09-01 20:48:21 +00:00
|
|
|
|
2023-08-21 21:12:00 +00:00
|
|
|
def test_partial_update_respects_page(self):
|
|
|
|
# add a suffix, otherwise 'foo 1' also matches 'foo 10'
|
2024-01-27 10:29:16 +00:00
|
|
|
self.setup_numbered_bookmarks(50, prefix="foo", suffix="-")
|
2023-08-21 21:12:00 +00:00
|
|
|
|
|
|
|
with sync_playwright() as p:
|
2024-01-27 10:29:16 +00:00
|
|
|
url = reverse("bookmarks:index") + "?q=foo&page=2"
|
2023-08-21 21:12:00 +00:00
|
|
|
self.open(url, p)
|
|
|
|
|
|
|
|
# with descending sort, page two has 'foo 1' to 'foo 20'
|
2024-01-27 10:29:16 +00:00
|
|
|
expected_titles = [f"foo {i}-" for i in range(1, 21)]
|
2023-08-21 21:12:00 +00:00
|
|
|
self.assertVisibleBookmarks(expected_titles)
|
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
self.locate_bookmark("foo 20-").get_by_text("Archive").click()
|
2023-08-21 21:12:00 +00:00
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
expected_titles = [f"foo {i}-" for i in range(1, 20)]
|
2023-08-21 21:12:00 +00:00
|
|
|
self.assertVisibleBookmarks(expected_titles)
|
|
|
|
|
|
|
|
def test_multiple_partial_updates(self):
|
|
|
|
self.setup_numbered_bookmarks(5)
|
|
|
|
|
|
|
|
with sync_playwright() as p:
|
2024-01-27 10:29:16 +00:00
|
|
|
url = reverse("bookmarks:index")
|
2023-08-21 21:12:00 +00:00
|
|
|
self.open(url, p)
|
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
self.locate_bookmark("Bookmark 1").get_by_text("Archive").click()
|
|
|
|
self.assertVisibleBookmarks(
|
|
|
|
["Bookmark 2", "Bookmark 3", "Bookmark 4", "Bookmark 5"]
|
|
|
|
)
|
2023-08-21 21:12:00 +00:00
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
self.locate_bookmark("Bookmark 2").get_by_text("Archive").click()
|
|
|
|
self.assertVisibleBookmarks(["Bookmark 3", "Bookmark 4", "Bookmark 5"])
|
2023-08-21 21:12:00 +00:00
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
self.locate_bookmark("Bookmark 3").get_by_text("Archive").click()
|
|
|
|
self.assertVisibleBookmarks(["Bookmark 4", "Bookmark 5"])
|
2023-08-21 21:12:00 +00:00
|
|
|
|
|
|
|
self.assertReloads(0)
|
|
|
|
|
|
|
|
def test_active_bookmarks_partial_update_on_archive(self):
|
|
|
|
self.setup_fixture()
|
|
|
|
|
|
|
|
with sync_playwright() as p:
|
2024-01-27 10:29:16 +00:00
|
|
|
self.open(reverse("bookmarks:index"), p)
|
2023-08-21 21:12:00 +00:00
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
self.locate_bookmark("Bookmark 2").get_by_text("Archive").click()
|
2023-08-21 21:12:00 +00:00
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
self.assertVisibleBookmarks(["Bookmark 1", "Bookmark 3"])
|
|
|
|
self.assertVisibleTags(["Tag 1", "Tag 3"])
|
2023-08-21 21:12:00 +00:00
|
|
|
self.assertReloads(0)
|
|
|
|
|
|
|
|
def test_active_bookmarks_partial_update_on_delete(self):
|
|
|
|
self.setup_fixture()
|
|
|
|
|
|
|
|
with sync_playwright() as p:
|
2024-01-27 10:29:16 +00:00
|
|
|
self.open(reverse("bookmarks:index"), p)
|
2023-08-21 21:12:00 +00:00
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
self.locate_bookmark("Bookmark 2").get_by_text("Remove").click()
|
|
|
|
self.locate_bookmark("Bookmark 2").get_by_text("Confirm").click()
|
2023-08-21 21:12:00 +00:00
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
self.assertVisibleBookmarks(["Bookmark 1", "Bookmark 3"])
|
|
|
|
self.assertVisibleTags(["Tag 1", "Tag 3"])
|
2023-08-21 21:12:00 +00:00
|
|
|
self.assertReloads(0)
|
|
|
|
|
|
|
|
def test_active_bookmarks_partial_update_on_mark_as_read(self):
|
|
|
|
self.setup_fixture()
|
2024-01-27 10:29:16 +00:00
|
|
|
bookmark2 = self.get_numbered_bookmark("Bookmark 2")
|
2023-08-21 21:12:00 +00:00
|
|
|
bookmark2.unread = True
|
|
|
|
bookmark2.save()
|
|
|
|
|
|
|
|
with sync_playwright() as p:
|
2024-01-27 10:29:16 +00:00
|
|
|
self.open(reverse("bookmarks:index"), p)
|
2023-08-21 21:12:00 +00:00
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
expect(self.locate_bookmark("Bookmark 2")).to_have_class("unread")
|
|
|
|
self.locate_bookmark("Bookmark 2").get_by_text("Unread").click()
|
|
|
|
self.locate_bookmark("Bookmark 2").get_by_text("Yes").click()
|
2023-08-21 21:12:00 +00:00
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
expect(self.locate_bookmark("Bookmark 2")).not_to_have_class("unread")
|
2023-08-24 17:11:36 +00:00
|
|
|
self.assertReloads(0)
|
|
|
|
|
|
|
|
def test_active_bookmarks_partial_update_on_unshare(self):
|
|
|
|
self.setup_fixture()
|
2024-01-27 10:29:16 +00:00
|
|
|
bookmark2 = self.get_numbered_bookmark("Bookmark 2")
|
2023-08-24 17:11:36 +00:00
|
|
|
bookmark2.shared = True
|
|
|
|
bookmark2.save()
|
|
|
|
|
|
|
|
with sync_playwright() as p:
|
2024-01-27 10:29:16 +00:00
|
|
|
self.open(reverse("bookmarks:index"), p)
|
2023-08-24 17:11:36 +00:00
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
expect(self.locate_bookmark("Bookmark 2")).to_have_class("shared")
|
|
|
|
self.locate_bookmark("Bookmark 2").get_by_text("Shared").click()
|
|
|
|
self.locate_bookmark("Bookmark 2").get_by_text("Yes").click()
|
2023-08-24 17:11:36 +00:00
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
expect(self.locate_bookmark("Bookmark 2")).not_to_have_class("shared")
|
2023-08-21 21:12:00 +00:00
|
|
|
self.assertReloads(0)
|
|
|
|
|
|
|
|
def test_active_bookmarks_partial_update_on_bulk_archive(self):
|
|
|
|
self.setup_fixture()
|
|
|
|
|
|
|
|
with sync_playwright() as p:
|
2024-01-27 10:29:16 +00:00
|
|
|
self.open(reverse("bookmarks:index"), p)
|
2023-08-21 21:12:00 +00:00
|
|
|
|
|
|
|
self.locate_bulk_edit_toggle().click()
|
2024-01-27 10:29:16 +00:00
|
|
|
self.locate_bookmark("Bookmark 2").locator(
|
2024-04-11 17:07:20 +00:00
|
|
|
"label.bulk-edit-checkbox"
|
2024-01-27 10:29:16 +00:00
|
|
|
).click()
|
|
|
|
self.select_bulk_action("Archive")
|
|
|
|
self.locate_bulk_edit_bar().get_by_text("Execute").click()
|
|
|
|
self.locate_bulk_edit_bar().get_by_text("Confirm").click()
|
|
|
|
|
|
|
|
self.assertVisibleBookmarks(["Bookmark 1", "Bookmark 3"])
|
|
|
|
self.assertVisibleTags(["Tag 1", "Tag 3"])
|
2023-08-21 21:12:00 +00:00
|
|
|
self.assertReloads(0)
|
|
|
|
|
|
|
|
def test_active_bookmarks_partial_update_on_bulk_delete(self):
|
|
|
|
self.setup_fixture()
|
|
|
|
|
|
|
|
with sync_playwright() as p:
|
2024-01-27 10:29:16 +00:00
|
|
|
self.open(reverse("bookmarks:index"), p)
|
2023-08-21 21:12:00 +00:00
|
|
|
|
|
|
|
self.locate_bulk_edit_toggle().click()
|
2024-01-27 10:29:16 +00:00
|
|
|
self.locate_bookmark("Bookmark 2").locator(
|
2024-04-11 17:07:20 +00:00
|
|
|
"label.bulk-edit-checkbox"
|
2024-01-27 10:29:16 +00:00
|
|
|
).click()
|
|
|
|
self.select_bulk_action("Delete")
|
|
|
|
self.locate_bulk_edit_bar().get_by_text("Execute").click()
|
|
|
|
self.locate_bulk_edit_bar().get_by_text("Confirm").click()
|
|
|
|
|
|
|
|
self.assertVisibleBookmarks(["Bookmark 1", "Bookmark 3"])
|
|
|
|
self.assertVisibleTags(["Tag 1", "Tag 3"])
|
2023-08-21 21:12:00 +00:00
|
|
|
self.assertReloads(0)
|
|
|
|
|
|
|
|
def test_archived_bookmarks_partial_update_on_unarchive(self):
|
|
|
|
self.setup_fixture()
|
|
|
|
|
|
|
|
with sync_playwright() as p:
|
2024-01-27 10:29:16 +00:00
|
|
|
self.open(reverse("bookmarks:archived"), p)
|
2023-08-21 21:12:00 +00:00
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
self.locate_bookmark("Archived Bookmark 2").get_by_text("Unarchive").click()
|
2023-08-21 21:12:00 +00:00
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
self.assertVisibleBookmarks(["Archived Bookmark 1", "Archived Bookmark 3"])
|
|
|
|
self.assertVisibleTags(["Archived Tag 1", "Archived Tag 3"])
|
2023-08-21 21:12:00 +00:00
|
|
|
self.assertReloads(0)
|
|
|
|
|
|
|
|
def test_archived_bookmarks_partial_update_on_delete(self):
|
|
|
|
self.setup_fixture()
|
|
|
|
|
|
|
|
with sync_playwright() as p:
|
2024-01-27 10:29:16 +00:00
|
|
|
self.open(reverse("bookmarks:archived"), p)
|
2023-08-21 21:12:00 +00:00
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
self.locate_bookmark("Archived Bookmark 2").get_by_text("Remove").click()
|
|
|
|
self.locate_bookmark("Archived Bookmark 2").get_by_text("Confirm").click()
|
2023-08-21 21:12:00 +00:00
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
self.assertVisibleBookmarks(["Archived Bookmark 1", "Archived Bookmark 3"])
|
|
|
|
self.assertVisibleTags(["Archived Tag 1", "Archived Tag 3"])
|
2023-08-21 21:12:00 +00:00
|
|
|
self.assertReloads(0)
|
|
|
|
|
2023-08-25 11:54:23 +00:00
|
|
|
def test_archived_bookmarks_partial_update_on_bulk_unarchive(self):
|
2023-08-21 21:12:00 +00:00
|
|
|
self.setup_fixture()
|
|
|
|
|
|
|
|
with sync_playwright() as p:
|
2024-01-27 10:29:16 +00:00
|
|
|
self.open(reverse("bookmarks:archived"), p)
|
2023-08-21 21:12:00 +00:00
|
|
|
|
|
|
|
self.locate_bulk_edit_toggle().click()
|
2024-01-27 10:29:16 +00:00
|
|
|
self.locate_bookmark("Archived Bookmark 2").locator(
|
2024-04-11 17:07:20 +00:00
|
|
|
"label.bulk-edit-checkbox"
|
2024-01-27 10:29:16 +00:00
|
|
|
).click()
|
|
|
|
self.select_bulk_action("Unarchive")
|
|
|
|
self.locate_bulk_edit_bar().get_by_text("Execute").click()
|
|
|
|
self.locate_bulk_edit_bar().get_by_text("Confirm").click()
|
|
|
|
|
|
|
|
self.assertVisibleBookmarks(["Archived Bookmark 1", "Archived Bookmark 3"])
|
|
|
|
self.assertVisibleTags(["Archived Tag 1", "Archived Tag 3"])
|
2023-08-21 21:12:00 +00:00
|
|
|
self.assertReloads(0)
|
|
|
|
|
|
|
|
def test_archived_bookmarks_partial_update_on_bulk_delete(self):
|
|
|
|
self.setup_fixture()
|
|
|
|
|
|
|
|
with sync_playwright() as p:
|
2024-01-27 10:29:16 +00:00
|
|
|
self.open(reverse("bookmarks:archived"), p)
|
2023-08-21 21:12:00 +00:00
|
|
|
|
|
|
|
self.locate_bulk_edit_toggle().click()
|
2024-01-27 10:29:16 +00:00
|
|
|
self.locate_bookmark("Archived Bookmark 2").locator(
|
2024-04-11 17:07:20 +00:00
|
|
|
"label.bulk-edit-checkbox"
|
2024-01-27 10:29:16 +00:00
|
|
|
).click()
|
|
|
|
self.select_bulk_action("Delete")
|
|
|
|
self.locate_bulk_edit_bar().get_by_text("Execute").click()
|
|
|
|
self.locate_bulk_edit_bar().get_by_text("Confirm").click()
|
|
|
|
|
|
|
|
self.assertVisibleBookmarks(["Archived Bookmark 1", "Archived Bookmark 3"])
|
|
|
|
self.assertVisibleTags(["Archived Tag 1", "Archived Tag 3"])
|
2023-08-21 21:12:00 +00:00
|
|
|
self.assertReloads(0)
|
|
|
|
|
|
|
|
def test_shared_bookmarks_partial_update_on_unarchive(self):
|
|
|
|
self.setup_fixture()
|
2024-01-27 10:29:16 +00:00
|
|
|
self.setup_numbered_bookmarks(
|
|
|
|
3, shared=True, prefix="My Bookmark", with_tags=True
|
|
|
|
)
|
2023-08-21 21:12:00 +00:00
|
|
|
|
|
|
|
with sync_playwright() as p:
|
2024-01-27 10:29:16 +00:00
|
|
|
self.open(reverse("bookmarks:shared"), p)
|
2023-08-21 21:12:00 +00:00
|
|
|
|
2024-01-27 10:29:16 +00:00
|
|
|
self.locate_bookmark("My Bookmark 2").get_by_text("Archive").click()
|
2023-08-21 21:12:00 +00:00
|
|
|
|
|
|
|
# Shared bookmarks page also shows archived bookmarks, though it probably shouldn't
|
2024-01-27 10:29:16 +00:00
|
|
|
self.assertVisibleBookmarks(
|
|
|
|
[
|
|
|
|
"My Bookmark 1",
|
|
|
|
"My Bookmark 2",
|
|
|
|
"My Bookmark 3",
|
|
|
|
"Joe's Bookmark 1",
|
|
|
|
"Joe's Bookmark 2",
|
|
|
|
"Joe's Bookmark 3",
|
|
|
|
]
|
|
|
|
)
|
|
|
|
self.assertVisibleTags(["Shared Tag 1", "Shared Tag 2", "Shared Tag 3"])
|
2023-08-21 21:12:00 +00:00
|
|
|
self.assertReloads(0)
|
|
|
|
|
|
|
|
def test_shared_bookmarks_partial_update_on_delete(self):
|
|
|
|
self.setup_fixture()
|
2024-01-27 10:29:16 +00:00
|
|
|
self.setup_numbered_bookmarks(
|
|
|
|
3, shared=True, prefix="My Bookmark", with_tags=True
|
|
|
|
)
|
2023-08-21 21:12:00 +00:00
|
|
|
|
|
|
|
with sync_playwright() as p:
|
2024-01-27 10:29:16 +00:00
|
|
|
self.open(reverse("bookmarks:shared"), p)
|
|
|
|
|
|
|
|
self.locate_bookmark("My Bookmark 2").get_by_text("Remove").click()
|
|
|
|
self.locate_bookmark("My Bookmark 2").get_by_text("Confirm").click()
|
|
|
|
|
|
|
|
self.assertVisibleBookmarks(
|
|
|
|
[
|
|
|
|
"My Bookmark 1",
|
|
|
|
"My Bookmark 3",
|
|
|
|
"Joe's Bookmark 1",
|
|
|
|
"Joe's Bookmark 2",
|
|
|
|
"Joe's Bookmark 3",
|
|
|
|
]
|
|
|
|
)
|
|
|
|
self.assertVisibleTags(["Shared Tag 1", "Shared Tag 3"])
|
2023-08-21 21:12:00 +00:00
|
|
|
self.assertReloads(0)
|