From a35c09d0dc257fc1cd3703b8d968e392306d69ce Mon Sep 17 00:00:00 2001 From: Fedorov Vladimir Date: Sun, 18 Oct 2026 18:32:06 +0700 Subject: [PATCH] up --- scripts/online-smoke.cjs | 39 ++- scripts/smoke.cjs | 15 +- src/components/ControlPage.vue | 149 +++------- src/components/MusicPlanPanel.vue | 453 +++++++++++++++++++++++------ src/components/ScreenPlanPanel.vue | 56 ++-- 5 files changed, 457 insertions(+), 255 deletions(-) diff --git a/scripts/online-smoke.cjs b/scripts/online-smoke.cjs index 1cf20a2..d34ee4f 100644 --- a/scripts/online-smoke.cjs +++ b/scripts/online-smoke.cjs @@ -42,8 +42,9 @@ module.exports = async function onlineSmoke({ { ID: 92, name: 'Два', filename: 'music-b.wav', position: 1 }, ], }, + { ID: 10, name: 'Тестовый плейлист', tracks: [] }, ] - let nextPlaylistId = 10 + let nextPlaylistId = 11 const requests = [] const server = createServer(async (req, res) => { const chunks = [] @@ -627,7 +628,7 @@ module.exports = async function onlineSmoke({ await poll( () => evaluate(`(() => { - const button = Array.from(document.querySelectorAll('[data-testid="screen-plan"] button')) + const button = Array.from(document.querySelector('[data-testid="screen-plan"]').closest('.n-card').querySelectorAll('button')) .find(b => (b.getAttribute('aria-label') ?? b.textContent.trim()) === ${JSON.stringify(label)}) if (!button || button.disabled) return false button.click(); return true @@ -730,7 +731,7 @@ module.exports = async function onlineSmoke({ poll( () => evaluate(`(() => { - const button = Array.from(document.querySelectorAll('[data-testid="music-plan-editor"] button')).find(b => (b.getAttribute('aria-label') ?? b.textContent.trim()) === ${JSON.stringify(label)}) + const button = Array.from(document.querySelector('[data-testid="music-plan"]').querySelectorAll('button')).find(b => (b.getAttribute('aria-label') ?? b.textContent.trim()) === ${JSON.stringify(label)}) if (!button || button.disabled) return false button.click(); return true })()`), @@ -774,13 +775,15 @@ module.exports = async function onlineSmoke({ async () => (await evaluate('window.screenBridge.onlineState()')).playlists.length > 0, 'library loaded automatically', ) - await setInput('#new-playlist-name', 'Создан из приложения') - await clickMusic('Создать плейлист') - await poll(() => library.some((p) => p.name === 'Создан из приложения'), 'playlist created') - await poll( - () => evaluate(`document.querySelector('#playlist-name')?.value === 'Создан из приложения'`), - 'new playlist selected', + await clickMusic('Редактировать') + assert.equal( + await evaluate(`!!document.querySelector('#new-playlist-name') || + Array.from(document.querySelectorAll('[data-testid="music-plan"] button')) + .some(b => b.textContent.trim() === 'Создать плейлист')`), + false, + 'playlist creation form is absent', ) + await choosePlaylist('Тестовый плейлист') await setInput('#playlist-name', 'Переименован') // Повторный snapshot не затирает ввод названия. await new Promise((resolve) => setTimeout(resolve, 650)) @@ -797,7 +800,7 @@ module.exports = async function onlineSmoke({ await poll( () => evaluate( - `document.querySelector('[data-testid="music-plan-editor"] ol')?.textContent.includes('native.mp3')`, + `document.querySelector('[data-testid="music-plan-editor"] .track-list')?.textContent.includes('native.mp3')`, ), 'native MP3 uploaded', ) @@ -810,7 +813,7 @@ module.exports = async function onlineSmoke({ await poll( () => evaluate( - `!document.querySelector('[data-testid="music-plan-editor"] ol')?.textContent.includes('native.mp3')`, + `!document.querySelector('[data-testid="music-plan-editor"] .track-list')?.textContent.includes('native.mp3')`, ), 'track removed', ) @@ -835,7 +838,7 @@ module.exports = async function onlineSmoke({ [91, 92], 'draft not published', ) - await clickMusic('Отменить') + await clickMusic('Отменить порядок') await evaluate(`document.querySelector('[aria-label="Опустить трек 1"]').click()`) await clickMusic('Сохранить порядок') await poll( @@ -848,6 +851,18 @@ module.exports = async function onlineSmoke({ assert.equal(afterOrder.seekOperation, beforeOrder.seekOperation) assert.equal(afterOrder.desired, 'playing') assert.ok(afterOrder.position >= beforeOrder.position) + await clickMusic('Готово') + await poll( + () => evaluate(`(() => { + const view = document.querySelector('[data-testid="music-plan-view"]') + const rows = Array.from(view?.querySelectorAll('[data-track-index]') ?? []) + return rows.length === 2 && !document.querySelector('[data-testid="music-plan-editor"]') + && rows.every(row => !row.querySelector('.track-preview') && row.querySelector('.n-progress')) + && rows.filter(row => !row.classList.contains('track-current')).every(row => + Array.from(row.querySelectorAll('button[aria-label]')).every(button => button.disabled)) + })()`), + 'music view shows tracks, progress and inactive controls', + ) console.log('SCREEN_MUSIC_PLAN_SMOKE_PASS') await evaluate(`Array.from(document.querySelectorAll('button')) .find(b => b.textContent.trim() === 'Отключиться').click()`) diff --git a/scripts/smoke.cjs b/scripts/smoke.cjs index 9787a14..888010d 100644 --- a/scripts/smoke.cjs +++ b/scripts/smoke.cjs @@ -426,13 +426,14 @@ app.whenReady().then(async () => { async () => (await state()).channels.main.status === 'paused', 'plan media paused', ) - await evaluate(`(() => { - const input = document.querySelector('.plan-step-current input[id^="volume-main-"]') - input.focus(); input.value = '42' - input.dispatchEvent(new InputEvent('input', { bubbles: true, inputType: 'insertText' })) - input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true })) - input.blur() - })()`) + await evaluate(`document.querySelector('.plan-step-current [id^="volume-main-"] [role="slider"]').focus()`) + for (let attempt = 0; attempt < 100; attempt++) { + const volume = (await state()).channels.main.volume + if (volume === 42) break + await evaluate(`document.querySelector('.plan-step-current [id^="volume-main-"] [role="slider"]') + .dispatchEvent(new KeyboardEvent('keydown', { key: ${JSON.stringify(volume > 42 ? 'ArrowLeft' : 'ArrowRight')}, bubbles: true }))`) + await poll(async () => (await state()).channels.main.volume !== volume, 'volume slider keyboard update') + } await poll(async () => (await state()).channels.main.volume === 42, 'plan media volume') assert.equal((await state()).channels.main.desired, 'paused') assert.equal((await state()).channels.music.desired, 'playing') diff --git a/src/components/ControlPage.vue b/src/components/ControlPage.vue index e979ac2..572be23 100644 --- a/src/components/ControlPage.vue +++ b/src/components/ControlPage.vue @@ -3,18 +3,16 @@ import { NAlert, NButton, NCard, - NInputNumber, + NSlider, NProgress, NSelect, NSpace, - NSwitch, NTag, useMessage, useDialog, } from 'naive-ui' import { computed, onMounted, onUnmounted, ref } from 'vue' import type { - Channel, HostInfo, Intent, Playback, @@ -28,7 +26,6 @@ import ConnectionPanel from './ConnectionPanel.vue' import MusicPlanPanel from './MusicPlanPanel.vue' import { useOnlineConnection } from '../composables/useOnlineConnection' import ScreenPlanPanel from './ScreenPlanPanel.vue' -import { playbackControl } from '../utils/playbackControl' import { formatTimer } from '../utils/presentation' const { @@ -60,7 +57,6 @@ const host = ref({ preferredDisplayId: null, }) const display = ref(null) -const positions = ref>({ main: 10, music: 10 }) const isBusy = ref(false) const preview = ref(null) const previewURL = computed(() => @@ -98,13 +94,6 @@ async function refreshPreview() { } } -const channel = 'music' as const -const musicControl = computed(() => - playbackControl(state.value?.channels.music ?? { desired: 'stopped', status: 'idle' }), -) -const playlist = computed(() => - state.value?.catalog.playlists.find((p) => p.id === state.value?.channels.music.playlistId), -) const statusLabels: Record = { idle: 'Файл не выбран', pending: 'Загрузка…', @@ -331,6 +320,27 @@ onUnmounted(() => { diff --git a/src/components/MusicPlanPanel.vue b/src/components/MusicPlanPanel.vue index f52650a..fc067bb 100644 --- a/src/components/MusicPlanPanel.vue +++ b/src/components/MusicPlanPanel.vue @@ -1,19 +1,65 @@