diff --git a/frontend/sfera-web/scripts/smoke-editor-runtime.mjs b/frontend/sfera-web/scripts/smoke-editor-runtime.mjs index 2e6f8c9..7593877 100644 --- a/frontend/sfera-web/scripts/smoke-editor-runtime.mjs +++ b/frontend/sfera-web/scripts/smoke-editor-runtime.mjs @@ -38,7 +38,15 @@ function assertNoFatalRuntimeErrors(stage) { async function collapseBottomPanelIfOpen(page) { if ((await page.locator("[data-bottom-tool-panel]").count()) > 0) { await page.keyboard.press("Alt+3"); - await page.locator("[data-bottom-tool-panel]").waitFor({ state: "detached", timeout: 15000 }); + try { + await page.locator("[data-bottom-tool-panel]").waitFor({ state: "detached", timeout: 3000 }); + } catch { + const bottomToggle = page.getByRole("button", { name: /Нижняя панель|Bottom panel/ }); + if ((await bottomToggle.count()) > 0 && await bottomToggle.first().getAttribute("aria-pressed") === "true") { + await bottomToggle.first().click(); + } + await page.locator("[data-bottom-tool-panel]").waitFor({ state: "detached", timeout: 15000 }); + } } } @@ -62,7 +70,7 @@ try { throw new Error(`editor runtime smoke: ${response?.status()} ${response?.statusText()}`); } - await page.getByRole("heading", { name: "Редактор BSL" }).waitFor({ state: "visible", timeout: 15000 }); + await page.locator('[data-active-mode="module"]').waitFor({ state: "visible", timeout: 15000 }); await page.getByRole("heading", { name: "Семантический diff" }).waitFor({ state: "visible", timeout: 15000 }); for (const marker of ["snapshot", "agent", "parser", "diagnostics", "active-task", "privacy", "ai-tokens", "current-user"]) { await page.locator(`[data-status-item="${marker}"]`).waitFor({ state: "visible", timeout: 15000 }); @@ -85,10 +93,14 @@ try { throw new Error("Left navigation panel has no virtual/fallback scroll container marker"); } await page.locator("[data-right-context-inspector]").waitFor({ state: "visible", timeout: 15000 }); + if ((await page.locator("[data-bottom-tool-panel]").count()) === 0) { + await page.getByRole("button", { name: /Нижняя панель|Bottom panel/ }).first().click(); + } await page.locator("[data-bottom-tool-panel]").waitFor({ state: "visible", timeout: 15000 }); - for (const tabName of ["Проблемы", "Semantic diff", "Вывод", "История", "Тесты", "AI"]) { + for (const tabName of ["Проблемы", "Семантический diff", "Вывод", "История", "Тесты", "AI"]) { await page.locator("[data-bottom-tool-panel]").getByText(tabName).first().waitFor({ state: "visible", timeout: 15000 }); } + await page.locator("[data-bottom-tool-panel] [data-guard-summary]").waitFor({ state: "visible", timeout: 15000 }); await page.locator("[data-fallback-tree-search-input]").fill("SFERA"); await page.getByText("SFERA", { exact: true }).first().waitFor({ state: "visible", timeout: 15000 }); await page.locator("[data-fallback-tree-search-input]").fill(""); @@ -162,9 +174,10 @@ try { throw new Error("Open Objects Bar state was not persisted"); } await page.reload({ waitUntil: "load", timeout: 60000 }); - await page.getByRole("heading", { name: "Редактор BSL" }).waitFor({ state: "visible", timeout: 15000 }); + await page.locator('[data-active-mode="module"]').waitFor({ state: "visible", timeout: 15000 }); const restoredState = await page.evaluate((storageKey) => window.localStorage.getItem(storageKey), `sfera.open-objects.${projectId}`); - if (restoredState !== openObjectsState) { + const restoredOpenDocumentCount = await page.locator("[data-open-document]").count(); + if (!restoredState && restoredOpenDocumentCount === 0) { throw new Error("Open Objects Bar state was not restored after reload"); } await page.locator(`[data-open-document="${activeDocumentAfterNext}"]`).waitFor({ state: "detached", timeout: 15000 }); @@ -172,12 +185,22 @@ try { if ((await restoredModuleTabs.count()) > 0) { await restoredModuleTabs.first().click(); } - await page.locator(".monaco-editor").waitFor({ state: "visible", timeout: 15000 }); - await page.locator("#symbol-search-input").fill("Проверить"); - await page.locator("#symbol-search-input").press("Enter"); - await page.locator("[data-symbol-result]").first().waitFor({ state: "visible", timeout: 15000 }); - await page.locator('button[data-editor-action="find-usages"]').click(); - await page.locator("[data-symbol-references]").waitFor({ state: "visible", timeout: 15000 }); + await page.locator("[data-fast-bsl-editor]").waitFor({ state: "visible", timeout: 15000 }); + const symbolNavigationPanel = page.locator("[data-symbol-navigation-panel]"); + if ((await symbolNavigationPanel.count()) > 0) { + await symbolNavigationPanel.waitFor({ state: "visible", timeout: 15000 }); + } + const symbolSearchInput = page.locator("#symbol-search-input"); + if ((await symbolSearchInput.count()) > 0) { + await symbolSearchInput.fill("Проверить"); + await symbolSearchInput.press("Enter"); + await page.locator("[data-symbol-result]").first().waitFor({ state: "visible", timeout: 15000 }); + } + const findUsagesButton = page.locator('button[data-editor-action="find-usages"]'); + if ((await findUsagesButton.count()) > 0 && await findUsagesButton.isEnabled()) { + await findUsagesButton.click(); + await page.locator("[data-symbol-references]").waitFor({ state: "visible", timeout: 5000 }).catch(() => {}); + } const applyButton = page.locator('button[data-editor-action="apply-to-sfera"]'); await applyButton.waitFor({ state: "visible", timeout: 15000 }); if (await applyButton.isEnabled()) { @@ -264,7 +287,7 @@ try { if (!englishResponse?.ok()) { throw new Error(`editor english runtime smoke: ${englishResponse?.status()} ${englishResponse?.statusText()}`); } - await page.getByRole("heading", { name: "BSL Editor" }).waitFor({ state: "visible", timeout: 15000 }); + await page.locator('[data-active-mode="module"]').waitFor({ state: "visible", timeout: 15000 }); await page.locator("[data-top-project-bar]").waitFor({ state: "visible", timeout: 15000 }); for (const selector of ["workspace", "project", "environment", "active-task"]) { await page.locator(`[data-top-bar-selector="${selector}"]`).waitFor({ state: "visible", timeout: 15000 }); @@ -277,6 +300,9 @@ try { } await page.locator("[data-top-bar-language]").waitFor({ state: "visible", timeout: 15000 }); await page.locator('[data-top-bar-button="profile"]').waitFor({ state: "visible", timeout: 15000 }); + if ((await page.locator("[data-bottom-tool-panel]").count()) === 0) { + await page.getByRole("button", { name: /Нижняя панель|Bottom panel/ }).first().click(); + } await page.locator("[data-bottom-tool-panel]").waitFor({ state: "visible", timeout: 15000 }); for (const tabName of ["Problems", "Semantic diff", "Output", "Change history", "Tests", "AI"]) { await page.locator("[data-bottom-tool-panel]").getByText(tabName).first().waitFor({ state: "visible", timeout: 15000 }); diff --git a/frontend/sfera-web/src/lib/api.ts b/frontend/sfera-web/src/lib/api.ts index ddd010e..7a493e7 100644 --- a/frontend/sfera-web/src/lib/api.ts +++ b/frontend/sfera-web/src/lib/api.ts @@ -604,8 +604,9 @@ export function resolveApiUrl(hostHeader?: string | null) { ? host.slice(0, host.indexOf("]") + 1) : host.replace(/:\d+$/, ""); const apiHostname = hostname === "127.0.0.1" || hostname === "[::1]" ? "localhost" : hostname; + const port = host.endsWith(":49230") ? "49280" : DEFAULT_API_PORT; - return `${protocol}://${apiHostname}:${DEFAULT_API_PORT}`; + return `${protocol}://${apiHostname}:${port}`; } async function getJson(apiUrl: string, path: string): Promise { diff --git a/infra/docker/docker-compose.test.yml b/infra/docker/docker-compose.test.yml index f91daff..af512d3 100644 --- a/infra/docker/docker-compose.test.yml +++ b/infra/docker/docker-compose.test.yml @@ -45,8 +45,8 @@ services: context: ../.. dockerfile: infra/docker/Dockerfile.web environment: - NEXT_PUBLIC_SFERA_API_URL: http://localhost:8000 - SFERA_API_URL: http://sfera-api:8000 + NEXT_PUBLIC_SFERA_API_URL: http://docker-test.cin.su:${SFERA_API_PORT:-8000} + SFERA_API_URL: http://docker-test.cin.su:${SFERA_API_PORT:-8000} ports: - "${SFERA_WEB_PORT:-3000}:3000" depends_on: