Skip to content

Commit

Permalink
refactor: clean up chat form test, replace to be depricated useEffect…
Browse files Browse the repository at this point in the history
…Once hook, combine command completions and preview to one event from chat
  • Loading branch information
MarcMcIntosh committed Feb 19, 2024
1 parent 7b1480b commit 647073e
Show file tree
Hide file tree
Showing 13 changed files with 68 additions and 135 deletions.
8 changes: 0 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,14 +175,6 @@ interface RequestAtCommandPreview extends ActionFromChat {
payload: { id: string; query: string; cursor: number };
}

/**
* This message is sent from the host to the chat contains the result of command preview request.
*/
interface ReceiveAtCommandPreview extends ActionToChat {
type: EVENT_NAMES_TO_CHAT.RECEIVE_AT_COMMAND_PREVIEW; // = "chat_receive_at_command_preview"
payload: { id: string; preview: ChatContextFileMessage[] };
}

/**
* This message is sent from the chat component to the host when the response to the question is received.
*/
Expand Down
107 changes: 41 additions & 66 deletions src/components/ChatForm/CharForm.test.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,50 @@
import { render } from "../../utils/test-utils";
import { describe, expect, test, vi } from "vitest";
import { ChatForm } from "./ChatForm";
import { ChatForm, ChatFormProps } from "./ChatForm";
import React from "react";

const noop = () => ({});

const App: React.FC<Partial<ChatFormProps>> = (props) => {
const defaultProps: ChatFormProps = {
removePreviewFileByName: noop,
selectedSnippet: { code: "", language: "" },
onSubmit: noop,
isStreaming: false,
onStopStreaming: noop,
onSetChatModel: noop,
model: "gpt-3.5-turbo",
caps: { fetching: false, default_cap: "foo", available_caps: [] },
error: "",
clearError: noop,
canChangeModel: false,
handleContextFile: noop,
hasContextFile: false,
commands: {
available_commands: [],
selected_command: "",
arguments: [],
is_cmd_executable: false,
},
requestCommandsCompletion: noop,
attachFile: {
name: "",
can_paste: false,
attach: false,
},
setSelectedCommand: noop,
filesInPreview: [],
...props,
};

return <ChatForm {...defaultProps} />;
};

