build fixes

This commit is contained in:
dal 2025-07-21 17:38:37 -06:00
parent cb3dd968e3
commit 9b9914cd70
No known key found for this signature in database
GPG Key ID: 16F4B0E1E9F61122
2 changed files with 110 additions and 69 deletions

View File

@ -16,11 +16,15 @@ vi.mock('@buster/database', () => ({
select: vi.fn(() => ({
from: vi.fn(() => ({
where: vi.fn(() => ({
limit: vi.fn(() => Promise.resolve([{ id: 'integration-1', defaultChannel: { id: 'C123' }, tokenVaultKey: 'vault-key-1' }]))
}))
}))
limit: vi.fn(() =>
Promise.resolve([
{ id: 'integration-1', defaultChannel: { id: 'C123' }, tokenVaultKey: 'vault-key-1' },
])
),
})),
})),
})),
transaction: vi.fn()
transaction: vi.fn(),
})),
getSecretByName: vi.fn(() => Promise.resolve({ secret: 'xoxb-test-token' })),
eq: vi.fn(),
@ -46,13 +50,13 @@ describe('slack-notifier', () => {
const mockConvertMarkdownToSlack = vi.mocked(convertMarkdownToSlack);
mockConvertMarkdownToSlack.mockReturnValue({
text: 'Kevin requested a "total count of customers".\n\n• I included all customer records in `customers.status`, regardless of status (active, inactive, deleted). If incorrect, this likely inflates the count.',
blocks: []
blocks: [],
});
// Mock the sendSlackMessage function's fetch call
vi.mocked(fetch).mockResolvedValue({
ok: true,
json: async () => ({ ok: true, ts: '1234567890.123456' })
json: async () => ({ ok: true, ts: '1234567890.123456' }),
} as Response);
// Import the actual functions after mocks are set up
@ -63,8 +67,9 @@ describe('slack-notifier', () => {
userName: 'Kevin',
chatId: 'chat-456',
summaryTitle: 'Customer Count Includes All Statuses',
summaryMessage: 'Kevin requested a "total count of customers".\n\n- I included all customer records in `customers.status`, regardless of status (active, inactive, deleted). If incorrect, this likely inflates the count.',
toolCalled: 'generateSummary'
summaryMessage:
'Kevin requested a "total count of customers".\n\n- I included all customer records in `customers.status`, regardless of status (active, inactive, deleted). If incorrect, this likely inflates the count.',
toolCalled: 'generateSummary',
};
const result = await sendSlackNotification(params);
@ -74,15 +79,18 @@ describe('slack-notifier', () => {
// Verify the fetch was called with converted text
const fetchCall = vi.mocked(fetch).mock.calls[0];
const body = JSON.parse(fetchCall[1]?.body as string);
if (!fetchCall || !fetchCall[1]) {
throw new Error('Expected fetch to be called');
}
const body = JSON.parse(fetchCall[1].body as string);
expect(body.blocks).toContainEqual({
type: 'section',
text: {
type: 'mrkdwn',
text: 'Kevin requested a "total count of customers".\n\n• I included all customer records in `customers.status`, regardless of status (active, inactive, deleted). If incorrect, this likely inflates the count.',
verbatim: false
}
verbatim: false,
},
});
});
@ -90,12 +98,12 @@ describe('slack-notifier', () => {
const mockConvertMarkdownToSlack = vi.mocked(convertMarkdownToSlack);
mockConvertMarkdownToSlack.mockReturnValue({
text: 'I found no matching records for the request about *recent returns*.',
blocks: []
blocks: [],
});
vi.mocked(fetch).mockResolvedValue({
ok: true,
json: async () => ({ ok: true, ts: '1234567890.123456' })
json: async () => ({ ok: true, ts: '1234567890.123456' }),
} as Response);
const { sendSlackNotification } = await import('./slack-notifier');
@ -105,7 +113,7 @@ describe('slack-notifier', () => {
userName: 'Nate',
chatId: 'chat-789',
toolCalled: 'flagChat',
message: 'I found no matching records for the request about **recent returns**.'
message: 'I found no matching records for the request about **recent returns**.',
};
const result = await sendSlackNotification(params);
@ -114,15 +122,18 @@ describe('slack-notifier', () => {
expect(mockConvertMarkdownToSlack).toHaveBeenCalledWith(params.message);
const fetchCall = vi.mocked(fetch).mock.calls[0];
const body = JSON.parse(fetchCall[1]?.body as string);
if (!fetchCall || !fetchCall[1]) {
throw new Error('Expected fetch to be called');
}
const body = JSON.parse(fetchCall[1].body as string);
expect(body.blocks).toContainEqual({
type: 'section',
text: {
type: 'mrkdwn',
text: 'I found no matching records for the request about *recent returns*.',
verbatim: false
}
verbatim: false,
},
});
});
@ -130,12 +141,12 @@ describe('slack-notifier', () => {
const mockConvertMarkdownToSlack = vi.mocked(convertMarkdownToSlack);
mockConvertMarkdownToSlack.mockReturnValue({
text: 'Leslie requested "users and their referral_ids for the Northwest team".\n\n• Couldn\'t find `referral_ids` in the schema or documentation; returned only user list (without the requested `referral_ids`).',
blocks: []
blocks: [],
});
vi.mocked(fetch).mockResolvedValue({
ok: true,
json: async () => ({ ok: true, ts: '1234567890.123456' })
json: async () => ({ ok: true, ts: '1234567890.123456' }),
} as Response);
const { sendSlackNotification } = await import('./slack-notifier');
@ -145,8 +156,9 @@ describe('slack-notifier', () => {
userName: 'Leslie',
chatId: 'chat-999',
summaryTitle: 'Missing Referral IDs',
summaryMessage: 'Leslie requested "users and their referral_ids for the Northwest team".\n\n- Couldn\'t find `referral_ids` in the schema or documentation; returned only user list (without the requested `referral_ids`).',
toolCalled: 'generateSummary'
summaryMessage:
'Leslie requested "users and their referral_ids for the Northwest team".\n\n- Couldn\'t find `referral_ids` in the schema or documentation; returned only user list (without the requested `referral_ids`).',
toolCalled: 'generateSummary',
};
const result = await sendSlackNotification(params);
@ -155,8 +167,11 @@ describe('slack-notifier', () => {
expect(mockConvertMarkdownToSlack).toHaveBeenCalledWith(params.summaryMessage);
const fetchCall = vi.mocked(fetch).mock.calls[0];
const body = JSON.parse(fetchCall[1]?.body as string);
if (!fetchCall || !fetchCall[1]) {
throw new Error('Expected fetch to be called');
}
const body = JSON.parse(fetchCall[1].body as string);
expect(body.blocks[1].text.text).toContain('`referral_ids`');
});
@ -164,12 +179,12 @@ describe('slack-notifier', () => {
const mockConvertMarkdownToSlack = vi.mocked(convertMarkdownToSlack);
mockConvertMarkdownToSlack.mockReturnValue({
text: 'Test message',
blocks: []
blocks: [],
});
vi.mocked(fetch).mockResolvedValue({
ok: true,
json: async () => ({ ok: true, ts: '1234567890.123456' })
json: async () => ({ ok: true, ts: '1234567890.123456' }),
} as Response);
const { sendSlackNotification } = await import('./slack-notifier');
@ -180,7 +195,7 @@ describe('slack-notifier', () => {
chatId: 'chat-123',
summaryTitle: 'Test Title',
summaryMessage: 'Test message',
toolCalled: 'generateSummary'
toolCalled: 'generateSummary',
};
const result = await sendSlackNotification(params);
@ -188,8 +203,11 @@ describe('slack-notifier', () => {
expect(result.sent).toBe(true);
const fetchCall = vi.mocked(fetch).mock.calls[0];
const body = JSON.parse(fetchCall[1]?.body as string);
if (!fetchCall || !fetchCall[1]) {
throw new Error('Expected fetch to be called');
}
const body = JSON.parse(fetchCall[1].body as string);
// Check that the button exists and has correct URL
const actionsBlock = body.blocks.find((block: any) => block.type === 'actions');
expect(actionsBlock).toBeDefined();
@ -203,12 +221,12 @@ describe('slack-notifier', () => {
const mockConvertMarkdownToSlack = vi.mocked(convertMarkdownToSlack);
mockConvertMarkdownToSlack.mockReturnValue({
text: 'Update: The analysis found *5 major assumptions* that need review.',
blocks: []
blocks: [],
});
vi.mocked(fetch).mockResolvedValue({
ok: true,
json: async () => ({ ok: true, ts: '1234567890.123456' })
json: async () => ({ ok: true, ts: '1234567890.123456' }),
} as Response);
const { sendSlackReplyNotification } = await import('./slack-notifier');
@ -222,7 +240,7 @@ describe('slack-notifier', () => {
threadTs: '1234567890.000001',
channelId: 'C123',
integrationId: 'integration-1',
tokenVaultKey: 'vault-key-1'
tokenVaultKey: 'vault-key-1',
};
const result = await sendSlackReplyNotification(params);
@ -231,22 +249,27 @@ describe('slack-notifier', () => {
expect(mockConvertMarkdownToSlack).toHaveBeenCalledWith(params.formattedMessage);
const fetchCall = vi.mocked(fetch).mock.calls[0];
const body = JSON.parse(fetchCall[1]?.body as string);
if (!fetchCall || !fetchCall[1]) {
throw new Error('Expected fetch to be called');
}
const body = JSON.parse(fetchCall[1].body as string);
expect(body.thread_ts).toBe('1234567890.000001');
expect(body.blocks[0].text.text).toBe('Update: The analysis found *5 major assumptions* that need review.');
expect(body.blocks[0].text.text).toBe(
'Update: The analysis found *5 major assumptions* that need review.'
);
});
it('should convert markdown in reply with summaryMessage', async () => {
const mockConvertMarkdownToSlack = vi.mocked(convertMarkdownToSlack);
mockConvertMarkdownToSlack.mockReturnValue({
text: 'Found issues with `order_status` field mapping.',
blocks: []
blocks: [],
});
vi.mocked(fetch).mockResolvedValue({
ok: true,
json: async () => ({ ok: true, ts: '1234567890.123456' })
json: async () => ({ ok: true, ts: '1234567890.123456' }),
} as Response);
const { sendSlackReplyNotification } = await import('./slack-notifier');
@ -261,7 +284,7 @@ describe('slack-notifier', () => {
threadTs: '1234567890.000001',
channelId: 'C123',
integrationId: 'integration-1',
tokenVaultKey: 'vault-key-1'
tokenVaultKey: 'vault-key-1',
};
const result = await sendSlackReplyNotification(params);
@ -270,8 +293,11 @@ describe('slack-notifier', () => {
expect(mockConvertMarkdownToSlack).toHaveBeenCalledWith(params.summaryMessage);
const fetchCall = vi.mocked(fetch).mock.calls[0];
const body = JSON.parse(fetchCall[1]?.body as string);
if (!fetchCall || !fetchCall[1]) {
throw new Error('Expected fetch to be called');
}
const body = JSON.parse(fetchCall[1].body as string);
expect(body.blocks[0].text.text).toContain('`order_status`');
});
@ -279,12 +305,12 @@ describe('slack-notifier', () => {
const mockConvertMarkdownToSlack = vi.mocked(convertMarkdownToSlack);
mockConvertMarkdownToSlack.mockReturnValue({
text: 'Error: Could not process the *dashboard request*.',
blocks: []
blocks: [],
});
vi.mocked(fetch).mockResolvedValue({
ok: true,
json: async () => ({ ok: true, ts: '1234567890.123456' })
json: async () => ({ ok: true, ts: '1234567890.123456' }),
} as Response);
const { sendSlackReplyNotification } = await import('./slack-notifier');
@ -298,7 +324,7 @@ describe('slack-notifier', () => {
threadTs: '1234567890.000001',
channelId: 'C123',
integrationId: 'integration-1',
tokenVaultKey: 'vault-key-1'
tokenVaultKey: 'vault-key-1',
};
const result = await sendSlackReplyNotification(params);
@ -307,8 +333,11 @@ describe('slack-notifier', () => {
expect(mockConvertMarkdownToSlack).toHaveBeenCalledWith(params.message);
const fetchCall = vi.mocked(fetch).mock.calls[0];
const body = JSON.parse(fetchCall[1]?.body as string);
if (!fetchCall || !fetchCall[1]) {
throw new Error('Expected fetch to be called');
}
const body = JSON.parse(fetchCall[1].body as string);
expect(body.blocks[0].text.text).toBe('Error: Could not process the *dashboard request*.');
});
});
@ -318,12 +347,12 @@ describe('slack-notifier', () => {
const mockConvertMarkdownToSlack = vi.mocked(convertMarkdownToSlack);
mockConvertMarkdownToSlack.mockReturnValue({
text: 'Simple text without formatting',
blocks: [] // Empty blocks array
blocks: [], // Empty blocks array
});
vi.mocked(fetch).mockResolvedValue({
ok: true,
json: async () => ({ ok: true, ts: '1234567890.123456' })
json: async () => ({ ok: true, ts: '1234567890.123456' }),
} as Response);
const { sendSlackNotification } = await import('./slack-notifier');
@ -334,7 +363,7 @@ describe('slack-notifier', () => {
chatId: 'chat-456',
summaryTitle: 'Simple Title',
summaryMessage: 'Simple text without formatting',
toolCalled: 'generateSummary'
toolCalled: 'generateSummary',
};
const result = await sendSlackNotification(params);
@ -342,24 +371,28 @@ describe('slack-notifier', () => {
expect(result.sent).toBe(true);
const fetchCall = vi.mocked(fetch).mock.calls[0];
const body = JSON.parse(fetchCall[1]?.body as string);
if (!fetchCall || !fetchCall[1]) {
throw new Error('Expected fetch to be called');
}
const body = JSON.parse(fetchCall[1].body as string);
// Should still have the section block with converted text
expect(body.blocks).toHaveLength(3); // Header, message, actions
expect(body.blocks[1].text.text).toBe('Simple text without formatting');
});
it('should handle complex markdown with multiple backticks and formatting', async () => {
const complexMarkdown = 'Assumed `SUM(subtotal + taxamt + freight)` from `sales_order_header` table for **total sales** calculation.';
const complexMarkdown =
'Assumed `SUM(subtotal + taxamt + freight)` from `sales_order_header` table for **total sales** calculation.';
const mockConvertMarkdownToSlack = vi.mocked(convertMarkdownToSlack);
mockConvertMarkdownToSlack.mockReturnValue({
text: 'Assumed `SUM(subtotal + taxamt + freight)` from `sales_order_header` table for *total sales* calculation.',
blocks: []
blocks: [],
});
vi.mocked(fetch).mockResolvedValue({
ok: true,
json: async () => ({ ok: true, ts: '1234567890.123456' })
json: async () => ({ ok: true, ts: '1234567890.123456' }),
} as Response);
const { sendSlackNotification } = await import('./slack-notifier');
@ -370,7 +403,7 @@ describe('slack-notifier', () => {
chatId: 'chat-456',
summaryTitle: 'Sales Calculation Assumption',
summaryMessage: complexMarkdown,
toolCalled: 'generateSummary'
toolCalled: 'generateSummary',
};
const result = await sendSlackNotification(params);
@ -379,12 +412,15 @@ describe('slack-notifier', () => {
expect(mockConvertMarkdownToSlack).toHaveBeenCalledWith(complexMarkdown);
const fetchCall = vi.mocked(fetch).mock.calls[0];
const body = JSON.parse(fetchCall[1]?.body as string);
if (!fetchCall || !fetchCall[1]) {
throw new Error('Expected fetch to be called');
}
const body = JSON.parse(fetchCall[1].body as string);
const messageBlock = body.blocks[1];
expect(messageBlock.text.text).toContain('`SUM(subtotal + taxamt + freight)`');
expect(messageBlock.text.text).toContain('`sales_order_header`');
expect(messageBlock.text.text).toContain('*total sales*');
});
});
});
});

View File

@ -71,7 +71,8 @@ The analysis uses data from your employee productivity system, which tracks tota
}
// Step 4: Add the action button block
const buttonUrl = 'https://platform.buster.so/app/chats/123/dashboards/456?dashboard_version_number=1';
const buttonUrl =
'https://platform.buster.so/app/chats/123/dashboards/456?dashboard_version_number=1';
messageBlocks.push({
type: 'actions' as const,
elements: [
@ -95,17 +96,21 @@ The analysis uses data from your employee productivity system, which tracks tota
};
// Step 6: Send the message
const result = await messagingService.sendMessage('xoxb-test-token', 'C123', completionMessage);
const result = await messagingService.sendMessage(
'xoxb-test-token',
'C123',
completionMessage
);
expect(result.success).toBe(true);
// Verify the message was sent correctly
const callArgs = mockSlackClient.chat.postMessage.mock.calls[0][0];
// The blocks should be preserved as-is
expect(callArgs.blocks).toBeDefined();
expect(callArgs.blocks).toEqual(messageBlocks);
// Verify the button is at the bottom
const lastBlock = callArgs.blocks[callArgs.blocks.length - 1];
expect(lastBlock.type).toBe('actions');
@ -173,10 +178,10 @@ Content 5`;
expect(result.success).toBe(true);
const callArgs = mockSlackClient.chat.postMessage.mock.calls[0][0];
// Verify all blocks including button are present
expect(callArgs.blocks).toEqual(messageBlocks);
// Verify button is still at the bottom
const lastBlock = callArgs.blocks[callArgs.blocks.length - 1];
expect(lastBlock.type).toBe('actions');
@ -191,10 +196,10 @@ Content 5`;
});
const originalText = '## Header\nSome **bold** text';
// Pre-convert the markdown
const convertedOnce = convertMarkdownToSlack(originalText);
// Create message with both text and already-converted blocks
const message = {
text: originalText, // Original markdown text
@ -222,13 +227,13 @@ Content 5`;
expect(result.success).toBe(true);
const callArgs = mockSlackClient.chat.postMessage.mock.calls[0][0];
// Blocks should be exactly what we provided, not re-converted
expect(callArgs.blocks).toEqual(message.blocks);
// Verify the button is still there
const lastBlock = callArgs.blocks[callArgs.blocks.length - 1];
expect(lastBlock.type).toBe('actions');
});
});
});
});