Add indexed history search across iOS and web
TestFlight / Build and upload (push) Successful in 1m55s
TestFlight / Build and upload (push) Successful in 1m55s
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import { scheduleWorkspaceSearch } from "../src/lib/workspace-search.ts";
|
||||
import { retainSelectedHistoryItem, resolveSidebarSelectionAfterRefresh } from "../src/lib/sidebar-selection.ts";
|
||||
|
||||
const flush = async () => { await Promise.resolve(); await Promise.resolve(); };
|
||||
|
||||
test("typing is debounced and superseded requests never start", async (t) => {
|
||||
t.mock.timers.enable({ apis: ["setTimeout"] });
|
||||
const queries = [];
|
||||
const results = [];
|
||||
const request = async (query) => { queries.push(query); return { items: [], hasMore: false }; };
|
||||
const reportError = (error) => assert.fail(String(error));
|
||||
const cancelFirst = scheduleWorkspaceSearch("ne", request, (result) => results.push(result), reportError);
|
||||
t.mock.timers.tick(299);
|
||||
assert.deepEqual(queries, []);
|
||||
cancelFirst();
|
||||
const cancelLast = scheduleWorkspaceSearch("nebula", request, (result) => results.push(result), reportError);
|
||||
t.mock.timers.tick(300);
|
||||
await flush();
|
||||
assert.deepEqual(queries, ["nebula"]);
|
||||
assert.deepEqual(results, [{ items: [], hasMore: false }]);
|
||||
cancelLast();
|
||||
});
|
||||
|
||||
test("cancellation aborts the transport and discards stale results and errors", async (t) => {
|
||||
t.mock.timers.enable({ apis: ["setTimeout"] });
|
||||
let resolveFirst;
|
||||
let rejectSecond;
|
||||
let signal;
|
||||
const results = [];
|
||||
const errors = [];
|
||||
const first = scheduleWorkspaceSearch("first", (_query, value) => {
|
||||
signal = value;
|
||||
return new Promise((resolve) => { resolveFirst = resolve; });
|
||||
}, (result) => results.push(result), (error) => errors.push(error));
|
||||
t.mock.timers.tick(300);
|
||||
first();
|
||||
assert.equal(signal.aborted, true);
|
||||
const second = scheduleWorkspaceSearch("second", () => new Promise((_resolve, reject) => { rejectSecond = reject; }),
|
||||
(result) => results.push(result), (error) => errors.push(error));
|
||||
t.mock.timers.tick(300);
|
||||
second();
|
||||
resolveFirst({ items: [{ id: "stale" }], hasMore: true });
|
||||
rejectSecond(new Error("stale failure"));
|
||||
await flush();
|
||||
assert.deepEqual(results, []);
|
||||
assert.deepEqual(errors, []);
|
||||
});
|
||||
|
||||
test("search results retain excerpts and truncation info; failures reach the UI", async (t) => {
|
||||
t.mock.timers.enable({ apis: ["setTimeout"] });
|
||||
const expected = { items: [{ type: "chat", id: "old", searchSnippet: "A nebula in the sky" }], hasMore: true };
|
||||
let received;
|
||||
let error;
|
||||
const cancel = scheduleWorkspaceSearch("nebula", async () => expected, (result) => { received = result; }, assert.fail);
|
||||
t.mock.timers.tick(300);
|
||||
await flush();
|
||||
assert.deepEqual(received, expected);
|
||||
cancel();
|
||||
const cancelFailure = scheduleWorkspaceSearch("nebula", async () => { throw new Error("Offline"); }, assert.fail, (result) => { error = result; });
|
||||
t.mock.timers.tick(300);
|
||||
await flush();
|
||||
assert.equal(error.message, "Offline");
|
||||
cancelFailure();
|
||||
});
|
||||
|
||||
test("opening older chat/search results survives collection refresh without restoring deleted or unrelated items", () => {
|
||||
const recent = [{ type: "chat", id: "recent" }];
|
||||
for (const kind of ["chat", "search"]) {
|
||||
const selection = { kind, id: "old" };
|
||||
const retained = { type: kind, id: "old" };
|
||||
const refreshed = retainSelectedHistoryItem(recent, selection, retained);
|
||||
assert.deepEqual(resolveSidebarSelectionAfterRefresh(selection, refreshed), selection);
|
||||
assert.equal(retainSelectedHistoryItem(refreshed, selection, retained), refreshed);
|
||||
assert.equal(retainSelectedHistoryItem(recent, { kind, id: "different" }, retained), recent);
|
||||
assert.equal(retainSelectedHistoryItem(recent, selection, null), recent);
|
||||
assert.equal(retainSelectedHistoryItem(recent, null, retained), recent);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user