import { chromium } from 'playwright' const baseUrl = (process.env.BASE_URL || 'https://explorer.d-bis.org').replace(/\/$/, '') const addressUnderTest = process.env.SMOKE_ADDRESS || '0x99b3511a2d315a497c8112c1fdd8d508d4b1e506' const checks = [ { path: '/', expectTexts: ['SolaceScan', 'Recent Blocks', 'Open wallet tools'] }, { path: '/blocks', expectTexts: ['Blocks'] }, { path: '/transactions', expectTexts: ['Transactions'] }, { path: '/addresses', expectTexts: ['Addresses', 'Open An Address'] }, { path: '/watchlist', expectTexts: ['Watchlist', 'Saved Addresses'] }, { path: '/pools', expectTexts: ['Pools', 'Pool operation shortcuts'] }, { path: '/liquidity', expectTexts: ['Chain 138 Liquidity Access', 'Explorer Access Points'] }, { path: '/wallet', expectTexts: ['Wallet & MetaMask', 'Install Open Snap'] }, { path: '/tokens', expectTexts: ['Tokens', 'Find A Token'] }, { path: '/search', expectTexts: ['Search'], placeholder: 'Search by address, transaction hash, block number...' }, { path: `/addresses/${addressUnderTest}`, expectTexts: [], anyOfTexts: ['Back to addresses', 'Address not found'] }, ] async function bodyText(page) { return (await page.textContent('body')) || '' } async function hasShell(page) { const homeLink = await page.getByRole('link', { name: /Go to explorer home/i }).isVisible().catch(() => false) const supportText = await page.getByText(/Support:/i).isVisible().catch(() => false) return homeLink && supportText } async function waitForBodyText(page, snippets, timeoutMs = 15000) { if (!snippets || snippets.length === 0) { return bodyText(page) } const deadline = Date.now() + timeoutMs let lastText = '' while (Date.now() < deadline) { lastText = await bodyText(page) if (snippets.every((snippet) => lastText.includes(snippet))) { return lastText } await page.waitForTimeout(250) } return lastText } async function main() { const browser = await chromium.launch({ headless: true }) const page = await browser.newPage() let failures = 0 for (const check of checks) { const url = `${baseUrl}${check.path}` try { const response = await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 20000 }) await page.waitForLoadState('networkidle', { timeout: 5000 }).catch(() => {}) if (!response || !response.ok()) { console.error(`FAIL ${check.path}: HTTP ${response ? response.status() : 'no-response'}`) failures += 1 continue } const text = await waitForBodyText(page, check.expectTexts) const missing = check.expectTexts.filter((snippet) => !text.includes(snippet)) if (missing.length > 0) { console.error(`FAIL ${check.path}: missing text ${missing.join(' | ')}`) failures += 1 continue } if (check.anyOfTexts && !check.anyOfTexts.some((snippet) => text.includes(snippet))) { console.error(`FAIL ${check.path}: expected one of ${check.anyOfTexts.join(' | ')}`) failures += 1 continue } if (check.placeholder) { const placeholderVisible = await page.getByPlaceholder(check.placeholder).isVisible().catch(() => false) if (!placeholderVisible) { console.error(`FAIL ${check.path}: missing placeholder ${check.placeholder}`) failures += 1 continue } } if (!(await hasShell(page))) { console.error(`FAIL ${check.path}: shared explorer shell not visible`) failures += 1 continue } console.log(`OK ${check.path}`) } catch (error) { console.error(`FAIL ${check.path}: ${error instanceof Error ? error.message : String(error)}`) failures += 1 } } await browser.close() if (failures > 0) { process.exitCode = 1 return } console.log(`All ${checks.length} route checks passed for ${baseUrl}`) } main().catch((error) => { console.error(error instanceof Error ? error.stack || error.message : String(error)) process.exitCode = 1 })