up
This commit is contained in:
+204
-4
@@ -1,6 +1,8 @@
|
||||
const assert = require('node:assert/strict')
|
||||
const { createServer } = require('node:http')
|
||||
const { readFileSync } = require('node:fs')
|
||||
const { readFileSync, writeFileSync, mkdtempSync, rmSync } = require('node:fs')
|
||||
const { tmpdir } = require('node:os')
|
||||
const { dialog } = require('electron')
|
||||
const { join } = require('node:path')
|
||||
|
||||
module.exports = async function onlineSmoke({
|
||||
@@ -31,6 +33,17 @@ module.exports = async function onlineSmoke({
|
||||
let timerLabel = 'Перерыв'
|
||||
let timerDurationSeconds = 600
|
||||
let timerState = 1
|
||||
const library = [
|
||||
{
|
||||
ID: 9,
|
||||
name: 'Редактор музыки',
|
||||
tracks: [
|
||||
{ ID: 91, name: 'Раз', filename: 'music-a.wav', position: 0 },
|
||||
{ ID: 92, name: 'Два', filename: 'music-b.wav', position: 1 },
|
||||
],
|
||||
},
|
||||
]
|
||||
let nextPlaylistId = 10
|
||||
const requests = []
|
||||
const server = createServer(async (req, res) => {
|
||||
const chunks = []
|
||||
@@ -102,8 +115,58 @@ module.exports = async function onlineSmoke({
|
||||
version++
|
||||
return send({})
|
||||
}
|
||||
if (path === '/api/games/6/music')
|
||||
return send(music ? { state: music, gamePlaylistId: 1, playlists: [music.playlist] } : {})
|
||||
if (path === '/api/playlists') {
|
||||
if (req.method === 'POST') library.push({ ID: nextPlaylistId++, name: body.name, tracks: [] })
|
||||
return send({ playlists: library })
|
||||
}
|
||||
const playlistMatch = path.match(/^\/api\/playlists\/(\d+)(?:\/tracks(?:\/(\d+|order))?)?$/)
|
||||
if (playlistMatch) {
|
||||
const item = library.find((p) => p.ID === Number(playlistMatch[1]))
|
||||
if (!item) return send({}, 404)
|
||||
if (path.endsWith('/order')) {
|
||||
item.tracks = body.trackIDs.map((id, position) => ({
|
||||
...item.tracks.find((t) => t.ID === id),
|
||||
position,
|
||||
}))
|
||||
if (music?.playlist.ID === item.ID) {
|
||||
const trackID = music.playlist.tracks[music.trackIndex].ID
|
||||
music = {
|
||||
...music,
|
||||
stateVersion: String(Number(music.stateVersion) + 1),
|
||||
playlist: structuredClone(item),
|
||||
trackIndex: item.tracks.findIndex((t) => t.ID === trackID),
|
||||
}
|
||||
}
|
||||
} else if (path.endsWith('/tracks') && req.method === 'POST') {
|
||||
assert.equal(body.filename, 'native.mp3')
|
||||
assert.equal(Buffer.from(body.data, 'base64').toString(), 'ID3test')
|
||||
item.tracks.push({
|
||||
ID: 93,
|
||||
name: body.name,
|
||||
filename: 'native.mp3',
|
||||
position: item.tracks.length,
|
||||
})
|
||||
} else if (playlistMatch[2] && req.method === 'DELETE')
|
||||
item.tracks = item.tracks.filter((t) => t.ID !== Number(playlistMatch[2]))
|
||||
else if (req.method === 'PUT') item.name = body.name
|
||||
else if (req.method === 'DELETE') library.splice(library.indexOf(item), 1)
|
||||
return send({ playlist: item })
|
||||
}
|
||||
if (path === '/api/games/6/music') {
|
||||
if (req.method === 'POST') {
|
||||
const item = library.find((p) => p.ID === body.playlistID)
|
||||
music = {
|
||||
...body,
|
||||
stateVersion: String(Number(music?.stateVersion || 0) + 1),
|
||||
playlist: structuredClone(item),
|
||||
}
|
||||
}
|
||||
return send(
|
||||
music
|
||||
? { state: music, gamePlaylistId: music.playlist.ID, playlists: [music.playlist] }
|
||||
: {},
|
||||
)
|
||||
}
|
||||
if (
|
||||
['/api/files/intro.wav', '/api/files/music-a.wav', '/api/files/music-b.wav'].includes(path)
|
||||
) {
|
||||
@@ -118,7 +181,10 @@ module.exports = async function onlineSmoke({
|
||||
return res.end(readFileSync(join(root, 'fixtures/audio.wav')))
|
||||
}
|
||||
if (path === '/api/screens') return send({ screenID: '67', accessToken: 'TEST-SCREEN' })
|
||||
if (path === '/api/screens/67/bind') return send({})
|
||||
if (path === '/api/screens/67/bind') {
|
||||
assert.equal(body.initializeAudio, true)
|
||||
return send({})
|
||||
}
|
||||
if (path === '/api/screens/state') {
|
||||
polls++
|
||||
assert.equal(req.headers.authorization, undefined)
|
||||
@@ -188,6 +254,19 @@ module.exports = async function onlineSmoke({
|
||||
),
|
||||
'server game selector',
|
||||
)
|
||||
await poll(
|
||||
() =>
|
||||
evaluate(
|
||||
`document.querySelectorAll('main.control > .n-card').length === 4 && document.querySelectorAll('.n-card-header__main').length === 5`,
|
||||
),
|
||||
'five control cards',
|
||||
)
|
||||
assert.deepEqual(
|
||||
await evaluate(
|
||||
`Array.from(document.querySelectorAll('.n-card-header__main')).map(e => e.textContent.trim())`,
|
||||
),
|
||||
['Сервер', 'Игра', 'Экран', 'План экранов', 'План музыки'],
|
||||
)
|
||||
varyGames = true
|
||||
for (let refresh = 0; refresh < 5; refresh++) {
|
||||
await poll(
|
||||
@@ -541,6 +620,127 @@ module.exports = async function onlineSmoke({
|
||||
await clickPlan('Сохранить план')
|
||||
await poll(async () => (await state()).catalog.steps.length === 0, 'plan deleted')
|
||||
console.log('SCREEN_PLAN_SMOKE_PASS')
|
||||
const clickMusic = async (label) =>
|
||||
poll(
|
||||
() =>
|
||||
evaluate(`(() => {
|
||||
const button = Array.from(document.querySelectorAll('[data-testid="music-plan-editor"] button')).find(b => b.textContent.trim() === ${JSON.stringify(label)})
|
||||
if (!button || button.disabled) return false
|
||||
button.click(); return true
|
||||
})()`),
|
||||
`music button ${label}`,
|
||||
)
|
||||
const choosePlaylist = async (name) => {
|
||||
await poll(
|
||||
() =>
|
||||
evaluate(
|
||||
`(() => { const select = document.querySelector('[data-testid="music-plan-editor"] .n-base-selection'); return select && !select.classList.contains('n-base-selection--disabled') })()`,
|
||||
),
|
||||
'library selector ready',
|
||||
)
|
||||
await evaluate(
|
||||
`document.querySelector('[data-testid="music-plan-editor"] .n-base-selection').click()`,
|
||||
)
|
||||
await poll(
|
||||
() =>
|
||||
evaluate(
|
||||
`Array.from(document.querySelectorAll('.n-base-select-option')).some(e => e.textContent.trim() === ${JSON.stringify(name)})`,
|
||||
),
|
||||
'library option',
|
||||
)
|
||||
await evaluate(
|
||||
`Array.from(document.querySelectorAll('.n-base-select-option')).find(e => e.textContent.trim() === ${JSON.stringify(name)}).click()`,
|
||||
)
|
||||
}
|
||||
const confirmDelete = async (title) => {
|
||||
await poll(
|
||||
() =>
|
||||
evaluate(`(() => {
|
||||
const dialog = Array.from(document.querySelectorAll('.n-dialog')).find(d => d.textContent.includes(${JSON.stringify(title)}))
|
||||
const button = dialog && Array.from(dialog.querySelectorAll('button')).find(b => b.textContent.trim() === 'Удалить')
|
||||
if (!button || button.disabled) return false
|
||||
button.click(); return true
|
||||
})()`),
|
||||
'delete confirmation ' + title,
|
||||
)
|
||||
}
|
||||
await clickMusic('Обновить плейлисты')
|
||||
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 setInput('#playlist-name', 'Переименован')
|
||||
// Повторный snapshot не затирает ввод названия.
|
||||
await new Promise((resolve) => setTimeout(resolve, 650))
|
||||
assert.equal(await evaluate(`document.querySelector('#playlist-name').value`), 'Переименован')
|
||||
await clickMusic('Сохранить название')
|
||||
await poll(() => library.some((p) => p.name === 'Переименован'), 'playlist renamed')
|
||||
const uploadDirectory = mkdtempSync(join(tmpdir(), 'screen-mp3-smoke-'))
|
||||
const originalDialog = dialog.showOpenDialog
|
||||
try {
|
||||
const file = join(uploadDirectory, 'native.mp3')
|
||||
writeFileSync(file, 'ID3test')
|
||||
dialog.showOpenDialog = async () => ({ canceled: false, filePaths: [file] })
|
||||
await clickMusic('Добавить MP3')
|
||||
await poll(
|
||||
() =>
|
||||
evaluate(
|
||||
`document.querySelector('[data-testid="music-plan-editor"] ol')?.textContent.includes('native.mp3')`,
|
||||
),
|
||||
'native MP3 uploaded',
|
||||
)
|
||||
} finally {
|
||||
dialog.showOpenDialog = originalDialog
|
||||
rmSync(uploadDirectory, { recursive: true, force: true })
|
||||
}
|
||||
await clickMusic('Удалить трек')
|
||||
await confirmDelete('Удалить трек?')
|
||||
await poll(
|
||||
() =>
|
||||
evaluate(
|
||||
`!document.querySelector('[data-testid="music-plan-editor"] ol')?.textContent.includes('native.mp3')`,
|
||||
),
|
||||
'track removed',
|
||||
)
|
||||
await clickMusic('Удалить плейлист')
|
||||
await confirmDelete('Удалить плейлист?')
|
||||
await poll(() => !library.some((p) => p.name === 'Переименован'), 'playlist removed')
|
||||
await choosePlaylist('Редактор музыки')
|
||||
await clickMusic('Использовать в игре')
|
||||
await poll(
|
||||
async () => (await state()).channels.music.playlistId === 9,
|
||||
'playlist assigned to game',
|
||||
)
|
||||
music = { ...music, playback: 2, stateVersion: String(Number(music.stateVersion) + 1) }
|
||||
await poll(
|
||||
async () => (await state()).channels.music.status === 'playing',
|
||||
'assigned music plays',
|
||||
)
|
||||
const beforeOrder = (await state()).channels.music
|
||||
await evaluate(`document.querySelector('[aria-label="Опустить трек 1"]').click()`)
|
||||
assert.deepEqual(
|
||||
library[0].tracks.map((t) => t.ID),
|
||||
[91, 92],
|
||||
'draft not published',
|
||||
)
|
||||
await clickMusic('Отменить')
|
||||
await evaluate(`document.querySelector('[aria-label="Опустить трек 1"]').click()`)
|
||||
await clickMusic('Сохранить порядок')
|
||||
await poll(
|
||||
async () => (await state()).channels.music.trackIndex === 1,
|
||||
'order applied without changing file',
|
||||
)
|
||||
const afterOrder = (await state()).channels.music
|
||||
assert.equal(afterOrder.source.url, beforeOrder.source.url)
|
||||
assert.equal(afterOrder.operation, beforeOrder.operation)
|
||||
assert.equal(afterOrder.seekOperation, beforeOrder.seekOperation)
|
||||
assert.equal(afterOrder.desired, 'playing')
|
||||
assert.ok(afterOrder.position >= beforeOrder.position)
|
||||
console.log('SCREEN_MUSIC_PLAN_SMOKE_PASS')
|
||||
|
||||
await act({ action: 'logout' })
|
||||
assert.equal((await evaluate('window.screenBridge.onlineState()')).authenticated, false)
|
||||
console.log('SCREEN_ONLINE_SMOKE_PASS', JSON.stringify({ polls, requests: requests.length }))
|
||||
|
||||
Reference in New Issue
Block a user