const {test}=require('node:test'); const assert=require('node:assert/strict'); const {readFileSync}=require('node:fs'); const {createHash}=require('node:crypto'); const {join}=require('node:path'); const app=readFileSync(join(__dirname,'app.js'),'utf8'); test('Phase 4 preserves the exact player, continuity, tracking and queue bodies',()=>{ {const start=app.indexOf("const Player = {");assert.ok(start>=0,"Player");const body=app.slice(start,start+30343);assert.equal(createHash('sha256').update(body).digest('hex'),"373df46f4f994717472d26a6bac07449f6ca0a930cb666bfe3895d1dc65aa351","Player body unchanged");} {const start=app.indexOf("const Transition = (() => {");assert.ok(start>=0,"Transition");const body=app.slice(start,start+8588);assert.equal(createHash('sha256').update(body).digest('hex'),"71997a537078308a41f0cbf8e29fd1658fb3a199c4f5a25d8af0931f1c2a6d50","Transition body unchanged");} {const start=app.indexOf("const Wave = (() => {");assert.ok(start>=0,"Wave");const body=app.slice(start,start+5241);assert.equal(createHash('sha256').update(body).digest('hex'),"7252f4e856c59aef8aabfcd394ce4bcba656110cbd01a1a8af662eeb48166a3c","Wave body unchanged");} {const start=app.indexOf("const StatsTrack = (() => {");assert.ok(start>=0,"StatsTrack");const body=app.slice(start,start+1462);assert.equal(createHash('sha256').update(body).digest('hex'),"9aae2631ba3bfad918319579b7120814af06c84949394d04e52c65345332d514","StatsTrack body unchanged");} {const start=app.indexOf("function wirePlayerEvents() {");assert.ok(start>=0,"wirePlayerEvents");const body=app.slice(start,start+4913);assert.equal(createHash('sha256').update(body).digest('hex'),"1c5a2b5ce310f6aef6764325eda85a95f47e4f507f2049036ce1da206379908c","wirePlayerEvents body unchanged");} {const start=app.indexOf("function updatePlayBtn() {");assert.ok(start>=0,"updatePlayBtn");const body=app.slice(start,start+522);assert.equal(createHash('sha256').update(body).digest('hex'),"1326233af07ae92a5ecc81cc211bd98d21ed5f291dc4eb59d040b8df9baba8c8","updatePlayBtn body unchanged");} {const start=app.indexOf("function persist() {");assert.ok(start>=0,"persist");const body=app.slice(start,start+147);assert.equal(createHash('sha256').update(body).digest('hex'),"01e5c5dbc80616266db09b3829dc45b66476a3256b1c169d8e44f4983b24ac45","persist body unchanged");} {const start=app.indexOf("function playFromList(list, index, source = '', { playFull = false } = {}) {");assert.ok(start>=0,"playFromList");const body=app.slice(start,start+401);assert.equal(createHash('sha256').update(body).digest('hex'),"f8009c9674b3478959997dca881fb7b9e1ab3708c98e5abdf1958d752e47ee41","playFromList body unchanged");} {const start=app.indexOf("function advanceQueue() {");assert.ok(start>=0,"advanceQueue");const body=app.slice(start,start+596);assert.equal(createHash('sha256').update(body).digest('hex'),"be405b9c163e3d41a949ef11f6022ef13115b04083e3b6ad21d97beba1f45ae6","advanceQueue body unchanged");} {const start=app.indexOf("function playNext() {");assert.ok(start>=0,"playNext");const body=app.slice(start,start+143);assert.equal(createHash('sha256').update(body).digest('hex'),"859d2ffd2e8c89a8d9c0dd0cf429fd403675452cedba2e34aa3dc72683d4f8c6","playNext body unchanged");} {const start=app.indexOf("function playPrev() {");assert.ok(start>=0,"playPrev");const body=app.slice(start,start+268);assert.equal(createHash('sha256').update(body).digest('hex'),"ece8d33bd03c8146a6a702534c8fed50ff606170685b08d730b19d9d3c68cf48","playPrev body unchanged");} {const start=app.indexOf("function onTrackEnded() {");assert.ok(start>=0,"onTrackEnded");const body=app.slice(start,start+702);assert.equal(createHash('sha256').update(body).digest('hex'),"d6e147238ad9656fa1c2335973b37597749bcfd02df1a66390b306fe1194ae0d","onTrackEnded body unchanged");} {const start=app.indexOf("function sleepFadeSec() {");assert.ok(start>=0,"sleepFadeSec");const body=app.slice(start,start+138);assert.equal(createHash('sha256').update(body).digest('hex'),"3f986c8cc474d8313476e9c209b9264e3724011ffaee887f47178bb5155a4d77","sleepFadeSec body unchanged");} {const start=app.indexOf("function applySleepFade(remaining) {");assert.ok(start>=0,"applySleepFade");const body=app.slice(start,start+346);assert.equal(createHash('sha256').update(body).digest('hex'),"9bd0fa697b271c6b80c128ff1d0a7b00afcb3ccf08f98b5c7e7dc86fd4329681","applySleepFade body unchanged");} {const start=app.indexOf("function startSleepTimer(minutes, { endOfSong = false } = {}) {");assert.ok(start>=0,"startSleepTimer");const body=app.slice(start,start+487);assert.equal(createHash('sha256').update(body).digest('hex'),"f0a93401ab90196096074cb607b28d52c5903e11dbdfb8ddb95114e143af2409","startSleepTimer body unchanged");} {const start=app.indexOf("function cancelSleepTimer() {");assert.ok(start>=0,"cancelSleepTimer");const body=app.slice(start,start+253);assert.equal(createHash('sha256').update(body).digest('hex'),"cf396ab758a70eede6af7444539a82ca15af801a9a57024dd5542067e9fa771a","cancelSleepTimer body unchanged");} {const start=app.indexOf("function finishSleep() {");assert.ok(start>=0,"finishSleep");const body=app.slice(start,start+662);assert.equal(createHash('sha256').update(body).digest('hex'),"7ee93bf760bad5f39f4644339963918c5b369b2acc554b8e561c1a1f070ac6fb","finishSleep body unchanged");} {const start=app.indexOf("const EQ = (() => {");assert.ok(start>=0,"EQ");const body=app.slice(start,start+7917);assert.equal(createHash('sha256').update(body).digest('hex'),"f0cba011c94f33e6fd0ab778021f4c97238262dfa0a8dd40bf3f17149c227528","EQ body unchanged");} {const start=app.indexOf("const EqRender = (() => {");assert.ok(start>=0,"EqRender");const body=app.slice(start,start+5912);assert.equal(createHash('sha256').update(body).digest('hex'),"f014dd41dafebc33f09e87be866074afd7a2443c5bb452103a435585353a828f","EqRender body unchanged");} {const start=app.indexOf("const Level = (() => {");assert.ok(start>=0,"Level");const body=app.slice(start,start+3892);assert.equal(createHash('sha256').update(body).digest('hex'),"e48ad7797384ac31bb8b864662fc2a546b04470b981042f016874ba750957226","Level body unchanged");} }); test('eager shell and Settings definitions load before app state and defer reading it',()=>{ const html=readFileSync(join(__dirname,'index.html'),'utf8'); for(const file of ['shell-core.js','views-core.js','section-rail.js']) { assert.ok(html.indexOf('src="'+file+'"'){ const source=app.match(/\/\* Remote facade \*\/([\s\S]*?)\/\* End remote facade \*\//)?.[1]; assert.ok(source,'remote facade is present'); const context=require('node:vm').createContext({window:{},Lazy:{proxy:()=>({}),onLoad(){}}}); require('node:vm').runInContext(source+';globalThis.api=Remote;',context); assert.equal(context.api.changed(),undefined); let calls=0;context.window.YT={Remote:{changed:()=>{calls++;return 'sync';}}}; assert.equal(context.api.changed(),'sync');assert.equal(calls,1); }); test('watch-party facade keeps playback decisions synchronous before and after loading',()=>{ const source=app.match(/\/\* Party facade \*\/([\s\S]*?)\/\* End party facade \*\//)?.[1];assert.ok(source); const context=require('node:vm').createContext({window:{},Lazy:{proxy:()=>({}),onLoad(){}}}); require('node:vm').runInContext(source+';globalThis.api=Party;',context); for(const method of ['guestActive','intercept','nextDJ'])assert.equal(context.api[method]('next'),false); context.window.YT={Party:{guestActive:()=>true,intercept:action=>action==='next',nextDJ:()=>true}}; for(const method of ['guestActive','intercept','nextDJ'])assert.equal(context.api[method]('next'),true); }); test('Share and External stay behind lazy entry proxies',()=>{ assert.match(app,/const Share = Lazy\.proxy\('feature:share-external'/); assert.match(app,/const External = Lazy\.proxy\('feature:share-external'/); const chunk=readFileSync(join(__dirname,'share-external.js'),'utf8'); const context=require('node:vm').createContext({window:{},navigator:{userAgent:''},location:{origin:'https://fixture.test'},isUploadId:()=>false}); require('node:vm').runInContext(chunk,context); assert.equal(typeof context.window.YT.Share.open,'function'); const text=context.window.YT.External.m3u([{id:'benchmedia01',title:'Fixture'}]); assert.match(text,/#EXTM3U/);assert.match(text,/benchmedia01/); }); test('listening tracking does not pull in the lazy Stats view',()=>{ const {groups}=JSON.parse(readFileSync(join(__dirname,'assets.json'),'utf8')); assert.deepEqual(groups['feature:stats-view'].files,['/stats-view.js']); assert.deepEqual(groups['feature:stats-view'].dependencies,['feature:stats']); assert.deepEqual(groups['feature:stats'].files,['/stats-core.js']); assert.match(app,/Lazy\.proxy\('feature:stats-view', \['render'\], 'StatsView'\)/); });