describe("ChatForm", () => {
test("when I push enter it should call onSubmit", async () => {
const fakeOnSubmit = vi.fn();

const { user, ...app } = render(
<ChatForm
removePreviewFileByName={() => ({})}
selectedSnippet={{ code: "", language: "" }}
onSubmit={fakeOnSubmit}
isStreaming={false}
onStopStreaming={vi.fn}
onSetChatModel={vi.fn}
model="gpt-3.5-turbo"
caps={{ fetching: false, default_cap: "foo", available_caps: [] }}
error=""
clearError={vi.fn}
canChangeModel={false}
handleContextFile={vi.fn}
hasContextFile={false}
commands={{
available_commands: [],
selected_command: "",
arguments: [],
is_cmd_executable: false,
}}
requestCommandsCompletion={() => ({})}
attachFile={{
name: "",
can_paste: false,
attach: false,
}}
setSelectedCommand={() => ({})}
executeCommand={() => ({})}
filesInPreview={[]}
// setSelectedCommand={() => ({})}
/>,
);
const { user, ...app } = render(<App onSubmit={fakeOnSubmit} />);

const textarea: HTMLTextAreaElement | null =
app.container.querySelector("textarea");
Expand All @@ -54,38 +60,7 @@ describe("ChatForm", () => {
test("when I hole shift and push enter it should not call onSubmit", async () => {
const fakeOnSubmit = vi.fn();

const { user, ...app } = render(
<ChatForm
removePreviewFileByName={() => ({})}
selectedSnippet={{ code: "", language: "" }}
onSubmit={fakeOnSubmit}
isStreaming={false}
onStopStreaming={vi.fn}
onSetChatModel={vi.fn}
model="gpt-3.5-turbo"
caps={{ fetching: false, default_cap: "foo", available_caps: [] }}
error=""
clearError={vi.fn}
canChangeModel={false}
handleContextFile={vi.fn}
hasContextFile={false}
commands={{
available_commands: [],
selected_command: "",
arguments: [],
is_cmd_executable: false,
}}
requestCommandsCompletion={() => ({})}
attachFile={{
name: "",
can_paste: false,
attach: false,
}}
setSelectedCommand={() => ({})}
executeCommand={() => ({})}
filesInPreview={[]}
/>,
);
const { user, ...app } = render(<App onSubmit={fakeOnSubmit} />);
const textarea = app.container.querySelector("textarea");
expect(textarea).not.toBeNull();
if (textarea) {
Expand Down
1 change: 0 additions & 1 deletion src/components/ChatForm/ChatForm.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ const meta = {
selectedSnippet: { code: "", language: "" },
removePreviewFileByName: () => ({}),
requestCommandsCompletion: () => ({}),
executeCommand: () => ({}),
setSelectedCommand: () => ({}),
},
} satisfies Meta<typeof ChatForm>;
Expand Down
10 changes: 4 additions & 6 deletions src/components/ChatForm/ChatForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const CapsSelect: React.FC<{
);
};

export const ChatForm: React.FC<{
export type ChatFormProps = {
onSubmit: (str: string) => void;
onClose?: () => void;
className?: string;
Expand All @@ -63,11 +63,12 @@ export const ChatForm: React.FC<{
number?: number,
) => void;
setSelectedCommand: (command: string) => void;
executeCommand: (command: string, cursor: number) => void;
filesInPreview: ChatContextFile[];
selectedSnippet: ChatState["selected_snippet"];
removePreviewFileByName: ComboBoxProps["removePreviewFileByName"];
}> = ({
};

export const ChatForm: React.FC<ChatFormProps> = ({
onSubmit,
onClose,
className,
Expand All @@ -85,12 +86,10 @@ export const ChatForm: React.FC<{
attachFile,
requestCommandsCompletion,
setSelectedCommand,
executeCommand,
filesInPreview,
selectedSnippet,
removePreviewFileByName,
}) => {
//TODO: handle attached snippet, when code is highlighted and chat is opened
const [value, setValue] = React.useState("");
const [snippetAdded, setSnippetAdded] = React.useState(false);

Expand Down Expand Up @@ -185,7 +184,6 @@ export const ChatForm: React.FC<{
commands.available_commands.length > 0 ? "Type @ for commands" : ""
}
render={(props) => <TextArea disabled={isStreaming} {...props} />}
executeCommand={executeCommand}
selectedCommand={commands.selected_command}
setSelectedCommand={setSelectedCommand}
removePreviewFileByName={removePreviewFileByName}
Expand Down
1 change: 0 additions & 1 deletion src/components/ComboBox/ComboBox.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ const App: React.FC<ComboBoxProps> = (props) => {
onChange={setValue}
selectedCommand={selectedCommand}
setSelectedCommand={setSelectedCommand}
executeCommand={() => ({})}
/>
</Card>
);
Expand Down
17 changes: 12 additions & 5 deletions src/components/ComboBox/ComboBox.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ const App = (props: Partial<ComboBoxProps>) => {
onSubmit: onSubmitSpy,
placeholder: "Type @ for commands",
render: (props: TextAreaProps) => <TextArea {...props} />,
executeCommand: () => ({}),
selectedCommand,
setSelectedCommand,
removePreviewFileByName: () => ({}),
Expand Down Expand Up @@ -128,7 +127,9 @@ describe("ComboBox", () => {

test("clicking on an executable command", async () => {
const executableSpy = vi.fn();
const { user, ...app } = render(<App executeCommand={executableSpy} />);
const { user, ...app } = render(
<App requestCommandsCompletion={executableSpy} />,
);
const textarea = app.getByRole("combobox");
await user.type(textarea, "@");

Expand All @@ -140,23 +141,29 @@ describe("ComboBox", () => {

test("execute command when pressing enter", async () => {
const executableSpy = vi.fn();
const { user, ...app } = render(<App executeCommand={executableSpy} />);
const { user, ...app } = render(
<App requestCommandsCompletion={executableSpy} />,
);
const textarea = app.getByRole("combobox");
await user.type(textarea, "@wo{Enter}");
expect(executableSpy).toHaveBeenLastCalledWith("@workspace ", 11);
});

test("execute command when pressing tab", async () => {
const executableSpy = vi.fn();
const { user, ...app } = render(<App executeCommand={executableSpy} />);
const { user, ...app } = render(
<App requestCommandsCompletion={executableSpy} />,
);
const textarea = app.getByRole("combobox");
await user.type(textarea, "@wo{Tab}");
expect(executableSpy).toHaveBeenLastCalledWith("@workspace ", 11);
});

test("typing executable command and pressing space", async () => {
const executableSpy = vi.fn();
const { user, ...app } = render(<App executeCommand={executableSpy} />);
const { user, ...app } = render(
<App requestCommandsCompletion={executableSpy} />,
);
const textarea = app.getByRole("combobox");
await user.type(textarea, "@workspace{Space}");
expect(executableSpy).toHaveBeenLastCalledWith("@workspace ", 11);
Expand Down
12 changes: 0 additions & 12 deletions src/components/ComboBox/ComboBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ export type ComboBoxProps = {
cursor: number,
number?: number,
) => void;
executeCommand: (command: string, cursor: number) => void;
setSelectedCommand: (command: string) => void;
selectedCommand: string;
removePreviewFileByName: (name: string) => void;
Expand All @@ -36,7 +35,6 @@ export const ComboBox: React.FC<ComboBoxProps> = ({
render,
commandArguments,
requestCommandsCompletion,
executeCommand,
setSelectedCommand,
selectedCommand,
removePreviewFileByName,
Expand Down Expand Up @@ -76,8 +74,6 @@ export const ComboBox: React.FC<ComboBoxProps> = ({
if (startPosition === null) return;
if (!trigger) return;
requestCommandsCompletion(value, ref.current.selectionStart);
executeCommand(value, ref.current.selectionStart);

// eslint-disable-next-line react-hooks/exhaustive-deps
}, [startPosition, trigger, value]);

Expand Down Expand Up @@ -260,14 +256,6 @@ export const ComboBox: React.FC<ComboBoxProps> = ({
onChange(nextValue.value);
setEndPosition(nextValue.endPosition);
};

console.log({
start: ref.current?.selectionStart,
end: ref.current?.selectionEnd,
statePositions: { endPosition, startPosition },
value,
cState: combobox.getState(),
});
return (
<>
<Combobox
Expand Down
12 changes: 0 additions & 12 deletions src/events/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ export enum EVENT_NAMES_FROM_CHAT {
NEW_FILE = "chat_create_new_file",
PASTE_DIFF = "chat_paste_diff",
REQUEST_AT_COMMAND_COMPLETION = "chat_request_at_command_completion",
REQUEST_AT_COMMAND_PREVIEW = "chat_request_at_command_preview",
}

export enum EVENT_NAMES_TO_CHAT {
Expand Down Expand Up @@ -92,17 +91,6 @@ export function isRequestAtCommandCompletion(
return action.type === EVENT_NAMES_FROM_CHAT.REQUEST_AT_COMMAND_COMPLETION;
}

export interface RequestAtCommandPreview extends ActionFromChat {
type: EVENT_NAMES_FROM_CHAT.REQUEST_AT_COMMAND_PREVIEW;
payload: { id: string; query: string; cursor: number };
}

export function isRequestAtCommandPreview(
action: unknown,
): action is RequestAtCommandPreview {
if (!isActionFromChat(action)) return false;
return action.type === EVENT_NAMES_FROM_CHAT.REQUEST_AT_COMMAND_PREVIEW;
}
export interface NewFileFromChat extends ActionFromChat {
type: EVENT_NAMES_FROM_CHAT.NEW_FILE;
payload: {
Expand Down
4 changes: 1 addition & 3 deletions src/features/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Flex, Responsive, Button } from "@radix-ui/themes";
import { isChatContextFileMessage } from "../services/refact";
import { useConfig } from "../contexts/config-context";
import { ArrowLeftIcon } from "@radix-ui/react-icons";
import { useEffectOnce } from "usehooks-ts";
import { useEffectOnce } from "../hooks";

export const Chat: React.FC<{ style?: React.CSSProperties }> = (props) => {
useEffectOnce(() => {
Expand All @@ -31,7 +31,6 @@ export const Chat: React.FC<{ style?: React.CSSProperties }> = (props) => {
handlePasteDiffClick,
requestCommandsCompletion,
setSelectedCommand,
executeCommand,
removePreviewFileByName,
retryQuestion,
} = useEventBusForChat();
Expand Down Expand Up @@ -123,7 +122,6 @@ export const Chat: React.FC<{ style?: React.CSSProperties }> = (props) => {
setSelectedCommand={setSelectedCommand}
onClose={maybeSendToSideBar}
attachFile={state.active_file}
executeCommand={executeCommand}
filesInPreview={state.files_in_preview}
selectedSnippet={state.selected_snippet}
removePreviewFileByName={removePreviewFileByName}
Expand Down
2 changes: 2 additions & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ export * from "./useIsOnline";
export * from "./useOnPressedEnter";
export * from "./useEventBusForSidebar";
export * from "./useApiKey";
export * from "./useEffectOnce";
export * from "./usePostMessage";
8 changes: 8 additions & 0 deletions src/hooks/useEffectOnce.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { useEffect } from "react";

import type { EffectCallback } from "react";

export function useEffectOnce(effect: EffectCallback) {
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(effect, []);
}
17 changes: 0 additions & 17 deletions src/hooks/useEventBusForChat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ import {
isReceiveAtCommandCompletion,
SetSelectedAtCommand,
isSetSelectedAtCommand,
RequestAtCommandPreview,
isReceiveAtCommandPreview,
isRemoveLastUserMessage,
isChatUserMessageResponse,
Expand Down Expand Up @@ -687,21 +686,6 @@ export const useEventBusForChat = () => {
dispatch(action);
}

const executeCommand = useDebounceCallback(
(command: string, cursor: number) => {
const action: RequestAtCommandPreview = {
type: EVENT_NAMES_FROM_CHAT.REQUEST_AT_COMMAND_PREVIEW,
payload: { id: state.chat.id, query: command, cursor },
};
if (!state.chat.model) {
setChatModel(state.caps.default_cap);
}
postMessage(action);
},
500,
{ leading: true },
);

function removePreviewFileByName(name: string) {
const action: RemovePreviewFileByName = {
type: EVENT_NAMES_TO_CHAT.REMOVE_PREVIEW_FILE_BY_NAME,
Expand Down Expand Up @@ -742,7 +726,6 @@ export const useEventBusForChat = () => {
handlePasteDiffClick,
requestCommandsCompletion,
setSelectedCommand,
executeCommand,
removePreviewFileByName,
retryQuestion,
};
Expand Down
Loading

0 comments on commit 647073e

Please sign in to comment.