Files
everything-claude-code/tests/lib/install-state.test.js
Affaan Mustafa 131f977841 feat: strengthen install lifecycle and target adapters (#512)
* fix: strengthen install lifecycle adapters

* fix: restore template content on uninstall
2026-03-15 21:47:31 -07:00

232 lines
6.2 KiB
JavaScript

/**
* Tests for scripts/lib/install-state.js
*/
const assert = require('assert');
const fs = require('fs');
const os = require('os');
const path = require('path');
const {
createInstallState,
readInstallState,
writeInstallState,
} = require('../../scripts/lib/install-state');
function test(name, fn) {
try {
fn();
console.log(` \u2713 ${name}`);
return true;
} catch (error) {
console.log(` \u2717 ${name}`);
console.log(` Error: ${error.message}`);
return false;
}
}
function createTestDir() {
return fs.mkdtempSync(path.join(os.tmpdir(), 'install-state-'));
}
function cleanupTestDir(dirPath) {
fs.rmSync(dirPath, { recursive: true, force: true });
}
function runTests() {
console.log('\n=== Testing install-state.js ===\n');
let passed = 0;
let failed = 0;
if (test('creates a valid install-state payload', () => {
const state = createInstallState({
adapter: { id: 'cursor-project' },
targetRoot: '/repo/.cursor',
installStatePath: '/repo/.cursor/ecc-install-state.json',
request: {
profile: 'developer',
modules: ['orchestration'],
legacyLanguages: ['typescript'],
legacyMode: true,
},
resolution: {
selectedModules: ['rules-core', 'orchestration'],
skippedModules: [],
},
operations: [
{
kind: 'copy-path',
moduleId: 'rules-core',
sourceRelativePath: 'rules',
destinationPath: '/repo/.cursor/rules',
strategy: 'preserve-relative-path',
ownership: 'managed',
scaffoldOnly: true,
},
],
source: {
repoVersion: '1.9.0',
repoCommit: 'abc123',
manifestVersion: 1,
},
installedAt: '2026-03-13T00:00:00Z',
});
assert.strictEqual(state.schemaVersion, 'ecc.install.v1');
assert.strictEqual(state.target.id, 'cursor-project');
assert.strictEqual(state.request.profile, 'developer');
assert.strictEqual(state.operations.length, 1);
})) passed++; else failed++;
if (test('writes and reads install-state from disk', () => {
const testDir = createTestDir();
const statePath = path.join(testDir, 'ecc-install-state.json');
try {
const state = createInstallState({
adapter: { id: 'claude-home' },
targetRoot: path.join(testDir, '.claude'),
installStatePath: statePath,
request: {
profile: 'core',
modules: [],
legacyLanguages: [],
legacyMode: false,
},
resolution: {
selectedModules: ['rules-core'],
skippedModules: [],
},
operations: [],
source: {
repoVersion: '1.9.0',
repoCommit: 'abc123',
manifestVersion: 1,
},
});
writeInstallState(statePath, state);
const loaded = readInstallState(statePath);
assert.strictEqual(loaded.target.id, 'claude-home');
assert.strictEqual(loaded.request.profile, 'core');
assert.deepStrictEqual(loaded.resolution.selectedModules, ['rules-core']);
} finally {
cleanupTestDir(testDir);
}
})) passed++; else failed++;
if (test('deep-clones nested operation metadata for lifecycle-managed operations', () => {
const operation = {
kind: 'merge-json',
moduleId: 'platform-configs',
sourceRelativePath: '.cursor/hooks.json',
destinationPath: '/repo/.cursor/hooks.json',
strategy: 'merge-json',
ownership: 'managed',
scaffoldOnly: false,
mergePayload: {
nested: {
enabled: true,
},
},
previousValue: {
nested: {
enabled: false,
},
},
};
const state = createInstallState({
adapter: { id: 'cursor-project' },
targetRoot: '/repo/.cursor',
installStatePath: '/repo/.cursor/ecc-install-state.json',
request: {
profile: null,
modules: ['platform-configs'],
legacyLanguages: [],
legacyMode: false,
},
resolution: {
selectedModules: ['platform-configs'],
skippedModules: [],
},
operations: [operation],
source: {
repoVersion: '1.9.0',
repoCommit: 'abc123',
manifestVersion: 1,
},
});
operation.mergePayload.nested.enabled = false;
operation.previousValue.nested.enabled = true;
assert.strictEqual(state.operations[0].mergePayload.nested.enabled, true);
assert.strictEqual(state.operations[0].previousValue.nested.enabled, false);
})) passed++; else failed++;
if (test('rejects invalid install-state payloads on read', () => {
const testDir = createTestDir();
const statePath = path.join(testDir, 'ecc-install-state.json');
try {
fs.writeFileSync(statePath, JSON.stringify({ schemaVersion: 'ecc.install.v1' }, null, 2));
assert.throws(
() => readInstallState(statePath),
/Invalid install-state/
);
} finally {
cleanupTestDir(testDir);
}
})) passed++; else failed++;
if (test('rejects unexpected properties and missing required request fields', () => {
const testDir = createTestDir();
const statePath = path.join(testDir, 'ecc-install-state.json');
try {
fs.writeFileSync(statePath, JSON.stringify({
schemaVersion: 'ecc.install.v1',
installedAt: '2026-03-13T00:00:00Z',
unexpected: true,
target: {
id: 'cursor-project',
root: '/repo/.cursor',
installStatePath: '/repo/.cursor/ecc-install-state.json',
},
request: {
modules: [],
includeComponents: [],
excludeComponents: [],
legacyLanguages: [],
legacyMode: false,
},
resolution: {
selectedModules: [],
skippedModules: [],
},
source: {
repoVersion: '1.9.0',
repoCommit: 'abc123',
manifestVersion: 1,
},
operations: [],
}, null, 2));
assert.throws(
() => readInstallState(statePath),
/Invalid install-state/
);
} finally {
cleanupTestDir(testDir);
}
})) passed++; else failed++;
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
process.exit(failed > 0 ? 1 : 0);
}
runTests();