@copilotkit/react-core 1.54.1 → 1.55.0-next.8
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/CHANGELOG.md +127 -116
- package/dist/copilotkit-B3Mb1yVE.cjs +7975 -0
- package/dist/copilotkit-B3Mb1yVE.cjs.map +1 -0
- package/dist/copilotkit-DBzgOMby.d.cts +2182 -0
- package/dist/copilotkit-DBzgOMby.d.cts.map +1 -0
- package/dist/copilotkit-DNYSFuz5.mjs +7562 -0
- package/dist/copilotkit-DNYSFuz5.mjs.map +1 -0
- package/dist/copilotkit-Dy5w3qEV.d.mts +2182 -0
- package/dist/copilotkit-Dy5w3qEV.d.mts.map +1 -0
- package/dist/index.cjs +27 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +4 -5
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +1941 -35
- package/dist/index.umd.js.map +1 -1
- package/dist/v2/index.cjs +77 -7
- package/dist/v2/index.css +1 -2
- package/dist/v2/index.d.cts +6 -4
- package/dist/v2/index.d.mts +6 -4
- package/dist/v2/index.mjs +7 -4
- package/dist/v2/index.umd.js +5725 -24
- package/dist/v2/index.umd.js.map +1 -1
- package/package.json +37 -9
- package/scripts/scope-preflight.mjs +101 -0
- package/src/components/CopilotListeners.tsx +2 -6
- package/src/components/copilot-provider/copilot-messages.tsx +1 -1
- package/src/components/copilot-provider/copilotkit-props.tsx +1 -1
- package/src/components/copilot-provider/copilotkit.tsx +4 -4
- package/src/context/copilot-messages-context.tsx +1 -1
- package/src/hooks/__tests__/use-coagent-config.test.ts +2 -2
- package/src/hooks/__tests__/use-coagent-state-render.e2e.test.tsx +2 -2
- package/src/hooks/__tests__/use-copilot-chat-internal-connect.test.tsx +3 -7
- package/src/hooks/__tests__/use-frontend-tool-available.test.tsx +1 -1
- package/src/hooks/__tests__/use-frontend-tool-remount.e2e.test.tsx +4 -4
- package/src/hooks/use-agent-nodename.ts +1 -1
- package/src/hooks/use-coagent-state-render-bridge.tsx +1 -4
- package/src/hooks/use-coagent.ts +1 -1
- package/src/hooks/use-configure-chat-suggestions.tsx +2 -2
- package/src/hooks/use-copilot-chat-suggestions.tsx +2 -2
- package/src/hooks/use-copilot-chat_internal.ts +2 -2
- package/src/hooks/use-copilot-readable.ts +1 -1
- package/src/hooks/use-frontend-tool.ts +2 -2
- package/src/hooks/use-human-in-the-loop.ts +2 -2
- package/src/hooks/use-langgraph-interrupt.ts +2 -5
- package/src/hooks/use-lazy-tool-renderer.tsx +1 -1
- package/src/hooks/use-render-tool-call.ts +1 -1
- package/src/lib/copilot-task.ts +1 -1
- package/src/setupTests.ts +18 -14
- package/src/v2/__tests__/A2UIMessageRenderer.test.tsx +176 -0
- package/src/v2/__tests__/globalSetup.ts +14 -0
- package/src/v2/__tests__/setup.ts +93 -0
- package/src/v2/__tests__/utils/test-helpers.tsx +470 -0
- package/src/v2/a2ui/A2UIMessageRenderer.tsx +206 -0
- package/src/v2/components/CopilotKitInspector.tsx +50 -0
- package/src/v2/components/MCPAppsActivityRenderer.tsx +785 -0
- package/src/v2/components/WildcardToolCallRender.tsx +86 -0
- package/src/v2/components/__tests__/license-warning-banner.test.tsx +46 -0
- package/src/v2/components/chat/CopilotChat.tsx +431 -0
- package/src/v2/components/chat/CopilotChatAssistantMessage.tsx +375 -0
- package/src/v2/components/chat/CopilotChatAudioRecorder.tsx +350 -0
- package/src/v2/components/chat/CopilotChatInput.tsx +1302 -0
- package/src/v2/components/chat/CopilotChatMessageView.tsx +556 -0
- package/src/v2/components/chat/CopilotChatReasoningMessage.tsx +252 -0
- package/src/v2/components/chat/CopilotChatSuggestionPill.tsx +59 -0
- package/src/v2/components/chat/CopilotChatSuggestionView.tsx +133 -0
- package/src/v2/components/chat/CopilotChatToggleButton.tsx +171 -0
- package/src/v2/components/chat/CopilotChatToolCallsView.tsx +40 -0
- package/src/v2/components/chat/CopilotChatUserMessage.tsx +388 -0
- package/src/v2/components/chat/CopilotChatView.tsx +598 -0
- package/src/v2/components/chat/CopilotModalHeader.tsx +129 -0
- package/src/v2/components/chat/CopilotPopup.tsx +81 -0
- package/src/v2/components/chat/CopilotPopupView.tsx +317 -0
- package/src/v2/components/chat/CopilotSidebar.tsx +76 -0
- package/src/v2/components/chat/CopilotSidebarView.tsx +255 -0
- package/src/v2/components/chat/__tests__/CopilotChat.e2e.test.tsx +1113 -0
- package/src/v2/components/chat/__tests__/CopilotChat.onError.test.tsx +73 -0
- package/src/v2/components/chat/__tests__/CopilotChat.slots.e2e.test.tsx +432 -0
- package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.tsx +150 -0
- package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.slots.e2e.test.tsx +624 -0
- package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.test.tsx +702 -0
- package/src/v2/components/chat/__tests__/CopilotChatCssClasses.test.tsx +107 -0
- package/src/v2/components/chat/__tests__/CopilotChatInput.slots.e2e.test.tsx +929 -0
- package/src/v2/components/chat/__tests__/CopilotChatInput.test.tsx +986 -0
- package/src/v2/components/chat/__tests__/CopilotChatMessageView.slots.e2e.test.tsx +1004 -0
- package/src/v2/components/chat/__tests__/CopilotChatMessageView.test.tsx +169 -0
- package/src/v2/components/chat/__tests__/CopilotChatSuggestionView.slots.e2e.test.tsx +530 -0
- package/src/v2/components/chat/__tests__/CopilotChatToolRendering.e2e.test.tsx +782 -0
- package/src/v2/components/chat/__tests__/CopilotChatToolRerenders.e2e.test.tsx +2413 -0
- package/src/v2/components/chat/__tests__/CopilotChatUserMessage.slots.e2e.test.tsx +621 -0
- package/src/v2/components/chat/__tests__/CopilotChatView.onClick.e2e.test.tsx +853 -0
- package/src/v2/components/chat/__tests__/CopilotChatView.slots.e2e.test.tsx +1050 -0
- package/src/v2/components/chat/__tests__/CopilotModalHeader.slots.e2e.test.tsx +484 -0
- package/src/v2/components/chat/__tests__/CopilotPopupView.slots.e2e.test.tsx +612 -0
- package/src/v2/components/chat/__tests__/CopilotSidebarView.slots.e2e.test.tsx +502 -0
- package/src/v2/components/chat/__tests__/MCPAppsActivityRenderer.e2e.test.tsx +1011 -0
- package/src/v2/components/chat/__tests__/setup.ts +1 -0
- package/src/v2/components/chat/index.ts +79 -0
- package/src/v2/components/index.ts +7 -0
- package/src/v2/components/license-warning-banner.tsx +198 -0
- package/src/v2/components/ui/button.tsx +123 -0
- package/src/v2/components/ui/dropdown-menu.tsx +258 -0
- package/src/v2/components/ui/tooltip.tsx +60 -0
- package/src/v2/hooks/__tests__/standard-schema-types.test.tsx +152 -0
- package/src/v2/hooks/__tests__/standard-schema.test.tsx +282 -0
- package/src/v2/hooks/__tests__/use-agent-context-timing.e2e.test.tsx +132 -0
- package/src/v2/hooks/__tests__/use-agent-context.test.tsx +401 -0
- package/src/v2/hooks/__tests__/use-agent-error-state.test.tsx +44 -0
- package/src/v2/hooks/__tests__/use-agent-stability.test.tsx +205 -0
- package/src/v2/hooks/__tests__/use-agent.e2e.test.tsx +148 -0
- package/src/v2/hooks/__tests__/use-component.test.tsx +123 -0
- package/src/v2/hooks/__tests__/use-configure-suggestions.e2e.test.tsx +696 -0
- package/src/v2/hooks/__tests__/use-default-render-tool.test.tsx +153 -0
- package/src/v2/hooks/__tests__/use-frontend-tool-available.test.tsx +167 -0
- package/src/v2/hooks/__tests__/use-frontend-tool.e2e.test.tsx +2129 -0
- package/src/v2/hooks/__tests__/use-human-in-the-loop.e2e.test.tsx +1261 -0
- package/src/v2/hooks/__tests__/use-interrupt.test.tsx +397 -0
- package/src/v2/hooks/__tests__/use-katex-styles.test.tsx +56 -0
- package/src/v2/hooks/__tests__/use-keyboard-height.test.tsx +192 -0
- package/src/v2/hooks/__tests__/use-render-tool.test.tsx +259 -0
- package/src/v2/hooks/__tests__/use-suggestions.e2e.test.tsx +524 -0
- package/src/v2/hooks/__tests__/use-threads.test.tsx +433 -0
- package/src/v2/hooks/__tests__/zod-regression.test.tsx +311 -0
- package/src/v2/hooks/index.ts +18 -0
- package/src/v2/hooks/use-agent-context.tsx +45 -0
- package/src/v2/hooks/use-agent.tsx +155 -0
- package/src/v2/hooks/use-component.tsx +89 -0
- package/src/v2/hooks/use-configure-suggestions.tsx +187 -0
- package/src/v2/hooks/use-default-render-tool.tsx +254 -0
- package/src/v2/hooks/use-frontend-tool.tsx +43 -0
- package/src/v2/hooks/use-human-in-the-loop.tsx +81 -0
- package/src/v2/hooks/use-interrupt.tsx +305 -0
- package/src/v2/hooks/use-keyboard-height.tsx +67 -0
- package/src/v2/hooks/use-render-activity-message.tsx +73 -0
- package/src/v2/hooks/use-render-custom-messages.tsx +93 -0
- package/src/v2/hooks/use-render-tool-call.tsx +175 -0
- package/src/v2/hooks/use-render-tool.tsx +181 -0
- package/src/v2/hooks/use-suggestions.tsx +91 -0
- package/src/v2/hooks/use-threads.tsx +256 -0
- package/src/v2/hooks/useKatexStyles.ts +27 -0
- package/src/v2/index.css +1 -1
- package/src/v2/index.ts +18 -2
- package/src/v2/lib/__tests__/completePartialMarkdown.test.ts +495 -0
- package/src/v2/lib/__tests__/renderSlot.test.tsx +588 -0
- package/src/v2/lib/react-core.ts +156 -0
- package/src/v2/lib/slots.tsx +143 -0
- package/src/v2/lib/transcription-client.ts +184 -0
- package/src/v2/lib/utils.ts +8 -0
- package/src/v2/providers/CopilotChatConfigurationProvider.tsx +162 -0
- package/src/v2/providers/CopilotKitProvider.tsx +600 -0
- package/src/v2/providers/__tests__/CopilotChatConfigurationProvider.test.tsx +546 -0
- package/src/v2/providers/__tests__/CopilotKitProvider.license.test.tsx +101 -0
- package/src/v2/providers/__tests__/CopilotKitProvider.onError.test.tsx +69 -0
- package/src/v2/providers/__tests__/CopilotKitProvider.renderCustomMessages.e2e.test.tsx +881 -0
- package/src/v2/providers/__tests__/CopilotKitProvider.stability.test.tsx +740 -0
- package/src/v2/providers/__tests__/CopilotKitProvider.test.tsx +642 -0
- package/src/v2/providers/__tests__/CopilotKitProvider.wildcard.test.tsx +294 -0
- package/src/v2/providers/index.ts +14 -0
- package/src/v2/styles/globals.css +230 -0
- package/src/v2/types/__tests__/defineToolCallRenderer.test.tsx +525 -0
- package/src/v2/types/defineToolCallRenderer.ts +65 -0
- package/src/v2/types/frontend-tool.ts +8 -0
- package/src/v2/types/human-in-the-loop.ts +33 -0
- package/src/v2/types/index.ts +7 -0
- package/src/v2/types/interrupt.ts +15 -0
- package/src/v2/types/react-activity-message-renderer.ts +27 -0
- package/src/v2/types/react-custom-message-renderer.ts +17 -0
- package/src/v2/types/react-tool-call-renderer.ts +32 -0
- package/tsdown.config.ts +34 -10
- package/vitest.config.mjs +4 -3
- package/LICENSE +0 -21
- package/dist/copilotkit-BRPQ2sqS.d.cts +0 -670
- package/dist/copilotkit-BRPQ2sqS.d.cts.map +0 -1
- package/dist/copilotkit-C94ayZbs.cjs +0 -2161
- package/dist/copilotkit-C94ayZbs.cjs.map +0 -1
- package/dist/copilotkit-CwZMFmSK.d.mts +0 -670
- package/dist/copilotkit-CwZMFmSK.d.mts.map +0 -1
- package/dist/copilotkit-Yh_Ld_FX.mjs +0 -2031
- package/dist/copilotkit-Yh_Ld_FX.mjs.map +0 -1
- package/dist/v2/index.css.map +0 -1
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render, screen, fireEvent } from "@testing-library/react";
|
|
3
|
+
import { describe, it, expect, vi } from "vitest";
|
|
4
|
+
import { CopilotSidebarView } from "../CopilotSidebarView";
|
|
5
|
+
import { CopilotKitProvider } from "../../../providers/CopilotKitProvider";
|
|
6
|
+
import { CopilotChatConfigurationProvider } from "../../../providers/CopilotChatConfigurationProvider";
|
|
7
|
+
|
|
8
|
+
// Wrapper to provide required context
|
|
9
|
+
const TestWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => (
|
|
10
|
+
<CopilotKitProvider>
|
|
11
|
+
<CopilotChatConfigurationProvider threadId="test-thread">
|
|
12
|
+
{children}
|
|
13
|
+
</CopilotChatConfigurationProvider>
|
|
14
|
+
</CopilotKitProvider>
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
const sampleMessages = [
|
|
18
|
+
{ id: "1", role: "user" as const, content: "Hello" },
|
|
19
|
+
{ id: "2", role: "assistant" as const, content: "Hi there!" },
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
describe("CopilotSidebarView Slot System E2E Tests", () => {
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// 1. TAILWIND CLASS TESTS - HEADER SLOT (UNIQUE TO SIDEBAR)
|
|
25
|
+
// ============================================================================
|
|
26
|
+
describe("1. Tailwind Class Slot Override - Header Slot", () => {
|
|
27
|
+
describe("header slot", () => {
|
|
28
|
+
it("should apply tailwind class string to header", () => {
|
|
29
|
+
const { container } = render(
|
|
30
|
+
<TestWrapper>
|
|
31
|
+
<CopilotSidebarView
|
|
32
|
+
messages={sampleMessages}
|
|
33
|
+
header="bg-gradient-to-r from-blue-500 to-purple-500 text-white"
|
|
34
|
+
/>
|
|
35
|
+
</TestWrapper>,
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const header = container.querySelector(".bg-gradient-to-r");
|
|
39
|
+
if (header) {
|
|
40
|
+
expect(header.classList.contains("from-blue-500")).toBe(true);
|
|
41
|
+
expect(header.classList.contains("text-white")).toBe(true);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("should override default header border with custom styles", () => {
|
|
46
|
+
const { container } = render(
|
|
47
|
+
<TestWrapper>
|
|
48
|
+
<CopilotSidebarView
|
|
49
|
+
messages={sampleMessages}
|
|
50
|
+
header="border-b-2 border-blue-500"
|
|
51
|
+
/>
|
|
52
|
+
</TestWrapper>,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const header = container.querySelector(".border-b-2");
|
|
56
|
+
expect(header).toBeDefined();
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// ============================================================================
|
|
62
|
+
// 2. PROPERTY PASSING TESTS - HEADER SLOT
|
|
63
|
+
// ============================================================================
|
|
64
|
+
describe("2. Property Passing - Header Slot", () => {
|
|
65
|
+
describe("header slot", () => {
|
|
66
|
+
it("should pass custom props to header", () => {
|
|
67
|
+
const { container } = render(
|
|
68
|
+
<TestWrapper>
|
|
69
|
+
<CopilotSidebarView
|
|
70
|
+
messages={sampleMessages}
|
|
71
|
+
header={{ "data-testid": "custom-sidebar-header" }}
|
|
72
|
+
/>
|
|
73
|
+
</TestWrapper>,
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const header = screen.queryByTestId("custom-sidebar-header");
|
|
77
|
+
expect(header).toBeDefined();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("should pass title prop through to header", () => {
|
|
81
|
+
render(
|
|
82
|
+
<TestWrapper>
|
|
83
|
+
<CopilotSidebarView
|
|
84
|
+
messages={sampleMessages}
|
|
85
|
+
header={{ title: "My Sidebar Chat" }}
|
|
86
|
+
/>
|
|
87
|
+
</TestWrapper>,
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
// The title should be rendered in the header
|
|
91
|
+
expect(screen.queryByText("My Sidebar Chat")).toBeDefined();
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// ============================================================================
|
|
97
|
+
// 3. CUSTOM COMPONENT TESTS - HEADER SLOT
|
|
98
|
+
// ============================================================================
|
|
99
|
+
describe("3. Custom Component - Header Slot", () => {
|
|
100
|
+
it("should allow custom component for header", () => {
|
|
101
|
+
const CustomHeader: React.FC = () => (
|
|
102
|
+
<header
|
|
103
|
+
data-testid="custom-header-component"
|
|
104
|
+
className="custom-sidebar-header"
|
|
105
|
+
>
|
|
106
|
+
<span>Custom Sidebar Header</span>
|
|
107
|
+
<button>Custom Close</button>
|
|
108
|
+
</header>
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
render(
|
|
112
|
+
<TestWrapper>
|
|
113
|
+
<CopilotSidebarView
|
|
114
|
+
messages={sampleMessages}
|
|
115
|
+
header={CustomHeader as any}
|
|
116
|
+
/>
|
|
117
|
+
</TestWrapper>,
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const custom = screen.queryByTestId("custom-header-component");
|
|
121
|
+
expect(custom).toBeDefined();
|
|
122
|
+
expect(custom?.textContent).toContain("Custom Sidebar Header");
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("should allow passing header props for customization", () => {
|
|
126
|
+
const { container } = render(
|
|
127
|
+
<TestWrapper>
|
|
128
|
+
<CopilotSidebarView
|
|
129
|
+
messages={sampleMessages}
|
|
130
|
+
header={{
|
|
131
|
+
title: "Customized Header",
|
|
132
|
+
titleContent: "text-xl font-bold",
|
|
133
|
+
closeButton: "bg-red-500",
|
|
134
|
+
}}
|
|
135
|
+
/>
|
|
136
|
+
</TestWrapper>,
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
expect(screen.queryByText("Customized Header")).toBeDefined();
|
|
140
|
+
expect(container.querySelector(".text-xl")).toBeDefined();
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// ============================================================================
|
|
145
|
+
// 4. INHERITED COPILOTCHATVIEW SLOTS
|
|
146
|
+
// ============================================================================
|
|
147
|
+
describe("4. Inherited CopilotChatView Slots", () => {
|
|
148
|
+
describe("messageView slot (inherited)", () => {
|
|
149
|
+
it("should apply tailwind class string to inherited messageView", () => {
|
|
150
|
+
const { container } = render(
|
|
151
|
+
<TestWrapper>
|
|
152
|
+
<CopilotSidebarView
|
|
153
|
+
messages={sampleMessages}
|
|
154
|
+
messageView="bg-gray-50 rounded-lg"
|
|
155
|
+
/>
|
|
156
|
+
</TestWrapper>,
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
const messageView = container.querySelector(".bg-gray-50");
|
|
160
|
+
expect(messageView).toBeDefined();
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
describe("input slot (inherited)", () => {
|
|
165
|
+
it("should apply tailwind class string to inherited input", () => {
|
|
166
|
+
const { container } = render(
|
|
167
|
+
<TestWrapper>
|
|
168
|
+
<CopilotSidebarView
|
|
169
|
+
messages={sampleMessages}
|
|
170
|
+
input="border-2 border-blue-400"
|
|
171
|
+
/>
|
|
172
|
+
</TestWrapper>,
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
const input = container.querySelector(".border-blue-400");
|
|
176
|
+
expect(input).toBeDefined();
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
describe("scrollView slot (inherited)", () => {
|
|
181
|
+
it("should apply tailwind class string to inherited scrollView", () => {
|
|
182
|
+
const { container } = render(
|
|
183
|
+
<TestWrapper>
|
|
184
|
+
<CopilotSidebarView
|
|
185
|
+
messages={sampleMessages}
|
|
186
|
+
scrollView="overflow-y-scroll bg-white"
|
|
187
|
+
/>
|
|
188
|
+
</TestWrapper>,
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
const scrollView = container.querySelector(".overflow-y-scroll");
|
|
192
|
+
expect(scrollView).toBeDefined();
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
describe("suggestionView slot (inherited)", () => {
|
|
197
|
+
it("should apply tailwind class string to inherited suggestionView", () => {
|
|
198
|
+
const suggestions = [
|
|
199
|
+
{ title: "Test", message: "Test message", isLoading: false },
|
|
200
|
+
];
|
|
201
|
+
|
|
202
|
+
const { container } = render(
|
|
203
|
+
<TestWrapper>
|
|
204
|
+
<CopilotSidebarView
|
|
205
|
+
messages={sampleMessages}
|
|
206
|
+
suggestions={suggestions}
|
|
207
|
+
suggestionView="gap-4 p-2"
|
|
208
|
+
/>
|
|
209
|
+
</TestWrapper>,
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
const suggestionView = container.querySelector(".gap-4");
|
|
213
|
+
if (suggestionView) {
|
|
214
|
+
expect(suggestionView.classList.contains("p-2")).toBe(true);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// ============================================================================
|
|
221
|
+
// 5. DRILL-DOWN INTO HEADER SUB-SLOTS
|
|
222
|
+
// ============================================================================
|
|
223
|
+
describe("5. Drill-down into Header Sub-slots", () => {
|
|
224
|
+
it("should allow customizing header titleContent through props object", () => {
|
|
225
|
+
const { container } = render(
|
|
226
|
+
<TestWrapper>
|
|
227
|
+
<CopilotSidebarView
|
|
228
|
+
messages={sampleMessages}
|
|
229
|
+
header={{
|
|
230
|
+
title: "Sidebar Chat",
|
|
231
|
+
titleContent: "text-2xl text-purple-600 font-extrabold",
|
|
232
|
+
}}
|
|
233
|
+
/>
|
|
234
|
+
</TestWrapper>,
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
const titleContent = container.querySelector(".text-2xl");
|
|
238
|
+
expect(titleContent).toBeDefined();
|
|
239
|
+
expect(titleContent?.classList.contains("text-purple-600")).toBe(true);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it("should allow customizing header closeButton through props object", () => {
|
|
243
|
+
const { container } = render(
|
|
244
|
+
<TestWrapper>
|
|
245
|
+
<CopilotSidebarView
|
|
246
|
+
messages={sampleMessages}
|
|
247
|
+
header={{
|
|
248
|
+
title: "Sidebar",
|
|
249
|
+
closeButton: "custom-close-btn",
|
|
250
|
+
}}
|
|
251
|
+
/>
|
|
252
|
+
</TestWrapper>,
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
const closeBtn = container.querySelector(".custom-close-btn");
|
|
256
|
+
expect(closeBtn).toBeDefined();
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it("should allow custom component for header via component slot", () => {
|
|
260
|
+
const CustomHeader: React.FC = () => (
|
|
261
|
+
<header data-testid="full-custom-header">
|
|
262
|
+
<span>Custom Header</span>
|
|
263
|
+
<button data-testid="sidebar-custom-close">← Back</button>
|
|
264
|
+
</header>
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
render(
|
|
268
|
+
<TestWrapper>
|
|
269
|
+
<CopilotSidebarView
|
|
270
|
+
messages={sampleMessages}
|
|
271
|
+
header={CustomHeader as any}
|
|
272
|
+
/>
|
|
273
|
+
</TestWrapper>,
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
const customClose = screen.queryByTestId("sidebar-custom-close");
|
|
277
|
+
expect(customClose).toBeDefined();
|
|
278
|
+
expect(customClose?.textContent).toBe("← Back");
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// ============================================================================
|
|
283
|
+
// 6. CLASSNAME AND MIXED CUSTOMIZATION
|
|
284
|
+
// ============================================================================
|
|
285
|
+
describe("6. className Override and Mixed Customization", () => {
|
|
286
|
+
it("should merge multiple slot classNames correctly", () => {
|
|
287
|
+
const { container } = render(
|
|
288
|
+
<TestWrapper>
|
|
289
|
+
<CopilotSidebarView
|
|
290
|
+
messages={sampleMessages}
|
|
291
|
+
header="header-style"
|
|
292
|
+
messageView="message-style"
|
|
293
|
+
input="input-style"
|
|
294
|
+
/>
|
|
295
|
+
</TestWrapper>,
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
expect(container.querySelector(".header-style")).toBeDefined();
|
|
299
|
+
expect(container.querySelector(".message-style")).toBeDefined();
|
|
300
|
+
expect(container.querySelector(".input-style")).toBeDefined();
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it("should work with property objects and class strings mixed", () => {
|
|
304
|
+
const onClick = vi.fn();
|
|
305
|
+
const { container } = render(
|
|
306
|
+
<TestWrapper>
|
|
307
|
+
<CopilotSidebarView
|
|
308
|
+
messages={sampleMessages}
|
|
309
|
+
header={{ onClick, className: "clickable-header" }}
|
|
310
|
+
input="styled-input"
|
|
311
|
+
/>
|
|
312
|
+
</TestWrapper>,
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
expect(container.querySelector(".styled-input")).toBeDefined();
|
|
316
|
+
|
|
317
|
+
const header = container.querySelector(".clickable-header");
|
|
318
|
+
if (header) {
|
|
319
|
+
fireEvent.click(header);
|
|
320
|
+
expect(onClick).toHaveBeenCalled();
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
it("should support custom width prop", () => {
|
|
325
|
+
const { container } = render(
|
|
326
|
+
<TestWrapper>
|
|
327
|
+
<CopilotSidebarView messages={sampleMessages} width={600} />
|
|
328
|
+
</TestWrapper>,
|
|
329
|
+
);
|
|
330
|
+
|
|
331
|
+
const sidebar = container.querySelector("[data-copilot-sidebar]");
|
|
332
|
+
expect(sidebar).toBeDefined();
|
|
333
|
+
// Width should be applied via CSS custom property
|
|
334
|
+
expect(sidebar?.getAttribute("style")).toContain("--sidebar-width");
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
it("should support string width prop", () => {
|
|
338
|
+
const { container } = render(
|
|
339
|
+
<TestWrapper>
|
|
340
|
+
<CopilotSidebarView messages={sampleMessages} width="50vw" />
|
|
341
|
+
</TestWrapper>,
|
|
342
|
+
);
|
|
343
|
+
|
|
344
|
+
const sidebar = container.querySelector("[data-copilot-sidebar]");
|
|
345
|
+
expect(sidebar).toBeDefined();
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
// ============================================================================
|
|
350
|
+
// 7. INTEGRATION TESTS
|
|
351
|
+
// ============================================================================
|
|
352
|
+
describe("7. Integration Tests", () => {
|
|
353
|
+
it("should render sidebar with all default components", () => {
|
|
354
|
+
const { container } = render(
|
|
355
|
+
<TestWrapper>
|
|
356
|
+
<CopilotSidebarView messages={sampleMessages} />
|
|
357
|
+
</TestWrapper>,
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
const sidebar = container.querySelector("[data-copilot-sidebar]");
|
|
361
|
+
expect(sidebar).toBeDefined();
|
|
362
|
+
// Should have header
|
|
363
|
+
expect(
|
|
364
|
+
container.querySelector('[data-slot="copilot-modal-header"]'),
|
|
365
|
+
).toBeDefined();
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
it("should render messages in sidebar", () => {
|
|
369
|
+
render(
|
|
370
|
+
<TestWrapper>
|
|
371
|
+
<CopilotSidebarView messages={sampleMessages} />
|
|
372
|
+
</TestWrapper>,
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
expect(screen.queryByText("Hello")).toBeDefined();
|
|
376
|
+
expect(screen.queryByText("Hi there!")).toBeDefined();
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
it("should handle empty messages array", () => {
|
|
380
|
+
const { container } = render(
|
|
381
|
+
<TestWrapper>
|
|
382
|
+
<CopilotSidebarView messages={[]} />
|
|
383
|
+
</TestWrapper>,
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
const sidebar = container.querySelector("[data-copilot-sidebar]");
|
|
387
|
+
expect(sidebar).toBeDefined();
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
it("should combine header customization with inherited slot customization", () => {
|
|
391
|
+
const { container } = render(
|
|
392
|
+
<TestWrapper>
|
|
393
|
+
<CopilotSidebarView
|
|
394
|
+
messages={sampleMessages}
|
|
395
|
+
header={{
|
|
396
|
+
title: "Full Custom",
|
|
397
|
+
className: "custom-header-root",
|
|
398
|
+
titleContent: "custom-title",
|
|
399
|
+
}}
|
|
400
|
+
messageView="custom-message"
|
|
401
|
+
input="custom-input"
|
|
402
|
+
scrollView="custom-scroll"
|
|
403
|
+
/>
|
|
404
|
+
</TestWrapper>,
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
expect(container.querySelector(".custom-header-root")).toBeDefined();
|
|
408
|
+
expect(container.querySelector(".custom-title")).toBeDefined();
|
|
409
|
+
expect(container.querySelector(".custom-message")).toBeDefined();
|
|
410
|
+
expect(container.querySelector(".custom-input")).toBeDefined();
|
|
411
|
+
expect(container.querySelector(".custom-scroll")).toBeDefined();
|
|
412
|
+
});
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
// ============================================================================
|
|
416
|
+
// 8. TOGGLE BUTTON SLOT TESTS
|
|
417
|
+
// ============================================================================
|
|
418
|
+
describe("8. Toggle Button Slot", () => {
|
|
419
|
+
describe("toggleButton slot - Tailwind class string", () => {
|
|
420
|
+
it("should apply tailwind class string to toggle button", () => {
|
|
421
|
+
const { container } = render(
|
|
422
|
+
<TestWrapper>
|
|
423
|
+
<CopilotSidebarView
|
|
424
|
+
messages={sampleMessages}
|
|
425
|
+
toggleButton="bg-red-500 hover:bg-red-600"
|
|
426
|
+
/>
|
|
427
|
+
</TestWrapper>,
|
|
428
|
+
);
|
|
429
|
+
|
|
430
|
+
const toggleButton = container.querySelector(".bg-red-500");
|
|
431
|
+
expect(toggleButton).toBeDefined();
|
|
432
|
+
expect(toggleButton?.classList.contains("hover:bg-red-600")).toBe(true);
|
|
433
|
+
});
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
describe("toggleButton slot - Props object", () => {
|
|
437
|
+
it("should pass custom props to toggle button", () => {
|
|
438
|
+
const { container } = render(
|
|
439
|
+
<TestWrapper>
|
|
440
|
+
<CopilotSidebarView
|
|
441
|
+
messages={sampleMessages}
|
|
442
|
+
toggleButton={{ "data-testid": "custom-toggle-button" }}
|
|
443
|
+
/>
|
|
444
|
+
</TestWrapper>,
|
|
445
|
+
);
|
|
446
|
+
|
|
447
|
+
const toggleButton = screen.queryByTestId("custom-toggle-button");
|
|
448
|
+
expect(toggleButton).toBeDefined();
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
it("should pass openIcon and closeIcon sub-slot props", () => {
|
|
452
|
+
const { container } = render(
|
|
453
|
+
<TestWrapper>
|
|
454
|
+
<CopilotSidebarView
|
|
455
|
+
messages={sampleMessages}
|
|
456
|
+
toggleButton={{
|
|
457
|
+
openIcon: "text-green-500",
|
|
458
|
+
closeIcon: "text-red-500",
|
|
459
|
+
}}
|
|
460
|
+
/>
|
|
461
|
+
</TestWrapper>,
|
|
462
|
+
);
|
|
463
|
+
|
|
464
|
+
// The icons should have custom classes applied
|
|
465
|
+
const openIconSlot = container.querySelector(
|
|
466
|
+
'[data-slot="chat-toggle-button-open-icon"]',
|
|
467
|
+
);
|
|
468
|
+
const closeIconSlot = container.querySelector(
|
|
469
|
+
'[data-slot="chat-toggle-button-close-icon"]',
|
|
470
|
+
);
|
|
471
|
+
expect(openIconSlot).toBeDefined();
|
|
472
|
+
expect(closeIconSlot).toBeDefined();
|
|
473
|
+
});
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
describe("toggleButton slot - Custom component", () => {
|
|
477
|
+
it("should allow custom component for toggle button", () => {
|
|
478
|
+
const CustomToggleButton: React.FC = () => (
|
|
479
|
+
<button
|
|
480
|
+
data-testid="custom-toggle-component"
|
|
481
|
+
className="custom-toggle"
|
|
482
|
+
>
|
|
483
|
+
Toggle Chat
|
|
484
|
+
</button>
|
|
485
|
+
);
|
|
486
|
+
|
|
487
|
+
render(
|
|
488
|
+
<TestWrapper>
|
|
489
|
+
<CopilotSidebarView
|
|
490
|
+
messages={sampleMessages}
|
|
491
|
+
toggleButton={CustomToggleButton as any}
|
|
492
|
+
/>
|
|
493
|
+
</TestWrapper>,
|
|
494
|
+
);
|
|
495
|
+
|
|
496
|
+
const custom = screen.queryByTestId("custom-toggle-component");
|
|
497
|
+
expect(custom).toBeDefined();
|
|
498
|
+
expect(custom?.textContent).toBe("Toggle Chat");
|
|
499
|
+
});
|
|
500
|
+
});
|
|
501
|
+
});
|
|
502
|
+
});
|