generated from nhcarrigan/template
fa906684c2
## Summary - **fix**: `show_thinking_blocks` setting now persists across sessions — it was defined on the TypeScript side but missing from the Rust `HikariConfig` struct, so serde silently dropped it on every save/load - **feat**: Tool calls are now rendered as collapsible blocks matching the Extended Thinking block aesthetic, replacing the old inline dropdown approach - **feat**: Add configurable max output tokens setting - **feat**: Use random creative names for conversation tabs - **test**: Significantly expanded frontend unit test coverage - **docs**: Require tests for all changes in CLAUDE.md - **feat**: Allow users to specify a custom terminal font (Closes #176) - **feat**: Display friendly names for memory files derived from the first heading (Closes #177) - **feat**: Add custom UI font support for the app chrome (buttons, labels, tabs) - **fix**: Apply custom UI font to the full app interface — `.app-container` was hardcoded, blocking inheritance from `body`; also renamed "Custom Font" to "Custom Terminal Font" for clarity ✨ This PR was created with help from Hikari~ 🌸 Reviewed-on: #175 Co-authored-by: Hikari <hikari@nhcarrigan.com> Co-committed-by: Hikari <hikari@nhcarrigan.com>
94 lines
2.8 KiB
TypeScript
94 lines
2.8 KiB
TypeScript
import { describe, it, expect, beforeEach } from "vitest";
|
|
import { get } from "svelte/store";
|
|
import { emitMockEvent } from "../../../vitest.setup";
|
|
import { todos, initializeTodoListener, cleanupTodoListener } from "./todos";
|
|
import type { TodoItem } from "./todos";
|
|
|
|
describe("todos store", () => {
|
|
beforeEach(() => {
|
|
cleanupTodoListener();
|
|
todos.clear();
|
|
});
|
|
|
|
describe("initial state", () => {
|
|
it("starts with an empty list", () => {
|
|
expect(get(todos)).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe("set and clear", () => {
|
|
it("can set todos directly", () => {
|
|
const items: TodoItem[] = [
|
|
{ content: "Task 1", status: "pending", activeForm: "Doing task 1" },
|
|
{ content: "Task 2", status: "in_progress", activeForm: "Doing task 2" },
|
|
];
|
|
todos.set(items);
|
|
expect(get(todos)).toEqual(items);
|
|
});
|
|
|
|
it("clear resets to empty array", () => {
|
|
todos.set([{ content: "Task", status: "completed", activeForm: "Doing task" }]);
|
|
todos.clear();
|
|
expect(get(todos)).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe("update", () => {
|
|
it("can update todos with a callback", () => {
|
|
const initial: TodoItem[] = [
|
|
{ content: "Task 1", status: "pending", activeForm: "Doing task 1" },
|
|
];
|
|
todos.set(initial);
|
|
todos.update((current) => [
|
|
...current,
|
|
{ content: "Task 2", status: "completed", activeForm: "Doing task 2" },
|
|
]);
|
|
expect(get(todos)).toHaveLength(2);
|
|
});
|
|
});
|
|
|
|
describe("initializeTodoListener", () => {
|
|
it("listens for claude:todo-update events", async () => {
|
|
await initializeTodoListener();
|
|
|
|
const newTodos: TodoItem[] = [
|
|
{ content: "Backend task", status: "in_progress", activeForm: "Running backend task" },
|
|
];
|
|
emitMockEvent("claude:todo-update", { todos: newTodos });
|
|
|
|
expect(get(todos)).toEqual(newTodos);
|
|
});
|
|
|
|
it("does not register a duplicate listener when called twice", async () => {
|
|
await initializeTodoListener();
|
|
await initializeTodoListener();
|
|
|
|
const newTodos: TodoItem[] = [
|
|
{ content: "Task", status: "pending", activeForm: "Doing task" },
|
|
];
|
|
emitMockEvent("claude:todo-update", { todos: newTodos });
|
|
|
|
// Should only have been set once (not doubled)
|
|
expect(get(todos)).toEqual(newTodos);
|
|
});
|
|
});
|
|
|
|
describe("cleanupTodoListener", () => {
|
|
it("stops listening for events after cleanup", async () => {
|
|
await initializeTodoListener();
|
|
cleanupTodoListener();
|
|
|
|
emitMockEvent("claude:todo-update", {
|
|
todos: [{ content: "Task", status: "pending", activeForm: "Doing task" }],
|
|
});
|
|
|
|
// Should not have been updated since we cleaned up
|
|
expect(get(todos)).toEqual([]);
|
|
});
|
|
|
|
it("is safe to call when not initialised", () => {
|
|
expect(() => cleanupTodoListener()).not.toThrow();
|
|
});
|
|
});
|
|
});
|