import { readFileSync } from 'node:fs' import { describe, expect, it } from 'vitest' const cameraView = readFileSync( new URL('./CameraApp.vue', import.meta.url), 'utf8', ) const appShell = readFileSync(new URL('../../App.vue', import.meta.url), 'utf8') const appWindow = readFileSync( new URL('../PhoneAppWindow.vue', import.meta.url), 'utf8', ) const shellStyles = readFileSync( new URL('../../assets/main.css', import.meta.url), 'utf8', ) const mediaCapture = readFileSync( new URL('../../components/PhoneMediaCapture.vue', import.meta.url), 'utf8', ) const cameraClient = readFileSync( new URL('../../../../sky_phone/source/client/camera.lua', import.meta.url), 'utf8', ) const focusClient = readFileSync( new URL('../../../../sky_phone/source/client/focus.lua', import.meta.url), 'utf8', ) const cameraConfig = readFileSync( new URL('../../../../sky_phone/config/config.lua', import.meta.url), 'utf8', ) const cameraAnimations = readFileSync( new URL( '../../../../sky_phone/source/client/animations.lua', import.meta.url, ), 'utf8', ) describe('Camera app controls', () => { it('uses shared liquid glass for camera interaction buttons', () => { expect(cameraView.match(/variant="glass"/g)).toHaveLength(5) expect(cameraView).toMatch( / { expect(cameraView).toContain('SkySegmented') expect(cameraView).toContain(':active-index="mode === \'photo\' ? 0 : 1"') expect(cameraView).not.toContain('SkyPillNavigation') expect(cameraView).not.toContain('k-segmented') expect(cameraView).not.toContain('k-navbar') }) it('stays dark when the global phone appearance is light', () => { const cameraPageTag = cameraView.match(/]*>/s)?.[0] expect(cameraPageTag).toBeDefined() expect(cameraPageTag).toMatch(/\bdark\b/) expect(cameraView).toMatch( /\.camera-page\s*\{[^}]*--sky-bg:\s*#000;[^}]*--sky-text:\s*#fff;[^}]*background:\s*var\(--sky-bg\);[^}]*color:\s*var\(--sky-text\);/s, ) }) it('fills the translucent landscape shell without letterbox gaps', () => { const landscapeViewport = cameraView.match( /\.camera-page--landscape \.camera-viewport\s*\{([^}]*)\}/s, )?.[1] expect(cameraView).toMatch( /\.camera-page--landscape\s*\{[^}]*--sky-bg:\s*rgba\(0, 0, 0, 0\.42\);/s, ) expect(landscapeViewport).toBeDefined() expect(landscapeViewport).toContain('top: 50%') expect(landscapeViewport).toContain( 'width: calc(100% * var(--phone-screen-portrait-ratio))', ) expect(landscapeViewport).toContain( 'aspect-ratio: var(--phone-screen-portrait-ratio)', ) expect(landscapeViewport).not.toContain('16 / 9') expect(cameraView).toMatch( /\.camera-page--landscape \.camera-shade\s*\{[^}]*linear-gradient\([^)]*90deg,[^)]*rgba\(0, 0, 0, 0\.42\) 0 18%,[^)]*transparent 18% 75%,[^)]*rgba\(0, 0, 0, 0\.42\) 75% 100%/s, ) expect(appShell).toMatch( /'phone-screen--camera-landscape':\s*activeAppId === 'camera' && phone\.cameraLandscape/, ) expect(appWindow).toMatch( /'app-window--camera-landscape':\s*app\.id === 'camera' && phone\.cameraLandscape/, ) expect(shellStyles).toMatch( /\.phone-screen\s*\{[^}]*--phone-screen-portrait-ratio:\s*2\.30951;/s, ) expect(shellStyles).toMatch( /\.phone-screen--camera-landscape\s*\{[^}]*background:\s*transparent;/s, ) expect(shellStyles).toMatch( /\.phone-screen--camera-landscape \.springboard\s*\{[^}]*visibility:\s*hidden;/s, ) expect(shellStyles).toMatch( /\.app-window--camera-landscape\s*\{[^}]*background:\s*transparent;/s, ) }) it('renders camera notices as plain text without a glass pill', () => { const noticeMarkup = cameraView.slice( cameraView.indexOf(' { const zoomControl = cameraView.slice( cameraView.indexOf('
'), cameraView.indexOf('