diff options
Diffstat (limited to 'spec/frontend/error_tracking/store/list')
3 files changed, 199 insertions, 33 deletions
diff --git a/spec/frontend/error_tracking/store/list/actions_spec.js b/spec/frontend/error_tracking/store/list/actions_spec.js new file mode 100644 index 00000000000..7906738f5b0 --- /dev/null +++ b/spec/frontend/error_tracking/store/list/actions_spec.js @@ -0,0 +1,117 @@ +import axios from '~/lib/utils/axios_utils'; +import MockAdapter from 'axios-mock-adapter'; +import testAction from 'helpers/vuex_action_helper'; +import httpStatusCodes from '~/lib/utils/http_status'; +import createFlash from '~/flash'; +import * as actions from '~/error_tracking/store/list/actions'; +import * as types from '~/error_tracking/store/list/mutation_types'; + +jest.mock('~/flash.js'); + +describe('error tracking actions', () => { + let mock; + + beforeEach(() => { + mock = new MockAdapter(axios); + }); + + afterEach(() => { + mock.restore(); + }); + + describe('startPolling', () => { + it('should start polling for data', done => { + const payload = { errors: [{ id: 1 }, { id: 2 }] }; + + mock.onGet().reply(httpStatusCodes.OK, payload); + testAction( + actions.startPolling, + {}, + {}, + [ + { type: types.SET_LOADING, payload: true }, + { type: types.SET_PAGINATION, payload: payload.pagination }, + { type: types.SET_ERRORS, payload: payload.errors }, + { type: types.SET_LOADING, payload: false }, + ], + [{ type: 'stopPolling' }], + () => { + done(); + }, + ); + }); + + it('should show flash on API error', done => { + mock.onGet().reply(httpStatusCodes.BAD_REQUEST); + + testAction( + actions.startPolling, + {}, + {}, + [{ type: types.SET_LOADING, payload: true }, { type: types.SET_LOADING, payload: false }], + [], + () => { + expect(createFlash).toHaveBeenCalledTimes(1); + done(); + }, + ); + }); + }); + + describe('restartPolling', () => { + it('should restart polling', () => { + testAction( + actions.restartPolling, + {}, + {}, + [{ type: types.SET_ERRORS, payload: [] }, { type: types.SET_LOADING, payload: true }], + [], + ); + }); + }); + + describe('searchByQuery', () => { + it('should search by query', () => { + const query = 'search'; + + testAction( + actions.searchByQuery, + query, + {}, + [ + { type: types.SET_SEARCH_QUERY, payload: query }, + { type: types.ADD_RECENT_SEARCH, payload: query }, + ], + [{ type: 'stopPolling' }, { type: 'startPolling' }], + ); + }); + }); + + describe('sortByField', () => { + it('should search by query', () => { + const field = 'frequency'; + + testAction( + actions.sortByField, + { field }, + {}, + [{ type: types.SET_SORT_FIELD, payload: { field } }], + [{ type: 'stopPolling' }, { type: 'startPolling' }], + ); + }); + }); + + describe('setEnpoint', () => { + it('should set search endpoint', () => { + const endpoint = 'https://sentry.io'; + + testAction( + actions.setEndpoint, + { endpoint }, + {}, + [{ type: types.SET_ENDPOINT, payload: { endpoint } }], + [], + ); + }); + }); +}); diff --git a/spec/frontend/error_tracking/store/list/getters_spec.js b/spec/frontend/error_tracking/store/list/getters_spec.js deleted file mode 100644 index 3cd7fa37d44..00000000000 --- a/spec/frontend/error_tracking/store/list/getters_spec.js +++ /dev/null @@ -1,33 +0,0 @@ -import * as getters from '~/error_tracking/store/list/getters'; - -describe('Error Tracking getters', () => { - let state; - - const mockErrors = [ - { title: 'ActiveModel::MissingAttributeError: missing attribute: encrypted_password' }, - { title: 'Grape::Exceptions::MethodNotAllowed: Grape::Exceptions::MethodNotAllowed' }, - { title: 'NoMethodError: undefined method `sanitize_http_headers=' }, - { title: 'NoMethodError: undefined method `pry' }, - ]; - - beforeEach(() => { - state = { - errors: mockErrors, - }; - }); - - describe('search results', () => { - it('should return errors filtered by words in title matching the query', () => { - const filteredErrors = getters.filterErrorsByTitle(state)('NoMethod'); - - expect(filteredErrors).not.toContainEqual(mockErrors[0]); - expect(filteredErrors.length).toBe(2); - }); - - it('should not return results if there is no matching query', () => { - const filteredErrors = getters.filterErrorsByTitle(state)('GitLab'); - - expect(filteredErrors.length).toBe(0); - }); - }); -}); diff --git a/spec/frontend/error_tracking/store/list/mutation_spec.js b/spec/frontend/error_tracking/store/list/mutation_spec.js index 6e021185b4d..44a75b6aa1f 100644 --- a/spec/frontend/error_tracking/store/list/mutation_spec.js +++ b/spec/frontend/error_tracking/store/list/mutation_spec.js @@ -1,6 +1,11 @@ +import { useLocalStorageSpy } from 'helpers/local_storage_helper'; import mutations from '~/error_tracking/store/list/mutations'; import * as types from '~/error_tracking/store/list/mutation_types'; +const ADD_RECENT_SEARCH = mutations[types.ADD_RECENT_SEARCH]; +const CLEAR_RECENT_SEARCHES = mutations[types.CLEAR_RECENT_SEARCHES]; +const LOAD_RECENT_SEARCHES = mutations[types.LOAD_RECENT_SEARCHES]; + describe('Error tracking mutations', () => { describe('SET_ERRORS', () => { let state; @@ -33,4 +38,81 @@ describe('Error tracking mutations', () => { }); }); }); + + describe('recent searches', () => { + useLocalStorageSpy(); + let state; + + beforeEach(() => { + state = { + indexPath: '/project/errors.json', + recentSearches: [], + }; + }); + + describe('ADD_RECENT_SEARCH', () => { + it('adds search queries to recentSearches and localStorage', () => { + ADD_RECENT_SEARCH(state, 'my issue'); + + expect(state.recentSearches).toEqual(['my issue']); + expect(localStorage.setItem).toHaveBeenCalledWith( + 'recent-searches/project/errors.json', + '["my issue"]', + ); + }); + + it('does not add empty searches', () => { + ADD_RECENT_SEARCH(state, ''); + + expect(state.recentSearches).toEqual([]); + expect(localStorage.setItem).not.toHaveBeenCalled(); + }); + + it('adds new queries to start of the list', () => { + state.recentSearches = ['previous', 'searches']; + + ADD_RECENT_SEARCH(state, 'new search'); + + expect(state.recentSearches).toEqual(['new search', 'previous', 'searches']); + }); + + it('limits recentSearches to 5 items', () => { + state.recentSearches = [1, 2, 3, 4, 5]; + + ADD_RECENT_SEARCH(state, 'new search'); + + expect(state.recentSearches).toEqual(['new search', 1, 2, 3, 4]); + }); + + it('does not add same search query twice', () => { + state.recentSearches = ['already', 'searched']; + + ADD_RECENT_SEARCH(state, 'searched'); + + expect(state.recentSearches).toEqual(['searched', 'already']); + }); + }); + + describe('CLEAR_RECENT_SEARCHES', () => { + it('clears recentSearches and localStorage', () => { + state.recentSearches = ['first', 'second']; + + CLEAR_RECENT_SEARCHES(state); + + expect(state.recentSearches).toEqual([]); + expect(localStorage.removeItem).toHaveBeenCalledWith('recent-searches/project/errors.json'); + }); + }); + + describe('LOAD_RECENT_SEARCHES', () => { + it('loads recent searches from localStorage', () => { + jest.spyOn(window.localStorage, 'getItem').mockReturnValue('["first", "second"]'); + + LOAD_RECENT_SEARCHES(state); + + expect(state.recentSearches).toEqual(['first', 'second']); + expect(localStorage.getItem).toHaveBeenCalledWith('recent-searches/project/errors.json'); + }); + }); + }); }); |