contact-api.spec.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. /**
  2. * 【API级】联系人管理全流程
  3. * ================================================================
  4. * 对应 DOM 版:e2e/contact-management.spec.js(远程无 SPA,DOM 版不可跑)
  5. * 接口契约来源:ContactController(/api/contact/*)
  6. * list : {} 联系人列表
  7. * create : Contact 实体 { name, phone?, relationshipType?, tags?, notes?, ... }
  8. * update : Contact 实体 { id, ... }
  9. * delete : { id }
  10. * detail : { id }
  11. * import-phone: { name, phone, extra? }
  12. * interaction : { id } 记录互动
  13. * relationshipType 合法值:family / friend / partner / colleague / other
  14. * 运行:npx playwright test -c playwright.config.api.js --project=desktop
  15. */
  16. const { test, expect } = require('@playwright/test');
  17. const { registerRole, apiPost, uniqueSuffix } = require('../helpers/api');
  18. test.describe('【API级】联系人管理全流程', () => {
  19. let ctx;
  20. test.beforeAll(async ({ request }) => {
  21. ctx = await registerRole(request, 'parent', 'QA-CONTACT');
  22. });
  23. /** 创建一个联系人,返回 { id, name } */
  24. async function createContact(request, tag, extra) {
  25. const name = 'QA_' + tag + '_' + uniqueSuffix();
  26. const payload = Object.assign(
  27. { name, relationshipType: 'friend', contactSource: 'manual', notes: 'QA' },
  28. extra || {}
  29. );
  30. const r = await apiPost(request, '/api/contact/create', payload, ctx.token);
  31. expect(r.code, '创建联系人应成功').toBe(200);
  32. expect(r.data && r.data.id, '应返回联系人ID').toBeTruthy();
  33. return { id: r.data.id, name: r.data.name || name };
  34. }
  35. // ===== 场景1:创建联系人 =====
  36. test('[场景1] 创建联系人 - 期望创建成功', async ({ request }) => {
  37. const c = await createContact(request, 'CREATE');
  38. const list = await apiPost(request, '/api/contact/list', {}, ctx.token);
  39. expect(list.code).toBe(200);
  40. expect(Array.isArray(list.data)).toBeTruthy();
  41. expect(list.data.some((x) => String(x.id) === String(c.id))).toBeTruthy();
  42. });
  43. // ===== 场景2:通讯录导入 =====
  44. test('[场景2] 通讯录导入 - 期望导入成功', async ({ request }) => {
  45. const name = 'QA_IMPORT_' + uniqueSuffix();
  46. const phone = '13' + String(Math.floor(Math.random() * 900000000) + 100000000);
  47. const r = await apiPost(request, '/api/contact/import-phone', { name, phone }, ctx.token);
  48. expect(r.code).toBe(200);
  49. expect(r.data).toBeTruthy();
  50. const list = await apiPost(request, '/api/contact/list', {}, ctx.token);
  51. expect(list.data.some((x) => x.name === name)).toBeTruthy();
  52. });
  53. // ===== 场景3:记录互动 =====
  54. test('[场景3] 记录互动 - 期望记录成功', async ({ request }) => {
  55. const c = await createContact(request, 'INTERACT');
  56. const r = await apiPost(request, '/api/contact/interaction', { id: c.id }, ctx.token);
  57. expect(r.code).toBe(200);
  58. expect(r.data).toBeTruthy();
  59. const detail = await apiPost(request, '/api/contact/detail', { id: c.id }, ctx.token);
  60. expect(detail.code).toBe(200);
  61. expect(detail.data).toBeTruthy();
  62. });
  63. // ===== 场景4:编辑/删除联系人 =====
  64. test('[场景4] 编辑联系人 - 期望更新成功', async ({ request }) => {
  65. const c = await createContact(request, 'UPDATE');
  66. const newName = 'QA_UPDATED_' + uniqueSuffix();
  67. const r = await apiPost(request, '/api/contact/update', { id: c.id, name: newName }, ctx.token);
  68. expect(r.code).toBe(200);
  69. const detail = await apiPost(request, '/api/contact/detail', { id: c.id }, ctx.token);
  70. expect(detail.code).toBe(200);
  71. expect(detail.data.name).toBe(newName);
  72. });
  73. test('[场景4b] 删除联系人 - 期望从列表中移除', async ({ request }) => {
  74. const c = await createContact(request, 'DELETE');
  75. const before = await apiPost(request, '/api/contact/list', {}, ctx.token);
  76. const beforeCount = before.data.length;
  77. const r = await apiPost(request, '/api/contact/delete', { id: c.id }, ctx.token);
  78. expect(r.code).toBe(200);
  79. const after = await apiPost(request, '/api/contact/list', {}, ctx.token);
  80. expect(after.data.length).toBeLessThan(beforeCount);
  81. expect(after.data.some((x) => String(x.id) === String(c.id))).toBeFalsy();
  82. });
  83. // ===== 场景5:权限边界 =====
  84. test('[场景5b] 越权操作他人联系人 - 期望被拒绝', async ({ request }) => {
  85. const c = await createContact(request, 'AUTH');
  86. const other = await registerRole(request, 'parent', 'QA-OTHER');
  87. const r = await apiPost(request, '/api/contact/delete', { id: c.id }, other.token);
  88. expect(r.code).not.toBe(200);
  89. });
  90. });