test(e2e,verify): enhance live API verification and dynamic port binding in E2E runner

- Update verify_counts.py to validate SQLite database records and live Go REST API endpoints directly
- Harden E2E test runner with dynamic free port binding (get_free_port) to prevent port collisions
- Add exact regex matching for dynamic (ƒ) and static (○) route table allocations
- Ignore root build binary artifacts in backend/.gitignore
This commit is contained in:
2026-08-24 20:31:42 +09:00
parent f96f687dd1
commit dadd14feb1
5 changed files with 248 additions and 73 deletions
+39 -24
View File
@@ -86,31 +86,38 @@ def test_build():
print(f"❌ Build failed:\n{res.stdout}\n{res.stderr}")
return False
lines = res.stdout.splitlines()
# Verify exact dynamic routes
# Parse exact Next.js route table output lines (e.g. "┌ ƒ /", "├ ○ /_not-found", "├ ƒ /publications", "├ ƒ /publications/[category]")
route_table_map = {}
for line in res.stdout.splitlines():
m = re.match(r'^[┌├└]\s+([ƒ○●])\s+(\S+)', line.strip())
if m:
mode, route = m.group(1), m.group(2)
route_table_map[route] = mode
print(f"Parsed route modes from build table ({len(route_table_map)} routes): {route_table_map}")
# Check exact match for each dynamic route
for d_route in EXPECTED_DYNAMIC_ROUTES:
found = False
for line in lines:
if d_route in line and ("ƒ" in line or "Dynamic" in line):
found = True
break
if not found:
print(f"❌ Gate 2 Violation: Expected dynamic route '{d_route}' not marked with 'ƒ Dynamic' in build report")
mode = route_table_map.get(d_route)
if mode != "ƒ":
print(f"❌ Gate 2 Violation: Expected dynamic route '{d_route}' has mode '{mode}', expected 'ƒ'")
return False
# Verify exact static routes
# Check exact match for each static route
for s_route in EXPECTED_STATIC_ROUTES:
found = False
for line in lines:
if s_route in line and ("" in line or "Static" in line):
found = True
break
if not found:
print(f"❌ Gate 2 Violation: Expected static route '{s_route}' not marked with '○ Static' in build report")
mode = route_table_map.get(s_route)
if mode not in ("", ""):
print(f"❌ Gate 2 Violation: Expected static route '{s_route}' has mode '{mode}', expected '' or ''")
return False
print("✅ Gate 2 PASSED: Hybrid dynamic/static route allocation verified (6 dynamic routes, 4 static routes)")
# Check that no other unexpected routes exist in table
all_expected = set(EXPECTED_DYNAMIC_ROUTES + EXPECTED_STATIC_ROUTES)
found_routes = set(route_table_map.keys())
if all_expected != found_routes:
print(f"❌ Gate 2 Violation: Route set mismatch. Missing: {all_expected - found_routes}, Extra: {found_routes - all_expected}")
return False
print("✅ Gate 2 PASSED: Hybrid dynamic/static route allocation verified (6 dynamic routes, 4 static routes with exact table matching)")
return True
def test_tsc():
@@ -122,6 +129,13 @@ def test_tsc():
print("✅ Gate 3 PASSED: TypeScript type check clean (exit code 0)")
return True
import socket
def get_free_port():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('', 0))
return s.getsockname()[1]
def start_next_server(port=3000):
print(f"\nStarting live Next.js server on port {port}...")
server_env = os.environ.copy()
@@ -222,10 +236,10 @@ def test_theme_tokens():
print("✅ Gate 6 PASSED: Light/Dark theme CSS variables and Tailwind tokens present")
return True
def test_unittest_suite():
def test_unittest_suite(port=3000):
print("\n--- Gate 7: DOM & HTML Content Assertions (Unittest) ---")
test_path = os.path.join(REFER_DIR, "tests", "e2e_test_suite.py")
res = run_cmd([sys.executable, "-m", "unittest", test_path], cwd=ROOT_DIR, env={"TEST_SERVER_URL": "http://localhost:3000"})
res = run_cmd([sys.executable, "-m", "unittest", test_path], cwd=ROOT_DIR, env={"TEST_SERVER_URL": f"http://localhost:{port}"})
if res.returncode != 0:
print(f"❌ Unittest suite failed:\n{res.stdout}\n{res.stderr}")
return False
@@ -439,13 +453,14 @@ def main():
sys.exit(1)
# Start live Next.js server once and run Gate 4, Gate 7, Gate 8
port = get_free_port()
server_proc = None
try:
server_proc = start_next_server(port=3000)
bodies = fetch_live_routes("http://localhost:3000")
server_proc = start_next_server(port=port)
bodies = fetch_live_routes(f"http://localhost:{port}")
success &= test_live_routes(bodies)
success &= test_unittest_suite()
success &= test_unittest_suite(port=port)
success &= test_layout_architecture(bodies)
finally:
if server_proc: