diff --git a/pkg/service/soundtouchweb/browser_compatibility_test.go b/pkg/service/soundtouchweb/browser_compatibility_test.go index a01753bf..ac1c3253 100644 --- a/pkg/service/soundtouchweb/browser_compatibility_test.go +++ b/pkg/service/soundtouchweb/browser_compatibility_test.go @@ -965,16 +965,20 @@ func TestStaleSourcesRemainVisibleButCannotBeSelected(t *testing.T) { t.Errorf("fresh sources: enabled=%d want=%d staleIndicatorMissing=%v", enabledCount, sourceCount, staleIndicatorMissing) } - var noInventoryText, noInventoryRole string + var emptyInventoryHidden, staleEmptyAnnounced bool if err := chromedp.Run(ctx, chromedp.Evaluate(`window.renderStatus('STANDBY', '', false, 'speaker', null, [])`, nil), - chromedp.WaitVisible(`#source-inventory-status`, chromedp.ByQuery), - chromedp.Text(`#source-inventory-status`, &noInventoryText, chromedp.ByQuery), - chromedp.AttributeValue(`#source-inventory-status`, "role", &noInventoryRole, nil, chromedp.ByQuery), + chromedp.Poll(`document.querySelector('.sources-section') === null`, nil), + chromedp.Evaluate(`document.querySelector('.sources-section') === null`, &emptyInventoryHidden), + // A stale empty inventory still has something to say: we know the list + // is untrustworthy, as opposed to simply not having read one yet. + chromedp.Evaluate(`window.renderStatus('STANDBY', '', true, 'speaker', null, [])`, nil), + chromedp.WaitVisible(`#source-stale-status`, chromedp.ByQuery), + chromedp.Evaluate(`document.querySelector('#source-stale-status').textContent.trim() === 'Source list out of date'`, &staleEmptyAnnounced), ); err != nil { t.Fatalf("render missing source inventory: %v", err) } - if noInventoryText != "Source list unavailable" || noInventoryRole != "status" { - t.Errorf("missing source inventory: text=%q role=%q", noInventoryText, noInventoryRole) + if !emptyInventoryHidden || !staleEmptyAnnounced { + t.Errorf("empty inventory: hidden=%v staleAnnounced=%v", emptyInventoryHidden, staleEmptyAnnounced) } } diff --git a/pkg/service/soundtouchweb/static/js/components/Sources.js b/pkg/service/soundtouchweb/static/js/components/Sources.js index 2e4ccbc1..e75d269f 100644 --- a/pkg/service/soundtouchweb/static/js/components/Sources.js +++ b/pkg/service/soundtouchweb/static/js/components/Sources.js @@ -95,12 +95,15 @@ export function Sources({ }, [command, currentSource, currentAccount, nowPlayingRevision]); const ready = items.filter(s => s.Status === 'READY'); + // Nothing to show and nothing to say: a device that has not been polled + // yet has no inventory to call out of date. Only render once there is + // either a list to offer or a list we are refusing to act on. + if (ready.length === 0 && !sourcesStale) return null; + const availabilityMessage = sourcesStale ? 'Source list out of date' - : (ready.length === 0 ? 'Source list unavailable' : ''); - const availabilityId = sourcesStale - ? 'source-stale-status' - : (ready.length === 0 ? 'source-inventory-status' : null); + : ''; + const availabilityId = sourcesStale ? 'source-stale-status' : null; async function select(src) { clearReadbacks();