101 lines
4.4 KiB
JavaScript
101 lines
4.4 KiB
JavaScript
/**
|
||
* Проверка работы интерфейса в офлайне.
|
||
*
|
||
* Блокирует все запросы к внешним хостам: если оформление или иконки
|
||
* подгружаются с CDN, они отвалятся. Успешное выполнение означает, что
|
||
* страница самодостаточна и работает в контейнере без сети.
|
||
*
|
||
* Требуется запущенный сервер:
|
||
* python -m uvicorn src.main:app --port 8123
|
||
* node tests/browser/ui_offline.js
|
||
*/
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
const os = require('os');
|
||
|
||
function resolvePlaywright() {
|
||
if (process.env.PLAYWRIGHT) return process.env.PLAYWRIGHT;
|
||
const base = path.join(os.homedir(), '.qwen', 'updates', 'npm');
|
||
if (!fs.existsSync(base)) return 'playwright-core';
|
||
const versions = fs.readdirSync(path.join(base, fs.readdirSync(base)[0], 'versions')).sort();
|
||
for (const v of versions.reverse()) {
|
||
const candidate = path.join(
|
||
base, fs.readdirSync(base)[0], 'versions', v,
|
||
'node_modules/@qwen-code/qwen-code/bundled/browser-use/runtime/node_modules/playwright-core'
|
||
);
|
||
if (fs.existsSync(candidate)) return candidate;
|
||
}
|
||
return 'playwright-core';
|
||
}
|
||
|
||
const { chromium } = require(resolvePlaywright());
|
||
|
||
const BASE = process.env.BASE_URL || 'http://127.0.0.1:8123';
|
||
const REPO = path.resolve(__dirname, '..', '..');
|
||
const FILE = path.join(REPO, 'dataset_hack/Для теста/spine.dcm');
|
||
|
||
(async () => {
|
||
const userDataDir = fs.mkdtempSync(path.join(os.tmpdir(), 'dxa-offline-'));
|
||
const context = await chromium.launchPersistentContext(userDataDir, { channel: 'chrome', headless: true });
|
||
const page = context.pages()[0] || await context.newPage();
|
||
await page.setViewportSize({ width: 1400, height: 1100 });
|
||
|
||
const external = [];
|
||
const failed = [];
|
||
await context.route('**/*', (route) => {
|
||
const url = route.request().url();
|
||
const isLocal = url.startsWith(BASE) || url.startsWith('data:') || url.startsWith('blob:');
|
||
if (!isLocal) {
|
||
external.push(url);
|
||
return route.abort();
|
||
}
|
||
return route.continue();
|
||
});
|
||
page.on('requestfailed', (r) => failed.push(r.url()));
|
||
|
||
await page.goto(BASE, { waitUntil: 'domcontentloaded' });
|
||
await page.waitForTimeout(1500);
|
||
|
||
// Оформление применилось? Проверяем вычисленные стили, а не наличие файла.
|
||
const styling = await page.evaluate(() => {
|
||
const drop = document.getElementById('dropZone');
|
||
const cs = getComputedStyle(drop);
|
||
const icon = document.querySelector('i.fas');
|
||
const iconFont = icon ? getComputedStyle(icon).fontFamily : null;
|
||
const iconWidth = icon ? icon.getBoundingClientRect().width : 0;
|
||
return {
|
||
dropZoneBorderRadius: cs.borderRadius,
|
||
dropZoneDisplay: cs.display,
|
||
iconFontFamily: iconFont,
|
||
iconWidth,
|
||
};
|
||
});
|
||
console.log('styling:', styling);
|
||
|
||
// Загрузка файла и открытие панели деталей в офлайне
|
||
await page.setInputFiles('#fileInput', [FILE]);
|
||
await page.waitForFunction(() => document.querySelectorAll('#resultsTable tr').length === 1, { timeout: 60000 });
|
||
await page.locator('#resultsTable tr').first().click();
|
||
await page.waitForTimeout(1200);
|
||
const panel = await page.evaluate(() => ({
|
||
visible: !document.getElementById('detailSection').classList.contains('hidden'),
|
||
basic: (document.getElementById('detailBasic') || {}).innerText?.replace(/\s+/g, ' ').trim(),
|
||
reason: (document.getElementById('detailReason') || {}).innerText?.replace(/\s+/g, ' ').trim().slice(0, 70),
|
||
images: document.querySelectorAll('#detailImage img, #detailMask img').length,
|
||
}));
|
||
console.log('panel:', panel);
|
||
|
||
console.log('\nвнешние запросы (заблокированы):', external.length ? external : 'нет');
|
||
console.log('проваленные запросы:', failed.length ? failed : 'нет');
|
||
|
||
const ok =
|
||
styling.dropZoneBorderRadius !== '0px' &&
|
||
panel.visible && panel.images === 2 &&
|
||
external.length === 0;
|
||
console.log('\nОФЛАЙН-ПРОВЕРКА:', ok ? 'ПРОЙДЕНА' : 'НЕ ПРОЙДЕНА');
|
||
|
||
await context.close();
|
||
fs.rmSync(userDataDir, { recursive: true, force: true });
|
||
process.exit(ok ? 0 : 1);
|
||
})().catch((e) => { console.error('FAILED:', e.message); process.exit(1); });
|