Files
TORCH/test/cmd-remove.test.mjs
T

146 lines
6.2 KiB
JavaScript

import { test, after } from 'node:test';
import assert from 'node:assert';
import fs from 'node:fs';
import path from 'node:path';
import { cmdInit } from '../src/ops.mjs';
import { cmdRemove } from '../src/cmd-remove.mjs';
const MOCK_CONFIG = {
installDir: 'torch',
namespace: 'test-namespace',
relays: ['wss://relay.damus.io']
};
const tempBase = fs.mkdtempSync(path.join(process.cwd(), 'test-ops-remove-'));
after(() => {
fs.rmSync(tempBase, { recursive: true, force: true });
});
test('cmdRemove reports nothing when no TORCH installation exists', async () => {
const projectRoot = path.join(tempBase, 'empty-project');
fs.mkdirSync(projectRoot, { recursive: true });
// Create a basic package.json so it looks like a real project
fs.writeFileSync(path.join(projectRoot, 'package.json'), JSON.stringify({ name: 'my-app' }));
// Should complete without error — just reports nothing found
await cmdRemove(true, projectRoot);
// Project should be untouched
assert.ok(fs.existsSync(path.join(projectRoot, 'package.json')), 'package.json still exists');
});
test('cmdRemove with --force removes torch/ directory', async () => {
const projectRoot = path.join(tempBase, 'project-force');
fs.mkdirSync(projectRoot, { recursive: true });
await cmdInit(false, projectRoot, MOCK_CONFIG);
// Verify init created the expected artifacts
assert.ok(fs.existsSync(path.join(projectRoot, 'torch')), 'torch/ exists before remove');
assert.ok(fs.existsSync(path.join(projectRoot, 'torch-config.json')), 'torch-config.json exists before remove');
assert.ok(fs.existsSync(path.join(projectRoot, '.torch')), '.torch/ exists before remove');
await cmdRemove(true, projectRoot);
// All TORCH artifacts should be gone
assert.ok(!fs.existsSync(path.join(projectRoot, 'torch')), 'torch/ removed');
assert.ok(!fs.existsSync(path.join(projectRoot, 'torch-config.json')), 'torch-config.json removed');
assert.ok(!fs.existsSync(path.join(projectRoot, '.torch')), '.torch/ removed');
});
test('cmdRemove removes runtime artifacts (task-logs, .scheduler-memory)', async () => {
const projectRoot = path.join(tempBase, 'project-runtime');
fs.mkdirSync(projectRoot, { recursive: true });
await cmdInit(false, projectRoot, MOCK_CONFIG);
// Simulate runtime artifacts that the scheduler would create
fs.mkdirSync(path.join(projectRoot, 'task-logs', 'daily'), { recursive: true });
fs.writeFileSync(path.join(projectRoot, 'task-logs', 'daily', 'run.md'), '# log');
fs.mkdirSync(path.join(projectRoot, '.scheduler-memory'), { recursive: true });
fs.writeFileSync(path.join(projectRoot, '.scheduler-memory', 'memory-store.json'), '{}');
await cmdRemove(true, projectRoot);
assert.ok(!fs.existsSync(path.join(projectRoot, 'task-logs')), 'task-logs/ removed');
assert.ok(!fs.existsSync(path.join(projectRoot, '.scheduler-memory')), '.scheduler-memory/ removed');
});
test('cmdRemove removes src/proposals/ and cleans empty src/', async () => {
const projectRoot = path.join(tempBase, 'project-proposals');
fs.mkdirSync(projectRoot, { recursive: true });
await cmdInit(false, projectRoot, MOCK_CONFIG);
// src/proposals/ is created by cmdInit
assert.ok(fs.existsSync(path.join(projectRoot, 'src', 'proposals')), 'src/proposals/ exists before remove');
await cmdRemove(true, projectRoot);
assert.ok(!fs.existsSync(path.join(projectRoot, 'src', 'proposals')), 'src/proposals/ removed');
// src/ should also be removed since it's now empty
assert.ok(!fs.existsSync(path.join(projectRoot, 'src')), 'empty src/ removed');
});
test('cmdRemove cleans torch:* scripts from host package.json', async () => {
const projectRoot = path.join(tempBase, 'project-scripts');
fs.mkdirSync(projectRoot, { recursive: true });
// Create a host package.json with existing user scripts
fs.writeFileSync(path.join(projectRoot, 'package.json'), JSON.stringify({
name: 'my-app',
scripts: {
test: 'jest',
build: 'webpack'
}
}, null, 2));
await cmdInit(false, projectRoot, MOCK_CONFIG);
// Verify init injected torch scripts
const pkgBefore = JSON.parse(fs.readFileSync(path.join(projectRoot, 'package.json'), 'utf8'));
assert.ok('torch:dashboard' in pkgBefore.scripts, 'torch:dashboard injected');
assert.ok('torch:check' in pkgBefore.scripts, 'torch:check injected');
await cmdRemove(true, projectRoot);
// User scripts should remain, torch scripts should be gone
const pkgAfter = JSON.parse(fs.readFileSync(path.join(projectRoot, 'package.json'), 'utf8'));
assert.strictEqual(pkgAfter.scripts.test, 'jest', 'user test script preserved');
assert.strictEqual(pkgAfter.scripts.build, 'webpack', 'user build script preserved');
assert.ok(!('torch:dashboard' in pkgAfter.scripts), 'torch:dashboard removed');
assert.ok(!('torch:check' in pkgAfter.scripts), 'torch:check removed');
assert.ok(!('torch:lock' in pkgAfter.scripts), 'torch:lock removed');
assert.ok(!('torch:health' in pkgAfter.scripts), 'torch:health removed');
assert.ok(!('torch:memory:list' in pkgAfter.scripts), 'torch:memory:list removed');
assert.ok(!('torch:memory:inspect' in pkgAfter.scripts), 'torch:memory:inspect removed');
});
test('cmdRemove cancels when user declines confirmation', async () => {
const projectRoot = path.join(tempBase, 'project-cancel');
fs.mkdirSync(projectRoot, { recursive: true });
await cmdInit(false, projectRoot, MOCK_CONFIG);
// Decline the confirmation
await cmdRemove(false, projectRoot, { confirm: false });
// Everything should still exist
assert.ok(fs.existsSync(path.join(projectRoot, 'torch')), 'torch/ still exists after cancel');
assert.ok(fs.existsSync(path.join(projectRoot, 'torch-config.json')), 'config still exists after cancel');
});
test('cmdRemove confirmed via mockAnswers removes artifacts', async () => {
const projectRoot = path.join(tempBase, 'project-confirm');
fs.mkdirSync(projectRoot, { recursive: true });
await cmdInit(false, projectRoot, MOCK_CONFIG);
// Confirm the removal
await cmdRemove(false, projectRoot, { confirm: true });
assert.ok(!fs.existsSync(path.join(projectRoot, 'torch')), 'torch/ removed after confirm');
assert.ok(!fs.existsSync(path.join(projectRoot, 'torch-config.json')), 'config removed after confirm');
});