168 lines
5.1 KiB
TypeScript
168 lines
5.1 KiB
TypeScript
/**
|
|
* Tests for .takt-repertoire-lock.yaml generation and parsing.
|
|
*
|
|
* Covers:
|
|
* - extractCommitSha: parse SHA from tarball directory name {owner}-{repo}-{sha}/
|
|
* - generateLockFile: produces correct fields (source, ref, commit, imported_at)
|
|
* - ref defaults to "HEAD" when not specified
|
|
* - parseLockFile: reads .takt-repertoire-lock.yaml content
|
|
*/
|
|
|
|
import { describe, it, expect } from 'vitest';
|
|
import {
|
|
extractCommitSha,
|
|
generateLockFile,
|
|
parseLockFile,
|
|
} from '../../features/repertoire/lock-file.js';
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// extractCommitSha
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe('extractCommitSha', () => {
|
|
it('should extract SHA from standard tarball directory name', () => {
|
|
// Given: tarball directory name in {owner}-{repo}-{sha} format
|
|
const dirName = 'nrslib-takt-fullstack-abc1234def5678';
|
|
|
|
// When: SHA is extracted
|
|
const sha = extractCommitSha(dirName);
|
|
|
|
// Then: last segment (the SHA) is returned
|
|
expect(sha).toBe('abc1234def5678');
|
|
});
|
|
|
|
it('should extract SHA when repo name contains hyphens', () => {
|
|
// Given: repo name has multiple hyphens
|
|
const dirName = 'nrslib-takt-security-facets-deadbeef1234';
|
|
|
|
// When: SHA is extracted
|
|
const sha = extractCommitSha(dirName);
|
|
|
|
// Then: the last segment is the SHA
|
|
expect(sha).toBe('deadbeef1234');
|
|
});
|
|
|
|
it('should extract SHA when owner is a single word', () => {
|
|
// Given: simple owner and repo
|
|
const dirName = 'owner-repo-0123456789abcdef';
|
|
|
|
// When: SHA is extracted
|
|
const sha = extractCommitSha(dirName);
|
|
|
|
// Then: last segment is returned
|
|
expect(sha).toBe('0123456789abcdef');
|
|
});
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// generateLockFile
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe('generateLockFile', () => {
|
|
it('should produce lock file with all required fields', () => {
|
|
// Given: all parameters provided
|
|
const params = {
|
|
source: 'github:nrslib/takt-fullstack',
|
|
ref: 'v1.2.0',
|
|
commitSha: 'abc1234def5678',
|
|
importedAt: new Date('2026-02-20T12:00:00Z'),
|
|
};
|
|
|
|
// When: lock file is generated
|
|
const lock = generateLockFile(params);
|
|
|
|
// Then: all fields are present
|
|
expect(lock.source).toBe('github:nrslib/takt-fullstack');
|
|
expect(lock.ref).toBe('v1.2.0');
|
|
expect(lock.commit).toBe('abc1234def5678');
|
|
expect(lock.imported_at).toBe('2026-02-20T12:00:00.000Z');
|
|
});
|
|
|
|
it('should default ref to "HEAD" when ref is undefined', () => {
|
|
// Given: ref not specified
|
|
const params = {
|
|
source: 'github:nrslib/takt-security-facets',
|
|
ref: undefined,
|
|
commitSha: 'deadbeef1234',
|
|
importedAt: new Date('2026-01-01T00:00:00Z'),
|
|
};
|
|
|
|
// When: lock file is generated
|
|
const lock = generateLockFile(params);
|
|
|
|
// Then: ref is "HEAD"
|
|
expect(lock.ref).toBe('HEAD');
|
|
});
|
|
|
|
it('should record the exact commit SHA from the tarball directory', () => {
|
|
// Given: SHA from tarball extraction
|
|
const sha = '9f8e7d6c5b4a';
|
|
const params = {
|
|
source: 'github:someone/dotfiles',
|
|
ref: undefined,
|
|
commitSha: sha,
|
|
importedAt: new Date(),
|
|
};
|
|
|
|
// When: lock file is generated
|
|
const lock = generateLockFile(params);
|
|
|
|
// Then: commit SHA matches
|
|
expect(lock.commit).toBe(sha);
|
|
});
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// parseLockFile
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe('parseLockFile', () => {
|
|
it('should parse a valid .takt-repertoire-lock.yaml string', () => {
|
|
// Given: lock file YAML content
|
|
const yaml = `source: github:nrslib/takt-fullstack
|
|
ref: v1.2.0
|
|
commit: abc1234def5678
|
|
imported_at: 2026-02-20T12:00:00.000Z
|
|
`;
|
|
|
|
// When: parsed
|
|
const lock = parseLockFile(yaml);
|
|
|
|
// Then: all fields are present
|
|
expect(lock.source).toBe('github:nrslib/takt-fullstack');
|
|
expect(lock.ref).toBe('v1.2.0');
|
|
expect(lock.commit).toBe('abc1234def5678');
|
|
expect(lock.imported_at).toBe('2026-02-20T12:00:00.000Z');
|
|
});
|
|
|
|
it('should parse lock file with HEAD ref', () => {
|
|
// Given: lock file with HEAD ref (no tag specified at import)
|
|
const yaml = `source: github:acme-corp/takt-backend
|
|
ref: HEAD
|
|
commit: 789abcdef0123
|
|
imported_at: 2026-01-15T08:30:00.000Z
|
|
`;
|
|
|
|
// When: parsed
|
|
const lock = parseLockFile(yaml);
|
|
|
|
// Then: ref is "HEAD"
|
|
expect(lock.ref).toBe('HEAD');
|
|
expect(lock.commit).toBe('789abcdef0123');
|
|
});
|
|
|
|
it('should return empty-valued lock without crashing when yaml is empty string', () => {
|
|
// Given: empty yaml (lock file absent - existsSync guard fell through to '')
|
|
// yaml.parse('') returns null, which must not cause TypeError
|
|
|
|
// When: parsed
|
|
const lock = parseLockFile('');
|
|
|
|
// Then: returns defaults without throwing
|
|
expect(lock.source).toBe('');
|
|
expect(lock.ref).toBe('HEAD');
|
|
expect(lock.commit).toBe('');
|
|
expect(lock.imported_at).toBe('');
|
|
});
|
|
});
|