blob: 8c1a47a63c85c5a4c94c2837e502c07faa9aa2e0 [file] [log] [blame]
philip.zeyliger26bc6592025-06-30 20:15:30 -07001/* eslint-disable @typescript-eslint/no-explicit-any */
Sean McCulloughb29f8912025-04-20 15:39:11 -07002import { test, expect } from "@sand4rt/experimental-ct-web";
Sean McCullough86b56862025-04-18 13:04:03 -07003import { SketchChatInput } from "./sketch-chat-input";
4
Sean McCulloughb29f8912025-04-20 15:39:11 -07005test("initializes with empty content by default", async ({ mount }) => {
6 const component = await mount(SketchChatInput, {});
7
8 // Check public property via component's evaluate method
9 const content = await component.evaluate((el: SketchChatInput) => el.content);
10 expect(content).toBe("");
11
12 // Check textarea value
13 await expect(component.locator("#chatInput")).toHaveValue("");
14});
15
16test("initializes with provided content", async ({ mount }) => {
17 const testContent = "Hello, world!";
18 const component = await mount(SketchChatInput, {
19 props: {
20 content: testContent,
21 },
Sean McCullough86b56862025-04-18 13:04:03 -070022 });
23
Sean McCulloughb29f8912025-04-20 15:39:11 -070024 // Check public property via component's evaluate method
25 const content = await component.evaluate((el: SketchChatInput) => el.content);
26 expect(content).toBe(testContent);
Sean McCullough86b56862025-04-18 13:04:03 -070027
Sean McCulloughb29f8912025-04-20 15:39:11 -070028 // Check textarea value
29 await expect(component.locator("#chatInput")).toHaveValue(testContent);
30});
31
32test("updates content when typing in the textarea", async ({ mount }) => {
33 const component = await mount(SketchChatInput, {});
34 const newValue = "New message";
35
36 // Fill the textarea with new content
37 await component.locator("#chatInput").fill(newValue);
38
39 // Check that the content property was updated
40 const content = await component.evaluate((el: SketchChatInput) => el.content);
41 expect(content).toBe(newValue);
42});
43
44test("sends message when clicking the send button", async ({ mount }) => {
45 const testContent = "Test message";
46 const component = await mount(SketchChatInput, {
47 props: {
48 content: testContent,
49 },
Sean McCullough86b56862025-04-18 13:04:03 -070050 });
51
Sean McCulloughb29f8912025-04-20 15:39:11 -070052 // Set up promise to wait for the event
53 const eventPromise = component.evaluate((el) => {
54 return new Promise((resolve) => {
55 el.addEventListener(
56 "send-chat",
57 (event) => {
58 resolve((event as CustomEvent).detail);
59 },
Philip Zeyliger72682df2025-04-23 13:09:46 -070060 { once: true },
Sean McCulloughb29f8912025-04-20 15:39:11 -070061 );
Sean McCullough86b56862025-04-18 13:04:03 -070062 });
Sean McCullough86b56862025-04-18 13:04:03 -070063 });
64
Sean McCulloughb29f8912025-04-20 15:39:11 -070065 // Click the send button
66 await component.locator("#sendChatButton").click();
Sean McCullough86b56862025-04-18 13:04:03 -070067
Sean McCulloughb29f8912025-04-20 15:39:11 -070068 // Wait for the event and check its details
69 const detail: any = await eventPromise;
70 expect(detail.message).toBe(testContent);
Sean McCulloughb29f8912025-04-20 15:39:11 -070071});
72
73test.skip("sends message when pressing Enter (without shift)", async ({
74 mount,
75}) => {
76 const testContent = "Test message";
77 const component = await mount(SketchChatInput, {
78 props: {
79 content: testContent,
80 },
81 });
82
83 // Set up promise to wait for the event
84 const eventPromise = component.evaluate((el) => {
85 return new Promise((resolve) => {
86 el.addEventListener(
87 "send-chat",
88 (event) => {
89 resolve((event as CustomEvent).detail);
90 },
Philip Zeyliger72682df2025-04-23 13:09:46 -070091 { once: true },
Sean McCulloughb29f8912025-04-20 15:39:11 -070092 );
93 });
94 });
95
96 // Press Enter in the textarea
97 await component.locator("#chatInput").press("Enter");
98
99 // Wait for the event and check its details
100 const detail: any = await eventPromise;
101 expect(detail.message).toBe(testContent);
102
103 // Check that content was cleared
104 const content = await component.evaluate((el: SketchChatInput) => el.content);
105 expect(content).toBe("");
106});
107
108test.skip("does not send message when pressing Shift+Enter", async ({
109 mount,
110}) => {
111 const testContent = "Test message";
112 const component = await mount(SketchChatInput, {
113 props: {
114 content: testContent,
115 },
116 });
117
118 // Set up to track if event fires
119 let eventFired = false;
120 await component.evaluate((el) => {
Sean McCullough86b56862025-04-18 13:04:03 -0700121 el.addEventListener("send-chat", () => {
Sean McCulloughb29f8912025-04-20 15:39:11 -0700122 (window as any).__eventFired = true;
Sean McCullough86b56862025-04-18 13:04:03 -0700123 });
Sean McCulloughb29f8912025-04-20 15:39:11 -0700124 (window as any).__eventFired = false;
Sean McCullough86b56862025-04-18 13:04:03 -0700125 });
126
Sean McCulloughb29f8912025-04-20 15:39:11 -0700127 // Press Shift+Enter in the textarea
128 await component.locator("#chatInput").press("Shift+Enter");
Sean McCullough86b56862025-04-18 13:04:03 -0700129
Sean McCulloughb29f8912025-04-20 15:39:11 -0700130 // Wait a short time and check if event fired
131 await new Promise((resolve) => setTimeout(resolve, 50));
132 eventFired = await component.evaluate(() => (window as any).__eventFired);
133 expect(eventFired).toBe(false);
Sean McCullough71941bd2025-04-18 13:31:48 -0700134
Sean McCulloughb29f8912025-04-20 15:39:11 -0700135 // Check that content was not cleared
136 const content = await component.evaluate((el: SketchChatInput) => el.content);
137 expect(content).toBe(testContent);
138});
139
Sean McCullough5164eee2025-04-21 18:20:23 -0700140test("resizes when user enters more text than will fit", async ({ mount }) => {
Sean McCullough07b3e392025-04-21 22:51:14 +0000141 const testContent = "Test message\n\n\n\n\n\n\n\n\n\n\n\n\nends here.";
142 const component = await mount(SketchChatInput, {
143 props: {
Sean McCullough5164eee2025-04-21 18:20:23 -0700144 content: "",
Sean McCullough07b3e392025-04-21 22:51:14 +0000145 },
146 });
Sean McCullough5164eee2025-04-21 18:20:23 -0700147 const origHeight = await component.evaluate(
Philip Zeyliger72682df2025-04-23 13:09:46 -0700148 (el: SketchChatInput) => el.chatInput.style.height,
Sean McCullough5164eee2025-04-21 18:20:23 -0700149 );
Sean McCullough07b3e392025-04-21 22:51:14 +0000150
151 // Enter very tall text in the textarea
152 await component.locator("#chatInput").fill(testContent);
153
Philip Zeyliger10a7ac12025-04-23 11:56:03 -0700154 // Wait for the requestAnimationFrame to complete
155 await component.evaluate(() => new Promise(requestAnimationFrame));
156
Sean McCullough07b3e392025-04-21 22:51:14 +0000157 // Check that textarea resized
Sean McCullough5164eee2025-04-21 18:20:23 -0700158 const newHeight = await component.evaluate(
Philip Zeyliger72682df2025-04-23 13:09:46 -0700159 (el: SketchChatInput) => el.chatInput.style.height,
Sean McCullough5164eee2025-04-21 18:20:23 -0700160 );
161 expect(Number.parseInt(newHeight)).toBeGreaterThan(
Philip Zeyliger72682df2025-04-23 13:09:46 -0700162 Number.parseInt(origHeight),
Sean McCullough5164eee2025-04-21 18:20:23 -0700163 );
Sean McCullough07b3e392025-04-21 22:51:14 +0000164});
Pokey Rule339b56e2025-05-15 14:48:07 +0000165
166test("shows drop overlay when file is dragged over", async ({ mount }) => {
167 const component = await mount(SketchChatInput, {});
168
169 // Simulate dragenter event
170 await component.evaluate((el: SketchChatInput) => {
Sean McCulloughb3795922025-06-27 01:59:41 +0000171 const container = el.querySelector(".chat-container");
Pokey Rule339b56e2025-05-15 14:48:07 +0000172 if (container) {
173 const event = new DragEvent("dragenter", { bubbles: true });
174 container.dispatchEvent(event);
175 }
176 });
177
178 // Check that the isDraggingOver state is true
179 const isDraggingOver = await component.evaluate(
180 (el: SketchChatInput) => el.isDraggingOver,
181 );
182 expect(isDraggingOver).toBe(true);
183
184 // Check that the drop zone overlay is visible
185 const overlay = await component.evaluate(
Sean McCulloughb3795922025-06-27 01:59:41 +0000186 (el: SketchChatInput) => el.querySelector(".drop-zone-overlay") !== null,
Pokey Rule339b56e2025-05-15 14:48:07 +0000187 );
188 expect(overlay).toBe(true);
189});
190
191test("hides drop overlay when drag leaves", async ({ mount }) => {
192 const component = await mount(SketchChatInput, {});
193
194 // First set isDraggingOver to true
195 await component.evaluate((el: SketchChatInput) => {
196 el.isDraggingOver = true;
197 });
198
199 // Simulate dragleave event
200 await component.evaluate((el: SketchChatInput) => {
Sean McCulloughb3795922025-06-27 01:59:41 +0000201 const container = el.querySelector(".chat-container");
Pokey Rule339b56e2025-05-15 14:48:07 +0000202 if (container) {
203 const event = new DragEvent("dragleave", { bubbles: true });
204 Object.defineProperty(event, "target", { value: container });
205 container.dispatchEvent(event);
206 }
207 });
208
209 // Check that the isDraggingOver state is false
210 const isDraggingOver = await component.evaluate(
211 (el: SketchChatInput) => el.isDraggingOver,
212 );
213 expect(isDraggingOver).toBe(false);
214});
215
216// Note: Testing actual file drop and upload would require mocking the fetch API
217// This is a simple test that the drop event handler exists
218test("has a drop event handler", async ({ mount }) => {
219 const component = await mount(SketchChatInput, {});
220
221 // Check that the component has the _handleDrop method
222 const hasDropHandler = await component.evaluate(
223 (el: SketchChatInput) => typeof (el as any)._handleDrop === "function",
224 );
225 expect(hasDropHandler).toBe(true);
226});