/* eslint-disable @next/next/no-img-element */ import "@testing-library/jest-dom"; import React from "react"; import { fireEvent, render, screen, waitFor } from "@testing-library/react"; import { AgentTurn } from "./AgentTurn"; jest.mock("next/image", () => ({ __esModule: true, default: (props: React.ImgHTMLAttributes) => ( {props.alt ), })); jest.mock("framer-motion", () => ({ AnimatePresence: ({ children }: { children: React.ReactNode }) => <>{children}, motion: { div: ({ children, animate: _animate, exit: _exit, initial: _initial, transition: _transition, ...props }: React.HTMLAttributes & Record) => (
{children}
), span: ({ children, animate: _animate, transition: _transition, ...props }: React.HTMLAttributes & Record) => ( {children} ), }, })); jest.mock("./AgentMarkdownBlock", () => ({ MarkdownBlock: ({ children }: { children: string }) => (
{children.split(/\n+/u).map((line) =>

{line}

)}
), normalizeClipboardText: (value: string) => value.replace(/\s+$/u, ""), })); describe("AgentTurn speech selection", () => { it("shows a floating action and reads from the selected text", async () => { const content = "第一段内容。\n\n第二段内容。"; const speechText = "第一段内容。\n第二段内容。"; const onSpeak = jest.fn(); const removeAllRanges = jest.fn(); render( , ); const selectedParagraph = screen.getByText("第二段内容。"); const selectedTextNode = selectedParagraph.firstChild as Text; const range = { commonAncestorContainer: selectedTextNode, getBoundingClientRect: () => ({ width: 72, height: 20, top: 120, right: 172, bottom: 140, left: 100, x: 100, y: 120, toJSON: () => ({}), }), } as unknown as Range; const selection = { rangeCount: 1, isCollapsed: false, getRangeAt: () => range, toString: () => "第二段", removeAllRanges, } as unknown as Selection; jest.spyOn(window, "getSelection").mockReturnValue(selection); jest.spyOn(window, "requestAnimationFrame").mockImplementation((callback) => { callback(0); return 1; }); fireEvent.pointerUp(selectedParagraph); const speechAction = await screen.findByRole("button", { name: "从这里开始朗读" }); fireEvent.click(speechAction); await waitFor(() => { expect(onSpeak).toHaveBeenCalledWith("assistant-1", speechText, { startOffset: speechText.indexOf("第二段"), }); }); expect(removeAllRanges).toHaveBeenCalledTimes(1); await waitFor(() => { expect(screen.queryByRole("button", { name: "从这里开始朗读" })).not.toBeInTheDocument(); }); }); });