diff --git a/webview-ui/src/components/history/CopyButton.tsx b/webview-ui/src/components/history/CopyButton.tsx index c11624ab8c..3c51285703 100644 --- a/webview-ui/src/components/history/CopyButton.tsx +++ b/webview-ui/src/components/history/CopyButton.tsx @@ -16,7 +16,10 @@ export const CopyButton = ({ itemTask }: CopyButtonProps) => { const onCopy = useCallback( (e: React.MouseEvent) => { e.stopPropagation() - !isCopied && copy(itemTask) + const tempDiv = document.createElement('div'); + tempDiv.innerHTML = itemTask; + const text = tempDiv.textContent || tempDiv.innerText || ""; + !isCopied && copy(text) }, [isCopied, copy, itemTask], ) diff --git a/webview-ui/src/components/history/HistoryView.tsx b/webview-ui/src/components/history/HistoryView.tsx index 64528cb0ea..79c0918a64 100644 --- a/webview-ui/src/components/history/HistoryView.tsx +++ b/webview-ui/src/components/history/HistoryView.tsx @@ -104,6 +104,7 @@ const HistoryView = ({ onDone }: HistoryViewProps) => { }} data={tasks} data-testid="virtuoso-container" + initialTopMostItemIndex={0} components={{ List: React.forwardRef((props, ref) => (
@@ -172,6 +173,7 @@ const HistoryView = ({ onDone }: HistoryViewProps) => { wordBreak: "break-word", overflowWrap: "anywhere", }} + data-testid="task-content" dangerouslySetInnerHTML={{ __html: item.task }} />
diff --git a/webview-ui/src/components/history/__tests__/HistoryView.test.tsx b/webview-ui/src/components/history/__tests__/HistoryView.test.tsx index 4470e5d02d..379f7ccda7 100644 --- a/webview-ui/src/components/history/__tests__/HistoryView.test.tsx +++ b/webview-ui/src/components/history/__tests__/HistoryView.test.tsx @@ -8,7 +8,6 @@ import { vscode } from "../../../utils/vscode" jest.mock("../../../context/ExtensionStateContext") jest.mock("../../../utils/vscode") jest.mock("../../../i18n/TranslationContext") - jest.mock("react-virtuoso", () => ({ Virtuoso: ({ data, itemContent }: any) => (
@@ -71,6 +70,12 @@ describe("HistoryView", () => { }) it("handles search functionality", () => { + // Setup clipboard mock that resolves immediately + const mockClipboard = { + writeText: jest.fn().mockResolvedValue(undefined), + } + Object.assign(navigator, { clipboard: mockClipboard }) + const onDone = jest.fn() render() @@ -97,6 +102,14 @@ describe("HistoryView", () => { // Verify radio button is checked const updatedRadio = within(radioGroup).getByTestId("radio-most-relevant") expect(updatedRadio).toBeInTheDocument() + + // Verify copy the plain text content of the task when the copy button is clicked + const taskContainer = screen.getByTestId("virtuoso-item-1") + fireEvent.mouseEnter(taskContainer) + const copyButton = within(taskContainer).getByTestId("copy-prompt-button") + fireEvent.click(copyButton) + const taskContent = within(taskContainer).getByTestId("task-content") + expect(navigator.clipboard.writeText).toHaveBeenCalledWith(taskContent.textContent) }) it("handles sort options correctly", async () => {