新增 doctor(7)、diagnosis(7)、consent(6)、medication(8)、 dialysis_prescription(7)、follow_up_template(7)、daily_monitoring(7) 覆盖 CRUD、状态流、列表过滤、软删除、租户隔离、乐观锁。
245 lines
7.8 KiB
Rust
245 lines
7.8 KiB
Rust
//! erp-health 随访模板集成测试
|
|
//!
|
|
//! 验证模板 CRUD + 字段管理、列表过滤、租户隔离、乐观锁。
|
|
|
|
use erp_health::dto::follow_up_template_dto::*;
|
|
use erp_health::service::follow_up_template_service;
|
|
|
|
use super::test_fixture::TestApp;
|
|
|
|
fn default_field_req() -> TemplateFieldReq {
|
|
TemplateFieldReq {
|
|
label: "血压".to_string(),
|
|
field_key: "blood_pressure".to_string(),
|
|
field_type: "text".to_string(),
|
|
required: true,
|
|
options: None,
|
|
placeholder: Some("请输入血压值".to_string()),
|
|
validation: None,
|
|
sort_order: 0,
|
|
}
|
|
}
|
|
|
|
fn default_create_req() -> CreateFollowUpTemplateReq {
|
|
CreateFollowUpTemplateReq {
|
|
name: "电话随访模板".to_string(),
|
|
description: Some("标准电话随访".to_string()),
|
|
follow_up_type: "phone".to_string(),
|
|
applicable_scope: None,
|
|
fields: vec![default_field_req()],
|
|
}
|
|
}
|
|
|
|
async fn seed_template(app: &TestApp) -> FollowUpTemplateResp {
|
|
follow_up_template_service::create_template(
|
|
app.health_state(), app.tenant_id(), Some(app.operator_id()),
|
|
default_create_req(),
|
|
)
|
|
.await
|
|
.expect("创建模板应成功")
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 测试 1: 创建模板(含字段)
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn test_template_create_with_fields() {
|
|
let app = TestApp::new().await;
|
|
let tmpl = seed_template(&app).await;
|
|
|
|
assert_eq!(tmpl.name, "电话随访模板");
|
|
assert_eq!(tmpl.follow_up_type, "phone");
|
|
assert_eq!(tmpl.status, "active");
|
|
assert_eq!(tmpl.fields.len(), 1);
|
|
assert_eq!(tmpl.fields[0].field_key, "blood_pressure");
|
|
assert_eq!(tmpl.version, 1);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 测试 2: 查询模板(含字段)
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn test_template_get_with_fields() {
|
|
let app = TestApp::new().await;
|
|
let tmpl = seed_template(&app).await;
|
|
|
|
let fetched = follow_up_template_service::get_template(
|
|
app.health_state(), app.tenant_id(), tmpl.id,
|
|
)
|
|
.await
|
|
.expect("查询应成功");
|
|
assert_eq!(fetched.id, tmpl.id);
|
|
assert_eq!(fetched.fields.len(), 1);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 测试 3: 更新模板(替换字段)
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn test_template_update_replace_fields() {
|
|
let app = TestApp::new().await;
|
|
let tmpl = seed_template(&app).await;
|
|
|
|
let updated = follow_up_template_service::update_template(
|
|
app.health_state(), app.tenant_id(), tmpl.id,
|
|
Some(app.operator_id()),
|
|
UpdateFollowUpTemplateReq {
|
|
name: Some("更新后的模板".to_string()),
|
|
fields: Some(vec![
|
|
TemplateFieldReq {
|
|
label: "体重".to_string(),
|
|
field_key: "weight".to_string(),
|
|
field_type: "number".to_string(),
|
|
required: false,
|
|
options: None,
|
|
placeholder: None,
|
|
validation: None,
|
|
sort_order: 0,
|
|
},
|
|
TemplateFieldReq {
|
|
label: "症状".to_string(),
|
|
field_key: "symptoms".to_string(),
|
|
field_type: "textarea".to_string(),
|
|
required: true,
|
|
options: None,
|
|
placeholder: None,
|
|
validation: None,
|
|
sort_order: 1,
|
|
},
|
|
]),
|
|
description: None,
|
|
follow_up_type: None,
|
|
applicable_scope: None,
|
|
status: None,
|
|
},
|
|
tmpl.version,
|
|
)
|
|
.await
|
|
.expect("更新应成功");
|
|
|
|
assert_eq!(updated.name, "更新后的模板");
|
|
assert_eq!(updated.fields.len(), 2);
|
|
assert_eq!(updated.version, 2);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 测试 4: 列表过滤
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn test_template_list_filter() {
|
|
let app = TestApp::new().await;
|
|
|
|
follow_up_template_service::create_template(
|
|
app.health_state(), app.tenant_id(), Some(app.operator_id()),
|
|
CreateFollowUpTemplateReq {
|
|
name: "门诊随访".to_string(),
|
|
follow_up_type: "outpatient".to_string(),
|
|
fields: vec![],
|
|
description: None,
|
|
applicable_scope: None,
|
|
},
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
follow_up_template_service::create_template(
|
|
app.health_state(), app.tenant_id(), Some(app.operator_id()),
|
|
default_create_req(),
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
// 全量
|
|
let all = follow_up_template_service::list_templates(
|
|
app.health_state(), app.tenant_id(), 1, 20, None, None,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(all.total, 2);
|
|
|
|
// 按类型过滤
|
|
let phone = follow_up_template_service::list_templates(
|
|
app.health_state(), app.tenant_id(), 1, 20,
|
|
Some("phone".to_string()), None,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(phone.total, 1);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 测试 5: 软删除(含字段)
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn test_template_soft_delete() {
|
|
let app = TestApp::new().await;
|
|
let tmpl = seed_template(&app).await;
|
|
|
|
follow_up_template_service::delete_template(
|
|
app.health_state(), app.tenant_id(), tmpl.id,
|
|
Some(app.operator_id()), tmpl.version,
|
|
)
|
|
.await
|
|
.expect("删除应成功");
|
|
|
|
let result = follow_up_template_service::get_template(
|
|
app.health_state(), app.tenant_id(), tmpl.id,
|
|
)
|
|
.await;
|
|
assert!(result.is_err(), "软删除后查询应失败");
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 测试 6: 租户隔离
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn test_template_tenant_isolation() {
|
|
let app = TestApp::new().await;
|
|
seed_template(&app).await;
|
|
|
|
let other_tenant = uuid::Uuid::new_v4();
|
|
let list = follow_up_template_service::list_templates(
|
|
app.health_state(), other_tenant, 1, 20, None, None,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
assert_eq!(list.total, 0, "不同租户不应看到模板");
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 测试 7: 乐观锁冲突
|
|
// ---------------------------------------------------------------------------
|
|
#[tokio::test]
|
|
async fn test_template_version_conflict() {
|
|
let app = TestApp::new().await;
|
|
let tmpl = seed_template(&app).await;
|
|
|
|
// 先更新一次
|
|
follow_up_template_service::update_template(
|
|
app.health_state(), app.tenant_id(), tmpl.id,
|
|
Some(app.operator_id()),
|
|
UpdateFollowUpTemplateReq {
|
|
name: Some("第一次".to_string()),
|
|
description: None, follow_up_type: None,
|
|
applicable_scope: None, status: None, fields: None,
|
|
},
|
|
tmpl.version,
|
|
)
|
|
.await
|
|
.unwrap();
|
|
|
|
// 用旧 version 再更新应失败
|
|
let result = follow_up_template_service::update_template(
|
|
app.health_state(), app.tenant_id(), tmpl.id,
|
|
Some(app.operator_id()),
|
|
UpdateFollowUpTemplateReq {
|
|
name: Some("冲突".to_string()),
|
|
description: None, follow_up_type: None,
|
|
applicable_scope: None, status: None, fields: None,
|
|
},
|
|
tmpl.version,
|
|
)
|
|
.await;
|
|
assert!(result.is_err(), "乐观锁冲突应返回错误");
|
|
}
|