@tambo-ai/react 0.49.0 → 0.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/__tests__/use-component-state.test.js +4 -1
- package/dist/hooks/__tests__/use-component-state.test.js.map +1 -1
- package/dist/hooks/__tests__/use-message-images.test.d.ts +2 -0
- package/dist/hooks/__tests__/use-message-images.test.d.ts.map +1 -0
- package/dist/hooks/__tests__/use-message-images.test.js +66 -0
- package/dist/hooks/__tests__/use-message-images.test.js.map +1 -0
- package/dist/hooks/__tests__/use-tambo-threads.test.js +1 -1
- package/dist/hooks/__tests__/use-tambo-threads.test.js.map +1 -1
- package/dist/hooks/use-component-state.js +3 -3
- package/dist/hooks/use-component-state.js.map +1 -1
- package/dist/hooks/use-message-images.d.ts +25 -0
- package/dist/hooks/use-message-images.d.ts.map +1 -0
- package/dist/hooks/use-message-images.js +66 -0
- package/dist/hooks/use-message-images.js.map +1 -0
- package/dist/hooks/use-suggestions.js +4 -2
- package/dist/hooks/use-suggestions.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/__tests__/mcp-client.test.d.ts +2 -0
- package/dist/mcp/__tests__/mcp-client.test.d.ts.map +1 -0
- package/dist/mcp/__tests__/mcp-client.test.js +502 -0
- package/dist/mcp/__tests__/mcp-client.test.js.map +1 -0
- package/dist/mcp/mcp-client.d.ts +77 -3
- package/dist/mcp/mcp-client.d.ts.map +1 -1
- package/dist/mcp/mcp-client.js +184 -19
- package/dist/mcp/mcp-client.js.map +1 -1
- package/dist/mcp/tambo-mcp-provider.d.ts +1 -0
- package/dist/mcp/tambo-mcp-provider.d.ts.map +1 -1
- package/dist/mcp/tambo-mcp-provider.js +1 -0
- package/dist/mcp/tambo-mcp-provider.js.map +1 -1
- package/dist/model/tambo-interactable.d.ts +1 -1
- package/dist/model/tambo-interactable.d.ts.map +1 -1
- package/dist/model/tambo-interactable.js.map +1 -1
- package/dist/providers/__tests__/tambo-interactable-provider-partial-updates.test.d.ts +2 -0
- package/dist/providers/__tests__/tambo-interactable-provider-partial-updates.test.d.ts.map +1 -0
- package/dist/providers/__tests__/tambo-interactable-provider-partial-updates.test.js +677 -0
- package/dist/providers/__tests__/tambo-interactable-provider-partial-updates.test.js.map +1 -0
- package/dist/providers/__tests__/tambo-stubs.test.js +6 -2
- package/dist/providers/__tests__/tambo-stubs.test.js.map +1 -1
- package/dist/providers/__tests__/tambo-thread-provider.test.js +14 -14
- package/dist/providers/__tests__/tambo-thread-provider.test.js.map +1 -1
- package/dist/providers/tambo-interactable-provider.d.ts.map +1 -1
- package/dist/providers/tambo-interactable-provider.js +26 -24
- package/dist/providers/tambo-interactable-provider.js.map +1 -1
- package/dist/providers/tambo-provider.d.ts +1 -0
- package/dist/providers/tambo-provider.d.ts.map +1 -1
- package/dist/providers/tambo-provider.js +1 -0
- package/dist/providers/tambo-provider.js.map +1 -1
- package/dist/providers/tambo-thread-input-provider.d.ts +11 -0
- package/dist/providers/tambo-thread-input-provider.d.ts.map +1 -1
- package/dist/providers/tambo-thread-input-provider.js +63 -12
- package/dist/providers/tambo-thread-input-provider.js.map +1 -1
- package/dist/providers/tambo-thread-provider.d.ts +1 -0
- package/dist/providers/tambo-thread-provider.d.ts.map +1 -1
- package/dist/providers/tambo-thread-provider.js +9 -5
- package/dist/providers/tambo-thread-provider.js.map +1 -1
- package/dist/setupTests.d.ts +0 -1
- package/dist/setupTests.d.ts.map +1 -1
- package/dist/setupTests.js +0 -1
- package/dist/setupTests.js.map +1 -1
- package/dist/util/__tests__/message-builder.test.d.ts +2 -0
- package/dist/util/__tests__/message-builder.test.d.ts.map +1 -0
- package/dist/util/__tests__/message-builder.test.js +191 -0
- package/dist/util/__tests__/message-builder.test.js.map +1 -0
- package/dist/util/message-builder.d.ts +10 -0
- package/dist/util/message-builder.d.ts.map +1 -0
- package/dist/util/message-builder.js +31 -0
- package/dist/util/message-builder.js.map +1 -0
- package/esm/hooks/__tests__/use-component-state.test.js +4 -1
- package/esm/hooks/__tests__/use-component-state.test.js.map +1 -1
- package/esm/hooks/__tests__/use-message-images.test.d.ts +2 -0
- package/esm/hooks/__tests__/use-message-images.test.d.ts.map +1 -0
- package/esm/hooks/__tests__/use-message-images.test.js +64 -0
- package/esm/hooks/__tests__/use-message-images.test.js.map +1 -0
- package/esm/hooks/__tests__/use-tambo-threads.test.js +1 -1
- package/esm/hooks/__tests__/use-tambo-threads.test.js.map +1 -1
- package/esm/hooks/use-component-state.js +3 -3
- package/esm/hooks/use-component-state.js.map +1 -1
- package/esm/hooks/use-message-images.d.ts +25 -0
- package/esm/hooks/use-message-images.d.ts.map +1 -0
- package/esm/hooks/use-message-images.js +63 -0
- package/esm/hooks/use-message-images.js.map +1 -0
- package/esm/hooks/use-suggestions.js +4 -2
- package/esm/hooks/use-suggestions.js.map +1 -1
- package/esm/index.d.ts +1 -0
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +1 -0
- package/esm/index.js.map +1 -1
- package/esm/mcp/__tests__/mcp-client.test.d.ts +2 -0
- package/esm/mcp/__tests__/mcp-client.test.d.ts.map +1 -0
- package/esm/mcp/__tests__/mcp-client.test.js +500 -0
- package/esm/mcp/__tests__/mcp-client.test.js.map +1 -0
- package/esm/mcp/mcp-client.d.ts +77 -3
- package/esm/mcp/mcp-client.d.ts.map +1 -1
- package/esm/mcp/mcp-client.js +184 -19
- package/esm/mcp/mcp-client.js.map +1 -1
- package/esm/mcp/tambo-mcp-provider.d.ts +1 -0
- package/esm/mcp/tambo-mcp-provider.d.ts.map +1 -1
- package/esm/mcp/tambo-mcp-provider.js +1 -0
- package/esm/mcp/tambo-mcp-provider.js.map +1 -1
- package/esm/model/tambo-interactable.d.ts +1 -1
- package/esm/model/tambo-interactable.d.ts.map +1 -1
- package/esm/model/tambo-interactable.js.map +1 -1
- package/esm/providers/__tests__/tambo-interactable-provider-partial-updates.test.d.ts +2 -0
- package/esm/providers/__tests__/tambo-interactable-provider-partial-updates.test.d.ts.map +1 -0
- package/esm/providers/__tests__/tambo-interactable-provider-partial-updates.test.js +672 -0
- package/esm/providers/__tests__/tambo-interactable-provider-partial-updates.test.js.map +1 -0
- package/esm/providers/__tests__/tambo-stubs.test.js +6 -2
- package/esm/providers/__tests__/tambo-stubs.test.js.map +1 -1
- package/esm/providers/__tests__/tambo-thread-provider.test.js +14 -14
- package/esm/providers/__tests__/tambo-thread-provider.test.js.map +1 -1
- package/esm/providers/tambo-interactable-provider.d.ts.map +1 -1
- package/esm/providers/tambo-interactable-provider.js +26 -24
- package/esm/providers/tambo-interactable-provider.js.map +1 -1
- package/esm/providers/tambo-provider.d.ts +1 -0
- package/esm/providers/tambo-provider.d.ts.map +1 -1
- package/esm/providers/tambo-provider.js +1 -0
- package/esm/providers/tambo-provider.js.map +1 -1
- package/esm/providers/tambo-thread-input-provider.d.ts +11 -0
- package/esm/providers/tambo-thread-input-provider.d.ts.map +1 -1
- package/esm/providers/tambo-thread-input-provider.js +63 -12
- package/esm/providers/tambo-thread-input-provider.js.map +1 -1
- package/esm/providers/tambo-thread-provider.d.ts +1 -0
- package/esm/providers/tambo-thread-provider.d.ts.map +1 -1
- package/esm/providers/tambo-thread-provider.js +9 -5
- package/esm/providers/tambo-thread-provider.js.map +1 -1
- package/esm/setupTests.d.ts +0 -1
- package/esm/setupTests.d.ts.map +1 -1
- package/esm/setupTests.js +0 -1
- package/esm/setupTests.js.map +1 -1
- package/esm/util/__tests__/message-builder.test.d.ts +2 -0
- package/esm/util/__tests__/message-builder.test.d.ts.map +1 -0
- package/esm/util/__tests__/message-builder.test.js +189 -0
- package/esm/util/__tests__/message-builder.test.js.map +1 -0
- package/esm/util/message-builder.d.ts +10 -0
- package/esm/util/message-builder.d.ts.map +1 -0
- package/esm/util/message-builder.js +28 -0
- package/esm/util/message-builder.js.map +1 -0
- package/package.json +7 -7
|
@@ -0,0 +1,677 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const react_1 = require("@testing-library/react");
|
|
7
|
+
const react_2 = __importDefault(require("react"));
|
|
8
|
+
const zod_1 = require("zod");
|
|
9
|
+
const tambo_interactable_provider_1 = require("../tambo-interactable-provider");
|
|
10
|
+
// Mock the context helpers
|
|
11
|
+
const mockAddContextHelper = jest.fn();
|
|
12
|
+
const mockRemoveContextHelper = jest.fn();
|
|
13
|
+
jest.mock("../tambo-context-helpers-provider", () => ({
|
|
14
|
+
TamboContextHelpersProvider: ({ children, }) => react_2.default.createElement(react_2.default.Fragment, null, children),
|
|
15
|
+
useTamboContextHelpers: () => ({
|
|
16
|
+
addContextHelper: mockAddContextHelper,
|
|
17
|
+
removeContextHelper: mockRemoveContextHelper,
|
|
18
|
+
}),
|
|
19
|
+
}));
|
|
20
|
+
// Mock the component provider
|
|
21
|
+
const mockRegisterTool = jest.fn();
|
|
22
|
+
jest.mock("../tambo-component-provider", () => ({
|
|
23
|
+
useTamboComponent: () => ({
|
|
24
|
+
registerTool: mockRegisterTool,
|
|
25
|
+
}),
|
|
26
|
+
}));
|
|
27
|
+
// Mock the context helper creation
|
|
28
|
+
jest.mock("../../context-helpers/current-interactables-context-helper", () => ({
|
|
29
|
+
createInteractablesContextHelper: () => jest.fn(() => ({
|
|
30
|
+
name: "interactables",
|
|
31
|
+
context: {
|
|
32
|
+
description: "Test interactables context",
|
|
33
|
+
components: [],
|
|
34
|
+
},
|
|
35
|
+
})),
|
|
36
|
+
}));
|
|
37
|
+
describe("updateInteractableComponentProps - Partial Updates", () => {
|
|
38
|
+
beforeEach(() => {
|
|
39
|
+
jest.clearAllMocks();
|
|
40
|
+
});
|
|
41
|
+
const wrapper = ({ children }) => (react_2.default.createElement(tambo_interactable_provider_1.TamboInteractableProvider, null, children));
|
|
42
|
+
describe("Partial Updates Functionality", () => {
|
|
43
|
+
it("should apply partial updates to existing props", () => {
|
|
44
|
+
const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
|
|
45
|
+
const component = {
|
|
46
|
+
name: "TestComponent",
|
|
47
|
+
description: "A test component",
|
|
48
|
+
component: () => react_2.default.createElement("div", null, "Test"),
|
|
49
|
+
props: {
|
|
50
|
+
title: "Original Title",
|
|
51
|
+
count: 0,
|
|
52
|
+
active: true,
|
|
53
|
+
metadata: { type: "test", version: "1.0" },
|
|
54
|
+
},
|
|
55
|
+
propsSchema: zod_1.z.object({
|
|
56
|
+
title: zod_1.z.string(),
|
|
57
|
+
count: zod_1.z.number(),
|
|
58
|
+
active: zod_1.z.boolean(),
|
|
59
|
+
metadata: zod_1.z.object({
|
|
60
|
+
type: zod_1.z.string(),
|
|
61
|
+
version: zod_1.z.string(),
|
|
62
|
+
}),
|
|
63
|
+
}),
|
|
64
|
+
};
|
|
65
|
+
let componentId = "";
|
|
66
|
+
(0, react_1.act)(() => {
|
|
67
|
+
componentId = result.current.addInteractableComponent(component);
|
|
68
|
+
});
|
|
69
|
+
// Verify initial state
|
|
70
|
+
expect(result.current.interactableComponents[0].props).toEqual({
|
|
71
|
+
title: "Original Title",
|
|
72
|
+
count: 0,
|
|
73
|
+
active: true,
|
|
74
|
+
metadata: { type: "test", version: "1.0" },
|
|
75
|
+
});
|
|
76
|
+
// Apply partial update - only change count
|
|
77
|
+
let updateResult = "";
|
|
78
|
+
(0, react_1.act)(() => {
|
|
79
|
+
updateResult = result.current.updateInteractableComponentProps(componentId, {
|
|
80
|
+
count: 5,
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
expect(updateResult).toBe("Updated successfully");
|
|
84
|
+
expect(result.current.interactableComponents[0].props).toEqual({
|
|
85
|
+
title: "Original Title", // unchanged
|
|
86
|
+
count: 5, // updated
|
|
87
|
+
active: true, // unchanged
|
|
88
|
+
metadata: { type: "test", version: "1.0" }, // unchanged
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
it("should apply multiple partial updates in sequence", () => {
|
|
92
|
+
const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
|
|
93
|
+
const component = {
|
|
94
|
+
name: "TestComponent",
|
|
95
|
+
description: "A test component",
|
|
96
|
+
component: () => react_2.default.createElement("div", null, "Test"),
|
|
97
|
+
props: {
|
|
98
|
+
title: "Original Title",
|
|
99
|
+
count: 0,
|
|
100
|
+
active: true,
|
|
101
|
+
description: "Original description",
|
|
102
|
+
},
|
|
103
|
+
propsSchema: zod_1.z.object({
|
|
104
|
+
title: zod_1.z.string(),
|
|
105
|
+
count: zod_1.z.number(),
|
|
106
|
+
active: zod_1.z.boolean(),
|
|
107
|
+
description: zod_1.z.string(),
|
|
108
|
+
}),
|
|
109
|
+
};
|
|
110
|
+
let componentId = "";
|
|
111
|
+
(0, react_1.act)(() => {
|
|
112
|
+
componentId = result.current.addInteractableComponent(component);
|
|
113
|
+
});
|
|
114
|
+
// First partial update - change title and count
|
|
115
|
+
(0, react_1.act)(() => {
|
|
116
|
+
result.current.updateInteractableComponentProps(componentId, {
|
|
117
|
+
title: "Updated Title",
|
|
118
|
+
count: 10,
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
expect(result.current.interactableComponents[0].props).toEqual({
|
|
122
|
+
title: "Updated Title",
|
|
123
|
+
count: 10,
|
|
124
|
+
active: true,
|
|
125
|
+
description: "Original description",
|
|
126
|
+
});
|
|
127
|
+
// Second partial update - change active and description
|
|
128
|
+
(0, react_1.act)(() => {
|
|
129
|
+
result.current.updateInteractableComponentProps(componentId, {
|
|
130
|
+
active: false,
|
|
131
|
+
description: "Updated description",
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
expect(result.current.interactableComponents[0].props).toEqual({
|
|
135
|
+
title: "Updated Title", // from previous update
|
|
136
|
+
count: 10, // from previous update
|
|
137
|
+
active: false, // new update
|
|
138
|
+
description: "Updated description", // new update
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
it("should handle nested object partial updates (shallow merge behavior)", () => {
|
|
142
|
+
const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
|
|
143
|
+
const component = {
|
|
144
|
+
name: "TestComponent",
|
|
145
|
+
description: "A test component",
|
|
146
|
+
component: () => react_2.default.createElement("div", null, "Test"),
|
|
147
|
+
props: {
|
|
148
|
+
title: "Original Title",
|
|
149
|
+
config: {
|
|
150
|
+
theme: "light",
|
|
151
|
+
language: "en",
|
|
152
|
+
features: {
|
|
153
|
+
notifications: true,
|
|
154
|
+
analytics: false,
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
propsSchema: zod_1.z.object({
|
|
159
|
+
title: zod_1.z.string(),
|
|
160
|
+
config: zod_1.z.object({
|
|
161
|
+
theme: zod_1.z.string(),
|
|
162
|
+
language: zod_1.z.string(),
|
|
163
|
+
features: zod_1.z.object({
|
|
164
|
+
notifications: zod_1.z.boolean(),
|
|
165
|
+
analytics: zod_1.z.boolean(),
|
|
166
|
+
}),
|
|
167
|
+
}),
|
|
168
|
+
}),
|
|
169
|
+
};
|
|
170
|
+
let componentId = "";
|
|
171
|
+
(0, react_1.act)(() => {
|
|
172
|
+
componentId = result.current.addInteractableComponent(component);
|
|
173
|
+
});
|
|
174
|
+
// Partial update - replace entire config object (shallow merge behavior)
|
|
175
|
+
(0, react_1.act)(() => {
|
|
176
|
+
result.current.updateInteractableComponentProps(componentId, {
|
|
177
|
+
config: {
|
|
178
|
+
theme: "dark",
|
|
179
|
+
// Note: language and features are not provided, so they will be undefined
|
|
180
|
+
// This demonstrates the shallow merge behavior
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
expect(result.current.interactableComponents[0].props).toEqual({
|
|
185
|
+
title: "Original Title",
|
|
186
|
+
config: {
|
|
187
|
+
theme: "dark", // updated
|
|
188
|
+
// language and features are now undefined due to shallow merge
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
it("should handle array partial updates", () => {
|
|
193
|
+
const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
|
|
194
|
+
const component = {
|
|
195
|
+
name: "TestComponent",
|
|
196
|
+
description: "A test component",
|
|
197
|
+
component: () => react_2.default.createElement("div", null, "Test"),
|
|
198
|
+
props: {
|
|
199
|
+
title: "Original Title",
|
|
200
|
+
items: ["item1", "item2", "item3"],
|
|
201
|
+
tags: ["tag1", "tag2"],
|
|
202
|
+
},
|
|
203
|
+
propsSchema: zod_1.z.object({
|
|
204
|
+
title: zod_1.z.string(),
|
|
205
|
+
items: zod_1.z.array(zod_1.z.string()),
|
|
206
|
+
tags: zod_1.z.array(zod_1.z.string()),
|
|
207
|
+
}),
|
|
208
|
+
};
|
|
209
|
+
let componentId = "";
|
|
210
|
+
(0, react_1.act)(() => {
|
|
211
|
+
componentId = result.current.addInteractableComponent(component);
|
|
212
|
+
});
|
|
213
|
+
// Partial update - only change items array
|
|
214
|
+
(0, react_1.act)(() => {
|
|
215
|
+
result.current.updateInteractableComponentProps(componentId, {
|
|
216
|
+
items: ["newItem1", "newItem2"],
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
expect(result.current.interactableComponents[0].props).toEqual({
|
|
220
|
+
title: "Original Title", // unchanged
|
|
221
|
+
items: ["newItem1", "newItem2"], // updated
|
|
222
|
+
tags: ["tag1", "tag2"], // unchanged
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
it("should handle null and undefined values in partial updates", () => {
|
|
226
|
+
const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
|
|
227
|
+
const component = {
|
|
228
|
+
name: "TestComponent",
|
|
229
|
+
description: "A test component",
|
|
230
|
+
component: () => react_2.default.createElement("div", null, "Test"),
|
|
231
|
+
props: {
|
|
232
|
+
title: "Original Title",
|
|
233
|
+
count: 5,
|
|
234
|
+
description: "Original description",
|
|
235
|
+
},
|
|
236
|
+
propsSchema: zod_1.z.object({
|
|
237
|
+
title: zod_1.z.string(),
|
|
238
|
+
count: zod_1.z.number(),
|
|
239
|
+
description: zod_1.z.string(),
|
|
240
|
+
}),
|
|
241
|
+
};
|
|
242
|
+
let componentId = "";
|
|
243
|
+
(0, react_1.act)(() => {
|
|
244
|
+
componentId = result.current.addInteractableComponent(component);
|
|
245
|
+
});
|
|
246
|
+
// Partial update with null value
|
|
247
|
+
(0, react_1.act)(() => {
|
|
248
|
+
result.current.updateInteractableComponentProps(componentId, {
|
|
249
|
+
description: null,
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
expect(result.current.interactableComponents[0].props).toEqual({
|
|
253
|
+
title: "Original Title",
|
|
254
|
+
count: 5,
|
|
255
|
+
description: null,
|
|
256
|
+
});
|
|
257
|
+
// Partial update with undefined value
|
|
258
|
+
(0, react_1.act)(() => {
|
|
259
|
+
result.current.updateInteractableComponentProps(componentId, {
|
|
260
|
+
count: undefined,
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
expect(result.current.interactableComponents[0].props).toEqual({
|
|
264
|
+
title: "Original Title",
|
|
265
|
+
count: undefined,
|
|
266
|
+
description: null,
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
describe("Error Handling", () => {
|
|
271
|
+
it("should return error for non-existent component", () => {
|
|
272
|
+
const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
|
|
273
|
+
let updateResult = "";
|
|
274
|
+
(0, react_1.act)(() => {
|
|
275
|
+
updateResult = result.current.updateInteractableComponentProps("non-existent", {
|
|
276
|
+
title: "New Title",
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
expect(updateResult).toBe("Updated successfully");
|
|
280
|
+
});
|
|
281
|
+
it("should return warning for empty props object", () => {
|
|
282
|
+
const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
|
|
283
|
+
const component = {
|
|
284
|
+
name: "TestComponent",
|
|
285
|
+
description: "A test component",
|
|
286
|
+
component: () => react_2.default.createElement("div", null, "Test"),
|
|
287
|
+
props: { title: "Original Title" },
|
|
288
|
+
propsSchema: zod_1.z.object({ title: zod_1.z.string() }),
|
|
289
|
+
};
|
|
290
|
+
let componentId = "";
|
|
291
|
+
(0, react_1.act)(() => {
|
|
292
|
+
componentId = result.current.addInteractableComponent(component);
|
|
293
|
+
});
|
|
294
|
+
let updateResult = "";
|
|
295
|
+
(0, react_1.act)(() => {
|
|
296
|
+
updateResult = result.current.updateInteractableComponentProps(componentId, {});
|
|
297
|
+
});
|
|
298
|
+
expect(updateResult).toBe(`Warning: No props provided for component with ID ${componentId}.`);
|
|
299
|
+
});
|
|
300
|
+
it("should return warning for null props", () => {
|
|
301
|
+
const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
|
|
302
|
+
const component = {
|
|
303
|
+
name: "TestComponent",
|
|
304
|
+
description: "A test component",
|
|
305
|
+
component: () => react_2.default.createElement("div", null, "Test"),
|
|
306
|
+
props: { title: "Original Title" },
|
|
307
|
+
propsSchema: zod_1.z.object({ title: zod_1.z.string() }),
|
|
308
|
+
};
|
|
309
|
+
let componentId = "";
|
|
310
|
+
(0, react_1.act)(() => {
|
|
311
|
+
componentId = result.current.addInteractableComponent(component);
|
|
312
|
+
});
|
|
313
|
+
let updateResult = "";
|
|
314
|
+
(0, react_1.act)(() => {
|
|
315
|
+
updateResult = result.current.updateInteractableComponentProps(componentId, null);
|
|
316
|
+
});
|
|
317
|
+
expect(updateResult).toBe(`Warning: No props provided for component with ID ${componentId}.`);
|
|
318
|
+
});
|
|
319
|
+
it("should return warning for undefined props", () => {
|
|
320
|
+
const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
|
|
321
|
+
const component = {
|
|
322
|
+
name: "TestComponent",
|
|
323
|
+
description: "A test component",
|
|
324
|
+
component: () => react_2.default.createElement("div", null, "Test"),
|
|
325
|
+
props: { title: "Original Title" },
|
|
326
|
+
propsSchema: zod_1.z.object({ title: zod_1.z.string() }),
|
|
327
|
+
};
|
|
328
|
+
let componentId = "";
|
|
329
|
+
(0, react_1.act)(() => {
|
|
330
|
+
componentId = result.current.addInteractableComponent(component);
|
|
331
|
+
});
|
|
332
|
+
let updateResult = "";
|
|
333
|
+
(0, react_1.act)(() => {
|
|
334
|
+
updateResult = result.current.updateInteractableComponentProps(componentId, undefined);
|
|
335
|
+
});
|
|
336
|
+
expect(updateResult).toBe(`Warning: No props provided for component with ID ${componentId}.`);
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
describe("Performance and Efficiency", () => {
|
|
340
|
+
it("should only update changed properties without affecting others", () => {
|
|
341
|
+
const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
|
|
342
|
+
const component = {
|
|
343
|
+
name: "TestComponent",
|
|
344
|
+
description: "A test component",
|
|
345
|
+
component: () => react_2.default.createElement("div", null, "Test"),
|
|
346
|
+
props: {
|
|
347
|
+
title: "Original Title",
|
|
348
|
+
count: 0,
|
|
349
|
+
active: true,
|
|
350
|
+
metadata: { type: "test", version: "1.0" },
|
|
351
|
+
items: ["item1", "item2"],
|
|
352
|
+
},
|
|
353
|
+
propsSchema: zod_1.z.object({
|
|
354
|
+
title: zod_1.z.string(),
|
|
355
|
+
count: zod_1.z.number(),
|
|
356
|
+
active: zod_1.z.boolean(),
|
|
357
|
+
metadata: zod_1.z.object({
|
|
358
|
+
type: zod_1.z.string(),
|
|
359
|
+
version: zod_1.z.string(),
|
|
360
|
+
}),
|
|
361
|
+
items: zod_1.z.array(zod_1.z.string()),
|
|
362
|
+
}),
|
|
363
|
+
};
|
|
364
|
+
let componentId = "";
|
|
365
|
+
(0, react_1.act)(() => {
|
|
366
|
+
componentId = result.current.addInteractableComponent(component);
|
|
367
|
+
});
|
|
368
|
+
const originalProps = result.current.interactableComponents[0].props;
|
|
369
|
+
const originalMetadata = originalProps.metadata;
|
|
370
|
+
const originalItems = originalProps.items;
|
|
371
|
+
// Apply minimal partial update - only change count
|
|
372
|
+
(0, react_1.act)(() => {
|
|
373
|
+
result.current.updateInteractableComponentProps(componentId, {
|
|
374
|
+
count: 1,
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
const updatedProps = result.current.interactableComponents[0].props;
|
|
378
|
+
// Verify that only count changed
|
|
379
|
+
expect(updatedProps.count).toBe(1);
|
|
380
|
+
expect(updatedProps.title).toBe("Original Title");
|
|
381
|
+
expect(updatedProps.active).toBe(true);
|
|
382
|
+
// Verify that nested objects are preserved (same reference for efficiency)
|
|
383
|
+
expect(updatedProps.metadata).toBe(originalMetadata);
|
|
384
|
+
expect(updatedProps.items).toBe(originalItems);
|
|
385
|
+
});
|
|
386
|
+
it("should handle large objects efficiently with partial updates", () => {
|
|
387
|
+
const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
|
|
388
|
+
// Create a component with a large initial state
|
|
389
|
+
const largeData = {
|
|
390
|
+
users: Array.from({ length: 1000 }, (_, i) => ({
|
|
391
|
+
id: i,
|
|
392
|
+
name: `User ${i}`,
|
|
393
|
+
})),
|
|
394
|
+
settings: {
|
|
395
|
+
theme: "light",
|
|
396
|
+
language: "en",
|
|
397
|
+
notifications: true,
|
|
398
|
+
privacy: {
|
|
399
|
+
shareData: false,
|
|
400
|
+
analytics: true,
|
|
401
|
+
marketing: false,
|
|
402
|
+
},
|
|
403
|
+
},
|
|
404
|
+
metadata: {
|
|
405
|
+
version: "1.0.0",
|
|
406
|
+
build: "12345",
|
|
407
|
+
timestamp: Date.now(),
|
|
408
|
+
},
|
|
409
|
+
};
|
|
410
|
+
const component = {
|
|
411
|
+
name: "TestComponent",
|
|
412
|
+
description: "A test component with large data",
|
|
413
|
+
component: () => react_2.default.createElement("div", null, "Test"),
|
|
414
|
+
props: largeData,
|
|
415
|
+
propsSchema: zod_1.z.object({
|
|
416
|
+
users: zod_1.z.array(zod_1.z.object({
|
|
417
|
+
id: zod_1.z.number(),
|
|
418
|
+
name: zod_1.z.string(),
|
|
419
|
+
})),
|
|
420
|
+
settings: zod_1.z.object({
|
|
421
|
+
theme: zod_1.z.string(),
|
|
422
|
+
language: zod_1.z.string(),
|
|
423
|
+
notifications: zod_1.z.boolean(),
|
|
424
|
+
privacy: zod_1.z.object({
|
|
425
|
+
shareData: zod_1.z.boolean(),
|
|
426
|
+
analytics: zod_1.z.boolean(),
|
|
427
|
+
marketing: zod_1.z.boolean(),
|
|
428
|
+
}),
|
|
429
|
+
}),
|
|
430
|
+
metadata: zod_1.z.object({
|
|
431
|
+
version: zod_1.z.string(),
|
|
432
|
+
build: zod_1.z.string(),
|
|
433
|
+
timestamp: zod_1.z.number(),
|
|
434
|
+
}),
|
|
435
|
+
}),
|
|
436
|
+
};
|
|
437
|
+
let componentId = "";
|
|
438
|
+
(0, react_1.act)(() => {
|
|
439
|
+
componentId = result.current.addInteractableComponent(component);
|
|
440
|
+
});
|
|
441
|
+
const originalProps = result.current.interactableComponents[0].props;
|
|
442
|
+
const originalUsers = originalProps.users;
|
|
443
|
+
// Apply a small partial update - only change theme (shallow merge behavior)
|
|
444
|
+
(0, react_1.act)(() => {
|
|
445
|
+
result.current.updateInteractableComponentProps(componentId, {
|
|
446
|
+
settings: {
|
|
447
|
+
theme: "dark",
|
|
448
|
+
// Note: other settings properties are not provided, so they will be undefined
|
|
449
|
+
// This demonstrates the shallow merge behavior
|
|
450
|
+
},
|
|
451
|
+
});
|
|
452
|
+
});
|
|
453
|
+
const updatedProps = result.current.interactableComponents[0].props;
|
|
454
|
+
// Verify the update worked
|
|
455
|
+
expect(updatedProps.settings.theme).toBe("dark");
|
|
456
|
+
// Due to shallow merge, other properties are now undefined
|
|
457
|
+
expect(updatedProps.settings.language).toBeUndefined();
|
|
458
|
+
expect(updatedProps.settings.notifications).toBeUndefined();
|
|
459
|
+
// Verify that large arrays are preserved (same reference for efficiency)
|
|
460
|
+
expect(updatedProps.users).toBe(originalUsers);
|
|
461
|
+
// Verify that metadata is preserved (not updated)
|
|
462
|
+
expect(updatedProps.metadata).toBe(originalProps.metadata);
|
|
463
|
+
});
|
|
464
|
+
});
|
|
465
|
+
describe("Edge Cases", () => {
|
|
466
|
+
it("should handle updating a property that doesn't exist in original props", () => {
|
|
467
|
+
const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
|
|
468
|
+
const component = {
|
|
469
|
+
name: "TestComponent",
|
|
470
|
+
description: "A test component",
|
|
471
|
+
component: () => react_2.default.createElement("div", null, "Test"),
|
|
472
|
+
props: {
|
|
473
|
+
title: "Original Title",
|
|
474
|
+
count: 0,
|
|
475
|
+
},
|
|
476
|
+
propsSchema: zod_1.z.object({
|
|
477
|
+
title: zod_1.z.string(),
|
|
478
|
+
count: zod_1.z.number(),
|
|
479
|
+
newProperty: zod_1.z.string().optional(),
|
|
480
|
+
}),
|
|
481
|
+
};
|
|
482
|
+
let componentId = "";
|
|
483
|
+
(0, react_1.act)(() => {
|
|
484
|
+
componentId = result.current.addInteractableComponent(component);
|
|
485
|
+
});
|
|
486
|
+
// Add a new property that wasn't in the original props
|
|
487
|
+
(0, react_1.act)(() => {
|
|
488
|
+
result.current.updateInteractableComponentProps(componentId, {
|
|
489
|
+
newProperty: "New Value",
|
|
490
|
+
});
|
|
491
|
+
});
|
|
492
|
+
expect(result.current.interactableComponents[0].props).toEqual({
|
|
493
|
+
title: "Original Title",
|
|
494
|
+
count: 0,
|
|
495
|
+
newProperty: "New Value",
|
|
496
|
+
});
|
|
497
|
+
});
|
|
498
|
+
it("should handle updating with same values (no-op updates)", () => {
|
|
499
|
+
const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
|
|
500
|
+
const component = {
|
|
501
|
+
name: "TestComponent",
|
|
502
|
+
description: "A test component",
|
|
503
|
+
component: () => react_2.default.createElement("div", null, "Test"),
|
|
504
|
+
props: {
|
|
505
|
+
title: "Original Title",
|
|
506
|
+
count: 5,
|
|
507
|
+
active: true,
|
|
508
|
+
},
|
|
509
|
+
propsSchema: zod_1.z.object({
|
|
510
|
+
title: zod_1.z.string(),
|
|
511
|
+
count: zod_1.z.number(),
|
|
512
|
+
active: zod_1.z.boolean(),
|
|
513
|
+
}),
|
|
514
|
+
};
|
|
515
|
+
let componentId = "";
|
|
516
|
+
(0, react_1.act)(() => {
|
|
517
|
+
componentId = result.current.addInteractableComponent(component);
|
|
518
|
+
});
|
|
519
|
+
const originalProps = result.current.interactableComponents[0].props;
|
|
520
|
+
// Update with the same values
|
|
521
|
+
let updateResult = "";
|
|
522
|
+
(0, react_1.act)(() => {
|
|
523
|
+
updateResult = result.current.updateInteractableComponentProps(componentId, {
|
|
524
|
+
title: "Original Title",
|
|
525
|
+
count: 5,
|
|
526
|
+
active: true,
|
|
527
|
+
});
|
|
528
|
+
});
|
|
529
|
+
expect(updateResult).toBe("Updated successfully");
|
|
530
|
+
expect(result.current.interactableComponents[0].props).toEqual(originalProps);
|
|
531
|
+
});
|
|
532
|
+
it("should handle proper nested partial updates by providing complete nested structure", () => {
|
|
533
|
+
const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
|
|
534
|
+
const component = {
|
|
535
|
+
name: "TestComponent",
|
|
536
|
+
description: "A test component",
|
|
537
|
+
component: () => react_2.default.createElement("div", null, "Test"),
|
|
538
|
+
props: {
|
|
539
|
+
title: "Original Title",
|
|
540
|
+
config: {
|
|
541
|
+
theme: "light",
|
|
542
|
+
language: "en",
|
|
543
|
+
features: {
|
|
544
|
+
notifications: true,
|
|
545
|
+
analytics: false,
|
|
546
|
+
experimental: {
|
|
547
|
+
beta: false,
|
|
548
|
+
alpha: true,
|
|
549
|
+
},
|
|
550
|
+
},
|
|
551
|
+
},
|
|
552
|
+
},
|
|
553
|
+
propsSchema: zod_1.z.object({
|
|
554
|
+
title: zod_1.z.string(),
|
|
555
|
+
config: zod_1.z.object({
|
|
556
|
+
theme: zod_1.z.string(),
|
|
557
|
+
language: zod_1.z.string(),
|
|
558
|
+
features: zod_1.z.object({
|
|
559
|
+
notifications: zod_1.z.boolean(),
|
|
560
|
+
analytics: zod_1.z.boolean(),
|
|
561
|
+
experimental: zod_1.z.object({
|
|
562
|
+
beta: zod_1.z.boolean(),
|
|
563
|
+
alpha: zod_1.z.boolean(),
|
|
564
|
+
}),
|
|
565
|
+
}),
|
|
566
|
+
}),
|
|
567
|
+
}),
|
|
568
|
+
};
|
|
569
|
+
let componentId = "";
|
|
570
|
+
(0, react_1.act)(() => {
|
|
571
|
+
componentId = result.current.addInteractableComponent(component);
|
|
572
|
+
});
|
|
573
|
+
// Proper nested partial update - provide complete nested structure
|
|
574
|
+
(0, react_1.act)(() => {
|
|
575
|
+
result.current.updateInteractableComponentProps(componentId, {
|
|
576
|
+
config: {
|
|
577
|
+
theme: "light", // keep original
|
|
578
|
+
language: "en", // keep original
|
|
579
|
+
features: {
|
|
580
|
+
notifications: true, // keep original
|
|
581
|
+
analytics: false, // keep original
|
|
582
|
+
experimental: {
|
|
583
|
+
beta: true, // update this
|
|
584
|
+
alpha: true, // keep original
|
|
585
|
+
},
|
|
586
|
+
},
|
|
587
|
+
},
|
|
588
|
+
});
|
|
589
|
+
});
|
|
590
|
+
expect(result.current.interactableComponents[0].props).toEqual({
|
|
591
|
+
title: "Original Title",
|
|
592
|
+
config: {
|
|
593
|
+
theme: "light", // unchanged
|
|
594
|
+
language: "en", // unchanged
|
|
595
|
+
features: {
|
|
596
|
+
notifications: true, // unchanged
|
|
597
|
+
analytics: false, // unchanged
|
|
598
|
+
experimental: {
|
|
599
|
+
beta: true, // updated
|
|
600
|
+
alpha: true, // unchanged
|
|
601
|
+
},
|
|
602
|
+
},
|
|
603
|
+
},
|
|
604
|
+
});
|
|
605
|
+
});
|
|
606
|
+
it("should handle complex nested partial updates (shallow merge behavior)", () => {
|
|
607
|
+
const { result } = (0, react_1.renderHook)(() => (0, tambo_interactable_provider_1.useTamboInteractable)(), { wrapper });
|
|
608
|
+
const component = {
|
|
609
|
+
name: "TestComponent",
|
|
610
|
+
description: "A test component",
|
|
611
|
+
component: () => react_2.default.createElement("div", null, "Test"),
|
|
612
|
+
props: {
|
|
613
|
+
title: "Original Title",
|
|
614
|
+
config: {
|
|
615
|
+
theme: "light",
|
|
616
|
+
language: "en",
|
|
617
|
+
features: {
|
|
618
|
+
notifications: true,
|
|
619
|
+
analytics: false,
|
|
620
|
+
experimental: {
|
|
621
|
+
beta: false,
|
|
622
|
+
alpha: true,
|
|
623
|
+
},
|
|
624
|
+
},
|
|
625
|
+
},
|
|
626
|
+
},
|
|
627
|
+
propsSchema: zod_1.z.object({
|
|
628
|
+
title: zod_1.z.string(),
|
|
629
|
+
config: zod_1.z.object({
|
|
630
|
+
theme: zod_1.z.string(),
|
|
631
|
+
language: zod_1.z.string(),
|
|
632
|
+
features: zod_1.z.object({
|
|
633
|
+
notifications: zod_1.z.boolean(),
|
|
634
|
+
analytics: zod_1.z.boolean(),
|
|
635
|
+
experimental: zod_1.z.object({
|
|
636
|
+
beta: zod_1.z.boolean(),
|
|
637
|
+
alpha: zod_1.z.boolean(),
|
|
638
|
+
}),
|
|
639
|
+
}),
|
|
640
|
+
}),
|
|
641
|
+
}),
|
|
642
|
+
};
|
|
643
|
+
let componentId = "";
|
|
644
|
+
(0, react_1.act)(() => {
|
|
645
|
+
componentId = result.current.addInteractableComponent(component);
|
|
646
|
+
});
|
|
647
|
+
// Deep nested partial update - only change beta flag (shallow merge behavior)
|
|
648
|
+
(0, react_1.act)(() => {
|
|
649
|
+
result.current.updateInteractableComponentProps(componentId, {
|
|
650
|
+
config: {
|
|
651
|
+
features: {
|
|
652
|
+
experimental: {
|
|
653
|
+
beta: true,
|
|
654
|
+
// Note: alpha is not provided, so it will be undefined
|
|
655
|
+
// This demonstrates the shallow merge behavior
|
|
656
|
+
},
|
|
657
|
+
},
|
|
658
|
+
},
|
|
659
|
+
});
|
|
660
|
+
});
|
|
661
|
+
expect(result.current.interactableComponents[0].props).toEqual({
|
|
662
|
+
title: "Original Title",
|
|
663
|
+
config: {
|
|
664
|
+
// theme and language are now undefined due to shallow merge
|
|
665
|
+
features: {
|
|
666
|
+
// notifications and analytics are now undefined due to shallow merge
|
|
667
|
+
experimental: {
|
|
668
|
+
beta: true, // updated
|
|
669
|
+
// alpha is now undefined due to shallow merge
|
|
670
|
+
},
|
|
671
|
+
},
|
|
672
|
+
},
|
|
673
|
+
});
|
|
674
|
+
});
|
|
675
|
+
});
|
|
676
|
+
});
|
|
677
|
+
//# sourceMappingURL=tambo-interactable-provider-partial-updates.test.js.map
|