diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-14 18:09:44 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-14 18:09:44 +0300 |
commit | 874ead9c3a50de4c4ca4551eaf5b7eb976d26b50 (patch) | |
tree | 637ee9f2da5e251bc08ebf3e972209d51966bf7c /spec/frontend | |
parent | 2e4c4055181eec9186458dd5dd3219c937032ec7 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
7 files changed, 297 insertions, 53 deletions
diff --git a/spec/frontend/monitoring/components/charts/time_series_spec.js b/spec/frontend/monitoring/components/charts/time_series_spec.js index 3aad4c87237..870e47edde0 100644 --- a/spec/frontend/monitoring/components/charts/time_series_spec.js +++ b/spec/frontend/monitoring/components/charts/time_series_spec.js @@ -50,6 +50,7 @@ describe('Time series component', () => { propsData: { graphData: { ...graphData, type }, deploymentData: store.state.monitoringDashboard.deploymentData, + annotations: store.state.monitoringDashboard.annotations, projectPath: `${mockHost}${mockProjectDir}`, }, store, diff --git a/spec/frontend/monitoring/store/actions_spec.js b/spec/frontend/monitoring/store/actions_spec.js index d6faec29b65..c34a5afceb0 100644 --- a/spec/frontend/monitoring/store/actions_spec.js +++ b/spec/frontend/monitoring/store/actions_spec.js @@ -16,6 +16,7 @@ import { fetchDeploymentsData, fetchEnvironmentsData, fetchDashboardData, + fetchAnnotations, fetchPrometheusMetric, setInitialState, filterEnvironments, @@ -24,10 +25,12 @@ import { } from '~/monitoring/stores/actions'; import { gqClient, parseEnvironmentsResponse } from '~/monitoring/stores/utils'; import getEnvironments from '~/monitoring/queries/getEnvironments.query.graphql'; +import getAnnotations from '~/monitoring/queries/getAnnotations.query.graphql'; import storeState from '~/monitoring/stores/state'; import { deploymentData, environmentData, + annotationsData, metricsDashboardResponse, metricsDashboardViewModel, dashboardGitResponse, @@ -120,17 +123,15 @@ describe('Monitoring store actions', () => { }); it('setting SET_ENVIRONMENTS_FILTER should dispatch fetchEnvironmentsData', () => { - jest.spyOn(gqClient, 'mutate').mockReturnValue( - Promise.resolve({ - data: { - project: { - data: { - environments: [], - }, + jest.spyOn(gqClient, 'mutate').mockReturnValue({ + data: { + project: { + data: { + environments: [], }, }, - }), - ); + }, + }); return testAction( filterEnvironments, @@ -180,17 +181,15 @@ describe('Monitoring store actions', () => { }); it('dispatches receiveEnvironmentsDataSuccess on success', () => { - jest.spyOn(gqClient, 'mutate').mockReturnValue( - Promise.resolve({ - data: { - project: { - data: { - environments: environmentData, - }, + jest.spyOn(gqClient, 'mutate').mockResolvedValue({ + data: { + project: { + data: { + environments: environmentData, }, }, - }), - ); + }, + }); return testAction( fetchEnvironmentsData, @@ -208,7 +207,7 @@ describe('Monitoring store actions', () => { }); it('dispatches receiveEnvironmentsDataFailure on error', () => { - jest.spyOn(gqClient, 'mutate').mockReturnValue(Promise.reject()); + jest.spyOn(gqClient, 'mutate').mockRejectedValue({}); return testAction( fetchEnvironmentsData, @@ -220,6 +219,80 @@ describe('Monitoring store actions', () => { }); }); + describe('fetchAnnotations', () => { + const { state } = store; + state.projectPath = 'gitlab-org/gitlab-test'; + state.currentEnvironmentName = 'production'; + state.currentDashboard = '.gitlab/dashboards/custom_dashboard.yml'; + + afterEach(() => { + resetStore(store); + }); + + it('fetches annotations data and dispatches receiveAnnotationsSuccess', () => { + const mockMutate = jest.spyOn(gqClient, 'mutate'); + const mutationVariables = { + mutation: getAnnotations, + variables: { + projectPath: state.projectPath, + environmentName: state.currentEnvironmentName, + dashboardId: state.currentDashboard, + }, + }; + + mockMutate.mockResolvedValue({ + data: { + project: { + environment: { + metricDashboard: { + annotations: annotationsData, + }, + }, + }, + }, + }); + + return testAction( + fetchAnnotations, + null, + state, + [], + [ + { type: 'requestAnnotations' }, + { type: 'receiveAnnotationsSuccess', payload: annotationsData }, + ], + () => { + expect(mockMutate).toHaveBeenCalledWith(mutationVariables); + }, + ); + }); + + it('dispatches receiveAnnotationsFailure if the annotations API call fails', () => { + const mockMutate = jest.spyOn(gqClient, 'mutate'); + const mutationVariables = { + mutation: getAnnotations, + variables: { + projectPath: state.projectPath, + environmentName: state.currentEnvironmentName, + dashboardId: state.currentDashboard, + }, + }; + + mockMutate.mockRejectedValue({}); + + return testAction( + fetchAnnotations, + null, + state, + [], + [{ type: 'requestAnnotations' }, { type: 'receiveAnnotationsFailure' }], + () => { + expect(mockMutate).toHaveBeenCalledWith(mutationVariables); + }, + ); + }); + }); + describe('Set initial state', () => { let mockedState; beforeEach(() => { diff --git a/spec/frontend/smart_interval_spec.js b/spec/frontend/smart_interval_spec.js new file mode 100644 index 00000000000..b32ac99e4e4 --- /dev/null +++ b/spec/frontend/smart_interval_spec.js @@ -0,0 +1,197 @@ +import $ from 'jquery'; +import { assignIn } from 'lodash'; +import waitForPromises from 'helpers/wait_for_promises'; +import SmartInterval from '~/smart_interval'; + +jest.useFakeTimers(); + +let interval; + +describe('SmartInterval', () => { + const DEFAULT_MAX_INTERVAL = 100; + const DEFAULT_STARTING_INTERVAL = 5; + const DEFAULT_INCREMENT_FACTOR = 2; + + function createDefaultSmartInterval(config) { + const defaultParams = { + callback: () => Promise.resolve(), + startingInterval: DEFAULT_STARTING_INTERVAL, + maxInterval: DEFAULT_MAX_INTERVAL, + incrementByFactorOf: DEFAULT_INCREMENT_FACTOR, + lazyStart: false, + immediateExecution: false, + hiddenInterval: null, + }; + + if (config) { + assignIn(defaultParams, config); + } + + return new SmartInterval(defaultParams); + } + + afterEach(() => { + interval.destroy(); + }); + + describe('Increment Interval', () => { + it('should increment the interval delay', () => { + interval = createDefaultSmartInterval(); + + jest.runOnlyPendingTimers(); + + return waitForPromises().then(() => { + const intervalConfig = interval.cfg; + const iterationCount = 4; + const maxIntervalAfterIterations = + intervalConfig.startingInterval * intervalConfig.incrementByFactorOf ** iterationCount; + const currentInterval = interval.getCurrentInterval(); + + // Provide some flexibility for performance of testing environment + expect(currentInterval).toBeGreaterThan(intervalConfig.startingInterval); + expect(currentInterval).toBeLessThanOrEqual(maxIntervalAfterIterations); + }); + }); + + it('should not increment past maxInterval', () => { + interval = createDefaultSmartInterval({ maxInterval: DEFAULT_STARTING_INTERVAL }); + + jest.runOnlyPendingTimers(); + + return waitForPromises().then(() => { + const currentInterval = interval.getCurrentInterval(); + + expect(currentInterval).toBe(interval.cfg.maxInterval); + }); + }); + + it('does not increment while waiting for callback', () => { + interval = createDefaultSmartInterval({ + callback: () => new Promise($.noop), + }); + + jest.runOnlyPendingTimers(); + + return waitForPromises().then(() => { + const oneInterval = interval.cfg.startingInterval * DEFAULT_INCREMENT_FACTOR; + + expect(interval.getCurrentInterval()).toEqual(oneInterval); + }); + }); + }); + + describe('Public methods', () => { + beforeEach(() => { + interval = createDefaultSmartInterval(); + }); + + it('should cancel an interval', () => { + jest.runOnlyPendingTimers(); + + interval.cancel(); + + return waitForPromises().then(() => { + const { intervalId } = interval.state; + const currentInterval = interval.getCurrentInterval(); + const intervalLowerLimit = interval.cfg.startingInterval; + + expect(intervalId).toBeUndefined(); + expect(currentInterval).toBe(intervalLowerLimit); + }); + }); + + it('should resume an interval', () => { + jest.runOnlyPendingTimers(); + + interval.cancel(); + + interval.resume(); + + return waitForPromises().then(() => { + const { intervalId } = interval.state; + + expect(intervalId).toBeTruthy(); + }); + }); + }); + + describe('DOM Events', () => { + beforeEach(() => { + // This ensures DOM and DOM events are initialized for these specs. + setFixtures('<div></div>'); + + interval = createDefaultSmartInterval(); + }); + + it('should pause when page is not visible', () => { + jest.runOnlyPendingTimers(); + + return waitForPromises().then(() => { + expect(interval.state.intervalId).toBeTruthy(); + + // simulates triggering of visibilitychange event + interval.onVisibilityChange({ target: { visibilityState: 'hidden' } }); + + expect(interval.state.intervalId).toBeUndefined(); + }); + }); + + it('should change to the hidden interval when page is not visible', () => { + interval.destroy(); + + const HIDDEN_INTERVAL = 1500; + interval = createDefaultSmartInterval({ hiddenInterval: HIDDEN_INTERVAL }); + + jest.runOnlyPendingTimers(); + + return waitForPromises().then(() => { + expect(interval.state.intervalId).toBeTruthy(); + expect( + interval.getCurrentInterval() >= DEFAULT_STARTING_INTERVAL && + interval.getCurrentInterval() <= DEFAULT_MAX_INTERVAL, + ).toBeTruthy(); + + // simulates triggering of visibilitychange event + interval.onVisibilityChange({ target: { visibilityState: 'hidden' } }); + + expect(interval.state.intervalId).toBeTruthy(); + expect(interval.getCurrentInterval()).toBe(HIDDEN_INTERVAL); + }); + }); + + it('should resume when page is becomes visible at the previous interval', () => { + jest.runOnlyPendingTimers(); + + return waitForPromises().then(() => { + expect(interval.state.intervalId).toBeTruthy(); + + // simulates triggering of visibilitychange event + interval.onVisibilityChange({ target: { visibilityState: 'hidden' } }); + + expect(interval.state.intervalId).toBeUndefined(); + + // simulates triggering of visibilitychange event + interval.onVisibilityChange({ target: { visibilityState: 'visible' } }); + + expect(interval.state.intervalId).toBeTruthy(); + }); + }); + + it('should cancel on page unload', () => { + jest.runOnlyPendingTimers(); + + return waitForPromises().then(() => { + $(document).triggerHandler('beforeunload'); + + expect(interval.state.intervalId).toBeUndefined(); + expect(interval.getCurrentInterval()).toBe(interval.cfg.startingInterval); + }); + }); + + it('should execute callback before first interval', () => { + interval = createDefaultSmartInterval({ immediateExecution: true }); + + expect(interval.cfg.immediateExecution).toBeFalsy(); + }); + }); +}); diff --git a/spec/frontend/static_site_editor/components/static_site_editor_spec.js b/spec/frontend/static_site_editor/components/static_site_editor_spec.js index a40f8edbeb2..2c4fa0e061a 100644 --- a/spec/frontend/static_site_editor/components/static_site_editor_spec.js +++ b/spec/frontend/static_site_editor/components/static_site_editor_spec.js @@ -30,7 +30,6 @@ describe('StaticSiteEditor', () => { store = new Vuex.Store({ state: createState(initialState), getters: { - isContentLoaded: () => false, contentChanged: () => false, ...getters, }, @@ -43,9 +42,11 @@ describe('StaticSiteEditor', () => { }; const buildContentLoadedStore = ({ initialState, getters } = {}) => { buildStore({ - initialState, + initialState: { + isContentLoaded: true, + ...initialState, + }, getters: { - isContentLoaded: () => true, ...getters, }, }); @@ -85,7 +86,7 @@ describe('StaticSiteEditor', () => { const content = 'edit area content'; beforeEach(() => { - buildStore({ initialState: { content }, getters: { isContentLoaded: () => true } }); + buildContentLoadedStore({ initialState: { content } }); buildWrapper(); }); diff --git a/spec/frontend/static_site_editor/store/getters_spec.js b/spec/frontend/static_site_editor/store/getters_spec.js index 1b482db9366..5793e344784 100644 --- a/spec/frontend/static_site_editor/store/getters_spec.js +++ b/spec/frontend/static_site_editor/store/getters_spec.js @@ -1,18 +1,8 @@ import createState from '~/static_site_editor/store/state'; -import { isContentLoaded, contentChanged } from '~/static_site_editor/store/getters'; +import { contentChanged } from '~/static_site_editor/store/getters'; import { sourceContent as content } from '../mock_data'; describe('Static Site Editor Store getters', () => { - describe('isContentLoaded', () => { - it('returns true when originalContent is not empty', () => { - expect(isContentLoaded(createState({ originalContent: content }))).toBe(true); - }); - - it('returns false when originalContent is empty', () => { - expect(isContentLoaded(createState({ originalContent: '' }))).toBe(false); - }); - }); - describe('contentChanged', () => { it('returns true when content and originalContent are different', () => { const state = createState({ content, originalContent: 'something else' }); diff --git a/spec/frontend/static_site_editor/store/mutations_spec.js b/spec/frontend/static_site_editor/store/mutations_spec.js index 1fd687eed4a..0b213c11a04 100644 --- a/spec/frontend/static_site_editor/store/mutations_spec.js +++ b/spec/frontend/static_site_editor/store/mutations_spec.js @@ -19,6 +19,7 @@ describe('Static Site Editor Store mutations', () => { mutation | stateProperty | payload | expectedValue ${types.LOAD_CONTENT} | ${'isLoadingContent'} | ${undefined} | ${true} ${types.RECEIVE_CONTENT_SUCCESS} | ${'isLoadingContent'} | ${contentLoadedPayload} | ${false} + ${types.RECEIVE_CONTENT_SUCCESS} | ${'isContentLoaded'} | ${contentLoadedPayload} | ${true} ${types.RECEIVE_CONTENT_SUCCESS} | ${'title'} | ${contentLoadedPayload} | ${title} ${types.RECEIVE_CONTENT_SUCCESS} | ${'content'} | ${contentLoadedPayload} | ${content} ${types.RECEIVE_CONTENT_SUCCESS} | ${'originalContent'} | ${contentLoadedPayload} | ${content} diff --git a/spec/frontend/vue_mr_widget/mr_widget_options_spec.js b/spec/frontend/vue_mr_widget/mr_widget_options_spec.js index ef95cb1b8f2..e022f68fdec 100644 --- a/spec/frontend/vue_mr_widget/mr_widget_options_spec.js +++ b/spec/frontend/vue_mr_widget/mr_widget_options_spec.js @@ -273,25 +273,6 @@ describe('mrWidgetOptions', () => { }; }); - it('should not tell service to check status if document is not visible', () => { - Object.defineProperty(document, 'visibilityState', { - value: 'hidden', - configurable: true, - }); - vm.checkStatus(cb); - - return vm.$nextTick().then(() => { - expect(vm.service.checkStatus).not.toHaveBeenCalled(); - expect(vm.mr.setData).not.toHaveBeenCalled(); - expect(vm.handleNotification).not.toHaveBeenCalled(); - expect(isCbExecuted).toBeFalsy(); - Object.defineProperty(document, 'visibilityState', { - value: 'visible', - configurable: true, - }); - }); - }); - it('should tell service to check status if document is visible', () => { vm.checkStatus(cb); |