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
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/vue_shared/components/color_select_dropdown')
-rw-r--r--spec/frontend/vue_shared/components/color_select_dropdown/color_item_spec.js35
-rw-r--r--spec/frontend/vue_shared/components/color_select_dropdown/color_select_root_spec.js192
-rw-r--r--spec/frontend/vue_shared/components/color_select_dropdown/dropdown_contents_color_view_spec.js43
-rw-r--r--spec/frontend/vue_shared/components/color_select_dropdown/dropdown_contents_spec.js113
-rw-r--r--spec/frontend/vue_shared/components/color_select_dropdown/dropdown_header_spec.js40
-rw-r--r--spec/frontend/vue_shared/components/color_select_dropdown/dropdown_value_spec.js46
-rw-r--r--spec/frontend/vue_shared/components/color_select_dropdown/mock_data.js30
7 files changed, 499 insertions, 0 deletions
diff --git a/spec/frontend/vue_shared/components/color_select_dropdown/color_item_spec.js b/spec/frontend/vue_shared/components/color_select_dropdown/color_item_spec.js
new file mode 100644
index 00000000000..fe614f03119
--- /dev/null
+++ b/spec/frontend/vue_shared/components/color_select_dropdown/color_item_spec.js
@@ -0,0 +1,35 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { hexToRgb } from '~/lib/utils/color_utils';
+import ColorItem from '~/vue_shared/components/color_select_dropdown/color_item.vue';
+import { color } from './mock_data';
+
+describe('ColorItem', () => {
+ let wrapper;
+
+ const propsData = color;
+
+ const createComponent = () => {
+ wrapper = shallowMountExtended(ColorItem, {
+ propsData,
+ });
+ };
+
+ const findColorItem = () => wrapper.findByTestId('color-item');
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders the correct title', () => {
+ expect(wrapper.text()).toBe(propsData.title);
+ });
+
+ it('renders the correct background color for the color item', () => {
+ const convertedColor = hexToRgb(propsData.color).join(', ');
+ expect(findColorItem().attributes('style')).toBe(`background-color: rgb(${convertedColor});`);
+ });
+});
diff --git a/spec/frontend/vue_shared/components/color_select_dropdown/color_select_root_spec.js b/spec/frontend/vue_shared/components/color_select_dropdown/color_select_root_spec.js
new file mode 100644
index 00000000000..93b59800c27
--- /dev/null
+++ b/spec/frontend/vue_shared/components/color_select_dropdown/color_select_root_spec.js
@@ -0,0 +1,192 @@
+import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import createFlash from '~/flash';
+import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue';
+import DropdownContents from '~/vue_shared/components/color_select_dropdown/dropdown_contents.vue';
+import DropdownValue from '~/vue_shared/components/color_select_dropdown/dropdown_value.vue';
+import epicColorQuery from '~/vue_shared/components/color_select_dropdown/graphql/epic_color.query.graphql';
+import updateEpicColorMutation from '~/vue_shared/components/color_select_dropdown/graphql/epic_update_color.mutation.graphql';
+import ColorSelectRoot from '~/vue_shared/components/color_select_dropdown/color_select_root.vue';
+import { DROPDOWN_VARIANT } from '~/vue_shared/components/color_select_dropdown/constants';
+import { colorQueryResponse, updateColorMutationResponse, color } from './mock_data';
+
+jest.mock('~/flash');
+
+Vue.use(VueApollo);
+
+const successfulQueryHandler = jest.fn().mockResolvedValue(colorQueryResponse);
+const successfulMutationHandler = jest.fn().mockResolvedValue(updateColorMutationResponse);
+const errorQueryHandler = jest.fn().mockRejectedValue('Error fetching epic color.');
+const errorMutationHandler = jest.fn().mockRejectedValue('An error occurred while updating color.');
+
+const defaultProps = {
+ allowEdit: true,
+ iid: '1',
+ fullPath: 'workspace-1',
+};
+
+describe('LabelsSelectRoot', () => {
+ let wrapper;
+
+ const findSidebarEditableItem = () => wrapper.findComponent(SidebarEditableItem);
+ const findDropdownValue = () => wrapper.findComponent(DropdownValue);
+ const findDropdownContents = () => wrapper.findComponent(DropdownContents);
+
+ const createComponent = ({
+ queryHandler = successfulQueryHandler,
+ mutationHandler = successfulMutationHandler,
+ propsData,
+ } = {}) => {
+ const mockApollo = createMockApollo([
+ [epicColorQuery, queryHandler],
+ [updateEpicColorMutation, mutationHandler],
+ ]);
+
+ wrapper = shallowMount(ColorSelectRoot, {
+ apolloProvider: mockApollo,
+ propsData: {
+ ...defaultProps,
+ ...propsData,
+ },
+ provide: {
+ canUpdate: true,
+ },
+ stubs: {
+ SidebarEditableItem,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('template', () => {
+ const defaultClasses = ['labels-select-wrapper', 'gl-relative'];
+
+ it.each`
+ variant | cssClass
+ ${'sidebar'} | ${defaultClasses}
+ ${'embedded'} | ${[...defaultClasses, 'is-embedded']}
+ `(
+ 'renders component root element with CSS class `$cssClass` when variant is "$variant"',
+ async ({ variant, cssClass }) => {
+ createComponent({
+ propsData: { variant },
+ });
+
+ expect(wrapper.classes()).toEqual(cssClass);
+ },
+ );
+ });
+
+ describe('if the variant is `sidebar`', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders SidebarEditableItem component', () => {
+ expect(findSidebarEditableItem().exists()).toBe(true);
+ });
+
+ it('renders correct props for the SidebarEditableItem component', () => {
+ expect(findSidebarEditableItem().props()).toMatchObject({
+ title: wrapper.vm.$options.i18n.widgetTitle,
+ canEdit: defaultProps.allowEdit,
+ loading: true,
+ });
+ });
+
+ describe('when colors are loaded', () => {
+ beforeEach(async () => {
+ createComponent();
+ await waitForPromises();
+ });
+
+ it('passes false `loading` prop to sidebar editable item', () => {
+ expect(findSidebarEditableItem().props('loading')).toBe(false);
+ });
+
+ it('renders dropdown value component when query colors is resolved', () => {
+ expect(findDropdownValue().props('selectedColor')).toMatchObject(color);
+ });
+ });
+ });
+
+ describe('if the variant is `embedded`', () => {
+ beforeEach(() => {
+ createComponent({ propsData: { iid: undefined, variant: DROPDOWN_VARIANT.Embedded } });
+ });
+
+ it('renders DropdownContents component', () => {
+ expect(findDropdownContents().exists()).toBe(true);
+ });
+
+ it('renders correct props for the DropdownContents component', () => {
+ expect(findDropdownContents().props()).toMatchObject({
+ variant: DROPDOWN_VARIANT.Embedded,
+ dropdownTitle: wrapper.vm.$options.i18n.assignColor,
+ dropdownButtonText: wrapper.vm.$options.i18n.dropdownButtonText,
+ });
+ });
+
+ it('handles DropdownContents setColor', () => {
+ findDropdownContents().vm.$emit('setColor', color);
+ expect(wrapper.emitted('updateSelectedColor')).toEqual([[color]]);
+ });
+ });
+
+ describe('when epicColorQuery errored', () => {
+ beforeEach(async () => {
+ createComponent({ queryHandler: errorQueryHandler });
+ await waitForPromises();
+ });
+
+ it('creates flash with error message', () => {
+ expect(createFlash).toHaveBeenCalledWith({
+ captureError: true,
+ message: 'Error fetching epic color.',
+ });
+ });
+ });
+
+ it('emits `updateSelectedColor` event on dropdown contents `setColor` event if iid is not set', () => {
+ createComponent({ propsData: { iid: undefined } });
+
+ findDropdownContents().vm.$emit('setColor', color);
+ expect(wrapper.emitted('updateSelectedColor')).toEqual([[color]]);
+ });
+
+ describe('when updating color for epic', () => {
+ beforeEach(() => {
+ createComponent();
+ findDropdownContents().vm.$emit('setColor', color);
+ });
+
+ it('sets the loading state', () => {
+ expect(findSidebarEditableItem().props('loading')).toBe(true);
+ });
+
+ it('updates color correctly after successful mutation', async () => {
+ await waitForPromises();
+ expect(findDropdownValue().props('selectedColor').color).toEqual(
+ updateColorMutationResponse.data.updateIssuableColor.issuable.color,
+ );
+ });
+
+ it('displays an error if mutation was rejected', async () => {
+ createComponent({ mutationHandler: errorMutationHandler });
+ findDropdownContents().vm.$emit('setColor', color);
+ await waitForPromises();
+
+ expect(createFlash).toHaveBeenCalledWith({
+ captureError: true,
+ error: expect.anything(),
+ message: 'An error occurred while updating color.',
+ });
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_contents_color_view_spec.js b/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_contents_color_view_spec.js
new file mode 100644
index 00000000000..303824c77b3
--- /dev/null
+++ b/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_contents_color_view_spec.js
@@ -0,0 +1,43 @@
+import { GlDropdownForm } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import DropdownContentsColorView from '~/vue_shared/components/color_select_dropdown/dropdown_contents_color_view.vue';
+import ColorItem from '~/vue_shared/components/color_select_dropdown/color_item.vue';
+import { ISSUABLE_COLORS } from '~/vue_shared/components/color_select_dropdown/constants';
+import { color as defaultColor } from './mock_data';
+
+const propsData = {
+ selectedColor: defaultColor,
+};
+
+describe('DropdownContentsColorView', () => {
+ let wrapper;
+
+ const createComponent = () => {
+ wrapper = shallowMount(DropdownContentsColorView, {
+ propsData,
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ const findColors = () => wrapper.findAllComponents(ColorItem);
+ const findColorList = () => wrapper.findComponent(GlDropdownForm);
+
+ it('renders color list', async () => {
+ expect(findColorList().exists()).toBe(true);
+ expect(findColors()).toHaveLength(ISSUABLE_COLORS.length);
+ });
+
+ it.each(ISSUABLE_COLORS)('emits an `input` event with %o on click on the option %#', (color) => {
+ const colorIndex = ISSUABLE_COLORS.indexOf(color);
+ findColors().at(colorIndex).trigger('click');
+
+ expect(wrapper.emitted('input')[0][0]).toMatchObject(color);
+ });
+});
diff --git a/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_contents_spec.js b/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_contents_spec.js
new file mode 100644
index 00000000000..74f50b878e2
--- /dev/null
+++ b/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_contents_spec.js
@@ -0,0 +1,113 @@
+import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import { DROPDOWN_VARIANT } from '~/vue_shared/components/color_select_dropdown/constants';
+import DropdownContents from '~/vue_shared/components/color_select_dropdown/dropdown_contents.vue';
+import DropdownContentsColorView from '~/vue_shared/components/color_select_dropdown/dropdown_contents_color_view.vue';
+
+import { color } from './mock_data';
+
+const showDropdown = jest.fn();
+const focusInput = jest.fn();
+
+const defaultProps = {
+ dropdownTitle: '',
+ selectedColor: color,
+ dropdownButtonText: '',
+ variant: '',
+ isVisible: false,
+};
+
+const GlDropdownStub = {
+ template: `
+ <div>
+ <slot name="header"></slot>
+ <slot></slot>
+ </div>
+ `,
+ methods: {
+ show: showDropdown,
+ hide: jest.fn(),
+ },
+};
+
+const DropdownHeaderStub = {
+ template: `
+ <div>Hello, I am a header</div>
+ `,
+ methods: {
+ focusInput,
+ },
+};
+
+describe('DropdownContent', () => {
+ let wrapper;
+
+ const createComponent = ({ propsData = {} } = {}) => {
+ wrapper = shallowMount(DropdownContents, {
+ propsData: {
+ ...defaultProps,
+ ...propsData,
+ },
+ stubs: {
+ GlDropdown: GlDropdownStub,
+ DropdownHeader: DropdownHeaderStub,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ const findColorView = () => wrapper.findComponent(DropdownContentsColorView);
+ const findDropdownHeader = () => wrapper.findComponent(DropdownHeaderStub);
+ const findDropdown = () => wrapper.findComponent(GlDropdownStub);
+
+ it('calls dropdown `show` method on `isVisible` prop change', async () => {
+ createComponent();
+ await wrapper.setProps({
+ isVisible: true,
+ });
+
+ expect(showDropdown).toHaveBeenCalledTimes(1);
+ });
+
+ it('does not emit `setColor` event on dropdown hide if color did not change', () => {
+ createComponent();
+ findDropdown().vm.$emit('hide');
+
+ expect(wrapper.emitted('setColor')).toBeUndefined();
+ });
+
+ it('emits `setColor` event on dropdown hide if color changed on non-sidebar widget', async () => {
+ createComponent({ propsData: { variant: DROPDOWN_VARIANT.Embedded } });
+ const updatedColor = {
+ title: 'Blue-gray',
+ color: '#6699cc',
+ };
+ findColorView().vm.$emit('input', updatedColor);
+ await nextTick();
+ findDropdown().vm.$emit('hide');
+
+ expect(wrapper.emitted('setColor')).toEqual([[updatedColor]]);
+ });
+
+ it('emits `setColor` event on visibility change if color changed on sidebar widget', async () => {
+ createComponent({ propsData: { variant: DROPDOWN_VARIANT.Sidebar, isVisible: true } });
+ const updatedColor = {
+ title: 'Blue-gray',
+ color: '#6699cc',
+ };
+ findColorView().vm.$emit('input', updatedColor);
+ wrapper.setProps({ isVisible: false });
+ await nextTick();
+
+ expect(wrapper.emitted('setColor')).toEqual([[updatedColor]]);
+ });
+
+ it('renders header', () => {
+ createComponent();
+
+ expect(findDropdownHeader().exists()).toBe(true);
+ });
+});
diff --git a/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_header_spec.js b/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_header_spec.js
new file mode 100644
index 00000000000..d203d78477f
--- /dev/null
+++ b/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_header_spec.js
@@ -0,0 +1,40 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlButton } from '@gitlab/ui';
+import DropdownHeader from '~/vue_shared/components/color_select_dropdown/dropdown_header.vue';
+
+const propsData = {
+ dropdownTitle: 'Epic color',
+};
+
+describe('DropdownHeader', () => {
+ let wrapper;
+
+ const createComponent = () => {
+ wrapper = shallowMount(DropdownHeader, { propsData });
+ };
+
+ const findButton = () => wrapper.findComponent(GlButton);
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders the correct title', () => {
+ expect(wrapper.text()).toBe(propsData.dropdownTitle);
+ });
+
+ it('renders a close button', () => {
+ expect(findButton().attributes('aria-label')).toBe('Close');
+ });
+
+ it('emits `closeDropdown` event on button click', () => {
+ expect(wrapper.emitted('closeDropdown')).toBeUndefined();
+ findButton().vm.$emit('click');
+
+ expect(wrapper.emitted('closeDropdown')).toEqual([[]]);
+ });
+});
diff --git a/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_value_spec.js b/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_value_spec.js
new file mode 100644
index 00000000000..f22592dd604
--- /dev/null
+++ b/spec/frontend/vue_shared/components/color_select_dropdown/dropdown_value_spec.js
@@ -0,0 +1,46 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+
+import ColorItem from '~/vue_shared/components/color_select_dropdown/color_item.vue';
+import DropdownValue from '~/vue_shared/components/color_select_dropdown/dropdown_value.vue';
+
+import { color } from './mock_data';
+
+const propsData = {
+ selectedColor: color,
+};
+
+describe('DropdownValue', () => {
+ let wrapper;
+
+ const findColorItems = () => wrapper.findAllComponents(ColorItem);
+
+ const createComponent = () => {
+ wrapper = shallowMountExtended(DropdownValue, { propsData });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('when there is a color set', () => {
+ it('renders the color', () => {
+ expect(findColorItems()).toHaveLength(2);
+ });
+
+ it.each`
+ index | cssClass
+ ${0} | ${['gl-font-base', 'gl-line-height-24']}
+ ${1} | ${['hide-collapsed']}
+ `(
+ 'passes correct props to the ColorItem with CSS class `$cssClass`',
+ async ({ index, cssClass }) => {
+ expect(findColorItems().at(index).props()).toMatchObject(propsData.selectedColor);
+ expect(findColorItems().at(index).classes()).toEqual(cssClass);
+ },
+ );
+ });
+});
diff --git a/spec/frontend/vue_shared/components/color_select_dropdown/mock_data.js b/spec/frontend/vue_shared/components/color_select_dropdown/mock_data.js
new file mode 100644
index 00000000000..097f47cc731
--- /dev/null
+++ b/spec/frontend/vue_shared/components/color_select_dropdown/mock_data.js
@@ -0,0 +1,30 @@
+export const color = {
+ color: '#217645',
+ title: 'Green',
+};
+
+export const colorQueryResponse = {
+ data: {
+ workspace: {
+ id: 'gid://gitlab/Workspace/1',
+ issuable: {
+ __typename: 'Epic',
+ id: 'gid://gitlab/Epic/1',
+ color: '#217645',
+ },
+ },
+ },
+};
+
+export const updateColorMutationResponse = {
+ data: {
+ updateIssuableColor: {
+ issuable: {
+ __typename: 'Epic',
+ id: 'gid://gitlab/Epic/1',
+ color: '#217645',
+ },
+ errors: [],
+ },
+ },
+};