import assert from 'node:assert/strict' import crypto from 'node:crypto' import test from 'node:test' import { YouYiDianNotificationClient } from './notification-client.mjs' const secret = 'example-project-secret-at-least-24-chars' const verifySignature = (request) => { const url = new URL(request.url) const timestamp = request.init.headers['x-yyd-timestamp'] const nonce = request.init.headers['x-yyd-nonce'] const bodyHash = crypto.createHash('sha256').update(request.init.body || '').digest('hex') const canonical = [timestamp, nonce, request.init.method, url.pathname.replace('/notification-center', ''), bodyHash].join('\n') const expected = crypto.createHmac('sha256', secret).update(canonical).digest('hex') assert.equal(request.init.headers['x-yyd-signature'], expected) } test('发送通知使用业务正文原文签名并返回投递记录', async () => { const requests = [] const client = new YouYiDianNotificationClient({ baseUrl: 'https://sc.example.com/notification-center', projectCode: 'fixed_asset', projectSecret: secret, fetchImpl: async (url, init) => { requests.push({ url, init }) return new Response(JSON.stringify({ id: 'delivery-1', status: 'pending' }), { status: 202, headers: { 'content-type': 'application/json' }, }) }, }) const payload = { idempotencyKey: 'asset_disposal:53:user-1:v1', recipientUserId: 'user-1', title: '资产报废待审批', content: '**申请时间:** 2026年7月16日 14:30', actionTitle: '立即审批', actionUrl: 'https://asset.example.com/workflows/disposals/53', } const delivery = await client.send(payload) assert.deepEqual(delivery, { id: 'delivery-1', status: 'pending' }) assert.equal(requests.length, 1) assert.equal(requests[0].url, 'https://sc.example.com/notification-center/v1/notifications') assert.equal(requests[0].init.body, JSON.stringify(payload)) verifySignature(requests[0]) }) test('查询通知使用空正文签名', async () => { let request const client = new YouYiDianNotificationClient({ baseUrl: 'https://sc.example.com/notification-center', projectCode: 'fixed_asset', projectSecret: secret, fetchImpl: async (url, init) => { request = { url, init } return new Response(JSON.stringify({ id: 'delivery-1', status: 'read' }), { status: 200, headers: { 'content-type': 'application/json' }, }) }, }) const delivery = await client.getDelivery('delivery-1') assert.equal(delivery.status, 'read') assert.equal(request.init.body, undefined) verifySignature(request) })