hamburger menu, article view
This commit is contained in:
@@ -2,6 +2,7 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { mount, flushPromises } from '@vue/test-utils'
|
||||
import axios from 'axios'
|
||||
import RssFeeds from '../RssFeeds.vue'
|
||||
import { useFeeds } from '../../composables/useFeeds'
|
||||
|
||||
vi.mock('axios')
|
||||
|
||||
@@ -19,6 +20,14 @@ describe('RssFeeds', () => {
|
||||
localStorage.setItem('user-token', 'test-token')
|
||||
localStorage.setItem('user-id', '7')
|
||||
vi.clearAllMocks()
|
||||
|
||||
// useFeeds() returns module-level singleton refs shared across the whole
|
||||
// app (and this spec file) — reset them so state doesn't leak between tests.
|
||||
const { feeds, showMessage, message, showModal } = useFeeds()
|
||||
feeds.value = []
|
||||
showMessage.value = false
|
||||
message.value = ''
|
||||
showModal.value = false
|
||||
})
|
||||
|
||||
it('fetches the current user articles and shows the empty state', async () => {
|
||||
@@ -98,20 +107,102 @@ describe('RssFeeds', () => {
|
||||
expect(titles).toEqual(['Newer article', 'Older article'])
|
||||
})
|
||||
|
||||
it('syncs feeds for the current user', async () => {
|
||||
axios.get.mockResolvedValue({ data: { feeds: [] } })
|
||||
axios.post.mockResolvedValueOnce({ status: 200 })
|
||||
it('shows a link to the original article until the readable version is loaded', async () => {
|
||||
// The API returns each item with a short summary already in `content` —
|
||||
// the link must key off the `readable` flag (set once Readability has
|
||||
// parsed the full article), not off `content` truthiness.
|
||||
axios.get.mockResolvedValueOnce({
|
||||
data: {
|
||||
feeds: [
|
||||
{
|
||||
title: 'My Feed',
|
||||
items: [
|
||||
{
|
||||
id: 1,
|
||||
title: 'Article one',
|
||||
content: '<p>short summary</p>',
|
||||
url: 'https://example.test/1',
|
||||
timestamp: '2026-01-01',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
axios.post.mockResolvedValueOnce({ data: { content: '<html><body><article><p>full text</p></article></body></html>' } })
|
||||
|
||||
const wrapper = mount(RssFeeds)
|
||||
await flushPromises()
|
||||
|
||||
await wrapper.find('.feed-actions p').trigger('click')
|
||||
const link = wrapper.find('.feed-original-link a')
|
||||
expect(link.exists()).toBe(true)
|
||||
expect(link.attributes('href')).toBe('https://example.test/1')
|
||||
expect(link.attributes('target')).toBe('_blank')
|
||||
|
||||
await wrapper.find('.feed-title').trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
expect(axios.post).toHaveBeenCalledWith(
|
||||
'/api/v1/article/sync',
|
||||
{ user_id: 7 },
|
||||
expect.anything(),
|
||||
)
|
||||
expect(wrapper.find('.feed-original-link a').exists()).toBe(false)
|
||||
})
|
||||
|
||||
it('switches to article view and navigates between articles', async () => {
|
||||
axios.get.mockResolvedValueOnce({
|
||||
data: {
|
||||
feeds: [
|
||||
{
|
||||
title: 'My Feed',
|
||||
items: [
|
||||
{
|
||||
id: 1,
|
||||
title: 'Article one',
|
||||
content: '<p>one</p>',
|
||||
url: 'https://example.test/1',
|
||||
timestamp: '2026-02-01 10:00:00',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'Article two',
|
||||
content: '<p>two</p>',
|
||||
url: 'https://example.test/2',
|
||||
timestamp: '2026-01-01 10:00:00',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
axios.put.mockResolvedValue({ status: 200 })
|
||||
axios.post.mockResolvedValue({ data: { content: '<html><body><article><p>full text</p></article></body></html>' } })
|
||||
|
||||
const wrapper = mount(RssFeeds)
|
||||
await flushPromises()
|
||||
|
||||
await wrapper.find('.view-toggle__btn').trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.find('.article-single .feed-title').text()).toBe('Article one')
|
||||
// Same as in list view: the readable content is loaded on demand by
|
||||
// clicking the headline, not fetched automatically on entering the view.
|
||||
expect(axios.post).not.toHaveBeenCalled()
|
||||
expect(wrapper.find('.article-single .feed-original-link a').exists()).toBe(true)
|
||||
|
||||
await wrapper.find('.article-single .feed-title').trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
expect(axios.post).toHaveBeenCalledWith('/api/v1/article/read', { url: 'https://example.test/1' }, expect.anything())
|
||||
expect(wrapper.find('.article-single .feed-original-link a').exists()).toBe(false)
|
||||
|
||||
expect(wrapper.findAll('.article-nav__btn')[0].attributes('disabled')).toBeDefined()
|
||||
|
||||
await wrapper.findAll('.article-nav__btn')[1].trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.find('.article-single .feed-title').text()).toBe('Article two')
|
||||
expect(wrapper.findAll('.article-nav__btn')[1].attributes('disabled')).toBeDefined()
|
||||
|
||||
await wrapper.findAll('.article-nav__btn')[0].trigger('click')
|
||||
await flushPromises()
|
||||
|
||||
expect(wrapper.find('.article-single .feed-title').text()).toBe('Article one')
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user