diff --git a/vue/src/composables/__tests__/viewModeBoot.spec.js b/vue/src/composables/__tests__/viewModeBoot.spec.js new file mode 100644 index 0000000..4aedde5 --- /dev/null +++ b/vue/src/composables/__tests__/viewModeBoot.spec.js @@ -0,0 +1,72 @@ +// Reproduces the "reload the tab while in article view" boot sequence: +// module-scope init must pick up the persisted viewMode, and RssFeeds' +// mount flow (fetchData + sync) must not reset it back to 'list'. +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' +import { flushPromises, mount } from '@vue/test-utils' + +vi.mock('axios') + +class FakeIntersectionObserver { + observe() {} + unobserve() {} + disconnect() {} +} +vi.stubGlobal('IntersectionObserver', FakeIntersectionObserver) + +describe('viewMode boot persistence', () => { + beforeEach(() => { + vi.resetModules() + localStorage.clear() + localStorage.setItem('user-token', 'test-token') + localStorage.setItem('user-id', '7') + }) + + afterEach(() => { + localStorage.clear() + }) + + it('boots into article view when localStorage says so, surviving the mount fetch/sync', async () => { + localStorage.setItem('viewMode', 'article') + + const axios = (await import('axios')).default + axios.get.mockResolvedValue({ + data: { + feeds: [ + { + title: 'My Feed', + items: [ + { id: 1, title: 'Article one', content: '

hi

', url: 'https://example.test/1', timestamp: '2026-01-01 10:00:00' }, + ], + }, + ], + }, + }) + axios.post.mockResolvedValue({ status: 200 }) + axios.put.mockResolvedValue({ status: 200 }) + + // Import AFTER setting storage — module-scope refs initialize at import. + const { useFeeds } = await import('../useFeeds') + const { viewMode } = useFeeds() + expect(viewMode.value).toBe('article') + + const RssFeeds = (await import('../../components/RssFeeds.vue')).default + const wrapper = mount(RssFeeds) + await flushPromises() + + expect(viewMode.value).toBe('article') + expect(wrapper.find('.article-single').exists()).toBe(true) + expect(wrapper.find('#article').exists()).toBe(false) + + wrapper.unmount() + }) + + it('boots into list view when the key is absent', async () => { + const axios = (await import('axios')).default + axios.get.mockResolvedValue({ data: { feeds: [] } }) + axios.post.mockResolvedValue({ status: 200 }) + + const { useFeeds } = await import('../useFeeds') + const { viewMode } = useFeeds() + expect(viewMode.value).toBe('list') + }) +})