summaryrefslogtreecommitdiff
path: root/web/test/tasks-board.test.mjs
diff options
context:
space:
mode:
authorClaudomator Agent <agent@claudomator.local>2026-07-06 05:26:24 +0000
committerClaudomator Agent <agent@claudomator.local>2026-07-06 05:26:24 +0000
commitd2cbe9aa07afdc0aac33c959803d6a6aaef69b8e (patch)
treec7861cc4c1a8472d48dff13be98b7d634090191a /web/test/tasks-board.test.mjs
parentd9db12a25a42d00e0f64ac87e10ac0b612b841a8 (diff)
fix(web): correct elapsed timer class/location, log-tail coverage, and tests (task 4 reviewer findings)
- Move elapsed timer span from card header to after meta block; add task-elapsed class alongside running-elapsed (Finding 1) - Replace PENDING/QUEUED-only log-tail div with full if/else: placeholder div.task-log-tail-placeholder for queue states, div.task-log-tail with dataset.logTarget for all other states (Finding 2) - Delete web/test/task-card-di.test.mjs; append correct tests to web/test/tasks-board.test.mjs covering log-tail and elapsed timer contracts (Finding 3) - Thread doc parameter through createEditForm, renderSubtaskRollup, and renderQuestionFooter so createTaskCard is fully testable without a browser DOM Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'web/test/tasks-board.test.mjs')
-rw-r--r--web/test/tasks-board.test.mjs81
1 files changed, 81 insertions, 0 deletions
diff --git a/web/test/tasks-board.test.mjs b/web/test/tasks-board.test.mjs
index 560e8c8..db61880 100644
--- a/web/test/tasks-board.test.mjs
+++ b/web/test/tasks-board.test.mjs
@@ -10,6 +10,7 @@ import {
TASK_COLUMNS,
columnForTaskState,
groupTasksByColumn,
+ createTaskCard,
} from '../app.js';
describe('columnForTaskState', () => {
@@ -146,3 +147,83 @@ describe('groupTasksByColumn', () => {
}
});
});
+
+// ── createTaskCard: log-tail placeholder + elapsed timer ────────────────────
+//
+// createTaskCard uses the real global `document` by default (existing
+// convention throughout app.js — e.g. renderEventTimeline(events, doc =
+// document)) but accepts an injectable `doc` for Node-based unit testing
+// without jsdom, matching the hand-rolled mock-DOM convention already used
+// by web/test/task-panel-summary.test.mjs and web/test/render-dedup.test.mjs.
+
+function makeMockDoc() {
+ function makeEl(tag) {
+ return {
+ tag,
+ className: '',
+ classList: {
+ _set: new Set(),
+ add(...cls) { cls.forEach(c => this._set.add(c)); },
+ toggle(cls, on) { on ? this._set.add(cls) : this._set.delete(cls); },
+ contains(cls) { return this._set.has(cls); },
+ },
+ textContent: '',
+ title: '',
+ hidden: false,
+ dataset: {},
+ children: [],
+ _listeners: {},
+ appendChild(child) { this.children.push(child); return child; },
+ append(...nodes) { nodes.forEach(n => this.children.push(n)); },
+ prepend(...nodes) { this.children.unshift(...nodes); },
+ addEventListener(type, fn) { this._listeners[type] = fn; },
+ querySelector(sel) {
+ const cls = sel.split(',')[0].trim().replace(/^\./, '');
+ const search = (el) => {
+ if (el.className && el.className.split(' ').includes(cls)) return el;
+ if (el.dataset && sel.includes('[data-started-at]') && el.className.includes('task-elapsed') && 'startedAt' in el.dataset) return el;
+ for (const c of el.children) {
+ const found = search(c);
+ if (found) return found;
+ }
+ return null;
+ };
+ return search(this);
+ },
+ };
+ }
+ return { createElement: (tag) => makeEl(tag) };
+}
+
+describe('createTaskCard log-tail placeholder', () => {
+ it('shows a "waiting to start" placeholder for PENDING/QUEUED tasks (no execution exists yet)', () => {
+ const doc = makeMockDoc();
+ for (const state of ['PENDING', 'QUEUED']) {
+ const card = createTaskCard({ id: 't1', name: 'Task', state }, doc);
+ const placeholder = card.querySelector('.task-log-tail-placeholder');
+ const tail = card.querySelector('.task-log-tail');
+ assert.ok(placeholder, `expected a placeholder for ${state}`);
+ assert.equal(tail, null, `expected no .task-log-tail element for ${state}`);
+ }
+ });
+
+ it('includes a .task-log-tail element for every non-Queue state', () => {
+ const doc = makeMockDoc();
+ for (const state of ['RUNNING', 'BLOCKED', 'READY', 'FAILED', 'TIMED_OUT', 'CANCELLED', 'BUDGET_EXCEEDED', 'COMPLETED']) {
+ const card = createTaskCard({ id: 't1', name: 'Task', state }, doc);
+ const tail = card.querySelector('.task-log-tail');
+ assert.ok(tail, `expected .task-log-tail for ${state}`);
+ }
+ });
+});
+
+describe('createTaskCard elapsed timer', () => {
+ it('includes a .task-elapsed[data-started-at] element only for RUNNING tasks', () => {
+ const doc = makeMockDoc();
+ const running = createTaskCard({ id: 't1', name: 'Task', state: 'RUNNING', updated_at: '2026-01-01T00:00:00Z' }, doc);
+ assert.ok(running.querySelector('.task-elapsed[data-started-at]'));
+
+ const ready = createTaskCard({ id: 't2', name: 'Task', state: 'READY' }, doc);
+ assert.equal(ready.querySelector('.task-elapsed[data-started-at]'), null);
+ });
+});