up
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
const assert = require('node:assert/strict')
|
||||
const { createServer } = require('node:http')
|
||||
const { readFileSync } = require('node:fs')
|
||||
const { join } = require('node:path')
|
||||
|
||||
module.exports = async function onlineSmoke({
|
||||
evaluate,
|
||||
inspect,
|
||||
state,
|
||||
command,
|
||||
poll,
|
||||
displayId,
|
||||
root,
|
||||
}) {
|
||||
let version = 1
|
||||
let offline = false
|
||||
let polls = 0
|
||||
let currentCommand = 'SCREEN_COMMAND_PLAY'
|
||||
const requests = []
|
||||
const server = createServer(async (req, res) => {
|
||||
const chunks = []
|
||||
for await (const chunk of req) chunks.push(chunk)
|
||||
const body = chunks.length ? JSON.parse(Buffer.concat(chunks).toString()) : {}
|
||||
const path = req.url
|
||||
requests.push(path)
|
||||
const send = (value, status = 200) => {
|
||||
res.writeHead(status, { 'Content-Type': 'application/json' })
|
||||
res.end(JSON.stringify(value))
|
||||
}
|
||||
if (path === '/api/auth/login') {
|
||||
assert.equal(body.email, 'organizer@example.test')
|
||||
return send({ accessToken: 'TEST-ACCESS', refreshToken: 'TEST-REFRESH' })
|
||||
}
|
||||
if (path === '/api/users/me') return send({ user: { roles: ['organizer'] } })
|
||||
if (path === '/api/games')
|
||||
return send({ games: [{ ID: 6, name: 'HTTP smoke', status: 'finish' }] })
|
||||
if (path === '/api/games/6')
|
||||
return send({
|
||||
game: {
|
||||
ID: 6,
|
||||
name: 'HTTP smoke',
|
||||
scenario: { story: { introduction: { audio: 'intro.wav' } } },
|
||||
},
|
||||
})
|
||||
if (path === '/api/games/6/screen-plan') return send({ plan: { steps: [{ mode: 2 }] } })
|
||||
if (path === '/api/games/6/music') return send({})
|
||||
if (path === '/api/files/intro.wav') {
|
||||
assert.equal(req.headers.authorization, undefined)
|
||||
res.writeHead(200, { 'Content-Type': 'audio/wav' })
|
||||
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/state') {
|
||||
polls++
|
||||
assert.equal(req.headers.authorization, undefined)
|
||||
assert.equal(body.accessToken, 'TEST-SCREEN')
|
||||
if (offline) return send({}, 503)
|
||||
return send({
|
||||
state: {
|
||||
gameID: 6,
|
||||
mode: 'SCREEN_MODE_INTRO',
|
||||
soundEnabled: true,
|
||||
volume: 80,
|
||||
stateVersion: String(version),
|
||||
command: currentCommand,
|
||||
},
|
||||
})
|
||||
}
|
||||
if (path === '/api/screens/results')
|
||||
return send({
|
||||
questions: [{ code: 'A', text: 'Вопрос' }],
|
||||
teams: [
|
||||
{
|
||||
team: { ID: 't', name: 'Детективы', password: 'PRIVATE' },
|
||||
place: 1,
|
||||
totalScore: 3,
|
||||
actionsCount: 1,
|
||||
answers: [{ questionCode: 'A', score: 3 }],
|
||||
},
|
||||
],
|
||||
})
|
||||
send({}, 404)
|
||||
})
|
||||
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve))
|
||||
const url = `http://127.0.0.1:${server.address().port}`
|
||||
const act = (intent) => evaluate(`window.screenBridge.onlineAction(${JSON.stringify(intent)})`)
|
||||
try {
|
||||
await evaluate('window.screenBridge.closeOutput()')
|
||||
// Вход через настоящую форму пульта, загрузка через защищённый IPC.
|
||||
await poll(() => evaluate('!!document.querySelector("#server")'), 'login form')
|
||||
await evaluate(`(() => {
|
||||
for (const [id, value] of Object.entries(${JSON.stringify({ server: url, email: 'organizer@example.test', password: 'test-password' })})) {
|
||||
const element = document.querySelector('#' + id)
|
||||
element.value = value; element.dispatchEvent(new Event('input', { bubbles: true }))
|
||||
}
|
||||
})()`)
|
||||
await evaluate(
|
||||
"Array.from(document.querySelectorAll('button')).find(b => b.textContent.trim() === 'Войти').click()",
|
||||
)
|
||||
await poll(
|
||||
async () => (await evaluate('window.screenBridge.onlineState()')).authenticated,
|
||||
'HTTP login',
|
||||
)
|
||||
await poll(
|
||||
async () => !(await evaluate('window.screenBridge.onlineState()')).busy,
|
||||
'login complete',
|
||||
)
|
||||
await act({ action: 'download', gameId: 6 })
|
||||
const packages = await evaluate('window.screenBridge.packages()')
|
||||
const pkg = packages.find((p) => p.name === 'HTTP smoke')
|
||||
assert.ok(pkg)
|
||||
await evaluate(`window.screenBridge.selectPackage(${JSON.stringify(pkg.key)})`)
|
||||
await act({ action: 'connect' })
|
||||
await evaluate(`window.screenBridge.show(${displayId})`)
|
||||
await poll(
|
||||
async () => (await evaluate('window.screenBridge.onlineState()')).connection === 'connected',
|
||||
'HTTP baseline',
|
||||
)
|
||||
assert.equal((await state()).channels.main.desired, 'stopped')
|
||||
version++
|
||||
await poll(
|
||||
async () => (await state()).channels.main.status === 'playing',
|
||||
'server play -> local audio',
|
||||
)
|
||||
assert.match(
|
||||
await inspect('document.querySelector("[data-channel=main-audio]").src'),
|
||||
/^screen-app:/,
|
||||
)
|
||||
await assert.rejects(act({ action: 'download', gameId: 6 }), /Закройте показ/)
|
||||
await command({ action: 'pause', channel: 'main' })
|
||||
const pausePolls = polls
|
||||
await poll(() => polls > pausePolls + 1, 'duplicate state polled')
|
||||
assert.equal((await state()).channels.main.desired, 'paused')
|
||||
offline = true
|
||||
await poll(
|
||||
async () => (await evaluate('window.screenBridge.onlineState()')).connection === 'offline',
|
||||
'offline indication',
|
||||
)
|
||||
await command({ action: 'play', channel: 'main' })
|
||||
offline = false
|
||||
currentCommand = 'SCREEN_COMMAND_STOP'
|
||||
version++
|
||||
await poll(
|
||||
async () => (await evaluate('window.screenBridge.onlineState()')).connection === 'connected',
|
||||
'reconnect baseline',
|
||||
)
|
||||
assert.equal((await state()).channels.main.desired, 'playing')
|
||||
version++
|
||||
await poll(async () => (await state()).channels.main.status === 'stopped', 'new remote stop')
|
||||
await act({ action: 'results' })
|
||||
assert.equal((await state()).results.teams[0].name, 'Детективы')
|
||||
assert.equal(JSON.stringify(await state()).includes('PRIVATE'), false)
|
||||
for (const method of ['onlineState()', "onlineAction({action:'logout'})", 'closeOutput()']) {
|
||||
assert.equal(
|
||||
await inspect(`window.screenBridge.${method}.then(() => false, () => true)`),
|
||||
true,
|
||||
)
|
||||
}
|
||||
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 }))
|
||||
} finally {
|
||||
server.closeAllConnections()
|
||||
await new Promise((resolve) => server.close(resolve))
|
||||
}
|
||||
}
|
||||
+13
-1
@@ -212,7 +212,10 @@ app.whenReady().then(async () => {
|
||||
() => BrowserWindow.getAllWindows().find((w) => w !== control),
|
||||
'output',
|
||||
)
|
||||
const inspect = (source) => output.webContents.executeJavaScript(source)
|
||||
const inspect = (source) =>
|
||||
BrowserWindow.getAllWindows()
|
||||
.find((w) => w !== control)
|
||||
.webContents.executeJavaScript(source)
|
||||
await poll(async () => (await state()).channels.main.status === 'stopped', 'fixture prepared')
|
||||
if (process.platform === 'linux')
|
||||
assert.equal(app.commandLine.getSwitchValue('ozone-platform'), 'x11')
|
||||
@@ -550,6 +553,15 @@ app.whenReady().then(async () => {
|
||||
assert.equal((await state()).channels.main.desired, 'stopped')
|
||||
assert.equal(await evaluate('typeof window.screenBridge.lan'), 'undefined')
|
||||
assert.equal((await state()).results, null)
|
||||
await require('./online-smoke.cjs')({
|
||||
evaluate,
|
||||
inspect,
|
||||
state,
|
||||
command,
|
||||
poll,
|
||||
displayId: targetDisplay.id,
|
||||
root,
|
||||
})
|
||||
console.log(
|
||||
'SCREEN_SMOKE_PASS',
|
||||
JSON.stringify({
|
||||
|
||||
Reference in New Issue
Block a user