mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-08 13:33:42 +08:00
00364fd645
Separate Galaxy authentication and local access policy from web presentation. Co-authored-by: Danny <dannyirwin31@yahoo.com> Co-authored-by: Prabhaav Pillai <prabhaav@msu.edu> Co-authored-by: dirwin31 <83434411+dirwin31@users.noreply.github.com> Co-authored-by: firestarsdog <229254897+firestarsdog@users.noreply.github.com>
79 lines
4.6 KiB
JavaScript
79 lines
4.6 KiB
JavaScript
const { chromium } = require(process.env.PLAYWRIGHT_MODULE || 'playwright')
|
|
const assert = require('node:assert/strict')
|
|
|
|
;(async () => {
|
|
const browser = await chromium.launch({ headless: true })
|
|
const page = await browser.newPage({ viewport: { width: 390, height: 900 } })
|
|
const errors = []
|
|
page.on('pageerror', error => errors.push(error.message))
|
|
await page.route('**/data/runtime.json', route => route.fulfill({ json: { schemaVersion: 1, monitor: 'local' } }))
|
|
await page.route('**/api/**', route => {
|
|
const path = new URL(route.request().url()).pathname
|
|
const json = path === '/api/auth/session' ? { state: 'configured', authenticated: true, localAccess: true } :
|
|
path === '/api/device/state' ? { state: 'parked', maxAgeMs: 3000 } :
|
|
path.startsWith('/api/settings/pages/') ? { page: 'hub', view: 'test', parked: true, rows: [] } : null
|
|
return route.fulfill({ status: json ? 200 : 503, json: json || { error: 'Unavailable in this test' } })
|
|
})
|
|
const base = process.env.GALAXY_URL || 'http://127.0.0.1:8765/'
|
|
await page.goto(base)
|
|
const nav = page.getByRole('navigation', { name: 'Primary navigation' })
|
|
await nav.getByRole('button', { name: 'Home', exact: true }).waitFor()
|
|
|
|
async function checkSlide(name, direction) {
|
|
await nav.getByRole('button', { name, exact: true }).click()
|
|
await page.waitForFunction(() => !!document.querySelector('.gx-route-enter-active'))
|
|
const motion = await page.locator('.gx-route-enter-active').evaluate(element => {
|
|
const matrix = new DOMMatrix(getComputedStyle(element).transform)
|
|
return { x: matrix.m41, y: matrix.m42 }
|
|
})
|
|
assert.ok(motion.x * direction > 0, `${name} enters from the correct horizontal side`)
|
|
assert.equal(motion.y, 0)
|
|
await page.waitForTimeout(500)
|
|
const geometry = await nav.evaluate(element => {
|
|
const pill = element.querySelector('.gx-nav-indicator').getBoundingClientRect()
|
|
const button = element.querySelector('[aria-current="page"]').getBoundingClientRect()
|
|
return { delta: Math.abs(pill.x - button.x), widthDelta: Math.abs(pill.width - button.width) }
|
|
})
|
|
assert.ok(geometry.delta < 2 && geometry.widthDelta < 2, 'glass indicator settles over the selected tab')
|
|
assert.equal(await page.evaluate(() => document.documentElement.scrollWidth > innerWidth), false)
|
|
}
|
|
await checkSlide('Tools', 1)
|
|
await checkSlide('Home', -1)
|
|
await checkSlide('Routes', 1)
|
|
await checkSlide('Toggles', -1)
|
|
// Fast changes must leave only one interactive page and the correct selected tab.
|
|
await nav.getByRole('button', { name: 'Tools', exact: true }).click()
|
|
await nav.getByRole('button', { name: 'Home', exact: true }).click()
|
|
await page.waitForTimeout(600)
|
|
assert.equal(await page.locator('.gx-route:not([inert])').count(), 1)
|
|
assert.equal(await nav.getByRole('button', { name: 'Home', exact: true }).getAttribute('aria-current'), 'page')
|
|
|
|
await page.goto(base + '#/model_laboratory')
|
|
const heading = page.getByText('Available models', { exact: true })
|
|
await heading.waitFor()
|
|
for (const width of [320, 360, 390, 600, 1280]) {
|
|
await page.setViewportSize({ width, height: 900 })
|
|
const layout = await page.evaluate(() => {
|
|
const title = [...document.querySelectorAll('.gx-section__title')].find(element => element.textContent === 'Available models')
|
|
const summary = title.closest('.gx-card').querySelector('.gx-summary')
|
|
const cells = [...summary.children].map(element => element.getBoundingClientRect())
|
|
return { headerHeight: title.parentElement.getBoundingClientRect().height,
|
|
summaryHeight: summary.getBoundingClientRect().height,
|
|
equalRows: cells.every(cell => Math.abs(cell.top - cells[0].top) < 1),
|
|
overflow: document.documentElement.scrollWidth > innerWidth }
|
|
})
|
|
assert.ok(layout.headerHeight < 80 && layout.summaryHeight < 100, 'model summary stays compact')
|
|
assert.equal(layout.equalRows, true, 'all three counts share one row')
|
|
assert.equal(layout.overflow, false)
|
|
}
|
|
await page.setViewportSize({ width: 390, height: 900 })
|
|
await page.emulateMedia({ reducedMotion: 'reduce' })
|
|
await nav.getByRole('button', { name: 'Home', exact: true }).click()
|
|
await page.waitForTimeout(50)
|
|
assert.equal(await page.locator('.gx-route-enter-active, .gx-route-leave-active').count(), 0)
|
|
assert.equal(await page.locator('.gx-nav-indicator').evaluate(element => getComputedStyle(element).transitionDuration), '0s')
|
|
assert.deepEqual(errors, [])
|
|
console.log('Directional tab slides, moving glass selection, rapid navigation, compact model summary and reduced motion passed.')
|
|
await browser.close()
|
|
})().catch(error => { console.error(error); process.exit(1) })
|