test(07-02): add failing tests for REST API chat methods
Add comprehensive unit tests for getChatMessages and sendChatMessage: - Test session and global channel message fetching - Test pagination cursor (before parameter) - Test all HTTP error codes (403, 404, 422, 500) - Test request headers and credentials - Test error handling with invalid JSON responses Tests fail as expected - functions not yet implemented. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
08bf66cce3
commit
b6ce5010ac
|
|
@ -0,0 +1,302 @@
|
|||
import { getChatMessages, sendChatMessage } from '../rest';
|
||||
|
||||
// Mock global fetch
|
||||
global.fetch = jest.fn();
|
||||
|
||||
// Mock environment variables
|
||||
process.env.REACT_APP_API_BASE_URL = 'http://localhost:3000/api';
|
||||
|
||||
describe('getChatMessages', () => {
|
||||
beforeEach(() => {
|
||||
// Clear all mocks before each test
|
||||
global.fetch.mockClear();
|
||||
});
|
||||
|
||||
test('fetches messages for session channel', async () => {
|
||||
global.fetch.mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
messages: [
|
||||
{ id: 'msg-1', message: 'Hello', sender_id: 'user-1' }
|
||||
],
|
||||
next: 20
|
||||
})
|
||||
});
|
||||
|
||||
const result = await getChatMessages({
|
||||
channel: 'session',
|
||||
sessionId: 'session-abc'
|
||||
});
|
||||
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
expect.stringContaining('/api/chat?channel=session&session_id=session-abc'),
|
||||
expect.objectContaining({ method: 'GET' })
|
||||
);
|
||||
expect(result.messages).toHaveLength(1);
|
||||
expect(result.next).toBe(20);
|
||||
});
|
||||
|
||||
test('fetches messages for global channel', async () => {
|
||||
global.fetch.mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
messages: [
|
||||
{ id: 'msg-1', message: 'Hello world', sender_id: 'user-1' }
|
||||
],
|
||||
next: null
|
||||
})
|
||||
});
|
||||
|
||||
const result = await getChatMessages({
|
||||
channel: 'global'
|
||||
});
|
||||
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
expect.stringContaining('/api/chat?channel=global'),
|
||||
expect.objectContaining({ method: 'GET' })
|
||||
);
|
||||
// Should NOT contain session_id in URL
|
||||
expect(fetch.mock.calls[0][0]).not.toContain('session_id');
|
||||
expect(result.messages).toHaveLength(1);
|
||||
expect(result.next).toBeNull();
|
||||
});
|
||||
|
||||
test('includes pagination cursor (before)', async () => {
|
||||
global.fetch.mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
messages: [],
|
||||
next: null
|
||||
})
|
||||
});
|
||||
|
||||
await getChatMessages({
|
||||
channel: 'session',
|
||||
sessionId: 'session-abc',
|
||||
before: 50
|
||||
});
|
||||
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
expect.stringContaining('before=50'),
|
||||
expect.any(Object)
|
||||
);
|
||||
});
|
||||
|
||||
test('throws error on 404', async () => {
|
||||
global.fetch.mockResolvedValue({
|
||||
ok: false,
|
||||
status: 404,
|
||||
statusText: 'Not Found'
|
||||
});
|
||||
|
||||
await expect(
|
||||
getChatMessages({ channel: 'session', sessionId: 'invalid' })
|
||||
).rejects.toThrow();
|
||||
});
|
||||
|
||||
test('throws error on 403', async () => {
|
||||
global.fetch.mockResolvedValue({
|
||||
ok: false,
|
||||
status: 403,
|
||||
statusText: 'Forbidden'
|
||||
});
|
||||
|
||||
await expect(
|
||||
getChatMessages({ channel: 'session', sessionId: 'session-abc' })
|
||||
).rejects.toThrow();
|
||||
});
|
||||
|
||||
test('throws error on 500', async () => {
|
||||
global.fetch.mockResolvedValue({
|
||||
ok: false,
|
||||
status: 500,
|
||||
statusText: 'Internal Server Error'
|
||||
});
|
||||
|
||||
await expect(
|
||||
getChatMessages({ channel: 'global' })
|
||||
).rejects.toThrow();
|
||||
});
|
||||
|
||||
test('includes credentials and content-type headers', async () => {
|
||||
global.fetch.mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({ messages: [], next: null })
|
||||
});
|
||||
|
||||
await getChatMessages({ channel: 'global' });
|
||||
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
expect.objectContaining({
|
||||
credentials: 'include',
|
||||
headers: expect.objectContaining({
|
||||
'Content-Type': 'application/json'
|
||||
})
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('sendChatMessage', () => {
|
||||
beforeEach(() => {
|
||||
global.fetch.mockClear();
|
||||
});
|
||||
|
||||
test('sends message to session channel', async () => {
|
||||
global.fetch.mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
message: {
|
||||
id: 'msg-new',
|
||||
message: 'Hello world',
|
||||
sender_id: 'user-1',
|
||||
created_at: '2026-01-26T12:00:00Z'
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
const result = await sendChatMessage({
|
||||
channel: 'session',
|
||||
sessionId: 'session-abc',
|
||||
message: 'Hello world'
|
||||
});
|
||||
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
expect.stringContaining('/api/chat'),
|
||||
expect.objectContaining({
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
channel: 'session',
|
||||
session_id: 'session-abc',
|
||||
message: 'Hello world'
|
||||
})
|
||||
})
|
||||
);
|
||||
expect(result.message.id).toBe('msg-new');
|
||||
});
|
||||
|
||||
test('sends message to global channel', async () => {
|
||||
global.fetch.mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({
|
||||
message: {
|
||||
id: 'msg-global',
|
||||
message: 'Hello everyone',
|
||||
sender_id: 'user-1',
|
||||
created_at: '2026-01-26T12:00:00Z'
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
const result = await sendChatMessage({
|
||||
channel: 'global',
|
||||
message: 'Hello everyone'
|
||||
});
|
||||
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
expect.objectContaining({
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
channel: 'global',
|
||||
message: 'Hello everyone'
|
||||
})
|
||||
})
|
||||
);
|
||||
// Should NOT contain session_id
|
||||
const body = JSON.parse(fetch.mock.calls[0][1].body);
|
||||
expect(body.session_id).toBeUndefined();
|
||||
expect(result.message.id).toBe('msg-global');
|
||||
});
|
||||
|
||||
test('throws error on 422 (validation error)', async () => {
|
||||
global.fetch.mockResolvedValue({
|
||||
ok: false,
|
||||
status: 422,
|
||||
statusText: 'Unprocessable Entity',
|
||||
json: async () => ({ error: 'Message too long' })
|
||||
});
|
||||
|
||||
await expect(
|
||||
sendChatMessage({
|
||||
channel: 'session',
|
||||
sessionId: 'abc',
|
||||
message: 'x'.repeat(1000)
|
||||
})
|
||||
).rejects.toThrow();
|
||||
});
|
||||
|
||||
test('throws error on 403', async () => {
|
||||
global.fetch.mockResolvedValue({
|
||||
ok: false,
|
||||
status: 403,
|
||||
statusText: 'Forbidden',
|
||||
json: async () => ({ error: 'Unauthorized' })
|
||||
});
|
||||
|
||||
await expect(
|
||||
sendChatMessage({
|
||||
channel: 'session',
|
||||
sessionId: 'session-abc',
|
||||
message: 'Hello'
|
||||
})
|
||||
).rejects.toThrow();
|
||||
});
|
||||
|
||||
test('throws error on 500', async () => {
|
||||
global.fetch.mockResolvedValue({
|
||||
ok: false,
|
||||
status: 500,
|
||||
statusText: 'Internal Server Error',
|
||||
json: async () => ({ error: 'Server error' })
|
||||
});
|
||||
|
||||
await expect(
|
||||
sendChatMessage({
|
||||
channel: 'global',
|
||||
message: 'Hello'
|
||||
})
|
||||
).rejects.toThrow();
|
||||
});
|
||||
|
||||
test('includes credentials and content-type headers', async () => {
|
||||
global.fetch.mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({ message: { id: 'msg-1' } })
|
||||
});
|
||||
|
||||
await sendChatMessage({
|
||||
channel: 'global',
|
||||
message: 'Test'
|
||||
});
|
||||
|
||||
expect(fetch).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
expect.objectContaining({
|
||||
credentials: 'include',
|
||||
headers: expect.objectContaining({
|
||||
'Content-Type': 'application/json'
|
||||
})
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test('handles error response with invalid json gracefully', async () => {
|
||||
global.fetch.mockResolvedValue({
|
||||
ok: false,
|
||||
status: 500,
|
||||
statusText: 'Internal Server Error',
|
||||
json: async () => {
|
||||
throw new Error('Invalid JSON');
|
||||
}
|
||||
});
|
||||
|
||||
await expect(
|
||||
sendChatMessage({
|
||||
channel: 'global',
|
||||
message: 'Test'
|
||||
})
|
||||
).rejects.toThrow();
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue