128 lines
4.6 KiB
Python
128 lines
4.6 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
import tempfile
|
|
import threading
|
|
import unittest
|
|
import urllib.request
|
|
from pathlib import Path
|
|
|
|
from daily_report.config import Config
|
|
from daily_report.db import Database
|
|
from daily_report.feishu_auth import create_session_cookie
|
|
from daily_report.web import create_server
|
|
|
|
|
|
def make_server() -> tuple:
|
|
temp_dir = Path(tempfile.mkdtemp(prefix="daily-report-web-"))
|
|
seed_path = temp_dir / "employees.json"
|
|
seed_path.write_text(
|
|
json.dumps([{"feishu_user_id": "u_1", "name": "Lin", "department": "Design", "active": True}]),
|
|
encoding="utf-8",
|
|
)
|
|
config = Config(
|
|
root_dir=Path(__file__).resolve().parent.parent,
|
|
port=0,
|
|
base_url="http://localhost:8787",
|
|
database_path=temp_dir / "test.sqlite",
|
|
employee_seed_path=seed_path,
|
|
workday_calendar_path=temp_dir / "workday-calendar.json",
|
|
feishu_webhook_url="",
|
|
feishu_webhook_secret="",
|
|
feishu_app_id="",
|
|
feishu_app_secret="",
|
|
session_secret="session-secret",
|
|
)
|
|
db = Database(config.database_path, config.employee_seed_path)
|
|
server = create_server(config, db)
|
|
thread = threading.Thread(target=server.serve_forever, daemon=True)
|
|
thread.start()
|
|
return server, db, f"http://127.0.0.1:{server.server_address[1]}"
|
|
|
|
|
|
def get(url: str) -> tuple[int, str]:
|
|
with urllib.request.urlopen(url, timeout=5) as response:
|
|
return response.status, response.read().decode("utf-8")
|
|
|
|
|
|
class WebTest(unittest.TestCase):
|
|
def test_serves_submit_and_manager_pages(self) -> None:
|
|
server, db, base_url = make_server()
|
|
try:
|
|
status, submit = get(f"{base_url}/submit")
|
|
self.assertEqual(status, 200)
|
|
self.assertIn("每日报告", submit)
|
|
self.assertIn("1. \n2. \n3. \n4.", submit)
|
|
self.assertIn("我的历史日报", submit)
|
|
|
|
status, manager = get(f"{base_url}/manager")
|
|
self.assertEqual(status, 200)
|
|
self.assertIn("日报浏览", manager)
|
|
finally:
|
|
server.shutdown()
|
|
server.server_close()
|
|
db.close()
|
|
|
|
def test_accepts_report_submission_and_returns_summary(self) -> None:
|
|
server, db, base_url = make_server()
|
|
try:
|
|
request = urllib.request.Request(
|
|
f"{base_url}/api/reports",
|
|
data=json.dumps(
|
|
{
|
|
"feishu_user_id": "u_1",
|
|
"report_date": "2026-05-07",
|
|
"today_done": "完成 API",
|
|
"tomorrow_plan": "完善界面",
|
|
},
|
|
ensure_ascii=False,
|
|
).encode("utf-8"),
|
|
headers={"content-type": "application/json"},
|
|
method="POST",
|
|
)
|
|
with urllib.request.urlopen(request, timeout=5) as response:
|
|
self.assertEqual(response.status, 200)
|
|
|
|
status, body = get(f"{base_url}/api/reports?date=2026-05-07")
|
|
summary = json.loads(body)
|
|
self.assertEqual(status, 200)
|
|
self.assertEqual(summary["submittedCount"], 1)
|
|
self.assertEqual(summary["reports"][0]["today_done"], "完成 API")
|
|
|
|
status, history_body = get(f"{base_url}/api/reports/history?feishu_user_id=u_1")
|
|
history = json.loads(history_body)
|
|
self.assertEqual(status, 200)
|
|
self.assertEqual(history["employee"]["name"], "Lin")
|
|
self.assertEqual(history["reports"][0]["tomorrow_plan"], "完善界面")
|
|
finally:
|
|
server.shutdown()
|
|
server.server_close()
|
|
db.close()
|
|
|
|
def test_submit_page_uses_logged_in_feishu_identity(self) -> None:
|
|
server, db, base_url = make_server()
|
|
try:
|
|
opener = urllib.request.build_opener()
|
|
opener.addheaders = [
|
|
(
|
|
"Cookie",
|
|
"daily_report_session="
|
|
+ create_session_cookie({"feishu_user_id": "u_1", "name": "Lin"}, "session-secret"),
|
|
)
|
|
]
|
|
with opener.open(f"{base_url}/submit", timeout=5) as response:
|
|
body = response.read().decode("utf-8")
|
|
|
|
self.assertEqual(response.status, 200)
|
|
self.assertIn("Lin", body)
|
|
self.assertIn('type="hidden" name="feishu_user_id" value="u_1"', body)
|
|
self.assertNotIn("员工 ID<input", body)
|
|
finally:
|
|
server.shutdown()
|
|
server.server_close()
|
|
db.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|