mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-08-03 02:00:22 +03:00
feat(web-test): T4.6 — гибридные режимы изоляции контекстов (tab default, window opt-in)
browser.mjs v1.12 + run.mjs v1.9: createContext принимает isolation параметр. По умолчанию 'tab' — все контексты живут в одном launchPersistentContext, каждый слот получает свою Page (вкладку). Преимущества: 1С extension грузится надёжно (через --load-extension в persistent profile), один процесс Chromium, дешёвая память. Cookies делятся между вкладками, но скоупятся по URL-path — для модели «разные пользователи через разные vrd-публикации» это естественно и достаточно. isolation: 'window' (opt-in) — старый путь chromium.launch() + newContext(): полная изоляция cookies, отдельный BrowserContext (и окно) на каждый слот, но extension может не подняться. Использовать когда нужна изоляция auth внутри одного URL. Смешивать режимы в одном прогоне нельзя — createContext бросает явную ошибку (первый createContext устанавливает activeMode, остальные обязаны совпадать). Конфиг tests/web-test/webtest.config.mjs: добавлен комментарий с описанием обоих режимов. По умолчанию tab — синтетика и наши smoke-тесты идут им. Live: 11/12 в полном прогоне (default tab) + 3/3 sanity-check в window mode (01-navigation + 14 + 15). Видеозапись из T4.5 работает в обоих режимах. 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
eef4f4bcea
commit
6c19846051
@@ -1,4 +1,4 @@
|
||||
// web-test browser v1.11 — Playwright browser management for 1C web client
|
||||
// web-test browser v1.12 — Playwright browser management for 1C web client
|
||||
// Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
/**
|
||||
* Playwright browser management for 1C web client.
|
||||
@@ -42,6 +42,10 @@ let highlightMode = false;
|
||||
// connect() does NOT use this Map — it preserves legacy single-session behavior for exec/run/start.
|
||||
const contexts = new Map();
|
||||
let activeContextName = null;
|
||||
// Isolation mode for the current cmdTest session — set by the first createContext call.
|
||||
// 'tab': all contexts share one persistent context (one window, multiple tabs, extension loads reliably).
|
||||
// 'window': each context gets its own BrowserContext (separate window per context, full cookie isolation, extension may not load).
|
||||
let activeMode = null;
|
||||
|
||||
const LOAD_TIMEOUT = 60000;
|
||||
const INIT_TIMEOUT = 60000;
|
||||
@@ -189,6 +193,7 @@ export async function disconnect() {
|
||||
}
|
||||
contexts.clear();
|
||||
activeContextName = null;
|
||||
activeMode = null;
|
||||
}
|
||||
|
||||
// Single-session path (connect): auto-stop recording if active
|
||||
@@ -315,7 +320,7 @@ function _attachSessionListeners(pg, slot, name) {
|
||||
* Use this from run.mjs cmdTest only — exec/run/start use connect() and stay on the
|
||||
* legacy persistent-context path.
|
||||
*/
|
||||
export async function createContext(name, url, { extensionPath } = {}) {
|
||||
export async function createContext(name, url, { extensionPath, isolation = 'tab' } = {}) {
|
||||
if (contexts.has(name)) {
|
||||
await setActiveContext(name);
|
||||
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: LOAD_TIMEOUT });
|
||||
@@ -325,35 +330,65 @@ export async function createContext(name, url, { extensionPath } = {}) {
|
||||
return await getPageState();
|
||||
}
|
||||
|
||||
// First context: launch browser. Subsequent: reuse existing browser.
|
||||
if (!browser) {
|
||||
if (!['tab', 'window'].includes(isolation)) {
|
||||
throw new Error(`createContext: invalid isolation "${isolation}", expected 'tab' or 'window'`);
|
||||
}
|
||||
if (activeMode && activeMode !== isolation) {
|
||||
throw new Error(`createContext: cannot mix isolation modes — first context used "${activeMode}", "${name}" requested "${isolation}". Use the same mode for all contexts in one run.`);
|
||||
}
|
||||
|
||||
// First context: launch browser. Subsequent: reuse existing.
|
||||
let isFirstContext = !browser;
|
||||
if (isFirstContext) {
|
||||
const extPath = findExtension(extensionPath);
|
||||
const launchArgs = ['--start-maximized'];
|
||||
if (extPath) {
|
||||
launchArgs.push('--disable-extensions-except=' + extPath, '--load-extension=' + extPath);
|
||||
}
|
||||
browser = await chromium.launch({ headless: false, args: launchArgs });
|
||||
} else if (typeof browser.newContext !== 'function') {
|
||||
throw new Error('createContext: existing browser was created via connect()/launchPersistentContext and cannot host additional isolated contexts. Call disconnect() first.');
|
||||
if (isolation === 'tab') {
|
||||
// Persistent context: extension loads reliably, one window with tabs per context
|
||||
persistentUserDataDir = pathJoin(tmpdir(), 'pw-1c-test-' + Date.now());
|
||||
mkdirSync(persistentUserDataDir, { recursive: true });
|
||||
browser = await chromium.launchPersistentContext(persistentUserDataDir, {
|
||||
headless: false,
|
||||
args: launchArgs,
|
||||
viewport: null,
|
||||
permissions: ['clipboard-read', 'clipboard-write'],
|
||||
});
|
||||
} else {
|
||||
// Window mode: separate BrowserContext per slot, full cookie isolation
|
||||
browser = await chromium.launch({ headless: false, args: launchArgs });
|
||||
}
|
||||
activeMode = isolation;
|
||||
}
|
||||
|
||||
// Save current active before switching
|
||||
_saveActiveSlot();
|
||||
|
||||
const newCtx = await browser.newContext({
|
||||
viewport: null,
|
||||
permissions: ['clipboard-read', 'clipboard-write'],
|
||||
});
|
||||
const newPage = await newCtx.newPage();
|
||||
// Create slot — page differs by mode
|
||||
let newCtx, newPage;
|
||||
if (activeMode === 'tab') {
|
||||
// Reuse the persistent context for all slots; each slot gets its own page (tab)
|
||||
newCtx = browser;
|
||||
if (isFirstContext) {
|
||||
newPage = browser.pages()[0] || await browser.newPage();
|
||||
} else {
|
||||
newPage = await browser.newPage();
|
||||
}
|
||||
} else {
|
||||
// Window mode: each slot owns its BrowserContext + page
|
||||
newCtx = await browser.newContext({
|
||||
viewport: null,
|
||||
permissions: ['clipboard-read', 'clipboard-write'],
|
||||
});
|
||||
newPage = await newCtx.newPage();
|
||||
}
|
||||
|
||||
const slot = {
|
||||
context: newCtx,
|
||||
page: newPage,
|
||||
sessionPrefix: null,
|
||||
seanceId: null,
|
||||
recorder: null,
|
||||
lastCaptions: [],
|
||||
lastRecordingDuration: null,
|
||||
highlightMode: false,
|
||||
};
|
||||
contexts.set(name, slot);
|
||||
|
||||
Reference in New Issue
Block a user