import { describe, it, expect, beforeEach } from "vitest"; import { get } from "svelte/store"; import { searchState, isSearchActive, searchQuery } from "./search"; describe("searchState store", () => { beforeEach(() => { searchState.clear(); }); describe("initial state", () => { it("starts with empty query", () => { const state = get(searchState); expect(state.query).toBe(""); }); it("starts inactive", () => { const state = get(searchState); expect(state.isActive).toBe(false); }); it("starts with zero match count", () => { const state = get(searchState); expect(state.matchCount).toBe(0); }); it("starts with zero current match index", () => { const state = get(searchState); expect(state.currentMatchIndex).toBe(0); }); }); describe("setQuery", () => { it("sets the query string", () => { searchState.setQuery("hello"); expect(get(searchState).query).toBe("hello"); }); it("activates the store when query is non-empty", () => { searchState.setQuery("hello"); expect(get(searchState).isActive).toBe(true); }); it("deactivates the store when query is empty", () => { searchState.setQuery("hello"); searchState.setQuery(""); expect(get(searchState).isActive).toBe(false); }); it("resets currentMatchIndex to 0 on each query change", () => { searchState.setQuery("hello"); searchState.setMatchCount(5); searchState.nextMatch(); searchState.nextMatch(); searchState.setQuery("world"); expect(get(searchState).currentMatchIndex).toBe(0); }); }); describe("setMatchCount", () => { it("updates the match count", () => { searchState.setMatchCount(7); expect(get(searchState).matchCount).toBe(7); }); it("does not reset currentMatchIndex", () => { searchState.setQuery("test"); searchState.setMatchCount(5); searchState.nextMatch(); searchState.setMatchCount(10); expect(get(searchState).currentMatchIndex).toBe(1); }); }); describe("nextMatch", () => { it("advances to the next match index", () => { searchState.setMatchCount(5); searchState.nextMatch(); expect(get(searchState).currentMatchIndex).toBe(1); }); it("wraps around to 0 after the last match", () => { searchState.setMatchCount(3); searchState.nextMatch(); searchState.nextMatch(); searchState.nextMatch(); expect(get(searchState).currentMatchIndex).toBe(0); }); it("stays at 0 when match count is 0", () => { searchState.setMatchCount(0); searchState.nextMatch(); expect(get(searchState).currentMatchIndex).toBe(0); }); }); describe("previousMatch", () => { it("goes to the previous match index", () => { searchState.setMatchCount(5); searchState.nextMatch(); searchState.nextMatch(); searchState.previousMatch(); expect(get(searchState).currentMatchIndex).toBe(1); }); it("wraps around to last match when at index 0", () => { searchState.setMatchCount(5); searchState.previousMatch(); expect(get(searchState).currentMatchIndex).toBe(4); }); it("stays at 0 when match count is 0", () => { searchState.setMatchCount(0); searchState.previousMatch(); expect(get(searchState).currentMatchIndex).toBe(0); }); }); describe("clear", () => { it("resets query to empty string", () => { searchState.setQuery("hello"); searchState.clear(); expect(get(searchState).query).toBe(""); }); it("resets isActive to false", () => { searchState.setQuery("hello"); searchState.clear(); expect(get(searchState).isActive).toBe(false); }); it("resets matchCount to 0", () => { searchState.setMatchCount(10); searchState.clear(); expect(get(searchState).matchCount).toBe(0); }); it("resets currentMatchIndex to 0", () => { searchState.setMatchCount(5); searchState.nextMatch(); searchState.nextMatch(); searchState.clear(); expect(get(searchState).currentMatchIndex).toBe(0); }); }); }); describe("isSearchActive derived store", () => { beforeEach(() => { searchState.clear(); }); it("is false initially", () => { expect(get(isSearchActive)).toBe(false); }); it("is true when query is set", () => { searchState.setQuery("test"); expect(get(isSearchActive)).toBe(true); }); it("is false after clearing", () => { searchState.setQuery("test"); searchState.clear(); expect(get(isSearchActive)).toBe(false); }); }); describe("searchQuery derived store", () => { beforeEach(() => { searchState.clear(); }); it("is empty string initially", () => { expect(get(searchQuery)).toBe(""); }); it("reflects the current query", () => { searchState.setQuery("my search"); expect(get(searchQuery)).toBe("my search"); }); it("is empty after clearing", () => { searchState.setQuery("test"); searchState.clear(); expect(get(searchQuery)).toBe(""); }); });