Skip to content

Commit 6722563

Browse files
committed
feat: add tests for HttpDispatcher to handle metadata operations including PUT and fallback to broker
1 parent a939863 commit 6722563

1 file changed

Lines changed: 107 additions & 0 deletions

File tree

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
2+
import { describe, it, expect, vi, beforeEach } from 'vitest';
3+
import { HttpDispatcher } from './http-dispatcher.js';
4+
import { ObjectKernel } from '@objectstack/core';
5+
6+
describe('HttpDispatcher', () => {
7+
let kernel: ObjectKernel;
8+
let dispatcher: HttpDispatcher;
9+
let mockProtocol: any;
10+
let mockBroker: any;
11+
12+
beforeEach(() => {
13+
// Mock Kernel
14+
mockProtocol = {
15+
saveMetaItem: vi.fn().mockResolvedValue({ success: true, message: 'Saved' }),
16+
getMetaItem: vi.fn().mockResolvedValue({ success: true, item: { foo: 'bar' } })
17+
};
18+
19+
mockBroker = {
20+
call: vi.fn(),
21+
};
22+
23+
kernel = {
24+
broker: mockBroker,
25+
context: {
26+
getService: (name: string) => {
27+
if (name === 'protocol') return mockProtocol;
28+
return null;
29+
}
30+
}
31+
} as any;
32+
33+
dispatcher = new HttpDispatcher(kernel);
34+
});
35+
36+
describe('handleMetadata', () => {
37+
it('should handle PUT /metadata/:type/:name by calling protocol.saveMetaItem', async () => {
38+
const context = { request: {} };
39+
const body = { label: 'New Label' };
40+
const path = '/objects/my_obj';
41+
42+
const result = await dispatcher.handleMetadata(path, context, 'PUT', body);
43+
44+
expect(result.handled).toBe(true);
45+
expect(result.response?.status).toBe(200);
46+
expect(mockProtocol.saveMetaItem).toHaveBeenCalledWith({
47+
type: 'objects',
48+
name: 'my_obj',
49+
item: body
50+
});
51+
expect(result.response?.body).toEqual({
52+
success: true,
53+
data: { success: true, message: 'Saved' },
54+
meta: undefined
55+
});
56+
});
57+
58+
it('should fallback to broker call if protocol is missing saveMetaItem', async () => {
59+
// Mock protocol without saveMetaItem
60+
kernel.context.getService = () => ({});
61+
// Mock broker success
62+
mockBroker.call.mockResolvedValue({ success: true, fromBroker: true });
63+
64+
const context = { request: {} };
65+
const body = { label: 'Fallback' };
66+
const path = '/objects/my_obj';
67+
68+
const result = await dispatcher.handleMetadata(path, context, 'PUT', body);
69+
70+
expect(result.handled).toBe(true);
71+
expect(mockBroker.call).toHaveBeenCalledWith(
72+
'metadata.saveItem',
73+
{ type: 'objects', name: 'my_obj', item: body },
74+
{ request: context.request }
75+
);
76+
expect(result.response?.body?.data).toEqual({ success: true, fromBroker: true });
77+
});
78+
79+
it('should return error if save fails', async () => {
80+
mockProtocol.saveMetaItem.mockRejectedValue(new Error('Save failed'));
81+
82+
const context = { request: {} };
83+
const body = {};
84+
const path = '/objects/bad_obj';
85+
86+
const result = await dispatcher.handleMetadata(path, context, 'PUT', body);
87+
88+
expect(result.handled).toBe(true);
89+
expect(result.response?.status).toBe(400);
90+
expect(result.response?.body?.error?.message).toBe('Save failed');
91+
});
92+
93+
it('should handle READ operations as before', async () => {
94+
mockBroker.call.mockResolvedValue({ name: 'my_obj' });
95+
96+
const context = { request: {} };
97+
const result = await dispatcher.handleMetadata('/objects/my_obj', context, 'GET');
98+
99+
expect(result.handled).toBe(true);
100+
expect(mockBroker.call).toHaveBeenCalledWith(
101+
'metadata.getObject',
102+
{ objectName: 'my_obj' },
103+
{ request: context.request }
104+
);
105+
});
106+
});
107+
});

0 commit comments

Comments
 (0)