✨ feature: Implement Gmail message fetching and Excel sheet name truncation
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
import { mkdtemp, rm } from 'node:fs/promises';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
||||
import XLSX from 'xlsx';
|
||||
import { ExcelWriter } from '../src/output/excel.js';
|
||||
|
||||
let dir = '';
|
||||
|
||||
beforeEach(async () => {
|
||||
dir = await mkdtemp(join(tmpdir(), 'nlc-excel-'));
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await rm(dir, { force: true, recursive: true });
|
||||
});
|
||||
|
||||
describe('ExcelWriter', () => {
|
||||
it('truncates newsletter sheet names to the Excel 31-character limit', async () => {
|
||||
const path = join(dir, 'catalog.xlsx');
|
||||
const newsletter = 'A Very Long Newsletter Name That Exceeds The Excel Limit';
|
||||
|
||||
await new ExcelWriter(path).write({
|
||||
rows: [
|
||||
{
|
||||
'Source Newsletter': newsletter,
|
||||
Title: 'Post',
|
||||
'Link URL': 'https://example.com'
|
||||
}
|
||||
],
|
||||
sponsors: [],
|
||||
deadLinks: []
|
||||
});
|
||||
|
||||
const workbook = XLSX.readFile(path);
|
||||
expect(workbook.SheetNames[0]).toBe('A Very Long Newsletter Name Tha');
|
||||
expect(workbook.SheetNames[0].length).toBe(31);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,79 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { buildBrowserCommand, GmailClient } from '../src/gmail/client.js';
|
||||
|
||||
describe('GmailClient', () => {
|
||||
it('uses PowerShell to open Windows OAuth URLs without splitting query parameters', () => {
|
||||
const url =
|
||||
'https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&response_type=code';
|
||||
|
||||
expect(buildBrowserCommand(url, 'win32')).toEqual({
|
||||
file: 'powershell.exe',
|
||||
args: ['-NoProfile', '-Command', 'Start-Process -FilePath $args[0]', url]
|
||||
});
|
||||
});
|
||||
|
||||
it('loads HTML messages from the configured Gmail label', async () => {
|
||||
const calls: string[] = [];
|
||||
const gmail = {
|
||||
users: {
|
||||
labels: {
|
||||
list: async () => ({
|
||||
data: { labels: [{ id: 'Label_1', name: 'Newsletters' }] }
|
||||
})
|
||||
},
|
||||
messages: {
|
||||
list: async (_params: unknown) => {
|
||||
calls.push('list');
|
||||
return { data: { messages: [{ id: 'msg-1' }] } };
|
||||
},
|
||||
get: async () => {
|
||||
calls.push('get');
|
||||
return {
|
||||
data: {
|
||||
id: 'msg-1',
|
||||
payload: {
|
||||
headers: [
|
||||
{ name: 'Message-ID', value: '<msg-1@example.com>' },
|
||||
{ name: 'From', value: 'Weekly <weekly@example.com>' },
|
||||
{ name: 'Date', value: 'Sat, 16 May 2026 10:00:00 -0500' }
|
||||
],
|
||||
parts: [
|
||||
{
|
||||
mimeType: 'text/html',
|
||||
body: {
|
||||
data: Buffer.from(
|
||||
'<h2>Python</h2><a href="https://example.com">Post</a>'
|
||||
).toString('base64url')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const messages = await new GmailClient(gmail).fetchMessages('Newsletters', { maxResults: 5 });
|
||||
|
||||
expect(calls).toEqual(['list', 'get']);
|
||||
expect(messages).toEqual([
|
||||
{
|
||||
id: 'msg-1',
|
||||
messageId: '<msg-1@example.com>',
|
||||
from: 'Weekly <weekly@example.com>',
|
||||
date: '2026-05-16T15:00:00.000Z',
|
||||
subject: '',
|
||||
html: '<h2>Python</h2><a href="https://example.com">Post</a>',
|
||||
headers: {
|
||||
date: 'Sat, 16 May 2026 10:00:00 -0500',
|
||||
from: 'Weekly <weekly@example.com>',
|
||||
listId: undefined,
|
||||
messageId: '<msg-1@example.com>',
|
||||
subject: ''
|
||||
}
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user