Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .github/workflows/nodejs-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Node.js Tests

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
node-tests:
name: Node.js Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Use Node.js 20
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Cache node modules
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-

- name: Install dependencies
run: npm ci

- name: Discover packages
id: discover
run: |
echo "Finding packages with tests..."
PACKAGES=$(node -e "const fs=require('fs');const dirs=fs.readdirSync('.').filter(d=>fs.statSync(d).isDirectory() && fs.existsSync(d+'/tests'));console.log(JSON.stringify(dirs))")
echo "PACKAGES=$PACKAGES" >> $GITHUB_OUTPUT

- name: Run tests
env:
PACKAGES: ${{ steps.discover.outputs.PACKAGES }}
run: |
PACKAGES_ENV="$PACKAGES"
PACKAGES=$(node -e "console.log(JSON.parse(process.env.PACKAGES || '[]').join(' '))")
echo "Discovered packages: $PACKAGES"
if [ -z "$PACKAGES" ]; then
echo "No packages found, running root tests"
npm test
exit 0
fi
for p in $PACKAGES; do
echo "Running tests for $p"
npx jest "$p/tests" --colors || exit 1
done
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
coverage/
.env
35 changes: 35 additions & 0 deletions gmail-to-drive-by-labels/tests/gas-utils.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const { getCleanBody, getFileHash } = require('../../src/gas-utils');

describe('getCleanBody', () => {
test('returns empty string for falsy input', () => {
expect(getCleanBody(null)).toBe('');
expect(getCleanBody('')).toBe('');
});

test('removes quoted lines starting with > and <', () => {
const input = 'Hello\n> quoted line\n< another quote\nWorld';
expect(getCleanBody(input)).toBe('Hello\nWorld');
});

test('cuts off at reply header (On ... wrote:)', () => {
const input = 'Line1\nOn Jan 1, 2020, John Doe <john@example.com> wrote:\nQuoted';
expect(getCleanBody(input)).toBe('Line1');
});

test('cuts off at confidentiality notice', () => {
const input = 'Message body\nThis is a confidentiality notice: do not share';
expect(getCleanBody(input)).toBe('Message body');
});
});

describe('getFileHash', () => {
test('computes md5 for a Buffer', () => {
const buf = Buffer.from('hello world');
expect(getFileHash(buf)).toBe('5eb63bbbe01eeed093cb22bb8f5acdc3');
});

test('computes md5 for an object with getBytes()', () => {
const blob = { getBytes: () => Buffer.from('abc') };
expect(getFileHash(blob)).toBe('900150983cd24fb0d6963f7d28e17f72');
});
});
32 changes: 32 additions & 0 deletions gmail-to-drive-by-labels/tests/mocks.integration.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const { createMessage, createBlob } = require('../../test-utils/mocks');

describe('Apps Script mocks integration', () => {
test('GmailApp createLabel and thread handling', () => {
const label = global.GmailApp.createLabel('TEST');
const msg = createMessage({ subject: 'Hi', body: 'Hello' });
const thread = global.GmailApp.__addThreadWithLabels(['TEST'], [msg]);

const found = global.GmailApp.getUserLabelByName('TEST');
expect(found).not.toBeNull();
const threads = found.getThreads();
expect(threads.length).toBe(1);
expect(threads[0].getMessages()[0].getSubject()).toBe('Hi');
});

test('DocumentApp appendParagraph and DriveApp deduplication helpers', () => {
const doc = global.DocumentApp.openById('doc-1');
const body = doc.getBody();
body.appendParagraph('Hello');
expect(body.getParagraphs().length).toBe(1);

const folder = global.DriveApp.getFolderById('f-1');
const b1 = createBlob('a', 'foo.txt');
const b2 = createBlob('a', 'foo.txt');
const f1 = folder.createFile(b1);
// files with same content should be separate objects but can be compared by getBlob
const existing = folder.getFilesByName('foo.txt');
expect(existing.hasNext()).toBe(true);
const file = existing.next();
expect(file.getBlob().getBytes().toString()).toBe(Buffer.from('a').toString());
});
});
5 changes: 5 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
testEnvironment: 'node',
setupFilesAfterEnv: ['<rootDir>/test-utils/setup.js'],
testMatch: ['**/tests/**/*.test.[jt]s?(x)']
};
Loading