Multi-Hoster-Upload/tests/doodstream-upload.test.js
Administrator ce5f20b1e1 fix(doodstream): surface real upload-failure reason + fix dead prod debug log
The "upload_result Seite hat keinen filecode" error fired with no actionable
detail when Doodstream's CDN returned an empty filecode (fn). Root cause is
server-side: the page structure is unchanged, the link is just missing —
Doodstream's backend refused the file (copyright/hash match, duplicate, size,
quota). XFileSharing reports the reason in the `st` field, which we ignored.

- Surface `st`: non-OK status now throws "Doodstream lehnt Datei ab (Status: …)".
- Enrich the generic error with st, fn-state, and the CDN node for diagnosis.
- Fix debug-log path: wrote to __dirname/.. which is read-only (app.asar) in
  packaged builds, so production captured zero traces. Now uses Electron's
  writable userData dir, with repo-root fallback for tests/plain node.
- Add tests/doodstream-upload.test.js (4 tests) pinning the parse/error paths.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 19:00:52 +02:00

66 lines
2.7 KiB
JavaScript

const { test } = require('node:test');
const assert = require('node:assert');
const DoodstreamUploader = require('../lib/doodstream-upload');
// The CDN hands back an XFileSharing form. `fn` is the filecode, `st` is the
// status ("OK" on success, an error string when the backend refuses the file).
// These tests pin the parse/error behaviour of _parseUploadResponse without
// touching the network — _fetch is stubbed to return the upload_result page.
function cdnForm({ fn = '', st = 'OK' } = {}) {
return `<HTML><BODY><Form name='F1' action='https://cdn.example/' method='POST'>` +
`<textarea name="op">upload_result</textarea>` +
`<textarea name="fn">${fn}</textarea>` +
`<textarea name="st">${st}</textarea>` +
`</Form></BODY></HTML>`;
}
const EMPTY_RESULT = '<textarea id="copy_dl" readonly class="form-control" rows="5"></textarea>';
const LINK_RESULT = (code) => `<textarea id="copy_dl" readonly class="form-control" rows="5">https://myvidplay.com/d/${code}</textarea>`;
function uploaderWithResult(resultHtml) {
const up = new DoodstreamUploader();
up._lastUploadUrl = 'https://cdn.example/upload/01';
// Stub the second-step submit so no real request goes out.
up._fetch = async () => ({ text: async () => resultHtml });
return up;
}
test('rejected file: empty fn + non-OK st surfaces the real status', async () => {
const up = uploaderWithResult(EMPTY_RESULT);
await assert.rejects(
() => up._parseUploadResponse(cdnForm({ fn: '', st: 'Error: file already exists' })),
(err) => {
assert.match(err.message, /lehnt Datei ab/);
assert.match(err.message, /file already exists/);
return true;
}
);
});
test('empty fn + st OK: generic error still reports st, fn-state and CDN node', async () => {
const up = uploaderWithResult(EMPTY_RESULT);
await assert.rejects(
() => up._parseUploadResponse(cdnForm({ fn: '', st: 'OK' })),
(err) => {
assert.match(err.message, /kein Filecode/);
assert.match(err.message, /st=OK/);
assert.match(err.message, /fehlt\/leer/);
assert.match(err.message, /cdn\.example/);
return true;
}
);
});
test('valid fn but empty result page: still resolves via fn (no regression)', async () => {
const up = uploaderWithResult(EMPTY_RESULT);
const res = await up._parseUploadResponse(cdnForm({ fn: '7mnp8xna3123', st: 'OK' }));
assert.equal(res.file_code, '7mnp8xna3123');
assert.equal(res.download_url, 'https://doodstream.com/d/7mnp8xna3123');
});
test('happy path: link in result page wins', async () => {
const up = uploaderWithResult(LINK_RESULT('jjsuhr931ds9'));
const res = await up._parseUploadResponse(cdnForm({ fn: 'jjsuhr931ds9', st: 'OK' }));
assert.equal(res.file_code, 'jjsuhr931ds9');
});