feat: 完成P13治理收尾并创建P14执行合同(Issue: P13-1,P13-2,P13-3,P13-4,P13-5,P13-6,P13-7,P13-8,P14-0)
这个提交包含在:
@@ -0,0 +1,106 @@
|
||||
const {
|
||||
IntegrationDispatchError,
|
||||
dispatchOutboxEvent,
|
||||
} = require("../../src/services/integrations/dispatcher");
|
||||
|
||||
describe("dispatchOutboxEvent", () => {
|
||||
it("handles mock ERP success", async () => {
|
||||
const result = await dispatchOutboxEvent({
|
||||
config: {
|
||||
erpSyncEnabled: true,
|
||||
erpSyncProvider: "mock",
|
||||
},
|
||||
eventType: "erp.reimbursement.paid",
|
||||
payload: {
|
||||
reimbursementId: "rb-1",
|
||||
formNumber: "BX-001",
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.channel).toBe("erp");
|
||||
expect(result.code).toBe("mock_synced");
|
||||
expect(result.response.externalId).toContain("BX-001");
|
||||
});
|
||||
|
||||
it("maps ERP disabled as non-retryable dispatch error", async () => {
|
||||
await expect(
|
||||
dispatchOutboxEvent({
|
||||
config: {
|
||||
erpSyncEnabled: false,
|
||||
erpSyncProvider: "mock",
|
||||
},
|
||||
eventType: "erp.reimbursement.paid",
|
||||
payload: {
|
||||
reimbursementId: "rb-2",
|
||||
formNumber: "BX-002",
|
||||
},
|
||||
}),
|
||||
).rejects.toMatchObject({
|
||||
name: "IntegrationDispatchError",
|
||||
code: "erp_sync_disabled",
|
||||
retryable: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("maps invalid ERP provider as non-retryable dispatch error", async () => {
|
||||
await expect(
|
||||
dispatchOutboxEvent({
|
||||
config: {
|
||||
erpSyncEnabled: true,
|
||||
erpSyncProvider: "invalid-provider",
|
||||
},
|
||||
eventType: "erp.reimbursement.paid",
|
||||
payload: {
|
||||
reimbursementId: "rb-3",
|
||||
formNumber: "BX-003",
|
||||
},
|
||||
}),
|
||||
).rejects.toMatchObject({
|
||||
name: "IntegrationDispatchError",
|
||||
code: "erp_sync_provider_invalid",
|
||||
retryable: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("handles IM notification outbox", async () => {
|
||||
const result = await dispatchOutboxEvent({
|
||||
config: {},
|
||||
eventType: "notification.im",
|
||||
payload: {
|
||||
channelType: "wecom",
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.channel).toBe("im");
|
||||
expect(result.code).toBe("mock_sent");
|
||||
expect(result.response.channelType).toBe("wecom");
|
||||
});
|
||||
|
||||
it("throws non-retryable error for unsupported event", async () => {
|
||||
await expect(
|
||||
dispatchOutboxEvent({
|
||||
config: { erpSyncEnabled: true, erpSyncProvider: "mock" },
|
||||
eventType: "unsupported.event",
|
||||
payload: {},
|
||||
}),
|
||||
).rejects.toMatchObject({
|
||||
name: "IntegrationDispatchError",
|
||||
code: "unsupported_outbox_event",
|
||||
retryable: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("preserves error class semantics", () => {
|
||||
const error = new IntegrationDispatchError({
|
||||
code: "unit_test",
|
||||
message: "unit test",
|
||||
retryable: true,
|
||||
statusCode: 503,
|
||||
});
|
||||
|
||||
expect(error).toBeInstanceOf(Error);
|
||||
expect(error.code).toBe("unit_test");
|
||||
expect(error.retryable).toBe(true);
|
||||
expect(error.statusCode).toBe(503);
|
||||
});
|
||||
});
|
||||
在新工单中引用
屏蔽一个用户