// @vitest-environment happy-dom import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' import FeedEmptyState from '../../src/components/posts/FeedEmptyState.vue' import { useSourcesStore } from '../../src/stores/sources.js' import { mountWithStore } from '../support/mountComponent.js' // #387 B4. This is the first screen a fresh install shows anyone, so the thing // worth pinning is that it tells the two empties apart. Telling an operator to // "add a source" when they already have three and are mid-backfill is worse // than saying nothing — it reads as the app not knowing its own state. const mountWith = (status) => mountWithStore(FeedEmptyState, () => { useSourcesStore().scheduleStatus = status }) describe('FeedEmptyState', () => { beforeEach(() => { globalThis.fetch = vi.fn(async () => { throw new Error('offline') }) }) afterEach(() => vi.restoreAllMocks()) it('a fresh install gets the on-ramp, credential first', () => { const w = mountWith({ total_sources: 0 }) expect(w.text()).toContain('Add a credential') expect(w.text()).toContain('Add a source') expect(w.text()).not.toContain("See what's running") }) it('an install that is already fetching is told so, not told to set up', () => { const w = mountWith({ total_sources: 3 }) expect(w.text()).toContain('3 sources') expect(w.text()).toContain("See what's running") expect(w.text()).not.toContain('Add a credential') }) it('singularises a lone source', () => { const w = mountWith({ total_sources: 1 }) expect(w.text()).toContain('1 source') expect(w.text()).not.toContain('1 sources') }) it('falls back to the on-ramp when the status call never answered', () => { // Safe direction: the on-ramp is merely redundant to an established // operator, whereas "see what's running" shown to someone with nothing // configured is a dead end. const w = mountWith(null) expect(w.text()).toContain('Add a credential') }) it('shows the brand mark, sized to be readable', () => { // logo.svg stops reading below ~48px — that is why the 22px nav slot has a // different mark. If this ever shrinks to a glyph, it is the wrong asset. const img = mountWith({ total_sources: 0 }).find('img.fc-empty__mark') expect(img.exists()).toBe(true) expect(img.attributes('src')).toBe('/logo.svg') expect(Number(img.attributes('width'))).toBeGreaterThanOrEqual(48) // Decorative: the surrounding prose already carries the meaning. expect(img.attributes('alt')).toBe('') }) })