114 lines
3.8 KiB
TypeScript
114 lines
3.8 KiB
TypeScript
import {
|
|
parseTsvBody,
|
|
valuesToMarkdownTable,
|
|
} from '../src/features/sheets/sheetsApi';
|
|
import { _parseSheetAttrs } from '../src/agent';
|
|
|
|
describe('parseTsvBody', () => {
|
|
test('returns [] for empty / whitespace input', () => {
|
|
expect(parseTsvBody('')).toEqual([]);
|
|
expect(parseTsvBody(' ')).toEqual([]);
|
|
expect(parseTsvBody('\n\n')).toEqual([]);
|
|
});
|
|
|
|
test('parses tab-separated rows', () => {
|
|
const body = '이름\t나이\t직책\n민지\t29\t디자이너\n준호\t31\t개발자';
|
|
expect(parseTsvBody(body)).toEqual([
|
|
['이름', '나이', '직책'],
|
|
['민지', '29', '디자이너'],
|
|
['준호', '31', '개발자'],
|
|
]);
|
|
});
|
|
|
|
test('falls back to pipe-separated when no tab present', () => {
|
|
const body = '이름 | 나이\n민지 | 29\n준호 | 31';
|
|
expect(parseTsvBody(body)).toEqual([
|
|
['이름', '나이'],
|
|
['민지', '29'],
|
|
['준호', '31'],
|
|
]);
|
|
});
|
|
|
|
test('strips leading and trailing blank lines (LLM artifact)', () => {
|
|
const body = '\n\n이름\t나이\n민지\t29\n\n';
|
|
expect(parseTsvBody(body)).toEqual([
|
|
['이름', '나이'],
|
|
['민지', '29'],
|
|
]);
|
|
});
|
|
|
|
test('preserves empty cells when tabs are present', () => {
|
|
const body = 'A\t\tC';
|
|
expect(parseTsvBody(body)).toEqual([['A', '', 'C']]);
|
|
});
|
|
});
|
|
|
|
describe('valuesToMarkdownTable', () => {
|
|
test('empty → placeholder', () => {
|
|
expect(valuesToMarkdownTable([])).toBe('_(empty)_');
|
|
});
|
|
|
|
test('renders header + separator + rows', () => {
|
|
const out = valuesToMarkdownTable([
|
|
['이름', '나이'],
|
|
['민지', 29],
|
|
['준호', 31],
|
|
]);
|
|
const lines = out.split('\n');
|
|
expect(lines[0]).toBe('| 이름 | 나이 |');
|
|
expect(lines[1]).toBe('|---|---|');
|
|
expect(lines[2]).toBe('| 민지 | 29 |');
|
|
expect(lines[3]).toBe('| 준호 | 31 |');
|
|
});
|
|
|
|
test('truncates beyond maxRows + adds note', () => {
|
|
const big: any[][] = [['col']];
|
|
for (let i = 0; i < 60; i++) big.push([`row${i}`]);
|
|
const out = valuesToMarkdownTable(big, 10);
|
|
expect(out).toContain('| col |');
|
|
expect(out).toContain('| row0 |');
|
|
expect(out).toContain('| row8 |'); // 10 rows total = header + 9 data
|
|
expect(out).not.toContain('| row9 |');
|
|
expect(out).toContain('51 more rows truncated');
|
|
});
|
|
|
|
test('escapes pipe characters inside cell values', () => {
|
|
const out = valuesToMarkdownTable([
|
|
['a|b', 'c'],
|
|
['d', 'e|f'],
|
|
]);
|
|
expect(out).toContain('| a\\|b | c |');
|
|
expect(out).toContain('| d | e\\|f |');
|
|
});
|
|
});
|
|
|
|
describe('_parseSheetAttrs', () => {
|
|
test('parses spreadsheet_id + range with double quotes', () => {
|
|
const a = _parseSheetAttrs(' spreadsheet_id="1abc" range="Sheet1!A1:D20" ');
|
|
expect(a.spreadsheetId).toBe('1abc');
|
|
expect(a.range).toBe('Sheet1!A1:D20');
|
|
});
|
|
|
|
test('accepts camelCase alias spreadsheetId', () => {
|
|
const a = _parseSheetAttrs('spreadsheetId="1xyz" range="A:B"');
|
|
expect(a.spreadsheetId).toBe('1xyz');
|
|
});
|
|
|
|
test('accepts sheet_id alias', () => {
|
|
const a = _parseSheetAttrs(`sheet_id='1qrs' range='Tab1'`);
|
|
expect(a.spreadsheetId).toBe('1qrs');
|
|
expect(a.range).toBe('Tab1');
|
|
});
|
|
|
|
test('parses bare (unquoted) values', () => {
|
|
const a = _parseSheetAttrs('spreadsheet_id=1simple range=Sheet1!A1');
|
|
expect(a.spreadsheetId).toBe('1simple');
|
|
expect(a.range).toBe('Sheet1!A1');
|
|
});
|
|
|
|
test('returns empty for missing attrs', () => {
|
|
expect(_parseSheetAttrs('')).toEqual({});
|
|
expect(_parseSheetAttrs('foo="bar"')).toEqual({});
|
|
});
|
|
});
|