Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-02-24 21:09:05 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-02-24 21:09:05 +0300
commitc2367afbf57ebc65d5b78a743b5d6a91f0aece9f (patch)
tree165c2c54bf72ab3a3a9417d97f63ece5c9eba9f5 /spec
parent51a9512965d86e3094968fa514e4ae8a96d38cf3 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/projects/hooks_controller_spec.rb9
-rw-r--r--spec/factories/ci/pipelines.rb1
-rw-r--r--spec/features/projects/navbar_spec.rb1
-rw-r--r--spec/features/projects/pipelines/pipeline_spec.rb6
-rw-r--r--spec/features/projects/services/user_views_services_spec.rb2
-rw-r--r--spec/features/projects/settings/operations_settings_spec.rb2
-rw-r--r--spec/features/projects/settings/webhooks_settings_spec.rb (renamed from spec/features/projects/settings/integration_settings_spec.rb)21
-rw-r--r--spec/frontend/grafana_integration/components/__snapshots__/grafana_integration_spec.js.snap6
-rw-r--r--spec/frontend/monitoring/components/charts/time_series_spec.js813
-rw-r--r--spec/frontend/monitoring/components/dashboard_spec.js2
-rw-r--r--spec/frontend/monitoring/mock_data.js42
-rw-r--r--spec/frontend/monitoring/store/mutations_spec.js3
-rw-r--r--spec/frontend/releases/components/app_edit_spec.js2
-rw-r--r--spec/frontend/releases/components/evidence_block_spec.js16
-rw-r--r--spec/frontend/releases/components/release_block_footer_spec.js2
-rw-r--r--spec/frontend/releases/components/release_block_header_spec.js10
-rw-r--r--spec/frontend/releases/components/release_block_milestone_info_spec.js29
-rw-r--r--spec/frontend/releases/components/release_block_spec.js62
-rw-r--r--spec/graphql/resolvers/boards_resolver_spec.rb15
-rw-r--r--spec/javascripts/filtered_search/visual_token_value_spec.js4
-rw-r--r--spec/javascripts/releases/components/app_index_spec.js6
-rw-r--r--spec/javascripts/releases/stores/modules/list/actions_spec.js6
-rw-r--r--spec/requests/api/graphql/boards/boards_query_spec.rb2
-rw-r--r--spec/support/shared_contexts/requests/api/graphql/group_and_project_boards_query_shared_context.rb14
-rw-r--r--spec/support/shared_examples/requests/api/graphql/group_and_project_boards_query_shared_examples.rb20
-rw-r--r--spec/views/profiles/preferences/show.html.haml_spec.rb2
26 files changed, 632 insertions, 466 deletions
diff --git a/spec/controllers/projects/hooks_controller_spec.rb b/spec/controllers/projects/hooks_controller_spec.rb
index f50ef2d804c..e97f602d9ab 100644
--- a/spec/controllers/projects/hooks_controller_spec.rb
+++ b/spec/controllers/projects/hooks_controller_spec.rb
@@ -12,12 +12,11 @@ describe Projects::HooksController do
end
describe '#index' do
- it 'redirects to settings/integrations page' do
- get(:index, params: { namespace_id: project.namespace, project_id: project })
+ it 'renders index with 200 status code' do
+ get :index, params: { namespace_id: project.namespace, project_id: project }
- expect(response).to redirect_to(
- project_settings_integrations_path(project)
- )
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template(:index)
end
end
diff --git a/spec/factories/ci/pipelines.rb b/spec/factories/ci/pipelines.rb
index afc203562ba..40b2aa3042e 100644
--- a/spec/factories/ci/pipelines.rb
+++ b/spec/factories/ci/pipelines.rb
@@ -22,6 +22,7 @@ FactoryBot.define do
factory :ci_pipeline do
trait :invalid do
+ status { :failed }
yaml_errors { 'invalid YAML' }
failure_reason { :config_error }
end
diff --git a/spec/features/projects/navbar_spec.rb b/spec/features/projects/navbar_spec.rb
index 4ab6b0ce506..95a8f974261 100644
--- a/spec/features/projects/navbar_spec.rb
+++ b/spec/features/projects/navbar_spec.rb
@@ -88,6 +88,7 @@ describe 'Project navbar' do
_('General'),
_('Members'),
_('Integrations'),
+ _('Webhooks'),
_('Repository'),
_('CI / CD'),
_('Operations'),
diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb
index 63c0695fe95..1c72c54f0a1 100644
--- a/spec/features/projects/pipelines/pipeline_spec.rb
+++ b/spec/features/projects/pipelines/pipeline_spec.rb
@@ -1077,8 +1077,6 @@ describe 'Pipeline', :js do
end
context 'when pipeline has configuration errors' do
- include_context 'pipeline builds'
-
let(:pipeline) do
create(:ci_pipeline,
:invalid,
@@ -1119,6 +1117,10 @@ describe 'Pipeline', :js do
%Q{span[title="#{pipeline.present.failure_reason}"]})
end
end
+
+ it 'contains a pipeline header with title' do
+ expect(page).to have_content "Pipeline ##{pipeline.id}"
+ end
end
context 'when pipeline is stuck' do
diff --git a/spec/features/projects/services/user_views_services_spec.rb b/spec/features/projects/services/user_views_services_spec.rb
index d9358a40602..cf403a131b0 100644
--- a/spec/features/projects/services/user_views_services_spec.rb
+++ b/spec/features/projects/services/user_views_services_spec.rb
@@ -14,7 +14,7 @@ describe 'User views services' do
end
it 'shows the list of available services' do
- expect(page).to have_content('Project services')
+ expect(page).to have_content('Integrations')
expect(page).to have_content('Campfire')
expect(page).to have_content('HipChat')
expect(page).to have_content('Assembla')
diff --git a/spec/features/projects/settings/operations_settings_spec.rb b/spec/features/projects/settings/operations_settings_spec.rb
index d57401471ff..3c9102431e8 100644
--- a/spec/features/projects/settings/operations_settings_spec.rb
+++ b/spec/features/projects/settings/operations_settings_spec.rb
@@ -35,7 +35,7 @@ describe 'Projects > Settings > For a forked project', :js do
end
it 'renders form for incident management' do
- expect(page).to have_selector('h4', text: 'Incidents')
+ expect(page).to have_selector('h3', text: 'Incidents')
end
it 'sets correct default values' do
diff --git a/spec/features/projects/settings/integration_settings_spec.rb b/spec/features/projects/settings/webhooks_settings_spec.rb
index de987b879eb..7e22117c63c 100644
--- a/spec/features/projects/settings/integration_settings_spec.rb
+++ b/spec/features/projects/settings/webhooks_settings_spec.rb
@@ -2,11 +2,10 @@
require 'spec_helper'
-describe 'Projects > Settings > Integration settings' do
+describe 'Projects > Settings > Webhook Settings' do
let(:project) { create(:project) }
let(:user) { create(:user) }
- let(:role) { :developer }
- let(:integrations_path) { project_settings_integrations_path(project) }
+ let(:webhooks_path) { project_hooks_path(project) }
before do
sign_in(user)
@@ -17,7 +16,7 @@ describe 'Projects > Settings > Integration settings' do
let(:role) { :developer }
it 'to be disallowed to view' do
- visit integrations_path
+ visit webhooks_path
expect(page.status_code).to eq(404)
end
@@ -33,7 +32,7 @@ describe 'Projects > Settings > Integration settings' do
it 'show list of webhooks' do
hook
- visit integrations_path
+ visit webhooks_path
expect(page.status_code).to eq(200)
expect(page).to have_content(hook.url)
@@ -49,7 +48,7 @@ describe 'Projects > Settings > Integration settings' do
end
it 'create webhook' do
- visit integrations_path
+ visit webhooks_path
fill_in 'hook_url', with: url
check 'Tag push events'
@@ -68,7 +67,7 @@ describe 'Projects > Settings > Integration settings' do
it 'edit existing webhook' do
hook
- visit integrations_path
+ visit webhooks_path
click_link 'Edit'
fill_in 'hook_url', with: url
@@ -81,25 +80,25 @@ describe 'Projects > Settings > Integration settings' do
it 'test existing webhook', :js do
WebMock.stub_request(:post, hook.url)
- visit integrations_path
+ visit webhooks_path
find('.hook-test-button.dropdown').click
click_link 'Push events'
- expect(current_path).to eq(integrations_path)
+ expect(current_path).to eq(webhooks_path)
end
context 'delete existing webhook' do
it 'from webhooks list page' do
hook
- visit integrations_path
+ visit webhooks_path
expect { click_link 'Delete' }.to change(ProjectHook, :count).by(-1)
end
it 'from webhook edit page' do
hook
- visit integrations_path
+ visit webhooks_path
click_link 'Edit'
expect { click_link 'Delete' }.to change(ProjectHook, :count).by(-1)
diff --git a/spec/frontend/grafana_integration/components/__snapshots__/grafana_integration_spec.js.snap b/spec/frontend/grafana_integration/components/__snapshots__/grafana_integration_spec.js.snap
index 3d56bef4b33..09977ecc7a3 100644
--- a/spec/frontend/grafana_integration/components/__snapshots__/grafana_integration_spec.js.snap
+++ b/spec/frontend/grafana_integration/components/__snapshots__/grafana_integration_spec.js.snap
@@ -8,13 +8,13 @@ exports[`grafana integration component default state to match the default snapsh
<div
class="settings-header"
>
- <h4
- class="js-section-header"
+ <h3
+ class="js-section-header h4"
>
Grafana Authentication
- </h4>
+ </h3>
<gl-button-stub
class="js-settings-toggle"
diff --git a/spec/frontend/monitoring/components/charts/time_series_spec.js b/spec/frontend/monitoring/components/charts/time_series_spec.js
index 49f2a70a8b2..4dd376faac0 100644
--- a/spec/frontend/monitoring/components/charts/time_series_spec.js
+++ b/spec/frontend/monitoring/components/charts/time_series_spec.js
@@ -2,6 +2,7 @@ import { shallowMount } from '@vue/test-utils';
import { setTestTimeout } from 'helpers/timeout';
import { GlLink } from '@gitlab/ui';
import { GlAreaChart, GlLineChart, GlChartSeriesLabel } from '@gitlab/ui/dist/charts';
+import { cloneDeep } from 'lodash';
import { shallowWrapperContainsSlotText } from 'helpers/vue_test_utils_helper';
import { chartColorValues } from '~/monitoring/constants';
import { createStore } from '~/monitoring/stores';
@@ -32,501 +33,563 @@ jest.mock('~/lib/utils/icon_utils', () => ({
describe('Time series component', () => {
let mockGraphData;
- let makeTimeSeriesChart;
let store;
- beforeEach(() => {
- setTestTimeout(1000);
-
- store = createStore();
-
- store.commit(
- `monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`,
- metricsDashboardPayload,
- );
-
- store.commit(`monitoringDashboard/${types.RECEIVE_DEPLOYMENTS_DATA_SUCCESS}`, deploymentData);
+ const makeTimeSeriesChart = (graphData, type) =>
+ shallowMount(TimeSeries, {
+ propsData: {
+ graphData: { ...graphData, type },
+ deploymentData: store.state.monitoringDashboard.deploymentData,
+ projectPath: `${mockHost}${mockProjectDir}`,
+ },
+ store,
+ });
- // Mock data contains 2 panel groups, with 1 and 2 panels respectively
- store.commit(
- `monitoringDashboard/${types.RECEIVE_METRIC_RESULT_SUCCESS}`,
- mockedQueryResultPayload,
- );
+ describe('With a single time series', () => {
+ beforeEach(() => {
+ setTestTimeout(1000);
- // Pick the second panel group and the first panel in it
- [mockGraphData] = store.state.monitoringDashboard.dashboard.panel_groups[1].panels;
+ store = createStore();
- makeTimeSeriesChart = (graphData, type) =>
- shallowMount(TimeSeries, {
- propsData: {
- graphData: { ...graphData, type },
- deploymentData: store.state.monitoringDashboard.deploymentData,
- projectPath: `${mockHost}${mockProjectDir}`,
- },
- store,
- });
- });
+ store.commit(
+ `monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`,
+ metricsDashboardPayload,
+ );
- describe('general functions', () => {
- let timeSeriesChart;
+ store.commit(`monitoringDashboard/${types.RECEIVE_DEPLOYMENTS_DATA_SUCCESS}`, deploymentData);
- const findChart = () => timeSeriesChart.find({ ref: 'chart' });
+ // Mock data contains 2 panel groups, with 1 and 2 panels respectively
+ store.commit(
+ `monitoringDashboard/${types.RECEIVE_METRIC_RESULT_SUCCESS}`,
+ mockedQueryResultPayload,
+ );
- beforeEach(done => {
- timeSeriesChart = makeTimeSeriesChart(mockGraphData, 'area-chart');
- timeSeriesChart.vm.$nextTick(done);
+ // Pick the second panel group and the first panel in it
+ [mockGraphData] = store.state.monitoringDashboard.dashboard.panel_groups[1].panels;
});
- it('allows user to override max value label text using prop', () => {
- timeSeriesChart.setProps({ legendMaxText: 'legendMaxText' });
-
- return timeSeriesChart.vm.$nextTick().then(() => {
- expect(timeSeriesChart.props().legendMaxText).toBe('legendMaxText');
- });
- });
+ describe('general functions', () => {
+ let timeSeriesChart;
- it('allows user to override average value label text using prop', () => {
- timeSeriesChart.setProps({ legendAverageText: 'averageText' });
+ const findChart = () => timeSeriesChart.find({ ref: 'chart' });
- return timeSeriesChart.vm.$nextTick().then(() => {
- expect(timeSeriesChart.props().legendAverageText).toBe('averageText');
+ beforeEach(done => {
+ timeSeriesChart = makeTimeSeriesChart(mockGraphData, 'area-chart');
+ timeSeriesChart.vm.$nextTick(done);
});
- });
- describe('events', () => {
- describe('datazoom', () => {
- let eChartMock;
- let startValue;
- let endValue;
-
- beforeEach(done => {
- eChartMock = {
- handlers: {},
- getOption: () => ({
- dataZoom: [
- {
- startValue,
- endValue,
- },
- ],
- }),
- off: jest.fn(eChartEvent => {
- delete eChartMock.handlers[eChartEvent];
- }),
- on: jest.fn((eChartEvent, fn) => {
- eChartMock.handlers[eChartEvent] = fn;
- }),
- };
-
- timeSeriesChart = makeTimeSeriesChart(mockGraphData);
- timeSeriesChart.vm.$nextTick(() => {
- findChart().vm.$emit('created', eChartMock);
- done();
- });
- });
+ it('allows user to override max value label text using prop', () => {
+ timeSeriesChart.setProps({ legendMaxText: 'legendMaxText' });
- it('handles datazoom event from chart', () => {
- startValue = 1577836800000; // 2020-01-01T00:00:00.000Z
- endValue = 1577840400000; // 2020-01-01T01:00:00.000Z
- eChartMock.handlers.datazoom();
-
- expect(timeSeriesChart.emitted('datazoom')).toHaveLength(1);
- expect(timeSeriesChart.emitted('datazoom')[0]).toEqual([
- {
- start: new Date(startValue).toISOString(),
- end: new Date(endValue).toISOString(),
- },
- ]);
+ return timeSeriesChart.vm.$nextTick().then(() => {
+ expect(timeSeriesChart.props().legendMaxText).toBe('legendMaxText');
});
});
- });
- describe('methods', () => {
- describe('formatTooltipText', () => {
- let mockDate;
- let mockCommitUrl;
- let generateSeriesData;
+ it('allows user to override average value label text using prop', () => {
+ timeSeriesChart.setProps({ legendAverageText: 'averageText' });
- beforeEach(() => {
- mockDate = deploymentData[0].created_at;
- mockCommitUrl = deploymentData[0].commitUrl;
- generateSeriesData = type => ({
- seriesData: [
- {
- seriesName: timeSeriesChart.vm.chartData[0].name,
- componentSubType: type,
- value: [mockDate, 5.55555],
- dataIndex: 0,
- },
- ],
- value: mockDate,
- });
+ return timeSeriesChart.vm.$nextTick().then(() => {
+ expect(timeSeriesChart.props().legendAverageText).toBe('averageText');
});
+ });
- it('does not throw error if data point is outside the zoom range', () => {
- const seriesDataWithoutValue = generateSeriesData('line');
- expect(
- timeSeriesChart.vm.formatTooltipText({
- ...seriesDataWithoutValue,
- seriesData: seriesDataWithoutValue.seriesData.map(data => ({
- ...data,
- value: undefined,
- })),
- }),
- ).toBeUndefined();
- });
+ describe('events', () => {
+ describe('datazoom', () => {
+ let eChartMock;
+ let startValue;
+ let endValue;
- describe('when series is of line type', () => {
beforeEach(done => {
- timeSeriesChart.vm.formatTooltipText(generateSeriesData('line'));
- timeSeriesChart.vm.$nextTick(done);
- });
+ eChartMock = {
+ handlers: {},
+ getOption: () => ({
+ dataZoom: [
+ {
+ startValue,
+ endValue,
+ },
+ ],
+ }),
+ off: jest.fn(eChartEvent => {
+ delete eChartMock.handlers[eChartEvent];
+ }),
+ on: jest.fn((eChartEvent, fn) => {
+ eChartMock.handlers[eChartEvent] = fn;
+ }),
+ };
- it('formats tooltip title', () => {
- expect(timeSeriesChart.vm.tooltip.title).toBe('16 Jul 2019, 10:14AM');
+ timeSeriesChart = makeTimeSeriesChart(mockGraphData);
+ timeSeriesChart.vm.$nextTick(() => {
+ findChart().vm.$emit('created', eChartMock);
+ done();
+ });
});
- it('formats tooltip content', () => {
- const name = 'Pod average';
- const value = '5.556';
- const dataIndex = 0;
- const seriesLabel = timeSeriesChart.find(GlChartSeriesLabel);
+ it('handles datazoom event from chart', () => {
+ startValue = 1577836800000; // 2020-01-01T00:00:00.000Z
+ endValue = 1577840400000; // 2020-01-01T01:00:00.000Z
+ eChartMock.handlers.datazoom();
- expect(seriesLabel.vm.color).toBe('');
- expect(shallowWrapperContainsSlotText(seriesLabel, 'default', name)).toBe(true);
- expect(timeSeriesChart.vm.tooltip.content).toEqual([
- { name, value, dataIndex, color: undefined },
+ expect(timeSeriesChart.emitted('datazoom')).toHaveLength(1);
+ expect(timeSeriesChart.emitted('datazoom')[0]).toEqual([
+ {
+ start: new Date(startValue).toISOString(),
+ end: new Date(endValue).toISOString(),
+ },
]);
-
- expect(
- shallowWrapperContainsSlotText(
- timeSeriesChart.find(GlAreaChart),
- 'tooltipContent',
- value,
- ),
- ).toBe(true);
});
});
+ });
+
+ describe('methods', () => {
+ describe('formatTooltipText', () => {
+ let mockDate;
+ let mockCommitUrl;
+ let generateSeriesData;
- describe('when series is of scatter type, for deployments', () => {
beforeEach(() => {
- timeSeriesChart.vm.formatTooltipText(generateSeriesData('scatter'));
+ mockDate = deploymentData[0].created_at;
+ mockCommitUrl = deploymentData[0].commitUrl;
+ generateSeriesData = type => ({
+ seriesData: [
+ {
+ seriesName: timeSeriesChart.vm.chartData[0].name,
+ componentSubType: type,
+ value: [mockDate, 5.55555],
+ dataIndex: 0,
+ },
+ ],
+ value: mockDate,
+ });
});
- it('formats tooltip title', () => {
- expect(timeSeriesChart.vm.tooltip.title).toBe('16 Jul 2019, 10:14AM');
+ it('does not throw error if data point is outside the zoom range', () => {
+ const seriesDataWithoutValue = generateSeriesData('line');
+ expect(
+ timeSeriesChart.vm.formatTooltipText({
+ ...seriesDataWithoutValue,
+ seriesData: seriesDataWithoutValue.seriesData.map(data => ({
+ ...data,
+ value: undefined,
+ })),
+ }),
+ ).toBeUndefined();
});
- it('formats tooltip sha', () => {
- expect(timeSeriesChart.vm.tooltip.sha).toBe('f5bcd1d9');
+ describe('when series is of line type', () => {
+ beforeEach(done => {
+ timeSeriesChart.vm.formatTooltipText(generateSeriesData('line'));
+ timeSeriesChart.vm.$nextTick(done);
+ });
+
+ it('formats tooltip title', () => {
+ expect(timeSeriesChart.vm.tooltip.title).toBe('16 Jul 2019, 10:14AM');
+ });
+
+ it('formats tooltip content', () => {
+ const name = 'Pod average';
+ const value = '5.556';
+ const dataIndex = 0;
+ const seriesLabel = timeSeriesChart.find(GlChartSeriesLabel);
+
+ expect(seriesLabel.vm.color).toBe('');
+ expect(shallowWrapperContainsSlotText(seriesLabel, 'default', name)).toBe(true);
+ expect(timeSeriesChart.vm.tooltip.content).toEqual([
+ { name, value, dataIndex, color: undefined },
+ ]);
+
+ expect(
+ shallowWrapperContainsSlotText(
+ timeSeriesChart.find(GlAreaChart),
+ 'tooltipContent',
+ value,
+ ),
+ ).toBe(true);
+ });
});
- it('formats tooltip commit url', () => {
- expect(timeSeriesChart.vm.tooltip.commitUrl).toBe(mockCommitUrl);
+ describe('when series is of scatter type, for deployments', () => {
+ beforeEach(() => {
+ timeSeriesChart.vm.formatTooltipText(generateSeriesData('scatter'));
+ });
+
+ it('formats tooltip title', () => {
+ expect(timeSeriesChart.vm.tooltip.title).toBe('16 Jul 2019, 10:14AM');
+ });
+
+ it('formats tooltip sha', () => {
+ expect(timeSeriesChart.vm.tooltip.sha).toBe('f5bcd1d9');
+ });
+
+ it('formats tooltip commit url', () => {
+ expect(timeSeriesChart.vm.tooltip.commitUrl).toBe(mockCommitUrl);
+ });
});
});
- });
- describe('setSvg', () => {
- const mockSvgName = 'mockSvgName';
+ describe('setSvg', () => {
+ const mockSvgName = 'mockSvgName';
- beforeEach(done => {
- timeSeriesChart.vm.setSvg(mockSvgName);
- timeSeriesChart.vm.$nextTick(done);
- });
+ beforeEach(done => {
+ timeSeriesChart.vm.setSvg(mockSvgName);
+ timeSeriesChart.vm.$nextTick(done);
+ });
- it('gets svg path content', () => {
- expect(iconUtils.getSvgIconPathContent).toHaveBeenCalledWith(mockSvgName);
- });
+ it('gets svg path content', () => {
+ expect(iconUtils.getSvgIconPathContent).toHaveBeenCalledWith(mockSvgName);
+ });
- it('sets svg path content', () => {
- timeSeriesChart.vm.$nextTick(() => {
- expect(timeSeriesChart.vm.svgs[mockSvgName]).toBe(`path://${mockSvgPathContent}`);
+ it('sets svg path content', () => {
+ timeSeriesChart.vm.$nextTick(() => {
+ expect(timeSeriesChart.vm.svgs[mockSvgName]).toBe(`path://${mockSvgPathContent}`);
+ });
});
- });
- it('contains an svg object within an array to properly render icon', () => {
- timeSeriesChart.vm.$nextTick(() => {
- expect(timeSeriesChart.vm.chartOptions.dataZoom).toEqual([
- {
- handleIcon: `path://${mockSvgPathContent}`,
- },
- ]);
+ it('contains an svg object within an array to properly render icon', () => {
+ timeSeriesChart.vm.$nextTick(() => {
+ expect(timeSeriesChart.vm.chartOptions.dataZoom).toEqual([
+ {
+ handleIcon: `path://${mockSvgPathContent}`,
+ },
+ ]);
+ });
});
});
- });
- describe('onResize', () => {
- const mockWidth = 233;
+ describe('onResize', () => {
+ const mockWidth = 233;
- beforeEach(() => {
- jest.spyOn(Element.prototype, 'getBoundingClientRect').mockImplementation(() => ({
- width: mockWidth,
- }));
- timeSeriesChart.vm.onResize();
- });
+ beforeEach(() => {
+ jest.spyOn(Element.prototype, 'getBoundingClientRect').mockImplementation(() => ({
+ width: mockWidth,
+ }));
+ timeSeriesChart.vm.onResize();
+ });
- it('sets area chart width', () => {
- expect(timeSeriesChart.vm.width).toBe(mockWidth);
+ it('sets area chart width', () => {
+ expect(timeSeriesChart.vm.width).toBe(mockWidth);
+ });
});
});
- });
- describe('computed', () => {
- const getChartOptions = () => findChart().props('option');
+ describe('computed', () => {
+ const getChartOptions = () => findChart().props('option');
- describe('chartData', () => {
- let chartData;
- const seriesData = () => chartData[0];
+ describe('chartData', () => {
+ let chartData;
+ const seriesData = () => chartData[0];
- beforeEach(() => {
- ({ chartData } = timeSeriesChart.vm);
- });
+ beforeEach(() => {
+ ({ chartData } = timeSeriesChart.vm);
+ });
- it('utilizes all data points', () => {
- const { values } = mockGraphData.metrics[0].result[0];
+ it('utilizes all data points', () => {
+ const { values } = mockGraphData.metrics[0].result[0];
- expect(chartData.length).toBe(1);
- expect(seriesData().data.length).toBe(values.length);
- });
+ expect(chartData.length).toBe(1);
+ expect(seriesData().data.length).toBe(values.length);
+ });
- it('creates valid data', () => {
- const { data } = seriesData();
+ it('creates valid data', () => {
+ const { data } = seriesData();
- expect(
- data.filter(
- ([time, value]) => new Date(time).getTime() > 0 && typeof value === 'number',
- ).length,
- ).toBe(data.length);
- });
+ expect(
+ data.filter(
+ ([time, value]) => new Date(time).getTime() > 0 && typeof value === 'number',
+ ).length,
+ ).toBe(data.length);
+ });
- it('formats line width correctly', () => {
- expect(chartData[0].lineStyle.width).toBe(2);
- });
+ it('formats line width correctly', () => {
+ expect(chartData[0].lineStyle.width).toBe(2);
+ });
- it('formats line color correctly', () => {
- expect(chartData[0].lineStyle.color).toBe(chartColorValues[0]);
+ it('formats line color correctly', () => {
+ expect(chartData[0].lineStyle.color).toBe(chartColorValues[0]);
+ });
});
- });
- describe('chartOptions', () => {
- describe('are extended by `option`', () => {
- const mockSeriesName = 'Extra series 1';
- const mockOption = {
- option1: 'option1',
- option2: 'option2',
- };
-
- it('arbitrary options', () => {
- timeSeriesChart.setProps({
- option: mockOption,
- });
+ describe('chartOptions', () => {
+ describe('are extended by `option`', () => {
+ const mockSeriesName = 'Extra series 1';
+ const mockOption = {
+ option1: 'option1',
+ option2: 'option2',
+ };
- return timeSeriesChart.vm.$nextTick().then(() => {
- expect(getChartOptions()).toEqual(expect.objectContaining(mockOption));
- });
- });
+ it('arbitrary options', () => {
+ timeSeriesChart.setProps({
+ option: mockOption,
+ });
- it('additional series', () => {
- timeSeriesChart.setProps({
- option: {
- series: [
- {
- name: mockSeriesName,
- },
- ],
- },
+ return timeSeriesChart.vm.$nextTick().then(() => {
+ expect(getChartOptions()).toEqual(expect.objectContaining(mockOption));
+ });
});
- return timeSeriesChart.vm.$nextTick().then(() => {
- const optionSeries = getChartOptions().series;
+ it('additional series', () => {
+ timeSeriesChart.setProps({
+ option: {
+ series: [
+ {
+ name: mockSeriesName,
+ },
+ ],
+ },
+ });
+
+ return timeSeriesChart.vm.$nextTick().then(() => {
+ const optionSeries = getChartOptions().series;
- expect(optionSeries.length).toEqual(2);
- expect(optionSeries[0].name).toEqual(mockSeriesName);
+ expect(optionSeries.length).toEqual(2);
+ expect(optionSeries[0].name).toEqual(mockSeriesName);
+ });
});
- });
- it('additional y axis data', () => {
- const mockCustomYAxisOption = {
- name: 'Custom y axis label',
- axisLabel: {
- formatter: jest.fn(),
- },
- };
+ it('additional y axis data', () => {
+ const mockCustomYAxisOption = {
+ name: 'Custom y axis label',
+ axisLabel: {
+ formatter: jest.fn(),
+ },
+ };
- timeSeriesChart.setProps({
- option: {
- yAxis: mockCustomYAxisOption,
- },
+ timeSeriesChart.setProps({
+ option: {
+ yAxis: mockCustomYAxisOption,
+ },
+ });
+
+ return timeSeriesChart.vm.$nextTick().then(() => {
+ const { yAxis } = getChartOptions();
+
+ expect(yAxis[0]).toMatchObject(mockCustomYAxisOption);
+ });
});
- return timeSeriesChart.vm.$nextTick().then(() => {
- const { yAxis } = getChartOptions();
+ it('additional x axis data', () => {
+ const mockCustomXAxisOption = {
+ name: 'Custom x axis label',
+ };
+
+ timeSeriesChart.setProps({
+ option: {
+ xAxis: mockCustomXAxisOption,
+ },
+ });
+
+ return timeSeriesChart.vm.$nextTick().then(() => {
+ const { xAxis } = getChartOptions();
- expect(yAxis[0]).toMatchObject(mockCustomYAxisOption);
+ expect(xAxis).toMatchObject(mockCustomXAxisOption);
+ });
});
});
- it('additional x axis data', () => {
- const mockCustomXAxisOption = {
- name: 'Custom x axis label',
- };
+ describe('yAxis formatter', () => {
+ let dataFormatter;
+ let deploymentFormatter;
- timeSeriesChart.setProps({
- option: {
- xAxis: mockCustomXAxisOption,
- },
+ beforeEach(() => {
+ dataFormatter = getChartOptions().yAxis[0].axisLabel.formatter;
+ deploymentFormatter = getChartOptions().yAxis[1].axisLabel.formatter;
});
- return timeSeriesChart.vm.$nextTick().then(() => {
- const { xAxis } = getChartOptions();
+ it('rounds to 3 decimal places', () => {
+ expect(dataFormatter(0.88888)).toBe('0.889');
+ });
- expect(xAxis).toMatchObject(mockCustomXAxisOption);
+ it('deployment formatter is set as is required to display a tooltip', () => {
+ expect(deploymentFormatter).toEqual(expect.any(Function));
});
});
});
- describe('yAxis formatter', () => {
- let dataFormatter;
- let deploymentFormatter;
+ describe('deploymentSeries', () => {
+ it('utilizes deployment data', () => {
+ expect(timeSeriesChart.vm.deploymentSeries.yAxisIndex).toBe(1); // same as deployment y axis
+ expect(timeSeriesChart.vm.deploymentSeries.data).toEqual([
+ ['2019-07-16T10:14:25.589Z', expect.any(Number)],
+ ['2019-07-16T11:14:25.589Z', expect.any(Number)],
+ ['2019-07-16T12:14:25.589Z', expect.any(Number)],
+ ]);
- beforeEach(() => {
- dataFormatter = getChartOptions().yAxis[0].axisLabel.formatter;
- deploymentFormatter = getChartOptions().yAxis[1].axisLabel.formatter;
+ expect(timeSeriesChart.vm.deploymentSeries.symbolSize).toBe(14);
});
+ });
- it('rounds to 3 decimal places', () => {
- expect(dataFormatter(0.88888)).toBe('0.889');
+ describe('yAxisLabel', () => {
+ it('y axis is configured correctly', () => {
+ const { yAxis } = getChartOptions();
+
+ expect(yAxis).toHaveLength(2);
+
+ const [dataAxis, deploymentAxis] = yAxis;
+
+ expect(dataAxis.boundaryGap).toHaveLength(2);
+ expect(dataAxis.scale).toBe(true);
+
+ expect(deploymentAxis.show).toBe(false);
+ expect(deploymentAxis.min).toEqual(expect.any(Number));
+ expect(deploymentAxis.max).toEqual(expect.any(Number));
+ expect(deploymentAxis.min).toBeLessThan(deploymentAxis.max);
});
- it('deployment formatter is set as is required to display a tooltip', () => {
- expect(deploymentFormatter).toEqual(expect.any(Function));
+ it('constructs a label for the chart y-axis', () => {
+ const { yAxis } = getChartOptions();
+
+ expect(yAxis[0].name).toBe('Memory Used per Pod');
});
});
});
- describe('deploymentSeries', () => {
- it('utilizes deployment data', () => {
- expect(timeSeriesChart.vm.deploymentSeries.yAxisIndex).toBe(1); // same as deployment y axis
- expect(timeSeriesChart.vm.deploymentSeries.data).toEqual([
- ['2019-07-16T10:14:25.589Z', expect.any(Number)],
- ['2019-07-16T11:14:25.589Z', expect.any(Number)],
- ['2019-07-16T12:14:25.589Z', expect.any(Number)],
- ]);
-
- expect(timeSeriesChart.vm.deploymentSeries.symbolSize).toBe(14);
- });
+ afterEach(() => {
+ timeSeriesChart.destroy();
});
+ });
- describe('yAxisLabel', () => {
- it('y axis is configured correctly', () => {
- const { yAxis } = getChartOptions();
+ describe('wrapped components', () => {
+ const glChartComponents = [
+ {
+ chartType: 'area-chart',
+ component: GlAreaChart,
+ },
+ {
+ chartType: 'line-chart',
+ component: GlLineChart,
+ },
+ ];
- expect(yAxis).toHaveLength(2);
+ glChartComponents.forEach(dynamicComponent => {
+ describe(`GitLab UI: ${dynamicComponent.chartType}`, () => {
+ let timeSeriesAreaChart;
+ const findChartComponent = () => timeSeriesAreaChart.find(dynamicComponent.component);
- const [dataAxis, deploymentAxis] = yAxis;
+ beforeEach(done => {
+ timeSeriesAreaChart = makeTimeSeriesChart(mockGraphData, dynamicComponent.chartType);
+ timeSeriesAreaChart.vm.$nextTick(done);
+ });
- expect(dataAxis.boundaryGap).toHaveLength(2);
- expect(dataAxis.scale).toBe(true);
+ afterEach(() => {
+ timeSeriesAreaChart.destroy();
+ });
- expect(deploymentAxis.show).toBe(false);
- expect(deploymentAxis.min).toEqual(expect.any(Number));
- expect(deploymentAxis.max).toEqual(expect.any(Number));
- expect(deploymentAxis.min).toBeLessThan(deploymentAxis.max);
- });
+ it('is a Vue instance', () => {
+ expect(findChartComponent().exists()).toBe(true);
+ expect(findChartComponent().isVueInstance()).toBe(true);
+ });
- it('constructs a label for the chart y-axis', () => {
- const { yAxis } = getChartOptions();
+ it('receives data properties needed for proper chart render', () => {
+ const props = findChartComponent().props();
- expect(yAxis[0].name).toBe('Memory Used per Pod');
- });
- });
- });
+ expect(props.data).toBe(timeSeriesAreaChart.vm.chartData);
+ expect(props.option).toBe(timeSeriesAreaChart.vm.chartOptions);
+ expect(props.formatTooltipText).toBe(timeSeriesAreaChart.vm.formatTooltipText);
+ expect(props.thresholds).toBe(timeSeriesAreaChart.vm.thresholds);
+ });
- afterEach(() => {
- timeSeriesChart.destroy();
- });
- });
+ it('recieves a tooltip title', done => {
+ const mockTitle = 'mockTitle';
+ timeSeriesAreaChart.vm.tooltip.title = mockTitle;
- describe('wrapped components', () => {
- const glChartComponents = [
- {
- chartType: 'area-chart',
- component: GlAreaChart,
- },
- {
- chartType: 'line-chart',
- component: GlLineChart,
- },
- ];
+ timeSeriesAreaChart.vm.$nextTick(() => {
+ expect(
+ shallowWrapperContainsSlotText(findChartComponent(), 'tooltipTitle', mockTitle),
+ ).toBe(true);
+ done();
+ });
+ });
- glChartComponents.forEach(dynamicComponent => {
- describe(`GitLab UI: ${dynamicComponent.chartType}`, () => {
- let timeSeriesAreaChart;
- const findChartComponent = () => timeSeriesAreaChart.find(dynamicComponent.component);
+ describe('when tooltip is showing deployment data', () => {
+ const mockSha = 'mockSha';
+ const commitUrl = `${mockProjectDir}/-/commit/${mockSha}`;
- beforeEach(done => {
- timeSeriesAreaChart = makeTimeSeriesChart(mockGraphData, dynamicComponent.chartType);
- timeSeriesAreaChart.vm.$nextTick(done);
- });
+ beforeEach(done => {
+ timeSeriesAreaChart.vm.tooltip.isDeployment = true;
+ timeSeriesAreaChart.vm.$nextTick(done);
+ });
- afterEach(() => {
- timeSeriesAreaChart.destroy();
- });
+ it('uses deployment title', () => {
+ expect(
+ shallowWrapperContainsSlotText(findChartComponent(), 'tooltipTitle', 'Deployed'),
+ ).toBe(true);
+ });
- it('is a Vue instance', () => {
- expect(findChartComponent().exists()).toBe(true);
- expect(findChartComponent().isVueInstance()).toBe(true);
- });
+ it('renders clickable commit sha in tooltip content', done => {
+ timeSeriesAreaChart.vm.tooltip.sha = mockSha;
+ timeSeriesAreaChart.vm.tooltip.commitUrl = commitUrl;
- it('receives data properties needed for proper chart render', () => {
- const props = findChartComponent().props();
+ timeSeriesAreaChart.vm.$nextTick(() => {
+ const commitLink = timeSeriesAreaChart.find(GlLink);
- expect(props.data).toBe(timeSeriesAreaChart.vm.chartData);
- expect(props.option).toBe(timeSeriesAreaChart.vm.chartOptions);
- expect(props.formatTooltipText).toBe(timeSeriesAreaChart.vm.formatTooltipText);
- expect(props.thresholds).toBe(timeSeriesAreaChart.vm.thresholds);
+ expect(shallowWrapperContainsSlotText(commitLink, 'default', mockSha)).toBe(true);
+ expect(commitLink.attributes('href')).toEqual(commitUrl);
+ done();
+ });
+ });
+ });
});
+ });
+ });
+ });
- it('recieves a tooltip title', done => {
- const mockTitle = 'mockTitle';
- timeSeriesAreaChart.vm.tooltip.title = mockTitle;
+ describe('with multiple time series', () => {
+ const mockedResultMultipleSeries = [];
+ const [, , panelData] = metricsDashboardPayload.panel_groups[1].panels;
- timeSeriesAreaChart.vm.$nextTick(() => {
- expect(
- shallowWrapperContainsSlotText(findChartComponent(), 'tooltipTitle', mockTitle),
- ).toBe(true);
- done();
- });
- });
+ for (let i = 0; i < panelData.metrics.length; i += 1) {
+ mockedResultMultipleSeries.push(cloneDeep(mockedQueryResultPayload));
+ mockedResultMultipleSeries[
+ i
+ ].metricId = `${panelData.metrics[i].metric_id}_${panelData.metrics[i].id}`;
+ }
- describe('when tooltip is showing deployment data', () => {
- const mockSha = 'mockSha';
- const commitUrl = `${mockProjectDir}/-/commit/${mockSha}`;
+ beforeEach(() => {
+ setTestTimeout(1000);
- beforeEach(done => {
- timeSeriesAreaChart.vm.tooltip.isDeployment = true;
- timeSeriesAreaChart.vm.$nextTick(done);
- });
+ store = createStore();
- it('uses deployment title', () => {
- expect(
- shallowWrapperContainsSlotText(findChartComponent(), 'tooltipTitle', 'Deployed'),
- ).toBe(true);
- });
+ store.commit(
+ `monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`,
+ metricsDashboardPayload,
+ );
- it('renders clickable commit sha in tooltip content', done => {
- timeSeriesAreaChart.vm.tooltip.sha = mockSha;
- timeSeriesAreaChart.vm.tooltip.commitUrl = commitUrl;
+ store.commit(`monitoringDashboard/${types.RECEIVE_DEPLOYMENTS_DATA_SUCCESS}`, deploymentData);
- timeSeriesAreaChart.vm.$nextTick(() => {
- const commitLink = timeSeriesAreaChart.find(GlLink);
+ // Mock data contains the metric_id for a multiple time series panel
+ for (let i = 0; i < panelData.metrics.length; i += 1) {
+ store.commit(
+ `monitoringDashboard/${types.RECEIVE_METRIC_RESULT_SUCCESS}`,
+ mockedResultMultipleSeries[i],
+ );
+ }
- expect(shallowWrapperContainsSlotText(commitLink, 'default', mockSha)).toBe(true);
- expect(commitLink.attributes('href')).toEqual(commitUrl);
- done();
- });
- });
+ // Pick the second panel group and the second panel in it
+ [, , mockGraphData] = store.state.monitoringDashboard.dashboard.panel_groups[1].panels;
+ });
+
+ describe('General functions', () => {
+ let timeSeriesChart;
+
+ beforeEach(done => {
+ timeSeriesChart = makeTimeSeriesChart(mockGraphData, 'area-chart');
+ timeSeriesChart.vm.$nextTick(done);
+ });
+
+ describe('computed', () => {
+ let chartData;
+
+ beforeEach(() => {
+ ({ chartData } = timeSeriesChart.vm);
+ });
+
+ it('should contain different colors for each time series', () => {
+ expect(chartData[0].lineStyle.color).toBe('#1f78d1');
+ expect(chartData[1].lineStyle.color).toBe('#1aaa55');
+ expect(chartData[2].lineStyle.color).toBe('#fc9403');
+ expect(chartData[3].lineStyle.color).toBe('#6d49cb');
+ expect(chartData[4].lineStyle.color).toBe('#1f78d1');
});
});
});
diff --git a/spec/frontend/monitoring/components/dashboard_spec.js b/spec/frontend/monitoring/components/dashboard_spec.js
index 15c82242262..fcf70a1af63 100644
--- a/spec/frontend/monitoring/components/dashboard_spec.js
+++ b/spec/frontend/monitoring/components/dashboard_spec.js
@@ -22,7 +22,7 @@ import {
} from '../mock_data';
const localVue = createLocalVue();
-const expectedPanelCount = 2;
+const expectedPanelCount = 3;
describe('Dashboard', () => {
let store;
diff --git a/spec/frontend/monitoring/mock_data.js b/spec/frontend/monitoring/mock_data.js
index 4d83933f2b8..bad3962dd8f 100644
--- a/spec/frontend/monitoring/mock_data.js
+++ b/spec/frontend/monitoring/mock_data.js
@@ -513,6 +513,48 @@ export const metricsDashboardPayload = {
},
],
},
+ {
+ title: 'memories',
+ type: 'area-chart',
+ y_label: 'memories',
+ metrics: [
+ {
+ id: 'metric_of_ages_1000',
+ label: 'memory_1000',
+ unit: 'count',
+ prometheus_endpoint_path: '/root',
+ metric_id: 20,
+ },
+ {
+ id: 'metric_of_ages_1001',
+ label: 'memory_1000',
+ unit: 'count',
+ prometheus_endpoint_path: '/root',
+ metric_id: 21,
+ },
+ {
+ id: 'metric_of_ages_1002',
+ label: 'memory_1000',
+ unit: 'count',
+ prometheus_endpoint_path: '/root',
+ metric_id: 22,
+ },
+ {
+ id: 'metric_of_ages_1003',
+ label: 'memory_1000',
+ unit: 'count',
+ prometheus_endpoint_path: '/root',
+ metric_id: 23,
+ },
+ {
+ id: 'metric_of_ages_1004',
+ label: 'memory_1004',
+ unit: 'count',
+ prometheus_endpoint_path: '/root',
+ metric_id: 24,
+ },
+ ],
+ },
],
},
],
diff --git a/spec/frontend/monitoring/store/mutations_spec.js b/spec/frontend/monitoring/store/mutations_spec.js
index d9aebafb9ec..3fb7b84fae5 100644
--- a/spec/frontend/monitoring/store/mutations_spec.js
+++ b/spec/frontend/monitoring/store/mutations_spec.js
@@ -50,9 +50,10 @@ describe('Monitoring mutations', () => {
expect(groups[0].panels).toHaveLength(1);
expect(groups[0].panels[0].metrics).toHaveLength(1);
- expect(groups[1].panels).toHaveLength(2);
+ expect(groups[1].panels).toHaveLength(3);
expect(groups[1].panels[0].metrics).toHaveLength(1);
expect(groups[1].panels[1].metrics).toHaveLength(1);
+ expect(groups[1].panels[2].metrics).toHaveLength(5);
});
it('assigns metrics a metric id', () => {
mutations[types.RECEIVE_METRICS_DATA_SUCCESS](stateCopy, payload);
diff --git a/spec/frontend/releases/components/app_edit_spec.js b/spec/frontend/releases/components/app_edit_spec.js
index cb940facbd6..b2dbb8cc435 100644
--- a/spec/frontend/releases/components/app_edit_spec.js
+++ b/spec/frontend/releases/components/app_edit_spec.js
@@ -13,7 +13,7 @@ describe('Release edit component', () => {
beforeEach(() => {
gon.api_version = 'v4';
- releaseClone = JSON.parse(JSON.stringify(convertObjectPropsToCamelCase(release)));
+ releaseClone = convertObjectPropsToCamelCase(release, { deep: true });
state = {
release: releaseClone,
diff --git a/spec/frontend/releases/components/evidence_block_spec.js b/spec/frontend/releases/components/evidence_block_spec.js
index 7b896575965..fb62f4a3bfe 100644
--- a/spec/frontend/releases/components/evidence_block_spec.js
+++ b/spec/frontend/releases/components/evidence_block_spec.js
@@ -2,12 +2,14 @@ import { mount } from '@vue/test-utils';
import { GlLink } from '@gitlab/ui';
import { truncateSha } from '~/lib/utils/text_utility';
import Icon from '~/vue_shared/components/icon.vue';
-import { release } from '../mock_data';
+import { release as originalRelease } from '../mock_data';
import EvidenceBlock from '~/releases/components/evidence_block.vue';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
describe('Evidence Block', () => {
let wrapper;
+ let release;
const factory = (options = {}) => {
wrapper = mount(EvidenceBlock, {
@@ -16,6 +18,8 @@ describe('Evidence Block', () => {
};
beforeEach(() => {
+ release = convertObjectPropsToCamelCase(originalRelease, { deep: true });
+
factory({
propsData: {
release,
@@ -32,7 +36,7 @@ describe('Evidence Block', () => {
});
it('renders the title for the dowload link', () => {
- expect(wrapper.find(GlLink).text()).toBe(`${release.tag_name}-evidence.json`);
+ expect(wrapper.find(GlLink).text()).toBe(`${release.tagName}-evidence.json`);
});
it('renders the correct hover text for the download', () => {
@@ -40,19 +44,19 @@ describe('Evidence Block', () => {
});
it('renders the correct file link for download', () => {
- expect(wrapper.find(GlLink).attributes().download).toBe(`${release.tag_name}-evidence.json`);
+ expect(wrapper.find(GlLink).attributes().download).toBe(`${release.tagName}-evidence.json`);
});
describe('sha text', () => {
it('renders the short sha initially', () => {
- expect(wrapper.find('.js-short').text()).toBe(truncateSha(release.evidence_sha));
+ expect(wrapper.find('.js-short').text()).toBe(truncateSha(release.evidenceSha));
});
it('renders the long sha after expansion', () => {
wrapper.find('.js-text-expander-prepend').trigger('click');
return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.find('.js-expanded').text()).toBe(release.evidence_sha);
+ expect(wrapper.find('.js-expanded').text()).toBe(release.evidenceSha);
});
});
});
@@ -68,7 +72,7 @@ describe('Evidence Block', () => {
it('copies the sha', () => {
expect(wrapper.find(ClipboardButton).attributes('data-clipboard-text')).toBe(
- release.evidence_sha,
+ release.evidenceSha,
);
});
});
diff --git a/spec/frontend/releases/components/release_block_footer_spec.js b/spec/frontend/releases/components/release_block_footer_spec.js
index 4125d5c7e74..c63637c4cae 100644
--- a/spec/frontend/releases/components/release_block_footer_spec.js
+++ b/spec/frontend/releases/components/release_block_footer_spec.js
@@ -24,7 +24,7 @@ describe('Release block footer', () => {
const factory = (props = {}) => {
wrapper = mount(ReleaseBlockFooter, {
propsData: {
- ...convertObjectPropsToCamelCase(releaseClone),
+ ...convertObjectPropsToCamelCase(releaseClone, { deep: true }),
...props,
},
});
diff --git a/spec/frontend/releases/components/release_block_header_spec.js b/spec/frontend/releases/components/release_block_header_spec.js
index 157df15ff3c..78adad13f69 100644
--- a/spec/frontend/releases/components/release_block_header_spec.js
+++ b/spec/frontend/releases/components/release_block_header_spec.js
@@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
-import { cloneDeep, merge } from 'lodash';
+import { merge } from 'lodash';
import { GlLink } from '@gitlab/ui';
import ReleaseBlockHeader from '~/releases/components/release_block_header.vue';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
@@ -18,9 +18,7 @@ describe('Release block header', () => {
};
beforeEach(() => {
- release = convertObjectPropsToCamelCase(cloneDeep(originalRelease), {
- ignoreKeyNames: ['_links'],
- });
+ release = convertObjectPropsToCamelCase(originalRelease, { deep: true });
});
afterEach(() => {
@@ -39,13 +37,13 @@ describe('Release block header', () => {
const link = findHeaderLink();
expect(link.text()).toBe(release.name);
- expect(link.attributes('href')).toBe(release._links.self);
+ expect(link.attributes('href')).toBe(release.Links.self);
});
});
describe('when _links.self is missing', () => {
beforeEach(() => {
- factory({ _links: { self: null } });
+ factory({ Links: { self: null } });
});
it('renders the title as text', () => {
diff --git a/spec/frontend/releases/components/release_block_milestone_info_spec.js b/spec/frontend/releases/components/release_block_milestone_info_spec.js
index 5a3204a4ce2..10f5db96b31 100644
--- a/spec/frontend/releases/components/release_block_milestone_info_spec.js
+++ b/spec/frontend/releases/components/release_block_milestone_info_spec.js
@@ -2,12 +2,13 @@ import { mount } from '@vue/test-utils';
import { GlProgressBar, GlLink, GlBadge, GlButton } from '@gitlab/ui';
import { trimText } from 'helpers/text_helper';
import ReleaseBlockMilestoneInfo from '~/releases/components/release_block_milestone_info.vue';
-import { milestones } from '../mock_data';
+import { milestones as originalMilestones } from '../mock_data';
import { MAX_MILESTONES_TO_DISPLAY } from '~/releases/constants';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
describe('Release block milestone info', () => {
let wrapper;
- let milestonesClone;
+ let milestones;
const factory = milestonesProp => {
wrapper = mount(ReleaseBlockMilestoneInfo, {
@@ -20,7 +21,7 @@ describe('Release block milestone info', () => {
};
beforeEach(() => {
- milestonesClone = JSON.parse(JSON.stringify(milestones));
+ milestones = convertObjectPropsToCamelCase(originalMilestones, { deep: true });
});
afterEach(() => {
@@ -32,7 +33,7 @@ describe('Release block milestone info', () => {
const issuesContainer = () => wrapper.find('.js-issues-container');
describe('with default props', () => {
- beforeEach(() => factory(milestonesClone));
+ beforeEach(() => factory(milestones));
it('renders the correct percentage', () => {
expect(milestoneProgressBarContainer().text()).toContain('41% complete');
@@ -53,13 +54,13 @@ describe('Release block milestone info', () => {
it('renders a list of links to all associated milestones', () => {
expect(trimText(milestoneListContainer().text())).toContain('Milestones 13.6 • 13.5');
- milestonesClone.forEach((m, i) => {
+ milestones.forEach((m, i) => {
const milestoneLink = milestoneListContainer()
.findAll(GlLink)
.at(i);
expect(milestoneLink.text()).toBe(m.title);
- expect(milestoneLink.attributes('href')).toBe(m.web_url);
+ expect(milestoneLink.attributes('href')).toBe(m.webUrl);
expect(milestoneLink.attributes('title')).toBe(m.description);
});
});
@@ -84,7 +85,7 @@ describe('Release block milestone info', () => {
beforeEach(() => {
lotsOfMilestones = [];
- const template = milestonesClone[0];
+ const template = milestones[0];
for (let i = 0; i < MAX_MILESTONES_TO_DISPLAY + 10; i += 1) {
lotsOfMilestones.push({
@@ -148,16 +149,16 @@ describe('Release block milestone info', () => {
/** Ensures we don't have any issues with dividing by zero when computing percentages */
describe('when all issue counts are zero', () => {
beforeEach(() => {
- milestonesClone = milestonesClone.map(m => ({
+ milestones = milestones.map(m => ({
...m,
- issue_stats: {
- ...m.issue_stats,
+ issueStats: {
+ ...m.issueStats,
opened: 0,
closed: 0,
},
}));
- return factory(milestonesClone);
+ return factory(milestones);
});
expectAllZeros();
@@ -165,12 +166,12 @@ describe('Release block milestone info', () => {
describe('if the API response is missing the "issue_stats" property', () => {
beforeEach(() => {
- milestonesClone = milestonesClone.map(m => ({
+ milestones = milestones.map(m => ({
...m,
- issue_stats: undefined,
+ issueStats: undefined,
}));
- return factory(milestonesClone);
+ return factory(milestones);
});
expectAllZeros();
diff --git a/spec/frontend/releases/components/release_block_spec.js b/spec/frontend/releases/components/release_block_spec.js
index aba1b8aff41..5d365b77560 100644
--- a/spec/frontend/releases/components/release_block_spec.js
+++ b/spec/frontend/releases/components/release_block_spec.js
@@ -5,10 +5,12 @@ import EvidenceBlock from '~/releases/components/evidence_block.vue';
import ReleaseBlock from '~/releases/components/release_block.vue';
import ReleaseBlockFooter from '~/releases/components/release_block_footer.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
-import { release } from '../mock_data';
+import { release as originalRelease } from '../mock_data';
import Icon from '~/vue_shared/components/icon.vue';
import { scrollToElement } from '~/lib/utils/common_utils';
+const { convertObjectPropsToCamelCase } = jest.requireActual('~/lib/utils/common_utils');
+
let mockLocationHash;
jest.mock('~/lib/utils/url_utility', () => ({
__esModule: true,
@@ -22,7 +24,7 @@ jest.mock('~/lib/utils/common_utils', () => ({
describe('Release block', () => {
let wrapper;
- let releaseClone;
+ let release;
const factory = (releaseProp, featureFlags = {}) => {
wrapper = mount(ReleaseBlock, {
@@ -45,7 +47,7 @@ describe('Release block', () => {
beforeEach(() => {
jest.spyOn($.fn, 'renderGFM');
- releaseClone = JSON.parse(JSON.stringify(release));
+ release = convertObjectPropsToCamelCase(originalRelease, { deep: true });
});
afterEach(() => {
@@ -61,7 +63,7 @@ describe('Release block', () => {
it('renders an edit button that links to the "Edit release" page', () => {
expect(editButton().exists()).toBe(true);
- expect(editButton().attributes('href')).toBe(release._links.edit_url);
+ expect(editButton().attributes('href')).toBe(release.Links.editUrl);
});
it('renders release name', () => {
@@ -74,7 +76,7 @@ describe('Release block', () => {
});
it('renders release date', () => {
- expect(wrapper.text()).toContain(timeagoMixin.methods.timeFormatted(release.released_at));
+ expect(wrapper.text()).toContain(timeagoMixin.methods.timeFormatted(release.releasedAt));
});
it('renders number of assets provided', () => {
@@ -129,72 +131,72 @@ describe('Release block', () => {
});
it('renders commit sha', () => {
- releaseClone.commit_path = '/commit/example';
+ release.commitPath = '/commit/example';
- return factory(releaseClone).then(() => {
- expect(wrapper.text()).toContain(release.commit.short_id);
+ return factory(release).then(() => {
+ expect(wrapper.text()).toContain(release.commit.shortId);
expect(wrapper.find('a[href="/commit/example"]').exists()).toBe(true);
});
});
it('renders tag name', () => {
- releaseClone.tag_path = '/tag/example';
+ release.tagPath = '/tag/example';
- return factory(releaseClone).then(() => {
- expect(wrapper.text()).toContain(release.tag_name);
+ return factory(release).then(() => {
+ expect(wrapper.text()).toContain(release.tagName);
expect(wrapper.find('a[href="/tag/example"]').exists()).toBe(true);
});
});
- it("does not render an edit button if release._links.edit_url isn't a string", () => {
- delete releaseClone._links;
+ it("does not render an edit button if release.Links.editUrl isn't a string", () => {
+ delete release.Links;
- return factory(releaseClone).then(() => {
+ return factory(release).then(() => {
expect(editButton().exists()).toBe(false);
});
});
it('does not render the milestone list if no milestones are associated to the release', () => {
- delete releaseClone.milestones;
+ delete release.milestones;
- return factory(releaseClone).then(() => {
+ return factory(release).then(() => {
expect(milestoneListLabel().exists()).toBe(false);
});
});
it('renders upcoming release badge', () => {
- releaseClone.upcoming_release = true;
+ release.upcomingRelease = true;
- return factory(releaseClone).then(() => {
+ return factory(release).then(() => {
expect(wrapper.text()).toContain('Upcoming Release');
});
});
- it('slugifies the tag_name before setting it as the elements ID', () => {
- releaseClone.tag_name = 'a dangerous tag name <script>alert("hello")</script>';
+ it('slugifies the tagName before setting it as the elements ID', () => {
+ release.tagName = 'a dangerous tag name <script>alert("hello")</script>';
- return factory(releaseClone).then(() => {
+ return factory(release).then(() => {
expect(wrapper.attributes().id).toBe('a-dangerous-tag-name-script-alert-hello-script');
});
});
describe('evidence block', () => {
it('renders the evidence block when the evidence is available and the feature flag is true', () =>
- factory(releaseClone, { releaseEvidenceCollection: true }).then(() =>
+ factory(release, { releaseEvidenceCollection: true }).then(() =>
expect(wrapper.find(EvidenceBlock).exists()).toBe(true),
));
it('does not render the evidence block when the evidence is available but the feature flag is false', () =>
- factory(releaseClone, { releaseEvidenceCollection: true }).then(() =>
+ factory(release, { releaseEvidenceCollection: true }).then(() =>
expect(wrapper.find(EvidenceBlock).exists()).toBe(true),
));
it('does not render the evidence block when there is no evidence', () => {
- releaseClone.evidence_sha = null;
+ release.evidenceSha = null;
- return factory(releaseClone).then(() => {
+ return factory(release).then(() => {
expect(wrapper.find(EvidenceBlock).exists()).toBe(false);
});
});
@@ -222,7 +224,7 @@ describe('Release block', () => {
});
it("attempts to scroll itself into view if the anchor tag matches the release's tag name", () => {
- mockLocationHash = release.tag_name;
+ mockLocationHash = release.tagName;
return factory(release).then(() => {
expect(scrollToElement).toHaveBeenCalledTimes(1);
@@ -231,7 +233,7 @@ describe('Release block', () => {
});
it('renders with a light blue background if it is the target of the anchor', () => {
- mockLocationHash = release.tag_name;
+ mockLocationHash = release.tagName;
return factory(release).then(() => {
expect(hasTargetBlueBackground()).toBe(true);
@@ -275,16 +277,16 @@ describe('Release block', () => {
expect(milestoneLink.text()).toBe(milestone.title);
- expect(milestoneLink.attributes('href')).toBe(milestone.web_url);
+ expect(milestoneLink.attributes('href')).toBe(milestone.webUrl);
expect(milestoneLink.attributes('title')).toBe(milestone.description);
});
});
it('renders the label as "Milestone" if only a single milestone is passed in', () => {
- releaseClone.milestones = releaseClone.milestones.slice(0, 1);
+ release.milestones = release.milestones.slice(0, 1);
- return factory(releaseClone, { releaseIssueSummary: false }).then(() => {
+ return factory(release, { releaseIssueSummary: false }).then(() => {
expect(
milestoneListLabel()
.find('.js-label-text')
diff --git a/spec/graphql/resolvers/boards_resolver_spec.rb b/spec/graphql/resolvers/boards_resolver_spec.rb
index ab77dfa8fc3..02d6f808118 100644
--- a/spec/graphql/resolvers/boards_resolver_spec.rb
+++ b/spec/graphql/resolvers/boards_resolver_spec.rb
@@ -45,6 +45,21 @@ describe Resolvers::BoardsResolver do
expect(resolve_boards).to eq [board1]
end
end
+
+ context 'when querying for a single board' do
+ let(:board1) { create(:board, name: 'One', resource_parent: board_parent) }
+
+ it 'returns specified board' do
+ expect(resolve_boards(args: { id: global_id_of(board1) })).to eq [board1]
+ end
+
+ it 'returns nil if board not found' do
+ outside_parent = create(board_parent.class.underscore.to_sym)
+ outside_board = create(:board, name: 'outside board', resource_parent: outside_parent)
+
+ expect(resolve_boards(args: { id: global_id_of(outside_board) })).to eq Board.none
+ end
+ end
end
describe '#resolve' do
diff --git a/spec/javascripts/filtered_search/visual_token_value_spec.js b/spec/javascripts/filtered_search/visual_token_value_spec.js
index a039e280028..4469ade1874 100644
--- a/spec/javascripts/filtered_search/visual_token_value_spec.js
+++ b/spec/javascripts/filtered_search/visual_token_value_spec.js
@@ -1,4 +1,4 @@
-import _ from 'underscore';
+import { escape as esc } from 'lodash';
import VisualTokenValue from '~/filtered_search/visual_token_value';
import AjaxCache from '~/lib/utils/ajax_cache';
import UsersCache from '~/lib/utils/users_cache';
@@ -121,7 +121,7 @@ describe('Filtered Search Visual Tokens', () => {
expect(tokenValueElement.innerText.trim()).toBe(dummyUser.name);
tokenValueElement.querySelector('.avatar').remove();
- expect(tokenValueElement.innerHTML.trim()).toBe(_.escape(dummyUser.name));
+ expect(tokenValueElement.innerHTML.trim()).toBe(esc(dummyUser.name));
})
.then(done)
.catch(done.fail);
diff --git a/spec/javascripts/releases/components/app_index_spec.js b/spec/javascripts/releases/components/app_index_spec.js
index bcf062f357a..962fe9c448d 100644
--- a/spec/javascripts/releases/components/app_index_spec.js
+++ b/spec/javascripts/releases/components/app_index_spec.js
@@ -12,6 +12,7 @@ import {
release,
releases,
} from '../mock_data';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
describe('Releases App ', () => {
const Component = Vue.extend(app);
@@ -27,7 +28,10 @@ describe('Releases App ', () => {
beforeEach(() => {
store = createStore({ list: listModule });
- releasesPagination = _.range(21).map(index => ({ ...release, tag_name: `${index}.00` }));
+ releasesPagination = _.range(21).map(index => ({
+ ...convertObjectPropsToCamelCase(release, { deep: true }),
+ tagName: `${index}.00`,
+ }));
});
afterEach(() => {
diff --git a/spec/javascripts/releases/stores/modules/list/actions_spec.js b/spec/javascripts/releases/stores/modules/list/actions_spec.js
index 037c9d8d54a..bf85e18997b 100644
--- a/spec/javascripts/releases/stores/modules/list/actions_spec.js
+++ b/spec/javascripts/releases/stores/modules/list/actions_spec.js
@@ -8,16 +8,18 @@ import {
import state from '~/releases/stores/modules/list/state';
import * as types from '~/releases/stores/modules/list/mutation_types';
import api from '~/api';
-import { parseIntPagination } from '~/lib/utils/common_utils';
-import { pageInfoHeadersWithoutPagination, releases } from '../../../mock_data';
+import { parseIntPagination, convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+import { pageInfoHeadersWithoutPagination, releases as originalReleases } from '../../../mock_data';
describe('Releases State actions', () => {
let mockedState;
let pageInfo;
+ let releases;
beforeEach(() => {
mockedState = state();
pageInfo = parseIntPagination(pageInfoHeadersWithoutPagination);
+ releases = convertObjectPropsToCamelCase(originalReleases, { deep: true });
});
describe('requestReleases', () => {
diff --git a/spec/requests/api/graphql/boards/boards_query_spec.rb b/spec/requests/api/graphql/boards/boards_query_spec.rb
index d0a2d0fffaf..a17554aba21 100644
--- a/spec/requests/api/graphql/boards/boards_query_spec.rb
+++ b/spec/requests/api/graphql/boards/boards_query_spec.rb
@@ -9,14 +9,12 @@ describe 'get list of boards' do
describe 'for a project' do
let(:board_parent) { create(:project, :repository, :private) }
- let(:boards_data) { graphql_data['project']['boards']['edges'] }
it_behaves_like 'group and project boards query'
end
describe 'for a group' do
let(:board_parent) { create(:group, :private) }
- let(:boards_data) { graphql_data['group']['boards']['edges'] }
before do
allow(board_parent).to receive(:multiple_issue_boards_available?).and_return(false)
diff --git a/spec/support/shared_contexts/requests/api/graphql/group_and_project_boards_query_shared_context.rb b/spec/support/shared_contexts/requests/api/graphql/group_and_project_boards_query_shared_context.rb
index e744c3d0abb..ca77c68c130 100644
--- a/spec/support/shared_contexts/requests/api/graphql/group_and_project_boards_query_shared_context.rb
+++ b/spec/support/shared_contexts/requests/api/graphql/group_and_project_boards_query_shared_context.rb
@@ -5,6 +5,8 @@ RSpec.shared_context 'group and project boards query context' do
let(:current_user) { user }
let(:params) { '' }
let(:board_parent_type) { board_parent.class.to_s.downcase }
+ let(:boards_data) { graphql_data[board_parent_type]['boards']['edges'] }
+ let(:board_data) { graphql_data[board_parent_type]['board'] }
let(:start_cursor) { graphql_data[board_parent_type]['boards']['pageInfo']['startCursor'] }
let(:end_cursor) { graphql_data[board_parent_type]['boards']['pageInfo']['endCursor'] }
@@ -28,6 +30,18 @@ RSpec.shared_context 'group and project boards query context' do
)
end
+ def query_single_board(board_params = params)
+ graphql_query_for(
+ board_parent_type,
+ { 'fullPath' => board_parent.full_path },
+ <<~BOARD
+ board(#{board_params}) {
+ #{all_graphql_fields_for('board'.classify)}
+ }
+ BOARD
+ )
+ end
+
def grab_names(data = boards_data)
data.map do |board|
board.dig('node', 'name')
diff --git a/spec/support/shared_examples/requests/api/graphql/group_and_project_boards_query_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/group_and_project_boards_query_shared_examples.rb
index 6044fefd2f7..90ac60a6fe7 100644
--- a/spec/support/shared_examples/requests/api/graphql/group_and_project_boards_query_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/graphql/group_and_project_boards_query_shared_examples.rb
@@ -89,4 +89,24 @@ RSpec.shared_examples 'group and project boards query' do
end
end
end
+
+ context 'when querying for a single board' do
+ before do
+ board_parent.add_reporter(current_user)
+ end
+
+ it_behaves_like 'a working graphql query' do
+ before do
+ post_graphql(query_single_board, current_user: current_user)
+ end
+ end
+
+ it 'finds the correct board' do
+ board = create(:board, resource_parent: board_parent, name: 'A')
+
+ post_graphql(query_single_board("id: \"#{global_id_of(board)}\""), current_user: current_user)
+
+ expect(board_data['name']).to eq board.name
+ end
+ end
end
diff --git a/spec/views/profiles/preferences/show.html.haml_spec.rb b/spec/views/profiles/preferences/show.html.haml_spec.rb
index e3eb822b045..16e4bd9c6d1 100644
--- a/spec/views/profiles/preferences/show.html.haml_spec.rb
+++ b/spec/views/profiles/preferences/show.html.haml_spec.rb
@@ -56,7 +56,7 @@ describe 'profiles/preferences/show' do
expect(rendered).not_to have_sourcegraph_field
end
- it 'does not display integrations settings' do
+ it 'does not display Integration Settings' do
expect(rendered).not_to have_integrations_section
end
end