Commit 2c5dce71 authored by Andrew Fontaine's avatar Andrew Fontaine

Merge branch '215077-update-roadmap-app-spec-to-use-vue-test-utils' into 'master'

Update RoadmapApp spec to use vue-test-utils

See merge request gitlab-org/gitlab!31004
parents 92ccde67 9e24bc1a
import { mount, shallowMount, createLocalVue } from '@vue/test-utils';
import Vue from 'vue'; import Vue from 'vue';
import Vuex from 'vuex';
import appComponent from 'ee/roadmap/components/roadmap_app.vue'; import EpicsListEmpty from 'ee/roadmap/components/epics_list_empty.vue';
import createStore from 'ee/roadmap/store'; import RoadmapApp from 'ee/roadmap/components/roadmap_app.vue';
import RoadmapShell from 'ee/roadmap/components/roadmap_shell.vue';
import { PRESET_TYPES, EXTEND_AS } from 'ee/roadmap/constants';
import eventHub from 'ee/roadmap/event_hub'; import eventHub from 'ee/roadmap/event_hub';
import createStore from 'ee/roadmap/store';
import * as types from 'ee/roadmap/store/mutation_types';
import { getTimeframeForMonthsView } from 'ee/roadmap/utils/roadmap_utils'; import { getTimeframeForMonthsView } from 'ee/roadmap/utils/roadmap_utils';
import { PRESET_TYPES, EXTEND_AS } from 'ee/roadmap/constants';
import { mountComponentWithStore } from 'helpers/vue_mount_component_helper';
import { import {
mockTimeframeInitialDate, basePath,
epicsPath,
mockFormattedEpic,
mockGroupId, mockGroupId,
mockNewEpicEndpoint, mockNewEpicEndpoint,
rawEpics,
mockSvgPath,
mockSortedBy, mockSortedBy,
basePath, mockSvgPath,
epicsPath, mockTimeframeInitialDate,
rawEpics,
} from 'ee_jest/roadmap/mock_data'; } from 'ee_jest/roadmap/mock_data';
const mockTimeframeMonths = getTimeframeForMonthsView(mockTimeframeInitialDate); describe('RoadmapApp', () => {
const localVue = createLocalVue();
const createComponent = () => { let store;
const Component = Vue.extend(appComponent); let wrapper;
localVue.use(Vuex);
const currentGroupId = mockGroupId;
const emptyStateIllustrationPath = mockSvgPath;
const epics = [mockFormattedEpic];
const hasFiltersApplied = true;
const newEpicEndpoint = mockNewEpicEndpoint;
const presetType = PRESET_TYPES.MONTHS;
const timeframe = getTimeframeForMonthsView(mockTimeframeInitialDate);
const createComponent = (mountFunction = shallowMount) => {
return mountFunction(RoadmapApp, {
localVue,
propsData: {
emptyStateIllustrationPath,
hasFiltersApplied,
newEpicEndpoint,
presetType,
},
store,
});
};
const store = createStore(); beforeEach(() => {
store = createStore();
store.dispatch('setInitialData', { store.dispatch('setInitialData', {
currentGroupId: mockGroupId, currentGroupId,
sortedBy: mockSortedBy, sortedBy: mockSortedBy,
presetType: PRESET_TYPES.MONTHS, presetType,
timeframe: mockTimeframeMonths, timeframe,
filterQueryString: '', filterQueryString: '',
initialEpicsPath: epicsPath, initialEpicsPath: epicsPath,
basePath, basePath,
}); });
});
return mountComponentWithStore(Component, { afterEach(() => {
store, wrapper.destroy();
props: { wrapper = null;
presetType: PRESET_TYPES.MONTHS,
hasFiltersApplied: true,
newEpicEndpoint: mockNewEpicEndpoint,
emptyStateIllustrationPath: mockSvgPath,
},
}); });
};
describe('Roadmap AppComponent', () => { describe('when the app contains epics', () => {
let vm; beforeEach(() => {
wrapper = createComponent();
store.commit(types.RECEIVE_EPICS_SUCCESS, epics);
});
it('the roadmap is shown', () => {
expect(wrapper.contains(RoadmapShell)).toBe(true);
});
it('the empty state view is not shown', () => {
expect(wrapper.contains(EpicsListEmpty)).toBe(false);
});
});
describe('when the app does not contain any epics', () => {
beforeEach(() => { beforeEach(() => {
vm = createComponent(); wrapper = createComponent();
store.commit(types.RECEIVE_EPICS_SUCCESS, []);
}); });
afterEach(() => { it('the roadmap is not shown', () => {
vm.$destroy(); expect(wrapper.contains(RoadmapShell)).toBe(false);
}); });
describe('computed', () => { it('the empty state view is shown', () => {
describe('timeframeStart', () => { expect(wrapper.contains(EpicsListEmpty)).toBe(true);
it('returns first item of timeframe array', () => {
expect(vm.timeframeStart instanceof Date).toBe(true);
}); });
}); });
describe('timeframeEnd', () => { describe('empty state view', () => {
it('returns last item of timeframe array', () => { beforeEach(() => {
expect(vm.timeframeEnd instanceof Date).toBe(true); wrapper = createComponent();
store.commit(types.RECEIVE_EPICS_SUCCESS, []);
}); });
it('contains path for the empty state illustration', () => {
expect(wrapper.find(EpicsListEmpty).props('emptyStateIllustrationPath')).toBe(
emptyStateIllustrationPath,
);
}); });
describe('showRoadmap', () => { it('contains whether to apply filters', () => {
it('returns true if `windowResizeInProgress`, `epicsFetchInProgress`, `epicsFetchResultEmpty` and `epicsFetchFailure` are all `false`', () => { expect(wrapper.find(EpicsListEmpty).props('hasFiltersApplied')).toBe(hasFiltersApplied);
vm.$store.state.windowResizeInProgress = false; });
vm.$store.state.epicsFetchInProgress = false;
vm.$store.state.epicsFetchResultEmpty = false;
vm.$store.state.epicsFetchFailure = false;
expect(vm.showRoadmap).toBe(true); it('contains whether it is child epics', () => {
expect(wrapper.find(EpicsListEmpty).props('isChildEpics')).toBe(false);
}); });
it('returns false if either of `windowResizeInProgress`, `epicsFetchInProgress`, `epicsFetchResultEmpty` and `epicsFetchFailure` is `true`', () => { it('contains endpoint to create a new epic', () => {
vm.$store.state.windowResizeInProgress = true; expect(wrapper.find(EpicsListEmpty).props('newEpicEndpoint')).toBe(mockNewEpicEndpoint);
vm.$store.state.epicsFetchInProgress = false; });
vm.$store.state.epicsFetchResultEmpty = false;
vm.$store.state.epicsFetchFailure = false;
expect(vm.showRoadmap).toBe(false); it('contains the preset type', () => {
expect(wrapper.find(EpicsListEmpty).props('presetType')).toBe(presetType);
});
vm.$store.state.windowResizeInProgress = false; it('contains the start of the timeframe', () => {
vm.$store.state.epicsFetchInProgress = true; expect(wrapper.find(EpicsListEmpty).props('timeframeStart')).toStrictEqual(timeframe[0]);
vm.$store.state.epicsFetchResultEmpty = false; });
vm.$store.state.epicsFetchFailure = false;
expect(vm.showRoadmap).toBe(false); it('contains the end of the timeframe', () => {
expect(wrapper.find(EpicsListEmpty).props('timeframeEnd')).toStrictEqual(
timeframe[timeframe.length - 1],
);
});
});
vm.$store.state.windowResizeInProgress = false; describe('roadmap view', () => {
vm.$store.state.epicsFetchInProgress = false; beforeEach(() => {
vm.$store.state.epicsFetchResultEmpty = true; wrapper = createComponent();
vm.$store.state.epicsFetchFailure = false; store.commit(types.RECEIVE_EPICS_SUCCESS, epics);
});
expect(vm.showRoadmap).toBe(false); it('contains the current group id', () => {
expect(wrapper.find(RoadmapShell).props('currentGroupId')).toBe(currentGroupId);
});
vm.$store.state.windowResizeInProgress = false; it('contains epics', () => {
vm.$store.state.epicsFetchInProgress = false; expect(wrapper.find(RoadmapShell).props('epics')).toEqual(epics);
vm.$store.state.epicsFetchResultEmpty = false; });
vm.$store.state.epicsFetchFailure = true;
expect(vm.showRoadmap).toBe(false); it('contains whether filters are applied', () => {
expect(wrapper.find(RoadmapShell).props('hasFiltersApplied')).toBe(hasFiltersApplied);
}); });
it('contains milestones', () => {
expect(wrapper.find(RoadmapShell).props('milestones')).toEqual([]);
}); });
it('contains the preset type', () => {
expect(wrapper.find(RoadmapShell).props('presetType')).toBe(presetType);
}); });
describe('methods', () => { it('contains timeframe', () => {
describe('processExtendedTimeline', () => { expect(wrapper.find(RoadmapShell).props('timeframe')).toEqual(timeframe);
it('updates timeline by extending timeframe from the start when called with extendType as `prepend`', () => { });
vm.$store.dispatch('receiveEpicsSuccess', { rawEpics }); });
vm.$store.state.epicsFetchInProgress = false;
return Vue.nextTick().then(() => { describe('extending the roadmap timeline', () => {
const roadmapTimelineEl = vm.$el.querySelector('.roadmap-timeline-section'); let roadmapTimelineEl;
beforeEach(() => {
wrapper = createComponent(mount);
store.dispatch('receiveEpicsSuccess', { rawEpics });
roadmapTimelineEl = wrapper.find('.roadmap-timeline-section').element;
});
jest.spyOn(eventHub, '$emit').mockImplementation(() => {}); it('updates timeline by extending timeframe from the start when called with extendType as `prepend`', () => {
jest.spyOn(eventHub, '$emit').mockImplementation();
vm.processExtendedTimeline({ wrapper.vm.processExtendedTimeline({
extendType: EXTEND_AS.PREPEND, extendType: EXTEND_AS.PREPEND,
roadmapTimelineEl, roadmapTimelineEl,
itemsCount: 0, itemsCount: 0,
...@@ -133,85 +188,48 @@ describe('Roadmap AppComponent', () => { ...@@ -133,85 +188,48 @@ describe('Roadmap AppComponent', () => {
expect(eventHub.$emit).toHaveBeenCalledWith('refreshTimeline', expect.any(Object)); expect(eventHub.$emit).toHaveBeenCalledWith('refreshTimeline', expect.any(Object));
expect(roadmapTimelineEl.parentElement.scrollBy).toHaveBeenCalled(); expect(roadmapTimelineEl.parentElement.scrollBy).toHaveBeenCalled();
}); });
});
it('updates timeline by extending timeframe from the end when called with extendType as `append`', () => { it('updates timeline by extending timeframe from the end when called with extendType as `append`', () => {
vm.$store.dispatch('receiveEpicsSuccess', { rawEpics }); jest.spyOn(eventHub, '$emit').mockImplementation();
vm.$store.state.epicsFetchInProgress = false;
return Vue.nextTick().then(() => {
const roadmapTimelineEl = vm.$el.querySelector('.roadmap-timeline-section');
jest.spyOn(eventHub, '$emit').mockImplementation(() => {}); wrapper.vm.processExtendedTimeline({
extendType: EXTEND_AS.APPEND,
vm.processExtendedTimeline({
extendType: EXTEND_AS.PREPEND,
roadmapTimelineEl, roadmapTimelineEl,
itemsCount: 0, itemsCount: 0,
}); });
expect(eventHub.$emit).toHaveBeenCalledWith('refreshTimeline', expect.any(Object)); expect(eventHub.$emit).toHaveBeenCalledWith('refreshTimeline', expect.any(Object));
}); });
});
});
describe('handleScrollToExtend', () => {
let roadmapTimelineEl;
beforeAll(() => {
vm.$store.dispatch('receiveEpicsSuccess', { rawEpics });
vm.$store.state.epicsFetchInProgress = false;
roadmapTimelineEl = vm.$el.querySelector('.roadmap-timeline-section');
});
it('updates the store and refreshes roadmap with extended timeline based on provided extendType', () => { it('updates the store and refreshes roadmap with extended timeline based on provided extendType', () => {
jest.spyOn(vm, 'extendTimeframe').mockImplementation(() => {}); jest.spyOn(wrapper.vm, 'extendTimeframe').mockImplementation();
jest.spyOn(vm, 'refreshEpicDates').mockImplementation(() => {}); jest.spyOn(wrapper.vm, 'refreshEpicDates').mockImplementation();
jest.spyOn(vm, 'refreshMilestoneDates').mockImplementation(() => {}); jest.spyOn(wrapper.vm, 'refreshMilestoneDates').mockImplementation();
jest.spyOn(vm, 'fetchEpicsForTimeframe').mockResolvedValue(); jest.spyOn(wrapper.vm, 'fetchEpicsForTimeframe').mockResolvedValue();
const extendType = EXTEND_AS.PREPEND; const extendType = EXTEND_AS.PREPEND;
vm.handleScrollToExtend(roadmapTimelineEl, extendType); wrapper.vm.handleScrollToExtend(roadmapTimelineEl, extendType);
expect(vm.extendTimeframe).toHaveBeenCalledWith({ extendAs: extendType }); expect(wrapper.vm.extendTimeframe).toHaveBeenCalledWith({ extendAs: extendType });
expect(vm.refreshEpicDates).toHaveBeenCalled(); expect(wrapper.vm.refreshEpicDates).toHaveBeenCalled();
expect(vm.refreshMilestoneDates).toHaveBeenCalled(); expect(wrapper.vm.refreshMilestoneDates).toHaveBeenCalled();
}); });
it('calls `fetchEpicsForTimeframe` with extended timeframe array', () => { it('calls `fetchEpicsForTimeframe` with extended timeframe array', () => {
jest.spyOn(vm, 'extendTimeframe').mockImplementation(() => {}); jest.spyOn(wrapper.vm, 'fetchEpicsForTimeframe').mockResolvedValue();
jest.spyOn(vm, 'refreshEpicDates').mockImplementation(() => {});
jest.spyOn(vm, 'refreshMilestoneDates').mockImplementation(() => {});
jest.spyOn(vm, 'fetchEpicsForTimeframe').mockResolvedValue();
const extendType = EXTEND_AS.PREPEND; const extendType = EXTEND_AS.PREPEND;
vm.handleScrollToExtend(roadmapTimelineEl, extendType); wrapper.vm.handleScrollToExtend(roadmapTimelineEl, extendType);
return vm.$nextTick().then(() => { return Vue.nextTick(() => {
expect(vm.fetchEpicsForTimeframe).toHaveBeenCalledWith( expect(wrapper.vm.fetchEpicsForTimeframe).toHaveBeenCalledWith(
expect.objectContaining({ expect.objectContaining({
timeframe: vm.extendedTimeframe, timeframe: wrapper.vm.extendedTimeframe,
}), }),
); );
}); });
}); });
}); });
});
describe('template', () => {
it('renders roadmap container with class `roadmap-container`', () => {
expect(vm.$el.classList.contains('roadmap-container')).toBe(true);
});
it('renders roadmap container with classes `roadmap-container overflow-reset` when isEpicsListEmpty prop is true', () => {
vm.$store.state.epicsFetchResultEmpty = true;
return Vue.nextTick().then(() => {
expect(vm.$el.classList.contains('roadmap-container')).toBe(true);
expect(vm.$el.classList.contains('overflow-reset')).toBe(true);
});
});
});
}); });
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