checkpoint: pre-split branch cleanup
This commit is contained in:
parent
4c2ae2e5b7
commit
b5db7a7753
276 changed files with 35912 additions and 60119 deletions
|
|
@ -1,82 +1,82 @@
|
|||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
|
||||
const ROOT = process.cwd();
|
||||
|
||||
async function read(relativePath) {
|
||||
return fs.readFile(path.join(ROOT, relativePath), 'utf8');
|
||||
}
|
||||
|
||||
test('graph page defines tabbed layout, epic chips, and mobile fallback', async () => {
|
||||
const graphPage = await read('src/components/graph/dependency-graph-page.tsx');
|
||||
|
||||
// Tabbed layout: Tasks and Dependencies tabs
|
||||
assert.match(graphPage, /WorkflowTabs/, 'should use WorkflowTabs component');
|
||||
assert.match(graphPage, /activeTab/, 'should track active tab state');
|
||||
|
||||
// Epic chip strip replaces sidebar
|
||||
assert.match(graphPage, /EpicChipStrip/, 'should use EpicChipStrip component');
|
||||
|
||||
// Mobile panel toggle preserved
|
||||
assert.match(graphPage, /Switch to Graph/);
|
||||
assert.match(graphPage, /Back to Selection/);
|
||||
|
||||
// Task card grid extracted
|
||||
assert.match(graphPage, /TaskCardGrid/, 'should use TaskCardGrid component');
|
||||
|
||||
// Task details drawer
|
||||
assert.match(graphPage, /TaskDetailsDrawer/, 'should use TaskDetailsDrawer drawer');
|
||||
assert.match(graphPage, /projectRoot=\{projectRoot\}/, 'drawer should receive project root for edits');
|
||||
assert.match(graphPage, /onIssueUpdated=\{.*refreshIssues\(\)\}/, 'drawer should trigger refresh after edits');
|
||||
|
||||
// Dependency flow strip
|
||||
assert.match(graphPage, /DependencyFlowStrip/, 'should use DependencyFlowStrip component');
|
||||
|
||||
// Graph section with ReactFlow
|
||||
assert.match(graphPage, /GraphSection/, 'should use GraphSection component');
|
||||
assert.match(graphPage, /ReactFlowProvider/, 'should wrap graph in ReactFlowProvider');
|
||||
|
||||
// Edge options and node types still configured
|
||||
assert.match(graphPage, /defaultEdgeOptions/);
|
||||
assert.match(graphPage, /nodeTypes/);
|
||||
|
||||
// Actionable node detection
|
||||
assert.match(graphPage, /actionableNodeIds/, 'should compute actionable (unblocked) nodes');
|
||||
assert.match(graphPage, /ui-field/, 'graph filters should use shared dark field styling');
|
||||
assert.match(graphPage, /ui-select/, 'graph select should use shared dark select styling');
|
||||
});
|
||||
|
||||
test('extracted graph section has viewport and legend', async () => {
|
||||
const graphSection = await read('src/components/graph/graph-section.tsx');
|
||||
|
||||
assert.match(graphSection, /className=\"workflow-graph-flow\"/, 'graph should have workflow-graph-flow class');
|
||||
assert.match(graphSection, /workflow-graph-legend/, 'should have legend');
|
||||
assert.match(graphSection, /translateExtent=\{\[/, 'should set translate extent');
|
||||
assert.match(graphSection, /defaultEdgeOptions=\{/, 'should pass edge options');
|
||||
assert.match(graphSection, /blockerAnalysis/, 'should show blocker stats');
|
||||
assert.match(graphSection, /hideClosed/, 'should support hideClosed state in legend');
|
||||
assert.match(graphSection, /!hideClosed/, 'done legend should be hidden when closed items are hidden');
|
||||
assert.match(graphSection, /Read left to right/, 'legend should include plain directional hint');
|
||||
assert.match(graphSection, /Left = blockers/, 'legend should include left/right dependency meaning');
|
||||
assert.match(graphSection, /Right = work unblocked by this task/, 'legend should include downstream meaning');
|
||||
assert.match(graphSection, /min-h-\[24rem\]/, 'graph container should enforce bounded minimum height');
|
||||
assert.match(graphSection, /md:min-h-\[35rem\]/, 'graph container should scale minimum height on desktop');
|
||||
});
|
||||
|
||||
test('graph node card supports tooltips and actionable glow', async () => {
|
||||
const nodeCard = await read('src/components/graph/graph-node-card.tsx');
|
||||
|
||||
assert.match(nodeCard, /isActionable/, 'should check actionable state');
|
||||
assert.match(nodeCard, /ring-emerald-400/, 'actionable nodes should have green glow');
|
||||
assert.match(nodeCard, /node-select-pulse/, 'selected nodes should pulse');
|
||||
assert.match(nodeCard, /blockerTooltipLines/, 'should display blocker tooltip');
|
||||
assert.match(nodeCard, /isDimmed/, 'should support dimming non-chain nodes');
|
||||
assert.match(nodeCard, /Ready to work/, 'actionable tooltip text');
|
||||
});
|
||||
|
||||
test('graph edges expose explicit relation labels', async () => {
|
||||
const graphPage = await read('src/components/graph/dependency-graph-page.tsx');
|
||||
assert.match(graphPage, /label:\s*'BLOCKS'/, 'edges should include plain-language relation labels');
|
||||
});
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
|
||||
const ROOT = process.cwd();
|
||||
|
||||
async function read(relativePath) {
|
||||
return fs.readFile(path.join(ROOT, relativePath), 'utf8');
|
||||
}
|
||||
|
||||
test('graph page defines tabbed layout, epic chips, and mobile fallback', async () => {
|
||||
const graphPage = await read('src/components/graph/dependency-graph-page.tsx');
|
||||
|
||||
// Tabbed layout: Tasks and Dependencies tabs
|
||||
assert.match(graphPage, /WorkflowTabs/, 'should use WorkflowTabs component');
|
||||
assert.match(graphPage, /activeTab/, 'should track active tab state');
|
||||
|
||||
// Epic chip strip replaces sidebar
|
||||
assert.match(graphPage, /EpicChipStrip/, 'should use EpicChipStrip component');
|
||||
|
||||
// Mobile panel toggle preserved
|
||||
assert.match(graphPage, /Switch to Graph/);
|
||||
assert.match(graphPage, /Back to Selection/);
|
||||
|
||||
// Task card grid extracted
|
||||
assert.match(graphPage, /TaskCardGrid/, 'should use TaskCardGrid component');
|
||||
|
||||
// Task details drawer
|
||||
assert.match(graphPage, /TaskDetailsDrawer/, 'should use TaskDetailsDrawer drawer');
|
||||
assert.match(graphPage, /projectRoot=\{projectRoot\}/, 'drawer should receive project root for edits');
|
||||
assert.match(graphPage, /onIssueUpdated=\{.*refreshIssues\(\)\}/, 'drawer should trigger refresh after edits');
|
||||
|
||||
// Dependency flow strip
|
||||
assert.match(graphPage, /DependencyFlowStrip/, 'should use DependencyFlowStrip component');
|
||||
|
||||
// Graph section with ReactFlow
|
||||
assert.match(graphPage, /GraphSection/, 'should use GraphSection component');
|
||||
assert.match(graphPage, /ReactFlowProvider/, 'should wrap graph in ReactFlowProvider');
|
||||
|
||||
// Edge options and node types still configured
|
||||
assert.match(graphPage, /defaultEdgeOptions/);
|
||||
assert.match(graphPage, /nodeTypes/);
|
||||
|
||||
// Actionable node detection
|
||||
assert.match(graphPage, /actionableNodeIds/, 'should compute actionable (unblocked) nodes');
|
||||
assert.match(graphPage, /ui-field/, 'graph filters should use shared dark field styling');
|
||||
assert.match(graphPage, /ui-select/, 'graph select should use shared dark select styling');
|
||||
});
|
||||
|
||||
test('extracted graph section has viewport and legend', async () => {
|
||||
const graphSection = await read('src/components/graph/graph-section.tsx');
|
||||
|
||||
assert.match(graphSection, /className=\"workflow-graph-flow\"/, 'graph should have workflow-graph-flow class');
|
||||
assert.match(graphSection, /workflow-graph-legend/, 'should have legend');
|
||||
assert.match(graphSection, /translateExtent=\{\[/, 'should set translate extent');
|
||||
assert.match(graphSection, /defaultEdgeOptions=\{/, 'should pass edge options');
|
||||
assert.match(graphSection, /blockerAnalysis/, 'should show blocker stats');
|
||||
assert.match(graphSection, /hideClosed/, 'should support hideClosed state in legend');
|
||||
assert.match(graphSection, /!hideClosed/, 'done legend should be hidden when closed items are hidden');
|
||||
assert.match(graphSection, /Read left to right/, 'legend should include plain directional hint');
|
||||
assert.match(graphSection, /Left = blockers/, 'legend should include left/right dependency meaning');
|
||||
assert.match(graphSection, /Right = work unblocked by this task/, 'legend should include downstream meaning');
|
||||
assert.match(graphSection, /min-h-\[24rem\]/, 'graph container should enforce bounded minimum height');
|
||||
assert.match(graphSection, /md:min-h-\[35rem\]/, 'graph container should scale minimum height on desktop');
|
||||
});
|
||||
|
||||
test('graph node card supports tooltips and actionable glow', async () => {
|
||||
const nodeCard = await read('src/components/graph/graph-node-card.tsx');
|
||||
|
||||
assert.match(nodeCard, /isActionable/, 'should check actionable state');
|
||||
assert.match(nodeCard, /ring-emerald-400/, 'actionable nodes should have green glow');
|
||||
assert.match(nodeCard, /node-select-pulse/, 'selected nodes should pulse');
|
||||
assert.match(nodeCard, /blockerTooltipLines/, 'should display blocker tooltip');
|
||||
assert.match(nodeCard, /isDimmed/, 'should support dimming non-chain nodes');
|
||||
assert.match(nodeCard, /Ready to work/, 'actionable tooltip text');
|
||||
});
|
||||
|
||||
test('graph edges expose explicit relation labels', async () => {
|
||||
const graphPage = await read('src/components/graph/dependency-graph-page.tsx');
|
||||
assert.match(graphPage, /label:\s*'BLOCKS'/, 'edges should include plain-language relation labels');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,52 +1,52 @@
|
|||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
|
||||
const ROOT = process.cwd();
|
||||
|
||||
async function read(relativePath) {
|
||||
return fs.readFile(path.join(ROOT, relativePath), 'utf8');
|
||||
}
|
||||
|
||||
test('kanban board uses expandable vertical swimlanes', async () => {
|
||||
const board = await read('src/components/kanban/kanban-board.tsx');
|
||||
|
||||
assert.match(board, /aria-expanded/);
|
||||
assert.match(board, /onActivateStatus/);
|
||||
assert.match(board, /max-h-\[50vh\]/);
|
||||
assert.match(board, /showClosed/, 'board should accept showClosed control');
|
||||
assert.match(board, /status !== 'closed' \|\| showClosed/, 'done lane should be hidden when showClosed is false');
|
||||
});
|
||||
|
||||
test('kanban page defines mobile detail drawer behavior', async () => {
|
||||
const page = await read('src/components/kanban/kanban-page.tsx');
|
||||
|
||||
assert.match(page, /fixed inset-0/);
|
||||
assert.match(page, /lg:hidden/);
|
||||
assert.match(page, /lg:grid-cols-\[minmax\(0,1fr\)_minmax\(22rem,26rem\)\]/);
|
||||
assert.match(page, /lg:border-l/);
|
||||
});
|
||||
|
||||
test('kanban controls use fluid full-width sizing on small viewports', async () => {
|
||||
const controls = await read('src/components/kanban/kanban-controls.tsx');
|
||||
|
||||
assert.match(controls, /w-full/);
|
||||
assert.match(controls, /sm:w-/);
|
||||
assert.match(controls, /ui-field/, 'controls should use shared dark field styling');
|
||||
assert.match(controls, /ui-select/, 'selects should use shared dark select styling');
|
||||
assert.match(controls, /Next Actionable/);
|
||||
assert.match(controls, /nextActionableFeedback/);
|
||||
});
|
||||
|
||||
test('kanban detail includes execution checklist rendering', async () => {
|
||||
const detail = await read('src/components/kanban/kanban-detail.tsx');
|
||||
|
||||
assert.match(detail, /Execution checklist/i);
|
||||
assert.match(detail, /Summary/i);
|
||||
assert.match(detail, /Task metadata/i);
|
||||
assert.match(detail, /Timeline/i);
|
||||
assert.match(detail, /Edit fields/i);
|
||||
assert.match(detail, /Save changes/i);
|
||||
assert.match(detail, /projectRoot\?/i);
|
||||
});
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
|
||||
const ROOT = process.cwd();
|
||||
|
||||
async function read(relativePath) {
|
||||
return fs.readFile(path.join(ROOT, relativePath), 'utf8');
|
||||
}
|
||||
|
||||
test('kanban board uses expandable vertical swimlanes', async () => {
|
||||
const board = await read('src/components/kanban/kanban-board.tsx');
|
||||
|
||||
assert.match(board, /aria-expanded/);
|
||||
assert.match(board, /onActivateStatus/);
|
||||
assert.match(board, /max-h-\[50vh\]/);
|
||||
assert.match(board, /showClosed/, 'board should accept showClosed control');
|
||||
assert.match(board, /status !== 'closed' \|\| showClosed/, 'done lane should be hidden when showClosed is false');
|
||||
});
|
||||
|
||||
test('kanban page defines mobile detail drawer behavior', async () => {
|
||||
const page = await read('src/components/kanban/kanban-page.tsx');
|
||||
|
||||
assert.match(page, /fixed inset-0/);
|
||||
assert.match(page, /lg:hidden/);
|
||||
assert.match(page, /lg:grid-cols-\[minmax\(0,1fr\)_minmax\(22rem,26rem\)\]/);
|
||||
assert.match(page, /lg:border-l/);
|
||||
});
|
||||
|
||||
test('kanban controls use fluid full-width sizing on small viewports', async () => {
|
||||
const controls = await read('src/components/kanban/kanban-controls.tsx');
|
||||
|
||||
assert.match(controls, /w-full/);
|
||||
assert.match(controls, /sm:w-/);
|
||||
assert.match(controls, /ui-field/, 'controls should use shared dark field styling');
|
||||
assert.match(controls, /ui-select/, 'selects should use shared dark select styling');
|
||||
assert.match(controls, /Next Actionable/);
|
||||
assert.match(controls, /nextActionableFeedback/);
|
||||
});
|
||||
|
||||
test('kanban detail includes execution checklist rendering', async () => {
|
||||
const detail = await read('src/components/kanban/kanban-detail.tsx');
|
||||
|
||||
assert.match(detail, /Execution checklist/i);
|
||||
assert.match(detail, /Summary/i);
|
||||
assert.match(detail, /Task metadata/i);
|
||||
assert.match(detail, /Timeline/i);
|
||||
assert.match(detail, /Edit fields/i);
|
||||
assert.match(detail, /Save changes/i);
|
||||
assert.match(detail, /projectRoot\?/i);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,4 +6,4 @@ import { scanForDirectIssuesJsonlWrites } from '../../tools/guardrails/no-direct
|
|||
test('source tree contains no direct write calls targeting .beads/issues.jsonl', () => {
|
||||
const violations = scanForDirectIssuesJsonlWrites('src');
|
||||
assert.deepEqual(violations, []);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue