mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-08-09 21:13:22 +03:00
feat(web-test): M8 — per-context lifecycle (closeContext + afterOpenContext/beforeCloseContext)
browser.mjs:
- + closeContext(name): logout slot + close page (tab) или context (window),
удаление из реестра. Throw если name неактивен (рулило: nicht den aktiven
closen, recorder always attached к active → invariant простой).
- _logoutSlot(slot, waitMs) — извлечён из disconnect, переиспользуется в
closeContext.
run.mjs:
- ensureContext() после createContext вызывает hooks.afterOpenContext(ctx, name, spec).
- wrapCloseContextHook() оборачивает ctx.closeContext (и каждую scoped-обёртку)
чтобы перед browser.closeContext fir'ить hooks.beforeCloseContext.
- Финальный teardown в finally: для всех живых контекстов кроме первого
(survivor) — beforeCloseContext + closeContext; для survivor только хук,
его закрывает disconnect().
_hooks.mjs v0.5:
- afterOpenContext инжектит persistent DOM-badge с displayName в правый
верхний угол page — в записанном видео всегда видно, какой контекст.
- beforeCloseContext counter-only.
- _state расширен полями afterOpenContext / beforeCloseContext.
15-multi-context-handover.test.mjs:
- +2 шага: closeContext('b') после handover, попытка closeContext(active)
ловится throw'ом с проверкой message.
00-hooks.test.mjs:
- +1 ассерт: afterOpenContext >= 1 (default уже создан), beforeCloseContext === 0
в теле первого теста.
spec §6:
- Раздел «Контекстный уровень» (afterOpenContext / beforeCloseContext + правила closeContext).
- ASCII-диаграмма порядка хуков обновлена с per-context lifecycle.
Регресс 19/19 ✓ (9m 16.8s).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
43ed9ba142
commit
eb87be5c04
@@ -1,4 +1,4 @@
|
||||
// _hooks.mjs v0.4 — автономный тестовый стенд для web-test + testlevel-хуки + title slides
|
||||
// _hooks.mjs v0.5 — автономный стенд + testlevel-хуки + title slides + per-context badge
|
||||
//
|
||||
// `prepare()` поднимает изолированный стенд по smart-логике:
|
||||
// 1) Если нужно пересоздавать БД (config-rebuild или --reload-data) — web-stop
|
||||
@@ -310,6 +310,8 @@ export const _state = {
|
||||
afterAll: 0,
|
||||
beforeEach: 0,
|
||||
afterEach: 0,
|
||||
afterOpenContext: 0,
|
||||
beforeCloseContext: 0,
|
||||
events: [],
|
||||
lastTestResult: null,
|
||||
};
|
||||
@@ -363,3 +365,55 @@ export async function afterEach(ctx) {
|
||||
}
|
||||
_state.events.push(`afterEach:${ctx.testInfo?.file || '?'}:${ctx.testResult?.status || '?'}`);
|
||||
}
|
||||
|
||||
// ── Per-context hooks (M8) ────────────────────────────────────────────────────
|
||||
//
|
||||
// `afterOpenContext` инжектит persistent DOM-badge с displayName в правый
|
||||
// верхний угол страницы контекста — в записанном видео всегда видно, какая
|
||||
// вкладка к какому пользователю относится. Badge переживает любые
|
||||
// перерисовки 1С (это собственный div с z-index, не часть SPA).
|
||||
//
|
||||
// `beforeCloseContext` — counter-only (страница вот-вот закроется, делать
|
||||
// что-либо с DOM бессмысленно).
|
||||
|
||||
async function injectContextBadge(ctx, name, spec) {
|
||||
const label = spec?.displayName || name;
|
||||
// ctx может быть scoped (auto-setActiveContext) или flat — в любом случае
|
||||
// getPage() возвращает активную страницу, которая на момент afterOpenContext
|
||||
// = только что созданный контекст.
|
||||
const page = ctx.getPage?.();
|
||||
if (!page) return;
|
||||
await page.evaluate((text) => {
|
||||
let div = document.getElementById('__web_test_ctx_badge');
|
||||
if (!div) {
|
||||
div = document.createElement('div');
|
||||
div.id = '__web_test_ctx_badge';
|
||||
document.body.appendChild(div);
|
||||
}
|
||||
div.style.cssText = [
|
||||
'position:fixed', 'top:8px', 'right:8px',
|
||||
'padding:4px 10px',
|
||||
'background:rgba(30,30,46,0.85)', 'color:#fff',
|
||||
'font:600 13px Segoe UI,Arial,sans-serif',
|
||||
'border-radius:4px', 'box-shadow:0 2px 6px rgba(0,0,0,0.25)',
|
||||
'z-index:999998', 'pointer-events:none',
|
||||
'letter-spacing:0.3px',
|
||||
].join(';');
|
||||
div.textContent = text;
|
||||
}, label);
|
||||
}
|
||||
|
||||
export async function afterOpenContext(ctx, name, spec) {
|
||||
_state.afterOpenContext++;
|
||||
_state.events.push(`afterOpenContext:${name}`);
|
||||
try {
|
||||
await injectContextBadge(ctx, name, spec);
|
||||
} catch {
|
||||
// Не валим прогон если badge не сел — это чисто визуальный bonus.
|
||||
}
|
||||
}
|
||||
|
||||
export async function beforeCloseContext(_ctx, name, _spec) {
|
||||
_state.beforeCloseContext++;
|
||||
_state.events.push(`beforeCloseContext:${name}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user