diff options
| author | Claudomator Agent <agent@claudomator.local> | 2026-07-06 05:26:24 +0000 |
|---|---|---|
| committer | Claudomator Agent <agent@claudomator.local> | 2026-07-06 05:26:24 +0000 |
| commit | d2cbe9aa07afdc0aac33c959803d6a6aaef69b8e (patch) | |
| tree | c7861cc4c1a8472d48dff13be98b7d634090191a /web/test/tasks-board.test.mjs | |
| parent | d9db12a25a42d00e0f64ac87e10ac0b612b841a8 (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.mjs | 81 |
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); + }); +}); |
