Files
contracts-flask/upload/frontend/test_upload_layer2.mjs
T
RepinoidandCopilot 6e6fc4db8e
Deploy contracts-flask / validate (push) Canceled after 0s
Integrate Obfuscator file picker into Contracts
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-30 10:24:23 +03:00

167 lines
4.9 KiB
JavaScript

import assert from 'node:assert/strict';
import { putToVm } from './upload/put_to_vm.js';
import { uploadViaVM } from './upload/upload_via_vm.js';
if (typeof globalThis.File === 'undefined') {
globalThis.File = class File extends Blob {
constructor(parts, name, options = {}) {
super(parts, options);
this.name = name;
this.lastModified = options.lastModified || Date.now();
}
};
}
globalThis.crypto = globalThis.crypto || { randomUUID: () => 'test-upload-id' };
let lastXHR;
class FakeXHR {
constructor() {
this.upload = {};
this.status = 0;
this.statusText = '';
this.timeout = 0;
lastXHR = this;
}
open(method, url) {
this.method = method;
this.url = url;
}
send(body) {
this.body = body;
}
complete(status = 200) {
this.status = status;
this.onload();
}
}
globalThis.XMLHttpRequest = FakeXHR;
let fetchCalls = [];
let fetchResponder;
globalThis.fetch = async (url, options) => {
fetchCalls.push({ url, options });
return fetchResponder(fetchCalls.length);
};
const tick = () => new Promise((resolve) => setTimeout(resolve, 0));
async function waitForNextXHR(previous) {
for (let attempt = 0; attempt < 20 && lastXHR === previous; attempt += 1) await tick();
assert.notEqual(lastXHR, previous, 'next PUT request was not started');
return lastXHR;
}
async function testPutToVmSuccess() {
const file = new File(['payload'], 'a.pdf');
const request = putToVm(file, 'https://vm.example/a');
assert.equal(lastXHR.method, 'PUT');
assert.equal(lastXHR.body, file);
lastXHR.complete();
await request;
}
async function testUploadIncludesPerFilePayloadAndResult() {
fetchCalls = [];
fetchResponder = async (callNumber) => ({
ok: true,
status: 200,
statusText: 'OK',
json: async () => ({
ok: true,
results: [{ ok: true, doc_id: `doc-${callNumber}`, parsed: { status: 'parsed' } }],
}),
});
const files = [
{ id: 'one', name: 'one.pdf', path: 'one.pdf', file: new File(['1'], 'one.pdf') },
{ id: 'two', name: 'two.pdf', path: 'archive.zip/folder/two.pdf', file: new File(['2'], 'two.pdf') },
];
const completed = [];
const previous = lastXHR;
const request = uploadViaVM(files, {
vmUploadUrl: 'https://vm.example/contracts-upload/',
backendUploadUrl: '/api/upload_refs',
getExtraPayload: (entry) => ({
batch_id: 'batch-1',
contract_id: 'contract-1',
zip_source: entry.id === 'two' ? 'archive.zip' : null,
}),
onFileComplete: (event) => completed.push(event),
});
const firstXHR = await waitForNextXHR(previous);
firstXHR.complete();
const secondXHR = await waitForNextXHR(firstXHR);
secondXHR.complete();
const result = await request;
assert.equal(result.ok, true);
assert.equal(fetchCalls.length, 2);
const firstBody = JSON.parse(fetchCalls[0].options.body);
const secondBody = JSON.parse(fetchCalls[1].options.body);
assert.equal(firstBody.batch_id, 'batch-1');
assert.equal(firstBody.contract_id, 'contract-1');
assert.equal(firstBody.files.length, 1);
assert.equal(secondBody.zip_source, 'archive.zip');
assert.equal(completed.length, 2);
assert.equal(completed[1].result.doc_id, 'doc-2');
assert.equal(completed[1].source.id, 'two');
}
async function testUploadReportsPutFailure() {
fetchCalls = [];
const previous = lastXHR;
const request = uploadViaVM([new File(['x'], 'x.pdf')], {
vmUploadUrl: 'https://vm.example/',
});
const xhr = await waitForNextXHR(previous);
xhr.onerror();
const result = await request;
assert.equal(result.ok, false);
assert.equal(fetchCalls.length, 0);
assert.match(result.error, /Ошибка отправки файла/);
}
async function testUploadReportsBackendFailure() {
fetchCalls = [];
fetchResponder = async () => ({
ok: false,
status: 502,
statusText: 'Bad Gateway',
json: async () => ({ ok: false, error: 'failed' }),
});
const previous = lastXHR;
const request = uploadViaVM([new File(['x'], 'x.pdf')], {
vmUploadUrl: 'https://vm.example/',
backendUploadUrl: '/api/upload_refs',
});
const xhr = await waitForNextXHR(previous);
xhr.complete();
const result = await request;
assert.equal(result.ok, false);
assert.match(result.error, /HTTP 502/);
}
async function testAbortBeforeUpload() {
const controller = new AbortController();
controller.abort();
const previous = lastXHR;
const result = await uploadViaVM([new File(['x'], 'x.pdf')], {
vmUploadUrl: 'https://vm.example/',
signal: controller.signal,
});
assert.equal(result.aborted, true);
assert.equal(lastXHR, previous);
}
const tests = [
['PUT via WebDAV', testPutToVmSuccess],
['per-file extra payload and sink result', testUploadIncludesPerFilePayloadAndResult],
['PUT failure', testUploadReportsPutFailure],
['backend failure', testUploadReportsBackendFailure],
['abort before upload', testAbortBeforeUpload],
];
for (const [name, test] of tests) {
await test();
console.log(`PASS ${name}`);
}