Files
openchamber/packages/web/server/lib/opencode/snippets.test.js
T
Isaac Sanchez-HawkinsandIsaac Sanchez b764577943 fix: preserve canonical snippet names (#1380)
* fix: preserve canonical snippet names

* test: cover same-directory snippet alias precedence

---------

Co-authored-by: Isaac Sanchez <isanchez-hawkins@arize.com>
2026-05-23 20:51:45 +03:00

98 lines
4.1 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('canonical snippet names take precedence over colliding aliases', () => {
writeSnippet('.opencode/snippets/review.md', 'Review by name');
writeSnippet('.opencode/snippet/helper.md', '---\naliases: [review, help]\n---\nReview by alias');
expect(getSnippet('review', projectDir)).toEqual(expect.objectContaining({ name: 'review', content: 'Review by name' }));
expect(getSnippet('help', projectDir)).toEqual(expect.objectContaining({ name: 'helper', content: 'Review by alias' }));
expect(expandSnippets('Use #review and #help', projectDir)).toBe('Use Review by name and Review by alias');
});
test('canonical snippet names override earlier same-directory aliases', () => {
writeSnippet('.opencode/snippet/alias-first.md', '---\naliases: [review, assist]\n---\nReview by alias');
writeSnippet('.opencode/snippet/review.md', 'Review by name');
const snippetDir = path.join(projectDir, '.opencode', 'snippet');
const originalReaddirSync = fs.readdirSync;
fs.readdirSync = function readdirSync(dir, ...args) {
if (dir === snippetDir) return ['alias-first.md', 'review.md'];
return originalReaddirSync.call(fs, dir, ...args);
};
try {
expect(getSnippet('review', projectDir)).toEqual(expect.objectContaining({ name: 'review', content: 'Review by name' }));
expect(getSnippet('assist', projectDir)).toEqual(expect.objectContaining({ name: 'alias-first', content: 'Review by alias' }));
expect(expandSnippets('Use #review and #assist', projectDir)).toBe('Use Review by name and Review by alias');
} finally {
fs.readdirSync = originalReaddirSync;
}
});
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');
});
});