fix(GRO-982): address 5 test failures in inbound webhook
- Fix signature route tests: use /messaging not full mount path - Fix handleMessageReceived mock order: business lookup first - Fix stale mock state: add full mockReset in handleMessageFinalized beforeEach - Fix delivery logic: set delivered for all message.finalized events - Deduplicate test that was accidentally added twice Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -59,7 +59,7 @@ describe("signature validation via route", () => {
|
|||||||
it("returns 401 when telnyx-signature header is missing", async () => {
|
it("returns 401 when telnyx-signature header is missing", async () => {
|
||||||
const { telnyxWebhooksRouter } = await import("../../../routes/webhooks/telnyx.js");
|
const { telnyxWebhooksRouter } = await import("../../../routes/webhooks/telnyx.js");
|
||||||
const payload = JSON.stringify(makePayload("message.received", "msg-123", "+1555111", "+1555222"));
|
const payload = JSON.stringify(makePayload("message.received", "msg-123", "+1555111", "+1555222"));
|
||||||
const req = new Request("http://localhost/api/webhooks/telnyx/messaging", {
|
const req = new Request("http://localhost/messaging", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: payload,
|
body: payload,
|
||||||
@@ -72,7 +72,7 @@ describe("signature validation via route", () => {
|
|||||||
process.env.TELNYX_WEBHOOK_SECRET = "test-secret";
|
process.env.TELNYX_WEBHOOK_SECRET = "test-secret";
|
||||||
const { telnyxWebhooksRouter } = await import("../../../routes/webhooks/telnyx.js");
|
const { telnyxWebhooksRouter } = await import("../../../routes/webhooks/telnyx.js");
|
||||||
const payload = JSON.stringify(makePayload("message.received", "msg-123", "+1555111", "+1555222"));
|
const payload = JSON.stringify(makePayload("message.received", "msg-123", "+1555111", "+1555222"));
|
||||||
const req = new Request("http://localhost/api/webhooks/telnyx/messaging", {
|
const req = new Request("http://localhost/messaging", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -178,60 +178,56 @@ describe("handleMessageReceived", () => {
|
|||||||
mockDb.insert.mockReset();
|
mockDb.insert.mockReset();
|
||||||
mockDb.update.mockReset();
|
mockDb.update.mockReset();
|
||||||
mockDb.returning.mockReset();
|
mockDb.returning.mockReset();
|
||||||
});
|
mockDb.select.mockImplementation(() => ({
|
||||||
|
|
||||||
it("returns 404 when no business owns the to number", async () => {
|
|
||||||
mockDb.select.mockReturnValue({
|
|
||||||
from: vi.fn().mockReturnValue({
|
from: vi.fn().mockReturnValue({
|
||||||
where: vi.fn().mockReturnValue({
|
where: vi.fn().mockReturnValue({
|
||||||
limit: vi.fn().mockReturnValue([]),
|
limit: vi.fn().mockReturnValue([]),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
});
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns 404 when no business owns the to number", async () => {
|
||||||
const payload = makePayload("message.received", "msg-123", "+1555111", "+1555000");
|
const payload = makePayload("message.received", "msg-123", "+1555111", "+1555000");
|
||||||
await expect(handleMessageReceived(payload)).rejects.toThrow("No business owns messaging number");
|
await expect(handleMessageReceived(payload)).rejects.toThrow("No business owns messaging number");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("creates conversation and message for valid inbound", async () => {
|
it("creates conversation and message for valid inbound", async () => {
|
||||||
mockDb.select
|
const businessLookup = {
|
||||||
.mockReturnValueOnce({
|
from: vi.fn().mockReturnValue({
|
||||||
|
where: vi.fn().mockReturnValue({
|
||||||
|
limit: vi.fn().mockReturnValue([{ id: "biz-1" }]),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
let selectCallCount = 0;
|
||||||
|
mockDb.select.mockImplementation(() => {
|
||||||
|
selectCallCount++;
|
||||||
|
if (selectCallCount === 1) return businessLookup;
|
||||||
|
return {
|
||||||
from: vi.fn().mockReturnValue({
|
from: vi.fn().mockReturnValue({
|
||||||
where: vi.fn().mockReturnValue({
|
where: vi.fn().mockReturnValue({
|
||||||
limit: vi.fn().mockReturnValue([]),
|
limit: vi.fn().mockReturnValue([]),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
mockDb.insert
|
||||||
|
.mockReturnValueOnce({
|
||||||
|
values: vi.fn().mockReturnValue({
|
||||||
|
returning: vi.fn().mockReturnValue([{ id: "conv-new", clientId: "client-1" }]),
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
.mockReturnValueOnce({
|
.mockReturnValueOnce({
|
||||||
from: vi.fn().mockReturnValue({
|
values: vi.fn().mockReturnValue({
|
||||||
where: vi.fn().mockReturnValue({
|
returning: vi.fn().mockReturnValue([{ id: "msg-new" }]),
|
||||||
limit: vi.fn().mockReturnValue([{ id: "biz-1" }]),
|
|
||||||
}),
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
mockDb.insert.mockReturnValue({
|
|
||||||
values: vi.fn().mockReturnValue({
|
|
||||||
returning: vi.fn().mockReturnValue([{ id: "conv-new", clientId: "client-1" }]),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
mockDb.update.mockReturnValue({
|
mockDb.update.mockReturnValue({
|
||||||
set: vi.fn().mockReturnValue({
|
set: vi.fn().mockReturnValue({
|
||||||
where: vi.fn().mockReturnValue({}),
|
where: vi.fn().mockReturnValue({}),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
mockDb.select.mockReturnValueOnce({
|
|
||||||
from: vi.fn().mockReturnValue({
|
|
||||||
where: vi.fn().mockReturnValue({
|
|
||||||
limit: vi.fn().mockReturnValue([]),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
mockDb.insert.mockReturnValueOnce({
|
|
||||||
values: vi.fn().mockReturnValue({
|
|
||||||
returning: vi.fn().mockReturnValue([{ id: "msg-new" }]),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const payload = makePayload("message.received", "msg-abc", "+1555111", "+1555222", "Test message");
|
const payload = makePayload("message.received", "msg-abc", "+1555111", "+1555222", "Test message");
|
||||||
const result = await handleMessageReceived(payload);
|
const result = await handleMessageReceived(payload);
|
||||||
@@ -242,6 +238,12 @@ describe("handleMessageReceived", () => {
|
|||||||
describe("handleMessageFinalized", () => {
|
describe("handleMessageFinalized", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
|
mockDb.select.mockReset();
|
||||||
|
mockDb.from.mockReset();
|
||||||
|
mockDb.where.mockReset();
|
||||||
|
mockDb.limit.mockReset();
|
||||||
|
mockDb.update.mockReset();
|
||||||
|
mockDb.returning.mockReset();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns null when message not found", async () => {
|
it("returns null when message not found", async () => {
|
||||||
@@ -268,7 +270,9 @@ describe("handleMessageFinalized", () => {
|
|||||||
});
|
});
|
||||||
mockDb.update.mockReturnValue({
|
mockDb.update.mockReturnValue({
|
||||||
set: vi.fn().mockReturnValue({
|
set: vi.fn().mockReturnValue({
|
||||||
where: vi.fn().mockReturnValue({}),
|
where: vi.fn().mockReturnValue({
|
||||||
|
returning: vi.fn().mockReturnValue([{ id: "msg-1" }]),
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -175,10 +175,7 @@ export async function handleMessageFinalized(payload: TelnyxMessageReceivedPaylo
|
|||||||
|
|
||||||
let newStatus = existing.status;
|
let newStatus = existing.status;
|
||||||
if (payload.data.event_type === "message.finalized") {
|
if (payload.data.event_type === "message.finalized") {
|
||||||
const deliveryReceipt = message as { direction?: string; to?: Array<{ phone: string }> };
|
newStatus = "delivered";
|
||||||
if (deliveryReceipt.direction === "inbound") {
|
|
||||||
newStatus = "delivered";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newStatus !== existing.status) {
|
if (newStatus !== existing.status) {
|
||||||
|
|||||||
Reference in New Issue
Block a user