Ctrl K
ComunidadGuías…

test_serve_app_js_audio.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"""Live view audio controls (toggle, button state, and autoplay fallback)."""
import json
import shutil
import subprocess
import unittest
from pathlib import Path


def audio_source(source):
    start = source.index("// ── audio direct (Live View)")
    return source[start:source.index("// ── fin audio direct (Live View)", start)]


class LiveViewAudioTests(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.node = shutil.which("node")
        if not cls.node:
            raise unittest.SkipTest("Node unavailable")
        cls.source = Path(__file__).with_name("serve_app.js").read_text(encoding="utf-8")
        cls.code = audio_source(cls.source)

    def run_js(self, scenario):
        script = r"""
const assert=require("node:assert/strict");
const videos=[];
const tick=()=>new Promise(resolve=>setImmediate(resolve));
class Video {
  constructor() {
    this.isConnected=true;this._muted=false;this._volume=1;this.events={};
    this.defaultMuted=false;this.plays=0;this.blockOnce=false;this.failure=null;
    this.classList={classes:new Set(),toggle(c,v){if(v)this.classes.add(c);else this.classes.delete(c);return this.classes.has(c);}};
    this.button={disabled:false,classList:this.classList,setAttribute(){},textContent:"",title:""};
    videos.push(this);
  }
  addEventListener(name,callback){(this.events[name]||=[]).push(callback);}
  emit(name){for(const fn of this.events[name]||[])fn({target:this});}
  get muted(){return this._muted;}
  set muted(v){if(this._muted!==v){this._muted=v;queueMicrotask(()=>this.emit("volumechange"));}}
  get volume(){return this._volume;}
  set volume(v){if(this._volume!==v){this._volume=v;queueMicrotask(()=>this.emit("volumechange"));}}
  closest(){return this.live?{querySelector:()=>this.button}:null;}
  play(){this.plays++;if(this.failure)return Promise.reject(this.failure);
    if(this.blockOnce){this.blockOnce=false;return Promise.reject(Object.assign(new Error("blocked"),{name:"NotAllowedError"}));}
    return Promise.resolve();}
}
const document={querySelectorAll:()=>videos.filter(v=>v.isConnected)};
const $=id=>({querySelector:()=>videos.at(-1)});
const h=String,t=String,cssId=String;
let system={camera_audio_enabled:true};
"""
        script += self.code + "\n"
        script += r"""
(async()=>{
 const first=new Video();
 first.live=true;
 preparerAudioVideo(first);
 await tick();
 assert.equal(first.muted,true);
 assert.equal(first.defaultMuted,true);

 if(SCENARIO==="initial"){
   assert.equal(first.button.textContent,"live.audio.waiting");
   assert.equal(first.button.disabled,true);
 }else if(SCENARIO==="speaker"){
   first.blinkAudioDisponible=true;
   actualiserBoutonAudio(first);
   assert.equal(first.button.textContent,"live.audio.listen");
   assert.equal(first.button.disabled,false);
   assert.equal(first.classList.classes.has("active"),false);

   // Toggle unmute (listen)
   toggleAudio("Cam");
   await tick();
   assert.equal(first.muted,false);
   assert.equal(first.button.textContent,"live.audio.mute");
   assert.equal(first.classList.classes.has("active"),true);

   // Toggle mute
   toggleAudio("Cam");
   await tick();
   assert.equal(first.muted,true);
   assert.equal(first.button.textContent,"live.audio.listen");
   assert.equal(first.classList.classes.has("active"),false);

   // Unavailable audio
   first.blinkAudioDisponible=false;
   actualiserBoutonAudio(first);
   assert.equal(first.button.disabled,true);
   assert.equal(first.button.textContent,"live.audio.unavailable");
 }else if(SCENARIO==="autoplay"){
   first.blinkAudioDisponible=true;
   actualiserBoutonAudio(first);
   first.muted=false;
   first.blockOnce=true;
   await lireVideo(first);
   await tick();
   assert.equal(first.muted,true);
   assert.equal(first.plays,2);
   assert.equal(first.button.textContent,"live.audio.listen");
 }else if(SCENARIO==="failure"){
   first.failure=new Error("decode failed");
   await assert.rejects(lireVideo(first),/decode failed/);
   assert.equal(first.muted,true);
 }
 console.log(JSON.stringify({ok:true}));
})().catch(error=>{console.error(error);process.exitCode=1;});
""".replace("SCENARIO", json.dumps(scenario))
        result = subprocess.run([self.node, "-"], input=script, text=True,
                                encoding="utf-8", capture_output=True, timeout=10)
        self.assertEqual(result.returncode, 0, result.stderr)
        self.assertTrue(json.loads(result.stdout)["ok"])

    def test_live_initial_state_is_muted(self): self.run_js("initial")
    def test_live_speaker_toggle_and_button_states(self): self.run_js("speaker")
    def test_live_autoplay_rejection_falls_back_to_muted(self): self.run_js("autoplay")
    def test_live_media_error_is_reterror(self): self.run_js("failure")


if __name__ == "__main__":
    unittest.main()