Merge branch 'main' into refactor/relay-list-label-consolidation-6018169095734119060

This commit is contained in:
thePR0M3TH3AN authored and GitHub committed 2026-02-20 16:41:31 -05:00
commit b296303b19
43 files changed
+7886 -249

No files matched your search

+98
View File
@@ -0,0 +1,98 @@
import { mock, describe, it, before, after, beforeEach } from 'node:test';
import assert from 'node:assert';
// Mock process.exit
const originalExit = process.exit;
let exitMock;
// Mock console
const originalError = console.error;
let errorMock;
const originalLog = console.log;
let logMock;
describe('main dispatch', () => {
let main;
before(async () => {
exitMock = mock.fn();
process.exit = exitMock;
errorMock = mock.fn();
console.error = errorMock;
logMock = mock.fn();
console.log = logMock;
// We import main
// Since we cannot mock modules easily in this environment (mock.module missing),
// we will rely on testing the error paths of the handlers, which don't trigger side effects.
const mod = await import('../src/lib.mjs');
main = mod.main;
});
after(() => {
process.exit = originalExit;
console.error = originalError;
console.log = originalLog;
mock.reset();
});
beforeEach(() => {
exitMock.mock.resetCalls();
errorMock.mock.resetCalls();
logMock.mock.resetCalls();
});
it('should exit with code 1 if no command provided', async () => {
await main([]);
assert.strictEqual(exitMock.mock.callCount(), 1);
assert.strictEqual(exitMock.mock.calls[0].arguments[0], 1);
});
it('should exit with code 1 if unknown command provided', async () => {
await main(['unknown']);
assert.strictEqual(exitMock.mock.callCount(), 1);
assert.strictEqual(exitMock.mock.calls[0].arguments[0], 1);
const unknownMsg = errorMock.mock.calls.find(c => c.arguments[0].includes('Unknown command'));
assert.ok(unknownMsg);
});
it('should exit with code 1 if check command misses cadence', async () => {
await main(['check']);
assert.strictEqual(exitMock.mock.callCount(), 1);
assert.strictEqual(exitMock.mock.calls[0].arguments[0], 1);
const missingMsg = errorMock.mock.calls.find(c => c.arguments[0].includes('required for check'));
assert.ok(missingMsg);
});
it('should exit with code 1 if lock command misses agent', async () => {
await main(['lock']);
assert.strictEqual(exitMock.mock.callCount(), 1);
assert.strictEqual(exitMock.mock.calls[0].arguments[0], 1);
const missingMsg = errorMock.mock.calls.find(c => c.arguments[0].includes('required for lock'));
assert.ok(missingMsg);
});
it('should exit with code 1 if complete command misses agent', async () => {
await main(['complete']);
assert.strictEqual(exitMock.mock.callCount(), 1);
assert.strictEqual(exitMock.mock.calls[0].arguments[0], 1);
const missingMsg = errorMock.mock.calls.find(c => c.arguments[0].includes('required for complete'));
assert.ok(missingMsg);
});
it('should exit with code 1 if proposal command misses subcommand', async () => {
await main(['proposal']);
assert.strictEqual(exitMock.mock.callCount(), 1);
assert.strictEqual(exitMock.mock.calls[0].arguments[0], 1);
const missingMsg = errorMock.mock.calls.find(c => c.arguments[0].includes('Missing subcommand'));
assert.ok(missingMsg);
});
});
+51
View File
@@ -0,0 +1,51 @@
import { describe, it } from 'node:test';
import assert from 'node:assert';
import { withTimeout } from '../src/utils.mjs';
describe('Async Utilities', () => {
describe('withTimeout', () => {
it('resolves when promise completes before timeout', async () => {
const result = await withTimeout(
new Promise((resolve) => setTimeout(() => resolve('success'), 10)),
200,
'Timed out'
);
assert.strictEqual(result, 'success');
});
it('rejects when promise times out', async () => {
try {
await withTimeout(
new Promise((resolve) => setTimeout(() => resolve('success'), 200)),
10,
'Operation timed out'
);
assert.fail('Should have rejected');
} catch (err) {
assert.strictEqual(err.message, 'Operation timed out');
}
});
it('clears timeout on success', async () => {
const result = await withTimeout(
Promise.resolve('fast'),
1000,
'timeout'
);
assert.strictEqual(result, 'fast');
});
it('propagates original promise rejection', async () => {
try {
await withTimeout(
Promise.reject(new Error('Original error')),
100,
'Timeout'
);
assert.fail('Should have rejected');
} catch (err) {
assert.strictEqual(err.message, 'Original error');
}
});
});
});
+17
View File
@@ -59,6 +59,23 @@ describe('Date Utilities', () => {
});
});
describe('Relay Utilities', () => {
describe('mergeRelayList', () => {
it('merges two lists of relays without duplicates', () => {
const primary = ['wss://relay1.com', 'wss://relay2.com'];
const fallback = ['wss://relay2.com', 'wss://relay3.com'];
const merged = mergeRelayList(primary, fallback);
assert.deepStrictEqual(merged, ['wss://relay1.com', 'wss://relay2.com', 'wss://relay3.com']);
});
it('handles empty lists', () => {
assert.deepStrictEqual(mergeRelayList([], []), []);
assert.deepStrictEqual(mergeRelayList(['wss://relay1.com'], []), ['wss://relay1.com']);
assert.deepStrictEqual(mergeRelayList([], ['wss://relay1.com']), ['wss://relay1.com']);
});
});
});
describe('Platform Utilities', () => {
describe('detectPlatform', () => {
const originalEnv = { ...process.env };