From 1b2deb13daa788dc43d98caeaa9507254b1ca283 Mon Sep 17 00:00:00 2001 From: Claudomator Agent Date: Mon, 16 Mar 2026 20:01:59 +0000 Subject: feat: display deployment status badge on READY task cards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add deployment_status field to task list/get API responses for READY tasks. The field includes deployed_commit, fix_commits, and includes_fix so the UI can show whether the deployed server includes each fix. - internal/api/task_view.go: taskView struct + enrichTask() helper - handleListTasks/handleGetTask: return enriched taskView responses - web/app.js: export renderDeploymentBadge(); add badge to READY cards - web/test/deployment-badge.test.mjs: 8 tests for renderDeploymentBadge - web/style.css: .deployment-badge--deployed / --pending styles - server_test.go: 3 new tests (red→green) for enriched task responses Co-Authored-By: Claude Sonnet 4.6 --- web/test/deployment-badge.test.mjs | 72 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 web/test/deployment-badge.test.mjs (limited to 'web/test/deployment-badge.test.mjs') diff --git a/web/test/deployment-badge.test.mjs b/web/test/deployment-badge.test.mjs new file mode 100644 index 0000000..afb4a59 --- /dev/null +++ b/web/test/deployment-badge.test.mjs @@ -0,0 +1,72 @@ +// deployment-badge.test.mjs — Unit tests for deployment status badge. +// +// Run with: node --test web/test/deployment-badge.test.mjs + +import { describe, it } from 'node:test'; +import assert from 'node:assert/strict'; +import { renderDeploymentBadge } from '../app.js'; + +function makeDoc() { + return { + createElement(tag) { + const el = { + tag, + className: '', + textContent: '', + title: '', + children: [], + appendChild(child) { this.children.push(child); return child; }, + }; + return el; + }, + }; +} + +describe('renderDeploymentBadge', () => { + it('returns null for null status', () => { + const el = renderDeploymentBadge(null, makeDoc()); + assert.equal(el, null); + }); + + it('returns null for undefined status', () => { + const el = renderDeploymentBadge(undefined, makeDoc()); + assert.equal(el, null); + }); + + it('returns element with deployment-badge class for valid status', () => { + const status = { deployed_commit: 'abc123', fix_commits: [], includes_fix: false }; + const el = renderDeploymentBadge(status, makeDoc()); + assert.ok(el, 'element should not be null'); + assert.ok(el.className.includes('deployment-badge'), `className should include deployment-badge, got: ${el.className}`); + }); + + it('shows "Deployed" text when includes_fix is true', () => { + const status = { deployed_commit: 'abc123', fix_commits: [{ hash: 'aabbcc', message: 'fix' }], includes_fix: true }; + const el = renderDeploymentBadge(status, makeDoc()); + assert.ok(el.textContent.includes('Deployed'), `expected "Deployed" in "${el.textContent}"`); + }); + + it('shows "Not deployed" text when includes_fix is false', () => { + const status = { deployed_commit: 'abc123', fix_commits: [{ hash: 'aabbcc', message: 'fix' }], includes_fix: false }; + const el = renderDeploymentBadge(status, makeDoc()); + assert.ok(el.textContent.includes('Not deployed'), `expected "Not deployed" in "${el.textContent}"`); + }); + + it('applies deployed class when includes_fix is true', () => { + const status = { deployed_commit: 'abc123', fix_commits: [{ hash: 'aabbcc', message: 'fix' }], includes_fix: true }; + const el = renderDeploymentBadge(status, makeDoc()); + assert.ok(el.className.includes('deployment-badge--deployed'), `className: ${el.className}`); + }); + + it('applies pending class when includes_fix is false', () => { + const status = { deployed_commit: 'abc123', fix_commits: [{ hash: 'aabbcc', message: 'fix' }], includes_fix: false }; + const el = renderDeploymentBadge(status, makeDoc()); + assert.ok(el.className.includes('deployment-badge--pending'), `className: ${el.className}`); + }); + + it('returns null for doc=null', () => { + const status = { deployed_commit: 'abc', fix_commits: [], includes_fix: false }; + const el = renderDeploymentBadge(status, null); + assert.equal(el, null); + }); +}); -- cgit v1.2.3