summaryrefslogtreecommitdiff
path: root/web/test/active-pane.test.mjs
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-03-08 20:46:35 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-03-08 20:46:35 +0000
commit188fe9b078e263bb6b648d7949f92dcb7b899953 (patch)
tree6df6cd38bf1925ff702fed479630ba83a7b260b4 /web/test/active-pane.test.mjs
parent095db94030455bde497f18da94d0b404dcf042ea (diff)
web/test: add active-pane, focus-preserve, is-user-editing, render-dedup tests
Unit tests for UI helper functions: active pane detection, input focus preservation during polls, user-editing guard, and render deduplication. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'web/test/active-pane.test.mjs')
-rw-r--r--web/test/active-pane.test.mjs81
1 files changed, 81 insertions, 0 deletions
diff --git a/web/test/active-pane.test.mjs b/web/test/active-pane.test.mjs
new file mode 100644
index 0000000..37bb8c5
--- /dev/null
+++ b/web/test/active-pane.test.mjs
@@ -0,0 +1,81 @@
+// active-pane.test.mjs — Tests for Active pane partition logic.
+//
+// Run with: node --test web/test/active-pane.test.mjs
+
+import { describe, it } from 'node:test';
+import assert from 'node:assert/strict';
+import { partitionActivePaneTasks } from '../app.js';
+
+function makeTask(id, state, created_at) {
+ return { id, name: `task-${id}`, state, created_at: created_at ?? `2024-01-01T00:0${id}:00Z` };
+}
+
+const ALL_STATES = [
+ 'PENDING', 'QUEUED', 'RUNNING', 'READY', 'BLOCKED',
+ 'COMPLETED', 'FAILED', 'TIMED_OUT', 'CANCELLED', 'BUDGET_EXCEEDED',
+];
+
+describe('partitionActivePaneTasks', () => {
+ it('running contains only RUNNING tasks', () => {
+ const tasks = ALL_STATES.map((s, i) => makeTask(String(i), s));
+ const { running } = partitionActivePaneTasks(tasks);
+ assert.equal(running.length, 1);
+ assert.equal(running[0].state, 'RUNNING');
+ });
+
+ it('ready contains only READY tasks', () => {
+ const tasks = ALL_STATES.map((s, i) => makeTask(String(i), s));
+ const { ready } = partitionActivePaneTasks(tasks);
+ assert.equal(ready.length, 1);
+ assert.equal(ready[0].state, 'READY');
+ });
+
+ it('excludes QUEUED, BLOCKED, PENDING, COMPLETED, FAILED and all other states', () => {
+ const tasks = ALL_STATES.map((s, i) => makeTask(String(i), s));
+ const { running, ready } = partitionActivePaneTasks(tasks);
+ const allReturned = [...running, ...ready];
+ assert.equal(allReturned.length, 2);
+ assert.ok(allReturned.every(t => t.state === 'RUNNING' || t.state === 'READY'));
+ });
+
+ it('returns empty arrays for empty input', () => {
+ const { running, ready } = partitionActivePaneTasks([]);
+ assert.deepEqual(running, []);
+ assert.deepEqual(ready, []);
+ });
+
+ it('handles multiple RUNNING tasks sorted by created_at ascending', () => {
+ const tasks = [
+ makeTask('b', 'RUNNING', '2024-01-01T00:02:00Z'),
+ makeTask('a', 'RUNNING', '2024-01-01T00:01:00Z'),
+ makeTask('c', 'RUNNING', '2024-01-01T00:03:00Z'),
+ ];
+ const { running } = partitionActivePaneTasks(tasks);
+ assert.equal(running.length, 3);
+ assert.equal(running[0].id, 'a');
+ assert.equal(running[1].id, 'b');
+ assert.equal(running[2].id, 'c');
+ });
+
+ it('handles multiple READY tasks sorted by created_at ascending', () => {
+ const tasks = [
+ makeTask('y', 'READY', '2024-01-01T00:02:00Z'),
+ makeTask('x', 'READY', '2024-01-01T00:01:00Z'),
+ ];
+ const { ready } = partitionActivePaneTasks(tasks);
+ assert.equal(ready.length, 2);
+ assert.equal(ready[0].id, 'x');
+ assert.equal(ready[1].id, 'y');
+ });
+
+ it('returns both sections independently when both states present', () => {
+ const tasks = [
+ makeTask('r1', 'RUNNING', '2024-01-01T00:01:00Z'),
+ makeTask('d1', 'READY', '2024-01-01T00:02:00Z'),
+ makeTask('r2', 'RUNNING', '2024-01-01T00:03:00Z'),
+ ];
+ const { running, ready } = partitionActivePaneTasks(tasks);
+ assert.equal(running.length, 2);
+ assert.equal(ready.length, 1);
+ });
+});