Report unavailable lazy chunks without rejecting UI actions

This commit is contained in:
Jonathan Sykes
2026-10-08 04:48:52 +08:00
parent b335f95f45
commit 2c5003575c
3 changed files with 15 additions and 4 deletions

View File

@@ -76,3 +76,10 @@ test('listening tracking does not pull in the lazy Stats view',()=>{
assert.deepEqual(groups['feature:stats'].files,['/stats-core.js']);
assert.match(app,/Lazy\.proxy\('feature:stats-view', \['render'\], 'StatsView'\)/);
});
test('an unavailable Stats chunk reports an error without rejecting the UI navigation',async()=>{
const source=app.match(/function renderStats\(\) \{[\s\S]*?\n\}/)?.[0];assert.ok(source);
const seen=[],context=require('node:vm').createContext({Lazy:{proxy:()=>({render:()=>Promise.reject(new Error('Unavailable fixture chunk'))})},toast:text=>seen.push(text)});
require('node:vm').runInContext(source+';globalThis.render=renderStats;',context);
await context.render();assert.deepEqual(seen,['Unavailable fixture chunk']);
});

View File

@@ -5181,7 +5181,7 @@ const StatsTrack = (() => {
// Stats view
// ============================================================================
function renderStats() {
return Lazy.proxy('feature:stats-view', ['render'], 'StatsView').render();
return Lazy.proxy('feature:stats-view', ['render'], 'StatsView').render().catch(error => toast(error.message));
}
@@ -7798,8 +7798,8 @@ document.querySelectorAll('.chip').forEach((c) => {
$('sleepCurtain').addEventListener('click', () => $('sleepCurtain').classList.add('hidden'));
$('sleepCancelBtn').addEventListener('click', () => { cancelSleepTimer(); toast('Sleep timer cancelled'); });
$('transitionBtn').addEventListener('click', () => Transition.cycle());
$('shareMomentBtn').addEventListener('click', () => Share.open());
$('externalBtn').addEventListener('click', () => External.open());
$('shareMomentBtn').addEventListener('click', () => Share.open().catch(error => toast(error.message)));
$('externalBtn').addEventListener('click', () => External.open().catch(error => toast(error.message)));
$('pipBtn').addEventListener('click', () => PiP.toggle());
$('eqBtn').addEventListener('click', () => EQ.open());
@@ -9005,7 +9005,7 @@ async function boot() {
syncOnLaunch();
startPlaylistInboxWatch();
if(LowerThird.active()) await Lazy.load('feature:lower-third');
await Presenter.boot();
await Presenter.boot().catch(error => toast(error.message));
if (LowerThird.active()) return;
SectionRail.boot();
if (isMediaId(new URLSearchParams(location.search).get('v'))) Share.bootFromUrl().catch(error => toast(error.message));

View File

@@ -63,6 +63,10 @@ async function run(name){
if(groups.includes('feature:stats-view')) {
await page.evaluate(async()=>{view={type:'stats'};render();});await page.waitForSelector('.stats-empty');checked.push('stats');
}
if(groups.includes('feature:share-external')) {
await page.evaluate(()=>{Share.open=()=>Promise.reject(new Error('Unavailable fixture chunk'));document.querySelector('#shareMomentBtn').click();});
await page.getByText('Unavailable fixture chunk',{exact:true}).waitFor();
}
assert.equal(proxy.getStats().requestCount,before,'all warmed seam code loads from SW without network');
// Ignore only verified disconnected version/recommendation API transports in WebKit.
const scriptErrors=errors.filter(e=>!(name==='webkit'&&(e==='TypeError: Load failed'||/\/api\/(?:recommendations\?[^\s]*|version)\.$/.test(e))));assert.deepEqual(scriptErrors,[]);