diff options
author | Lin Jen-Shin <godfat@godfat.org> | 2019-09-06 14:03:33 +0000 |
---|---|---|
committer | Lin Jen-Shin <godfat@godfat.org> | 2019-09-06 14:03:33 +0000 |
commit | 35023d435ddd4c4709f06ea24ebd92480a1a64cb (patch) | |
tree | bef43eb74ba58505a397c33a45b9614f3365f1c5 | |
parent | 222d9e62f2f88b01542bea0890fb8fba816f83a5 (diff) | |
parent | 3d7b3300e75960376f29123d7e2c81e542e8d270 (diff) | |
download | gitlab-ce-35023d435ddd4c4709f06ea24ebd92480a1a64cb.tar.gz |
Merge branch 'revert-93f16f3d' into 'master'
Revert "Merge branch 'winh-fix-flaky-dashboard_spec' into 'master'"
Closes gitlab-ee#14795
See merge request gitlab-org/gitlab-ce!32753
-rw-r--r-- | spec/frontend/environment.js | 1 | ||||
-rw-r--r-- | spec/frontend/test_setup.js | 3 | ||||
-rw-r--r-- | spec/javascripts/monitoring/components/dashboard_spec.js (renamed from spec/frontend/monitoring/components/dashboard_spec.js) | 380 |
3 files changed, 194 insertions, 190 deletions
diff --git a/spec/frontend/environment.js b/spec/frontend/environment.js index a8e42721bf0..290c0e797cb 100644 --- a/spec/frontend/environment.js +++ b/spec/frontend/environment.js @@ -40,7 +40,6 @@ class CustomEnvironment extends JSDOMEnvironment { this.global.fixturesBasePath = `${ROOT_PATH}/tmp/tests/frontend/fixtures${IS_EE ? '-ee' : ''}`; this.global.staticFixturesBasePath = `${ROOT_PATH}/spec/frontend/fixtures`; - this.global.IS_EE = IS_EE; // Not yet supported by JSDOM: https://github.com/jsdom/jsdom/issues/317 this.global.document.createRange = () => ({ diff --git a/spec/frontend/test_setup.js b/spec/frontend/test_setup.js index e7944441fe1..d52aeb1fe6b 100644 --- a/spec/frontend/test_setup.js +++ b/spec/frontend/test_setup.js @@ -73,9 +73,6 @@ expect.extend(customMatchers); // Tech debt issue TBD testUtilsConfig.logModifiedComponents = false; -// Stub for URL.createObjectURL -window.URL.createObjectURL = function createObjectURL() {}; - // Basic stub for MutationObserver global.MutationObserver = () => ({ disconnect: () => {}, diff --git a/spec/frontend/monitoring/components/dashboard_spec.js b/spec/javascripts/monitoring/components/dashboard_spec.js index 2a8e0240bf9..15e41e2fe93 100644 --- a/spec/frontend/monitoring/components/dashboard_spec.js +++ b/spec/javascripts/monitoring/components/dashboard_spec.js @@ -1,64 +1,19 @@ import Vue from 'vue'; import { shallowMount, createLocalVue } from '@vue/test-utils'; -import { GlToast, GlDropdownItem } from '@gitlab/ui'; +import { GlToast } from '@gitlab/ui'; import MockAdapter from 'axios-mock-adapter'; import Dashboard from '~/monitoring/components/dashboard.vue'; -import GraphGroup from '~/monitoring/components/graph_group.vue'; -import EmptyState from '~/monitoring/components/empty_state.vue'; -import { timeWindows } from '~/monitoring/constants'; +import { timeWindows, timeWindowsKeyNames } from '~/monitoring/constants'; import * as types from '~/monitoring/stores/mutation_types'; import { createStore } from '~/monitoring/stores'; import axios from '~/lib/utils/axios_utils'; - -// TODO: replace with dynamic fixture -// https://gitlab.com/gitlab-org/gitlab-ce/issues/62785 import MonitoringMock, { metricsGroupsAPIResponse, mockApiEndpoint, environmentData, singleGroupResponse, dashboardGitResponse, -} from '../../../../spec/javascripts/monitoring/mock_data'; - -/* eslint-disable no-unused-vars */ -/* eslint-disable no-undef */ -// see https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/32571#note_211860465 -function setupComponentStore(component) { - component.$store.commit( - `monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`, - metricsGroupsAPIResponse, - ); - component.$store.commit( - `monitoringDashboard/${types.SET_QUERY_RESULT}`, - mockedQueryResultPayload, - ); - component.$store.commit( - `monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`, - environmentData, - ); -} - -// Mock imported files while retaining the original behaviour -// See https://github.com/facebook/jest/issues/936#issuecomment-265074320 -function mockMonitoringUtils() { - const original = require.requireActual('~/monitoring/utils'); - return { - ...original, // Pass down all the exported objects - getTimeDiff: jest.spyOn(original, 'getTimeDiff'), - }; -} -jest.mock('~/monitoring/utils', () => mockMonitoringUtils()); -const monitoringUtils = require.requireMock('~/monitoring/utils'); - -function mockUrlUtility() { - const original = require.requireActual('~/lib/utils/url_utility'); - return { - ...original, // Pass down all the exported objects - getParameterValues: jest.spyOn(original, 'getParameterValues'), - }; -} -jest.mock('~/lib/utils/url_utility', () => mockUrlUtility()); -const urlUtility = require.requireMock('~/lib/utils/url_utility'); +} from '../mock_data'; const localVue = createLocalVue(); const propsData = { @@ -128,7 +83,7 @@ describe('Dashboard', () => { }); it('shows the environment selector', () => { - expect(component.$el.querySelector('#monitor-environments-dropdown')).toBeTruthy(); + expect(component.$el.querySelector('.js-environments-dropdown')).toBeTruthy(); }); }); @@ -140,7 +95,7 @@ describe('Dashboard', () => { store, }); - expect(component.$el.querySelector('#monitor-environments-dropdown')).toBeTruthy(); + expect(component.$el.querySelector('.js-environments-dropdown')).toBeTruthy(); }); }); @@ -162,27 +117,47 @@ describe('Dashboard', () => { }); }); + it('hides the legend when showLegend is false', done => { + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), + propsData: { + ...propsData, + hasMetrics: true, + showLegend: false, + }, + store, + }); + + setTimeout(() => { + expect(component.showEmptyState).toEqual(false); + expect(component.$el.querySelector('.legend-group')).toEqual(null); + expect(component.$el.querySelector('.prometheus-graph-group')).toBeTruthy(); + done(); + }); + }); + it('hides the group panels when showPanels is false', done => { - const wrapper = shallowMount(DashboardComponent, { + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), propsData: { ...propsData, hasMetrics: true, showPanels: false, }, store, - sync: false, - localVue, }); - setImmediate(() => { - expect(wrapper.find(EmptyState).exists()).toBe(false); - expect(wrapper.find(GraphGroup).exists()).toBe(true); - expect(wrapper.find(GraphGroup).props().showPanels).toBe(false); + + setTimeout(() => { + expect(component.showEmptyState).toEqual(false); + expect(component.$el.querySelector('.prometheus-panel')).toEqual(null); + expect(component.$el.querySelector('.prometheus-graph-group')).toBeTruthy(); done(); }); }); - it('renders the environments dropdown with a number of environments', () => { - const wrapper = shallowMount(DashboardComponent, { + it('renders the environments dropdown with a number of environments', done => { + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), propsData: { ...propsData, hasMetrics: true, @@ -191,30 +166,38 @@ describe('Dashboard', () => { store, }); - store.commit( + component.$store.commit( `monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`, environmentData, ); - store.commit( + component.$store.commit( `monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`, singleGroupResponse, ); - Vue.nextTick(() => { - const dropdownMenuEnvironments = wrapper - .find('.js-environments-dropdown') - .findAll(GlDropdownItem); + Vue.nextTick() + .then(() => { + const dropdownMenuEnvironments = component.$el.querySelectorAll( + '.js-environments-dropdown .dropdown-item', + ); - expect(environmentData.length).toBeGreaterThan(0); - expect(dropdownMenuEnvironments.length).toEqual(environmentData.length); - dropdownMenuEnvironments.wrappers.forEach((value, index) => { - expect(value.attributes('href')).toEqual(environmentData[index].metrics_path); - }); - }); + expect(component.environments.length).toEqual(environmentData.length); + expect(dropdownMenuEnvironments.length).toEqual(component.environments.length); + + Array.from(dropdownMenuEnvironments).forEach((value, index) => { + if (environmentData[index].metrics_path) { + expect(value).toHaveAttr('href', environmentData[index].metrics_path); + } + }); + + done(); + }) + .catch(done.fail); }); - it('hides the environments dropdown list when there is no environments', () => { - const wrapper = shallowMount(DashboardComponent, { + it('hides the environments dropdown list when there is no environments', done => { + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), propsData: { ...propsData, hasMetrics: true, @@ -223,48 +206,54 @@ describe('Dashboard', () => { store, }); - const findEnvironmentsDropdownItems = () => wrapper.find('#monitor-environments-wrapper'); - - store.commit(`monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`, []); - store.commit( + component.$store.commit(`monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`, []); + component.$store.commit( `monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`, singleGroupResponse, ); - return Vue.nextTick(() => { - expect(findEnvironmentsDropdownItems(wrapper).exists()).toEqual(false); - }); + Vue.nextTick() + .then(() => { + const dropdownMenuEnvironments = component.$el.querySelectorAll( + '.js-environments-dropdown .dropdown-item', + ); + + expect(dropdownMenuEnvironments.length).toEqual(0); + done(); + }) + .catch(done.fail); }); - it('renders the environments dropdown with a single active element', () => { - const wrapper = shallowMount(DashboardComponent, { + it('renders the environments dropdown with a single active element', done => { + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), propsData: { ...propsData, hasMetrics: true, showPanels: false, }, store, - sync: false, - localVue, }); - store.commit( + component.$store.commit( `monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`, environmentData, ); - store.commit( + component.$store.commit( `monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`, singleGroupResponse, ); - Vue.nextTick(() => { - const activeDropdownMenuEnvironments = wrapper - .find('#monitor-environments-dropdown') - .findAll(GlDropdownItem) - .filter(item => item.attributes('active') === 'true'); + Vue.nextTick() + .then(() => { + const dropdownItems = component.$el.querySelectorAll( + '.js-environments-dropdown .dropdown-item.active', + ); - expect(activeDropdownMenuEnvironments.length).toEqual(1); - }); + expect(dropdownItems.length).toEqual(1); + done(); + }) + .catch(done.fail); }); it('hides the dropdown', done => { @@ -288,40 +277,33 @@ describe('Dashboard', () => { }); it('renders the time window dropdown with a set of options', done => { - const wrapper = shallowMount(DashboardComponent, { + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), propsData: { ...propsData, hasMetrics: true, showPanels: false, - sync: false, }, store, }); - const numberOfTimeWindows = Object.keys(timeWindows).length; - setImmediate(() => { - const timeWindowDropdown = wrapper.find('.js-time-window-dropdown'); - const timeWindowDropdownEls = wrapper - .find('.js-time-window-dropdown') - .findAll(GlDropdownItem); + setTimeout(() => { + const timeWindowDropdown = component.$el.querySelector('.js-time-window-dropdown'); + const timeWindowDropdownEls = component.$el.querySelectorAll( + '.js-time-window-dropdown .dropdown-item', + ); - expect(timeWindowDropdown.exists()).toBe(true); + expect(timeWindowDropdown).not.toBeNull(); expect(timeWindowDropdownEls.length).toEqual(numberOfTimeWindows); done(); }); }); - it('fetches the metrics data with proper time window', () => { - jest.spyOn(store, 'dispatch').mockImplementationOnce(() => {}); - - store.commit( - `monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`, - environmentData, - ); - - shallowMount(DashboardComponent, { + it('fetches the metrics data with proper time window', done => { + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), propsData: { ...propsData, hasMetrics: true, @@ -330,49 +312,75 @@ describe('Dashboard', () => { store, }); - const defaultRange = monitoringUtils.getTimeDiff(); - return Vue.nextTick().then(() => { - expect(store.dispatch).toHaveBeenCalledWith('monitoringDashboard/fetchData', defaultRange); - }); + spyOn(component.$store, 'dispatch').and.stub(); + const getTimeDiffSpy = spyOnDependency(Dashboard, 'getTimeDiff').and.callThrough(); + + component.$store.commit( + `monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`, + environmentData, + ); + + component.$mount(); + + Vue.nextTick() + .then(() => { + expect(component.$store.dispatch).toHaveBeenCalled(); + expect(getTimeDiffSpy).toHaveBeenCalled(); + + done(); + }) + .catch(done.fail); }); it('shows a specific time window selected from the url params', done => { const start = 1564439536; const end = 1564441336; - monitoringUtils.getTimeDiff.mockReturnValueOnce({ + spyOnDependency(Dashboard, 'getTimeDiff').and.returnValue({ start, end, }); - urlUtility.getParameterValues.mockImplementationOnce(param => { + spyOnDependency(Dashboard, 'getParameterValues').and.callFake(param => { if (param === 'start') return [start]; if (param === 'end') return [end]; return []; }); - const wrapper = shallowMount(DashboardComponent, { - propsData: { - ...propsData, - hasMetrics: true, - showPanels: false, - }, + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), + propsData: { ...propsData, hasMetrics: true }, store, }); - setImmediate(() => { - const activeTimeWindowItems = wrapper - .find('.js-time-window-dropdown') - .findAll(GlDropdownItem) - .filter(item => item.attributes('active') === 'true'); + setTimeout(() => { + const selectedTimeWindow = component.$el.querySelector('.js-time-window-dropdown .active'); + + expect(selectedTimeWindow.textContent.trim()).toEqual('30 minutes'); + done(); + }); + }); - expect(activeTimeWindowItems.length).toEqual(1); - expect(activeTimeWindowItems.wrappers[0].text().trim()).toEqual('30 minutes'); + it('defaults to the eight hours time window for non valid url parameters', done => { + spyOnDependency(Dashboard, 'getParameterValues').and.returnValue([ + '<script>alert("XSS")</script>', + ]); + + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), + propsData: { ...propsData, hasMetrics: true }, + store, + }); + + Vue.nextTick(() => { + expect(component.selectedTimeWindowKey).toEqual(timeWindowsKeyNames.eightHours); done(); }); }); }); - describe('link to chart', () => { + // https://gitlab.com/gitlab-org/gitlab-ce/issues/66922 + // eslint-disable-next-line jasmine/no-disabled-tests + xdescribe('link to chart', () => { let wrapper; const currentDashboard = 'TEST_DASHBOARD'; localVue.use(GlToast); @@ -384,13 +392,13 @@ describe('Dashboard', () => { wrapper = shallowMount(DashboardComponent, { localVue, + sync: false, + attachToDocument: true, propsData: { ...propsData, hasMetrics: true, currentDashboard }, store, }); - setImmediate(() => { - done(); - }); + setTimeout(done); }); afterEach(() => { @@ -429,7 +437,7 @@ describe('Dashboard', () => { }); it('creates a toast when clicked', () => { - jest.spyOn(wrapper.vm.$toast, 'show').mockImplementation(() => {}); + spyOn(wrapper.vm.$toast, 'show').and.stub(); link().vm.$emit('click'); @@ -440,6 +448,11 @@ describe('Dashboard', () => { describe('when the window resizes', () => { beforeEach(() => { mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse); + jasmine.clock().install(); + }); + + afterEach(() => { + jasmine.clock().uninstall(); }); it('sets elWidth to page width when the sidebar is resized', done => { @@ -460,7 +473,7 @@ describe('Dashboard', () => { Vue.nextTick() .then(() => { - jest.advanceTimersByTime(1000); + jasmine.clock().tick(1000); return Vue.nextTick(); }) .then(() => { @@ -472,12 +485,11 @@ describe('Dashboard', () => { }); describe('external dashboard link', () => { - let wrapper; - - beforeEach(done => { + beforeEach(() => { mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse); - wrapper = shallowMount(DashboardComponent, { + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), propsData: { ...propsData, hasMetrics: true, @@ -486,53 +498,61 @@ describe('Dashboard', () => { externalDashboardUrl: '/mockUrl', }, store, - sync: false, - localVue, }); - - setImmediate(done); }); - it('shows the link', () => { - expect(wrapper.find('.js-external-dashboard-link').text()).toContain('View full dashboard'); + it('shows the link', done => { + setTimeout(() => { + expect(component.$el.querySelector('.js-external-dashboard-link').innerText).toContain( + 'View full dashboard', + ); + done(); + }); }); }); describe('Dashboard dropdown', () => { - let wrapper; - - beforeEach(done => { + beforeEach(() => { mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse); - wrapper = shallowMount(DashboardComponent, { - propsData: { ...propsData, hasMetrics: true, showPanels: false }, + component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), + propsData: { + ...propsData, + hasMetrics: true, + showPanels: false, + }, store, - sync: false, - localVue, }); - setImmediate(() => { - store.dispatch('monitoringDashboard/setFeatureFlags', { - prometheusEndpoint: false, - multipleDashboardsEnabled: true, - }); + component.$store.dispatch('monitoringDashboard/setFeatureFlags', { + prometheusEndpoint: false, + multipleDashboardsEnabled: true, + }); - store.commit( - `monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`, - environmentData, - ); - store.commit( - `monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`, - singleGroupResponse, - ); + component.$store.commit( + `monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`, + environmentData, + ); - store.commit(`monitoringDashboard/${types.SET_ALL_DASHBOARDS}`, dashboardGitResponse); - done(); - }); + component.$store.commit( + `monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`, + singleGroupResponse, + ); + + component.$store.commit( + `monitoringDashboard/${types.SET_ALL_DASHBOARDS}`, + dashboardGitResponse, + ); }); - it('shows the dashboard dropdown', () => { - expect(wrapper.find('.js-dashboards-dropdown').exists()).toEqual(true); + it('shows the dashboard dropdown', done => { + setTimeout(() => { + const dashboardDropdown = component.$el.querySelector('.js-dashboards-dropdown'); + + expect(dashboardDropdown).not.toEqual(null); + done(); + }); }); }); @@ -557,25 +577,13 @@ describe('Dashboard', () => { const data = mockGraphData.queries[0].result[0].values; const firstRow = `${data[0][0]},${data[0][1]}`; - expect(component.csvText(mockGraphData)).toContain(`${header}\r\n${firstRow}`); + expect(component.csvText(mockGraphData)).toMatch(`^${header}\r\n${firstRow}`); }); }); describe('downloadCsv', () => { - let spy; - - beforeEach(() => { - spy = jest.spyOn(window.URL, 'createObjectURL'); - }); - - afterEach(() => { - spy.mockRestore(); - }); - - it('creates a string containing a URL that represents the object', () => { - component.downloadCsv(mockGraphData); - - expect(spy).toHaveBeenCalled(); + it('produces a link with a Blob', () => { + expect(component.downloadCsv(mockGraphData)).toContain(`blob:`); }); }); }); |