data
' }) + expect(w.find('.skeleton-stub').exists()).toBe(true) + expect(w.text()).not.toContain('data') + }) + + it('error: renders Message + retry Button; emits retry on click', async () => { + const w = mountSB({ state: 'error', errorMessage: 'Mislukt' }) + expect(w.get('.message-stub').text()).toContain('Mislukt') + await w.get('.btn-stub').trigger('click') + expect(w.emitted('retry')).toHaveLength(1) + }) + + it('empty: renders empty Card + action Button; emits action on click', async () => { + const w = mountSB({ state: 'empty', emptyMessage: 'Niets hier', actionLabel: 'Maak aan' }) + expect(w.text()).toContain('Niets hier') + await w.get('.btn-stub').trigger('click') + expect(w.emitted('action')).toHaveLength(1) + }) + + it('success: renders the default slot, no state chrome', () => { + const w = mountSB({ state: 'success' }, { default: 'real content
' }) + expect(w.text()).toContain('real content') + expect(w.find('.skeleton-stub').exists()).toBe(false) + expect(w.find('.message-stub').exists()).toBe(false) + }) + + it('transition loading→success swaps chrome for slot content', async () => { + const w = mountSB({ state: 'loading' }, { default: 'loaded
' }) + expect(w.find('.skeleton-stub').exists()).toBe(true) + await w.setProps({ state: 'success' }) + expect(w.find('.skeleton-stub').exists()).toBe(false) + expect(w.text()).toContain('loaded') + }) + + it('transition error→loading clears the message', async () => { + const w = mountSB({ state: 'error', errorMessage: 'Mislukt' }) + expect(w.text()).toContain('Mislukt') + await w.setProps({ state: 'loading' }) + expect(w.find('.message-stub').exists()).toBe(false) + expect(w.find('.skeleton-stub').exists()).toBe(true) + }) +}) +``` + +- [ ] **Step 2: Run — expect FAIL.** Run: `pnpm test -- StateBlock`. + +- [ ] **Step 3: Implement `StateBlock.vue`** + +```vue + + + ++ {{ emptyMessage ?? 'Nog niets om te tonen.' }} +
+ + +Echte inhoud.
{{ tags }}