Skip to main content
Glama
commitment-deduplication.test.ts6.8 kB
// test/commitment-deduplication.test.ts import { describe, it } from 'node:test'; import assert from 'node:assert/strict'; import { SummaryCalculator } from '../src/services/summary-calculator.js'; import type { DailySummary, CompanyConfig } from '../src/types/index.js'; /** * Test that entries with multiple tags mapping to the same commitment * only count once per commitment (no duplicate counting) */ describe('Commitment Deduplication', () => { it('should not double-count entries with multiple tags mapping to same commitment', () => { const calculator = new SummaryCalculator(); // Config where #dev and #devops both map to 'development' const config: CompanyConfig = { company: 'Test', commitments: { development: { limit: 20, unit: 'hours/week' }, total: { limit: 25, unit: 'hours/week' } }, projects: { 'Infrastructure': { tags: ['devops'], commitment: 'development' } }, tagMappings: { 'dev': 'development' } }; // Entry with both #dev and #devops (both map to development) const days: DailySummary[] = [{ date: '2025-10-21', totalHours: 2, entries: [{ date: '2025-10-21', time: '14:00', task: 'DevOps work', duration: 2, tags: ['dev', 'devops'] // Both map to 'development' }] }]; const summary = calculator.calculateWeekly(43, 2025, '2025-10-21', '2025-10-27', days, config); // Should count 2h once, not 4h (2h × 2 tags) assert.strictEqual(summary.byCommitment['development'], 2, 'Entry with multiple tags mapping to same commitment should count only once'); // Both tags should still be tracked separately assert.strictEqual(summary.byTag['dev'], 2, 'Tag dev should have 2h'); assert.strictEqual(summary.byTag['devops'], 2, 'Tag devops should have 2h'); }); it('should handle multiple entries with overlapping tag mappings', () => { const calculator = new SummaryCalculator(); const config: CompanyConfig = { company: 'Test', commitments: { development: { limit: 20, unit: 'hours/week' }, total: { limit: 25, unit: 'hours/week' } }, projects: { 'Infrastructure': { tags: ['devops', 'infra'], commitment: 'development' } }, tagMappings: { 'dev': 'development', 'code': 'development' } }; const days: DailySummary[] = [{ date: '2025-10-21', totalHours: 5, entries: [ { date: '2025-10-21', time: '10:00', task: 'Coding', duration: 2, tags: ['dev', 'code'] // Both map to 'development' }, { date: '2025-10-21', time: '14:00', task: 'Infrastructure', duration: 3, tags: ['devops', 'infra'] // Both map to 'development' via Infrastructure project } ] }]; const summary = calculator.calculateWeekly(43, 2025, '2025-10-21', '2025-10-27', days, config); // Should be 2h + 3h = 5h, not 10h (if double-counted) assert.strictEqual(summary.byCommitment['development'], 5, 'Multiple entries with overlapping mappings should each count once'); // Tags should still aggregate correctly assert.strictEqual(summary.byTag['dev'], 2); assert.strictEqual(summary.byTag['code'], 2); assert.strictEqual(summary.byTag['devops'], 3); assert.strictEqual(summary.byTag['infra'], 3); }); it('should handle entry with three tags mapping to same commitment', () => { const calculator = new SummaryCalculator(); const config: CompanyConfig = { company: 'Test', commitments: { development: { limit: 20, unit: 'hours/week' }, total: { limit: 25, unit: 'hours/week' } }, tagMappings: { 'dev': 'development', 'code': 'development', 'coding': 'development' } }; const days: DailySummary[] = [{ date: '2025-10-21', totalHours: 1.5, entries: [{ date: '2025-10-21', time: '14:00', task: 'Development work', duration: 1.5, tags: ['dev', 'code', 'coding'] // All three map to 'development' }] }]; const summary = calculator.calculateWeekly(43, 2025, '2025-10-21', '2025-10-27', days, config); // Should count 1.5h once, not 4.5h (1.5h × 3 tags) assert.strictEqual(summary.byCommitment['development'], 1.5, 'Entry with three tags mapping to same commitment should count only once'); }); it('should correctly count entries mapping to different commitments', () => { const calculator = new SummaryCalculator(); const config: CompanyConfig = { company: 'Test', commitments: { development: { limit: 20, unit: 'hours/week' }, meeting: { limit: 5, unit: 'hours/week' }, total: { limit: 25, unit: 'hours/week' } }, tagMappings: { 'dev': 'development', 'sync': 'meeting' } }; const days: DailySummary[] = [{ date: '2025-10-21', totalHours: 3, entries: [ { date: '2025-10-21', time: '10:00', task: 'Development', duration: 2, tags: ['dev'] }, { date: '2025-10-21', time: '14:00', task: 'Standup', duration: 1, tags: ['sync'] } ] }]; const summary = calculator.calculateWeekly(43, 2025, '2025-10-21', '2025-10-27', days, config); // Should have correct counts for different commitments assert.strictEqual(summary.byCommitment['development'], 2); assert.strictEqual(summary.byCommitment['meeting'], 1); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/markwharton/time-tracking-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server