collabSupport/tests/phoneService.cdrFeed.test.js
jmcqueen a25fc08fe2 Rename /voicereport to /callreport with scoped user and phone targets.
Add store/email/phone filtering, richer call-line formatting, CDR feed pagination and queueing, and split Jira poller enrichment into testable modules.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-27 10:10:03 -04:00

91 lines
3.4 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { extractCdrFeedList, parseCdrFeedLinkNext, resolveCdrFeedNextPage } from '../services/cdrFeedParser.js';
import {
cdrDedupKey,
cdrStartTime,
cdrCallingNumber,
} from '../services/cdrFeedParser.js';
import { filterCdrToWindow } from '../services/callReport/joinCallQuality.js';
test('extractCdrFeedList handles items array', () => {
const rows = [{ id: 1 }, { id: 2 }];
assert.deepEqual(extractCdrFeedList({ items: rows }), rows);
});
test('extractCdrFeedList handles numeric-keyed items object', () => {
const rows = [{ id: 'a' }, { id: 'b' }];
assert.deepEqual(extractCdrFeedList({ items: { 0: rows[0], 1: rows[1] } }), rows);
});
test('extractCdrFeedList handles top-level array', () => {
const rows = [{ id: 1 }];
assert.deepEqual(extractCdrFeedList(rows), rows);
});
test('extractCdrFeedList handles records alias', () => {
const rows = [{ id: 1 }];
assert.deepEqual(extractCdrFeedList({ records: rows }), rows);
});
test('cdrField reads report column labels', () => {
const row = {
'Report ID': 'abc-1',
'Start time': '2026-07-23T14:00:00.000Z',
'Calling number': '+15551234567',
'Called number': '+12122194600',
Duration: 42,
Direction: 'Inbound',
};
assert.equal(cdrStartTime(row), '2026-07-23T14:00:00.000Z');
assert.equal(cdrCallingNumber(row), '+15551234567');
assert.equal(cdrDedupKey(row), 'id:abc-1');
});
test('cdrDedupKey keeps distinct report rows', () => {
const a = { 'Report ID': '1', 'Start time': '2026-07-23T14:00:00.000Z' };
const b = { 'Report ID': '2', 'Start time': '2026-07-23T15:00:00.000Z' };
assert.notEqual(cdrDedupKey(a), cdrDedupKey(b));
});
test('filterCdrToWindow keeps API rows when start time is report-labeled', () => {
const window = {
startTime: '2026-07-23T13:00:00.000Z',
endTime: '2026-07-24T01:00:00.000Z',
};
const rows = [
{ 'Start time': '2026-07-23T14:00:00.000Z', 'Report ID': '1' },
{ 'Start time': '2026-07-23T15:00:00.000Z', 'Report ID': '2' },
];
assert.equal(filterCdrToWindow(rows, window).length, 2);
});
test('parseCdrFeedLinkNext reads rel=next from Link header', () => {
const link = '<https://analytics-calling.webexapis.com/v1/cdr_feed?startTimeForNextFetch=2025-08-15T09:30:00.000Z&max=5000>; rel="next"';
assert.equal(
parseCdrFeedLinkNext(link),
'https://analytics-calling.webexapis.com/v1/cdr_feed?startTimeForNextFetch=2025-08-15T09:30:00.000Z&max=5000',
);
});
test('resolveCdrFeedNextPage prefers Link header over body token', () => {
const baseUrl = 'https://analytics-calling.webexapis.com/v1/cdr_feed';
const baseParams = { startTime: 'a', endTime: 'b', locations: 'Store 0782', max: 5000 };
const next = resolveCdrFeedNextPage(
{ next: 'cursor-token' },
{ link: '<https://example.com/page2>; rel="next"' },
baseUrl,
baseParams,
);
assert.deepEqual(next, { url: 'https://example.com/page2', params: null });
});
test('resolveCdrFeedNextPage falls back to body next cursor', () => {
const baseUrl = 'https://analytics-calling.webexapis.com/v1/cdr_feed';
const baseParams = { startTime: 'a', endTime: 'b', locations: 'Store 0782', max: 5000 };
const next = resolveCdrFeedNextPage({ next: 'cursor-token' }, {}, baseUrl, baseParams);
assert.deepEqual(next, {
url: baseUrl,
params: { ...baseParams, next: 'cursor-token' },
});
});