mirror of
https://github.com/sissbruecker/linkding.git
synced 2026-02-28 06:53:12 +08:00
Run tests in CI in parallel (#1254)
* Run tests in CI in parallel * make tests automatically open/close playwright * fix parallel tests and screenshots * fix capturing screenshots for non-failing tests * cleanup * cleanup * format * log js errors * provide screenshots as artifacts * remove old scripts
This commit is contained in:
10
.github/workflows/main.yaml
vendored
10
.github/workflows/main.yaml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
uv sync
|
||||
mkdir data
|
||||
- name: Run tests
|
||||
run: uv run manage.py test bookmarks.tests
|
||||
run: uv run pytest -n auto
|
||||
e2e_tests:
|
||||
name: E2E Tests
|
||||
runs-on: ubuntu-latest
|
||||
@@ -59,4 +59,10 @@ jobs:
|
||||
npm run build
|
||||
uv run manage.py collectstatic
|
||||
- name: Run tests
|
||||
run: uv run manage.py test bookmarks.tests_e2e --pattern="e2e_test_*.py"
|
||||
run: uv run pytest bookmarks/tests_e2e -n auto -o "python_files=e2e_test_*.py"
|
||||
- name: Upload screenshots
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: e2e-screenshots
|
||||
path: test-results/screenshots
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -60,6 +60,7 @@ coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
test-results/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
from django.urls import reverse
|
||||
from playwright.sync_api import sync_playwright, expect
|
||||
from playwright.sync_api import expect
|
||||
|
||||
from bookmarks.tests_e2e.helpers import LinkdingE2ETestCase
|
||||
|
||||
|
||||
class A11yNavigationFocusTest(LinkdingE2ETestCase):
|
||||
def test_initial_page_load_focus(self):
|
||||
with sync_playwright() as p:
|
||||
# First page load should keep focus on the body
|
||||
page = self.open(reverse("linkding:bookmarks.index"), p)
|
||||
page = self.open(reverse("linkding:bookmarks.index"))
|
||||
focused_tag = page.evaluate("document.activeElement?.tagName")
|
||||
self.assertEqual("BODY", focused_tag)
|
||||
|
||||
@@ -31,8 +30,7 @@ class A11yNavigationFocusTest(LinkdingE2ETestCase):
|
||||
def test_page_navigation_focus(self):
|
||||
bookmark = self.setup_bookmark()
|
||||
|
||||
with sync_playwright() as p:
|
||||
page = self.open(reverse("linkding:bookmarks.index"), p)
|
||||
page = self.open(reverse("linkding:bookmarks.index"))
|
||||
|
||||
# Subsequent navigation should move focus to main content
|
||||
self.reset_focus()
|
||||
@@ -64,9 +62,7 @@ class A11yNavigationFocusTest(LinkdingE2ETestCase):
|
||||
|
||||
# Closing modal should move focus back to the bookmark item
|
||||
page.keyboard.press("Escape")
|
||||
focused = self.locate_bookmark(bookmark.title).locator(
|
||||
"a.view-action:focus"
|
||||
)
|
||||
focused = self.locate_bookmark(bookmark.title).locator("a.view-action:focus")
|
||||
expect(focused).to_be_visible()
|
||||
|
||||
def reset_focus(self):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from django.test import override_settings
|
||||
from django.urls import reverse
|
||||
from playwright.sync_api import sync_playwright, expect
|
||||
from playwright.sync_api import expect
|
||||
|
||||
from bookmarks.tests_e2e.helpers import LinkdingE2ETestCase
|
||||
from bookmarks.models import Bookmark
|
||||
@@ -10,8 +10,7 @@ class BookmarkDetailsModalE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_show_details(self):
|
||||
bookmark = self.setup_bookmark()
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.index"), p)
|
||||
self.open(reverse("linkding:bookmarks.index"))
|
||||
|
||||
details_modal = self.open_details_modal(bookmark)
|
||||
title = details_modal.locator("h2")
|
||||
@@ -20,8 +19,7 @@ class BookmarkDetailsModalE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_close_details(self):
|
||||
bookmark = self.setup_bookmark()
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.index"), p)
|
||||
self.open(reverse("linkding:bookmarks.index"))
|
||||
|
||||
# close with close button
|
||||
details_modal = self.open_details_modal(bookmark)
|
||||
@@ -42,10 +40,9 @@ class BookmarkDetailsModalE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_toggle_archived(self):
|
||||
bookmark = self.setup_bookmark()
|
||||
|
||||
with sync_playwright() as p:
|
||||
# archive
|
||||
url = reverse("linkding:bookmarks.index")
|
||||
self.open(url, p)
|
||||
self.open(url)
|
||||
|
||||
details_modal = self.open_details_modal(bookmark)
|
||||
details_modal.get_by_text("Archived", exact=False).click()
|
||||
@@ -65,10 +62,9 @@ class BookmarkDetailsModalE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_toggle_unread(self):
|
||||
bookmark = self.setup_bookmark()
|
||||
|
||||
with sync_playwright() as p:
|
||||
# mark as unread
|
||||
url = reverse("linkding:bookmarks.index")
|
||||
self.open(url, p)
|
||||
self.open(url)
|
||||
|
||||
details_modal = self.open_details_modal(bookmark)
|
||||
|
||||
@@ -90,10 +86,9 @@ class BookmarkDetailsModalE2ETestCase(LinkdingE2ETestCase):
|
||||
|
||||
bookmark = self.setup_bookmark()
|
||||
|
||||
with sync_playwright() as p:
|
||||
# share bookmark
|
||||
url = reverse("linkding:bookmarks.index")
|
||||
self.open(url, p)
|
||||
self.open(url)
|
||||
|
||||
details_modal = self.open_details_modal(bookmark)
|
||||
|
||||
@@ -111,9 +106,8 @@ class BookmarkDetailsModalE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_edit_return_url(self):
|
||||
bookmark = self.setup_bookmark()
|
||||
|
||||
with sync_playwright() as p:
|
||||
url = reverse("linkding:bookmarks.index") + f"?q={bookmark.title}"
|
||||
self.open(url, p)
|
||||
self.open(url)
|
||||
|
||||
details_modal = self.open_details_modal(bookmark)
|
||||
|
||||
@@ -129,9 +123,8 @@ class BookmarkDetailsModalE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_delete(self):
|
||||
bookmark = self.setup_bookmark()
|
||||
|
||||
with sync_playwright() as p:
|
||||
url = reverse("linkding:bookmarks.index") + f"?q={bookmark.title}"
|
||||
self.open(url, p)
|
||||
self.open(url)
|
||||
|
||||
details_modal = self.open_details_modal(bookmark)
|
||||
|
||||
@@ -152,9 +145,8 @@ class BookmarkDetailsModalE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_create_snapshot_remove_snapshot(self):
|
||||
bookmark = self.setup_bookmark()
|
||||
|
||||
with sync_playwright() as p:
|
||||
url = reverse("linkding:bookmarks.index") + f"?q={bookmark.title}"
|
||||
self.open(url, p)
|
||||
self.open(url)
|
||||
|
||||
details_modal = self.open_details_modal(bookmark)
|
||||
asset_list = details_modal.locator(".assets")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from unittest import skip
|
||||
|
||||
from django.urls import reverse
|
||||
from playwright.sync_api import sync_playwright, expect
|
||||
from playwright.sync_api import expect
|
||||
|
||||
from bookmarks.tests_e2e.helpers import LinkdingE2ETestCase
|
||||
|
||||
@@ -11,8 +11,7 @@ class BookmarkItemE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_toggle_notes_should_show_hide_notes(self):
|
||||
bookmark = self.setup_bookmark(notes="Test notes")
|
||||
|
||||
with sync_playwright() as p:
|
||||
page = self.open(reverse("linkding:bookmarks.index"), p)
|
||||
page = self.open(reverse("linkding:bookmarks.index"))
|
||||
|
||||
notes = self.locate_bookmark(bookmark.title).locator(".notes")
|
||||
expect(notes).to_be_hidden()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from django.urls import reverse
|
||||
from playwright.sync_api import sync_playwright, expect
|
||||
from playwright.sync_api import expect
|
||||
|
||||
from bookmarks.tests_e2e.helpers import LinkdingE2ETestCase
|
||||
from bookmarks.models import Bookmark
|
||||
@@ -36,8 +36,7 @@ class BookmarkPageBulkEditE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_active_bookmarks_bulk_select_across(self):
|
||||
self.setup_test_data()
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.index"), p)
|
||||
self.open(reverse("linkding:bookmarks.index"))
|
||||
|
||||
bookmark_list = self.locate_bookmark_list().element_handle()
|
||||
self.locate_bulk_edit_toggle().click()
|
||||
@@ -74,8 +73,7 @@ class BookmarkPageBulkEditE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_archived_bookmarks_bulk_select_across(self):
|
||||
self.setup_test_data()
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.archived"), p)
|
||||
self.open(reverse("linkding:bookmarks.archived"))
|
||||
|
||||
bookmark_list = self.locate_bookmark_list().element_handle()
|
||||
self.locate_bulk_edit_toggle().click()
|
||||
@@ -112,8 +110,7 @@ class BookmarkPageBulkEditE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_active_bookmarks_bulk_select_across_respects_query(self):
|
||||
self.setup_test_data()
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.index") + "?q=foo", p)
|
||||
self.open(reverse("linkding:bookmarks.index") + "?q=foo")
|
||||
|
||||
bookmark_list = self.locate_bookmark_list().element_handle()
|
||||
self.locate_bulk_edit_toggle().click()
|
||||
@@ -150,8 +147,7 @@ class BookmarkPageBulkEditE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_archived_bookmarks_bulk_select_across_respects_query(self):
|
||||
self.setup_test_data()
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.archived") + "?q=foo", p)
|
||||
self.open(reverse("linkding:bookmarks.archived") + "?q=foo")
|
||||
|
||||
bookmark_list = self.locate_bookmark_list().element_handle()
|
||||
self.locate_bulk_edit_toggle().click()
|
||||
@@ -188,9 +184,8 @@ class BookmarkPageBulkEditE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_select_all_toggles_all_checkboxes(self):
|
||||
self.setup_numbered_bookmarks(5)
|
||||
|
||||
with sync_playwright() as p:
|
||||
url = reverse("linkding:bookmarks.index")
|
||||
page = self.open(url, p)
|
||||
page = self.open(url)
|
||||
|
||||
self.locate_bulk_edit_toggle().click()
|
||||
|
||||
@@ -212,9 +207,8 @@ class BookmarkPageBulkEditE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_select_all_shows_select_across(self):
|
||||
self.setup_numbered_bookmarks(5)
|
||||
|
||||
with sync_playwright() as p:
|
||||
url = reverse("linkding:bookmarks.index")
|
||||
self.open(url, p)
|
||||
self.open(url)
|
||||
|
||||
self.locate_bulk_edit_toggle().click()
|
||||
|
||||
@@ -229,9 +223,8 @@ class BookmarkPageBulkEditE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_select_across_is_unchecked_when_toggling_all(self):
|
||||
self.setup_numbered_bookmarks(5)
|
||||
|
||||
with sync_playwright() as p:
|
||||
url = reverse("linkding:bookmarks.index")
|
||||
self.open(url, p)
|
||||
self.open(url)
|
||||
|
||||
self.locate_bulk_edit_toggle().click()
|
||||
|
||||
@@ -251,9 +244,8 @@ class BookmarkPageBulkEditE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_select_across_is_unchecked_when_toggling_bookmark(self):
|
||||
self.setup_numbered_bookmarks(5)
|
||||
|
||||
with sync_playwright() as p:
|
||||
url = reverse("linkding:bookmarks.index")
|
||||
self.open(url, p)
|
||||
self.open(url)
|
||||
|
||||
self.locate_bulk_edit_toggle().click()
|
||||
|
||||
@@ -263,23 +255,18 @@ class BookmarkPageBulkEditE2ETestCase(LinkdingE2ETestCase):
|
||||
expect(self.locate_bulk_edit_select_across()).to_be_checked()
|
||||
|
||||
# Hide select across by toggling a single bookmark
|
||||
self.locate_bookmark("Bookmark 1").locator(
|
||||
"label.bulk-edit-checkbox"
|
||||
).click()
|
||||
self.locate_bookmark("Bookmark 1").locator("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.bulk-edit-checkbox"
|
||||
).click()
|
||||
self.locate_bookmark("Bookmark 1").locator("label.bulk-edit-checkbox").click()
|
||||
expect(self.locate_bulk_edit_select_across()).not_to_be_checked()
|
||||
|
||||
def test_execute_resets_all_checkboxes(self):
|
||||
self.setup_numbered_bookmarks(100)
|
||||
|
||||
with sync_playwright() as p:
|
||||
url = reverse("linkding:bookmarks.index")
|
||||
page = self.open(url, p)
|
||||
page = self.open(url)
|
||||
|
||||
bookmark_list = self.locate_bookmark_list().element_handle()
|
||||
|
||||
@@ -309,9 +296,8 @@ class BookmarkPageBulkEditE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_update_select_across_bookmark_count(self):
|
||||
self.setup_numbered_bookmarks(100)
|
||||
|
||||
with sync_playwright() as p:
|
||||
url = reverse("linkding:bookmarks.index")
|
||||
self.open(url, p)
|
||||
self.open(url)
|
||||
|
||||
bookmark_list = self.locate_bookmark_list().element_handle()
|
||||
self.locate_bulk_edit_toggle().click()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from typing import List
|
||||
|
||||
from django.urls import reverse
|
||||
from playwright.sync_api import sync_playwright, expect
|
||||
from playwright.sync_api import expect
|
||||
|
||||
from bookmarks.tests_e2e.helpers import LinkdingE2ETestCase
|
||||
|
||||
@@ -43,9 +43,8 @@ class BookmarkPagePartialUpdatesE2ETestCase(LinkdingE2ETestCase):
|
||||
self.setup_numbered_bookmarks(5, prefix="foo")
|
||||
self.setup_numbered_bookmarks(5, prefix="bar")
|
||||
|
||||
with sync_playwright() as p:
|
||||
url = reverse("linkding:bookmarks.index") + "?q=foo"
|
||||
self.open(url, p)
|
||||
self.open(url)
|
||||
|
||||
self.assertVisibleBookmarks(["foo 1", "foo 2", "foo 3", "foo 4", "foo 5"])
|
||||
|
||||
@@ -55,9 +54,8 @@ class BookmarkPagePartialUpdatesE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_partial_update_respects_sort(self):
|
||||
self.setup_numbered_bookmarks(5, prefix="foo")
|
||||
|
||||
with sync_playwright() as p:
|
||||
url = reverse("linkding:bookmarks.index") + "?sort=title_asc"
|
||||
page = self.open(url, p)
|
||||
page = self.open(url)
|
||||
|
||||
first_item = page.locator("ul.bookmark-list > li").first
|
||||
expect(first_item).to_contain_text("foo 1")
|
||||
@@ -71,9 +69,8 @@ class BookmarkPagePartialUpdatesE2ETestCase(LinkdingE2ETestCase):
|
||||
# add a suffix, otherwise 'foo 1' also matches 'foo 10'
|
||||
self.setup_numbered_bookmarks(50, prefix="foo", suffix="-")
|
||||
|
||||
with sync_playwright() as p:
|
||||
url = reverse("linkding:bookmarks.index") + "?q=foo&page=2"
|
||||
self.open(url, p)
|
||||
self.open(url)
|
||||
|
||||
# with descending sort, page two has 'foo 1' to 'foo 20'
|
||||
expected_titles = [f"foo {i}-" for i in range(1, 21)]
|
||||
@@ -87,9 +84,8 @@ class BookmarkPagePartialUpdatesE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_multiple_partial_updates(self):
|
||||
self.setup_numbered_bookmarks(5)
|
||||
|
||||
with sync_playwright() as p:
|
||||
url = reverse("linkding:bookmarks.index")
|
||||
self.open(url, p)
|
||||
self.open(url)
|
||||
|
||||
self.locate_bookmark("Bookmark 1").get_by_text("Archive").click()
|
||||
self.assertVisibleBookmarks(
|
||||
@@ -107,8 +103,7 @@ class BookmarkPagePartialUpdatesE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_active_bookmarks_partial_update_on_archive(self):
|
||||
self.setup_fixture()
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.index"), p)
|
||||
self.open(reverse("linkding:bookmarks.index"))
|
||||
|
||||
self.locate_bookmark("Bookmark 2").get_by_text("Archive").click()
|
||||
|
||||
@@ -119,8 +114,7 @@ class BookmarkPagePartialUpdatesE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_active_bookmarks_partial_update_on_delete(self):
|
||||
self.setup_fixture()
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.index"), p)
|
||||
self.open(reverse("linkding:bookmarks.index"))
|
||||
|
||||
self.locate_bookmark("Bookmark 2").get_by_text("Remove").click()
|
||||
self.locate_confirm_dialog().get_by_text("Confirm").click()
|
||||
@@ -135,8 +129,7 @@ class BookmarkPagePartialUpdatesE2ETestCase(LinkdingE2ETestCase):
|
||||
bookmark2.unread = True
|
||||
bookmark2.save()
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.index"), p)
|
||||
self.open(reverse("linkding:bookmarks.index"))
|
||||
|
||||
expect(self.locate_bookmark("Bookmark 2")).to_have_class("unread")
|
||||
self.locate_bookmark("Bookmark 2").get_by_text("Unread").click()
|
||||
@@ -151,8 +144,7 @@ class BookmarkPagePartialUpdatesE2ETestCase(LinkdingE2ETestCase):
|
||||
bookmark2.shared = True
|
||||
bookmark2.save()
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.index"), p)
|
||||
self.open(reverse("linkding:bookmarks.index"))
|
||||
|
||||
expect(self.locate_bookmark("Bookmark 2")).to_have_class("shared")
|
||||
self.locate_bookmark("Bookmark 2").get_by_text("Shared").click()
|
||||
@@ -164,13 +156,10 @@ class BookmarkPagePartialUpdatesE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_active_bookmarks_partial_update_on_bulk_archive(self):
|
||||
self.setup_fixture()
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.index"), p)
|
||||
self.open(reverse("linkding:bookmarks.index"))
|
||||
|
||||
self.locate_bulk_edit_toggle().click()
|
||||
self.locate_bookmark("Bookmark 2").locator(
|
||||
"label.bulk-edit-checkbox"
|
||||
).click()
|
||||
self.locate_bookmark("Bookmark 2").locator("label.bulk-edit-checkbox").click()
|
||||
self.select_bulk_action("Archive")
|
||||
self.locate_bulk_edit_bar().get_by_text("Execute").click()
|
||||
self.locate_confirm_dialog().get_by_text("Confirm").click()
|
||||
@@ -182,13 +171,10 @@ class BookmarkPagePartialUpdatesE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_active_bookmarks_partial_update_on_bulk_delete(self):
|
||||
self.setup_fixture()
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.index"), p)
|
||||
self.open(reverse("linkding:bookmarks.index"))
|
||||
|
||||
self.locate_bulk_edit_toggle().click()
|
||||
self.locate_bookmark("Bookmark 2").locator(
|
||||
"label.bulk-edit-checkbox"
|
||||
).click()
|
||||
self.locate_bookmark("Bookmark 2").locator("label.bulk-edit-checkbox").click()
|
||||
self.select_bulk_action("Delete")
|
||||
self.locate_bulk_edit_bar().get_by_text("Execute").click()
|
||||
self.locate_confirm_dialog().get_by_text("Confirm").click()
|
||||
@@ -200,8 +186,7 @@ class BookmarkPagePartialUpdatesE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_archived_bookmarks_partial_update_on_unarchive(self):
|
||||
self.setup_fixture()
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.archived"), p)
|
||||
self.open(reverse("linkding:bookmarks.archived"))
|
||||
|
||||
self.locate_bookmark("Archived Bookmark 2").get_by_text("Unarchive").click()
|
||||
|
||||
@@ -212,8 +197,7 @@ class BookmarkPagePartialUpdatesE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_archived_bookmarks_partial_update_on_delete(self):
|
||||
self.setup_fixture()
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.archived"), p)
|
||||
self.open(reverse("linkding:bookmarks.archived"))
|
||||
|
||||
self.locate_bookmark("Archived Bookmark 2").get_by_text("Remove").click()
|
||||
self.locate_confirm_dialog().get_by_text("Confirm").click()
|
||||
@@ -225,8 +209,7 @@ class BookmarkPagePartialUpdatesE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_archived_bookmarks_partial_update_on_bulk_unarchive(self):
|
||||
self.setup_fixture()
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.archived"), p)
|
||||
self.open(reverse("linkding:bookmarks.archived"))
|
||||
|
||||
self.locate_bulk_edit_toggle().click()
|
||||
self.locate_bookmark("Archived Bookmark 2").locator(
|
||||
@@ -243,8 +226,7 @@ class BookmarkPagePartialUpdatesE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_archived_bookmarks_partial_update_on_bulk_delete(self):
|
||||
self.setup_fixture()
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.archived"), p)
|
||||
self.open(reverse("linkding:bookmarks.archived"))
|
||||
|
||||
self.locate_bulk_edit_toggle().click()
|
||||
self.locate_bookmark("Archived Bookmark 2").locator(
|
||||
@@ -264,8 +246,7 @@ class BookmarkPagePartialUpdatesE2ETestCase(LinkdingE2ETestCase):
|
||||
3, shared=True, prefix="My Bookmark", with_tags=True
|
||||
)
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.shared"), p)
|
||||
self.open(reverse("linkding:bookmarks.shared"))
|
||||
|
||||
self.locate_bookmark("My Bookmark 2").get_by_text("Archive").click()
|
||||
|
||||
@@ -289,8 +270,7 @@ class BookmarkPagePartialUpdatesE2ETestCase(LinkdingE2ETestCase):
|
||||
3, shared=True, prefix="My Bookmark", with_tags=True
|
||||
)
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.shared"), p)
|
||||
self.open(reverse("linkding:bookmarks.shared"))
|
||||
|
||||
self.locate_bookmark("My Bookmark 2").get_by_text("Remove").click()
|
||||
self.locate_confirm_dialog().get_by_text("Confirm").click()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from django.urls import reverse
|
||||
from playwright.sync_api import sync_playwright, expect
|
||||
from playwright.sync_api import expect
|
||||
|
||||
from bookmarks.tests_e2e.helpers import LinkdingE2ETestCase
|
||||
|
||||
@@ -9,9 +9,8 @@ class BookmarkItemE2ETestCase(LinkdingE2ETestCase):
|
||||
group1 = self.setup_numbered_bookmarks(3, prefix="foo")
|
||||
group2 = self.setup_numbered_bookmarks(3, prefix="bar")
|
||||
|
||||
with sync_playwright() as p:
|
||||
# shows all bookmarks initially
|
||||
page = self.open(reverse("linkding:bundles.new"), p)
|
||||
page = self.open(reverse("linkding:bundles.new"))
|
||||
|
||||
expect(
|
||||
page.get_by_text(f"Found 6 bookmarks matching this bundle")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from django.urls import reverse
|
||||
from playwright.sync_api import sync_playwright, expect
|
||||
from playwright.sync_api import expect
|
||||
|
||||
from bookmarks.tests_e2e.helpers import LinkdingE2ETestCase
|
||||
|
||||
@@ -22,13 +22,10 @@ class CollapseSidePanelE2ETestCase(LinkdingE2ETestCase):
|
||||
).to_be_visible()
|
||||
|
||||
def test_side_panel_should_be_visible_by_default(self):
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.index"), p)
|
||||
self.open(reverse("linkding:bookmarks.index"))
|
||||
self.assertSidePanelIsVisible()
|
||||
|
||||
self.page.goto(
|
||||
self.live_server_url + reverse("linkding:bookmarks.archived")
|
||||
)
|
||||
self.page.goto(self.live_server_url + reverse("linkding:bookmarks.archived"))
|
||||
self.assertSidePanelIsVisible()
|
||||
|
||||
self.page.goto(self.live_server_url + reverse("linkding:bookmarks.shared"))
|
||||
@@ -39,13 +36,10 @@ class CollapseSidePanelE2ETestCase(LinkdingE2ETestCase):
|
||||
user.profile.collapse_side_panel = True
|
||||
user.profile.save()
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.index"), p)
|
||||
self.open(reverse("linkding:bookmarks.index"))
|
||||
self.assertSidePanelIsHidden()
|
||||
|
||||
self.page.goto(
|
||||
self.live_server_url + reverse("linkding:bookmarks.archived")
|
||||
)
|
||||
self.page.goto(self.live_server_url + reverse("linkding:bookmarks.archived"))
|
||||
self.assertSidePanelIsHidden()
|
||||
|
||||
self.page.goto(self.live_server_url + reverse("linkding:bookmarks.shared"))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from django.urls import reverse
|
||||
from playwright.sync_api import sync_playwright, expect
|
||||
from playwright.sync_api import expect
|
||||
|
||||
from bookmarks.tests_e2e.helpers import LinkdingE2ETestCase
|
||||
|
||||
@@ -18,8 +18,7 @@ class DropdownE2ETestCase(LinkdingE2ETestCase):
|
||||
return self.locate_dropdown().locator(".menu")
|
||||
|
||||
def test_click_toggle_opens_and_closes_dropdown(self):
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.index"), p)
|
||||
self.open(reverse("linkding:bookmarks.index"))
|
||||
|
||||
toggle = self.locate_dropdown_toggle()
|
||||
menu = self.locate_dropdown_menu()
|
||||
@@ -33,8 +32,7 @@ class DropdownE2ETestCase(LinkdingE2ETestCase):
|
||||
expect(menu).not_to_be_visible()
|
||||
|
||||
def test_outside_click_closes_dropdown(self):
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.index"), p)
|
||||
self.open(reverse("linkding:bookmarks.index"))
|
||||
|
||||
toggle = self.locate_dropdown_toggle()
|
||||
menu = self.locate_dropdown_menu()
|
||||
@@ -48,8 +46,7 @@ class DropdownE2ETestCase(LinkdingE2ETestCase):
|
||||
expect(menu).not_to_be_visible()
|
||||
|
||||
def test_escape_closes_dropdown_and_restores_focus(self):
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.index"), p)
|
||||
self.open(reverse("linkding:bookmarks.index"))
|
||||
|
||||
toggle = self.locate_dropdown_toggle()
|
||||
menu = self.locate_dropdown_menu()
|
||||
@@ -68,8 +65,7 @@ class DropdownE2ETestCase(LinkdingE2ETestCase):
|
||||
expect(toggle).to_be_focused()
|
||||
|
||||
def test_focus_out_closes_dropdown(self):
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.index"), p)
|
||||
self.open(reverse("linkding:bookmarks.index"))
|
||||
|
||||
toggle = self.locate_dropdown_toggle()
|
||||
menu = self.locate_dropdown_menu()
|
||||
@@ -85,8 +81,7 @@ class DropdownE2ETestCase(LinkdingE2ETestCase):
|
||||
expect(menu).not_to_be_visible()
|
||||
|
||||
def test_aria_expanded_attribute(self):
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.index"), p)
|
||||
self.open(reverse("linkding:bookmarks.index"))
|
||||
|
||||
toggle = self.locate_dropdown_toggle()
|
||||
menu = self.locate_dropdown_menu()
|
||||
@@ -109,8 +104,7 @@ class DropdownE2ETestCase(LinkdingE2ETestCase):
|
||||
expect(toggle).to_have_attribute("aria-expanded", "false")
|
||||
|
||||
def test_can_click_menu_item(self):
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:bookmarks.index"), p)
|
||||
self.open(reverse("linkding:bookmarks.index"))
|
||||
|
||||
toggle = self.locate_dropdown_toggle()
|
||||
menu = self.locate_dropdown_menu()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.urls import reverse
|
||||
from playwright.sync_api import sync_playwright, expect
|
||||
from playwright.sync_api import expect
|
||||
|
||||
from bookmarks.tests_e2e.helpers import LinkdingE2ETestCase
|
||||
from bookmarks.services import website_loader
|
||||
@@ -24,14 +24,13 @@ class BookmarkFormE2ETestCase(LinkdingE2ETestCase):
|
||||
self.website_loader_patch.start()
|
||||
|
||||
def tearDown(self) -> None:
|
||||
super().tearDown()
|
||||
self.website_loader_patch.stop()
|
||||
super().tearDown()
|
||||
|
||||
def test_should_not_check_for_existing_bookmark(self):
|
||||
bookmark = self.setup_bookmark()
|
||||
|
||||
with sync_playwright() as p:
|
||||
page = self.open(reverse("linkding:bookmarks.edit", args=[bookmark.id]), p)
|
||||
page = self.open(reverse("linkding:bookmarks.edit", args=[bookmark.id]))
|
||||
|
||||
page.wait_for_timeout(timeout=1000)
|
||||
page.get_by_text("This URL is already bookmarked.").wait_for(state="hidden")
|
||||
@@ -41,8 +40,7 @@ class BookmarkFormE2ETestCase(LinkdingE2ETestCase):
|
||||
title="Initial title", description="Initial description"
|
||||
)
|
||||
|
||||
with sync_playwright() as p:
|
||||
page = self.open(reverse("linkding:bookmarks.edit", args=[bookmark.id]), p)
|
||||
page = self.open(reverse("linkding:bookmarks.edit", args=[bookmark.id]))
|
||||
page.wait_for_timeout(timeout=1000)
|
||||
|
||||
title = page.get_by_label("Title")
|
||||
@@ -53,8 +51,7 @@ class BookmarkFormE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_enter_url_should_not_prefill_title_and_description(self):
|
||||
bookmark = self.setup_bookmark()
|
||||
|
||||
with sync_playwright() as p:
|
||||
page = self.open(reverse("linkding:bookmarks.edit", args=[bookmark.id]), p)
|
||||
page = self.open(reverse("linkding:bookmarks.edit", args=[bookmark.id]))
|
||||
|
||||
page.get_by_label("URL").fill("https://example.com")
|
||||
page.wait_for_timeout(timeout=1000)
|
||||
@@ -67,8 +64,7 @@ class BookmarkFormE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_refresh_button_should_be_visible_when_editing(self):
|
||||
bookmark = self.setup_bookmark()
|
||||
|
||||
with sync_playwright() as p:
|
||||
page = self.open(reverse("linkding:bookmarks.edit", args=[bookmark.id]), p)
|
||||
page = self.open(reverse("linkding:bookmarks.edit", args=[bookmark.id]))
|
||||
|
||||
refresh_button = page.get_by_text("Refresh from website")
|
||||
expect(refresh_button).to_be_visible()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from django.urls import reverse
|
||||
from playwright.sync_api import sync_playwright, expect
|
||||
from playwright.sync_api import expect
|
||||
|
||||
from bookmarks.tests_e2e.helpers import LinkdingE2ETestCase
|
||||
|
||||
@@ -9,8 +9,7 @@ class FilterDrawerE2ETestCase(LinkdingE2ETestCase):
|
||||
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("linkding:bookmarks.index"), p)
|
||||
page = self.open(reverse("linkding:bookmarks.index"))
|
||||
|
||||
# use smaller viewport to make filter button visible
|
||||
page.set_viewport_size({"width": 375, "height": 812})
|
||||
@@ -40,8 +39,7 @@ class FilterDrawerE2ETestCase(LinkdingE2ETestCase):
|
||||
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("linkding:bookmarks.index"), p)
|
||||
page = self.open(reverse("linkding:bookmarks.index"))
|
||||
|
||||
# use smaller viewport to make filter button visible
|
||||
page.set_viewport_size({"width": 375, "height": 812})
|
||||
|
||||
@@ -1,32 +1,24 @@
|
||||
from django.urls import reverse
|
||||
from playwright.sync_api import sync_playwright, expect
|
||||
from playwright.sync_api import expect
|
||||
|
||||
from bookmarks.tests_e2e.helpers import LinkdingE2ETestCase
|
||||
|
||||
|
||||
class GlobalShortcutsE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_focus_search(self):
|
||||
with sync_playwright() as p:
|
||||
browser = self.setup_browser(p)
|
||||
page = browser.new_page()
|
||||
page.goto(self.live_server_url + reverse("linkding:bookmarks.index"))
|
||||
self.open(reverse("linkding:bookmarks.index"))
|
||||
|
||||
page.press("body", "s")
|
||||
self.page.press("body", "s")
|
||||
|
||||
expect(page.get_by_placeholder("Search for words or #tags")).to_be_focused()
|
||||
|
||||
browser.close()
|
||||
expect(
|
||||
self.page.get_by_placeholder("Search for words or #tags")
|
||||
).to_be_focused()
|
||||
|
||||
def test_add_bookmark(self):
|
||||
with sync_playwright() as p:
|
||||
browser = self.setup_browser(p)
|
||||
page = browser.new_page()
|
||||
page.goto(self.live_server_url + reverse("linkding:bookmarks.index"))
|
||||
self.open(reverse("linkding:bookmarks.index"))
|
||||
|
||||
page.press("body", "n")
|
||||
self.page.press("body", "n")
|
||||
|
||||
expect(page).to_have_url(
|
||||
expect(self.page).to_have_url(
|
||||
self.live_server_url + reverse("linkding:bookmarks.new")
|
||||
)
|
||||
|
||||
browser.close()
|
||||
|
||||
@@ -2,7 +2,7 @@ from unittest.mock import patch
|
||||
from urllib.parse import quote
|
||||
|
||||
from django.urls import reverse
|
||||
from playwright.sync_api import sync_playwright, expect
|
||||
from playwright.sync_api import expect
|
||||
|
||||
from bookmarks.models import Bookmark
|
||||
from bookmarks.services import website_loader
|
||||
@@ -26,12 +26,11 @@ class BookmarkFormE2ETestCase(LinkdingE2ETestCase):
|
||||
self.website_loader_mock = self.website_loader_patch.start()
|
||||
|
||||
def tearDown(self) -> None:
|
||||
super().tearDown()
|
||||
self.website_loader_patch.stop()
|
||||
super().tearDown()
|
||||
|
||||
def test_enter_url_prefills_title_and_description(self):
|
||||
with sync_playwright() as p:
|
||||
page = self.open(reverse("linkding:bookmarks.new"), p)
|
||||
page = self.open(reverse("linkding:bookmarks.new"))
|
||||
url = page.get_by_label("URL")
|
||||
title = page.get_by_label("Title")
|
||||
description = page.get_by_label("Description")
|
||||
@@ -43,8 +42,7 @@ class BookmarkFormE2ETestCase(LinkdingE2ETestCase):
|
||||
)
|
||||
|
||||
def test_enter_url_does_not_overwrite_modified_title_and_description(self):
|
||||
with sync_playwright() as p:
|
||||
page = self.open(reverse("linkding:bookmarks.new"), p)
|
||||
page = self.open(reverse("linkding:bookmarks.new"))
|
||||
url = page.get_by_label("URL")
|
||||
title = page.get_by_label("Title")
|
||||
description = page.get_by_label("Description")
|
||||
@@ -58,12 +56,10 @@ class BookmarkFormE2ETestCase(LinkdingE2ETestCase):
|
||||
expect(description).to_have_value("Modified description")
|
||||
|
||||
def test_with_initial_url_prefills_title_and_description(self):
|
||||
with sync_playwright() as p:
|
||||
page_url = (
|
||||
reverse("linkding:bookmarks.new")
|
||||
+ f"?url={quote('https://example.com')}"
|
||||
reverse("linkding:bookmarks.new") + f"?url={quote('https://example.com')}"
|
||||
)
|
||||
page = self.open(page_url, p)
|
||||
page = self.open(page_url)
|
||||
url = page.get_by_label("URL")
|
||||
title = page.get_by_label("Title")
|
||||
description = page.get_by_label("Description")
|
||||
@@ -79,12 +75,11 @@ class BookmarkFormE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_with_initial_url_title_description_does_not_overwrite_title_and_description(
|
||||
self,
|
||||
):
|
||||
with sync_playwright() as p:
|
||||
page_url = (
|
||||
reverse("linkding:bookmarks.new")
|
||||
+ f"?url={quote('https://example.com')}&title=Initial+title&description=Initial+description"
|
||||
)
|
||||
page = self.open(page_url, p)
|
||||
page = self.open(page_url)
|
||||
url = page.get_by_label("URL")
|
||||
title = page.get_by_label("Title")
|
||||
description = page.get_by_label("Description")
|
||||
@@ -105,8 +100,7 @@ class BookmarkFormE2ETestCase(LinkdingE2ETestCase):
|
||||
)
|
||||
tag_names = " ".join(existing_bookmark.tag_names)
|
||||
|
||||
with sync_playwright() as p:
|
||||
page = self.open(reverse("linkding:bookmarks.new"), p)
|
||||
page = self.open(reverse("linkding:bookmarks.new"))
|
||||
|
||||
# Enter bookmarked URL
|
||||
page.get_by_label("URL").fill(existing_bookmark.url)
|
||||
@@ -138,8 +132,7 @@ class BookmarkFormE2ETestCase(LinkdingE2ETestCase):
|
||||
notes="Existing notes", description="Existing description"
|
||||
)
|
||||
|
||||
with sync_playwright() as p:
|
||||
page = self.open(reverse("linkding:bookmarks.new"), p)
|
||||
page = self.open(reverse("linkding:bookmarks.new"))
|
||||
|
||||
details = page.locator("details.notes")
|
||||
expect(details).not_to_have_attribute("open", value="")
|
||||
@@ -152,13 +145,12 @@ class BookmarkFormE2ETestCase(LinkdingE2ETestCase):
|
||||
profile.auto_tagging_rules = "github.com dev github"
|
||||
profile.save()
|
||||
|
||||
with sync_playwright() as p:
|
||||
# Open page with URL that should have auto tags
|
||||
url = (
|
||||
reverse("linkding:bookmarks.new")
|
||||
+ "?url=https%3A%2F%2Fgithub.com%2Fsissbruecker%2Flinkding"
|
||||
)
|
||||
page = self.open(url, p)
|
||||
page = self.open(url)
|
||||
|
||||
auto_tags_hint = page.locator(".form-input-hint.auto-tags")
|
||||
expect(auto_tags_hint).to_be_visible()
|
||||
@@ -170,8 +162,7 @@ class BookmarkFormE2ETestCase(LinkdingE2ETestCase):
|
||||
expect(auto_tags_hint).to_be_hidden()
|
||||
|
||||
def test_clear_buttons_only_shown_when_fields_have_content(self):
|
||||
with sync_playwright() as p:
|
||||
page = self.open(reverse("linkding:bookmarks.new"), p)
|
||||
page = self.open(reverse("linkding:bookmarks.new"))
|
||||
|
||||
title_field = page.get_by_label("Title")
|
||||
title_clear_button = page.locator("ld-clear-button[data-for='id_title']")
|
||||
@@ -205,8 +196,7 @@ class BookmarkFormE2ETestCase(LinkdingE2ETestCase):
|
||||
title="Existing title", description="Existing description"
|
||||
)
|
||||
|
||||
with sync_playwright() as p:
|
||||
page = self.open(reverse("linkding:bookmarks.new"), p)
|
||||
page = self.open(reverse("linkding:bookmarks.new"))
|
||||
refresh_button = page.locator("#refresh-button")
|
||||
|
||||
# Initially, refresh button should be hidden
|
||||
@@ -233,8 +223,7 @@ class BookmarkFormE2ETestCase(LinkdingE2ETestCase):
|
||||
title="Existing title", description="Existing description"
|
||||
)
|
||||
|
||||
with sync_playwright() as p:
|
||||
page = self.open(reverse("linkding:bookmarks.new"), p)
|
||||
page = self.open(reverse("linkding:bookmarks.new"))
|
||||
url_field = page.get_by_label("URL")
|
||||
title_field = page.get_by_label("Title")
|
||||
description_field = page.get_by_label("Description")
|
||||
@@ -277,8 +266,7 @@ class BookmarkFormE2ETestCase(LinkdingE2ETestCase):
|
||||
title="Existing title", description="Existing description"
|
||||
)
|
||||
|
||||
with sync_playwright() as p:
|
||||
page = self.open(reverse("linkding:bookmarks.new"), p)
|
||||
page = self.open(reverse("linkding:bookmarks.new"))
|
||||
url_field = page.get_by_label("URL")
|
||||
title_field = page.get_by_label("Title")
|
||||
description_field = page.get_by_label("Description")
|
||||
@@ -314,8 +302,7 @@ class BookmarkFormE2ETestCase(LinkdingE2ETestCase):
|
||||
expect(description_field).to_have_class("form-input")
|
||||
|
||||
def test_ctrl_enter_submits_form_from_description(self):
|
||||
with sync_playwright() as p:
|
||||
page = self.open(reverse("linkding:bookmarks.new"), p)
|
||||
page = self.open(reverse("linkding:bookmarks.new"))
|
||||
url_field = page.get_by_label("URL")
|
||||
description_field = page.get_by_label("Description")
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from django.urls import reverse
|
||||
from playwright.sync_api import sync_playwright, expect
|
||||
from playwright.sync_api import expect
|
||||
|
||||
from bookmarks.tests_e2e.helpers import LinkdingE2ETestCase
|
||||
from bookmarks.models import UserProfile
|
||||
@@ -7,21 +7,18 @@ from bookmarks.models import UserProfile
|
||||
|
||||
class SettingsGeneralE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_should_only_enable_public_sharing_if_sharing_is_enabled(self):
|
||||
with sync_playwright() as p:
|
||||
browser = self.setup_browser(p)
|
||||
page = browser.new_page()
|
||||
page.goto(self.live_server_url + reverse("linkding:settings.general"))
|
||||
self.open(reverse("linkding:settings.general"))
|
||||
|
||||
enable_sharing = page.get_by_label("Enable bookmark sharing")
|
||||
enable_sharing_label = page.get_by_text("Enable bookmark sharing")
|
||||
enable_public_sharing = page.get_by_label("Enable public bookmark sharing")
|
||||
enable_public_sharing_label = page.get_by_text(
|
||||
enable_sharing = self.page.get_by_label("Enable bookmark sharing")
|
||||
enable_sharing_label = self.page.get_by_text("Enable bookmark sharing")
|
||||
enable_public_sharing = self.page.get_by_label("Enable public bookmark sharing")
|
||||
enable_public_sharing_label = self.page.get_by_text(
|
||||
"Enable public bookmark sharing"
|
||||
)
|
||||
default_mark_shared = page.get_by_label(
|
||||
default_mark_shared = self.page.get_by_label(
|
||||
"Create bookmarks as shared by default"
|
||||
)
|
||||
default_mark_shared_label = page.get_by_text(
|
||||
default_mark_shared_label = self.page.get_by_text(
|
||||
"Create bookmarks as shared by default"
|
||||
)
|
||||
|
||||
@@ -63,12 +60,9 @@ class SettingsGeneralE2ETestCase(LinkdingE2ETestCase):
|
||||
)
|
||||
profile.save()
|
||||
|
||||
with sync_playwright() as p:
|
||||
browser = self.setup_browser(p)
|
||||
page = browser.new_page()
|
||||
page.goto(self.live_server_url + reverse("linkding:settings.general"))
|
||||
self.open(reverse("linkding:settings.general"))
|
||||
|
||||
max_lines = page.get_by_label("Bookmark description max lines")
|
||||
max_lines = self.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):
|
||||
@@ -78,24 +72,18 @@ class SettingsGeneralE2ETestCase(LinkdingE2ETestCase):
|
||||
)
|
||||
profile.save()
|
||||
|
||||
with sync_playwright() as p:
|
||||
browser = self.setup_browser(p)
|
||||
page = browser.new_page()
|
||||
page.goto(self.live_server_url + reverse("linkding:settings.general"))
|
||||
self.open(reverse("linkding:settings.general"))
|
||||
|
||||
max_lines = page.get_by_label("Bookmark description max lines")
|
||||
max_lines = self.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("linkding:settings.general"))
|
||||
self.open(reverse("linkding:settings.general"))
|
||||
|
||||
max_lines = page.get_by_label("Bookmark description max lines")
|
||||
max_lines = self.page.get_by_label("Bookmark description max lines")
|
||||
expect(max_lines).to_be_hidden()
|
||||
|
||||
display = page.get_by_label("Bookmark description", exact=True)
|
||||
display = self.page.get_by_label("Bookmark description", exact=True)
|
||||
display.select_option("separate")
|
||||
expect(max_lines).to_be_visible()
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
from django.urls import reverse
|
||||
from playwright.sync_api import sync_playwright, expect
|
||||
from playwright.sync_api import expect
|
||||
|
||||
from bookmarks.tests_e2e.helpers import LinkdingE2ETestCase
|
||||
|
||||
|
||||
class SettingsIntegrationsE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_create_api_token(self):
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:settings.integrations"), p)
|
||||
self.open(reverse("linkding:settings.integrations"))
|
||||
|
||||
# Click create API token button
|
||||
self.page.get_by_text("Create API token").click()
|
||||
@@ -50,8 +49,7 @@ class SettingsIntegrationsE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_delete_api_token(self):
|
||||
self.setup_api_token(name="Token To Delete")
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:settings.integrations"), p)
|
||||
self.open(reverse("linkding:settings.integrations"))
|
||||
|
||||
token_table = self.page.locator("table.crud-table")
|
||||
expect(token_table.get_by_text("Token To Delete")).to_be_visible()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from django.urls import reverse
|
||||
from playwright.sync_api import sync_playwright, expect
|
||||
from playwright.sync_api import expect
|
||||
|
||||
from bookmarks.models import Tag
|
||||
from bookmarks.tests_e2e.helpers import LinkdingE2ETestCase
|
||||
@@ -25,8 +25,7 @@ class TagManagementE2ETestCase(LinkdingE2ETestCase):
|
||||
expect(success_message).to_contain_text(text)
|
||||
|
||||
def test_create_tag(self):
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:tags.index"), p)
|
||||
self.open(reverse("linkding:tags.index"))
|
||||
|
||||
# Click the Create Tag button to open the modal
|
||||
self.page.get_by_text("Create Tag").click()
|
||||
@@ -60,8 +59,7 @@ class TagManagementE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_create_tag_validation_error(self):
|
||||
existing_tag = self.setup_tag(name="existing-tag")
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:tags.index"), p)
|
||||
self.open(reverse("linkding:tags.index"))
|
||||
|
||||
# Click the Create Tag button to open the modal
|
||||
self.page.get_by_text("Create Tag").click()
|
||||
@@ -94,8 +92,7 @@ class TagManagementE2ETestCase(LinkdingE2ETestCase):
|
||||
def test_edit_tag(self):
|
||||
tag = self.setup_tag(name="old-name")
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:tags.index"), p)
|
||||
self.open(reverse("linkding:tags.index"))
|
||||
|
||||
# Click the Edit button for the tag
|
||||
tag_row = self.locate_tag_row(tag.name)
|
||||
@@ -131,8 +128,7 @@ class TagManagementE2ETestCase(LinkdingE2ETestCase):
|
||||
tag = self.setup_tag(name="tag-to-edit")
|
||||
other_tag = self.setup_tag(name="other-tag")
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:tags.index"), p)
|
||||
self.open(reverse("linkding:tags.index"))
|
||||
|
||||
# Click the Edit button for the tag
|
||||
tag_row = self.locate_tag_row(tag.name)
|
||||
@@ -170,8 +166,7 @@ class TagManagementE2ETestCase(LinkdingE2ETestCase):
|
||||
bookmark1 = self.setup_bookmark(tags=[merge_tag1])
|
||||
bookmark2 = self.setup_bookmark(tags=[merge_tag2])
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:tags.index"), p)
|
||||
self.open(reverse("linkding:tags.index"))
|
||||
|
||||
# Click the Merge Tags button to open the modal
|
||||
self.page.get_by_text("Merge Tags", exact=True).click()
|
||||
@@ -217,8 +212,7 @@ class TagManagementE2ETestCase(LinkdingE2ETestCase):
|
||||
target_tag = self.setup_tag(name="target-tag")
|
||||
merge_tag = self.setup_tag(name="merge-tag")
|
||||
|
||||
with sync_playwright() as p:
|
||||
self.open(reverse("linkding:tags.index"), p)
|
||||
self.open(reverse("linkding:tags.index"))
|
||||
|
||||
# Click the Merge Tags button to open the modal
|
||||
self.page.get_by_text("Merge Tags", exact=True).click()
|
||||
|
||||
@@ -1,18 +1,66 @@
|
||||
import os
|
||||
|
||||
from django.contrib.staticfiles.testing import LiveServerTestCase
|
||||
from playwright.sync_api import BrowserContext, Playwright, Page
|
||||
from playwright.sync_api import BrowserContext, Page, sync_playwright
|
||||
from playwright.sync_api import expect
|
||||
|
||||
from bookmarks.tests.helpers import BookmarkFactoryMixin
|
||||
|
||||
SCREENSHOT_DIR = "test-results/screenshots"
|
||||
|
||||
# Allow Django ORM operations within Playwright's async context
|
||||
os.environ.setdefault("DJANGO_ALLOW_ASYNC_UNSAFE", "true")
|
||||
|
||||
|
||||
class LinkdingE2ETestCase(LiveServerTestCase, BookmarkFactoryMixin):
|
||||
def setUp(self) -> None:
|
||||
self.client.force_login(self.get_or_create_test_user())
|
||||
self.cookie = self.client.cookies["sessionid"]
|
||||
self.playwright = None
|
||||
self.browser = None
|
||||
self.context = None
|
||||
self.page = None
|
||||
|
||||
def setup_browser(self, playwright) -> BrowserContext:
|
||||
browser = playwright.chromium.launch(headless=True)
|
||||
context = browser.new_context()
|
||||
def tearDown(self) -> None:
|
||||
if self.page and self._test_has_failed():
|
||||
self._capture_screenshot()
|
||||
if self.browser:
|
||||
self.browser.close()
|
||||
if self.playwright:
|
||||
self.playwright.stop()
|
||||
super().tearDown()
|
||||
|
||||
def _test_has_failed(self) -> bool:
|
||||
"""Detect if the current test has failed. Works with both Django/unittest and pytest."""
|
||||
# Check _outcome for failure info
|
||||
if self._outcome is not None:
|
||||
result = self._outcome.result
|
||||
if result:
|
||||
# pytest stores exception info in _excinfo
|
||||
if hasattr(result, "_excinfo") and result._excinfo:
|
||||
return True
|
||||
# Django/unittest stores failures and errors in the result
|
||||
# Check if THIS test is in failures/errors (not just any test)
|
||||
if hasattr(result, "failures"):
|
||||
for failed_test, _ in result.failures:
|
||||
if failed_test is self:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _ensure_playwright(self):
|
||||
if not self.playwright:
|
||||
self.playwright = sync_playwright().start()
|
||||
self.browser = self.playwright.chromium.launch(headless=True)
|
||||
|
||||
def _capture_screenshot(self):
|
||||
os.makedirs(SCREENSHOT_DIR, exist_ok=True)
|
||||
filename = f"{self.__class__.__name__}_{self._testMethodName}.png"
|
||||
filepath = os.path.join(SCREENSHOT_DIR, filename)
|
||||
self.page.screenshot(path=filepath, full_page=True)
|
||||
|
||||
def setup_browser(self) -> BrowserContext:
|
||||
self._ensure_playwright()
|
||||
context = self.browser.new_context()
|
||||
context.add_cookies(
|
||||
[
|
||||
{
|
||||
@@ -25,14 +73,20 @@ class LinkdingE2ETestCase(LiveServerTestCase, BookmarkFactoryMixin):
|
||||
)
|
||||
return context
|
||||
|
||||
def open(self, url: str, playwright: Playwright) -> Page:
|
||||
browser = self.setup_browser(playwright)
|
||||
self.page = browser.new_page()
|
||||
def open(self, url: str) -> Page:
|
||||
self.context = self.setup_browser()
|
||||
self.page = self.context.new_page()
|
||||
self.page.on("pageerror", self.on_page_error)
|
||||
self.page.goto(self.live_server_url + url)
|
||||
self.page.on("load", self.on_load)
|
||||
self.num_loads = 0
|
||||
return self.page
|
||||
|
||||
def on_page_error(self, error):
|
||||
print(f"[JS ERROR] {error}")
|
||||
if hasattr(error, "stack"):
|
||||
print(f"[JS STACK] {error.stack}")
|
||||
|
||||
def on_load(self):
|
||||
self.num_loads += 1
|
||||
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
# Example setup for OIDC with Zitadel
|
||||
export LD_ENABLE_OIDC=True
|
||||
export OIDC_USE_PKCE=True
|
||||
export OIDC_OP_AUTHORIZATION_ENDPOINT=http://localhost:8080/oauth/v2/authorize
|
||||
export OIDC_OP_TOKEN_ENDPOINT=http://localhost:8080/oauth/v2/token
|
||||
export OIDC_OP_USER_ENDPOINT=http://localhost:8080/oidc/v1/userinfo
|
||||
export OIDC_OP_JWKS_ENDPOINT=http://localhost:8080/oauth/v2/keys
|
||||
export OIDC_RP_CLIENT_ID=<client-id>
|
||||
@@ -1,12 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Make sure Chromium is installed
|
||||
uv run playwright install chromium
|
||||
|
||||
# Test server loads assets from static folder, so make sure files there are up-to-date
|
||||
rm -rf static
|
||||
npm run build
|
||||
uv run manage.py collectstatic
|
||||
|
||||
# Run E2E tests
|
||||
uv run manage.py test bookmarks.tests_e2e --pattern="e2e_test_*.py"
|
||||
@@ -23,7 +23,8 @@ export LD_DB_ENGINE=postgres
|
||||
export LD_DB_USER=linkding
|
||||
export LD_DB_PASSWORD=linkding
|
||||
|
||||
./scripts/test.sh
|
||||
make test
|
||||
make e2e
|
||||
|
||||
# Remove postgres container
|
||||
docker rm -f linkding-postgres-test || true
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
uv run manage.py test bookmarks.tests
|
||||
@@ -1,2 +0,0 @@
|
||||
./scripts/test-unit.sh
|
||||
./scripts/test-e2e.sh
|
||||
Reference in New Issue
Block a user