test: add unit tests for roster loading logic

- Implemented dependency injection in `src/roster.mjs` to allow mocking `fs` and `loadTorchConfig`.
- Added `test/roster.test.mjs` with comprehensive test cases:
    - Fallback behavior when no files/config exist.
    - Priority of `torch/roster.json` (User Roster) over `roster.json` (CWD).
    - Internal module roster fallback.
    - Environment variable overrides.
    - Configuration overrides.
    - Error handling for malformed JSON or missing fields.
- Exported `_resetRosterCache`, `_setRosterDependencies`, and `_restoreRosterDependencies` for testing purposes.

Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
google-labs-jules[bot]andPR0M3TH3AN committed 2026-02-18 03:31:12 +00:00
1 parent cea50da512
commit a31332457d
2 files changed
+183 -4

No files matched your search

+26 -4
View File
@@ -3,6 +3,23 @@ import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { loadTorchConfig } from './torch-config.mjs';
const defaultDeps = {
fs,
loadTorchConfig,
};
const deps = { ...defaultDeps };
/** @internal */
export function _setRosterDependencies(overrides) {
Object.assign(deps, overrides);
}
/** @internal */
export function _restoreRosterDependencies() {
Object.assign(deps, defaultDeps);
}
const ROSTER_FILE = path.resolve(path.dirname(fileURLToPath(import.meta.url)), 'prompts/roster.json');
const USER_ROSTER_FILE = path.resolve(process.cwd(), 'torch/roster.json');
const CWD_ROSTER_FILE = path.resolve(process.cwd(), 'roster.json');
@@ -59,14 +76,14 @@ function loadCanonicalRoster() {
let rosterPath = ROSTER_FILE;
// Prefer user-managed roster if present
if (fs.existsSync(USER_ROSTER_FILE)) {
if (deps.fs.existsSync(USER_ROSTER_FILE)) {
rosterPath = USER_ROSTER_FILE;
} else if (fs.existsSync(CWD_ROSTER_FILE)) {
} else if (deps.fs.existsSync(CWD_ROSTER_FILE)) {
rosterPath = CWD_ROSTER_FILE;
}
try {
const parsed = JSON.parse(fs.readFileSync(rosterPath, 'utf8'));
const parsed = JSON.parse(deps.fs.readFileSync(rosterPath, 'utf8'));
const daily = Array.isArray(parsed.daily) ? parsed.daily.map((item) => String(item).trim()).filter(Boolean) : [];
const weekly = Array.isArray(parsed.weekly)
? parsed.weekly.map((item) => String(item).trim()).filter(Boolean)
@@ -86,6 +103,11 @@ function loadCanonicalRoster() {
return cachedCanonicalRoster;
}
/** @internal */
export function _resetRosterCache() {
cachedCanonicalRoster = null;
}
function parseEnvRoster(value) {
if (!value) return null;
return value
@@ -95,7 +117,7 @@ function parseEnvRoster(value) {
}
export async function getRoster(cadence) {
const config = await loadTorchConfig();
const config = await deps.loadTorchConfig();
const dailyFromEnv = parseEnvRoster(process.env.NOSTR_LOCK_DAILY_ROSTER);
const weeklyFromEnv = parseEnvRoster(process.env.NOSTR_LOCK_WEEKLY_ROSTER);
const canonical = loadCanonicalRoster();