import { By } from 'selenium-webdriver' import fs from 'fs' import { expect } from 'chai' import { Condition } from 'selenium-webdriver' export const DEFAULT_UI_WAIT_MS = 3000 const executionDialogStatusBy = By.css('.execution-dialog-status') export async function getActionButtons () { // Currently, only the active dashboard's contents are rendered, // so we don't need to scope the selector by dashboard title. return await webdriver.findElements(By.css('.action-button button')) } export async function getExecutionDialogOutput() { await webdriver.wait(new Condition('Dialog with long int is visible', async () => { const dialog = await webdriver.findElement({ id: 'execution-results-popup' }) return await dialog.isDisplayed() })); const ret = await webdriver.executeScript('return window.logEntries.get(window.executionDialog.executionTrackingId).output') return ret } export async function closeExecutionDialog() { const btnClose = await webdriver.findElements(By.css('[title="Close"]')) await btnClose[0].click() } export function takeScreenshotOnFailure (test, webdriver) { if (test.state === 'failed') { const title = test.fullTitle(); console.log(`Test failed, taking screenshot: ${title}`); takeScreenshot(webdriver, title); } } export function takeScreenshot (webdriver, title) { return webdriver.takeScreenshot().then((img) => { fs.mkdirSync('screenshots', { recursive: true }); title = title.replaceAll('config: ', '') title = title.replaceAll(/[\(\)\|\*\<\>\:]/g, "_") title = title + '.failed-test' fs.writeFileSync('screenshots/' + title + '.png', img, 'base64') }) } export async function waitForDashboardLoaded(timeoutMs = DEFAULT_UI_WAIT_MS, expectedTitle = null) { await webdriver.wait(new Condition('wait for loaded-dashboard', async function () { const body = await webdriver.findElement(By.tagName('body')) const attr = await body.getAttribute('loaded-dashboard') console.log('loaded-dashboard: ', attr) if (attr == null || attr === '') { return false } if (expectedTitle != null) { return attr === expectedTitle } return true }), timeoutMs) } export async function waitForLogsPage(timeoutMs = DEFAULT_UI_WAIT_MS) { await webdriver.wait(new Condition('wait for logs page', async () => { const url = await webdriver.getCurrentUrl() return url.includes('/logs/') && !url.endsWith('/logs') }), timeoutMs) } export async function waitForArgumentFormPage(timeoutMs = DEFAULT_UI_WAIT_MS) { await webdriver.wait(new Condition('wait for argument form page', async () => { const url = await webdriver.getCurrentUrl() return url.includes('/actionBinding/') && url.includes('/argumentForm') }), timeoutMs) } export async function waitForArgumentFormReady(timeoutMs = DEFAULT_UI_WAIT_MS) { await webdriver.wait(new Condition('wait for argument form ready', async () => { const body = await webdriver.findElement(By.tagName('body')) const attr = await body.getAttribute('loaded-argument-form') return attr != null && attr !== '' }), timeoutMs) } export async function waitForExecutionComplete(timeoutMs = DEFAULT_UI_WAIT_MS) { await webdriver.wait(new Condition('wait for execution status', async () => { const statusElements = await webdriver.findElements(executionDialogStatusBy) return statusElements.length > 0 }), timeoutMs) await webdriver.wait(new Condition('wait for execution to finish', async () => { try { const statusElement = await webdriver.findElement(executionDialogStatusBy) const statusText = await statusElement.getText() return !statusText.includes('Still running') && !statusText.includes('Queued') } catch (e) { return false } }), timeoutMs) } export async function getRootAndWait() { await webdriver.get(runner.baseUrl()) await waitForDashboardLoaded() } export async function closeSidebar() { await webdriver.findElement(By.id('sidebar-toggler-button')).click() const sidebar = await webdriver.findElement(By.id('mainnav')) const neededLeft = '-250px' // Assuming sidebar is closed at this position let lastLeft = '' await webdriver.wait(new Condition('wait for sidebar to close', async function() { const left = await sidebar.getCssValue('left') if (left !== lastLeft) { lastLeft = left console.log('Sidebar left changed to: ', left) return false } else { console.log('Sidebar closed, left is: *' + left, left === neededLeft ? ' (as expected)' : '') return left === neededLeft } }), DEFAULT_UI_WAIT_MS) } export async function openSidebar() { await webdriver.findElement(By.id('sidebar-toggler-button')).click() const sidebar = await webdriver.findElement(By.id('mainnav')) let lastLeft = 0 await webdriver.wait(new Condition('wait for sidebar to open', async function() { const left = await sidebar.getCssValue('left') if (left !== lastLeft) { lastLeft = left console.log('Sidebar left changed to: ', left) return false } else { console.log('Sidebar opened, left is: ', left) return true } }), DEFAULT_UI_WAIT_MS) } export async function getNavigationLinks() { const navigationLinks = await webdriver.findElements(By.css('.navigation-links li')) return navigationLinks } export async function requireExecutionDialogStatus (webdriver, expected) { await webdriver.wait(new Condition('wait for action to be running', async function () { const dialogStatus = await webdriver.findElement(executionDialogStatusBy) const actual = await dialogStatus.getText() if (actual === expected) { return true } else { console.log('Waiting for domStatus text to be: ', expected, ', it is currently: ', actual) return false } }), DEFAULT_UI_WAIT_MS) } export async function findExecutionDialog (webdriver) { return webdriver.findElement(By.id('execution-results-popup')) } export async function getActionButton (webdriver, title) { const buttons = await webdriver.findElements(By.css('[title="' + title + '"]')) expect(buttons).to.have.length(1) return buttons[0] } export async function getTerminalBuffer() { try { const output = await webdriver.executeScript(` if (window.terminal && window.terminal.getBufferAsString) { return window.terminal.getBufferAsString(); } return null; `) return output } catch (e) { console.log('[getTerminalBuffer] Error:', e.message) return null } }