# Instructions

- Following Playwright test failed.
- Explain why, be concise, respect Playwright best practices.
- Provide a snippet of code with the fix, if possible.

# Test info

- Name: transaction-full.spec.ts >> 安全与边界 >> 负数金额应报错
- Location: tests/transaction-full.spec.ts:799:7

# Error details

```
Error: expect(received).not.toBe(expected) // Object.is equality

Expected: not 201
```

# Test source

```ts
  707 |     const res = await request.post(`${BASE}/nail/appointments`, {
  708 |       headers: headers(),
  709 |       data: {
  710 |         items: [{ service_id: SVC_PURE, employee_id: null, start_time: '2026-07-27T14:00:00Z' }],
  711 |         notes: '',
  712 |         client_id: ADA_ID,
  713 |       },
  714 |     });
  715 |     expect(res.status()).not.toBe(500);
  716 |   });
  717 | 
  718 |   test('创建预约 - 多服务项', async ({ request }) => {
  719 |     const res = await request.post(`${BASE}/nail/appointments`, {
  720 |       headers: headers(),
  721 |       data: {
  722 |         client_id: ADA_ID,
  723 |         service_id: SVC_PURE,
  724 |         employee_id: EMPLOYEE_ID,
  725 |         start_time: '2026-07-27T16:00:00Z',
  726 |         source: 'sys_employee',
  727 |         items: [
  728 |           { service_id: SVC_PURE, employee_id: EMPLOYEE_ID, start_time: '2026-07-27T16:00:00Z', price_cents: 8800 },
  729 |           { service_id: SVC_GRADIENT, employee_id: EMPLOYEE_ID, start_time: '2026-07-27T17:00:00Z', price_cents: 13800 },
  730 |         ],
  731 |         notes: '多服务预约',
  732 |       },
  733 |     });
  734 |     expect(res.status()).toBe(201);
  735 |   });
  736 | 
  737 |   test('创建预约 - 无效 service_id 不应 500', async ({ request }) => {
  738 |     const res = await request.post(`${BASE}/nail/appointments`, {
  739 |       headers: headers(),
  740 |       data: {
  741 |         client_id: ADA_ID,
  742 |         service_id: 'invalid_service',
  743 |         employee_id: EMPLOYEE_ID,
  744 |         start_time: '2026-07-27T18:00:00Z',
  745 |         source: 'sys_employee',
  746 |         items: [{ service_id: 'invalid_service', employee_id: EMPLOYEE_ID, start_time: '2026-07-27T18:00:00Z', price_cents: 8800 }],
  747 |         notes: '',
  748 |       },
  749 |     });
  750 |     expect(res.status()).not.toBe(500);
  751 |   });
  752 | 
  753 |   test('创建预约 - 过去时间应报错', async ({ request }) => {
  754 |     const res = await request.post(`${BASE}/nail/appointments`, {
  755 |       headers: headers(),
  756 |       data: {
  757 |         client_id: ADA_ID,
  758 |         service_id: SVC_PURE,
  759 |         employee_id: EMPLOYEE_ID,
  760 |         start_time: '2020-01-01T10:00:00Z',
  761 |         source: 'sys_employee',
  762 |         items: [{ service_id: SVC_PURE, employee_id: EMPLOYEE_ID, start_time: '2020-01-01T10:00:00Z', price_cents: 8800 }],
  763 |         notes: '',
  764 |       },
  765 |     });
  766 |     // 过去时间应该报错或至少不 500
  767 |     expect(res.status()).not.toBe(500);
  768 |   });
  769 | 
  770 |   test('查询预约列表', async ({ request }) => {
  771 |     const res = await request.get(`${BASE}/nail/appointments?start=2026-07-27&end=2026-07-27`, {
  772 |       headers: headers(),
  773 |     });
  774 |     expect(res.status()).toBe(200);
  775 |     const data = await res.json();
  776 |     expect(data).toHaveProperty('appointments');
  777 |   });
  778 | });
  779 | 
  780 | // ═══════════════════════════════════════════════════
  781 | // 九、安全与边界
  782 | // ═══════════════════════════════════════════════════
  783 | test.describe('安全与边界', () => {
  784 | 
  785 |   test('无 token 访问应返回 401', async ({ request }) => {
  786 |     const res = await request.get(`${BASE}/nail/pos/orders`, {
  787 |       headers: { 'Product': 'inail' },
  788 |     });
  789 |     expect(res.status()).toBe(401);
  790 |   });
  791 | 
  792 |   test('过期 token 应返回 401', async ({ request }) => {
  793 |     const res = await request.get(`${BASE}/nail/pos/orders`, {
  794 |       headers: { 'Product': 'inail', 'Authorization': 'Bearer expired_token_123' },
  795 |     });
  796 |     expect(res.status()).toBe(401);
  797 |   });
  798 | 
  799 |   test('负数金额应报错', async ({ request }) => {
  800 |     const res = await request.post(`${BASE}/nail/pos/transactions`, {
  801 |       headers: headers(),
  802 |       data: makeTransaction({
  803 |         items: [serviceItem(SVC_PURE, '纯色美甲', -8800)],
  804 |         split_payments: [{ method: 'cash', amount_cents: -8800 }],
  805 |       }),
  806 |     });
> 807 |     expect(res.status()).not.toBe(201);
      |                              ^ Error: expect(received).not.toBe(expected) // Object.is equality
  808 |     expect(res.status()).not.toBe(500);
  809 |   });
  810 | 
  811 |   test('超大金额不应崩溃', async ({ request }) => {
  812 |     const res = await request.post(`${BASE}/nail/pos/transactions`, {
  813 |       headers: headers(),
  814 |       data: makeTransaction({
  815 |         items: [serviceItem(SVC_PURE, '纯色美甲', 99999999)],
  816 |         split_payments: [{ method: 'cash', amount_cents: 99999999 }],
  817 |       }),
  818 |     });
  819 |     expect(res.status()).not.toBe(500);
  820 |   });
  821 | 
  822 |   test('无效支付方式应报错', async ({ request }) => {
  823 |     const res = await request.post(`${BASE}/nail/pos/transactions`, {
  824 |       headers: headers(),
  825 |       data: makeTransaction({
  826 |         items: [serviceItem(SVC_PURE, '纯色美甲', 8800)],
  827 |         method: 'bitcoin',
  828 |         split_payments: [{ method: 'bitcoin', amount_cents: 8800 }],
  829 |       }),
  830 |     });
  831 |     expect(res.status()).not.toBe(500);
  832 |     expect(res.status()).toBeGreaterThanOrEqual(400);
  833 |   });
  834 | 
  835 |   test('split_payments 金额总和不等于 items 总和应报错', async ({ request }) => {
  836 |     const res = await request.post(`${BASE}/nail/pos/transactions`, {
  837 |       headers: headers(),
  838 |       data: makeTransaction({
  839 |         items: [serviceItem(SVC_PURE, '纯色美甲', 8800)],
  840 |         split_payments: [{ method: 'cash', amount_cents: 5000 }], // 少付了
  841 |       }),
  842 |     });
  843 |     expect(res.status()).not.toBe(500);
  844 |   });
  845 | });
  846 | 
```