Commit 16db5a72 authored by Dylan Griffith's avatar Dylan Griffith

Merge branch 'ek-revert-351853-vsa-empty-state' into 'master'

Revert "Merge branch 351853-vsa-add-empty-state-at-the-group-level-when-there-are-no-custom-value-streams"

See merge request gitlab-org/gitlab!83706
parents 2fc4e258 c45c81b9
...@@ -15,7 +15,6 @@ import { METRICS_REQUESTS } from '../constants'; ...@@ -15,7 +15,6 @@ import { METRICS_REQUESTS } from '../constants';
import DurationChart from './duration_chart.vue'; import DurationChart from './duration_chart.vue';
import TypeOfWorkCharts from './type_of_work_charts.vue'; import TypeOfWorkCharts from './type_of_work_charts.vue';
import ValueStreamAggregationStatus from './value_stream_aggregation_status.vue'; import ValueStreamAggregationStatus from './value_stream_aggregation_status.vue';
import ValueStreamEmptyState from './value_stream_empty_state.vue';
import ValueStreamSelect from './value_stream_select.vue'; import ValueStreamSelect from './value_stream_select.vue';
export default { export default {
...@@ -27,7 +26,6 @@ export default { ...@@ -27,7 +26,6 @@ export default {
StageTable, StageTable,
PathNavigation, PathNavigation,
ValueStreamAggregationStatus, ValueStreamAggregationStatus,
ValueStreamEmptyState,
ValueStreamFilters, ValueStreamFilters,
ValueStreamMetrics, ValueStreamMetrics,
ValueStreamSelect, ValueStreamSelect,
...@@ -76,10 +74,9 @@ export default { ...@@ -76,10 +74,9 @@ export default {
'pathNavigationData', 'pathNavigationData',
'isOverviewStageSelected', 'isOverviewStageSelected',
'selectedStageCount', 'selectedStageCount',
'hasValueStreams',
]), ]),
shouldRenderEmptyState() { shouldRenderEmptyState() {
return this.isLoadingValueStreams || !this.hasValueStreams; return !this.currentGroup && !this.isLoading;
}, },
shouldDisplayFilters() { shouldDisplayFilters() {
return !this.errorCode && !this.hasNoAccessError; return !this.errorCode && !this.hasNoAccessError;
...@@ -201,25 +198,24 @@ export default { ...@@ -201,25 +198,24 @@ export default {
</script> </script>
<template> <template>
<div> <div>
<value-stream-empty-state <div
class="gl-mb-3 gl-display-flex gl-flex-direction-column gl-sm-flex-direction-row gl-justify-content-space-between"
>
<h3>{{ __('Value Stream Analytics') }}</h3>
<div class="gl-display-flex gl-flex-direction-row gl-align-items-center gl-mt-0 gl-sm-mt-5">
<value-stream-aggregation-status v-if="isAggregationStatusAvailable" :data="aggregation" />
<value-stream-select v-if="shouldDisplayCreateMultipleValueStreams" />
</div>
</div>
<gl-empty-state
v-if="shouldRenderEmptyState" v-if="shouldRenderEmptyState"
:is-loading="isLoadingValueStreams" :title="__('Value Stream Analytics can help you determine your team’s velocity')"
:empty-state-svg-path="emptyStateSvgPath" :description="
:has-date-range-error="!hasDateRangeSet" __('Filter parameters are not valid. Make sure that the end date is after the start date.')
"
:svg-path="emptyStateSvgPath"
/> />
<div v-else class="gl-max-w-full"> <div v-else class="gl-max-w-full">
<div
class="gl-mb-3 gl-display-flex gl-flex-direction-column gl-sm-flex-direction-row gl-justify-content-space-between"
>
<h3>{{ __('Value Stream Analytics') }}</h3>
<div class="gl-display-flex gl-flex-direction-row gl-align-items-center gl-mt-0 gl-sm-mt-5">
<value-stream-aggregation-status
v-if="isAggregationStatusAvailable"
:data="aggregation"
/>
<value-stream-select v-if="shouldDisplayCreateMultipleValueStreams" />
</div>
</div>
<path-navigation <path-navigation
v-if="selectedStageReady" v-if="selectedStageReady"
data-testid="vsa-path-navigation" data-testid="vsa-path-navigation"
......
...@@ -76,7 +76,6 @@ export default { ...@@ -76,7 +76,6 @@ export default {
:svg-path="emptyStateSvgPath" :svg-path="emptyStateSvgPath"
:title="title" :title="title"
:description="description" :description="description"
data-testid="vsa-empty-state"
> >
<template v-if="!hasDateRangeError" #actions> <template v-if="!hasDateRangeError" #actions>
<gl-button <gl-button
......
...@@ -13,8 +13,6 @@ import { DEFAULT_VALUE_STREAM_ID, OVERVIEW_STAGE_CONFIG } from '../constants'; ...@@ -13,8 +13,6 @@ import { DEFAULT_VALUE_STREAM_ID, OVERVIEW_STAGE_CONFIG } from '../constants';
export const hasNoAccessError = (state) => state.errorCode === httpStatus.FORBIDDEN; export const hasNoAccessError = (state) => state.errorCode === httpStatus.FORBIDDEN;
export const hasValueStreams = ({ valueStreams }) => Boolean(valueStreams?.length);
export const currentValueStreamId = ({ selectedValueStream }) => export const currentValueStreamId = ({ selectedValueStream }) =>
selectedValueStream?.id || DEFAULT_VALUE_STREAM_ID; selectedValueStream?.id || DEFAULT_VALUE_STREAM_ID;
......
...@@ -97,13 +97,7 @@ class Groups::Analytics::CycleAnalytics::ValueStreamsController < Groups::Analyt ...@@ -97,13 +97,7 @@ class Groups::Analytics::CycleAnalytics::ValueStreamsController < Groups::Analyt
end end
def value_streams def value_streams
value_streams = @group.value_streams.preload_associated_models @group.value_streams.preload_associated_models.presence || [in_memory_default_value_stream]
if Feature.enabled?(:use_vsa_aggregated_tables, @group, default_enabled: :yaml)
value_streams
else
value_streams.presence || [in_memory_default_value_stream]
end
end end
def in_memory_default_value_stream def in_memory_default_value_stream
......
...@@ -11,11 +11,7 @@ module EE ...@@ -11,11 +11,7 @@ module EE
def execute def execute
return forbidden unless allowed? return forbidden unless allowed?
if parent.is_a?(Group) && ::Feature.enabled?(:use_vsa_aggregated_tables, parent, default_enabled: :yaml) success(persisted_stages.presence || build_default_stages)
success(persisted_stages)
else
success(persisted_stages.presence || build_default_stages)
end
end end
private private
......
...@@ -5,8 +5,6 @@ require 'spec_helper' ...@@ -5,8 +5,6 @@ require 'spec_helper'
RSpec.describe Groups::Analytics::CycleAnalytics::StagesController do RSpec.describe Groups::Analytics::CycleAnalytics::StagesController do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:group, refind: true) { create(:group) } let_it_be(:group, refind: true) { create(:group) }
let_it_be(:stages) { [] }
let_it_be(:value_stream) { create(:cycle_analytics_group_value_stream, group: group, name: 'No stage value stream', stages: stages) }
context 'when params have only group_id' do context 'when params have only group_id' do
let(:params) { { group_id: group } } let(:params) { { group_id: group } }
...@@ -21,8 +19,6 @@ RSpec.describe Groups::Analytics::CycleAnalytics::StagesController do ...@@ -21,8 +19,6 @@ RSpec.describe Groups::Analytics::CycleAnalytics::StagesController do
end end
context 'when use_vsa_aggregated_tables FF is disabled' do context 'when use_vsa_aggregated_tables FF is disabled' do
let_it_be(:stages) { Gitlab::Analytics::CycleAnalytics::DefaultStages.all }
it_behaves_like 'Value Stream Analytics Stages controller' do it_behaves_like 'Value Stream Analytics Stages controller' do
before do before do
stub_feature_flags(use_vsa_aggregated_tables: false) stub_feature_flags(use_vsa_aggregated_tables: false)
...@@ -32,14 +28,7 @@ RSpec.describe Groups::Analytics::CycleAnalytics::StagesController do ...@@ -32,14 +28,7 @@ RSpec.describe Groups::Analytics::CycleAnalytics::StagesController do
end end
context 'when params have group_id and value_stream_id' do context 'when params have group_id and value_stream_id' do
let_it_be(:stages) do let_it_be(:value_stream) { create(:cycle_analytics_group_value_stream, group: group) }
[
create(:cycle_analytics_group_stage, group: group, name: "Issue", relative_position: 1),
create(:cycle_analytics_group_stage, group: group, name: "Code", relative_position: 2)
]
end
let_it_be(:value_stream) { create(:cycle_analytics_group_value_stream, group: group, name: 'First value stream', stages: stages) }
let(:params) { { group_id: group, value_stream_id: value_stream.id } } let(:params) { { group_id: group, value_stream_id: value_stream.id } }
let(:parent) { group } let(:parent) { group }
......
...@@ -16,34 +16,14 @@ RSpec.describe Groups::Analytics::CycleAnalytics::ValueStreamsController do ...@@ -16,34 +16,14 @@ RSpec.describe Groups::Analytics::CycleAnalytics::ValueStreamsController do
end end
describe 'GET #index' do describe 'GET #index' do
context 'when the use_vsa_aggregated_tables feature flag is off' do it 'returns an in-memory default value stream' do
before do get :index, params: params
stub_feature_flags(use_vsa_aggregated_tables: false)
end
it 'returns an in-memory default value stream' do
get :index, params: params
expect(response).to have_gitlab_http_status(:ok)
expect(json_response.size).to eq(1)
expect(json_response.first['id']).to eq(Analytics::CycleAnalytics::Stages::BaseService::DEFAULT_VALUE_STREAM_NAME)
expect(json_response.first['name']).to eq(Analytics::CycleAnalytics::Stages::BaseService::DEFAULT_VALUE_STREAM_NAME)
end
end
context 'when the use_vsa_aggregated_tables feature flag is on' do
before do
stub_feature_flags(use_vsa_aggregated_tables: true)
end
it 'returns an empty array' do expect(response).to have_gitlab_http_status(:ok)
get :index, params: params
expect(response).to have_gitlab_http_status(:ok) expect(json_response.size).to eq(1)
expect(json_response.first['id']).to eq(Analytics::CycleAnalytics::Stages::BaseService::DEFAULT_VALUE_STREAM_NAME)
expect(json_response.size).to eq(0) expect(json_response.first['name']).to eq(Analytics::CycleAnalytics::Stages::BaseService::DEFAULT_VALUE_STREAM_NAME)
end
end end
context 'when persisted value streams present' do context 'when persisted value streams present' do
......
...@@ -6,18 +6,11 @@ RSpec.describe 'Value stream analytics charts', :js do ...@@ -6,18 +6,11 @@ RSpec.describe 'Value stream analytics charts', :js do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group, name: 'CA-test-group') } let_it_be(:group) { create(:group, name: 'CA-test-group') }
let_it_be(:group2) { create(:group, name: 'CA-bad-test-group') }
let_it_be(:project) { create(:project, :repository, namespace: group, group: group, name: 'Cool fun project') } let_it_be(:project) { create(:project, :repository, namespace: group, group: group, name: 'Cool fun project') }
let_it_be(:group_with_value_stream) { create(:group, name: 'CA-vsa-test-group') } let_it_be(:group_label1) { create(:group_label, group: group) }
let_it_be(:vsa_group_project) { create(:project, :repository, namespace: group_with_value_stream, group: group_with_value_stream) } let_it_be(:group_label2) { create(:group_label, group: group) }
let_it_be(:value_stream) { create(:cycle_analytics_group_value_stream, group: group_with_value_stream, name: 'First value stream') } let_it_be(:label) { create(:group_label, group: group2) }
let_it_be(:vsa_stages) do
[
create(:cycle_analytics_group_stage, group: group_with_value_stream, name: "Issue", relative_position: 1, value_stream: value_stream),
create(:cycle_analytics_group_stage, group: group_with_value_stream, name: "Code", relative_position: 2, value_stream: value_stream)
]
end
empty_state_selector = '[data-testid="vsa-empty-state"]'
3.times do |i| 3.times do |i|
let_it_be("issue_#{i}".to_sym) { create(:issue, title: "New Issue #{i}", project: project, created_at: 2.days.ago) } let_it_be("issue_#{i}".to_sym) { create(:issue, title: "New Issue #{i}", project: project, created_at: 2.days.ago) }
...@@ -31,7 +24,6 @@ RSpec.describe 'Value stream analytics charts', :js do ...@@ -31,7 +24,6 @@ RSpec.describe 'Value stream analytics charts', :js do
before_all do before_all do
group.add_owner(user) group.add_owner(user)
group_with_value_stream.add_owner(user)
end end
before do before do
...@@ -40,14 +32,15 @@ RSpec.describe 'Value stream analytics charts', :js do ...@@ -40,14 +32,15 @@ RSpec.describe 'Value stream analytics charts', :js do
sign_in(user) sign_in(user)
end end
shared_examples 'has the empty state' do context 'Duration chart' do
it 'renders the empty state' do let(:custom_value_stream_name) { "New created value stream" }
expect(page).to have_selector(empty_state_selector)
expect(page).to have_text(s_('CycleAnalytics|Custom value streams to measure your DevSecOps lifecycle')) before do
select_group(group)
create_custom_value_stream(custom_value_stream_name)
end end
end
shared_examples 'has the duration chart' do
it 'displays data for all stages on the overview' do it 'displays data for all stages on the overview' do
page.within('[data-testid="vsa-path-navigation"]') do page.within('[data-testid="vsa-path-navigation"]') do
click_button "Overview" click_button "Overview"
...@@ -65,134 +58,73 @@ RSpec.describe 'Value stream analytics charts', :js do ...@@ -65,134 +58,73 @@ RSpec.describe 'Value stream analytics charts', :js do
end end
end end
shared_examples 'has the tasks by type chart' do describe 'Tasks by type chart', :js do
context 'with data available' do filters_selector = '.js-tasks-by-type-chart-filters'
filters_selector = '.js-tasks-by-type-chart-filters'
before do
group_label1 = create(:group_label, group: selected_group)
group_label2 = create(:group_label, group: selected_group)
mr_issue = create(:labeled_issue, created_at: 5.days.ago, project: create(:project, group: selected_group), labels: [group_label2])
create(:merge_request, iid: mr_issue.id, created_at: 3.days.ago, source_project: selected_project, labels: [group_label1, group_label2])
3.times do |i|
create(:labeled_issue, created_at: i.days.ago, project: create(:project, group: selected_group), labels: [group_label1])
create(:labeled_issue, created_at: i.days.ago, project: create(:project, group: selected_group), labels: [group_label2])
end
select_group(selected_group) before do
end stub_licensed_features(cycle_analytics_for_groups: true, type_of_work_analytics: true)
it 'displays the chart' do project.add_maintainer(user)
expect(page).to have_text(s_('CycleAnalytics|Type of work'))
expect(page).to have_text(s_('CycleAnalytics|Tasks by type')) sign_in(user)
end end
it 'has 2 labels selected' do context 'enabled' do
expect(page).to have_text('Showing Issues and 2 labels') context 'with data available' do
end before do
mr_issue = create(:labeled_issue, created_at: 5.days.ago, project: create(:project, group: group), labels: [group_label2])
create(:merge_request, iid: mr_issue.id, created_at: 3.days.ago, source_project: project, labels: [group_label1, group_label2])
it 'has chart filters' do 3.times do |i|
expect(page).to have_css(filters_selector) create(:labeled_issue, created_at: i.days.ago, project: create(:project, group: group), labels: [group_label1])
end create(:labeled_issue, created_at: i.days.ago, project: create(:project, group: group), labels: [group_label2])
end
it 'can update the filters' do select_group(group)
page.within filters_selector do
find('.dropdown-toggle').click
first_selected_label = all('[data-testid="type-of-work-filters-label"] .dropdown-item.active').first
first_selected_label.click
end end
expect(page).to have_text('Showing Issues and 1 label') it 'displays the chart' do
expect(page).to have_text(s_('CycleAnalytics|Type of work'))
page.within filters_selector do expect(page).to have_text(s_('CycleAnalytics|Tasks by type'))
find('.dropdown-toggle').click
find('[data-testid="type-of-work-filters-subject"] label', text: 'Merge Requests').click
end end
expect(page).to have_text('Showing Merge Requests and 1 label') it 'has 2 labels selected' do
end expect(page).to have_text('Showing Issues and 2 labels')
end
context 'no data available' do
before do
select_group(selected_group)
end
it 'shows the no data available message' do
expect(page).to have_text(s_('CycleAnalytics|Type of work'))
expect(page).to have_text(_('There is no data available. Please change your selection.'))
end
end
end
describe 'Duration chart', :js do
context 'use_vsa_aggregated_tables feature flag off' do
before do
stub_feature_flags(use_vsa_aggregated_tables: false)
select_group(group)
end
it_behaves_like 'has the duration chart'
end
context 'use_vsa_aggregated_tables feature flag on' do
context 'with no value streams' do
before do
select_group(group, empty_state_selector)
end end
it_behaves_like 'has the empty state' it 'has chart filters' do
end expect(page).to have_css(filters_selector)
context 'with a value stream' do
before do
select_group(group_with_value_stream)
end end
it_behaves_like 'has the duration chart' it 'can update the filters' do
end page.within filters_selector do
end find('.dropdown-toggle').click
end first_selected_label = all('[data-testid="type-of-work-filters-label"] .dropdown-item.active').first
first_selected_label.click
describe 'Tasks by type chart', :js do end
before do
stub_licensed_features(cycle_analytics_for_groups: true, type_of_work_analytics: true)
project.add_maintainer(user) expect(page).to have_text('Showing Issues and 1 label')
sign_in(user)
end
context 'use_vsa_aggregated_tables feature flag off' do page.within filters_selector do
let(:selected_group) { group } find('.dropdown-toggle').click
let(:selected_project) { project } find('[data-testid="type-of-work-filters-subject"] label', text: 'Merge Requests').click
end
before do expect(page).to have_text('Showing Merge Requests and 1 label')
stub_feature_flags(use_vsa_aggregated_tables: false) end
end end
it_behaves_like 'has the tasks by type chart' context 'no data available' do
end
context 'use_vsa_aggregated_tables feature flag on' do
context 'with no value streams' do
before do before do
select_group(group, empty_state_selector) select_group(group)
end end
it_behaves_like 'has the empty state' it 'shows the no data available message' do
end expect(page).to have_text(s_('CycleAnalytics|Type of work'))
context 'with a value stream' do
let(:selected_group) { group_with_value_stream }
let(:selected_project) { vsa_group_project }
it_behaves_like 'has the tasks by type chart' expect(page).to have_text(_('There is no data available. Please change your selection.'))
end
end end
end end
end end
......
...@@ -20,8 +20,6 @@ RSpec.describe 'Group value stream analytics filters and data', :js do ...@@ -20,8 +20,6 @@ RSpec.describe 'Group value stream analytics filters and data', :js do
path_nav_selector = '[data-testid="vsa-path-navigation"]' path_nav_selector = '[data-testid="vsa-path-navigation"]'
filter_bar_selector = '[data-testid="vsa-filter-bar"]' filter_bar_selector = '[data-testid="vsa-filter-bar"]'
card_metric_selector = '[data-testid="vsa-metrics"] .gl-single-stat' card_metric_selector = '[data-testid="vsa-metrics"] .gl-single-stat'
empty_state_selector = '[data-testid="vsa-empty-state"]'
empty_stage_state_selector = '.empty-state'
new_issues_count = 3 new_issues_count = 3
new_issues_count.times do |i| new_issues_count.times do |i|
...@@ -59,9 +57,9 @@ RSpec.describe 'Group value stream analytics filters and data', :js do ...@@ -59,9 +57,9 @@ RSpec.describe 'Group value stream analytics filters and data', :js do
sign_in(user) sign_in(user)
end end
shared_examples 'empty value stream stage' do shared_examples 'empty state' do
it 'displays an empty state' do it 'displays an empty state' do
element = page.find(empty_stage_state_selector) element = page.find('.empty-state')
expect(element).to have_content(_("We don't have enough data to show this stage.")) expect(element).to have_content(_("We don't have enough data to show this stage."))
expect(element.find('.svg-content img')['src']).to have_content('illustrations/analytics/cycle-analytics-empty-chart') expect(element.find('.svg-content img')['src']).to have_content('illustrations/analytics/cycle-analytics-empty-chart')
...@@ -172,219 +170,176 @@ RSpec.describe 'Group value stream analytics filters and data', :js do ...@@ -172,219 +170,176 @@ RSpec.describe 'Group value stream analytics filters and data', :js do
end end
end end
context 'use_vsa_aggregated_tables feature flag off' do context 'without valid query parameters set' do
before do context 'with created_after date > created_before date' do
stub_feature_flags(use_vsa_aggregated_tables: false)
select_group(group)
end
it 'does not render the VSA empty state' do
expect(page).not_to have_selector(empty_state_selector)
expect(page).not_to have_text(s_('CycleAnalytics|Custom value streams to measure your DevSecOps lifecycle'))
end
end
context 'use_vsa_aggregated_tables feature flag on' do
context 'without a value stream' do
before do before do
select_group(group, empty_state_selector) visit "#{group_analytics_cycle_analytics_path(group)}?created_after=2019-12-31&created_before=2019-11-01"
end end
it 'renders the empty value stream state' do it_behaves_like 'no group available'
expect(page).to have_text(s_('CycleAnalytics|Custom value streams to measure your DevSecOps lifecycle'))
end
end end
context 'with a value stream' do context 'with fake parameters' do
before do before do
value_stream = create(:cycle_analytics_group_value_stream, group: group, name: 'First value stream') visit "#{group_analytics_cycle_analytics_path(group)}?beans=not-cool"
sub_value_stream = create(:cycle_analytics_group_value_stream, group: sub_group, name: 'First sub group value stream')
Gitlab::Analytics::CycleAnalytics::DefaultStages.all.map do |stage_params| select_stage("Issue")
group.cycle_analytics_stages.create!(stage_params.merge(value_stream: value_stream))
sub_group.cycle_analytics_stages.create!(stage_params.merge(value_stream: sub_value_stream))
end
end end
context 'without valid query parameters set' do it_behaves_like 'empty state'
context 'with created_after date > created_before date' do end
before do end
visit "#{group_analytics_cycle_analytics_path(group)}?created_after=2019-12-31&created_before=2019-11-01"
end
it_behaves_like 'no group available'
end
context 'with fake parameters' do
before do
visit "#{group_analytics_cycle_analytics_path(group)}?beans=not-cool"
select_stage("Issue") context 'with valid query parameters set' do
end projects_dropdown = '.js-projects-dropdown-filter'
it_behaves_like 'empty value stream stage' context 'with project_ids set' do
end before do
visit "#{group_analytics_cycle_analytics_path(group)}?project_ids[]=#{project.id}"
end end
context 'with valid query parameters set' do it 'has the projects dropdown prepopulated' do
projects_dropdown = '.js-projects-dropdown-filter' element = page.find(projects_dropdown)
context 'with project_ids set' do
before do
visit "#{group_analytics_cycle_analytics_path(group)}?project_ids[]=#{project.id}"
end
it 'has the projects dropdown prepopulated' do
element = page.find(projects_dropdown)
expect(element).to have_content project.name
end
end
context 'with created_before and created_after set' do
let(:created_after) { '2019-11-01' }
let(:created_before) { '2019-12-31' }
date_range = '.js-daterange-picker' expect(element).to have_content project.name
end
end
before do context 'with created_before and created_after set' do
visit "#{group_analytics_cycle_analytics_path(group)}?created_before=#{created_before}&created_after=#{created_after}" date_range = '.js-daterange-picker'
end
it 'has the date range prepopulated' do before do
element = page.find(date_range) visit "#{group_analytics_cycle_analytics_path(group)}?created_before=2019-12-31&created_after=2019-11-01"
end
expect(element.find('.js-daterange-picker-from input').value).to eq created_after it 'has the date range prepopulated' do
expect(element.find('.js-daterange-picker-to input').value).to eq created_before element = page.find(date_range)
expect(page.find('.js-tasks-by-type-chart')).to have_text(_("Showing data for group '%{group_name}' from Nov 1, 2019 to Dec 31, 2019") % { group_name: group.name }) expect(element.find('.js-daterange-picker-from input').value).to eq '2019-11-01'
end expect(element.find('.js-daterange-picker-to input').value).to eq '2019-12-31'
end expect(page.find('.js-tasks-by-type-chart')).to have_text(_("Showing data for group '%{group_name}' from Nov 1, 2019 to Dec 31, 2019") % { group_name: group.name })
end end
end
end
context 'with a group' do context 'with a group' do
let(:selected_group) { group } let(:selected_group) { group }
before do before do
select_group(group) select_group(group)
end end
it_behaves_like 'group value stream analytics' it_behaves_like 'group value stream analytics'
it_behaves_like 'has overview metrics' it_behaves_like 'has overview metrics'
it_behaves_like 'has default filters' it_behaves_like 'has default filters'
end end
context 'with a sub group' do context 'with a sub group' do
let(:selected_group) { sub_group } let(:selected_group) { sub_group }
before do before do
select_group(sub_group) select_group(sub_group)
end end
it_behaves_like 'group value stream analytics' it_behaves_like 'group value stream analytics'
it_behaves_like 'has overview metrics' it_behaves_like 'has overview metrics'
it_behaves_like 'has default filters' it_behaves_like 'has default filters'
end end
context 'with lots of data', :js do context 'with lots of data', :js do
let_it_be(:issue) { create(:issue, project: project) } let_it_be(:issue) { create(:issue, project: project) }
around do |example| around do |example|
freeze_time { example.run } freeze_time { example.run }
end end
before do before do
issue.update!(created_at: 5.days.ago) stub_feature_flags(use_vsa_aggregated_tables: false)
create_cycle(user, project, issue, mr, milestone, pipeline) issue.update!(created_at: 5.days.ago)
create(:labeled_issue, created_at: 5.days.ago, project: create(:project, group: group), labels: [group_label1]) create_cycle(user, project, issue, mr, milestone, pipeline)
create(:labeled_issue, created_at: 3.days.ago, project: create(:project, group: group), labels: [group_label2]) create(:labeled_issue, created_at: 5.days.ago, project: create(:project, group: group), labels: [group_label1])
create(:labeled_issue, created_at: 3.days.ago, project: create(:project, group: group), labels: [group_label2])
issue.metrics.update!(first_mentioned_in_commit_at: mr.created_at - 5.hours) issue.metrics.update!(first_mentioned_in_commit_at: mr.created_at - 5.hours)
mr.metrics.update!(first_deployed_to_production_at: mr.created_at + 2.hours, merged_at: mr.created_at + 1.hour) mr.metrics.update!(first_deployed_to_production_at: mr.created_at + 2.hours, merged_at: mr.created_at + 1.hour)
deploy_master(user, project, environment: 'staging') deploy_master(user, project, environment: 'staging')
deploy_master(user, project) deploy_master(user, project)
aggregation = Analytics::CycleAnalytics::Aggregation.safe_create_for_group(group) select_group(group)
Analytics::CycleAnalytics::AggregatorService.new(aggregation: aggregation).execute end
select_group(group) stages_with_data = [
end { title: 'Issue', description: 'Time before an issue gets scheduled', events_count: 1, time: '5d' },
{ title: 'Code', description: 'Time until first merge request', events_count: 1, time: '5h' },
{ title: 'Review', description: 'Time between merge request creation and merge/close', events_count: 1, time: '1h' },
{ title: 'Staging', description: 'From merge request merge until deploy to production', events_count: 1, time: '1h' }
]
stages_without_data = [
{ title: 'Plan', description: 'Time before an issue starts implementation', events_count: 0, time: "-" },
{ title: 'Test', description: 'Total test time for all commits/merges', events_count: 0, time: "-" }
]
it 'each stage with events will display the stage events list when selected', :sidekiq_might_not_need_inline do
stages_without_data.each do |stage|
select_stage(stage[:title])
expect(page).not_to have_selector('[data-testid="vsa-stage-event"]')
end
stages_with_data = [ stages_with_data.each do |stage|
{ title: 'Issue', description: 'Time before an issue gets scheduled', events_count: 1, time: '5d' }, select_stage(stage[:title])
{ title: 'Code', description: 'Time until first merge request', events_count: 1, time: '5h' }, expect(page).to have_selector('[data-testid="vsa-stage-table"]')
{ title: 'Review', description: 'Time between merge request creation and merge/close', events_count: 1, time: '1h' }, expect(page.all('[data-testid="vsa-stage-event"]').length).to eq(stage[:events_count])
{ title: 'Staging', description: 'From merge request merge until deploy to production', events_count: 1, time: '1h' } end
] end
stages_without_data = [
{ title: 'Plan', description: 'Time before an issue starts implementation', events_count: 0, time: "-" },
{ title: 'Test', description: 'Total test time for all commits/merges', events_count: 0, time: "-" }
]
it 'each stage with events will display the stage events list when selected', :sidekiq_might_not_need_inline do
stages_without_data.each do |stage|
select_stage(stage[:title])
expect(page).not_to have_selector('[data-testid="vsa-stage-event"]')
end
stages_with_data.each do |stage|
select_stage(stage[:title])
expect(page).to have_selector('[data-testid="vsa-stage-table"]')
expect(page.all('[data-testid="vsa-stage-event"]').length).to eq(stage[:events_count])
end
end
it 'each stage will be selectable' do it 'each stage will be selectable' do
[].concat(stages_without_data, stages_with_data).each do |stage| [].concat(stages_without_data, stages_with_data).each do |stage|
select_stage(stage[:title]) select_stage(stage[:title])
stage_name = page.find("#{path_nav_selector} .gl-path-active-item-indigo").text stage_name = page.find("#{path_nav_selector} .gl-path-active-item-indigo").text
expect(stage_name).to include(stage[:title]) expect(stage_name).to include(stage[:title])
expect(stage_name).to include(stage[:time]) expect(stage_name).to include(stage[:time])
expect(page).to have_selector('[data-testid="vsa-duration-chart"]') expect(page).to have_selector('[data-testid="vsa-duration-chart"]')
end end
end end
it 'will not display the stage table on the overview stage' do it 'will not display the stage table on the overview stage' do
expect(page).not_to have_selector('[data-testid="vsa-stage-table"]') expect(page).not_to have_selector('[data-testid="vsa-stage-table"]')
select_stage("Issue") select_stage("Issue")
expect(page).to have_selector('[data-testid="vsa-stage-table"]') expect(page).to have_selector('[data-testid="vsa-stage-table"]')
end end
it 'will have data available' do it 'will have data available' do
duration_chart_content = page.find('[data-testid="vsa-duration-chart"]') duration_chart_content = page.find('[data-testid="vsa-duration-chart"]')
expect(duration_chart_content).not_to have_text(_("There is no data available. Please change your selection.")) expect(duration_chart_content).not_to have_text(_("There is no data available. Please change your selection."))
expect(duration_chart_content).to have_text(s_('CycleAnalytics|Average time to completion')) expect(duration_chart_content).to have_text(s_('CycleAnalytics|Average time to completion'))
tasks_by_type_chart_content = page.find('.js-tasks-by-type-chart') tasks_by_type_chart_content = page.find('.js-tasks-by-type-chart')
expect(tasks_by_type_chart_content).not_to have_text(_("There is no data available. Please change your selection.")) expect(tasks_by_type_chart_content).not_to have_text(_("There is no data available. Please change your selection."))
end end
context 'with filters applied' do context 'with filters applied' do
before do before do
visit "#{group_analytics_cycle_analytics_path(group)}?created_before=2019-12-31&created_after=2019-11-01" visit "#{group_analytics_cycle_analytics_path(group)}?created_before=2019-12-31&created_after=2019-11-01"
wait_for_stages_to_load wait_for_stages_to_load
end end
it 'will filter the data' do it 'will filter the data' do
duration_chart_content = page.find('[data-testid="vsa-duration-chart"]') duration_chart_content = page.find('[data-testid="vsa-duration-chart"]')
expect(duration_chart_content).not_to have_text(s_('CycleAnalytics|Average time to completion')) expect(duration_chart_content).not_to have_text(s_('CycleAnalytics|Average time to completion'))
expect(duration_chart_content).to have_text(s_("CycleAnalytics|There is no data for 'Total time' available. Adjust the current filters.")) expect(duration_chart_content).to have_text(s_("CycleAnalytics|There is no data for 'Total time' available. Adjust the current filters."))
tasks_by_type_chart_content = page.find('.js-tasks-by-type-chart') tasks_by_type_chart_content = page.find('.js-tasks-by-type-chart')
expect(tasks_by_type_chart_content).to have_text(_("There is no data available. Please change your selection.")) expect(tasks_by_type_chart_content).to have_text(_("There is no data available. Please change your selection."))
end
end
end end
end end
end end
......
...@@ -18,7 +18,7 @@ RSpec.describe 'Multiple value streams', :js do ...@@ -18,7 +18,7 @@ RSpec.describe 'Multiple value streams', :js do
let(:extended_form_fields_selector) { '[data-testid="extended-form-fields"]' } let(:extended_form_fields_selector) { '[data-testid="extended-form-fields"]' }
let(:preset_selector) { '[data-testid="vsa-preset-selector"]' } let(:preset_selector) { '[data-testid="vsa-preset-selector"]' }
let(:empty_state_selector) { '[data-testid="vsa-empty-state"]' } let!(:default_value_stream) { create(:cycle_analytics_group_value_stream, group: group, name: 'default') }
3.times do |i| 3.times do |i|
let_it_be("issue_#{i}".to_sym) { create(:issue, title: "New Issue #{i}", project: project, created_at: 2.days.ago) } let_it_be("issue_#{i}".to_sym) { create(:issue, title: "New Issue #{i}", project: project, created_at: 2.days.ago) }
...@@ -198,7 +198,7 @@ RSpec.describe 'Multiple value streams', :js do ...@@ -198,7 +198,7 @@ RSpec.describe 'Multiple value streams', :js do
end end
end end
shared_examples 'create group value streams' do describe 'With a group' do
name = 'group value stream' name = 'group value stream'
before do before do
...@@ -210,7 +210,7 @@ RSpec.describe 'Multiple value streams', :js do ...@@ -210,7 +210,7 @@ RSpec.describe 'Multiple value streams', :js do
it_behaves_like 'delete a value stream', name it_behaves_like 'delete a value stream', name
end end
shared_examples 'create sub group value streams' do describe 'With a sub group' do
name = 'sub group value stream' name = 'sub group value stream'
before do before do
...@@ -221,42 +221,4 @@ RSpec.describe 'Multiple value streams', :js do ...@@ -221,42 +221,4 @@ RSpec.describe 'Multiple value streams', :js do
it_behaves_like 'update a value stream', name it_behaves_like 'update a value stream', name
it_behaves_like 'delete a value stream', name it_behaves_like 'delete a value stream', name
end end
context 'use_vsa_aggregated_tables feature flag off' do
before do
stub_feature_flags(use_vsa_aggregated_tables: false)
end
it_behaves_like 'create group value streams'
it_behaves_like 'create sub group value streams'
end
context 'use_vsa_aggregated_tables feature flag on' do
context 'without a value stream' do
before do
select_group(group, empty_state_selector)
end
it 'renders the empty state' do
expect(page).to have_text(s_('CycleAnalytics|Custom value streams to measure your DevSecOps lifecycle'))
end
it 'can navigate to the create value stream form' do
page.find('[data-testid="create-value-stream-button"]').click
expect(page).to have_selector('[data-testid="value-stream-form-modal"]')
end
end
context 'with a value stream' do
before do
# ensure we have a value stream already available
create(:cycle_analytics_group_value_stream, group: group, name: 'default')
create(:cycle_analytics_group_value_stream, group: sub_group, name: 'default')
end
it_behaves_like 'create group value streams'
it_behaves_like 'create sub group value streams'
end
end
end end
...@@ -9,7 +9,6 @@ import DurationChart from 'ee/analytics/cycle_analytics/components/duration_char ...@@ -9,7 +9,6 @@ import DurationChart from 'ee/analytics/cycle_analytics/components/duration_char
import TypeOfWorkCharts from 'ee/analytics/cycle_analytics/components/type_of_work_charts.vue'; import TypeOfWorkCharts from 'ee/analytics/cycle_analytics/components/type_of_work_charts.vue';
import ValueStreamSelect from 'ee/analytics/cycle_analytics/components/value_stream_select.vue'; import ValueStreamSelect from 'ee/analytics/cycle_analytics/components/value_stream_select.vue';
import ValueStreamAggregationStatus from 'ee/analytics/cycle_analytics/components/value_stream_aggregation_status.vue'; import ValueStreamAggregationStatus from 'ee/analytics/cycle_analytics/components/value_stream_aggregation_status.vue';
import ValueStreamEmptyState from 'ee/analytics/cycle_analytics/components/value_stream_empty_state.vue';
import createStore from 'ee/analytics/cycle_analytics/store'; import createStore from 'ee/analytics/cycle_analytics/store';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
import { import {
...@@ -196,12 +195,11 @@ describe('EE Value Stream Analytics component', () => { ...@@ -196,12 +195,11 @@ describe('EE Value Stream Analytics component', () => {
expect(wrapper.findComponent(ValueStreamSelect).exists()).toBe(flag); expect(wrapper.findComponent(ValueStreamSelect).exists()).toBe(flag);
}; };
describe('with no value streams', () => { describe('without a group', () => {
beforeEach(async () => { beforeEach(async () => {
const { group, ...stateWithoutGroup } = initialCycleAnalyticsState;
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
wrapper = await createComponent({ wrapper = await createComponent({ initialState: stateWithoutGroup });
initialState: { ...initialCycleAnalyticsState, valueStreams: [] },
});
}); });
afterEach(() => { afterEach(() => {
...@@ -211,10 +209,10 @@ describe('EE Value Stream Analytics component', () => { ...@@ -211,10 +209,10 @@ describe('EE Value Stream Analytics component', () => {
}); });
it('displays an empty state', () => { it('displays an empty state', () => {
const emptyState = wrapper.findComponent(ValueStreamEmptyState); const emptyState = wrapper.findComponent(GlEmptyState);
expect(emptyState.exists()).toBe(true); expect(emptyState.exists()).toBe(true);
expect(emptyState.props('emptyStateSvgPath')).toBe(emptyStateSvgPath); expect(emptyState.props('svgPath')).toBe(emptyStateSvgPath);
}); });
it('does not display the metrics cards', () => { it('does not display the metrics cards', () => {
......
...@@ -21,24 +21,8 @@ RSpec.describe Analytics::CycleAnalytics::Stages::ListService do ...@@ -21,24 +21,8 @@ RSpec.describe Analytics::CycleAnalytics::Stages::ListService do
it_behaves_like 'permission check for Value Stream Analytics Stage services', :cycle_analytics_for_groups it_behaves_like 'permission check for Value Stream Analytics Stage services', :cycle_analytics_for_groups
context 'when the use_vsa_aggregated_tables feature is enabled' do it 'returns only the default stages' do
before do expect(stages.size).to eq(Gitlab::Analytics::CycleAnalytics::DefaultStages.all.size)
stub_feature_flags(use_vsa_aggregated_tables: true)
end
it 'returns empty array' do
expect(stages.size).to eq(0)
end
end
context 'when the use_vsa_aggregated_tables feature is disabled' do
before do
stub_feature_flags(use_vsa_aggregated_tables: false)
end
it 'returns the default stages' do
expect(stages.size).to eq(Gitlab::Analytics::CycleAnalytics::DefaultStages.all.size)
end
end end
it 'provides the default stages as non-persisted objects' do it 'provides the default stages as non-persisted objects' do
......
...@@ -22,7 +22,7 @@ RSpec.shared_examples 'Value Stream Analytics Stages controller' do ...@@ -22,7 +22,7 @@ RSpec.shared_examples 'Value Stream Analytics Stages controller' do
subject subject
response_start_events = json_response['stages'].map { |s| s['start_event_identifier'] } response_start_events = json_response['stages'].map { |s| s['start_event_identifier'] }
start_events = stages.map { |s| s['start_event_identifier'] } start_events = Gitlab::Analytics::CycleAnalytics::DefaultStages.all.map { |s| s['start_event_identifier'] }
expect(response_start_events).to eq(start_events) expect(response_start_events).to eq(start_events)
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment