diff options
-rw-r--r-- | src/components/FeedItemDisplay.vue | 43 | ||||
-rw-r--r-- | src/components/Unread.vue | 1 | ||||
-rw-r--r-- | tests/javascript/unit/components/FeedItemDisplay.spec.ts | 92 | ||||
-rw-r--r-- | tests/javascript/unit/components/FeedItemDisplayList.spec.ts | 66 | ||||
-rw-r--r-- | tests/javascript/unit/components/FeedItemRow.spec.ts | 10 |
5 files changed, 196 insertions, 16 deletions
diff --git a/src/components/FeedItemDisplay.vue b/src/components/FeedItemDisplay.vue index edb576b5f..5818fad51 100644 --- a/src/components/FeedItemDisplay.vue +++ b/src/components/FeedItemDisplay.vue @@ -129,28 +129,55 @@ export default Vue.extend({ ...mapState(['feeds']), }, methods: { - clearSelected() { + /** + * Sends message to state to clear the selectedId number + */ + clearSelected(): void { this.$store.commit(MUTATIONS.SET_SELECTED_ITEM, { id: undefined }) }, - formatDate(epoch: number) { + /** + * Returns locale formatted date string + * + * @param {number} epoch date value in epoch format + * @return {string} locale formatted date string (based on users browser) + */ + formatDate(epoch: number): string { return new Date(epoch).toLocaleString() }, - formatDatetime(epoch: number) { + /** + * Returns UTC formatted datetime in format recognized by `datetime` property + * + * @param {number} epoch date value in epoch format + * @return {string} UTC formatted datetime string (in format yyyy-MM-ddTHH:mm:ssZ) + */ + formatDatetime(epoch: number): string { return new Date(epoch).toISOString() }, + /** + * Retrieve the feed by id number + * + * @param {number} id id of feed to fetch + * @return {Feed} associated Feed + */ getFeed(id: number): Feed { return this.$store.getters.feeds.find((feed: Feed) => feed.id === id) || {} }, - getMediaType(mime: any): 'audio' | 'video' | false { + /** + * Sends message to change the items starred property to the opposite value + * + * @param {FeedItem} item item to toggle starred status on + */ + toggleStarred(item: FeedItem): void { + this.$store.dispatch(item.starred ? ACTIONS.UNSTAR_ITEM : ACTIONS.STAR_ITEM, { item }) + }, + + getMediaType(mime: string): 'audio' | 'video' | false { // TODO: figure out how to check media type return false }, - play(item: any) { + play(item: FeedItem) { // TODO: implement play audio/video }, - toggleStarred(item: FeedItem): void { - this.$store.dispatch(item.starred ? ACTIONS.UNSTAR_ITEM : ACTIONS.STAR_ITEM, { item }) - }, }, }) diff --git a/src/components/Unread.vue b/src/components/Unread.vue index 195623245..9a59f529b 100644 --- a/src/components/Unread.vue +++ b/src/components/Unread.vue @@ -26,6 +26,7 @@ import { FeedItem } from '../types/FeedItem' import { ACTIONS, MUTATIONS } from '../store' type UnreadItemState = { + // need cache so we aren't always removing items when they get read unreadCache?: FeedItem[] } diff --git a/tests/javascript/unit/components/FeedItemDisplay.spec.ts b/tests/javascript/unit/components/FeedItemDisplay.spec.ts new file mode 100644 index 000000000..594ccf9c1 --- /dev/null +++ b/tests/javascript/unit/components/FeedItemDisplay.spec.ts @@ -0,0 +1,92 @@ +import { shallowMount, createLocalVue, Wrapper } from '@vue/test-utils' + +import FeedItemDisplay from '../../../../src/components/FeedItemDisplay.vue' +import { ACTIONS, MUTATIONS } from '../../../../src/store' + +describe('FeedItemDisplay.vue', () => { + 'use strict' + const localVue = createLocalVue() + let wrapper: Wrapper<FeedItemDisplay> + + const mockItem = { + feedId: 1, + title: 'feed item', + pubDate: Date.now() / 1000, + } + const mockFeed = { + id: 1, + } + + const dispatchStub = jest.fn() + const commitStub = jest.fn() + beforeAll(() => { + wrapper = shallowMount(FeedItemDisplay, { + propsData: { + item: mockItem, + }, + localVue, + mocks: { + $store: { + getters: { + feeds: [mockFeed], + }, + state: { + feeds: [], + folders: [], + }, + dispatch: dispatchStub, + commit: commitStub, + }, + }, + }) + }) + + beforeEach(() => { + dispatchStub.mockReset() + commitStub.mockReset() + }) + + it('should send SET_SELECTED_ITEM with undefined id', () => { + (wrapper.vm as any).clearSelected() + + expect(commitStub).toBeCalledWith(MUTATIONS.SET_SELECTED_ITEM, { id: undefined }) + }) + + it('should format date to match locale', () => { + const epoch = Date.now() // Provide an epoch timestamp + const formattedDate = (wrapper.vm as any).formatDate(epoch) + + expect(formattedDate).toEqual(new Date(epoch).toLocaleString()) + }) + + it('should format datetime to match international standard', () => { + const epoch = Date.now() // Provide an epoch timestamp + const formattedDate = (wrapper.vm as any).formatDatetime(epoch) + + expect(formattedDate).toEqual(new Date(epoch).toISOString()) + }) + + it('should retrieve feed by ID', () => { + const feed = (wrapper.vm as any).getFeed(mockFeed.id) + + expect(feed).toEqual(mockFeed) + }) + + it('toggles starred state', () => { + wrapper.vm.$props.item.starred = true; + + (wrapper.vm as any).toggleStarred(wrapper.vm.$props.item) + expect(dispatchStub).toHaveBeenCalledWith(ACTIONS.UNSTAR_ITEM, { + item: wrapper.vm.$props.item, + }) + + wrapper.vm.$props.item.starred = false; + + (wrapper.vm as any).toggleStarred(wrapper.vm.$props.item) + expect(dispatchStub).toHaveBeenCalledWith(ACTIONS.STAR_ITEM, { + item: wrapper.vm.$props.item, + }) + }) + + // TODO: Audio/Video tests +}) diff --git a/tests/javascript/unit/components/FeedItemDisplayList.spec.ts b/tests/javascript/unit/components/FeedItemDisplayList.spec.ts new file mode 100644 index 000000000..2b1d7e455 --- /dev/null +++ b/tests/javascript/unit/components/FeedItemDisplayList.spec.ts @@ -0,0 +1,66 @@ +import Vuex, { Store } from 'vuex' +import { shallowMount, createLocalVue, Wrapper } from '@vue/test-utils' + +import FeedItemDisplayList from '../../../../src/components/FeedItemDisplayList.vue' +import VirtualScroll from '../../../../src/components/VirtualScroll.vue' +import FeedItemRow from '../../../../src/components/FeedItemRow.vue' + +jest.mock('@nextcloud/axios') + +describe('FeedItemDisplayList.vue', () => { + 'use strict' + const localVue = createLocalVue() + localVue.use(Vuex) + let wrapper: Wrapper<FeedItemDisplayList> + + const mockItem = { + feedId: 1, + title: 'feed item', + pubDate: Date.now() / 1000, + } + + let store: Store<any> + beforeAll(() => { + store = new Vuex.Store({ + state: { + items: { + allItemsLoaded: { + unread: false, + }, + }, + }, + actions: { + }, + getters: { + unread: () => [mockItem, mockItem], + }, + }) + + store.dispatch = jest.fn() + store.commit = jest.fn() + + wrapper = shallowMount(FeedItemDisplayList, { + propsData: { + items: [mockItem], + fetchKey: 'unread', + }, + localVue, + store, + }) + }) + + it('should create FeedItemRow items from input', () => { + expect((wrapper.findComponent(VirtualScroll)).findAllComponents(FeedItemRow).length).toEqual(1) + + wrapper = shallowMount(FeedItemDisplayList, { + propsData: { + items: [mockItem, mockItem], + fetchKey: 'unread', + }, + localVue, + store, + }) + expect((wrapper.findComponent(VirtualScroll)).findAllComponents(FeedItemRow).length).toEqual(2) + }) + +}) diff --git a/tests/javascript/unit/components/FeedItemRow.spec.ts b/tests/javascript/unit/components/FeedItemRow.spec.ts index 14c2d6cca..dde0106a9 100644 --- a/tests/javascript/unit/components/FeedItemRow.spec.ts +++ b/tests/javascript/unit/components/FeedItemRow.spec.ts @@ -48,20 +48,14 @@ describe('FeedItemRow.vue', () => { expect(wrapper.vm.$data.keepUnread).toBeFalsy() }) - it('should expand when clicked', async () => { - await wrapper.find('.feed-item-row').trigger('click') - - // expect(wrapper.vm.$data.expanded).toBe(true) - }) - - it('should format date correctly', () => { + it('should format date to match locale', () => { const epoch = Date.now() // Provide an epoch timestamp const formattedDate = (wrapper.vm as any).formatDate(epoch) expect(formattedDate).toEqual(new Date(epoch).toLocaleString()) }) - it('should format datetime correctly', () => { + it('should format datetime to match international standard', () => { const epoch = Date.now() // Provide an epoch timestamp const formattedDate = (wrapper.vm as any).formatDatetime(epoch) |