forked from CopilotKit/CopilotKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcopilot-chat-input.component.spec.ts
More file actions
120 lines (95 loc) · 3.76 KB
/
Copy pathcopilot-chat-input.component.spec.ts
File metadata and controls
120 lines (95 loc) · 3.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import {
EnvironmentInjector,
Injectable,
runInInjectionContext,
signal,
} from "@angular/core";
import { TestBed } from "@angular/core/testing";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { CopilotChatInput } from "../copilot-chat-input";
import { ChatState } from "../../../chat-state";
@Injectable()
class ChatStateStub extends ChatState {
inputValue = signal("");
override readonly attachmentsEnabled = signal(false);
override readonly attachmentsUploading = signal(false);
submitInput = vi.fn((value: string) => this.inputValue.set(value));
changeInput = vi.fn((value: string) => this.inputValue.set(value));
addFile = vi.fn();
}
describe("CopilotChatInput", () => {
let injector: EnvironmentInjector;
let component: CopilotChatInput;
let chatState: ChatStateStub;
beforeEach(() => {
TestBed.resetTestingModule();
TestBed.configureTestingModule({
providers: [{ provide: ChatState, useClass: ChatStateStub }],
});
injector = TestBed.inject(EnvironmentInjector);
chatState = TestBed.inject(ChatState) as ChatStateStub;
component = runInInjectionContext(injector, () => new CopilotChatInput());
const textAreaMock = {
setValue: vi.fn(),
focus: vi.fn(),
};
const audioRecorderMock = {
start: vi.fn().mockResolvedValue(undefined),
stop: vi.fn().mockResolvedValue(undefined),
getState: () => "idle",
};
(component as any).textAreaRef = () => textAreaMock;
(component as any).audioRecorderRef = () => audioRecorderMock;
});
it("switches between input and transcribe modes", () => {
expect(component.computedMode()).toBe("input");
component.handleStartTranscribe();
expect(component.computedMode()).toBe("transcribe");
component.handleCancelTranscribe();
expect(component.computedMode()).toBe("input");
});
it("emits value changes and updates chat state", () => {
const valueSpy = vi.fn();
component.valueChange.subscribe(valueSpy);
component.handleValueChange("Hello world");
expect(valueSpy).toHaveBeenCalledWith("Hello world");
expect(chatState.changeInput).toHaveBeenCalledWith("Hello world");
});
it("submits trimmed messages and clears input", () => {
const submitSpy = vi.fn();
component.submitMessage.subscribe(submitSpy);
component.handleValueChange(" Do it ");
component.send();
expect(submitSpy).toHaveBeenCalledWith("Do it");
expect(chatState.submitInput).toHaveBeenCalledWith("Do it");
expect(chatState.changeInput).toHaveBeenLastCalledWith("");
expect(component.textAreaRef()?.setValue).toHaveBeenCalledWith("");
});
it("disables send while attachments are uploading", () => {
component.handleValueChange("Do it");
chatState.attachmentsUploading.set(true);
expect(component.sendButtonDisabled()).toBe(true);
component.send();
expect(chatState.submitInput).not.toHaveBeenCalled();
expect(component.textAreaRef()?.setValue).not.toHaveBeenCalled();
});
it("only opens the file picker when attachments are enabled", () => {
const addFileSpy = vi.fn();
component.addFile.subscribe(addFileSpy);
expect(component.addFileButtonDisabled()).toBe(true);
component.handleAddFile();
expect(addFileSpy).not.toHaveBeenCalled();
expect(chatState.addFile).not.toHaveBeenCalled();
chatState.attachmentsEnabled.set(true);
expect(component.addFileButtonDisabled()).toBe(false);
component.handleAddFile();
expect(addFileSpy).toHaveBeenCalledOnce();
expect(chatState.addFile).toHaveBeenCalledOnce();
});
it("exposes tools menu through computed signal", () => {
(component as any).toolsMenu = () => [
{ label: "Example", onSelect: vi.fn() },
];
expect(component.computedToolsMenu()).toHaveLength(1);
});
});