mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-07-18 16:49:41 +03:00
8ccd562625
resetState молча сдавался: крутил 10 попыток closeForm, игнорировал их
результат и ничего не возвращал. Контекст с чужой открытой формой уходил в
пул как «чистый», следующий тест кликал в него (заявка пилота: Сц.3 роняет
форму → Сц.5 падает на чужой).
- resetState возвращает вердикт {clean, attempts, form, title, modal}. «Чисто»
определяется не как «форм нет» (form == null — верно только для пустого
стола), а как «закрывать нечего»: closeForm.nothingToClose. Замерено на
стенде пилота — рабочий стол там это form=5, formCount=3, openForms=[5,6,7],
и старое правило объявляло бы чистый контекст грязным ПОСЛЕ КАЖДОГО теста
(clean:false за 8.7с). Теперь clean:true за 0.9с, одна итерация вместо десяти.
- resetOrAbort читает вердикт: не clean → !-строка с именем оставшейся формы +
abortContext. Ровно логика, уже работавшая для пробоя дедлайна.
- Диагностика буферизуется и печатается ПОД строкой своего теста: cleanup идёт
до записи результата, поэтому раньше !-строки вставали над тестом и
приписывались предыдущему (на этом купилась и сама сессия).
- Ранний выход по closed:false НЕ вводим: A/B на живом наборе показал, что
грязная «Приходная накладная» отдаёт closed:false на первой попытке и
закрывается на следующей — выход прерывал бы контекст зря.
Проверено: контракт стабом 5/5; на стенде пилота ложное срабатывание снято
(8.8с→0.9с), стопка форм разбирается до стола; полный регресс 25/25, ноль
строк «not clean» (было две — «Тестовые ошибки»).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
83 lines
4.0 KiB
JavaScript
83 lines
4.0 KiB
JavaScript
// web-test cli/test-runner/discover v1.3 — test file discovery + state reset between tests
|
|
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
|
import { existsSync, readdirSync } from 'fs';
|
|
import { resolve } from 'path';
|
|
|
|
// Accepts a single path or an array of paths (files and/or dirs). Each .test.mjs file is
|
|
// taken directly; each directory is walked recursively (skipping _ / . prefixes). Results
|
|
// are deduped and sorted — sorting preserves the numeric-prefix order the suite relies on
|
|
// (00-, 01-, …) even when paths are listed out of order.
|
|
export function discoverTests(testPaths) {
|
|
const paths = Array.isArray(testPaths) ? testPaths : [testPaths];
|
|
const files = [];
|
|
function walk(dir) {
|
|
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
if (entry.name.startsWith('_') || entry.name.startsWith('.')) continue;
|
|
const full = resolve(dir, entry.name);
|
|
if (entry.isDirectory()) walk(full);
|
|
else if (entry.name.endsWith('.test.mjs')) files.push(full);
|
|
}
|
|
}
|
|
for (const p of paths) {
|
|
const full = resolve(p);
|
|
if (full.endsWith('.test.mjs')) {
|
|
if (existsSync(full)) files.push(full);
|
|
} else if (existsSync(full)) {
|
|
walk(full);
|
|
}
|
|
}
|
|
return [...new Set(files)].sort();
|
|
}
|
|
|
|
/**
|
|
* Return the context to a clean desktop between tests — and REPORT whether that worked.
|
|
*
|
|
* The verdict is the point. closeForm does not throw when a form refuses to close: it returns
|
|
* `{closed:false}`, and this loop used to drop that on the floor, so a context with someone else's
|
|
* modal still open went back into the pool as "clean" and the next test clicked into it. Measured
|
|
* on the pilot's stand: 10 idle iterations, `closed:false` every time, state unchanged — and the
|
|
* runner called it a success.
|
|
*
|
|
* @returns {Promise<{clean: boolean, attempts: number, form?: any, title?: string, modal?: boolean, lastError?: Error}>}
|
|
* `clean:false` also when the check itself failed — not being able to confirm is not being clean.
|
|
*/
|
|
export async function resetState(ctx) {
|
|
try { if (typeof ctx.dismissPendingErrors === 'function') await ctx.dismissPendingErrors(); } catch {}
|
|
let attempts = 0;
|
|
let lastError = null;
|
|
for (let i = 0; i < 10; i++) {
|
|
try {
|
|
const state = await ctx.getFormState();
|
|
// form === null means no form open (desktop). form === 0 is a real background form
|
|
// 1C exposes in some states — must still close it to fully reset.
|
|
if (state.form == null) return { clean: true, attempts };
|
|
attempts++;
|
|
const r = await ctx.closeForm({ save: false });
|
|
// The platform found nothing closable → this is the desktop, however many forms sit on it.
|
|
// Without this the check would be "form == null", which is only true for an EMPTY desktop:
|
|
// on a real application the home page keeps its own forms (measured: form=5, formCount=3,
|
|
// no cross), so the old rule declared a perfectly clean context dirty after every test.
|
|
if (r?.nothingToClose) return { clean: true, attempts, desktop: true };
|
|
// Deliberately NOT bailing out on `closed:false`: measured A/B on the live suite — a dirty
|
|
// «Приходная накладная *» reports closed:false on the first round and closes on a later one,
|
|
// so an early exit aborted a context that was about to be clean. `closed` compares form
|
|
// numbers, so an intermediate step (a popup going away) reads as "nothing happened" even
|
|
// though progress was made. The verdict below judges the END state, which is what matters.
|
|
} catch (e) { lastError = e; break; }
|
|
}
|
|
|
|
// Control check — the loop proves nothing on its own: it can also exit via `catch` above.
|
|
try {
|
|
const state = await ctx.getFormState();
|
|
if (state.form == null) return { clean: true, attempts };
|
|
return {
|
|
clean: false, attempts, lastError,
|
|
form: state.form,
|
|
title: state.activeTab || null,
|
|
modal: !!state.modal,
|
|
};
|
|
} catch (e) {
|
|
return { clean: false, attempts, lastError: lastError || e };
|
|
}
|
|
}
|