google-docs-mcp / src /tools /docs /structureHelpers.test.ts
iFightDucks's picture
Initial HF Space deploy: a-bonus/google-docs-mcp with HF metadata
7dc28be
import { describe, expect, it } from 'vitest';
import { extractDocumentTables, findHeadings, getTableById } from './structureHelpers.js';
const mockDocument = {
body: {
content: [
{
startIndex: 1,
endIndex: 25,
paragraph: {
paragraphStyle: { namedStyleType: 'HEADING_2' },
elements: [{ textRun: { content: '今回のスプリントのタスク\n' } }],
},
},
{
startIndex: 25,
endIndex: 120,
table: {
tableRows: [
{
tableCells: [
{
startIndex: 30,
endIndex: 40,
content: [
{
paragraph: {
elements: [{ textRun: { content: 'No.\n' } }],
},
},
],
},
{
startIndex: 40,
endIndex: 60,
content: [
{
paragraph: {
elements: [{ textRun: { content: '課題名\n' } }],
},
},
],
},
],
},
{
tableCells: [
{
startIndex: 60,
endIndex: 78,
content: [
{
paragraph: {
elements: [{ textRun: { content: '1\n' } }],
},
},
],
},
{
startIndex: 78,
endIndex: 118,
content: [
{
paragraph: {
elements: [{ textRun: { content: 'SHIN-2870 調査\n' } }],
},
},
],
},
],
},
],
},
},
{
startIndex: 120,
endIndex: 145,
paragraph: {
paragraphStyle: { namedStyleType: 'HEADING_2' },
elements: [{ textRun: { content: '5. TDAからTAPへの確認事項\n' } }],
},
},
],
},
} as any;
describe('structureHelpers', () => {
it('extracts tables with dimensions and cell text', () => {
const tables = extractDocumentTables(mockDocument);
expect(tables).toHaveLength(1);
expect(tables[0]).toMatchObject({
tableId: 'table:body:0',
rowCount: 2,
columnCount: 2,
startIndex: 25,
endIndex: 120,
});
expect(tables[0].cells).toEqual([
{
rowIndex: 0,
columnIndex: 0,
startIndex: 30,
endIndex: 40,
contentStartIndex: null,
contentEndIndex: null,
text: 'No.',
},
{
rowIndex: 0,
columnIndex: 1,
startIndex: 40,
endIndex: 60,
contentStartIndex: null,
contentEndIndex: null,
text: '課題名',
},
{
rowIndex: 1,
columnIndex: 0,
startIndex: 60,
endIndex: 78,
contentStartIndex: null,
contentEndIndex: null,
text: '1',
},
{
rowIndex: 1,
columnIndex: 1,
startIndex: 78,
endIndex: 118,
contentStartIndex: null,
contentEndIndex: null,
text: 'SHIN-2870 調査',
},
]);
});
it('finds a table by its MCP table ID', () => {
const table = getTableById(mockDocument, 'table:body:0');
expect(table?.tableId).toBe('table:body:0');
expect(getTableById(mockDocument, 'table:body:999')).toBeNull();
});
it('finds heading sections and the next table following the heading', () => {
const sections = findHeadings(mockDocument, [
'今回のスプリントのタスク',
'5. TDAからTAPへの確認事項',
]);
expect(sections).toEqual([
{
headingText: '今回のスプリントのタスク',
headingLevel: 'HEADING_2',
startIndex: 1,
endIndex: 25,
tableIdFollowing: 'table:body:0',
},
{
headingText: '5. TDAからTAPへの確認事項',
headingLevel: 'HEADING_2',
startIndex: 120,
endIndex: 145,
tableIdFollowing: undefined,
},
]);
});
});