feat: improve Wagtail admin editor experience for articles #40

Merged
mark merged 6 commits from feature/improve-editor-experience into main 2026-03-03 20:46:31 +00:00
4 changed files with 25 additions and 7 deletions
Showing only changes of commit be8d6d4a12 - Show all commits

View File

@@ -1,3 +1,5 @@
from datetime import timedelta
import pytest
from django.test import override_settings
from django.utils import timezone
@@ -32,7 +34,7 @@ def test_published_date_preserved_when_explicitly_set(home_page):
index = ArticleIndexPage(title="Articles", slug="articles")
home_page.add_child(instance=index)
author = AuthorFactory()
custom_date = timezone.now() - timezone.timedelta(days=30)
custom_date = timezone.now() - timedelta(days=30)
article = ArticlePage(
title="Custom Date",
slug="custom-date",
@@ -60,7 +62,7 @@ def test_homepage_orders_articles_by_published_date(home_page):
author=author,
summary="s",
body=[("rich_text", "<p>body</p>")],
published_date=timezone.now() - timezone.timedelta(days=10),
published_date=timezone.now() - timedelta(days=10),
)
index.add_child(instance=older)
older.save_revision().publish()
@@ -94,7 +96,7 @@ def test_article_index_orders_by_published_date(home_page, rf):
author=author,
summary="s",
body=[("rich_text", "<p>b</p>")],
published_date=timezone.now() - timezone.timedelta(days=5),
published_date=timezone.now() - timedelta(days=5),
)
index.add_child(instance=old)
old.save_revision().publish()

View File

@@ -20,6 +20,8 @@ class Command(BaseCommand):
def handle(self, *args, **options):
import datetime
from django.utils import timezone
root = Page.get_first_root_node()
home = HomePage.objects.child_of(root).first()
@@ -43,6 +45,9 @@ class Command(BaseCommand):
)
# Primary article — comments enabled, used by nightly journey test
# published_date is set explicitly to ensure deterministic ordering
# (most recent first) so this article appears at the top of listings.
now = timezone.now()
article = ArticlePage.objects.child_of(article_index).filter(slug="nightly-playwright-journey").first()
if article is None:
article = ArticlePage(
@@ -52,9 +57,12 @@ class Command(BaseCommand):
summary="Seeded article for nightly browser journey.",
body=[("rich_text", "<p>Seeded article body for nightly browser checks.</p>")],
comments_enabled=True,
published_date=now,
)
article_index.add_child(instance=article)
article.save_revision().publish()
# Ensure deterministic ordering — primary article always newest
ArticlePage.objects.filter(pk=article.pk).update(published_date=now)
# Seed one approved top-level comment on the primary article for reply E2E tests
if not Comment.objects.filter(article=article, author_name="E2E Approved Commenter").exists():
@@ -78,9 +86,13 @@ class Command(BaseCommand):
summary="An article with tags for E2E filter tests.",
body=[("rich_text", "<p>This article is tagged with AI Tools.</p>")],
comments_enabled=True,
published_date=now - datetime.timedelta(hours=1),
)
article_index.add_child(instance=tagged_article)
tagged_article.save_revision().publish()
ArticlePage.objects.filter(pk=tagged_article.pk).update(
published_date=now - datetime.timedelta(hours=1)
)
tagged_article.tags.add(tag)
tagged_article.save()
@@ -94,6 +106,7 @@ class Command(BaseCommand):
summary="An article with comments disabled.",
body=[("rich_text", "<p>Comments are disabled on this one.</p>")],
comments_enabled=False,
published_date=now - datetime.timedelta(hours=2),
)
article_index.add_child(instance=no_comments_article)
# Explicitly persist False after add_child (which internally calls save())
@@ -101,6 +114,9 @@ class Command(BaseCommand):
ArticlePage.objects.filter(pk=no_comments_article.pk).update(comments_enabled=False)
no_comments_article.comments_enabled = False
no_comments_article.save_revision().publish()
ArticlePage.objects.filter(pk=no_comments_article.pk).update(
published_date=now - datetime.timedelta(hours=2)
)
# About page
if not AboutPage.objects.child_of(home).filter(slug="about").exists():

View File

@@ -32,7 +32,7 @@ def test_nightly_playwright_journey() -> None:
article_url = article_href if article_href.startswith("http") else f"{base_url}{article_href}"
page.goto(article_url, wait_until="networkidle")
expect(page.get_by_role("heading", name="Comments")).to_be_visible()
expect(page.get_by_role("heading", name="Comments", exact=True)).to_be_visible()
expect(page.get_by_role("button", name="Post comment")).to_be_visible()
page.goto(f"{base_url}/feed/", wait_until="networkidle")

View File

@@ -19,7 +19,7 @@ def admin_login(page: Page, base_url: str) -> None:
def test_articles_menu_item_visible(page: Page, base_url: str) -> None:
"""The admin sidebar should contain an 'Articles' menu item."""
admin_login(page, base_url)
sidebar = page.locator("[data-side-panel]").first
sidebar = page.locator("#wagtail-sidebar")
articles_link = sidebar.get_by_role("link", name="Articles")
expect(articles_link).to_be_visible()
@@ -47,8 +47,8 @@ def test_article_editor_has_tabs(page: Page, base_url: str) -> None:
"""The article editor should have Content, Metadata, Publishing, and SEO tabs."""
admin_login(page, base_url)
page.goto(f"{base_url}/cms/articles/", wait_until="networkidle")
# Click the first article to edit it
page.get_by_text("Nightly Playwright Journey").first.click()
# Click the first article title link to edit it
page.get_by_role("link", name="Nightly Playwright Journey").first.click()
page.wait_for_load_state("networkidle")
expect(page.get_by_role("tab", name="Content")).to_be_visible()
expect(page.get_by_role("tab", name="Metadata")).to_be_visible()