209 lines
9.9 KiB
Python
209 lines
9.9 KiB
Python
import json
|
|
import uuid
|
|
import pytest
|
|
from backend.app import create_app
|
|
|
|
|
|
@pytest.fixture
|
|
def client():
|
|
app = create_app()
|
|
app.config["TESTING"] = True
|
|
with app.test_client() as client:
|
|
yield client
|
|
|
|
|
|
@pytest.fixture
|
|
def auth_headers(client):
|
|
"""
|
|
Registers a test user with unique username and returns auth headers.
|
|
"""
|
|
unique_suffix = str(uuid.uuid4())[:8]
|
|
username = f"projtest_{unique_suffix}"
|
|
email = f"{username}@example.com"
|
|
payload = {
|
|
"username": username,
|
|
"email": email,
|
|
"password": "Password123"
|
|
}
|
|
response = client.post("/api/register", data=json.dumps(payload), content_type="application/json")
|
|
assert response.status_code == 201, f"Registration failed: {response.data.decode()}"
|
|
data = json.loads(response.data)
|
|
token = data["token"]
|
|
return {"Authorization": f"Bearer {token}"}
|
|
|
|
|
|
def test_create_project(client, auth_headers):
|
|
payload = {
|
|
"name": "Test Project",
|
|
"topic": "Testing",
|
|
"description": "A project for testing purposes."
|
|
}
|
|
response = client.post("/api/projects", data=json.dumps(payload),
|
|
content_type="application/json", headers=auth_headers)
|
|
assert response.status_code == 201, f"Create project failed: {response.data.decode()}"
|
|
data = json.loads(response.data)
|
|
assert "project_id" in data
|
|
assert "passkey" in data
|
|
|
|
|
|
def test_get_projects(client, auth_headers):
|
|
# Create two projects.
|
|
payload1 = {"name": "Test Project One", "description": "First test project."}
|
|
payload2 = {"name": "Test Project Two", "description": "Second test project."}
|
|
|
|
response1 = client.post("/api/projects", data=json.dumps(payload1),
|
|
content_type="application/json", headers=auth_headers)
|
|
response2 = client.post("/api/projects", data=json.dumps(payload2),
|
|
content_type="application/json", headers=auth_headers)
|
|
assert response1.status_code == 201, f"Project one creation failed: {response1.data.decode()}"
|
|
assert response2.status_code == 201, f"Project two creation failed: {response2.data.decode()}"
|
|
|
|
response = client.get("/api/projects", headers=auth_headers)
|
|
assert response.status_code == 200, f"Get projects failed: {response.data.decode()}"
|
|
data = json.loads(response.data)
|
|
assert "projects" in data
|
|
assert isinstance(data["projects"], list)
|
|
assert len(data["projects"]) >= 2
|
|
|
|
|
|
def test_get_project_detail(client, auth_headers):
|
|
payload = {"name": "Detail Project1111", "description": "A project for detail testing."}
|
|
create_resp = client.post("/api/projects", data=json.dumps(payload),
|
|
content_type="application/json", headers=auth_headers)
|
|
assert create_resp.status_code == 201, f"Creation failed: {create_resp.data.decode()}"
|
|
project_id = json.loads(create_resp.data)["project_id"]
|
|
|
|
response = client.get(f"/api/projects/{project_id}", headers=auth_headers)
|
|
assert response.status_code == 200, f"Get detail failed: {response.data.decode()}"
|
|
data = json.loads(response.data)
|
|
assert data.get("name") == "Detail Project1111"
|
|
assert "updatedAt" in data
|
|
|
|
|
|
def test_update_project(client, auth_headers):
|
|
payload = {"name": "Update Project", "description": "Initial description."}
|
|
create_resp = client.post("/api/projects", data=json.dumps(payload),
|
|
content_type="application/json", headers=auth_headers)
|
|
assert create_resp.status_code == 201, f"Creation failed: {create_resp.data.decode()}"
|
|
project_id = json.loads(create_resp.data)["project_id"]
|
|
|
|
update_payload = {"description": "Updated description.", "topic": "Updated Topic"}
|
|
update_resp = client.put(f"/api/projects/{project_id}", data=json.dumps(update_payload),
|
|
content_type="application/json", headers=auth_headers)
|
|
assert update_resp.status_code == 200, f"Update failed: {update_resp.data.decode()}"
|
|
|
|
detail_resp = client.get(f"/api/projects/{project_id}", headers=auth_headers)
|
|
detail_data = json.loads(detail_resp.data)
|
|
assert detail_data.get("description") == "Updated description."
|
|
assert detail_data.get("topic") == "Updated Topic"
|
|
|
|
|
|
def test_delete_project(client, auth_headers):
|
|
payload = {"name": "Delete Project", "description": "Project to be deleted."}
|
|
create_resp = client.post("/api/projects", data=json.dumps(payload),
|
|
content_type="application/json", headers=auth_headers)
|
|
assert create_resp.status_code == 201, f"Creation failed: {create_resp.data.decode()}"
|
|
project_id = json.loads(create_resp.data)["project_id"]
|
|
|
|
delete_resp = client.delete(f"/api/projects/{project_id}", headers=auth_headers)
|
|
assert delete_resp.status_code == 200, f"Deletion failed: {delete_resp.data.decode()}"
|
|
detail_resp = client.get(f"/api/projects/{project_id}", headers=auth_headers)
|
|
assert detail_resp.status_code == 404, "Deleted project still accessible"
|
|
|
|
|
|
def test_get_project_summaries(client, auth_headers):
|
|
# Create a new project to ensure at least one exists.
|
|
payload = {"name": "Summary Project", "description": "Project for summary test."}
|
|
create_resp = client.post("/api/projects", data=json.dumps(payload),
|
|
content_type="application/json", headers=auth_headers)
|
|
assert create_resp.status_code == 201, f"Project creation failed: {create_resp.data.decode()}"
|
|
|
|
response = client.get("/api/projects/summary", headers=auth_headers)
|
|
assert response.status_code == 200, f"Summary fetch failed: {response.data.decode()}"
|
|
data = json.loads(response.data)
|
|
assert "projects" in data
|
|
# Each project summary should include project_id, name, and updatedAt.
|
|
for proj in data["projects"]:
|
|
assert "project_id" in proj
|
|
assert "name" in proj
|
|
assert "updatedAt" in proj
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# New Tests
|
|
# ------------------------------------------------------------------------------
|
|
|
|
def test_get_project_info(client, auth_headers):
|
|
"""
|
|
Tests the /api/projects/<project_id>/info endpoint,
|
|
which returns name, topic, description, keywords, summary.
|
|
"""
|
|
payload = {
|
|
"name": "Info Project",
|
|
"topic": "InfoTopic",
|
|
"description": "Project with an info endpoint."
|
|
}
|
|
create_resp = client.post("/api/projects", data=json.dumps(payload),
|
|
content_type="application/json", headers=auth_headers)
|
|
assert create_resp.status_code == 201, f"Project creation failed: {create_resp.data.decode()}"
|
|
project_id = json.loads(create_resp.data)["project_id"]
|
|
|
|
info_resp = client.get(f"/api/projects/{project_id}/info", headers=auth_headers)
|
|
assert info_resp.status_code == 200, f"Get project info failed: {info_resp.data.decode()}"
|
|
info_data = json.loads(info_resp.data)
|
|
|
|
assert info_data.get("name") == "Info Project"
|
|
assert info_data.get("topic") == "InfoTopic"
|
|
assert info_data.get("description") == "Project with an info endpoint."
|
|
assert isinstance(info_data.get("keywords", []), list)
|
|
assert "summary" in info_data
|
|
|
|
|
|
def test_recalc_project_keywords(client, auth_headers):
|
|
"""
|
|
Tests the /api/projects/<project_id>/recalc_keywords endpoint.
|
|
It should gather all URL keywords, sum them, sort by top 20, and update the project.
|
|
"""
|
|
# 1) Create a project
|
|
payload = {"name": "Keyword Recalc Project", "description": "Test for recalc keywords."}
|
|
create_resp = client.post("/api/projects", data=json.dumps(payload),
|
|
content_type="application/json", headers=auth_headers)
|
|
assert create_resp.status_code == 201, f"Project creation failed: {create_resp.data.decode()}"
|
|
project_id = json.loads(create_resp.data)["project_id"]
|
|
|
|
# 2) Create multiple URLs with keywords
|
|
url1_keywords = [{"word": "alpha", "percentage": 50}, {"word": "beta", "percentage": 10}]
|
|
url2_keywords = [{"word": "alpha", "percentage": 20}, {"word": "gamma", "percentage": 15}]
|
|
url_create_payload1 = {"url": "https://url1.com", "keywords": url1_keywords}
|
|
url_create_payload2 = {"url": "https://url2.com", "keywords": url2_keywords}
|
|
|
|
resp1 = client.post(f"/api/projects/{project_id}/urls", data=json.dumps(url_create_payload1),
|
|
content_type="application/json", headers=auth_headers)
|
|
resp2 = client.post(f"/api/projects/{project_id}/urls", data=json.dumps(url_create_payload2),
|
|
content_type="application/json", headers=auth_headers)
|
|
assert resp1.status_code == 201, f"URL1 creation failed: {resp1.data.decode()}"
|
|
assert resp2.status_code == 201, f"URL2 creation failed: {resp2.data.decode()}"
|
|
|
|
# 3) Recalc keywords
|
|
recalc_resp = client.put(f"/api/projects/{project_id}/recalc_keywords", headers=auth_headers)
|
|
assert recalc_resp.status_code == 200, f"Keyword recalc failed: {recalc_resp.data.decode()}"
|
|
recalc_data = json.loads(recalc_resp.data)
|
|
assert "keywords" in recalc_data
|
|
top_keywords = recalc_data["keywords"]
|
|
# Check that alpha is presumably 70, gamma=15, beta=10 => alpha, gamma, beta
|
|
assert len(top_keywords) <= 20
|
|
# alpha => 70 (50 + 20)
|
|
alpha_kw = next((k for k in top_keywords if k["word"] == "alpha"), None)
|
|
assert alpha_kw is not None, "Expected alpha in combined keywords"
|
|
assert alpha_kw["percentage"] == 70.0
|
|
|
|
# 4) Fetch the project detail or info to confirm stored result
|
|
info_resp = client.get(f"/api/projects/{project_id}/info", headers=auth_headers)
|
|
assert info_resp.status_code == 200, f"Get project info after recalc failed: {info_resp.data.decode()}"
|
|
info_data = json.loads(info_resp.data)
|
|
# The project now has 'keywords' -> top 20
|
|
project_keywords = info_data.get("keywords", [])
|
|
alpha_in_project = next((k for k in project_keywords if k["word"] == "alpha"), None)
|
|
assert alpha_in_project is not None, "Project keywords missing alpha"
|
|
assert alpha_in_project["percentage"] == 70.0
|