Files
crm_project/server/tests/api/test_customers.py
hankin 815cbf9d8c v0.2.0: CRM/ERP 系统升级 - 清理 .gitignore 并移除误提交的 venv/env/db 文件
- 更新 .gitignore:全面覆盖环境变量、数据库、日志、缓存、上传文件
- 移除误跟踪的 server/venv/、crm_data.db、.env 文件
- 新增 server/.env.example 模板
- 新增合同管理、利润核算、AI教练等功能模块
- 新增 Playwright e2e 测试套件
- 前后端多项功能升级和 bug 修复
2026-05-11 07:24:19 +00:00

145 lines
5.4 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
客户管理模块测试 —— /api/customers
覆盖: CRUD / 搜索 / 归档恢复 / 转移 / 数据权限隔离
"""
import uuid
import pytest
from httpx import AsyncClient
from tests.conftest import (
make_auth_headers, ADMIN_USER_ID, SALES_USER_ID,
COMPANY_ID, CUSTOMER_ID,
)
class TestCreateCustomer:
"""POST /api/customers"""
async def test_create_customer_success(self, client: AsyncClient, admin_headers):
"""正常创建客户 → 200"""
resp = await client.post("/api/customers", headers=admin_headers, json={
"name": "新客户测试公司",
"level": "B",
"industry": "制造业",
"contact": "李经理",
"phone": "13900139000",
})
assert resp.status_code == 200
data = resp.json()["data"]
assert data["name"] == "新客户测试公司"
assert data["level"] == "B"
async def test_create_customer_minimal(self, client: AsyncClient, admin_headers):
"""仅必填字段(name → 200"""
resp = await client.post("/api/customers", headers=admin_headers, json={
"name": "最简客户",
})
assert resp.status_code == 200
async def test_create_customer_no_auth(self, client: AsyncClient, seed_data):
"""无认证 → 422"""
resp = await client.post("/api/customers", json={"name": "test"})
assert resp.status_code == 422
class TestListCustomers:
"""GET /api/customers"""
async def test_list_customers_success(self, client: AsyncClient, admin_headers):
"""管理员列表 → 200 + 包含种子客户"""
resp = await client.get("/api/customers", headers=admin_headers)
assert resp.status_code == 200
data = resp.json()["data"]
assert data["total"] >= 1
assert len(data["items"]) >= 1
async def test_list_customers_with_level_filter(self, client: AsyncClient, admin_headers):
"""等级筛选 level=A → 只返回A级"""
resp = await client.get("/api/customers?level=A", headers=admin_headers)
assert resp.status_code == 200
for item in resp.json()["data"]["items"]:
assert item["level"] == "A"
async def test_list_customers_keyword_search(self, client: AsyncClient, admin_headers):
"""关键词搜索 → 模糊匹配"""
resp = await client.get("/api/customers?keyword=中石化", headers=admin_headers)
assert resp.status_code == 200
async def test_list_customers_pagination(self, client: AsyncClient, admin_headers):
"""分页参数 page=1&size=5 → 正常分页"""
resp = await client.get("/api/customers?page=1&size=5", headers=admin_headers)
assert resp.status_code == 200
data = resp.json()["data"]
assert "total" in data
assert "items" in data
class TestGetCustomer:
"""GET /api/customers/{id}"""
async def test_get_customer_success(self, client: AsyncClient, admin_headers):
"""获取种子客户 → 200"""
resp = await client.get(f"/api/customers/{CUSTOMER_ID}", headers=admin_headers)
assert resp.status_code == 200
assert resp.json()["data"]["name"] == "中石化天津分公司"
async def test_get_customer_not_found(self, client: AsyncClient, admin_headers):
"""不存在的 UUID → 404"""
fake_id = uuid.uuid4()
resp = await client.get(f"/api/customers/{fake_id}", headers=admin_headers)
assert resp.status_code == 404
class TestUpdateCustomer:
"""PUT /api/customers/{id}"""
async def test_update_customer_success(self, client: AsyncClient, admin_headers):
"""更新客户等级 → 200"""
resp = await client.put(f"/api/customers/{CUSTOMER_ID}", headers=admin_headers, json={
"level": "B",
"industry": "化学工业",
})
assert resp.status_code == 200
data = resp.json()["data"]
assert data["level"] == "B"
class TestDeleteAndRestore:
"""DELETE + PUT /restore"""
async def test_delete_customer(self, client: AsyncClient, admin_headers):
"""软删除 → 200"""
resp = await client.delete(f"/api/customers/{CUSTOMER_ID}", headers=admin_headers)
assert resp.status_code == 200
assert "归档" in resp.json()["message"]
async def test_restore_customer(self, client: AsyncClient, admin_headers):
"""恢复归档 → 200"""
# 先归档
await client.delete(f"/api/customers/{CUSTOMER_ID}", headers=admin_headers)
# 再恢复
resp = await client.put(f"/api/customers/{CUSTOMER_ID}/restore", headers=admin_headers)
assert resp.status_code == 200
class TestSearchCustomer:
"""GET /api/customers/search"""
async def test_search_success(self, client: AsyncClient, admin_headers):
"""搜索 q=中石化 → 返回匹配结果"""
resp = await client.get("/api/customers/search?q=中石化", headers=admin_headers)
assert resp.status_code == 200
class TestTransferCustomer:
"""PUT /api/customers/{id}/transfer"""
async def test_transfer_success(self, client: AsyncClient, admin_headers):
"""管理员转移客户 → 200"""
resp = await client.put(
f"/api/customers/{CUSTOMER_ID}/transfer",
headers=admin_headers,
json={"new_owner_id": str(ADMIN_USER_ID)}
)
assert resp.status_code == 200
assert "转移成功" in resp.json()["message"]