- Configure Next.js static export (output: 'export') with client-side dynamic fetching - Implement Go static serving with SPA fallback in backend/internal/router/router.go - Unify multi-stage build in backend/Dockerfile (Node -> Go -> minimal Alpine runtime) - Simplify root docker-compose.yml to single anl-app service on port 8080 - Update REQUIREMENTS.md DM-03 and AC-17 normative contracts to v3.0 Unified Go Backend - Restore strict regression verification in Gate 9 (AC-35/36/37) and unittest suite - All Go unit tests, TypeScript type checks, ESLint, and E2E gates passed clean
159 lines
6.7 KiB
Python
159 lines
6.7 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Python Unittest Suite for ANL Homepage E2E Verification
|
|
Queries live running unified Go backend server to assert DOM structure, text content, and theme attributes.
|
|
"""
|
|
|
|
import unittest
|
|
import os
|
|
import re
|
|
import urllib.request
|
|
|
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
TEST_SERVER_URL = os.environ.get("TEST_SERVER_URL", "http://localhost:8080")
|
|
|
|
class TestANLHomepageE2E(unittest.TestCase):
|
|
_html_cache = {}
|
|
|
|
def get_route_html(self, route):
|
|
if route in self._html_cache:
|
|
return self._html_cache[route]
|
|
url = f"{TEST_SERVER_URL}{route}"
|
|
req = urllib.request.Request(url, headers={"User-Agent": "E2ETestRunner"})
|
|
with urllib.request.urlopen(req, timeout=10) as resp:
|
|
html = resp.read().decode("utf-8")
|
|
self._html_cache[route] = html
|
|
return html
|
|
|
|
def read_html(self, relative_path):
|
|
route_map = {
|
|
"index.html": "/",
|
|
"members.html": "/members",
|
|
"publications.html": "/publications",
|
|
os.path.join("publications", "intl-journal-conf.html"): "/publications/intl-journal-conf",
|
|
"publications/intl-journal-conf.html": "/publications/intl-journal-conf",
|
|
os.path.join("publications", "domestic-journal-conf.html"): "/publications/domestic-journal-conf",
|
|
"publications/domestic-journal-conf.html": "/publications/domestic-journal-conf",
|
|
os.path.join("publications", "patent.html"): "/publications/patent",
|
|
"publications/patent.html": "/publications/patent",
|
|
"lectures.html": "/lectures",
|
|
"standardization.html": "/standardization",
|
|
}
|
|
route = route_map.get(relative_path, f"/{relative_path}")
|
|
return self.get_route_html(route)
|
|
|
|
def test_01_home_page_structure(self):
|
|
"""TC-T1-F3: Verify Home page HTML content and semantic structures."""
|
|
html = self.read_html("index.html")
|
|
|
|
# 1. Brand & Header titles
|
|
self.assertIn("ANL", html)
|
|
self.assertIn("AI Agent Networking LAB", html)
|
|
self.assertIn("Research Areas", html)
|
|
self.assertIn("International Standardizations", html)
|
|
|
|
# 2. Location / Address section
|
|
self.assertIn("address", html.lower())
|
|
self.assertIn("Kyungpook National University", html)
|
|
self.assertIn("College of IT Engineering", html)
|
|
self.assertIn("Prof. Seok-Joo Koh", html)
|
|
self.assertIn("sjkoh@knu.ac.kr", html)
|
|
|
|
def test_02_members_page_content(self):
|
|
"""TC-T1-F4: Verify Members page static shell & professor profile."""
|
|
html = self.read_html("members.html")
|
|
|
|
# Professor profile
|
|
self.assertIn("Prof. Seok-Joo Koh", html)
|
|
self.assertIn("Seok-Joo Koh", html)
|
|
self.assertIn("sjkoh@knu.ac.kr", html)
|
|
|
|
# Sections & Static Bio content
|
|
self.assertIn("LAB MEMBERS", html)
|
|
self.assertIn("Active Researchers", html)
|
|
self.assertIn("Project Editor", html)
|
|
self.assertIn("Graduates", html)
|
|
|
|
def test_03_publications_category_routes(self):
|
|
"""TC-T1-F5: Verify Publications categories live dynamic pages."""
|
|
cats = [
|
|
("intl-journal-conf.html", "International Journal"),
|
|
("domestic-journal-conf.html", "Domestic Journal"),
|
|
("patent.html", "Patent"),
|
|
]
|
|
for path_suffix, expected_text in cats:
|
|
rel_path = os.path.join("publications", path_suffix)
|
|
html = self.read_html(rel_path)
|
|
self.assertIn(expected_text, html, f"Category route {path_suffix} missing '{expected_text}'")
|
|
|
|
def test_04_lectures_page_content(self):
|
|
"""TC-T1-F6: Verify Lectures page HTML structure."""
|
|
html = self.read_html("lectures.html")
|
|
self.assertIn("LECTURES", html)
|
|
|
|
def test_05_standardization_page_content(self):
|
|
"""TC-T1-F6: Verify Standardization page standards bodies."""
|
|
html = self.read_html("standardization.html")
|
|
self.assertIn("International Standardization", html)
|
|
|
|
def test_06_theme_css_variables(self):
|
|
"""TC-T1-F2: Verify globals.css and built assets contain theme tokens."""
|
|
globals_path = os.path.join(BASE_DIR, "app", "globals.css")
|
|
with open(globals_path, "r", encoding="utf-8") as f:
|
|
css = f.read()
|
|
|
|
for token in ["--ink", "--ivory", "--paper", "--line", "--vermillion", "--cobalt"]:
|
|
self.assertIn(token, css, f"Missing CSS variable {token} in globals.css")
|
|
|
|
def test_07_research_projects_pageview(self):
|
|
"""TC-T1-F7: Verify Research Project PageView structural content in Home HTML."""
|
|
html = self.read_html("index.html")
|
|
|
|
# International Standardizations Section
|
|
self.assertIn("International Standardizations", html)
|
|
self.assertIn("IEC TC100: Multimedia Systems and Equipment", html)
|
|
self.assertIn("ISO/IEC JTC1/SC6: Reliable Multicasting", html)
|
|
|
|
def test_08_publications_highlights_and_category_nav(self):
|
|
"""TC-T1-F8: Verify Highlights heading and CategoryNav in Publications."""
|
|
html = self.read_html("publications.html")
|
|
|
|
# 1. Verify Highlights heading & section
|
|
self.assertIn("PUBLICATIONS", html)
|
|
self.assertIn("Highlights", html)
|
|
self.assertIn("Categories", html)
|
|
|
|
# 2. Verify category detail active card border & label
|
|
patent_html = self.read_html(os.path.join("publications", "patent.html"))
|
|
self.assertIn("border-2 border-cobalt-dark", patent_html)
|
|
self.assertIn("Active View ●", patent_html)
|
|
self.assertIn("Patent", patent_html)
|
|
|
|
def test_09_footer_cite_and_brand_links(self):
|
|
"""TC-T1-F9: Verify Footer CITE abbreviation and brand/contact elements."""
|
|
html = self.read_html("index.html")
|
|
|
|
# 1. Institution link label CITE
|
|
self.assertIn("<span>CITE</span>", html)
|
|
self.assertIn("<span>KNU</span>", html)
|
|
self.assertIn("<span>CSE</span>", html)
|
|
|
|
# 2. Advisor contact info
|
|
self.assertIn("Prof. Seok-Joo Koh", html)
|
|
self.assertIn("sjkoh@knu.ac.kr", html)
|
|
|
|
def test_10_subpage_layout_and_english_headers(self):
|
|
"""TC-T1-F10: Verify English page headers across all subpages."""
|
|
subpages = [
|
|
("members.html", "LAB MEMBERS"),
|
|
("publications.html", "PUBLICATIONS"),
|
|
("lectures.html", "LECTURES"),
|
|
("standardization.html", "International Standardization"),
|
|
]
|
|
for rel_path, expected_h1 in subpages:
|
|
html = self.read_html(rel_path)
|
|
self.assertIn(expected_h1, html, f"Subpage {rel_path} missing H1 '{expected_h1}'")
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|