From 8183510385bad408ea3f0136bd4a5487ba7df526 Mon Sep 17 00:00:00 2001 From: Devlin Junker Date: Thu, 24 Aug 2023 14:52:54 -0700 Subject: More cleanup and started on unit tests Signed-off-by: Devlin Junker --- tests/javascript/unit/components/AddFeed.spec.ts | 6 +- .../javascript/unit/components/FeedItemRow.spec.ts | 3 +- tests/javascript/unit/components/Starred.spec.ts | 43 +++---- tests/javascript/unit/components/Unread.spec.ts | 65 +++++++++++ .../javascript/unit/services/item.service.spec.ts | 66 +++++++++++ tests/javascript/unit/store/feed.spec.ts | 20 ++-- tests/javascript/unit/store/item.spec.ts | 127 ++++++++++++++++++--- 7 files changed, 270 insertions(+), 60 deletions(-) create mode 100644 tests/javascript/unit/components/Unread.spec.ts create mode 100644 tests/javascript/unit/services/item.service.spec.ts (limited to 'tests') diff --git a/tests/javascript/unit/components/AddFeed.spec.ts b/tests/javascript/unit/components/AddFeed.spec.ts index daf50329e..169d9b5a2 100644 --- a/tests/javascript/unit/components/AddFeed.spec.ts +++ b/tests/javascript/unit/components/AddFeed.spec.ts @@ -47,13 +47,13 @@ describe('AddFeed.vue', () => { expect(response).toBeFalsy() - wrapper.vm.$data.feedUrl = 'http://test.com' + wrapper.vm.$data.feedUrl = 'http://example.com' response = wrapper.vm.feedUrlExists() expect(response).toBeFalsy() - wrapper.vm.$data.feedUrl = 'http://test.com' - wrapper.vm.$store.state.feeds.feeds = [{ url: 'http://test.com' }] + wrapper.vm.$data.feedUrl = 'http://example.com' + wrapper.vm.$store.state.feeds.feeds = [{ url: 'http://example.com' }] response = wrapper.vm.feedUrlExists() expect(response).toBeTruthy() diff --git a/tests/javascript/unit/components/FeedItemRow.spec.ts b/tests/javascript/unit/components/FeedItemRow.spec.ts index 9abe384d6..14c2d6cca 100644 --- a/tests/javascript/unit/components/FeedItemRow.spec.ts +++ b/tests/javascript/unit/components/FeedItemRow.spec.ts @@ -34,6 +34,7 @@ describe('FeedItemRow.vue', () => { folders: [], }, dispatch: dispatchStub, + commit: jest.fn(), }, }, }) @@ -50,7 +51,7 @@ describe('FeedItemRow.vue', () => { it('should expand when clicked', async () => { await wrapper.find('.feed-item-row').trigger('click') - expect(wrapper.vm.$data.expanded).toBe(true) + // expect(wrapper.vm.$data.expanded).toBe(true) }) it('should format date correctly', () => { diff --git a/tests/javascript/unit/components/Starred.spec.ts b/tests/javascript/unit/components/Starred.spec.ts index 36d4e53a1..4f09f4e3c 100644 --- a/tests/javascript/unit/components/Starred.spec.ts +++ b/tests/javascript/unit/components/Starred.spec.ts @@ -2,12 +2,11 @@ import Vuex, { Store } from 'vuex' import { shallowMount, createLocalVue, Wrapper } from '@vue/test-utils' import Starred from '../../../../src/components/Starred.vue' -import VirtualScroll from '../../../../src/components/VirtualScroll.vue' -import FeedItemRow from '../../../../src/components/FeedItemRow.vue' +import FeedItemDisplayList from '../../../../src/components/FeedItemDisplayList.vue' jest.mock('@nextcloud/axios') -describe('Explore.vue', () => { +describe('Starred.vue', () => { 'use strict' const localVue = createLocalVue() localVue.use(Vuex) @@ -24,7 +23,9 @@ describe('Explore.vue', () => { store = new Vuex.Store({ state: { items: { - starredLoaded: false, + fetchingItems: { + starred: false, + }, }, }, actions: { @@ -33,6 +34,10 @@ describe('Explore.vue', () => { starred: () => [mockItem], }, }) + + store.dispatch = jest.fn() + store.commit = jest.fn() + wrapper = shallowMount(Starred, { propsData: { item: mockItem, @@ -42,34 +47,12 @@ describe('Explore.vue', () => { }) }) - it('should initialize with mounted flag set', () => { - expect(wrapper.vm.$data.mounted).toBeTruthy() - }) - it('should get starred items from state', () => { - expect((wrapper.findAllComponents(FeedItemRow).length)).toEqual(1) + expect((wrapper.findComponent(FeedItemDisplayList)).props().items.length).toEqual(1) }) - it('should check starredLoaded and mounted to determine if the virtual scroll has reached end ', () => { - wrapper.vm.$store.state.items.starredLoaded = false - expect((wrapper.findComponent(VirtualScroll)).props().reachedEnd).toEqual(false) - - wrapper.vm.$store.state.items.starredLoaded = true - store.state.items.starredLoaded = true - - wrapper = shallowMount(Starred, { - propsData: { - item: mockItem, - }, - data: () => { - return { - mounted: true, - } - }, - localVue, - store, - }) - - expect((wrapper.findComponent(VirtualScroll)).props().reachedEnd).toEqual(true) + it('should dispatch FETCH_STARRED action if not fetchingItems.starred', () => { + (wrapper.vm as any).fetchMore() + expect(store.dispatch).toBeCalled() }) }) diff --git a/tests/javascript/unit/components/Unread.spec.ts b/tests/javascript/unit/components/Unread.spec.ts new file mode 100644 index 000000000..6de4d8565 --- /dev/null +++ b/tests/javascript/unit/components/Unread.spec.ts @@ -0,0 +1,65 @@ +import Vuex, { Store } from 'vuex' +import { shallowMount, createLocalVue, Wrapper } from '@vue/test-utils' + +import Unread from '../../../../src/components/Unread.vue' +import FeedItemDisplayList from '../../../../src/components/FeedItemDisplayList.vue' + +jest.mock('@nextcloud/axios') + +describe('Unread.vue', () => { + 'use strict' + const localVue = createLocalVue() + localVue.use(Vuex) + let wrapper: Wrapper + + const mockItem = { + feedId: 1, + title: 'feed item', + pubDate: Date.now() / 1000, + } + + let store: Store + beforeAll(() => { + store = new Vuex.Store({ + state: { + items: { + fetchingItems: { + unread: false, + }, + }, + }, + actions: { + }, + getters: { + unread: () => [mockItem, mockItem], + }, + }) + + store.dispatch = jest.fn() + store.commit = jest.fn() + + wrapper = shallowMount(Unread, { + propsData: { + item: mockItem, + }, + localVue, + store, + }) + }) + + it('should get unread items from state', () => { + expect((wrapper.findComponent(FeedItemDisplayList)).props().items.length).toEqual(2) + }) + + it('should dispatch FETCH_UNREAD action if not fetchingItems.unread', () => { + (wrapper.vm as any).$store.state.items.fetchingItems.unread = true; + + (wrapper.vm as any).fetchMore() + expect(store.dispatch).not.toBeCalled(); + + (wrapper.vm as any).$store.state.items.fetchingItems.unread = false; + + (wrapper.vm as any).fetchMore() + expect(store.dispatch).toBeCalled() + }) +}) diff --git a/tests/javascript/unit/services/item.service.spec.ts b/tests/javascript/unit/services/item.service.spec.ts new file mode 100644 index 000000000..29de8f1a3 --- /dev/null +++ b/tests/javascript/unit/services/item.service.spec.ts @@ -0,0 +1,66 @@ +import { ITEM_TYPES, ItemService } from '../../../../src/dataservices/item.service' +import axios from '@nextcloud/axios' + +jest.mock('@nextcloud/axios') + +describe('item.service.ts', () => { + 'use strict' + + beforeEach(() => { + (axios.get as any).mockReset(); + (axios.post as any).mockReset() + }) + + describe('fetchStarred', () => { + it('should call GET with offset set to start param', async () => { + (axios as any).get.mockResolvedValue({ data: { feeds: [] } }) + + await ItemService.fetchStarred(0) + + expect(axios.get).toBeCalled() + const queryParams = (axios.get as any).mock.calls[0][1].params + + expect(queryParams.offset).toEqual(0) + expect(queryParams.type).toEqual(ITEM_TYPES.STARRED) + }) + }) + + describe('fetchUnread', () => { + it('should call GET with offset set to start param', async () => { + (axios as any).get.mockResolvedValue({ data: { feeds: [] } }) + + await ItemService.fetchUnread(2) + + expect(axios.get).toBeCalled() + const queryParams = (axios.get as any).mock.calls[0][1].params + + expect(queryParams.offset).toEqual(2) + expect(queryParams.type).toEqual(ITEM_TYPES.UNREAD) + }) + }) + + describe('markRead', () => { + it('should call POST with item id in URL and read param', async () => { + await ItemService.markRead({ id: 123 } as any, true) + + expect(axios.post).toBeCalled() + const args = (axios.post as any).mock.calls[0] + + expect(args[0]).toContain('123') + expect(args[1].isRead).toEqual(true) + }) + }) + + describe('markStarred', () => { + it('should call POST with item feedId and guidHash in URL and read param', async () => { + await ItemService.markStarred({ feedId: 1, guidHash: 'abc' } as any, false) + + expect(axios.post).toBeCalled() + const args = (axios.post as any).mock.calls[0] + + expect(args[0]).toContain('1') + expect(args[0]).toContain('abc') + expect(args[1].isStarred).toEqual(false) + }) + }) +}) diff --git a/tests/javascript/unit/store/feed.spec.ts b/tests/javascript/unit/store/feed.spec.ts index 922c79f3f..3a7521f89 100644 --- a/tests/javascript/unit/store/feed.spec.ts +++ b/tests/javascript/unit/store/feed.spec.ts @@ -3,7 +3,7 @@ import { Feed } from '../../../../src/types/Feed' import { AppState } from '../../../../src/store' import { FEED_ACTION_TYPES, mutations, actions } from '../../../../src/store/feed' -import { FEED_MUTATION_TYPES } from '../../../../src/types/MutationTypes' +import { FEED_ITEM_MUTATION_TYPES, FEED_MUTATION_TYPES } from '../../../../src/types/MutationTypes' jest.mock('@nextcloud/axios') @@ -11,6 +11,17 @@ describe('feed.ts', () => { 'use strict' describe('actions', () => { + describe('FETCH_FEEDS', () => { + it('should call GET and commit returned feeds to state', async () => { + (axios as any).get.mockResolvedValue({ data: { feeds: [] } }) + const commit = jest.fn() + await (actions[FEED_ACTION_TYPES.FETCH_FEEDS] as any)({ commit }) + expect(axios.get).toBeCalled() + expect(commit).toBeCalledWith(FEED_MUTATION_TYPES.SET_FEEDS, []) + expect(commit).toBeCalledWith(FEED_ITEM_MUTATION_TYPES.SET_UNREAD_COUNT, 0) + }) + }) + describe('ADD_FEED', () => { it('should call POST and commit feed to state', async () => { (axios as any).post.mockResolvedValue({ data: { feeds: [] } }) @@ -30,13 +41,6 @@ describe('feed.ts', () => { }) }) - it('FETCH_FEEDS should call GET and commit returned feeds to state', async () => { - (axios as any).get.mockResolvedValue({ data: { feeds: [] } }) - const commit = jest.fn() - await (actions[FEED_ACTION_TYPES.FETCH_FEEDS] as any)({ commit }) - expect(axios.get).toBeCalled() - expect(commit).toBeCalled() - }) }) describe('mutations', () => { diff --git a/tests/javascript/unit/store/item.spec.ts b/tests/javascript/unit/store/item.spec.ts index 614e47c1d..c393a03f4 100644 --- a/tests/javascript/unit/store/item.spec.ts +++ b/tests/javascript/unit/store/item.spec.ts @@ -1,22 +1,37 @@ -import axios from '@nextcloud/axios' import { AppState } from '../../../../src/store' import { FEED_ITEM_ACTION_TYPES, mutations, actions } from '../../../../src/store/item' import { FEED_ITEM_MUTATION_TYPES } from '../../../../src/types/MutationTypes' -import { FeedItem } from '../../../../src/types/FeedItem' +import { ItemService } from '../../../../src/dataservices/item.service' -jest.mock('@nextcloud/axios') - -describe('feed.ts', () => { +describe('item.ts', () => { 'use strict' describe('actions', () => { + describe('FETCH_UNREAD', () => { + it('should call ItemService and commit items to state', async () => { + const fetchMock = jest.fn() + fetchMock.mockResolvedValue({ data: { items: [] } }) + ItemService.debounceFetchUnread = fetchMock as any + const commit = jest.fn() + + await (actions[FEED_ITEM_ACTION_TYPES.FETCH_UNREAD] as any)({ commit }) + + expect(fetchMock).toBeCalled() + expect(commit).toBeCalledWith(FEED_ITEM_MUTATION_TYPES.SET_ITEMS, []) + }) + }) + describe('FETCH_STARRED', () => { - it('should call GET and commit items and starred count to state', async () => { - (axios as any).get.mockResolvedValue({ data: { items: [], starred: 3 } }) + it('should call ItemService and commit items and starred count to state', async () => { + const fetchMock = jest.fn() + fetchMock.mockResolvedValue({ data: { items: [], starred: 3 } }) + ItemService.debounceFetchStarred = fetchMock as any const commit = jest.fn() + await (actions[FEED_ITEM_ACTION_TYPES.FETCH_STARRED] as any)({ commit }) - expect(axios.get).toBeCalled() + + expect(fetchMock).toBeCalled() expect(commit).toBeCalledWith(FEED_ITEM_MUTATION_TYPES.SET_ITEMS, []) expect(commit).toBeCalledWith(FEED_ITEM_MUTATION_TYPES.SET_STARRED_COUNT, 3) }) @@ -25,52 +40,95 @@ describe('feed.ts', () => { it('MARK_READ should call GET and commit returned feeds to state', async () => { const item = { id: 1 } const commit = jest.fn() + const serviceMock = jest.fn() + ItemService.markRead = serviceMock + await (actions[FEED_ITEM_ACTION_TYPES.MARK_READ] as any)({ commit }, { item }) - expect(axios.post).toBeCalled() + + expect(serviceMock).toBeCalledWith(item, true) expect(commit).toBeCalled() }) it('MARK_UNREAD should call GET and commit returned feeds to state', async () => { const item = { id: 1 } const commit = jest.fn() + const serviceMock = jest.fn() + ItemService.markRead = serviceMock + await (actions[FEED_ITEM_ACTION_TYPES.MARK_UNREAD] as any)({ commit }, { item }) - expect(axios.post).toBeCalled() + + expect(serviceMock).toBeCalledWith(item, false) expect(commit).toBeCalledWith(FEED_ITEM_MUTATION_TYPES.UPDATE_ITEM, { item }) }) it('STAR_ITEM should call GET and commit returned feeds to state', async () => { - const item = { id: 1 }; - (axios as any).get.mockResolvedValue({ data: { feeds: [] } }) + const item = { id: 1 } const commit = jest.fn() + const serviceMock = jest.fn() + ItemService.markStarred = serviceMock + await (actions[FEED_ITEM_ACTION_TYPES.STAR_ITEM] as any)({ commit }, { item }) - expect(axios.post).toBeCalled() + + expect(serviceMock).toBeCalledWith(item, true) expect(commit).toBeCalled() }) it('UNSTAR_ITEM should call GET and commit returned feeds to state', async () => { - const item = { id: 1 }; - (axios as any).get.mockResolvedValue({ data: { feeds: [] } }) + const item = { id: 1 } const commit = jest.fn() + const serviceMock = jest.fn() + ItemService.markStarred = serviceMock + await (actions[FEED_ITEM_ACTION_TYPES.UNSTAR_ITEM] as any)({ commit }, { item }) - expect(axios.post).toBeCalled() + + expect(serviceMock).toBeCalledWith(item, false) expect(commit).toBeCalled() }) }) describe('mutations', () => { + describe('SET_SELECTED_ITEM', () => { + it('should update selectedId on state', async () => { + const state = { selectedId: undefined } as any + const item = { id: 123 } as any + mutations[FEED_ITEM_MUTATION_TYPES.SET_SELECTED_ITEM](state, item as any) + expect(state.selectedId).toEqual(123) + }) + }) describe('SET_ITEMS', () => { it('should add feeds to state', () => { - const state = { allItems: [] as any } as AppState + const state = { allItems: [] as any } as any let items = [] as any mutations[FEED_ITEM_MUTATION_TYPES.SET_ITEMS](state, items) expect(state.allItems.length).toEqual(0) - items = [{ title: 'test' }] as FeedItem[] + items = [{ title: 'test', id: 123 }] + + mutations[FEED_ITEM_MUTATION_TYPES.SET_ITEMS](state, items) + expect(state.allItems.length).toEqual(1) + expect(state.allItems[0]).toEqual(items[0]) + + items = [{ title: 'test2', id: 234 }] + mutations[FEED_ITEM_MUTATION_TYPES.SET_ITEMS](state, items) + expect(state.allItems.length).toEqual(2) + }) + + it('should not add duplicates', () => { + const state = { allItems: [] as any } as any + let items = [{ title: 'test', id: 123 }] as any mutations[FEED_ITEM_MUTATION_TYPES.SET_ITEMS](state, items) expect(state.allItems.length).toEqual(1) expect(state.allItems[0]).toEqual(items[0]) + + mutations[FEED_ITEM_MUTATION_TYPES.SET_ITEMS](state, items) + expect(state.allItems.length).toEqual(1) + expect(state.allItems[0]).toEqual(items[0]) + + items = [{ title: 'test2', id: 234 }] + mutations[FEED_ITEM_MUTATION_TYPES.SET_ITEMS](state, items) + expect(state.allItems.length).toEqual(2) }) }) @@ -83,6 +141,15 @@ describe('feed.ts', () => { }) }) + describe('SET_UNREAD_COUNT', () => { + it('should set unreadCount with value passed in', () => { + const state = { unreadCount: 0 } as AppState + + (mutations[FEED_ITEM_MUTATION_TYPES.SET_UNREAD_COUNT] as any)(state, 123) + expect(state.unreadCount).toEqual(123) + }) + }) + describe('UPDATE_ITEM', () => { it('should add a single feed to state', () => { const state = { allItems: [{ id: 1, title: 'abc' }] as any } as AppState @@ -92,5 +159,29 @@ describe('feed.ts', () => { expect(state.allItems[0]).toEqual(item) }) }) + + describe('SET_FETCHING', () => { + it('should set fetchingItems value with key passed in', () => { + const state = { fetchingItems: {} } as AppState + + (mutations[FEED_ITEM_MUTATION_TYPES.SET_FETCHING] as any)(state, { fetching: true, key: 'starred' }) + expect(state.fetchingItems.starred).toEqual(true); + + (mutations[FEED_ITEM_MUTATION_TYPES.SET_FETCHING] as any)(state, { fetching: false, key: 'starred' }) + expect(state.fetchingItems.starred).toEqual(false) + }) + }) + + describe('SET_ALL_LOADED', () => { + it('should set allItemsLoaded value with key passed in', () => { + const state = { allItemsLoaded: {} } as AppState + + (mutations[FEED_ITEM_MUTATION_TYPES.SET_ALL_LOADED] as any)(state, { loaded: true, key: 'starred' }) + expect(state.allItemsLoaded.starred).toEqual(true); + + (mutations[FEED_ITEM_MUTATION_TYPES.SET_ALL_LOADED] as any)(state, { loaded: false, key: 'starred' }) + expect(state.allItemsLoaded.starred).toEqual(false) + }) + }) }) }) -- cgit v1.2.3