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:
Nuwan 2026-01-27 08:14:00 +05:30
parent 08bf66cce3
commit b6ce5010ac
1 changed files with 302 additions and 0 deletions

View File

@ -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();
});
});