Commit 6cae55a9 authored by Mike Greiling's avatar Mike Greiling

Merge branch '32112-follow-up-migrate-mock-data-to-fixture-spec' into 'master'

Resolve "Follow up - Migrate mock data to fixture spec"

Closes #32112

See merge request gitlab-org/gitlab!17727
parents a296b9b4 85e2d719
import Vue from 'vue';
import { mount } from '@vue/test-utils';
import CustomStageForm from 'ee/analytics/cycle_analytics/components/custom_stage_form.vue';
import { apiResponse, groupLabels } from '../mock_data';
const { events } = apiResponse;
const startEvents = events.filter(ev => ev.canBeStartEvent);
const stopEvents = events.filter(ev => !ev.canBeStartEvent);
import {
groupLabels,
customStageEvents as events,
labelStartEvent,
labelStopEvent,
customStageStartEvents as startEvents,
customStageStopEvents as stopEvents,
} from '../mock_data';
const initData = {
name: 'Cool stage pre',
startEvent: 'issue_label_added',
startEvent: labelStartEvent.identifier,
startEventLabel: groupLabels[0].id,
stopEvent: 'issue_label_removed',
stopEvent: labelStopEvent.identifier,
stopEventLabel: groupLabels[1].id,
};
......@@ -129,7 +131,7 @@ describe('CustomStageForm', () => {
it('will display the start event label field if a label event is selected', done => {
wrapper.setData({
fields: {
startEvent: 'issue_label_added',
startEvent: labelStartEvent.identifier,
},
});
......@@ -143,7 +145,7 @@ describe('CustomStageForm', () => {
const selectedLabelId = groupLabels[0].id;
expect(wrapper.vm.fields.startEventLabel).toEqual(null);
wrapper.find(sel.startEvent).setValue('issue_label_added');
wrapper.find(sel.startEvent).setValue(labelStartEvent.identifier);
Vue.nextTick(() => {
wrapper
.find(sel.startEventLabel)
......@@ -162,12 +164,7 @@ describe('CustomStageForm', () => {
describe('Stop event', () => {
beforeEach(() => {
wrapper = createComponent(
{
events,
},
false,
);
wrapper = createComponent({}, false);
});
it('notifies that a start event needs to be selected first', () => {
......@@ -208,17 +205,24 @@ describe('CustomStageForm', () => {
it('will only display valid stop events allowed for the selected start event', done => {
let stopOptions = wrapper.find(sel.stopEvent).findAll('option');
const index = 2;
const selectedStopEventIdentifer = startEvents[index].allowedEndEvents[0];
const selectedStopEvent = stopEvents.find(
ev => ev.identifier === selectedStopEventIdentifer,
);
expect(stopOptions.at(0).html()).toEqual('<option value="">Select stop event</option>');
selectDropdownOption(wrapper, sel.startEvent, 1);
selectDropdownOption(wrapper, sel.startEvent, index);
Vue.nextTick(() => {
stopOptions = wrapper.find(sel.stopEvent).findAll('option');
[
{ name: 'Select stop event', identifier: '' },
{
name: 'Issue first associated with a milestone or issue first added to a board',
identifier: 'issue_stage_end',
name: selectedStopEvent.name,
identifier: selectedStopEvent.identifier,
},
].forEach(({ name, identifier }, i) => {
expect(stopOptions.at(i).html()).toEqual(
......@@ -307,8 +311,8 @@ describe('CustomStageForm', () => {
wrapper.setData({
fields: {
startEvent: 'issue_label_added',
stopEvent: 'issue_label_removed',
stopEvent: labelStopEvent.identifier,
startEvent: labelStartEvent.identifier,
},
});
......@@ -324,8 +328,8 @@ describe('CustomStageForm', () => {
wrapper.setData({
fields: {
startEvent: 'issue_label_added',
stopEvent: 'issue_label_removed',
startEvent: labelStartEvent.identifier,
stopEvent: labelStopEvent.identifier,
},
});
......@@ -373,10 +377,16 @@ describe('CustomStageForm', () => {
});
describe('with all fields set', () => {
const startEventIndex = 2;
const firstStopEventIdentifier = startEvents[startEventIndex].allowedEndEvents[0];
const stopEventIndex = stopEvents.findIndex(
ev => ev.identifier === firstStopEventIdentifier,
);
beforeEach(() => {
wrapper = createComponent({}, false);
selectDropdownOption(wrapper, sel.startEvent, 1);
selectDropdownOption(wrapper, sel.startEvent, startEventIndex);
return Vue.nextTick(() => {
selectDropdownOption(wrapper, sel.stopEvent, 1);
......@@ -402,9 +412,9 @@ describe('CustomStageForm', () => {
const res = [
{
name: 'Cool stage',
startEvent: 'issue_created',
startEvent: startEvents[startEventIndex].identifier,
startEventLabel: null,
stopEvent: 'issue_stage_end',
stopEvent: stopEvents[stopEventIndex].identifier,
stopEventLabel: null,
},
];
......@@ -440,8 +450,8 @@ describe('CustomStageForm', () => {
wrapper.setData({
fields: {
name: 'Cool stage pre',
startEvent: 'issue_label_added',
stopEvent: 'issue_label_removed',
startEvent: labelStartEvent.identifier,
stopEvent: labelStopEvent.identifier,
},
});
......@@ -512,8 +522,8 @@ describe('CustomStageForm', () => {
wrapper.setData({
fields: {
name: 'Cool stage pre',
startEvent: 'issue_label_added',
stopEvent: 'issue_label_removed',
startEvent: labelStartEvent.identifier,
stopEvent: labelStopEvent.identifier,
},
});
......
......@@ -55,199 +55,24 @@ export const testEvents = stageFixtures.test;
export const stagingEvents = stageFixtures.staging;
export const productionEvents = stageFixtures.production;
// NOTE: once the backend is complete, we can generate this as a JSON fixture
// https://gitlab.com/gitlab-org/gitlab/issues/32112
export const apiResponse = {
events: [
{
name: 'Issue created',
identifier: 'issue_created',
type: 'simple',
canBeStartEvent: true,
allowedEndEvents: ['issue_stage_end'],
},
{
name: 'Issue first mentioned in a commit',
identifier: 'issue_first_mentioned_in_commit',
type: 'simple',
canBeStartEvent: false,
allowedEndEvents: [],
},
{
name: 'Merge request created',
identifier: 'merge_request_created',
type: 'simple',
canBeStartEvent: true,
allowedEndEvents: ['merge_request_merged'],
},
{
name: 'Merge request first deployed to production',
identifier: 'merge_request_first_deployed_to_production',
type: 'simple',
canBeStartEvent: false,
allowedEndEvents: [],
},
{
name: 'Merge request last build finish time',
identifier: 'merge_request_last_build_finished',
type: 'simple',
canBeStartEvent: false,
allowedEndEvents: [],
},
{
name: 'Merge request last build start time',
identifier: 'merge_request_last_build_started',
type: 'simple',
canBeStartEvent: true,
allowedEndEvents: ['merge_request_last_build_finished'],
},
{
name: 'Merge request merged',
identifier: 'merge_request_merged',
type: 'simple',
canBeStartEvent: true,
allowedEndEvents: ['merge_request_first_deployed_to_production'],
},
{
name: 'Issue first mentioned in a commit',
identifier: 'code_stage_start',
type: 'simple',
canBeStartEvent: true,
allowedEndEvents: ['merge_request_created'],
},
{
name: 'Issue first associated with a milestone or issue first added to a board',
identifier: 'issue_stage_end',
type: 'simple',
canBeStartEvent: false,
allowedEndEvents: [],
},
{
name: 'Issue first associated with a milestone or issue first added to a board',
identifier: 'plan_stage_start',
type: 'simple',
canBeStartEvent: true,
allowedEndEvents: ['issue_first_mentioned_in_commit'],
},
{
identifier: 'issue_label_added',
name: 'Issue Label Added',
type: 'label',
canBeStartEvent: true,
allowedEndEvents: ['issue_closed', 'issue_label_removed'],
},
{
identifier: 'issue_label_removed',
name: 'Issue Label Removed',
const { events: rawCustomStageEvents } = getJSONFixture('analytics/cycle_analytics/stages.json');
const camelCasedStageEvents = rawCustomStageEvents.map(deepCamelCase);
export const customStageStartEvents = camelCasedStageEvents.filter(ev => ev.canBeStartEvent);
export const customStageStopEvents = camelCasedStageEvents.filter(ev => !ev.canBeStartEvent);
// TODO: the shim below should be removed once we have label events seeding
export const labelStartEvent = { ...customStageStartEvents[0], type: 'label' };
const firstAllowedStopEvent = labelStartEvent.allowedEndEvents[0];
// We need to enusre that the stop event can be applied to the start event
export const labelStopEvent = {
...customStageStopEvents.find(ev => ev.identifier === firstAllowedStopEvent),
type: 'label',
canBeStartEvent: false,
allowedEndEvents: [],
},
],
stages: [
{
name: 'issue',
legend: 'Related Issues',
description: 'Time before an issue gets scheduled',
id: 'issue',
position: 1,
hidden: false,
custom: false,
startEventIdentifier: 'issue_created',
endEventIdentifier: 'issue_stage_end',
},
{
name: 'plan',
legend: 'Related Issues',
description: 'Time before an issue starts implementation',
id: 'plan',
position: 2,
hidden: false,
custom: false,
startEventIdentifier: 'plan_stage_start',
endEventIdentifier: 'issue_first_mentioned_in_commit',
},
{
name: 'code',
legend: 'Related Merged Requests',
description: 'Time until first merge request',
id: 'code',
position: 3,
hidden: false,
custom: false,
startEventIdentifier: 'code_stage_start',
endEventIdentifier: 'merge_request_created',
},
{
name: 'test',
legend: 'Related Merged Requests',
description: 'Total test time for all commits/merges',
id: 'test',
position: 4,
hidden: false,
custom: false,
startEventIdentifier: 'merge_request_last_build_started',
endEventIdentifier: 'merge_request_last_build_finished',
},
{
name: 'review',
legend: 'Related Merged Requests',
description: 'Time between merge request creation and merge/close',
id: 'review',
position: 5,
hidden: false,
custom: false,
startEventIdentifier: 'merge_request_created',
endEventIdentifier: 'merge_request_merged',
},
{
name: 'staging',
legend: 'Related Merged Requests',
description: 'From merge request merge until deploy to production',
id: 'staging',
position: 6,
hidden: false,
custom: false,
startEventIdentifier: 'merge_request_merged',
endEventIdentifier: 'merge_request_first_deployed_to_production',
},
{
name: 'production',
legend: 'Related Merged Requests',
description: 'From issue creation until deploy to production',
id: 'production',
position: 7,
hidden: false,
custom: false,
startEventIdentifier: 'merge_request_merged',
endEventIdentifier: 'merge_request_first_deployed_to_production',
},
],
summary: [
{
value: 2,
title: 'New Issues',
},
{
value: 0,
title: 'Commits',
},
{
value: 0,
title: 'Deploys',
},
],
permissions: {
issue: true,
plan: true,
code: true,
test: true,
review: true,
staging: true,
production: true,
},
};
export default {
apiResponse,
};
export const customStageEvents = [
...customStageStartEvents.filter(ev => ev.identifier !== labelStartEvent.identifier),
...customStageStopEvents.filter(ev => ev.identifier !== labelStopEvent.identifier),
labelStartEvent,
labelStopEvent,
];
......@@ -6,23 +6,24 @@ import {
eventsByIdentifier,
getLabelEventsIdentifiers,
} from 'ee/analytics/cycle_analytics/utils';
import { apiResponse } from './mock_data';
const { events } = apiResponse;
import {
customStageEvents as events,
labelStartEvent,
labelStopEvent,
customStageStartEvents as startEvents,
customStageStopEvents as stopEvents,
} from './mock_data';
const startEvent = events[0];
const endEvent = events[1];
const labelEvent = events[11];
const labelEvents = [events[10], events[11]].map(i => i.identifier);
const labelEvents = [labelStartEvent, labelStopEvent].map(i => i.identifier);
describe('Cycle analytics utils', () => {
describe('isStartEvent', () => {
it('will return true for a valid start event', () => {
expect(isStartEvent(startEvent)).toEqual(true);
expect(isStartEvent(startEvents[0])).toEqual(true);
});
it('will return false for input that is not a start event', () => {
[endEvent, {}, [], null, undefined].forEach(ev => {
[stopEvents[0], {}, [], null, undefined].forEach(ev => {
expect(isStartEvent(ev)).toEqual(false);
});
});
......@@ -30,10 +31,10 @@ describe('Cycle analytics utils', () => {
describe('isLabelEvent', () => {
it('will return true if the given event identifier is in the labelEvents array', () => {
expect(isLabelEvent(labelEvents, labelEvent.identifier)).toEqual(true);
expect(isLabelEvent(labelEvents, labelStartEvent.identifier)).toEqual(true);
});
it('will return false if the given event identifier is not in the labelEvents array', () => {
[startEvent.identifier, null, undefined, ''].forEach(ev => {
[startEvents[1].identifier, null, undefined, ''].forEach(ev => {
expect(isLabelEvent(labelEvents, ev)).toEqual(false);
});
expect(isLabelEvent(labelEvents)).toEqual(false);
......@@ -68,6 +69,7 @@ describe('Cycle analytics utils', () => {
expect(res.length).toEqual(labelEvents.length);
expect(res).toEqual(labelEvents);
});
it('will return an empty array when there are no matches', () => {
const ev = [{ _type: 'simple' }, { type: 'simple' }, { t: 'simple' }];
expect(getLabelEventsIdentifiers(ev)).toEqual([]);
......@@ -77,8 +79,8 @@ describe('Cycle analytics utils', () => {
describe('getAllowedEndEvents', () => {
it('will return the relevant end events for a given start event identifier', () => {
const se = events[10].allowedEndEvents;
expect(getAllowedEndEvents(events, 'issue_label_added')).toEqual(se);
const se = events[0];
expect(getAllowedEndEvents(events, se.identifier)).toEqual(se.allowedEndEvents);
});
it('will return an empty array if there are no end events available', () => {
......@@ -90,7 +92,7 @@ describe('Cycle analytics utils', () => {
describe('eventsByIdentifier', () => {
it('will return the events with an identifier in the provided array', () => {
expect(eventsByIdentifier(events, labelEvents)).toEqual([events[10], events[11]]);
expect(eventsByIdentifier(events, labelEvents)).toEqual([labelStartEvent, labelStopEvent]);
});
it('will return an empty array if there are no matching events', () => {
......
......@@ -45,7 +45,6 @@ describe 'Analytics (JavaScript fixtures)' do
end
describe Groups::CycleAnalytics::EventsController, type: :controller do
using RSpec::Parameterized::TableSyntax
render_views
before do
......@@ -87,4 +86,21 @@ describe 'Analytics (JavaScript fixtures)' do
expect(response).to be_successful
end
end
describe Analytics::CycleAnalytics::StagesController, type: :controller do
render_views
before do
stub_feature_flags(Gitlab::Analytics::CYCLE_ANALYTICS_FEATURE_FLAG => true)
stub_licensed_features(cycle_analytics_for_groups: true)
sign_in(user)
end
it 'analytics/cycle_analytics/stages.json' do
get(:index, params: { group_id: group.name }, format: :json)
expect(response).to be_successful
end
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