agent-ecosystem/test/shared/utils/taskWorkDuration.test.ts
2026-05-08 09:58:57 +03:00

163 lines
4.5 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import {
calculateTaskImplementationEventDuration,
calculateTaskImplementationDuration,
formatTaskImplementationDuration,
shouldShowTaskImplementationDuration,
} from '@shared/utils/taskWorkDuration';
describe('taskWorkDuration', () => {
it('sums completed intervals and the current in-progress interval', () => {
const duration = calculateTaskImplementationDuration(
{
status: 'in_progress',
workIntervals: [
{
startedAt: '2026-05-08T10:00:00.000Z',
completedAt: '2026-05-08T10:02:30.000Z',
},
{ startedAt: '2026-05-08T10:05:00.000Z' },
],
},
Date.parse('2026-05-08T10:07:00.000Z')
);
expect(duration).toEqual({
elapsedMs: 270_000,
hasRunningInterval: true,
countedIntervalCount: 2,
});
expect(shouldShowTaskImplementationDuration(duration)).toBe(true);
});
it('does not keep an open interval running after the task leaves in progress', () => {
const duration = calculateTaskImplementationDuration(
{
status: 'completed',
workIntervals: [
{
startedAt: '2026-05-08T10:00:00.000Z',
completedAt: '2026-05-08T10:02:00.000Z',
},
{ startedAt: '2026-05-08T10:05:00.000Z' },
],
},
Date.parse('2026-05-08T10:30:00.000Z')
);
expect(duration).toEqual({
elapsedMs: 120_000,
hasRunningInterval: false,
countedIntervalCount: 1,
});
});
it('merges overlapping intervals to avoid double counting malformed data', () => {
const duration = calculateTaskImplementationDuration(
{
status: 'completed',
workIntervals: [
{
startedAt: '2026-05-08T10:00:00.000Z',
completedAt: '2026-05-08T10:10:00.000Z',
},
{
startedAt: '2026-05-08T10:05:00.000Z',
completedAt: '2026-05-08T10:12:00.000Z',
},
],
},
Date.parse('2026-05-08T10:30:00.000Z')
);
expect(duration.elapsedMs).toBe(720_000);
expect(duration.countedIntervalCount).toBe(2);
});
it('matches a closed interval to the status transition that ended implementation', () => {
const duration = calculateTaskImplementationEventDuration(
{
status: 'completed',
workIntervals: [
{
startedAt: '2026-05-08T10:00:00.000Z',
completedAt: '2026-05-08T10:02:30.000Z',
},
],
},
{
id: 'event-completed',
timestamp: '2026-05-08T10:02:32.000Z',
type: 'status_changed',
from: 'in_progress',
to: 'completed',
}
);
expect(duration).toEqual({ elapsedMs: 150_000, running: false });
});
it('shows a running interval only on the event that started the active implementation', () => {
const task = {
status: 'in_progress',
workIntervals: [{ startedAt: '2026-05-08T10:05:00.000Z' }],
};
expect(
calculateTaskImplementationEventDuration(
task,
{
id: 'event-started',
timestamp: '2026-05-08T10:05:00.000Z',
type: 'status_changed',
from: 'completed',
to: 'in_progress',
},
Date.parse('2026-05-08T10:07:30.000Z')
)
).toEqual({ elapsedMs: 150_000, running: true });
expect(
calculateTaskImplementationEventDuration(
task,
{
id: 'event-created',
timestamp: '2026-05-08T10:00:00.000Z',
type: 'task_created',
status: 'pending',
},
Date.parse('2026-05-08T10:07:30.000Z')
)
).toBeNull();
});
it('does not derive transition durations from history gaps without a matching work interval', () => {
const duration = calculateTaskImplementationEventDuration(
{
status: 'completed',
workIntervals: [
{
startedAt: '2026-05-08T10:00:00.000Z',
completedAt: '2026-05-08T10:02:30.000Z',
},
],
},
{
id: 'event-comment',
timestamp: '2026-05-08T10:20:00.000Z',
type: 'status_changed',
from: 'in_progress',
to: 'completed',
}
);
expect(duration).toBeNull();
});
it('formats seconds, minutes, and hours for compact UI labels', () => {
expect(formatTaskImplementationDuration(42_900)).toBe('42s');
expect(formatTaskImplementationDuration(65_000)).toBe('1m 05s');
expect(formatTaskImplementationDuration(7_260_000)).toBe('2h 01m');
});
});