-
- {typeof stream.messages[0]?.content === "string"
- ? stream.messages[0]?.content
- : JSON.stringify(stream.messages[0]?.content)}
-
-
{stream.values.customField}
-
{stream.isLoading ? "Loading" : "Not loading"}
+ return (
+
+
+ {typeof stream.messages[0]?.content === "string"
+ ? stream.messages[0]?.content
+ : JSON.stringify(stream.messages[0]?.content)}
- );
+
{stream.values.customField}
+
+ {stream.isLoading ? "Loading" : "Not loading"}
+
+
+ );
}
render(
);
// Should immediately show initial values without any loading
- expect(screen.getByTestId("message-0")).toHaveTextContent("Initial message");
- expect(screen.getByTestId("custom-field")).toHaveTextContent("initial-value");
+ expect(screen.getByTestId("message-0")).toHaveTextContent(
+ "Initial message",
+ );
+ expect(screen.getByTestId("custom-field")).toHaveTextContent(
+ "initial-value",
+ );
expect(screen.getByTestId("loading")).toHaveTextContent("Not loading");
});
});
+
+describe("useStream onStop callback", () => {
+ const user = userEvent.setup();
+
+ it("calls onStop callback when stop is called", async () => {
+ const onStopCallback = vi.fn();
+
+ function TestComponent() {
+ const { submit, stop } = useStream({
+ assistantId: "test-assistant",
+ apiKey: "test-api-key",
+ onStop: onStopCallback,
+ });
+
+ return (
+
+
+
+
+ );
+ }
+
+ render(
);
+
+ // Start a stream and stop it
+ await user.click(screen.getByTestId("submit"));
+ await user.click(screen.getByTestId("stop"));
+
+ // Verify onStop was called with mutate function
+ expect(onStopCallback).toHaveBeenCalledTimes(1);
+ expect(onStopCallback).toHaveBeenCalledWith(
+ expect.objectContaining({
+ mutate: expect.any(Function),
+ }),
+ );
+ });
+
+ it("mutate function updates stream values immediately", async () => {
+ function TestComponent() {
+ const { submit, stop, values } = useStream({
+ assistantId: "test-assistant",
+ apiKey: "test-api-key",
+ onStop: ({ mutate }) => {
+ mutate((prev) => ({
+ ...prev,
+ stoppedByUser: true,
+ customMessage: "Stream stopped",
+ }));
+ },
+ });
+
+ return (
+
+
+ {(values as any).stoppedByUser ? "Stopped" : "Not stopped"}
+
+
+ {(values as any).customMessage || "No message"}
+
+
+
+
+ );
+ }
+
+ render(
);
+
+ // Initial state
+ expect(screen.getByTestId("stopped-status")).toHaveTextContent(
+ "Not stopped",
+ );
+ expect(screen.getByTestId("custom-message")).toHaveTextContent(
+ "No message",
+ );
+
+ // Start and stop stream
+ await user.click(screen.getByTestId("submit"));
+ await user.click(screen.getByTestId("stop"));
+
+ // Verify state was updated immediately
+ await waitFor(() => {
+ expect(screen.getByTestId("stopped-status")).toHaveTextContent("Stopped");
+ expect(screen.getByTestId("custom-message")).toHaveTextContent(
+ "Stream stopped",
+ );
+ });
+ });
+
+ it("handles functional updates correctly", async () => {
+ function TestComponent() {
+ const { submit, stop, values } = useStream({
+ assistantId: "test-assistant",
+ apiKey: "test-api-key",
+ initialValues: {
+ counter: 5,
+ items: ["item1", "item2"],
+ },
+ onStop: ({ mutate }) => {
+ mutate((prev: any) => ({
+ ...prev,
+ counter: (prev.counter || 0) + 10,
+ items: [...(prev.items || []), "stopped"],
+ }));
+ },
+ });
+
+ return (
+
+
{(values as any).counter}
+
{(values as any).items?.join(", ")}
+
+
+
+ );
+ }
+
+ render(
);
+
+ // Initial state
+ expect(screen.getByTestId("counter")).toHaveTextContent("5");
+ expect(screen.getByTestId("items")).toHaveTextContent("item1, item2");
+
+ // Start and stop stream
+ await user.click(screen.getByTestId("submit"));
+ await user.click(screen.getByTestId("stop"));
+
+ // Verify functional update was applied correctly
+ await waitFor(() => {
+ expect(screen.getByTestId("counter")).toHaveTextContent("15");
+ expect(screen.getByTestId("items")).toHaveTextContent(
+ "item1, item2, stopped",
+ );
+ });
+ });
+
+ it("is not called when stream completes naturally", async () => {
+ const onStopCallback = vi.fn();
+
+ function TestComponent() {
+ const { submit } = useStream({
+ assistantId: "test-assistant",
+ apiKey: "test-api-key",
+ onStop: onStopCallback,
+ });
+
+ return (
+
+
+
+ );
+ }
+
+ render(
);
+
+ // Start a stream and let it complete naturally
+ await user.click(screen.getByTestId("submit"));
+
+ // Wait for stream to complete naturally
+ await waitFor(() => {
+ expect(onStopCallback).not.toHaveBeenCalled();
+ });
+ });
+});