/**
* Сценарий audio — звук мира через DEV-шпион window.__gameAudioLog
* (на слух в headless не проверить: читаем фактические запуски sfx/амбиента).
* 1) новая игра: амбиент лугов запущен ровно один раз;
* 2) шаги: step_* в логе, боевых звуков нет;
* 3) атака: bell_hit;
* 4) guard амбиента: повторный playAmbience того же ключа не перезапускает;
* 5) лог ограничен 24 записями.
* Запуск: node tools/agent.mjs run tools/checks/audio.mjs
*/
import { withChecks } from '../lib.mjs';
export default async function ({ pretty }) {
return withChecks(
'audio',
async (t) => {
const { c } = t;
await c.run('новая игра: амбиент лугов запущен ровно один раз', async () => {
await t.boot();
const log = await t.readAudioLog();
c.expect(Array.isArray(log), 'DEV-лог аудио недоступен (прод-сборка?)', log);
const amb = log.filter((e) => e.key === 'ambience/meadows');
c.expect(amb.length === 1, 'амбиент лугов должен стартовать ровно один раз', amb);
return null;
});
await c.run('шаги: step_* в логе, боевых звуков нет', async () => {
await t.sleepEnemies();
const before = (await t.readAudioLog()).filter((e) => e.key.startsWith('sfx/step_')).length;
await t.ctx.agent.walkTo(16, 14, { timeoutTicks: 1500 });
const log = await t.waitAudioLog(
(l) => l.filter((e) => e.key.startsWith('sfx/step_')).length > before
);
const steps = log.filter((e) => e.key.startsWith('sfx/step_'));
c.expect(steps.length > before, 'шагов в логе нет', { steps: steps.length });
const combat = log.filter((e) => ['sfx/hurt', 'sfx/ash_die', 'sfx/spit'].includes(e.key));
c.expect(combat.length === 0, 'боевые звуки без боя', combat);
return null;
});
await c.run('атака: bell_hit в логе', async () => {
await t.ctx.agent.press('attack');
const log = await t.waitAudioLog((l) => l.some((e) => e.key === 'sfx/bell_hit'));
c.expect(log.some((e) => e.key === 'sfx/bell_hit'), 'атака не сыграла bell_hit', log);
return null;
});
await c.run('guard амбиента: тот же ключ не перезапускается', async () => {
const count = async () =>
(await t.readAudioLog()).filter((e) => e.key === 'ambience/meadows').length;
const before = await count();
await t.ctx.page.evaluate(() => window.__game.playAmbience('ambience/meadows'));
await t.ctx.agent.step(60);
c.expect((await count()) === before, 'повторный playAmbience перезапустил трек', {
before,
after: await count()
});
return null;
});
await c.run('лог ограничен 24 записями', async () => {
// Прогулка туда-обратно — шагов больше, чем вмещает кольцевой буфер.
for (const [x, y] of [[17, 14], [15, 14], [17, 14], [15, 14], [17, 14], [15, 14]]) {
await t.ctx.agent.walkTo(x, y, { timeoutTicks: 1500 });
}
const log = await t.readAudioLog();
c.expect(log.length <= 24, 'лог не обрезается до 24', log.length);
c.expect(log.length > 0, 'лог пуст после прогулки');
return null;
});
},
{ pretty }
);
}