feat(M10-A): 完成统一通知中心与投递闭环
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import {
|
||||
createNotificationAdaptersFromEnvironment,
|
||||
HttpNotificationAdapter,
|
||||
NotificationError
|
||||
} from '../dist/notifications/notification-service.js';
|
||||
|
||||
const requests = [];
|
||||
const fetcher = async (url, init) => {
|
||||
requests.push({ url: String(url), init });
|
||||
return {
|
||||
ok: true, status: 200,
|
||||
headers: { get(name) { return name === 'x-request-id' ? 'provider-request-1' : null; } },
|
||||
async json() { return { providerMessageId: 'provider-message-1' }; }
|
||||
};
|
||||
};
|
||||
const adapters = createNotificationAdaptersFromEnvironment({
|
||||
QIPAI_NOTIFICATION_WECHAT_GATEWAY_URL: 'https://gateway.example.test/wechat',
|
||||
QIPAI_NOTIFICATION_WECHAT_GATEWAY_TOKEN: 'wechat-secret',
|
||||
QIPAI_NOTIFICATION_WECOM_GATEWAY_URL: 'https://gateway.example.test/wecom',
|
||||
QIPAI_NOTIFICATION_CLOUD_SPEAKER_GATEWAY_URL: 'https://gateway.example.test/speaker',
|
||||
QIPAI_NOTIFICATION_HTTP_TIMEOUT_MS: '5000'
|
||||
}, fetcher);
|
||||
assert.deepEqual([...adapters.keys()], [
|
||||
'IN_APP', 'WEBHOOK', 'WECHAT_SUBSCRIBE', 'WE_COM', 'CLOUD_SPEAKER'
|
||||
]);
|
||||
const input = { deliveryId: '31', tenantId: '7', channel: 'WECHAT_SUBSCRIBE',
|
||||
recipientId: '21', title: '提醒', body: '订单已支付', payload: { orderId: '41' },
|
||||
externalTemplateId: 'template-1' };
|
||||
assert.deepEqual(await adapters.get('WECHAT_SUBSCRIBE').send(input), {
|
||||
providerMessageId: 'provider-message-1'
|
||||
});
|
||||
assert.equal(requests[0].url, 'https://gateway.example.test/wechat');
|
||||
assert.equal(requests[0].init.headers.authorization, 'Bearer wechat-secret');
|
||||
assert.equal(requests[0].init.headers['idempotency-key'], 'notification:31');
|
||||
assert.equal(JSON.parse(requests[0].init.body).externalTemplateId, 'template-1');
|
||||
|
||||
await adapters.get('WEBHOOK').send({ ...input, channel: 'WEBHOOK',
|
||||
recipientId: 'https://store.example.test/hooks/notify' });
|
||||
assert.equal(requests[1].url, 'https://store.example.test/hooks/notify');
|
||||
await assert.rejects(
|
||||
() => adapters.get('WEBHOOK').send({ ...input, channel: 'WEBHOOK',
|
||||
recipientId: 'http://127.0.0.1/internal' }),
|
||||
(error) => error instanceof NotificationError && error.code === 'NOTIFICATION_ENDPOINT_INVALID'
|
||||
);
|
||||
const failing = new HttpNotificationAdapter({ endpoint: 'https://gateway.example.test/fail',
|
||||
fetcher: async () => ({ ok: false, status: 503, headers: { get() { return null; } },
|
||||
async json() { return {}; } }) });
|
||||
await assert.rejects(() => failing.send(input),
|
||||
(error) => error instanceof NotificationError && error.code === 'NOTIFICATION_PROVIDER_HTTP_ERROR');
|
||||
|
||||
console.log('PASS: M10-A configured HTTP adapters enforce HTTPS, idempotency and provider failures.');
|
||||
Reference in New Issue
Block a user