108 lines
3.5 KiB
TypeScript
108 lines
3.5 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
import { createCompletedTaskAutoClear, TODO_AUTO_CLEAR_DELAY_MS } from "../src/auto-clear.ts";
|
|
import { TaskState } from "../src/state.ts";
|
|
|
|
function clearState(state: TaskState, onClear: () => void): boolean {
|
|
state.set("replace", [], false);
|
|
onClear();
|
|
return true;
|
|
}
|
|
|
|
test("clears the task tree ten seconds after every task remains done", (context) => {
|
|
context.mock.timers.enable({ apis: ["setTimeout"] });
|
|
const state = new TaskState();
|
|
state.add([{ name: "Done", status: "done" }]);
|
|
let clearCount = 0;
|
|
const autoClear = createCompletedTaskAutoClear(state, () => clearState(state, () => {
|
|
clearCount += 1;
|
|
}));
|
|
|
|
autoClear.sync();
|
|
context.mock.timers.tick(TODO_AUTO_CLEAR_DELAY_MS - 1);
|
|
assert.equal(state.stats().total, 1);
|
|
|
|
context.mock.timers.tick(1);
|
|
assert.deepEqual(state.snapshot(), { tasks: [], nextId: 1 });
|
|
assert.equal(clearCount, 1);
|
|
});
|
|
|
|
test("cancels a pending clear when unfinished work appears", (context) => {
|
|
context.mock.timers.enable({ apis: ["setTimeout"] });
|
|
const state = new TaskState();
|
|
state.add([{ name: "Done", status: "done" }]);
|
|
let clearCount = 0;
|
|
const autoClear = createCompletedTaskAutoClear(state, () => clearState(state, () => {
|
|
clearCount += 1;
|
|
}));
|
|
|
|
autoClear.sync();
|
|
state.add([{ name: "New work" }]);
|
|
autoClear.sync();
|
|
context.mock.timers.tick(TODO_AUTO_CLEAR_DELAY_MS);
|
|
|
|
assert.equal(state.stats().total, 2);
|
|
assert.equal(clearCount, 0);
|
|
});
|
|
|
|
test("preserves the deadline for unrelated refreshes", (context) => {
|
|
context.mock.timers.enable({ apis: ["setTimeout"] });
|
|
const state = new TaskState();
|
|
state.add([{ name: "Done", status: "done" }]);
|
|
const autoClear = createCompletedTaskAutoClear(state, () => clearState(state, () => {}));
|
|
|
|
autoClear.sync();
|
|
context.mock.timers.tick(9_000);
|
|
state.update([{ id: 1, name: "Renamed" }]);
|
|
autoClear.sync();
|
|
context.mock.timers.tick(1_000);
|
|
|
|
assert.equal(state.stats().total, 0);
|
|
});
|
|
|
|
test("restarts the delay for changed or restored completed trees", (context) => {
|
|
context.mock.timers.enable({ apis: ["setTimeout"] });
|
|
const state = new TaskState();
|
|
state.add([{ name: "Done", status: "done" }]);
|
|
const autoClear = createCompletedTaskAutoClear(state, () => clearState(state, () => {}));
|
|
|
|
autoClear.sync();
|
|
context.mock.timers.tick(9_000);
|
|
state.add([{ name: "Also done", status: "done" }]);
|
|
autoClear.sync();
|
|
context.mock.timers.tick(1_000);
|
|
assert.equal(state.stats().total, 2);
|
|
|
|
context.mock.timers.tick(8_000);
|
|
autoClear.sync(true);
|
|
context.mock.timers.tick(2_000);
|
|
assert.equal(state.stats().total, 2);
|
|
|
|
context.mock.timers.tick(8_000);
|
|
assert.equal(state.stats().total, 0);
|
|
});
|
|
|
|
test("retries after a clear transaction fails and supports shutdown cancellation", (context) => {
|
|
context.mock.timers.enable({ apis: ["setTimeout"] });
|
|
const state = new TaskState();
|
|
state.add([{ name: "Done", status: "done" }]);
|
|
let attempts = 0;
|
|
const autoClear = createCompletedTaskAutoClear(state, () => {
|
|
attempts += 1;
|
|
if (attempts === 1) return false;
|
|
return clearState(state, () => {});
|
|
});
|
|
|
|
autoClear.sync();
|
|
context.mock.timers.tick(TODO_AUTO_CLEAR_DELAY_MS);
|
|
assert.equal(state.stats().total, 1);
|
|
context.mock.timers.tick(TODO_AUTO_CLEAR_DELAY_MS);
|
|
assert.equal(state.stats().total, 0);
|
|
|
|
state.add([{ name: "Done again", status: "done" }]);
|
|
autoClear.sync();
|
|
autoClear.cancel();
|
|
context.mock.timers.tick(TODO_AUTO_CLEAR_DELAY_MS);
|
|
assert.equal(state.stats().total, 1);
|
|
});
|