93 lines
4.0 KiB
JavaScript
93 lines
4.0 KiB
JavaScript
'use strict';
|
|
const test = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const { ScraperService, validateSettings } = require('../service');
|
|
|
|
function fixture(scanLibrary) {
|
|
const service = new ScraperService({ scanLibrary, adapters: [] });
|
|
service.state = { version: 4, paused: true, status: 'paused', queue: [], settings: validateSettings({}), currentIds: {} };
|
|
service.recentEvents = async () => [];
|
|
return service;
|
|
}
|
|
const inventory = title => ({ mangas: title ? [{ id: title, title, status: 'ongoing', autoUpdate: true, chapters: [], sources: [] }] : [] });
|
|
|
|
test('cold status returns controls immediately and simultaneous probes share one slow scan', { timeout: 1000 }, async () => {
|
|
let finish, scans = 0;
|
|
const service = fixture(() => { scans++; return new Promise(resolve => { finish = resolve; }); });
|
|
const states = await Promise.all(Array.from({ length: 8 }, () => service.publicState()));
|
|
assert.equal(scans, 1);
|
|
for (const state of states) {
|
|
assert.equal(state.paused, true);
|
|
assert.equal(state.settings.sourceRates.mangadex.minMs, 1000);
|
|
assert.deepEqual(state.library, []);
|
|
assert.equal(state.libraryStatus.ready, false);
|
|
assert.equal(state.libraryStatus.refreshing, true);
|
|
}
|
|
finish(inventory('Demo'));
|
|
await service.inventoryRefresh;
|
|
const ready = await service.publicState();
|
|
assert.equal(ready.library[0].title, 'Demo');
|
|
assert.equal(ready.libraryStatus.ready, true);
|
|
assert.equal(ready.libraryStatus.stale, false);
|
|
assert.equal(scans, 1);
|
|
});
|
|
|
|
test('status keeps previous summary but authoritative callers await scans and reject invalidated results', { timeout: 1000 }, async () => {
|
|
const completions = [];
|
|
const service = fixture(() => new Promise(resolve => completions.push(resolve)));
|
|
const first = service.libraryInventory(true);
|
|
await Promise.resolve();
|
|
completions[0](inventory('Old'));
|
|
await first;
|
|
service.invalidateInventory();
|
|
const fresh = service.libraryInventory(true);
|
|
await Promise.resolve();
|
|
let finished = false;
|
|
fresh.then(() => { finished = true; });
|
|
let state = await service.publicState();
|
|
assert.equal(state.library[0].title, 'Old');
|
|
assert.equal(state.libraryStatus.stale, true);
|
|
assert.equal(state.libraryStatus.refreshing, true);
|
|
assert.equal(finished, false);
|
|
// Publication during an in-flight scan requires another authoritative scan.
|
|
service.invalidateInventory();
|
|
const scan = service.inventoryRefresh;
|
|
completions[1](inventory('Obsolete'));
|
|
await scan;
|
|
await Promise.resolve();
|
|
assert.equal(completions.length, 3);
|
|
assert.equal(finished, false);
|
|
completions[2](inventory('Published'));
|
|
assert.equal((await fresh).mangas[0].title, 'Published');
|
|
state = await service.publicState();
|
|
assert.equal(state.library[0].title, 'Published');
|
|
assert.equal(state.libraryStatus.stale, false);
|
|
});
|
|
|
|
test('background inventory failures are visible without breaking controls or launching a poll storm', { timeout: 1000 }, async () => {
|
|
let scans = 0;
|
|
const service = fixture(async () => { scans++; throw new Error('Scan failed https://test.example/a?token=private'); });
|
|
await service.publicState();
|
|
await assert.rejects(service.inventoryRefresh, /Scan failed/);
|
|
for (let n = 0; n < 3; n++) {
|
|
const state = await service.publicState();
|
|
assert.equal(state.paused, true);
|
|
assert.match(state.libraryStatus.error, /Scan failed/);
|
|
assert.ok(!state.libraryStatus.error.includes('private'));
|
|
}
|
|
assert.equal(scans, 1);
|
|
await assert.rejects(service.libraryInventory(true), /Scan failed/);
|
|
assert.equal(scans, 2);
|
|
});
|
|
|
|
test('dashboard polling reuses a recent snapshot while decisions still force a fresh scan', async () => {
|
|
let scans = 0;
|
|
const service = fixture(async () => { scans++; return inventory('Demo'); });
|
|
await service.libraryInventory(true);
|
|
service.inventoryCachedAt = Date.now() - 30000;
|
|
for (let n = 0; n < 5; n++) assert.equal((await service.publicState()).library[0].title, 'Demo');
|
|
assert.equal(scans, 1);
|
|
await service.libraryInventory(true);
|
|
assert.equal(scans, 2);
|
|
});
|