Skip to content

Commit

Permalink
Refactor client-side fetch logic (#693)
Browse files Browse the repository at this point in the history
* extract generic behaviors

* preserve query string when refreshing content

* refactor details modal refresh

* refactor bulk edit

* update tests

* restore tag modal

* Make IntelliJ aware of custom attributes

* improve e2e test coverage
  • Loading branch information
sissbruecker committed Apr 11, 2024
1 parent 82f86bf commit 65f0eb2
Show file tree
Hide file tree
Showing 32 changed files with 628 additions and 416 deletions.
38 changes: 38 additions & 0 deletions bookmarks/e2e/e2e_test_bookmark_details_modal.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.test import override_settings
from django.urls import reverse
from playwright.sync_api import sync_playwright, expect

Expand Down Expand Up @@ -44,14 +45,17 @@ def test_toggle_archived(self):
details_modal = self.open_details_modal(bookmark)
details_modal.get_by_text("Archived", exact=False).click()
expect(self.locate_bookmark(bookmark.title)).not_to_be_visible()
self.assertReloads(0)

# unarchive
url = reverse("bookmarks:archived")
self.page.goto(self.live_server_url + url)
self.resetReloads()

details_modal = self.open_details_modal(bookmark)
details_modal.get_by_text("Archived", exact=False).click()
expect(self.locate_bookmark(bookmark.title)).not_to_be_visible()
self.assertReloads(0)

def test_toggle_unread(self):
bookmark = self.setup_bookmark()
Expand All @@ -66,11 +70,13 @@ def test_toggle_unread(self):
details_modal.get_by_text("Unread").click()
bookmark_item = self.locate_bookmark(bookmark.title)
expect(bookmark_item.get_by_text("Unread")).to_be_visible()
self.assertReloads(0)

# mark as read
details_modal.get_by_text("Unread").click()
bookmark_item = self.locate_bookmark(bookmark.title)
expect(bookmark_item.get_by_text("Unread")).not_to_be_visible()
self.assertReloads(0)

def test_toggle_shared(self):
profile = self.get_or_create_test_user().profile
Expand All @@ -89,11 +95,13 @@ def test_toggle_shared(self):
details_modal.get_by_text("Shared").click()
bookmark_item = self.locate_bookmark(bookmark.title)
expect(bookmark_item.get_by_text("Shared")).to_be_visible()
self.assertReloads(0)

# unshare bookmark
details_modal.get_by_text("Shared").click()
bookmark_item = self.locate_bookmark(bookmark.title)
expect(bookmark_item.get_by_text("Shared")).not_to_be_visible()
self.assertReloads(0)

def test_edit_return_url(self):
bookmark = self.setup_bookmark()
Expand Down Expand Up @@ -131,3 +139,33 @@ def test_delete(self):
expect(self.locate_bookmark(bookmark.title)).not_to_be_visible()

self.assertEqual(Bookmark.objects.count(), 0)

@override_settings(LD_ENABLE_SNAPSHOTS=True)
def test_create_snapshot_remove_snapshot(self):
bookmark = self.setup_bookmark()

with sync_playwright() as p:
url = reverse("bookmarks:index") + f"?q={bookmark.title}"
self.open(url, p)

details_modal = self.open_details_modal(bookmark)
asset_list = details_modal.locator(".assets")

# No snapshots initially
snapshot = asset_list.get_by_text("HTML snapshot from", exact=False)
expect(snapshot).not_to_be_visible()

# Create snapshot
details_modal.get_by_text("Create HTML snapshot", exact=False).click()
self.assertReloads(0)

# Has new snapshots
expect(snapshot).to_be_visible()

# Create snapshot
asset_list.get_by_text("Remove", exact=False).click()
asset_list.get_by_text("Confirm", exact=False).click()

# Snapshot is removed
expect(snapshot).not_to_be_visible()
self.assertReloads(0)
8 changes: 4 additions & 4 deletions bookmarks/e2e/e2e_test_bookmark_page_bulk_edit.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ def test_select_all_toggles_all_checkboxes(self):

self.locate_bulk_edit_toggle().click()

checkboxes = page.locator("label[ld-bulk-edit-checkbox] input")
checkboxes = page.locator("label.bulk-edit-checkbox input")
self.assertEqual(6, checkboxes.count())
for i in range(checkboxes.count()):
expect(checkboxes.nth(i)).not_to_be_checked()
Expand Down Expand Up @@ -264,13 +264,13 @@ def test_select_across_is_unchecked_when_toggling_bookmark(self):

# Hide select across by toggling a single bookmark
self.locate_bookmark("Bookmark 1").locator(
"label[ld-bulk-edit-checkbox]"
"label.bulk-edit-checkbox"
).click()
expect(self.locate_bulk_edit_select_across()).not_to_be_visible()

# Show select across again, verify it is unchecked
self.locate_bookmark("Bookmark 1").locator(
"label[ld-bulk-edit-checkbox]"
"label.bulk-edit-checkbox"
).click()
expect(self.locate_bulk_edit_select_across()).not_to_be_checked()

Expand All @@ -297,7 +297,7 @@ def test_execute_resets_all_checkboxes(self):
expect(bookmark_list).not_to_be_visible()

# Verify bulk edit checkboxes are reset
checkboxes = page.locator("label[ld-bulk-edit-checkbox] input")
checkboxes = page.locator("label.bulk-edit-checkbox input")
self.assertEqual(31, checkboxes.count())
for i in range(checkboxes.count()):
expect(checkboxes.nth(i)).not_to_be_checked()
Expand Down
8 changes: 4 additions & 4 deletions bookmarks/e2e/e2e_test_bookmark_page_partial_updates.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ def test_active_bookmarks_partial_update_on_bulk_archive(self):

self.locate_bulk_edit_toggle().click()
self.locate_bookmark("Bookmark 2").locator(
"label[ld-bulk-edit-checkbox]"
"label.bulk-edit-checkbox"
).click()
self.select_bulk_action("Archive")
self.locate_bulk_edit_bar().get_by_text("Execute").click()
Expand All @@ -187,7 +187,7 @@ def test_active_bookmarks_partial_update_on_bulk_delete(self):

self.locate_bulk_edit_toggle().click()
self.locate_bookmark("Bookmark 2").locator(
"label[ld-bulk-edit-checkbox]"
"label.bulk-edit-checkbox"
).click()
self.select_bulk_action("Delete")
self.locate_bulk_edit_bar().get_by_text("Execute").click()
Expand Down Expand Up @@ -230,7 +230,7 @@ def test_archived_bookmarks_partial_update_on_bulk_unarchive(self):

self.locate_bulk_edit_toggle().click()
self.locate_bookmark("Archived Bookmark 2").locator(
"label[ld-bulk-edit-checkbox]"
"label.bulk-edit-checkbox"
).click()
self.select_bulk_action("Unarchive")
self.locate_bulk_edit_bar().get_by_text("Execute").click()
Expand All @@ -248,7 +248,7 @@ def test_archived_bookmarks_partial_update_on_bulk_delete(self):

self.locate_bulk_edit_toggle().click()
self.locate_bookmark("Archived Bookmark 2").locator(
"label[ld-bulk-edit-checkbox]"
"label.bulk-edit-checkbox"
).click()
self.select_bulk_action("Delete")
self.locate_bulk_edit_bar().get_by_text("Execute").click()
Expand Down
76 changes: 76 additions & 0 deletions bookmarks/e2e/e2e_test_tag_cloud_modal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
from django.test import override_settings
from django.urls import reverse
from playwright.sync_api import sync_playwright, expect, Locator

from bookmarks.e2e.helpers import LinkdingE2ETestCase
from bookmarks.models import Bookmark


class TagCloudModalE2ETestCase(LinkdingE2ETestCase):
def test_show_modal_close_modal(self):
self.setup_bookmark(tags=[self.setup_tag(name="cooking")])
self.setup_bookmark(tags=[self.setup_tag(name="hiking")])

with sync_playwright() as p:
page = self.open(reverse("bookmarks:index"), p)

# use smaller viewport to make tags button visible
page.set_viewport_size({"width": 375, "height": 812})

# open tag cloud modal
modal_trigger = page.locator(".content-area-header").get_by_role(
"button", name="Tags"
)
modal_trigger.click()

# verify modal is visible
modal = page.locator(".modal")
expect(modal).to_be_visible()
expect(modal.locator(".modal-title")).to_have_text("Tags")

# close with close button
modal.locator("button.close").click()
expect(modal).to_be_hidden()

# open modal again
modal_trigger.click()

# close with backdrop
backdrop = modal.locator(".modal-overlay")
backdrop.click(position={"x": 0, "y": 0})
expect(modal).to_be_hidden()

def test_select_tag(self):
self.setup_bookmark(tags=[self.setup_tag(name="cooking")])
self.setup_bookmark(tags=[self.setup_tag(name="hiking")])

with sync_playwright() as p:
page = self.open(reverse("bookmarks:index"), p)

# use smaller viewport to make tags button visible
page.set_viewport_size({"width": 375, "height": 812})

# open tag cloud modal
modal_trigger = page.locator(".content-area-header").get_by_role(
"button", name="Tags"
)
modal_trigger.click()

# verify tags are displayed
modal = page.locator(".modal")
unselected_tags = modal.locator(".unselected-tags")
expect(unselected_tags.get_by_text("cooking")).to_be_visible()
expect(unselected_tags.get_by_text("hiking")).to_be_visible()

# select tag
unselected_tags.get_by_text("cooking").click()

# open modal again
modal_trigger.click()

# verify tag is selected, other tag is not visible anymore
selected_tags = modal.locator(".selected-tags")
expect(selected_tags.get_by_text("cooking")).to_be_visible()

expect(unselected_tags.get_by_text("cooking")).not_to_be_visible()
expect(unselected_tags.get_by_text("hiking")).not_to_be_visible()
5 changes: 4 additions & 1 deletion bookmarks/e2e/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ def on_load(self):
def assertReloads(self, count: int):
self.assertEqual(self.num_loads, count)

def resetReloads(self):
self.num_loads = 0

def locate_bookmark_list(self):
return self.page.locator("ul[ld-bookmark-list]")

Expand All @@ -62,7 +65,7 @@ def locate_bulk_edit_bar(self):
return self.page.locator(".bulk-edit-bar")

def locate_bulk_edit_select_all(self):
return self.locate_bulk_edit_bar().locator("label[ld-bulk-edit-checkbox][all]")
return self.locate_bulk_edit_bar().locator("label.bulk-edit-checkbox.all")

def locate_bulk_edit_select_across(self):
return self.locate_bulk_edit_bar().locator("label.select-across")
Expand Down
61 changes: 1 addition & 60 deletions bookmarks/frontend/behaviors/bookmark-page.js
Original file line number Diff line number Diff line change
@@ -1,63 +1,4 @@
import { registerBehavior, swapContent } from "./index";

class BookmarkPage {
constructor(element) {
this.element = element;
this.form = element.querySelector("form.bookmark-actions");
this.form.addEventListener("submit", this.onFormSubmit.bind(this));

this.bookmarkList = element.querySelector(".bookmark-list-container");
this.tagCloud = element.querySelector(".tag-cloud-container");

document.addEventListener("bookmark-page-refresh", () => {
this.refresh();
});
}

async onFormSubmit(event) {
event.preventDefault();

const url = this.form.action;
const formData = new FormData(this.form);
formData.append(event.submitter.name, event.submitter.value);

await fetch(url, {
method: "POST",
body: formData,
redirect: "manual", // ignore redirect
});
await this.refresh();
}

async refresh() {
const query = window.location.search;
const bookmarksUrl = this.element.getAttribute("bookmarks-url");
const tagsUrl = this.element.getAttribute("tags-url");
Promise.all([
fetch(`${bookmarksUrl}${query}`).then((response) => response.text()),
fetch(`${tagsUrl}${query}`).then((response) => response.text()),
]).then(([bookmarkListHtml, tagCloudHtml]) => {
swapContent(this.bookmarkList, bookmarkListHtml);
swapContent(this.tagCloud, tagCloudHtml);

// Dispatch list updated event
const listElement = this.bookmarkList.querySelector(
"ul[data-bookmarks-total]",
);
const bookmarksTotal =
(listElement && listElement.dataset.bookmarksTotal) || 0;

this.bookmarkList.dispatchEvent(
new CustomEvent("bookmark-list-updated", {
bubbles: true,
detail: { bookmarksTotal },
}),
);
});
}
}

registerBehavior("ld-bookmark-page", BookmarkPage);
import { registerBehavior } from "./index";

class BookmarkItem {
constructor(element) {
Expand Down

0 comments on commit 65f0eb2

Please sign in to comment.