| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172 |
- // Ticket 14 browser acceptance. real transport uses controlled HTTP responses,
- // not a deployed-backend integration claim (that belongs to ticket 18).
- import assert from 'node:assert/strict'
- import { registerCockpitMocks } from '../../../src/modules/cockpit/mocks/contractMocks.js'
- import { registerMockTransport, findMockTransport } from '../../../src/modules/cockpit/services/cockpitApi.js'
- const base = process.env.COCKPIT_BASE || 'http://localhost:8001'
- const puppeteer = (await import(process.env.PUPPETEER_CORE_PATH || 'file:///C:/Users/ASUS/.dsh/puppeteer-runner/node_modules/puppeteer-core/lib/puppeteer/puppeteer-core.js')).default
- registerCockpitMocks({ handlers: { registerMockTransport } })
- const browser = await puppeteer.launch({ executablePath: process.env.CHROME_PATH || 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe', headless: true, defaultViewport: { width: 1680, height: 950 }, args: ['--no-sandbox'] })
- let passed = 0
- function check(name, condition, evidence) { assert.ok(condition, `${name}: ${JSON.stringify(evidence)}`); passed++; console.log(`PASS ${name}: ${JSON.stringify(evidence)}`) }
- async function open(config, controlled = false) {
- const page = await browser.newPage()
- const paths = []
- if (controlled) {
- await page.setRequestInterception(true)
- page.on('request', async request => {
- const url = new URL(request.url())
- if (!url.pathname.startsWith('/ticket14-api/')) return request.continue()
- const path = url.pathname.slice('/ticket14-api'.length) + url.search
- paths.push(path)
- if (url.pathname.endsWith('/monitoring/overview')) return request.respond({ status: 401, body: '{}' })
- const handler = findMockTransport(path)
- if (!handler) return request.respond({ status: 404, body: '{}' })
- try { const data = await handler({ path }); await request.respond({ status: 200, contentType: 'application/json', body: JSON.stringify(data) }) }
- catch { await request.respond({ status: 500, body: '{}' }) }
- })
- }
- await page.evaluateOnNewDocument(config => { window.__COCKPIT_CONFIG__ = config }, config)
- await page.goto(`${base}/#/cockpit`, { waitUntil: 'domcontentloaded', timeout: 60000 })
- await page.waitForSelector('.cockpit-shell')
- return { page, paths }
- }
- const map = { intro: { enabled: false }, cesium: { enabled: false } }
- try {
- {
- const { page } = await open({ dataSource: 'mock', map })
- await page.$eval('.cockpit-shell__mode:nth-child(3)', r => r.click())
- await page.waitForSelector('[data-pie-slice]')
- const counts = () => page.$$eval('[data-legend-key]', rows => rows.map(r => [r.dataset.legendKey, r.dataset.statusCount]))
- const before = await counts()
- await page.$eval('[data-legend-key="ALARM"]', r => r.click())
- await page.$eval('[data-legend-key="WARNING"]', r => r.click())
- await page.waitForFunction(() => document.querySelector('[data-legend-key="ALARM"]')?.dataset.statusSelected === 'yes' && document.querySelector('[data-legend-key="WARNING"]')?.dataset.statusSelected === 'yes')
- const selected = await page.$$eval('[data-legend-key][data-status-selected="yes"]', rows => rows.map(r => r.dataset.legendKey).sort())
- check('two-status OR selection', selected.join(',') === 'ALARM,WARNING', selected)
- check('global counts stable', JSON.stringify(await counts()) === JSON.stringify(before), before)
- await page.waitForSelector('[data-pie-slice][data-pie-selected="yes"]').catch(async error => { console.log(await page.$eval('.cockpit-shell', r => r.innerText)); throw error })
- const pie = await page.$$eval('[data-pie-slice]', rows => rows.map(r => ({ key: r.dataset.pieSlice, selected: r.dataset.pieSelected, dim: r.classList.contains('is-dim'), path: r.getAttribute('d') })))
- check('pie selection and dimming', pie.filter(r => r.selected === 'yes').length === 2 && pie.filter(r => r.selected !== 'yes').every(r => r.dim), pie)
- check('pie has finite geometry', pie.every(r => !/NaN|Infinity/.test(r.path)), pie)
- await page.$eval('[data-legend-key="ALARM"]', r => r.click())
- check('remove one status preserves other', await page.$eval('[data-legend-key="WARNING"]', r => r.dataset.statusSelected === 'yes'), null)
- await page.close()
- }
- {
- const { page, paths } = await open({ dataSource: 'real', api: { baseUrl: `${base}/ticket14-api` }, map, runtime: { refreshSeconds: 3600 } }, true)
- await page.$eval('.cockpit-shell__mode:nth-child(3)', r => r.click())
- await page.waitForSelector('[data-section-name="monitoringOverview"][data-section-state="unavailable"]')
- await page.waitForSelector('[data-section-name="monitoringDistribution"][data-section-state="success"]')
- check('real transport auto starts and isolates 401', paths.some(p => p.startsWith('/map-snapshot')) && paths.some(p => p.startsWith('/monitoring/situation')) && paths.some(p => p.startsWith('/overview/')) && paths.some(p => p.startsWith('/infrastructure/')), paths)
- await page.close()
- }
- {
- const { page } = await open({ dataSource: 'real', api: { baseUrl: '' }, map })
- await page.waitForSelector('[data-section-name="equipmentAggregate"][data-section-state="unavailable"]')
- await page.waitForSelector('[data-section-name="mapSnapshot"][data-section-state="unavailable"]')
- check('NO_BASE_URL unavailable without mock fallback', await page.$eval('[data-section-name="mapSnapshot"]', r => r.textContent.includes('不可用')), null)
- await page.close()
- }
- } finally { await browser.close() }
- console.log(`T14 final walkthrough: ${passed} passed`)
|