## Summary Closes #18. - Add per-page titles, meta descriptions, Open Graph/Twitter tags, and canonical URLs on public `base2.html` pages - Improve semantic structure: skip link, primary nav ARIA, single `<main id="main-content">`, heading hierarchy, descriptive image alts - Publish `/robots.txt`, `/sitemap.xml`, and `/llms.txt` (linked from site head via `rel="alternate"`) - Agentic/a11y fixes: membership checkbox label associations, ZIP `name` attribute, layout stability (image aspect-ratio / min-height), footer year without `document.write` - WebMCP deferred — membership + Stripe checkout remain standard HTML/Stripe flows; no audit flag justified custom MCP surface yet ## Lighthouse / agentic notes Baseline Lighthouse runs still need Chrome Canary export on staging/prod. Structural SEO/a11y items from the ticket are implemented so follow-up audits can capture before/after scores. Expected audit wins vs prior minimal `charset`+`viewport` head: - SEO: unique titles/descriptions, crawl directives, sitemap - Agentic/a11y: landmarks, labels, CLS-oriented image sizing ## Test plan - [x] `uv run python manage.py test schasite` (34 passed) - [ ] Spot-check Home/About/Calendar/Dues/Membership/Board/Links in browser - [ ] Confirm `/robots.txt`, `/sitemap.xml`, `/llms.txt` on deployed host - [ ] Run Lighthouse SEO + Agentic browsing on key pages and note before/after pass ratio on the issue Reviewed-on: #27
This commit was merged in pull request #27.
This commit is contained in:
@@ -89,6 +89,49 @@ class PublicPageTests(TestCase):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, "City of Wheaton")
|
||||
|
||||
def test_public_pages_include_seo_metadata(self):
|
||||
pages = [
|
||||
("index2", "Home | Stonehedge"),
|
||||
("about_us2", "About Us | Stonehedge"),
|
||||
("calendar2", "Calendar | Stonehedge"),
|
||||
("dues2", "Pay Dues | Stonehedge"),
|
||||
("membership_form2", "Join Today | Stonehedge"),
|
||||
("scha_board2", "SCHA Board | Stonehedge"),
|
||||
("useful_links2", "Useful Links | Stonehedge"),
|
||||
]
|
||||
|
||||
for name, title_fragment in pages:
|
||||
with self.subTest(page=name):
|
||||
response = self.client.get(reverse(name))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, f"<title>{title_fragment}")
|
||||
self.assertContains(response, 'name="description"')
|
||||
self.assertContains(response, 'property="og:title"')
|
||||
self.assertContains(response, 'rel="canonical"')
|
||||
self.assertContains(response, 'id="main-content"')
|
||||
self.assertContains(response, "Skip to main content")
|
||||
|
||||
def test_robots_txt(self):
|
||||
response = self.client.get(reverse("robots_txt"))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response["Content-Type"].split(";")[0], "text/plain")
|
||||
self.assertContains(response, "Sitemap:")
|
||||
self.assertContains(response, "Disallow: /admin/")
|
||||
|
||||
def test_sitemap_xml(self):
|
||||
response = self.client.get(reverse("sitemap_xml"))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn("xml", response["Content-Type"])
|
||||
self.assertContains(response, reverse("index2"))
|
||||
self.assertContains(response, reverse("dues2"))
|
||||
|
||||
def test_llms_txt(self):
|
||||
response = self.client.get(reverse("llms_txt"))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response["Content-Type"].split(";")[0], "text/plain")
|
||||
self.assertContains(response, "Stonehedge Community Homeowners Association")
|
||||
self.assertContains(response, reverse("membership_form2").lstrip("/"))
|
||||
|
||||
|
||||
@override_settings(
|
||||
RECAPTCHA_PUBLIC_KEY="test-public-key",
|
||||
|
||||
Reference in New Issue
Block a user