69 lines
2.5 KiB
JavaScript
69 lines
2.5 KiB
JavaScript
import { afterEach, beforeEach, describe, expect, test } from 'bun:test';
|
|||
|
|
import fs from 'fs';
|
||
|
|
import os from 'os';
|
||
|
|
import path from 'path';
|
||
|
|
import {
|
||
|
|
createSnippet,
|
||
|
|
deleteSnippet,
|
||
|
|
expandSnippets,
|
||
|
|
getSnippet,
|
||
|
|
listSnippets,
|
||
|
|
updateSnippet,
|
||
|
|
} from './snippets.js';
|
||
|
|
|
||
|
|
let projectDir;
|
||
|
|
|
||
|
|
function writeSnippet(relativePath, content) {
|
||
|
|
const filePath = path.join(projectDir, relativePath);
|
||
|
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
||
|
|
fs.writeFileSync(filePath, content, 'utf8');
|
||
|
|
}
|
||
|
|
|
||
|
|
describe('snippets', () => {
|
||
|
|
beforeEach(() => {
|
||
|
|
projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'openchamber-snippets-'));
|
||
|
|
});
|
||
|
|
|
||
|
|
afterEach(() => {
|
||
|
|
fs.rmSync(projectDir, { recursive: true, force: true });
|
||
|
|
});
|
||
|
|
|
||
|
|
test('loads project snippets with aliases and description', () => {
|
||
|
|
writeSnippet('.opencode/snippet/review.md', '---\naliases: [rev]\ndescription: Review helper\n---\nReview carefully.');
|
||
|
|
|
||
|
|
expect(listSnippets(projectDir)).toContainEqual(
|
||
|
|
expect.objectContaining({ name: 'review', aliases: ['rev'], description: 'Review helper', source: 'project' }),
|
||
|
|
);
|
||
|
|
expect(getSnippet('rev', projectDir)).toEqual(expect.objectContaining({ name: 'review' }));
|
||
|
|
});
|
||
|
|
|
||
|
|
test('snippet directory wins over snippets directory', () => {
|
||
|
|
writeSnippet('.opencode/snippets/same.md', 'Old');
|
||
|
|
writeSnippet('.opencode/snippet/same.md', 'New');
|
||
|
|
|
||
|
|
expect(getSnippet('same', projectDir)?.content).toBe('New');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('creates updates and deletes snippets', () => {
|
||
|
|
expect(createSnippet('custom-one', { content: 'Body', aliases: ['co'] }, projectDir, 'project')).toEqual(
|
||
|
|
expect.objectContaining({ name: 'custom-one', content: 'Body', aliases: ['co'] }),
|
||
|
|
);
|
||
|
|
expect(updateSnippet('custom-one', { content: 'Updated' }, projectDir)).toEqual(
|
||
|
|
expect.objectContaining({ name: 'custom-one', content: 'Updated', aliases: ['co'] }),
|
||
|
|
);
|
||
|
|
deleteSnippet('custom-one', projectDir);
|
||
|
|
expect(getSnippet('custom-one', projectDir)).toBeNull();
|
||
|
|
});
|
||
|
|
|
||
|
|
test('expands snippets recursively with prepend and append blocks', () => {
|
||
|
|
writeSnippet('.opencode/snippet/base.md', 'Base text');
|
||
|
|
writeSnippet('.opencode/snippet/review.md', '<prepend>Before</prepend>Review #base<append>After</append>');
|
||
|
|
|
||
|
|
expect(expandSnippets('Please #review', projectDir)).toBe('Before\n\nPlease Review Base text\n\nAfter');
|
||
|
|
});
|
||
|
|
|
||
|
|
test('rejects invalid snippet names', () => {
|
||
|
|
expect(() => createSnippet('../bad', { content: '' }, projectDir, 'project')).toThrow('Snippet name');
|
||
|
|
});
|
||
|
|
});
|