- 12 Semaphore tests: FIFO ordering, abort support, limit updates, listener cleanup - 8 Throttle tests: rate limiting, abort signal, concurrent consume, updateRate - 9 ConfigStore tests: defaults, merge, round-trip, corruption fallback, history cap - 12 UploadManager tests: progress events, retry, cancel, size filter, concurrency - 21 UI smoke tests: tab navigation, settings panels, statusbar, context menu - Fix: Semaphore.release() and updateLimit() now properly remove abort listeners Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
124 lines
4.4 KiB
JavaScript
124 lines
4.4 KiB
JavaScript
const { describe, it, beforeEach, afterEach } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const os = require('os');
|
|
const ConfigStore = require('../lib/config-store');
|
|
|
|
let tmpDir;
|
|
let store;
|
|
|
|
function createStore() {
|
|
const fakeApp = {
|
|
isPackaged: false,
|
|
getPath: () => tmpDir
|
|
};
|
|
// ConfigStore uses path.join(__dirname, '..') for non-packaged
|
|
// We override by setting filePath directly
|
|
store = new ConfigStore(fakeApp);
|
|
store.filePath = path.join(tmpDir, 'electron-config.json');
|
|
return store;
|
|
}
|
|
|
|
describe('ConfigStore', () => {
|
|
beforeEach(() => {
|
|
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cfg-test-'));
|
|
store = createStore();
|
|
});
|
|
|
|
afterEach(() => {
|
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
});
|
|
|
|
it('load returns defaults when file does not exist', () => {
|
|
const config = store.load();
|
|
assert.ok(config.hosters);
|
|
assert.ok(config.hosters['doodstream.com']);
|
|
assert.ok(config.hosters['voe.sx']);
|
|
assert.ok(config.hosters['vidmoly.me']);
|
|
assert.ok(config.hosters['byse.sx']);
|
|
assert.ok(config.hosterSettings);
|
|
assert.equal(config.hosterSettings['doodstream.com'].retries, 3);
|
|
assert.equal(config.hosterSettings['doodstream.com'].parallelCount, 2);
|
|
assert.equal(config.globalSettings.alwaysOnTop, false);
|
|
assert.equal(config.globalSettings.shutdownAfterFinish, 'nothing');
|
|
assert.deepEqual(config.history, []);
|
|
});
|
|
|
|
it('save then load round-trips', () => {
|
|
store.save({ hosters: { 'doodstream.com': { enabled: true, apiKey: 'test-key-123' } } });
|
|
const config = store.load();
|
|
assert.equal(config.hosters['doodstream.com'].apiKey, 'test-key-123');
|
|
});
|
|
|
|
it('load merges with defaults for missing hosters', () => {
|
|
// Write partial config
|
|
fs.writeFileSync(store.filePath, JSON.stringify({
|
|
hosters: { 'doodstream.com': { apiKey: 'abc' } }
|
|
}), 'utf-8');
|
|
|
|
const config = store.load();
|
|
assert.equal(config.hosters['doodstream.com'].apiKey, 'abc');
|
|
// Other hosters should still have defaults
|
|
assert.equal(config.hosters['voe.sx'].enabled, true);
|
|
assert.equal(config.hosters['voe.sx'].apiKey, '');
|
|
});
|
|
|
|
it('hosterSettings merge fills gaps with defaults', () => {
|
|
fs.writeFileSync(store.filePath, JSON.stringify({
|
|
hosterSettings: { 'voe.sx': { retries: 5 } }
|
|
}), 'utf-8');
|
|
|
|
const config = store.load();
|
|
assert.equal(config.hosterSettings['voe.sx'].retries, 5);
|
|
assert.equal(config.hosterSettings['voe.sx'].parallelCount, 2); // default
|
|
assert.equal(config.hosterSettings['voe.sx'].maxSpeedKbs, 0); // default
|
|
});
|
|
|
|
it('save only updates provided sections', () => {
|
|
// Save hoster settings first
|
|
store.save({ hosterSettings: { 'doodstream.com': { retries: 10, maxSpeedKbs: 0, parallelCount: 2, restartBelowKbs: 0, timeIntervalSec: 0, maxSizeMb: 0 } } });
|
|
// Save hosters credentials separately
|
|
store.save({ hosters: { 'doodstream.com': { enabled: true, apiKey: 'key123' } } });
|
|
|
|
const config = store.load();
|
|
assert.equal(config.hosters['doodstream.com'].apiKey, 'key123');
|
|
assert.equal(config.hosterSettings['doodstream.com'].retries, 10); // preserved
|
|
});
|
|
|
|
it('appendHistory adds entries and caps at 100', () => {
|
|
for (let i = 0; i < 105; i++) {
|
|
store.appendHistory({ id: `batch-${i}`, timestamp: new Date().toISOString(), files: [] });
|
|
}
|
|
const history = store.loadHistory();
|
|
assert.equal(history.length, 100);
|
|
assert.equal(history[0].id, 'batch-5'); // first 5 dropped
|
|
assert.equal(history[99].id, 'batch-104');
|
|
});
|
|
|
|
it('clearHistory empties the array', () => {
|
|
store.appendHistory({ id: 'test', files: [] });
|
|
assert.equal(store.loadHistory().length, 1);
|
|
store.clearHistory();
|
|
assert.equal(store.loadHistory().length, 0);
|
|
});
|
|
|
|
it('corrupted JSON falls back to defaults', () => {
|
|
fs.writeFileSync(store.filePath, '{invalid json!!!', 'utf-8');
|
|
const config = store.load();
|
|
assert.ok(config.hosters);
|
|
assert.ok(config.hosterSettings);
|
|
assert.deepEqual(config.history, []);
|
|
});
|
|
|
|
it('globalSettings merge preserves partial values', () => {
|
|
fs.writeFileSync(store.filePath, JSON.stringify({
|
|
globalSettings: { alwaysOnTop: true }
|
|
}), 'utf-8');
|
|
|
|
const config = store.load();
|
|
assert.equal(config.globalSettings.alwaysOnTop, true);
|
|
assert.equal(config.globalSettings.shutdownAfterFinish, 'nothing'); // default
|
|
});
|
|
});
|