import React from "react";
import { render } from "@testing-library/react";
import { describe, it, expect, vi } from "vitest";
// ─── Mock react-native ───────────────────────────────────────────────────────
vi.mock("react-native", () => {
const React = require("react");
const View = React.forwardRef(
(
{
children,
style,
testID,
accessibilityLabel,
accessibilityRole,
...rest
}: any,
ref: any,
) =>
React.createElement(
"div",
{
ref,
style,
"data-testid": testID,
"aria-label": accessibilityLabel,
role: accessibilityRole,
...rest,
},
children,
),
);
View.displayName = "View";
const Text = React.forwardRef(({ children, style, ...rest }: any, ref: any) =>
React.createElement("span", { ref, style, ...rest }, children),
);
Text.displayName = "Text";
const AnimatedValue = class {
_value: number;
constructor(value: number) {
this._value = value;
}
interpolate({ outputRange }: any) {
return outputRange[0];
}
};
const AnimatedView = React.forwardRef(
({ children, style, ...rest }: any, ref: any) =>
React.createElement("div", { ref, style, ...rest }, children),
);
AnimatedView.displayName = "Animated.View";
const timing = () => ({ start: vi.fn(), stop: vi.fn() });
const sequence = () => ({ start: vi.fn(), stop: vi.fn() });
const loop = () => ({ start: vi.fn(), stop: vi.fn() });
const parallel = () => ({ start: vi.fn(), stop: vi.fn() });
const delay = () => ({ start: vi.fn(), stop: vi.fn() });
return {
View,
Text,
Animated: {
Value: AnimatedValue,
View: AnimatedView,
timing,
sequence,
loop,
parallel,
delay,
},
StyleSheet: {
create: (styles: any) => styles,
flatten: (style: any) =>
Array.isArray(style) ? Object.assign({}, ...style) : style || {},
},
};
});
// ─── Mock Markdown ────────────────────────────────────────────────────────────
vi.mock("../../Markdown", () => ({
CopilotMarkdown: ({ content }: { content: string }) => {
const React = require("react");
return React.createElement(
"div",
{ "data-testid": "copilot-markdown" },
content,
);
},
}));
import { AssistantMessage } from "../AssistantMessage";
import { UserMessage } from "../UserMessage";
import { TypingIndicator } from "../TypingIndicator";
// ─── Tests ───────────────────────────────────────────────────────────────────
describe("AssistantMessage edge cases", () => {
it("renders empty content without crashing", () => {
const { container } = render();
expect(container).toBeTruthy();
});
it("shows both markdown content AND typing indicator when both content and isLoading are provided", () => {
// When content is truthy AND isLoading is true, BOTH should render
// Looking at the source: content is rendered when truthy, isLoading adds typing indicator
const { queryByTestId, queryByLabelText } = render(
,
);
expect(queryByTestId("copilot-markdown")).toBeTruthy();
expect(queryByLabelText("Typing indicator")).toBeTruthy();
});
it("does not render markdown when content is empty", () => {
const { queryByTestId } = render();
// Empty content = falsy = CopilotMarkdown should not render
expect(queryByTestId("copilot-markdown")).toBeNull();
});
it("does not render typing indicator when isLoading is false", () => {
const { queryByLabelText } = render(
,
);
expect(queryByLabelText("Typing indicator")).toBeNull();
});
it("accepts style override", () => {
const { container } = render(
,
);
expect(container).toBeTruthy();
});
});
describe("UserMessage edge cases", () => {
it("renders empty content without crashing", () => {
const { container } = render();
expect(container).toBeTruthy();
});
it("renders long content without crashing", () => {
const longText = "A".repeat(5000);
const { container } = render();
expect(container.textContent).toContain("A".repeat(100));
});
it("accepts style override", () => {
const { container } = render(
,
);
expect(container).toBeTruthy();
});
});
describe("TypingIndicator edge cases", () => {
it("accepts style override", () => {
const { getByLabelText } = render(
,
);
expect(getByLabelText("Typing indicator")).toBeTruthy();
});
it("has correct accessibility attributes", () => {
const { getByLabelText } = render();
const indicator = getByLabelText("Typing indicator");
expect(indicator).toBeTruthy();
expect(indicator.getAttribute("role")).toBe("text");
});
});