Files
ECC/tests/lib/github-coordination-policy.test.js
T
Alexis D.andGitHub ff15079b9f test(lib): extract shared mini test runner for coordination tests (#2663)
Address CodeRabbit review on #2311: dedupe the local test(name, fn)
harness and route all reporter output through a shared helper
(tests/lib/helpers/mini-test-runner.js) instead of direct console.log.
2026-08-04 00:29:31 -04:00

300 lines
10 KiB
JavaScript

/**
* Tests for scripts/lib/github-coordination/policy.js — loadPolicy branch coverage
*
* Run with: node tests/lib/github-coordination-policy.test.js
*/
'use strict';
const assert = require('assert');
const fs = require('fs');
const os = require('os');
const path = require('path');
const {
loadPolicy,
DEFAULT_POLICY,
DEFAULT_LABELS,
DEFAULT_SCHEMA_VERSION,
DEFAULT_SECTION_MARKER,
} = require('../../scripts/lib/github-coordination/policy');
const { test, banner, section, summary } = require('./helpers/mini-test-runner');
function withTempDir(fn) {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-policy-test-'));
try {
fn(tmpDir);
} finally {
fs.rmSync(tmpDir, { recursive: true, force: true });
}
}
function writeConfig(tmpDir, content) {
const configDir = path.join(tmpDir, 'config');
fs.mkdirSync(configDir, { recursive: true });
const configPath = path.join(configDir, 'github-native-coordination.json');
fs.writeFileSync(configPath, typeof content === 'string' ? content : JSON.stringify(content));
return configPath;
}
let passed = 0;
let failed = 0;
banner('Testing github-coordination/policy.js');
section('loadPolicy — no config file:');
if (test('returns default policy when no config file exists in rootDir', () => {
withTempDir(tmpDir => {
const result = loadPolicy(tmpDir);
assert.strictEqual(result.sourcePath, null);
assert.strictEqual(result.schemaVersion, DEFAULT_SCHEMA_VERSION);
assert.strictEqual(result.sectionMarker, DEFAULT_SECTION_MARKER);
assert.deepStrictEqual(result.labels, DEFAULT_LABELS);
assert.deepStrictEqual(result.review, DEFAULT_POLICY.review);
});
})) passed++; else failed++;
if (test('returns default policy when custom configPath does not exist', () => {
withTempDir(tmpDir => {
const result = loadPolicy(tmpDir, path.join(tmpDir, 'nonexistent.json'));
assert.strictEqual(result.sourcePath, null);
assert.deepStrictEqual(result.review, DEFAULT_POLICY.review);
});
})) passed++; else failed++;
section('loadPolicy — configPath argument:');
if (test('uses configPath when explicitly provided', () => {
withTempDir(tmpDir => {
const configPath = path.join(tmpDir, 'my-policy.json');
fs.writeFileSync(configPath, JSON.stringify({ schemaVersion: 'custom-v1' }));
const result = loadPolicy(tmpDir, configPath);
assert.strictEqual(result.sourcePath, configPath);
assert.strictEqual(result.schemaVersion, 'custom-v1');
});
})) passed++; else failed++;
if (test('falls back to rootDir config file when configPath is null', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, { schemaVersion: 'root-v1' });
const result = loadPolicy(tmpDir, null);
assert.strictEqual(result.schemaVersion, 'root-v1');
assert.ok(result.sourcePath !== null);
});
})) passed++; else failed++;
section('loadPolicy — invalid JSON:');
if (test('throws on invalid JSON', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, '{ bad json !!!! }');
assert.throws(() => loadPolicy(tmpDir), /Failed to load policy/);
});
})) passed++; else failed++;
section('loadPolicy — non-object JSON:');
if (test('throws when top-level JSON is null', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, 'null');
assert.throws(() => loadPolicy(tmpDir), /must contain a JSON object/);
});
})) passed++; else failed++;
if (test('throws when top-level JSON is an array', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, '[]');
assert.throws(() => loadPolicy(tmpDir), /must contain a JSON object/);
});
})) passed++; else failed++;
if (test('throws when top-level JSON is a string', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, '"just a string"');
assert.throws(() => loadPolicy(tmpDir), /must contain a JSON object/);
});
})) passed++; else failed++;
section('loadPolicy — labels merging:');
if (test('merges labels when parsed.labels is a plain object', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, { labels: { epic: 'my-epic' } });
const result = loadPolicy(tmpDir);
assert.strictEqual(result.labels.epic, 'my-epic');
assert.strictEqual(result.labels.available, DEFAULT_LABELS.available);
});
})) passed++; else failed++;
if (test('falls back to empty labels when parsed.labels is null', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, { labels: null });
const result = loadPolicy(tmpDir);
assert.deepStrictEqual(result.labels, DEFAULT_LABELS);
});
})) passed++; else failed++;
if (test('falls back to empty labels when parsed.labels is an array', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, { labels: ['a', 'b'] });
const result = loadPolicy(tmpDir);
assert.deepStrictEqual(result.labels, DEFAULT_LABELS);
});
})) passed++; else failed++;
if (test('falls back to empty labels when parsed.labels is a string', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, { labels: 'bad' });
const result = loadPolicy(tmpDir);
assert.deepStrictEqual(result.labels, DEFAULT_LABELS);
});
})) passed++; else failed++;
section('loadPolicy — review merging:');
if (test('merges review when parsed.review is a plain object', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, { review: { required: false } });
const result = loadPolicy(tmpDir);
assert.strictEqual(result.review.required, false);
assert.strictEqual(result.review.defaultMode, DEFAULT_POLICY.review.defaultMode);
});
})) passed++; else failed++;
if (test('falls back when parsed.review is not an object', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, { review: 'string' });
const result = loadPolicy(tmpDir);
assert.deepStrictEqual(result.review, DEFAULT_POLICY.review);
});
})) passed++; else failed++;
if (test('falls back when parsed.review is null', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, { review: null });
const result = loadPolicy(tmpDir);
assert.deepStrictEqual(result.review, DEFAULT_POLICY.review);
});
})) passed++; else failed++;
if (test('falls back when parsed.review is an array', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, { review: [] });
const result = loadPolicy(tmpDir);
assert.deepStrictEqual(result.review, DEFAULT_POLICY.review);
});
})) passed++; else failed++;
section('loadPolicy — validation merging:');
if (test('merges validation when parsed.validation is a plain object', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, { validation: { required: false } });
const result = loadPolicy(tmpDir);
assert.strictEqual(result.validation.required, false);
});
})) passed++; else failed++;
if (test('falls back when parsed.validation is not an object', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, { validation: 42 });
const result = loadPolicy(tmpDir);
assert.deepStrictEqual(result.validation, DEFAULT_POLICY.validation);
});
})) passed++; else failed++;
section('loadPolicy — branchModel merging:');
if (test('merges branchModel when parsed.branchModel is a plain object', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, { branchModel: { epicOnly: false, taskBranches: true } });
const result = loadPolicy(tmpDir);
assert.strictEqual(result.branchModel.epicOnly, false);
assert.strictEqual(result.branchModel.taskBranches, true);
});
})) passed++; else failed++;
if (test('falls back when parsed.branchModel is not an object', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, { branchModel: true });
const result = loadPolicy(tmpDir);
assert.deepStrictEqual(result.branchModel, DEFAULT_POLICY.branchModel);
});
})) passed++; else failed++;
section('loadPolicy — project merging:');
if (test('merges project when parsed.project is a plain object', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, { project: { enabled: true } });
const result = loadPolicy(tmpDir);
assert.strictEqual(result.project.enabled, true);
assert.deepStrictEqual(result.project.fieldNames, DEFAULT_POLICY.project.fieldNames);
});
})) passed++; else failed++;
if (test('falls back when parsed.project is not an object', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, { project: 'invalid' });
const result = loadPolicy(tmpDir);
assert.deepStrictEqual(result.project, DEFAULT_POLICY.project);
});
})) passed++; else failed++;
if (test('falls back when parsed.project is null', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, { project: null });
const result = loadPolicy(tmpDir);
assert.deepStrictEqual(result.project, DEFAULT_POLICY.project);
});
})) passed++; else failed++;
section('loadPolicy — project.fieldNames merging:');
if (test('merges fieldNames when project.fieldNames is a plain object', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, { project: { enabled: true, fieldNames: { status: 'MyStatus' } } });
const result = loadPolicy(tmpDir);
assert.strictEqual(result.project.fieldNames.status, 'MyStatus');
assert.strictEqual(result.project.fieldNames.owner, DEFAULT_POLICY.project.fieldNames.owner);
});
})) passed++; else failed++;
if (test('falls back when project.fieldNames is not an object', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, { project: { fieldNames: 'bad' } });
const result = loadPolicy(tmpDir);
assert.deepStrictEqual(result.project.fieldNames, DEFAULT_POLICY.project.fieldNames);
});
})) passed++; else failed++;
if (test('falls back when project.fieldNames is null', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, { project: { fieldNames: null } });
const result = loadPolicy(tmpDir);
assert.deepStrictEqual(result.project.fieldNames, DEFAULT_POLICY.project.fieldNames);
});
})) passed++; else failed++;
if (test('falls back when project.fieldNames is an array', () => {
withTempDir(tmpDir => {
writeConfig(tmpDir, { project: { fieldNames: [] } });
const result = loadPolicy(tmpDir);
assert.deepStrictEqual(result.project.fieldNames, DEFAULT_POLICY.project.fieldNames);
});
})) passed++; else failed++;
section('loadPolicy — sourcePath:');
if (test('sets sourcePath to the resolved config file path', () => {
withTempDir(tmpDir => {
const configPath = writeConfig(tmpDir, {});
const result = loadPolicy(tmpDir);
assert.strictEqual(result.sourcePath, configPath);
});
})) passed++; else failed++;
summary(passed, failed);