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>
91 lines
3.4 KiB
JavaScript
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' },
|
|
});
|
|
});
|