train_utility/tests/frontend_smoke.js

172 lines
4.4 KiB
JavaScript

const assert = require('node:assert/strict');
const path = require('node:path');
class FakeElement {
constructor(id = '') {
this.id = id;
this.value = id === 'task' ? 'detect' : '';
this.checked = false;
this.disabled = false;
this.style = {};
this.children = [];
this.listeners = {};
this.className = '';
this.textContent = '';
this.scrollTop = 0;
this.scrollHeight = 0;
this.classList = {
add() {},
remove() {},
contains() { return false; }
};
}
addEventListener(name, handler) {
this.listeners[name] = handler;
}
appendChild(child) {
this.children.push(child);
this.lastElementChild = child;
return child;
}
getContext() {
return {};
}
remove() {}
set innerHTML(value) {
this._innerHTML = value;
this.children = [];
}
get innerHTML() {
return this._innerHTML || '';
}
}
const elements = new Map();
const element = id => {
if (!elements.has(id)) elements.set(id, new FakeElement(id));
return elements.get(id);
};
let domReady;
global.document = {
addEventListener(name, handler) {
if (name === 'DOMContentLoaded') domReady = handler;
},
querySelectorAll() {
return [];
},
getElementById: element,
createElement() {
return new FakeElement();
},
head: new FakeElement('head'),
body: new FakeElement('body')
};
const storage = new Map();
global.localStorage = {
getItem(key) { return storage.has(key) ? storage.get(key) : null; },
setItem(key, value) { storage.set(key, value); },
removeItem(key) { storage.delete(key); }
};
global.confirm = () => true;
global.window = {location: {protocol: 'http:', host: '127.0.0.1:8000'}};
class FakeChart {
static instances = [];
constructor(_context, config) {
this.data = config.data;
this.options = config.options;
FakeChart.instances.push(this);
}
destroy() {}
update() {}
}
global.Chart = FakeChart;
class FakeWebSocket {
static instances = [];
constructor(url) {
this.url = url;
FakeWebSocket.instances.push(this);
}
}
global.WebSocket = FakeWebSocket;
const response = (ok, data) => ({
ok,
async json() { return data; }
});
global.fetch = async url => {
if (url === '/api/datasets' || url === '/api/models' || url === '/api/sessions') {
return response(true, []);
}
if (url === '/api/sessions/last_run') return response(false, {});
if (url === '/api/config/defaults') {
return response(true, {
dataset: 'coco8.yaml',
model: 'yolo11n.pt',
task: 'detect',
workers: 8,
patience: 100,
augmentation: {enabled: true, close_mosaic: 10},
mlflow: {enabled: false},
split: {enabled: false}
});
}
return response(false, {});
};
require(path.resolve(__dirname, '../src/yolo_webui/static/app.js'));
async function flushPromises() {
await new Promise(resolve => setImmediate(resolve));
await new Promise(resolve => setImmediate(resolve));
}
(async () => {
assert.equal(typeof domReady, 'function');
domReady();
await flushPromises();
element('workers').value = '0';
element('patience').value = '0';
element('close-mosaic').value = '0';
element('config-form').listeners.input();
const savedConfig = JSON.parse(storage.get('draft_config'));
assert.equal(savedConfig.workers, 0);
assert.equal(savedConfig.patience, 0);
assert.equal(savedConfig.augmentation.close_mosaic, 0);
assert.equal(FakeWebSocket.instances.length, 1);
const socket = FakeWebSocket.instances[0];
socket.onmessage({
data: JSON.stringify({
type: 'init',
status: 'idle',
logs: [],
metrics: [
{epoch: 1, mAP50: 0.5},
{epoch: 2, loss: 0.2}
]
})
});
const chart = FakeChart.instances.at(-1);
assert.deepEqual(chart.data.labels, [1, 2]);
assert.deepEqual(chart.data.datasets.map(item => item.label), ['mAP50', 'loss']);
assert.deepEqual(chart.data.datasets[0].data, [0.5, null]);
assert.deepEqual(chart.data.datasets[1].data, [null, 0.2]);
})().catch(error => {
console.error(error);
process.exitCode = 1;
});