diff options
author | Robert Speicher <rspeicher@gmail.com> | 2021-01-20 13:34:23 -0600 |
---|---|---|
committer | Robert Speicher <rspeicher@gmail.com> | 2021-01-20 13:34:23 -0600 |
commit | 6438df3a1e0fb944485cebf07976160184697d72 (patch) | |
tree | 00b09bfd170e77ae9391b1a2f5a93ef6839f2597 /spec/frontend/vue_shared | |
parent | 42bcd54d971da7ef2854b896a7b34f4ef8601067 (diff) | |
download | gitlab-ce-6438df3a1e0fb944485cebf07976160184697d72.tar.gz |
Add latest changes from gitlab-org/gitlab@13-8-stable-eev13.8.0-rc42
Diffstat (limited to 'spec/frontend/vue_shared')
104 files changed, 940 insertions, 769 deletions
diff --git a/spec/frontend/vue_shared/components/__snapshots__/clone_dropdown_spec.js.snap b/spec/frontend/vue_shared/components/__snapshots__/clone_dropdown_spec.js.snap index 63d38e7587a..1bf757ea312 100644 --- a/spec/frontend/vue_shared/components/__snapshots__/clone_dropdown_spec.js.snap +++ b/spec/frontend/vue_shared/components/__snapshots__/clone_dropdown_spec.js.snap @@ -4,6 +4,7 @@ exports[`Clone Dropdown Button rendering matches the snapshot 1`] = ` <gl-dropdown-stub category="primary" headertext="" + hideheaderborder="true" right="true" size="medium" text="Clone" diff --git a/spec/frontend/vue_shared/components/__snapshots__/split_button_spec.js.snap b/spec/frontend/vue_shared/components/__snapshots__/split_button_spec.js.snap index dd88ba9a6fb..c4f351eb58d 100644 --- a/spec/frontend/vue_shared/components/__snapshots__/split_button_spec.js.snap +++ b/spec/frontend/vue_shared/components/__snapshots__/split_button_spec.js.snap @@ -4,6 +4,7 @@ exports[`SplitButton renders actionItems 1`] = ` <gl-dropdown-stub category="primary" headertext="" + hideheaderborder="true" menu-class="" size="medium" split="true" diff --git a/spec/frontend/vue_shared/components/actions_button_spec.js b/spec/frontend/vue_shared/components/actions_button_spec.js index 6e7ed9d612b..2ac4bfda29a 100644 --- a/spec/frontend/vue_shared/components/actions_button_spec.js +++ b/spec/frontend/vue_shared/components/actions_button_spec.js @@ -1,5 +1,5 @@ import { shallowMount } from '@vue/test-utils'; -import { GlDropdown, GlButton } from '@gitlab/ui'; +import { GlDropdown, GlDropdownDivider, GlButton } from '@gitlab/ui'; import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; import ActionsButton from '~/vue_shared/components/actions_button.vue'; @@ -40,7 +40,7 @@ describe('Actions button component', () => { wrapper.destroy(); }); - const getTooltip = child => { + const getTooltip = (child) => { const directiveBinding = getBinding(child.element, 'gl-tooltip'); return directiveBinding.value; @@ -52,8 +52,8 @@ describe('Actions button component', () => { const parseDropdownItems = () => findDropdown() .findAll('gl-dropdown-item-stub,gl-dropdown-divider-stub') - .wrappers.map(x => { - if (x.is('gl-dropdown-divider-stub')) { + .wrappers.map((x) => { + if (x.is(GlDropdownDivider)) { return { type: 'divider' }; } diff --git a/spec/frontend/vue_shared/components/alert_details_table_spec.js b/spec/frontend/vue_shared/components/alert_details_table_spec.js index ef7815f9e9e..49b82cb4d4e 100644 --- a/spec/frontend/vue_shared/components/alert_details_table_spec.js +++ b/spec/frontend/vue_shared/components/alert_details_table_spec.js @@ -45,13 +45,13 @@ describe('AlertDetails', () => { const findTableComponent = () => wrapper.find(GlTable); const findTableKeys = () => findTableComponent().findAll('tbody td:first-child'); - const findTableFieldValueByKey = fieldKey => + const findTableFieldValueByKey = (fieldKey) => findTableComponent() .findAll('tbody tr') - .filter(row => row.text().includes(fieldKey)) + .filter((row) => row.text().includes(fieldKey)) .at(0) .find('td:nth-child(2)'); - const findTableField = (fields, fieldName) => fields.filter(row => row.text() === fieldName); + const findTableField = (fields, fieldName) => fields.filter((row) => row.text() === fieldName); describe('Alert details', () => { describe('empty state', () => { diff --git a/spec/frontend/vue_shared/components/awards_list_spec.js b/spec/frontend/vue_shared/components/awards_list_spec.js index d20de81c446..550ac4a9d38 100644 --- a/spec/frontend/vue_shared/components/awards_list_spec.js +++ b/spec/frontend/vue_shared/components/awards_list_spec.js @@ -58,10 +58,10 @@ describe('vue_shared/components/awards_list', () => { wrapper = mount(AwardsList, { propsData: props }); }; - const matchingEmojiTag = name => expect.stringMatching(`gl-emoji data-name="${name}"`); + const matchingEmojiTag = (name) => expect.stringMatching(`gl-emoji data-name="${name}"`); const findAwardButtons = () => wrapper.findAll('[data-testid="award-button"]'); const findAwardsData = () => - findAwardButtons().wrappers.map(x => { + findAwardButtons().wrappers.map((x) => { return { classes: x.classes(), title: x.attributes('title'), @@ -135,9 +135,7 @@ describe('vue_shared/components/awards_list', () => { it('with award clicked, it emits award', () => { expect(wrapper.emitted().award).toBeUndefined(); - findAwardButtons() - .at(2) - .vm.$emit('click'); + findAwardButtons().at(2).vm.$emit('click'); expect(wrapper.emitted().award).toEqual([[EMOJI_SMILE]]); }); @@ -162,9 +160,7 @@ describe('vue_shared/components/awards_list', () => { it('when clicked, it emits award as number', () => { expect(wrapper.emitted().award).toBeUndefined(); - findAwardButtons() - .at(0) - .vm.$emit('click'); + findAwardButtons().at(0).vm.$emit('click'); expect(wrapper.emitted().award).toEqual([[Number(EMOJI_100)]]); }); @@ -209,7 +205,7 @@ describe('vue_shared/components/awards_list', () => { const buttons = findAwardButtons(); expect(buttons.length).toBe(7); - expect(buttons.wrappers.every(x => x.classes('disabled'))).toBe(true); + expect(buttons.wrappers.every((x) => x.classes('disabled'))).toBe(true); }); }); diff --git a/spec/frontend/vue_shared/components/ci_badge_link_spec.js b/spec/frontend/vue_shared/components/ci_badge_link_spec.js index f656bb0b60d..a633ef65aa4 100644 --- a/spec/frontend/vue_shared/components/ci_badge_link_spec.js +++ b/spec/frontend/vue_shared/components/ci_badge_link_spec.js @@ -81,7 +81,7 @@ describe('CI Badge Link Component', () => { }); it('should render each status badge', () => { - Object.keys(statuses).map(status => { + Object.keys(statuses).map((status) => { vm = mountComponent(CIBadge, { status: statuses[status] }); expect(vm.$el.getAttribute('href')).toEqual(statuses[status].details_path); diff --git a/spec/frontend/vue_shared/components/clipboard_button_spec.js b/spec/frontend/vue_shared/components/clipboard_button_spec.js index ac0be1537b7..0d4266ce82f 100644 --- a/spec/frontend/vue_shared/components/clipboard_button_spec.js +++ b/spec/frontend/vue_shared/components/clipboard_button_spec.js @@ -1,6 +1,7 @@ import { mount } from '@vue/test-utils'; import { GlButton } from '@gitlab/ui'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; +import initCopyToClipboard from '~/behaviors/copy_to_clipboard'; describe('clipboard button', () => { let wrapper; @@ -87,4 +88,25 @@ describe('clipboard button', () => { expect(onClick).toHaveBeenCalled(); }); + + describe('integration', () => { + it('actually copies to clipboard', () => { + initCopyToClipboard(); + + document.execCommand = () => {}; + jest.spyOn(document, 'execCommand').mockImplementation(() => true); + + createWrapper( + { + text: 'copy me', + title: 'Copy this value', + }, + { attachTo: document.body }, + ); + + findButton().trigger('click'); + + expect(document.execCommand).toHaveBeenCalledWith('copy'); + }); + }); }); diff --git a/spec/frontend/vue_shared/components/color_picker/color_picker_spec.js b/spec/frontend/vue_shared/components/color_picker/color_picker_spec.js index a50a4b742b3..c8fe6c3131c 100644 --- a/spec/frontend/vue_shared/components/color_picker/color_picker_spec.js +++ b/spec/frontend/vue_shared/components/color_picker/color_picker_spec.js @@ -130,9 +130,7 @@ describe('ColorPicker', () => { it('has preset color selected', async () => { createComponent(); - await presetColors() - .at(0) - .trigger('click'); + await presetColors().at(0).trigger('click'); expect(wrapper.vm.$data.selectedColor).toBe(setColor); }); diff --git a/spec/frontend/vue_shared/components/commit_spec.js b/spec/frontend/vue_shared/components/commit_spec.js index 9b5c0941a0d..6f3c97f7194 100644 --- a/spec/frontend/vue_shared/components/commit_spec.js +++ b/spec/frontend/vue_shared/components/commit_spec.js @@ -7,14 +7,14 @@ describe('Commit component', () => { let props; let wrapper; - const findIcon = name => { - const icons = wrapper.findAll(GlIcon).filter(c => c.attributes('name') === name); + const findIcon = (name) => { + const icons = wrapper.findAll(GlIcon).filter((c) => c.attributes('name') === name); return icons.length ? icons.at(0) : icons; }; const findUserAvatar = () => wrapper.find(UserAvatarLink); - const createComponent = propsData => { + const createComponent = (propsData) => { wrapper = shallowMount(CommitComponent, { propsData, }); @@ -43,12 +43,7 @@ describe('Commit component', () => { }, }); - expect( - wrapper - .find('.icon-container') - .find(GlIcon) - .exists(), - ).toBe(true); + expect(wrapper.find('.icon-container').find(GlIcon).exists()).toBe(true); }); describe('Given all the props', () => { diff --git a/spec/frontend/vue_shared/components/confirm_modal_spec.js b/spec/frontend/vue_shared/components/confirm_modal_spec.js index 96ccf56cbc6..db8d0674121 100644 --- a/spec/frontend/vue_shared/components/confirm_modal_spec.js +++ b/spec/frontend/vue_shared/components/confirm_modal_spec.js @@ -53,7 +53,7 @@ describe('vue_shared/components/confirm_modal', () => { const findFormData = () => findForm() .findAll('input') - .wrappers.map(x => ({ name: x.attributes('name'), value: x.attributes('value') })); + .wrappers.map((x) => ({ name: x.attributes('name'), value: x.attributes('value') })); describe('template', () => { describe('when modal data is set', () => { diff --git a/spec/frontend/vue_shared/components/content_viewer/viewers/markdown_viewer_spec.js b/spec/frontend/vue_shared/components/content_viewer/viewers/markdown_viewer_spec.js index c75891c9ed3..22ee6acfed8 100644 --- a/spec/frontend/vue_shared/components/content_viewer/viewers/markdown_viewer_spec.js +++ b/spec/frontend/vue_shared/components/content_viewer/viewers/markdown_viewer_spec.js @@ -9,7 +9,7 @@ describe('MarkdownViewer', () => { let wrapper; let mock; - const createComponent = props => { + const createComponent = (props) => { wrapper = mount(MarkdownViewer, { propsData: { ...props, diff --git a/spec/frontend/vue_shared/components/date_time_picker/date_time_picker_lib_spec.js b/spec/frontend/vue_shared/components/date_time_picker/date_time_picker_lib_spec.js index e46c63a1a32..10eacff630d 100644 --- a/spec/frontend/vue_shared/components/date_time_picker/date_time_picker_lib_spec.js +++ b/spec/frontend/vue_shared/components/date_time_picker/date_time_picker_lib_spec.js @@ -71,7 +71,7 @@ describe('date time picker lib', () => { '2019-19-23', '2019-09-23 x', '2019-09-29 24:24:24', - ].forEach(input => { + ].forEach((input) => { it(`throws error for invalid input like ${input}`, () => { expect(() => inputStringToIsoDate(input)).toThrow(); }); diff --git a/spec/frontend/vue_shared/components/date_time_picker/date_time_picker_spec.js b/spec/frontend/vue_shared/components/date_time_picker/date_time_picker_spec.js index afd1f1a3123..33667a1bb71 100644 --- a/spec/frontend/vue_shared/components/date_time_picker/date_time_picker_spec.js +++ b/spec/frontend/vue_shared/components/date_time_picker/date_time_picker_spec.js @@ -17,7 +17,7 @@ describe('DateTimePicker', () => { const applyButtonElement = () => wrapper.find('button.btn-success').element; const findQuickRangeItems = () => wrapper.findAll('.dropdown-item'); - const createComponent = props => { + const createComponent = (props) => { wrapper = mount(DateTimePicker, { propsData: { ...props, @@ -235,7 +235,7 @@ describe('DateTimePicker', () => { it('unchecks quick range when text is input is clicked', () => { const findActiveItems = () => - findQuickRangeItems().filter(w => w.classes().includes('active')); + findQuickRangeItems().filter((w) => w.classes().includes('active')); expect(findActiveItems().length).toBe(1); diff --git a/spec/frontend/vue_shared/components/deployment_instance/deployment_instance_spec.js b/spec/frontend/vue_shared/components/deployment_instance/deployment_instance_spec.js new file mode 100644 index 00000000000..b812ced72c9 --- /dev/null +++ b/spec/frontend/vue_shared/components/deployment_instance/deployment_instance_spec.js @@ -0,0 +1,103 @@ +import { shallowMount } from '@vue/test-utils'; +import DeployBoardInstance from '~/vue_shared/components/deployment_instance.vue'; +import { folder } from './mock_data'; + +describe('Deploy Board Instance', () => { + let wrapper; + + const createComponent = (props = {}) => + shallowMount(DeployBoardInstance, { + propsData: { + status: 'succeeded', + ...props, + }, + }); + + describe('as a non-canary deployment', () => { + afterEach(() => { + wrapper.destroy(); + }); + + it('should render a div with the correct css status and tooltip data', () => { + wrapper = createComponent({ + logsPath: folder.logs_path, + tooltipText: 'This is a pod', + }); + + expect(wrapper.classes('deployment-instance-succeeded')).toBe(true); + expect(wrapper.attributes('title')).toEqual('This is a pod'); + }); + + it('should render a div without tooltip data', (done) => { + wrapper = createComponent({ + status: 'deploying', + tooltipText: '', + }); + + wrapper.vm.$nextTick(() => { + expect(wrapper.classes('deployment-instance-deploying')).toBe(true); + expect(wrapper.attributes('title')).toEqual(''); + done(); + }); + }); + + it('should have a log path computed with a pod name as a parameter', () => { + wrapper = createComponent({ + logsPath: folder.logs_path, + podName: 'tanuki-1', + }); + + expect(wrapper.vm.computedLogPath).toEqual( + '/root/review-app/-/logs?environment_name=foo&pod_name=tanuki-1', + ); + }); + }); + + describe('as a canary deployment', () => { + afterEach(() => { + wrapper.destroy(); + }); + + it('should render a div with canary class when stable prop is provided as false', (done) => { + wrapper = createComponent({ + stable: false, + }); + + wrapper.vm.$nextTick(() => { + expect(wrapper.classes('deployment-instance-canary')).toBe(true); + done(); + }); + }); + }); + + describe('as a legend item', () => { + afterEach(() => { + wrapper.destroy(); + }); + + it('should not be a link without a logsPath prop', (done) => { + wrapper = createComponent({ + stable: false, + logsPath: '', + }); + + wrapper.vm.$nextTick(() => { + expect(wrapper.vm.computedLogPath).toBeNull(); + expect(wrapper.vm.isLink).toBeFalsy(); + done(); + }); + }); + + it('should render a link without href if path is not passed', () => { + wrapper = createComponent(); + + expect(wrapper.attributes('href')).toBeUndefined(); + }); + + it('should not have a tooltip', () => { + wrapper = createComponent(); + + expect(wrapper.attributes('title')).toEqual(''); + }); + }); +}); diff --git a/spec/frontend/vue_shared/components/deployment_instance/mock_data.js b/spec/frontend/vue_shared/components/deployment_instance/mock_data.js new file mode 100644 index 00000000000..6618c57948c --- /dev/null +++ b/spec/frontend/vue_shared/components/deployment_instance/mock_data.js @@ -0,0 +1,144 @@ +export const environmentsList = [ + { + name: 'DEV', + size: 1, + id: 7, + state: 'available', + external_url: null, + environment_type: null, + last_deployment: null, + has_stop_action: false, + environment_path: '/root/review-app/environments/7', + stop_path: '/root/review-app/environments/7/stop', + created_at: '2017-01-31T10:53:46.894Z', + updated_at: '2017-01-31T10:53:46.894Z', + project_path: '/root/review-app', + rollout_status: {}, + }, + { + folderName: 'build', + size: 5, + id: 12, + name: 'build/update-README', + state: 'available', + external_url: null, + environment_type: 'build', + last_deployment: null, + has_stop_action: false, + environment_path: '/root/review-app/environments/12', + stop_path: '/root/review-app/environments/12/stop', + created_at: '2017-02-01T19:42:18.400Z', + updated_at: '2017-02-01T19:42:18.400Z', + project_path: '/root/review-app', + rollout_status: {}, + }, +]; + +export const serverData = [ + { + name: 'DEV', + size: 1, + latest: { + id: 7, + name: 'DEV', + state: 'available', + external_url: null, + environment_type: null, + last_deployment: null, + has_stop_action: false, + environment_path: '/root/review-app/environments/7', + stop_path: '/root/review-app/environments/7/stop', + created_at: '2017-01-31T10:53:46.894Z', + updated_at: '2017-01-31T10:53:46.894Z', + rollout_status: {}, + }, + }, + { + name: 'build', + size: 5, + latest: { + id: 12, + name: 'build/update-README', + state: 'available', + external_url: null, + environment_type: 'build', + last_deployment: null, + has_stop_action: false, + environment_path: '/root/review-app/environments/12', + stop_path: '/root/review-app/environments/12/stop', + created_at: '2017-02-01T19:42:18.400Z', + updated_at: '2017-02-01T19:42:18.400Z', + }, + }, + { + name: 'build', + size: 1, + latest: { + id: 12, + name: 'build/update-README', + state: 'available', + external_url: null, + environment_type: 'build', + last_deployment: null, + has_stop_action: false, + environment_path: '/root/review-app/environments/12', + stop_path: '/root/review-app/environments/12/stop', + created_at: '2017-02-01T19:42:18.400Z', + updated_at: '2017-02-01T19:42:18.400Z', + }, + }, +]; + +export const deployBoardMockData = { + instances: [ + { status: 'finished', tooltip: 'tanuki-2334 Finished', pod_name: 'production-tanuki-1' }, + { status: 'finished', tooltip: 'tanuki-2335 Finished', pod_name: 'production-tanuki-1' }, + { status: 'finished', tooltip: 'tanuki-2336 Finished', pod_name: 'production-tanuki-1' }, + { status: 'finished', tooltip: 'tanuki-2337 Finished', pod_name: 'production-tanuki-1' }, + { status: 'finished', tooltip: 'tanuki-2338 Finished', pod_name: 'production-tanuki-1' }, + { status: 'finished', tooltip: 'tanuki-2339 Finished', pod_name: 'production-tanuki-1' }, + { status: 'finished', tooltip: 'tanuki-2340 Finished', pod_name: 'production-tanuki-1' }, + { status: 'finished', tooltip: 'tanuki-2334 Finished', pod_name: 'production-tanuki-1' }, + { status: 'finished', tooltip: 'tanuki-2335 Finished', pod_name: 'production-tanuki-1' }, + { status: 'finished', tooltip: 'tanuki-2336 Finished', pod_name: 'production-tanuki-1' }, + { status: 'finished', tooltip: 'tanuki-2337 Finished', pod_name: 'production-tanuki-1' }, + { status: 'finished', tooltip: 'tanuki-2338 Finished', pod_name: 'production-tanuki-1' }, + { status: 'finished', tooltip: 'tanuki-2339 Finished', pod_name: 'production-tanuki-1' }, + { status: 'finished', tooltip: 'tanuki-2340 Finished', pod_name: 'production-tanuki-1' }, + { status: 'deploying', tooltip: 'tanuki-2341 Deploying', pod_name: 'production-tanuki-1' }, + { status: 'deploying', tooltip: 'tanuki-2342 Deploying', pod_name: 'production-tanuki-1' }, + { status: 'deploying', tooltip: 'tanuki-2343 Deploying', pod_name: 'production-tanuki-1' }, + { status: 'failed', tooltip: 'tanuki-2344 Failed', pod_name: 'production-tanuki-1' }, + { status: 'ready', tooltip: 'tanuki-2345 Ready', pod_name: 'production-tanuki-1' }, + { status: 'ready', tooltip: 'tanuki-2346 Ready', pod_name: 'production-tanuki-1' }, + { status: 'preparing', tooltip: 'tanuki-2348 Preparing', pod_name: 'production-tanuki-1' }, + { status: 'preparing', tooltip: 'tanuki-2349 Preparing', pod_name: 'production-tanuki-1' }, + { status: 'preparing', tooltip: 'tanuki-2350 Preparing', pod_name: 'production-tanuki-1' }, + { status: 'preparing', tooltip: 'tanuki-2353 Preparing', pod_name: 'production-tanuki-1' }, + { status: 'waiting', tooltip: 'tanuki-2354 Waiting', pod_name: 'production-tanuki-1' }, + { status: 'waiting', tooltip: 'tanuki-2355 Waiting', pod_name: 'production-tanuki-1' }, + { status: 'waiting', tooltip: 'tanuki-2356 Waiting', pod_name: 'production-tanuki-1' }, + ], + abort_url: 'url', + rollback_url: 'url', + completion: 100, + status: 'found', +}; + +export const folder = { + folderName: 'build', + size: 5, + id: 12, + name: 'build/update-README', + state: 'available', + external_url: null, + environment_type: 'build', + last_deployment: null, + has_stop_action: false, + environment_path: '/root/review-app/environments/12', + stop_path: '/root/review-app/environments/12/stop', + created_at: '2017-02-01T19:42:18.400Z', + updated_at: '2017-02-01T19:42:18.400Z', + rollout_status: {}, + logs_path: '/root/review-app/-/logs?environment_name=foo', +}; diff --git a/spec/frontend/vue_shared/components/deprecated_modal_2_spec.js b/spec/frontend/vue_shared/components/deprecated_modal_2_spec.js deleted file mode 100644 index c37a44df6f8..00000000000 --- a/spec/frontend/vue_shared/components/deprecated_modal_2_spec.js +++ /dev/null @@ -1,258 +0,0 @@ -import Vue from 'vue'; -import mountComponent from 'helpers/vue_mount_component_helper'; -import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue'; - -const modalComponent = Vue.extend(DeprecatedModal2); - -describe('DeprecatedModal2', () => { - let vm; - - afterEach(() => { - vm.$destroy(); - }); - - describe('props', () => { - describe('with id', () => { - const props = { - id: 'my-modal', - }; - - beforeEach(() => { - vm = mountComponent(modalComponent, props); - }); - - it('assigns the id to the modal', () => { - expect(vm.$el.id).toBe(props.id); - }); - }); - - describe('without id', () => { - beforeEach(() => { - vm = mountComponent(modalComponent, {}); - }); - - it('does not add an id attribute to the modal', () => { - expect(vm.$el.hasAttribute('id')).toBe(false); - }); - }); - - describe('with headerTitleText', () => { - const props = { - headerTitleText: 'my title text', - }; - - beforeEach(() => { - vm = mountComponent(modalComponent, props); - }); - - it('sets the modal title', () => { - const modalTitle = vm.$el.querySelector('.modal-title'); - - expect(modalTitle.innerHTML.trim()).toBe(props.headerTitleText); - }); - }); - - describe('with footerPrimaryButtonVariant', () => { - const props = { - footerPrimaryButtonVariant: 'danger', - }; - - beforeEach(() => { - vm = mountComponent(modalComponent, props); - }); - - it('sets the primary button class', () => { - const primaryButton = vm.$el.querySelector('.modal-footer button:last-of-type'); - - expect(primaryButton).toHaveClass(`btn-${props.footerPrimaryButtonVariant}`); - }); - }); - - describe('with footerPrimaryButtonText', () => { - const props = { - footerPrimaryButtonText: 'my button text', - }; - - beforeEach(() => { - vm = mountComponent(modalComponent, props); - }); - - it('sets the primary button text', () => { - const primaryButton = vm.$el.querySelector('.js-modal-primary-action .gl-button-text'); - - expect(primaryButton.innerHTML.trim()).toBe(props.footerPrimaryButtonText); - }); - }); - }); - - it('works with data-toggle="modal"', () => { - setFixtures(` - <button id="modal-button" data-toggle="modal" data-target="#my-modal"></button> - <div id="modal-container"></div> - `); - - const modalContainer = document.getElementById('modal-container'); - const modalButton = document.getElementById('modal-button'); - vm = mountComponent( - modalComponent, - { - id: 'my-modal', - }, - modalContainer, - ); - const modalElement = document.getElementById('my-modal'); - - modalButton.click(); - - expect(modalElement).not.toHaveClass('show'); - - // let the modal fade in - jest.runOnlyPendingTimers(); - - expect(modalElement).toHaveClass('show'); - }); - - describe('methods', () => { - const dummyEvent = 'not really an event'; - - beforeEach(() => { - vm = mountComponent(modalComponent, {}); - jest.spyOn(vm, '$emit').mockImplementation(() => {}); - }); - - describe('emitCancel', () => { - it('emits a cancel event', () => { - vm.emitCancel(dummyEvent); - - expect(vm.$emit).toHaveBeenCalledWith('cancel', dummyEvent); - }); - }); - - describe('emitSubmit', () => { - it('emits a submit event', () => { - vm.emitSubmit(dummyEvent); - - expect(vm.$emit).toHaveBeenCalledWith('submit', dummyEvent); - }); - }); - - describe('opened', () => { - it('emits a open event', () => { - vm.opened(); - - expect(vm.$emit).toHaveBeenCalledWith('open'); - }); - }); - - describe('closed', () => { - it('emits a closed event', () => { - vm.closed(); - - expect(vm.$emit).toHaveBeenCalledWith('closed'); - }); - }); - }); - - describe('slots', () => { - const slotContent = 'this should go into the slot'; - - const modalWithSlot = slot => { - return Vue.extend({ - components: { - DeprecatedModal2, - }, - render: h => - h('deprecated-modal-2', [slot ? h('template', { slot }, slotContent) : slotContent]), - }); - }; - - describe('default slot', () => { - beforeEach(() => { - vm = mountComponent(modalWithSlot()); - }); - - it('sets the modal body', () => { - const modalBody = vm.$el.querySelector('.modal-body'); - - expect(modalBody.innerHTML).toBe(slotContent); - }); - }); - - describe('header slot', () => { - beforeEach(() => { - vm = mountComponent(modalWithSlot('header')); - }); - - it('sets the modal header', () => { - const modalHeader = vm.$el.querySelector('.modal-header'); - - expect(modalHeader.innerHTML).toBe(slotContent); - }); - }); - - describe('title slot', () => { - beforeEach(() => { - vm = mountComponent(modalWithSlot('title')); - }); - - it('sets the modal title', () => { - const modalTitle = vm.$el.querySelector('.modal-title'); - - expect(modalTitle.innerHTML).toBe(slotContent); - }); - }); - - describe('footer slot', () => { - beforeEach(() => { - vm = mountComponent(modalWithSlot('footer')); - }); - - it('sets the modal footer', () => { - const modalFooter = vm.$el.querySelector('.modal-footer'); - - expect(modalFooter.innerHTML).toBe(slotContent); - }); - }); - }); - - describe('handling sizes', () => { - it('should render modal-sm', () => { - vm = mountComponent(modalComponent, { - modalSize: 'sm', - }); - - expect(vm.$el.querySelector('.modal-dialog').classList.contains('modal-sm')).toEqual(true); - }); - - it('should render modal-lg', () => { - vm = mountComponent(modalComponent, { - modalSize: 'lg', - }); - - expect(vm.$el.querySelector('.modal-dialog').classList.contains('modal-lg')).toEqual(true); - }); - - it('should render modal-xl', () => { - vm = mountComponent(modalComponent, { - modalSize: 'xl', - }); - - expect(vm.$el.querySelector('.modal-dialog').classList.contains('modal-xl')).toEqual(true); - }); - - it('should not add modal size classes when md size is passed', () => { - vm = mountComponent(modalComponent, { - modalSize: 'md', - }); - - expect(vm.$el.querySelector('.modal-dialog').classList.contains('modal-md')).toEqual(false); - }); - - it('should not add modal size classes by default', () => { - vm = mountComponent(modalComponent, {}); - - expect(vm.$el.querySelector('.modal-dialog').classList.contains('modal-sm')).toEqual(false); - expect(vm.$el.querySelector('.modal-dialog').classList.contains('modal-lg')).toEqual(false); - }); - }); -}); diff --git a/spec/frontend/vue_shared/components/diff_viewer/diff_viewer_spec.js b/spec/frontend/vue_shared/components/diff_viewer/diff_viewer_spec.js index a6e4d812c3c..68e3ee11a0d 100644 --- a/spec/frontend/vue_shared/components/diff_viewer/diff_viewer_spec.js +++ b/spec/frontend/vue_shared/components/diff_viewer/diff_viewer_spec.js @@ -26,7 +26,7 @@ describe('DiffViewer', () => { vm.$destroy(); }); - it('renders image diff', done => { + it('renders image diff', (done) => { window.gon = { relative_url_root: '', }; @@ -46,7 +46,7 @@ describe('DiffViewer', () => { }); }); - it('renders fallback download diff display', done => { + it('renders fallback download diff display', (done) => { createComponent({ ...requiredProps, diffViewerMode: 'added', diff --git a/spec/frontend/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js b/spec/frontend/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js index f364f374887..b6bffbcc6f3 100644 --- a/spec/frontend/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js +++ b/spec/frontend/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js @@ -51,7 +51,7 @@ describe('ImageDiffViewer', () => { wrapper.destroy(); }); - it('renders image diff for replaced', done => { + it('renders image diff for replaced', (done) => { createComponent({ ...allProps }); vm.$nextTick(() => { @@ -78,7 +78,7 @@ describe('ImageDiffViewer', () => { }); }); - it('renders image diff for new', done => { + it('renders image diff for new', (done) => { createComponent({ ...allProps, diffMode: 'new', oldPath: '' }); setImmediate(() => { @@ -91,7 +91,7 @@ describe('ImageDiffViewer', () => { }); }); - it('renders image diff for deleted', done => { + it('renders image diff for deleted', (done) => { createComponent({ ...allProps, diffMode: 'deleted', newPath: '' }); setImmediate(() => { @@ -104,7 +104,7 @@ describe('ImageDiffViewer', () => { }); }); - it('renders image diff for renamed', done => { + it('renders image diff for renamed', (done) => { vm = new Vue({ components: { imageDiffViewer, @@ -139,7 +139,7 @@ describe('ImageDiffViewer', () => { }); describe('swipeMode', () => { - beforeEach(done => { + beforeEach((done) => { createComponent({ ...requiredProps }); setImmediate(() => { @@ -147,7 +147,7 @@ describe('ImageDiffViewer', () => { }); }); - it('switches to Swipe Mode', done => { + it('switches to Swipe Mode', (done) => { vm.$el.querySelector('.view-modes-menu li:nth-child(2)').click(); vm.$nextTick(() => { @@ -158,7 +158,7 @@ describe('ImageDiffViewer', () => { }); describe('onionSkin', () => { - beforeEach(done => { + beforeEach((done) => { createComponent({ ...requiredProps }); setImmediate(() => { @@ -166,7 +166,7 @@ describe('ImageDiffViewer', () => { }); }); - it('switches to Onion Skin Mode', done => { + it('switches to Onion Skin Mode', (done) => { vm.$el.querySelector('.view-modes-menu li:nth-child(3)').click(); vm.$nextTick(() => { @@ -177,7 +177,7 @@ describe('ImageDiffViewer', () => { }); }); - it('has working drag handler', done => { + it('has working drag handler', (done) => { vm.$el.querySelector('.view-modes-menu li:nth-child(3)').click(); vm.$nextTick(() => { diff --git a/spec/frontend/vue_shared/components/dismissible_container_spec.js b/spec/frontend/vue_shared/components/dismissible_container_spec.js index e49ca1e2285..2c0e363fa0e 100644 --- a/spec/frontend/vue_shared/components/dismissible_container_spec.js +++ b/spec/frontend/vue_shared/components/dismissible_container_spec.js @@ -43,7 +43,7 @@ describe('DismissibleContainer', () => { default: 'default slot', }; - it.each(Object.keys(slots))('renders the %s slot', slot => { + it.each(Object.keys(slots))('renders the %s slot', (slot) => { const slotContent = slots[slot]; wrapper = shallowMount(dismissibleContainer, { propsData, diff --git a/spec/frontend/vue_shared/components/editor_lite_spec.js b/spec/frontend/vue_shared/components/editor_lite_spec.js index 52502fcf64f..70fdd8e24a5 100644 --- a/spec/frontend/vue_shared/components/editor_lite_spec.js +++ b/spec/frontend/vue_shared/components/editor_lite_spec.js @@ -7,20 +7,22 @@ jest.mock('~/editor/editor_lite'); describe('Editor Lite component', () => { let wrapper; - const onDidChangeModelContent = jest.fn(); - const updateModelLanguage = jest.fn(); - const getValue = jest.fn(); - const setValue = jest.fn(); + let mockInstance; + const value = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'; const fileName = 'lorem.txt'; const fileGlobalId = 'snippet_777'; - const createInstanceMock = jest.fn().mockImplementation(() => ({ - onDidChangeModelContent, - updateModelLanguage, - getValue, - setValue, - dispose: jest.fn(), - })); + const createInstanceMock = jest.fn().mockImplementation(() => { + mockInstance = { + onDidChangeModelContent: jest.fn(), + updateModelLanguage: jest.fn(), + getValue: jest.fn(), + setValue: jest.fn(), + dispose: jest.fn(), + }; + return mockInstance; + }); + Editor.mockImplementation(() => { return { createInstance: createInstanceMock, @@ -45,9 +47,9 @@ describe('Editor Lite component', () => { wrapper.destroy(); }); - const triggerChangeContent = val => { - getValue.mockReturnValue(val); - const [cb] = onDidChangeModelContent.mock.calls[0]; + const triggerChangeContent = (val) => { + mockInstance.getValue.mockReturnValue(val); + const [cb] = mockInstance.onDidChangeModelContent.mock.calls[0]; cb(); @@ -92,12 +94,12 @@ describe('Editor Lite component', () => { }); return nextTick().then(() => { - expect(updateModelLanguage).toHaveBeenCalledWith(newFileName); + expect(mockInstance.updateModelLanguage).toHaveBeenCalledWith(newFileName); }); }); it('registers callback with editor onChangeContent', () => { - expect(onDidChangeModelContent).toHaveBeenCalledWith(expect.any(Function)); + expect(mockInstance.onDidChangeModelContent).toHaveBeenCalledWith(expect.any(Function)); }); it('emits input event when the blob content is changed', () => { @@ -117,6 +119,10 @@ describe('Editor Lite component', () => { expect(wrapper.emitted()['editor-ready']).toBeDefined(); }); + it('component API `getEditor()` returns the editor instance', () => { + expect(wrapper.vm.getEditor()).toBe(mockInstance); + }); + describe('reaction to the value update', () => { it('reacts to the changes in the passed value', async () => { const newValue = 'New Value'; @@ -126,7 +132,7 @@ describe('Editor Lite component', () => { }); await nextTick(); - expect(setValue).toHaveBeenCalledWith(newValue); + expect(mockInstance.setValue).toHaveBeenCalledWith(newValue); }); it("does not update value if the passed one is exactly the same as the editor's content", async () => { @@ -137,7 +143,7 @@ describe('Editor Lite component', () => { }); await nextTick(); - expect(setValue).not.toHaveBeenCalled(); + expect(mockInstance.setValue).not.toHaveBeenCalled(); }); }); }); diff --git a/spec/frontend/vue_shared/components/expand_button_spec.js b/spec/frontend/vue_shared/components/expand_button_spec.js index aea90e5b31f..724405a109f 100644 --- a/spec/frontend/vue_shared/components/expand_button_spec.js +++ b/spec/frontend/vue_shared/components/expand_button_spec.js @@ -41,12 +41,7 @@ describe('Expand button', () => { }); it('does not render expanded text', () => { - expect( - wrapper - .find(ExpandButton) - .text() - .trim(), - ).not.toBe(text.short); + expect(wrapper.find(ExpandButton).text().trim()).not.toBe(text.short); }); describe('when short text is provided', () => { @@ -60,12 +55,7 @@ describe('Expand button', () => { }); it('renders short text', () => { - expect( - wrapper - .find(ExpandButton) - .text() - .trim(), - ).toBe(text.short); + expect(wrapper.find(ExpandButton).text().trim()).toBe(text.short); }); it('renders button before text', () => { @@ -76,7 +66,7 @@ describe('Expand button', () => { }); describe('on click', () => { - beforeEach(done => { + beforeEach((done) => { expanderPrependEl().trigger('click'); Vue.nextTick(done); }); @@ -95,7 +85,7 @@ describe('Expand button', () => { }); describe('when short text is provided', () => { - beforeEach(done => { + beforeEach((done) => { factory({ slots: { expanded: `<p>${text.expanded}</p>`, @@ -108,12 +98,7 @@ describe('Expand button', () => { }); it('only renders expanded text', () => { - expect( - wrapper - .find(ExpandButton) - .text() - .trim(), - ).toBe(text.expanded); + expect(wrapper.find(ExpandButton).text().trim()).toBe(text.expanded); }); it('renders button after text', () => { @@ -125,7 +110,7 @@ describe('Expand button', () => { }); describe('append button', () => { - beforeEach(done => { + beforeEach((done) => { expanderPrependEl().trigger('click'); Vue.nextTick(done); }); @@ -140,26 +125,16 @@ describe('Expand button', () => { }); it('clicking hides expanded text', () => { - expect( - wrapper - .find(ExpandButton) - .text() - .trim(), - ).toBe(text.expanded); + expect(wrapper.find(ExpandButton).text().trim()).toBe(text.expanded); expanderAppendEl().trigger('click'); return wrapper.vm.$nextTick().then(() => { - expect( - wrapper - .find(ExpandButton) - .text() - .trim(), - ).not.toBe(text.expanded); + expect(wrapper.find(ExpandButton).text().trim()).not.toBe(text.expanded); }); }); describe('when short text is provided', () => { - beforeEach(done => { + beforeEach((done) => { factory({ slots: { expanded: `<p>${text.expanded}</p>`, @@ -172,21 +147,11 @@ describe('Expand button', () => { }); it('clicking reveals short text', () => { - expect( - wrapper - .find(ExpandButton) - .text() - .trim(), - ).toBe(text.expanded); + expect(wrapper.find(ExpandButton).text().trim()).toBe(text.expanded); expanderAppendEl().trigger('click'); return wrapper.vm.$nextTick().then(() => { - expect( - wrapper - .find(ExpandButton) - .text() - .trim(), - ).toBe(text.short); + expect(wrapper.find(ExpandButton).text().trim()).toBe(text.short); }); }); }); diff --git a/spec/frontend/vue_shared/components/file_finder/index_spec.js b/spec/frontend/vue_shared/components/file_finder/index_spec.js index 40026021777..238a5440664 100644 --- a/spec/frontend/vue_shared/components/file_finder/index_spec.js +++ b/spec/frontend/vue_shared/components/file_finder/index_spec.js @@ -31,7 +31,7 @@ describe('File finder item spec', () => { }); describe('with entries', () => { - beforeEach(done => { + beforeEach((done) => { createComponent({ files: [ { @@ -57,7 +57,7 @@ describe('File finder item spec', () => { expect(vm.$el.textContent).not.toContain('folder'); }); - it('filters entries', done => { + it('filters entries', (done) => { vm.searchText = 'index'; setImmediate(() => { @@ -68,7 +68,7 @@ describe('File finder item spec', () => { }); }); - it('shows clear button when searchText is not empty', done => { + it('shows clear button when searchText is not empty', (done) => { vm.searchText = 'index'; setImmediate(() => { @@ -79,7 +79,7 @@ describe('File finder item spec', () => { }); }); - it('clear button resets searchText', done => { + it('clear button resets searchText', (done) => { vm.searchText = 'index'; waitForPromises() @@ -94,7 +94,7 @@ describe('File finder item spec', () => { .catch(done.fail); }); - it('clear button focuses search input', done => { + it('clear button focuses search input', (done) => { jest.spyOn(vm.$refs.searchInput, 'focus').mockImplementation(() => {}); vm.searchText = 'index'; @@ -111,7 +111,7 @@ describe('File finder item spec', () => { }); describe('listShowCount', () => { - it('returns 1 when no filtered entries exist', done => { + it('returns 1 when no filtered entries exist', (done) => { vm.searchText = 'testing 123'; setImmediate(() => { @@ -131,7 +131,7 @@ describe('File finder item spec', () => { expect(vm.listHeight).toBe(55); }); - it('returns 33 when entries dont exist', done => { + it('returns 33 when entries dont exist', (done) => { vm.searchText = 'testing 123'; setImmediate(() => { @@ -143,7 +143,7 @@ describe('File finder item spec', () => { }); describe('filteredBlobsLength', () => { - it('returns length of filtered blobs', done => { + it('returns length of filtered blobs', (done) => { vm.searchText = 'index'; setImmediate(() => { @@ -156,7 +156,7 @@ describe('File finder item spec', () => { describe('watches', () => { describe('searchText', () => { - it('resets focusedIndex when updated', done => { + it('resets focusedIndex when updated', (done) => { vm.focusedIndex = 1; vm.searchText = 'test'; @@ -169,7 +169,7 @@ describe('File finder item spec', () => { }); describe('visible', () => { - it('returns searchText when false', done => { + it('returns searchText when false', (done) => { vm.searchText = 'test'; vm.visible = true; @@ -206,7 +206,7 @@ describe('File finder item spec', () => { }); describe('onKeyup', () => { - it('opens file on enter key', done => { + it('opens file on enter key', (done) => { const event = new CustomEvent('keyup'); event.keyCode = ENTER_KEY_CODE; @@ -221,7 +221,7 @@ describe('File finder item spec', () => { }); }); - it('closes file finder on esc key', done => { + it('closes file finder on esc key', (done) => { const event = new CustomEvent('keyup'); event.keyCode = ESC_KEY_CODE; @@ -300,7 +300,7 @@ describe('File finder item spec', () => { }); describe('keyboard shortcuts', () => { - beforeEach(done => { + beforeEach((done) => { createComponent(); jest.spyOn(vm, 'toggle').mockImplementation(() => {}); @@ -308,7 +308,7 @@ describe('File finder item spec', () => { vm.$nextTick(done); }); - it('calls toggle on `t` key press', done => { + it('calls toggle on `t` key press', (done) => { Mousetrap.trigger('t'); vm.$nextTick() @@ -319,7 +319,7 @@ describe('File finder item spec', () => { .catch(done.fail); }); - it('calls toggle on `mod+p` key press', done => { + it('calls toggle on `mod+p` key press', (done) => { Mousetrap.trigger('mod+p'); vm.$nextTick() diff --git a/spec/frontend/vue_shared/components/file_finder/item_spec.js b/spec/frontend/vue_shared/components/file_finder/item_spec.js index 5a45a5dbba1..c60e6335389 100644 --- a/spec/frontend/vue_shared/components/file_finder/item_spec.js +++ b/spec/frontend/vue_shared/components/file_finder/item_spec.js @@ -37,7 +37,7 @@ describe('File finder item spec', () => { expect(vm.$el.classList).toContain('is-focused'); }); - it('does not have is-focused class when not focused', done => { + it('does not have is-focused class when not focused', (done) => { vm.focused = false; vm.$nextTick(() => { @@ -53,7 +53,7 @@ describe('File finder item spec', () => { expect(vm.$el.querySelector('.diff-changed-stats')).toBe(null); }); - it('renders when a changed file', done => { + it('renders when a changed file', (done) => { vm.file.changed = true; vm.$nextTick(() => { @@ -63,7 +63,7 @@ describe('File finder item spec', () => { }); }); - it('renders when a temp file', done => { + it('renders when a temp file', (done) => { vm.file.tempFile = true; vm.$nextTick(() => { @@ -85,7 +85,7 @@ describe('File finder item spec', () => { describe('path', () => { let el; - beforeEach(done => { + beforeEach((done) => { vm.searchText = 'file'; el = vm.$el.querySelector('.diff-changed-file-path'); @@ -97,7 +97,7 @@ describe('File finder item spec', () => { expect(el.querySelectorAll('.highlighted').length).toBe(4); }); - it('adds ellipsis to long text', done => { + it('adds ellipsis to long text', (done) => { vm.file.path = new Array(70) .fill() .map((_, i) => `${i}-`) @@ -113,7 +113,7 @@ describe('File finder item spec', () => { describe('name', () => { let el; - beforeEach(done => { + beforeEach((done) => { vm.searchText = 'file'; el = vm.$el.querySelector('.diff-changed-file-name'); @@ -125,7 +125,7 @@ describe('File finder item spec', () => { expect(el.querySelectorAll('.highlighted').length).toBe(4); }); - it('does not add ellipsis to long text', done => { + it('does not add ellipsis to long text', (done) => { vm.file.name = new Array(70) .fill() .map((_, i) => `${i}-`) diff --git a/spec/frontend/vue_shared/components/file_tree_spec.js b/spec/frontend/vue_shared/components/file_tree_spec.js index 38979d9d844..7a4982fd29b 100644 --- a/spec/frontend/vue_shared/components/file_tree_spec.js +++ b/spec/frontend/vue_shared/components/file_tree_spec.js @@ -28,7 +28,7 @@ describe('File Tree component', () => { const findFileRow = () => wrapper.find(MockFileRow); const findChildrenTrees = () => wrapper.findAll(FileTree).wrappers.slice(1); const findChildrenTreeProps = () => - findChildrenTrees().map(x => ({ + findChildrenTrees().map((x) => ({ ...x.props(), ...pick(x.attributes(), Object.keys(TEST_EXTA_ARGS)), })); @@ -61,7 +61,7 @@ describe('File Tree component', () => { describe('file tree', () => { const createChildren = () => [{ id: 1 }, { id: 2 }]; const createChildrenExpectation = (props = {}) => - createChildren().map(file => ({ + createChildren().map((file) => ({ fileRowComponent: MockFileRow, file, ...TEST_EXTA_ARGS, diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/filtered_search_bar_root_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/filtered_search_bar_root_spec.js index 8cc5d6775a7..b58ce0083c0 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/filtered_search_bar_root_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/filtered_search_bar_root_spec.js @@ -25,10 +25,11 @@ import { tokenValueLabel, tokenValueMilestone, tokenValueMembership, + tokenValueConfidential, } from './mock_data'; jest.mock('~/vue_shared/components/filtered_search_bar/filtered_search_utils', () => ({ - uniqueTokens: jest.fn().mockImplementation(tokens => tokens), + uniqueTokens: jest.fn().mockImplementation((tokens) => tokens), stripQuotes: jest.requireActual( '~/vue_shared/components/filtered_search_bar/filtered_search_utils', ).stripQuotes, @@ -227,12 +228,13 @@ describe('FilteredSearchBarRoot', () => { }); describe('removeQuotesEnclosure', () => { - const mockFilters = [tokenValueAuthor, tokenValueLabel, 'foo']; + const mockFilters = [tokenValueAuthor, tokenValueLabel, tokenValueConfidential, 'foo']; it('returns filter array with unescaped strings for values which have spaces', () => { expect(wrapper.vm.removeQuotesEnclosure(mockFilters)).toEqual([ tokenValueAuthor, tokenValueLabel, + tokenValueConfidential, 'foo', ]); }); diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/filtered_search_utils_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/filtered_search_utils_spec.js index 4869e75a2f3..9e96c154546 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/filtered_search_utils_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/filtered_search_utils_spec.js @@ -82,7 +82,10 @@ describe('prepareTokens', () => { ], [ 'assignees', - [{ value: 'krillin', operator: '=' }, { value: 'piccolo', operator: '!=' }], + [ + { value: 'krillin', operator: '=' }, + { value: 'piccolo', operator: '!=' }, + ], [ { type: 'assignees', value: { data: 'krillin', operator: '=' } }, { type: 'assignees', value: { data: 'piccolo', operator: '!=' } }, @@ -90,7 +93,10 @@ describe('prepareTokens', () => { ], [ 'foo', - [{ value: 'bar', operator: '!=' }, { value: 'baz', operator: '!=' }], + [ + { value: 'bar', operator: '!=' }, + { value: 'baz', operator: '!=' }, + ], [ { type: 'foo', value: { data: 'bar', operator: '!=' } }, { type: 'foo', value: { data: 'baz', operator: '!=' } }, @@ -112,7 +118,10 @@ describe('processFilters', () => { expect(result).toStrictEqual({ foo: [{ value: 'foo', operator: '=' }], - bar: [{ value: 'bar1', operator: '=' }, { value: 'bar2', operator: '!=' }], + bar: [ + { value: 'bar1', operator: '=' }, + { value: 'bar2', operator: '!=' }, + ], }); }); @@ -164,17 +173,26 @@ describe('filterToQueryObject', () => { ], [ 'foo', - [{ value: 'bar', operator: '=' }, { value: 'baz', operator: '=' }], + [ + { value: 'bar', operator: '=' }, + { value: 'baz', operator: '=' }, + ], { foo: ['bar', 'baz'], 'not[foo]': null }, ], [ 'foo', - [{ value: 'bar', operator: '!=' }, { value: 'baz', operator: '!=' }], + [ + { value: 'bar', operator: '!=' }, + { value: 'baz', operator: '!=' }, + ], { foo: null, 'not[foo]': ['bar', 'baz'] }, ], [ 'foo', - [{ value: 'bar', operator: '!=' }, { value: 'baz', operator: '=' }], + [ + { value: 'bar', operator: '!=' }, + { value: 'baz', operator: '=' }, + ], { foo: ['baz'], 'not[foo]': ['bar'] }, ], ])('gathers filter values %s=%j into query object=%j', (token, value, result) => { @@ -200,15 +218,30 @@ describe('urlQueryToFilter', () => { ['not[foo]=bar&foo=baz', { foo: { value: 'baz', operator: '=' } }], [ 'foo[]=bar&foo[]=baz¬[foo]=', - { foo: [{ value: 'bar', operator: '=' }, { value: 'baz', operator: '=' }] }, + { + foo: [ + { value: 'bar', operator: '=' }, + { value: 'baz', operator: '=' }, + ], + }, ], [ 'foo[]=¬[foo][]=bar¬[foo][]=baz', - { foo: [{ value: 'bar', operator: '!=' }, { value: 'baz', operator: '!=' }] }, + { + foo: [ + { value: 'bar', operator: '!=' }, + { value: 'baz', operator: '!=' }, + ], + }, ], [ 'foo[]=baz¬[foo][]=bar', - { foo: [{ value: 'baz', operator: '=' }, { value: 'bar', operator: '!=' }] }, + { + foo: [ + { value: 'baz', operator: '=' }, + { value: 'bar', operator: '!=' }, + ], + }, ], ['not[foo][]=bar', { foo: [{ value: 'bar', operator: '!=' }] }], ])('gathers filter values %s into query object=%j', (query, result) => { diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js b/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js index 64fbe70696d..7606b3bd91c 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/mock_data.js @@ -110,7 +110,10 @@ export const mockMembershipToken = { token: GlFilteredSearchToken, unique: true, operators: [{ value: '=', description: 'is' }], - options: [{ value: 'exclude', title: 'Direct' }, { value: 'only', title: 'Inherited' }], + options: [ + { value: 'exclude', title: 'Direct' }, + { value: 'only', title: 'Inherited' }, + ], }; export const mockMembershipTokenOptionsWithoutTitles = { @@ -152,6 +155,14 @@ export const tokenValueMembership = { }, }; +export const tokenValueConfidential = { + type: 'confidential', + value: { + operator: '=', + data: true, + }, +}; + export const tokenValuePlain = { type: 'filtered-search-term', value: { data: 'foo' }, diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/test_helper.js b/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/test_helper.js index 1b7c80a5252..84297923df3 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/test_helper.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/test_helper.js @@ -1,11 +1,11 @@ export function getFilterParams(tokens, options = {}) { const { key = 'value', operator = '=', prop = 'title' } = options; - return tokens.map(token => { + return tokens.map((token) => { return { [key]: token[prop], operator }; }); } export function getFilterValues(tokens, options = {}) { const { prop = 'title' } = options; - return tokens.map(token => token[prop]); + return tokens.map((token) => token[prop]); } diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js index 3fd1d8b7f42..3997d6a99a6 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js @@ -189,8 +189,8 @@ describe('AuthorToken', () => { suggestionsSegment.vm.$emit('activate'); await wrapper.vm.$nextTick(); - expect(wrapper.contains(GlFilteredSearchSuggestion)).toBe(false); - expect(wrapper.contains(GlDropdownDivider)).toBe(false); + expect(wrapper.find(GlFilteredSearchSuggestion).exists()).toBe(false); + expect(wrapper.find(GlDropdownDivider).exists()).toBe(false); }); it('renders `DEFAULT_LABEL_ANY` as default suggestions', async () => { diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js index 5b7f7d242e9..35f487330be 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js @@ -189,8 +189,8 @@ describe('BranchToken', () => { }); await showSuggestions(); - expect(wrapper.contains(GlFilteredSearchSuggestion)).toBe(false); - expect(wrapper.contains(GlDropdownDivider)).toBe(false); + expect(wrapper.find(GlFilteredSearchSuggestion).exists()).toBe(false); + expect(wrapper.find(GlDropdownDivider).exists()).toBe(false); }); it('renders no suggestions as default', async () => { diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js index 74172db81c2..dda0ad39bbc 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js @@ -181,12 +181,9 @@ describe('LabelToken', () => { expect(tokenSegments).toHaveLength(3); // Label, =, "Foo Label" expect(tokenSegments.at(2).text()).toBe(`~${mockRegularLabel.title}`); // "Foo Label" - expect( - tokenSegments - .at(2) - .find('.gl-token') - .attributes('style'), - ).toBe('background-color: rgb(186, 218, 85); color: rgb(255, 255, 255);'); + expect(tokenSegments.at(2).find('.gl-token').attributes('style')).toBe( + 'background-color: rgb(186, 218, 85); color: rgb(255, 255, 255);', + ); }); it('renders provided defaultLabels as suggestions', async () => { @@ -219,8 +216,8 @@ describe('LabelToken', () => { suggestionsSegment.vm.$emit('activate'); await wrapper.vm.$nextTick(); - expect(wrapper.contains(GlFilteredSearchSuggestion)).toBe(false); - expect(wrapper.contains(GlDropdownDivider)).toBe(false); + expect(wrapper.find(GlFilteredSearchSuggestion).exists()).toBe(false); + expect(wrapper.find(GlDropdownDivider).exists()).toBe(false); }); it('renders `DEFAULT_LABELS` as default suggestions', async () => { diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/milestone_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/milestone_token_spec.js index 67f9a9c70cc..164561f6244 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/milestone_token_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/milestone_token_spec.js @@ -140,7 +140,10 @@ describe('MilestoneToken', () => { }); describe('template', () => { - const defaultMilestones = [{ text: 'foo', value: 'foo' }, { text: 'bar', value: 'baz' }]; + const defaultMilestones = [ + { text: 'foo', value: 'foo' }, + { text: 'bar', value: 'baz' }, + ]; beforeEach(async () => { wrapper = createComponent({ value: { data: `"${mockRegularMilestone.title}"` } }); @@ -193,8 +196,8 @@ describe('MilestoneToken', () => { suggestionsSegment.vm.$emit('activate'); await wrapper.vm.$nextTick(); - expect(wrapper.contains(GlFilteredSearchSuggestion)).toBe(false); - expect(wrapper.contains(GlDropdownDivider)).toBe(false); + expect(wrapper.find(GlFilteredSearchSuggestion).exists()).toBe(false); + expect(wrapper.find(GlDropdownDivider).exists()).toBe(false); }); it('renders `DEFAULT_MILESTONES` as default suggestions', async () => { diff --git a/spec/frontend/vue_shared/components/gfm_autocomplete/__snapshots__/utils_spec.js.snap b/spec/frontend/vue_shared/components/gfm_autocomplete/__snapshots__/utils_spec.js.snap index d0fa2086fdc..d8e6e37bb89 100644 --- a/spec/frontend/vue_shared/components/gfm_autocomplete/__snapshots__/utils_spec.js.snap +++ b/spec/frontend/vue_shared/components/gfm_autocomplete/__snapshots__/utils_spec.js.snap @@ -1,5 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`gfm_autocomplete/utils emojis config shows the emoji name and icon in the menu item 1`] = ` +"raised_hands + <gl-emoji + + data-name=\\"raised_hands\\"></gl-emoji> + " +`; + exports[`gfm_autocomplete/utils issues config shows the iid and title in the menu item within a project context 1`] = `"<small>123456</small> Project context issue title <script>alert('hi')</script>"`; exports[`gfm_autocomplete/utils issues config shows the reference and title in the menu item within a group context 1`] = `"<small>gitlab#987654</small> Group context issue title <script>alert('hi')</script>"`; @@ -44,4 +52,9 @@ exports[`gfm_autocomplete/utils merge requests config shows the reference and ti exports[`gfm_autocomplete/utils milestones config shows the title in the menu item 1`] = `"13.2 <script>alert('hi')</script>"`; +exports[`gfm_autocomplete/utils quick actions config shows the name, aliases, params and description in the menu item 1`] = ` +"<div>/unlabel <small>(or /remove_label)</small> <small>~label1 ~\\"label 2\\"</small></div> + <div><small><em>Remove all or specific label(s)</em></small></div>" +`; + exports[`gfm_autocomplete/utils snippets config shows the id and title in the menu item 1`] = `"<small>123456</small> Snippet title <script>alert('hi')</script>"`; diff --git a/spec/frontend/vue_shared/components/gfm_autocomplete/utils_spec.js b/spec/frontend/vue_shared/components/gfm_autocomplete/utils_spec.js index 647f8c6e000..7ec3fbd4e3b 100644 --- a/spec/frontend/vue_shared/components/gfm_autocomplete/utils_spec.js +++ b/spec/frontend/vue_shared/components/gfm_autocomplete/utils_spec.js @@ -2,6 +2,31 @@ import { escape, last } from 'lodash'; import { GfmAutocompleteType, tributeConfig } from '~/vue_shared/components/gfm_autocomplete/utils'; describe('gfm_autocomplete/utils', () => { + describe('emojis config', () => { + const emojisConfig = tributeConfig[GfmAutocompleteType.Emojis].config; + const emoji = 'raised_hands'; + + it('uses : as the trigger', () => { + expect(emojisConfig.trigger).toBe(':'); + }); + + it('searches using the emoji name', () => { + expect(emojisConfig.lookup(emoji)).toBe(emoji); + }); + + it('limits the number of rendered items to 100', () => { + expect(emojisConfig.menuItemLimit).toBe(100); + }); + + it('shows the emoji name and icon in the menu item', () => { + expect(emojisConfig.menuItemTemplate({ original: emoji })).toMatchSnapshot(); + }); + + it('inserts the emoji name on autocomplete selection', () => { + expect(emojisConfig.selectTemplate({ original: emoji })).toBe(`:${emoji}:`); + }); + }); + describe('issues config', () => { const issuesConfig = tributeConfig[GfmAutocompleteType.Issues].config; const groupContextIssue = { @@ -26,6 +51,10 @@ describe('gfm_autocomplete/utils', () => { ); }); + it('limits the number of rendered items to 100', () => { + expect(issuesConfig.menuItemLimit).toBe(100); + }); + it('shows the reference and title in the menu item within a group context', () => { expect(issuesConfig.menuItemTemplate({ original: groupContextIssue })).toMatchSnapshot(); }); @@ -77,6 +106,10 @@ describe('gfm_autocomplete/utils', () => { expect(labelsConfig.lookup).toBe('title'); }); + it('limits the number of rendered items to 100', () => { + expect(labelsConfig.menuItemLimit).toBe(100); + }); + it('shows the title in the menu item', () => { expect(labelsConfig.menuItemTemplate({ original: label })).toMatchSnapshot(); }); @@ -180,6 +213,10 @@ describe('gfm_autocomplete/utils', () => { expect(membersConfig.lookup(groupMember)).toBe(last(groupMember.name.split(' / '))); }); + it('limits the items in the autocomplete menu to 10', () => { + expect(membersConfig.menuItemLimit).toBe(10); + }); + it('shows the avatar, name and username in the menu item for a user', () => { expect(membersConfig.menuItemTemplate({ original: userMember })).toMatchSnapshot(); }); @@ -266,6 +303,10 @@ describe('gfm_autocomplete/utils', () => { ); }); + it('limits the number of rendered items to 100', () => { + expect(mergeRequestsConfig.menuItemLimit).toBe(100); + }); + it('shows the reference and title in the menu item within a group context', () => { expect( mergeRequestsConfig.menuItemTemplate({ original: groupContextMergeRequest }), @@ -307,6 +348,10 @@ describe('gfm_autocomplete/utils', () => { expect(milestonesConfig.lookup).toBe('title'); }); + it('limits the number of rendered items to 100', () => { + expect(milestonesConfig.menuItemLimit).toBe(100); + }); + it('shows the title in the menu item', () => { expect(milestonesConfig.menuItemTemplate({ original: milestone })).toMatchSnapshot(); }); @@ -318,6 +363,40 @@ describe('gfm_autocomplete/utils', () => { }); }); + describe('quick actions config', () => { + const quickActionsConfig = tributeConfig[GfmAutocompleteType.QuickActions].config; + const quickAction = { + name: 'unlabel', + aliases: ['remove_label'], + description: 'Remove all or specific label(s)', + warning: '', + icon: '', + params: ['~label1 ~"label 2"'], + }; + + it('uses / as the trigger', () => { + expect(quickActionsConfig.trigger).toBe('/'); + }); + + it('inserts the name on autocomplete selection', () => { + expect(quickActionsConfig.fillAttr).toBe('name'); + }); + + it('searches using both the name and aliases', () => { + expect(quickActionsConfig.lookup(quickAction)).toBe( + `${quickAction.name}${quickAction.aliases.join(', /')}`, + ); + }); + + it('limits the number of rendered items to 100', () => { + expect(quickActionsConfig.menuItemLimit).toBe(100); + }); + + it('shows the name, aliases, params and description in the menu item', () => { + expect(quickActionsConfig.menuItemTemplate({ original: quickAction })).toMatchSnapshot(); + }); + }); + describe('snippets config', () => { const snippetsConfig = tributeConfig[GfmAutocompleteType.Snippets].config; const snippet = { @@ -337,6 +416,10 @@ describe('gfm_autocomplete/utils', () => { expect(snippetsConfig.lookup(snippet)).toBe(`${snippet.id}${snippet.title}`); }); + it('limits the number of rendered items to 100', () => { + expect(snippetsConfig.menuItemLimit).toBe(100); + }); + it('shows the id and title in the menu item', () => { expect(snippetsConfig.menuItemTemplate({ original: snippet })).toMatchSnapshot(); }); diff --git a/spec/frontend/vue_shared/components/gl_countdown_spec.js b/spec/frontend/vue_shared/components/gl_countdown_spec.js index 365c9fad478..fcc5c0cd310 100644 --- a/spec/frontend/vue_shared/components/gl_countdown_spec.js +++ b/spec/frontend/vue_shared/components/gl_countdown_spec.js @@ -17,21 +17,19 @@ describe('GlCountdown', () => { }); describe('when there is time remaining', () => { - beforeEach(done => { + beforeEach((done) => { vm = mountComponent(Component, { endDateString: '2000-01-01T01:02:03Z', }); - Vue.nextTick() - .then(done) - .catch(done.fail); + Vue.nextTick().then(done).catch(done.fail); }); it('displays remaining time', () => { expect(vm.$el.textContent).toContain('01:02:03'); }); - it('updates remaining time', done => { + it('updates remaining time', (done) => { now = '2000-01-01T00:00:01Z'; jest.advanceTimersByTime(1000); @@ -45,14 +43,12 @@ describe('GlCountdown', () => { }); describe('when there is no time remaining', () => { - beforeEach(done => { + beforeEach((done) => { vm = mountComponent(Component, { endDateString: '1900-01-01T00:00:00Z', }); - Vue.nextTick() - .then(done) - .catch(done.fail); + Vue.nextTick().then(done).catch(done.fail); }); it('displays 00:00:00', () => { diff --git a/spec/frontend/vue_shared/components/gl_modal_vuex_spec.js b/spec/frontend/vue_shared/components/gl_modal_vuex_spec.js index 93f4db5df18..6802499ed52 100644 --- a/spec/frontend/vue_shared/components/gl_modal_vuex_spec.js +++ b/spec/frontend/vue_shared/components/gl_modal_vuex_spec.js @@ -118,7 +118,7 @@ describe('GlModalVuex', () => { expect(actions.hide).toHaveBeenCalledTimes(1); }); - it('calls bootstrap show when isVisible changes', done => { + it('calls bootstrap show when isVisible changes', (done) => { state.isVisible = false; factory(); @@ -135,7 +135,7 @@ describe('GlModalVuex', () => { .catch(done.fail); }); - it('calls bootstrap hide when isVisible changes', done => { + it('calls bootstrap hide when isVisible changes', (done) => { state.isVisible = true; factory(); @@ -154,7 +154,7 @@ describe('GlModalVuex', () => { it.each(['ok', 'cancel'])( 'passes an "%s" handler to the "modal-footer" slot scope', - handlerName => { + (handlerName) => { state.isVisible = true; const modalFooterSlotContent = jest.fn(); diff --git a/spec/frontend/vue_shared/components/issuable/issuable_header_warnings_spec.js b/spec/frontend/vue_shared/components/issuable/issuable_header_warnings_spec.js index 2f910a10bc6..a03a3915e1b 100644 --- a/spec/frontend/vue_shared/components/issuable/issuable_header_warnings_spec.js +++ b/spec/frontend/vue_shared/components/issuable/issuable_header_warnings_spec.js @@ -17,13 +17,13 @@ describe('IssuableHeaderWarnings', () => { const findConfidentialIcon = () => wrapper.find('[data-testid="confidential"]'); const findLockedIcon = () => wrapper.find('[data-testid="locked"]'); - const renderTestMessage = renders => (renders ? 'renders' : 'does not render'); + const renderTestMessage = (renders) => (renders ? 'renders' : 'does not render'); - const setLock = locked => { + const setLock = (locked) => { store.getters.getNoteableData.discussion_locked = locked; }; - const setConfidential = confidential => { + const setConfidential = (confidential) => { store.getters.getNoteableData.confidential = confidential; }; diff --git a/spec/frontend/vue_shared/components/issue/issue_assignees_spec.js b/spec/frontend/vue_shared/components/issue/issue_assignees_spec.js index 192e33d8b00..5f614bfc751 100644 --- a/spec/frontend/vue_shared/components/issue/issue_assignees_spec.js +++ b/spec/frontend/vue_shared/components/issue/issue_assignees_spec.js @@ -11,7 +11,7 @@ describe('IssueAssigneesComponent', () => { let wrapper; let vm; - const factory = props => { + const factory = (props) => { wrapper = shallowMount(IssueAssignees, { propsData: { assignees: mockAssigneesList, @@ -99,11 +99,11 @@ describe('IssueAssigneesComponent', () => { }); it('renders assignee', () => { - const data = findAvatars().wrappers.map(x => ({ + const data = findAvatars().wrappers.map((x) => ({ ...x.props(), })); - const expected = mockAssigneesList.slice(0, TEST_MAX_VISIBLE - 1).map(x => + const expected = mockAssigneesList.slice(0, TEST_MAX_VISIBLE - 1).map((x) => expect.objectContaining({ linkHref: x.web_url, imgAlt: `Avatar for ${x.name}`, diff --git a/spec/frontend/vue_shared/components/issue/issue_milestone_spec.js b/spec/frontend/vue_shared/components/issue/issue_milestone_spec.js index d1bfc180082..ffcb891c4fc 100644 --- a/spec/frontend/vue_shared/components/issue/issue_milestone_spec.js +++ b/spec/frontend/vue_shared/components/issue/issue_milestone_spec.js @@ -19,7 +19,7 @@ describe('IssueMilestoneComponent', () => { let wrapper; let vm; - beforeEach(done => { + beforeEach((done) => { wrapper = createComponent(); ({ vm } = wrapper); diff --git a/spec/frontend/vue_shared/components/issue/related_issuable_item_spec.js b/spec/frontend/vue_shared/components/issue/related_issuable_item_spec.js index 2319bf61482..3dc34583118 100644 --- a/spec/frontend/vue_shared/components/issue/related_issuable_item_spec.js +++ b/spec/frontend/vue_shared/components/issue/related_issuable_item_spec.js @@ -1,5 +1,5 @@ import { mount } from '@vue/test-utils'; -import { TEST_HOST } from 'jest/helpers/test_constants'; +import { TEST_HOST } from 'helpers/test_constants'; import { formatDate } from '~/lib/utils/datetime_utility'; import RelatedIssuableItem from '~/vue_shared/components/issue/related_issuable_item.vue'; import IssueDueDate from '~/boards/components/issue_due_date.vue'; @@ -115,9 +115,7 @@ describe('RelatedIssuableItem', () => { const tokenMetadata = () => wrapper.find('.item-meta'); it('renders item path and ID', () => { - const pathAndID = tokenMetadata() - .find('.item-path-id') - .text(); + const pathAndID = tokenMetadata().find('.item-path-id').text(); expect(pathAndID).toContain('gitlab-org/gitlab-test'); expect(pathAndID).toContain('#1'); diff --git a/spec/frontend/vue_shared/components/issue/related_issuable_mock_data.js b/spec/frontend/vue_shared/components/issue/related_issuable_mock_data.js index 17813f2833d..6cdb945ec20 100644 --- a/spec/frontend/vue_shared/components/issue/related_issuable_mock_data.js +++ b/spec/frontend/vue_shared/components/issue/related_issuable_mock_data.js @@ -1,4 +1,4 @@ -import { TEST_HOST } from 'jest/helpers/test_constants'; +import { TEST_HOST } from 'helpers/test_constants'; export const defaultProps = { endpoint: '/foo/bar/issues/1/related_issues', diff --git a/spec/frontend/vue_shared/components/local_storage_sync_spec.js b/spec/frontend/vue_shared/components/local_storage_sync_spec.js index 464fe3411dd..4c5a0c1e601 100644 --- a/spec/frontend/vue_shared/components/local_storage_sync_spec.js +++ b/spec/frontend/vue_shared/components/local_storage_sync_spec.js @@ -49,7 +49,7 @@ describe('Local Storage Sync', () => { it.each('foo', 3, true, ['foo', 'bar'], { foo: 'bar' })( 'saves updated value to localStorage', - newValue => { + (newValue) => { createComponent({ props: { storageKey, diff --git a/spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap b/spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap index b8a9143bc79..c454166e30b 100644 --- a/spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap +++ b/spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap @@ -7,6 +7,7 @@ exports[`Suggestion Diff component matches snapshot 1`] = ` <suggestion-diff-header-stub batchsuggestionscount="1" class="qa-suggestion-diff-header js-suggestion-diff-header" + defaultcommitmessage="Apply suggestion" helppagepath="path_to_docs" isapplyingbatch="true" isbatched="true" diff --git a/spec/frontend/vue_shared/components/markdown/apply_suggestion_spec.js b/spec/frontend/vue_shared/components/markdown/apply_suggestion_spec.js index 0598506891b..b9f0d88548d 100644 --- a/spec/frontend/vue_shared/components/markdown/apply_suggestion_spec.js +++ b/spec/frontend/vue_shared/components/markdown/apply_suggestion_spec.js @@ -3,10 +3,10 @@ import { GlDropdown, GlFormTextarea, GlButton } from '@gitlab/ui'; import ApplySuggestionComponent from '~/vue_shared/components/markdown/apply_suggestion.vue'; describe('Apply Suggestion component', () => { - const propsData = { fileName: 'test.js', disabled: false }; + const propsData = { defaultCommitMessage: 'Apply suggestion', disabled: false }; let wrapper; - const createWrapper = props => { + const createWrapper = (props) => { wrapper = shallowMount(ApplySuggestionComponent, { propsData: { ...propsData, ...props } }); }; @@ -27,7 +27,6 @@ describe('Apply Suggestion component', () => { expect(dropdown.exists()).toBe(true); expect(dropdown.props('text')).toBe('Apply suggestion'); - expect(dropdown.props('headerText')).toBe('Apply suggestion commit message'); expect(dropdown.props('disabled')).toBe(false); }); @@ -35,7 +34,7 @@ describe('Apply Suggestion component', () => { const textArea = findTextArea(); expect(textArea.exists()).toBe(true); - expect(textArea.attributes('placeholder')).toBe('Apply suggestion on test.js'); + expect(textArea.attributes('placeholder')).toBe('Apply suggestion'); }); it('renders an apply button', () => { @@ -55,11 +54,11 @@ describe('Apply Suggestion component', () => { }); describe('apply suggestion', () => { - it('emits an apply event with a default message if no message was added', () => { + it('emits an apply event with no message if no message was added', () => { findTextArea().vm.$emit('input', null); findApplyButton().vm.$emit('click'); - expect(wrapper.emitted('apply')).toEqual([['Apply suggestion on test.js']]); + expect(wrapper.emitted('apply')).toEqual([[null]]); }); it('emits an apply event with a user-defined message', () => { diff --git a/spec/frontend/vue_shared/components/markdown/header_spec.js b/spec/frontend/vue_shared/components/markdown/header_spec.js index 82bc9b9fe08..077c2174571 100644 --- a/spec/frontend/vue_shared/components/markdown/header_spec.js +++ b/spec/frontend/vue_shared/components/markdown/header_spec.js @@ -6,7 +6,7 @@ import ToolbarButton from '~/vue_shared/components/markdown/toolbar_button.vue'; describe('Markdown field header component', () => { let wrapper; - const createWrapper = props => { + const createWrapper = (props) => { wrapper = shallowMount(HeaderComponent, { propsData: { previewMarkdown: false, @@ -18,7 +18,7 @@ describe('Markdown field header component', () => { const findToolbarButtons = () => wrapper.findAll(ToolbarButton); const findToolbarButtonByProp = (prop, value) => findToolbarButtons() - .filter(button => button.props(prop) === value) + .filter((button) => button.props(prop) === value) .at(0); beforeEach(() => { diff --git a/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js b/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js index c0a000690f8..bf65adc866d 100644 --- a/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js +++ b/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js @@ -9,6 +9,7 @@ const DEFAULT_PROPS = { isBatched: false, isApplyingBatch: false, helpPagePath: 'path_to_docs', + defaultCommitMessage: 'Apply suggestion', }; describe('Suggestion Diff component', () => { @@ -91,7 +92,7 @@ describe('Suggestion Diff component', () => { }); it('emits apply', () => { - expect(wrapper.emitted().apply).toEqual([[expect.any(Function)]]); + expect(wrapper.emitted().apply).toEqual([[expect.any(Function), undefined]]); }); it('does not render apply suggestion and add to batch buttons', () => { diff --git a/spec/frontend/vue_shared/components/markdown/suggestion_diff_row_spec.js b/spec/frontend/vue_shared/components/markdown/suggestion_diff_row_spec.js index b67f4cf12bf..f9a8b64f89b 100644 --- a/spec/frontend/vue_shared/components/markdown/suggestion_diff_row_spec.js +++ b/spec/frontend/vue_shared/components/markdown/suggestion_diff_row_spec.js @@ -61,11 +61,7 @@ describe('SuggestionDiffRow', () => { }); expect(wrapper.classes()).toContain('line_holder'); - expect( - findSuggestionContent() - .find('span') - .classes(), - ).toContain('line'); + expect(findSuggestionContent().find('span').classes()).toContain('line'); }); it('renders the rich text when it is available', () => { diff --git a/spec/frontend/vue_shared/components/markdown/suggestion_diff_spec.js b/spec/frontend/vue_shared/components/markdown/suggestion_diff_spec.js index 232feb126dc..5bd6bda2d2c 100644 --- a/spec/frontend/vue_shared/components/markdown/suggestion_diff_spec.js +++ b/spec/frontend/vue_shared/components/markdown/suggestion_diff_spec.js @@ -42,6 +42,7 @@ const MOCK_DATA = { is_applying_batch: true, }, helpPagePath: 'path_to_docs', + defaultCommitMessage: 'Apply suggestion', batchSuggestionsInfo: [{ suggestionId }], }; diff --git a/spec/frontend/vue_shared/components/markdown/suggestions_spec.js b/spec/frontend/vue_shared/components/markdown/suggestions_spec.js index 34ccdf38b00..6fcac2df0b6 100644 --- a/spec/frontend/vue_shared/components/markdown/suggestions_spec.js +++ b/spec/frontend/vue_shared/components/markdown/suggestions_spec.js @@ -44,13 +44,14 @@ const MOCK_DATA = { `, isApplied: false, helpPagePath: 'path_to_docs', + defaultCommitMessage: 'Apply suggestion', }; describe('Suggestion component', () => { let vm; let diffTable; - beforeEach(done => { + beforeEach((done) => { const Component = Vue.extend(SuggestionsComponent); vm = new Component({ @@ -86,7 +87,7 @@ describe('Suggestion component', () => { }); it('generates a diff table that contains contents the suggested lines', () => { - MOCK_DATA.suggestions[0].diff_lines.forEach(line => { + MOCK_DATA.suggestions[0].diff_lines.forEach((line) => { const text = line.text.substring(1); expect(diffTable.innerHTML.includes(text)).toBe(true); diff --git a/spec/frontend/vue_shared/components/markdown/toolbar_button_spec.js b/spec/frontend/vue_shared/components/markdown/toolbar_button_spec.js index 8a7946fd7b1..786dfabb990 100644 --- a/spec/frontend/vue_shared/components/markdown/toolbar_button_spec.js +++ b/spec/frontend/vue_shared/components/markdown/toolbar_button_spec.js @@ -10,7 +10,7 @@ describe('toolbar_button', () => { tag: 'test tag', }; - const createComponent = propUpdates => { + const createComponent = (propUpdates) => { wrapper = shallowMount(ToolbarButton, { propsData: { ...defaultProps, diff --git a/spec/frontend/vue_shared/components/navigation_tabs_spec.js b/spec/frontend/vue_shared/components/navigation_tabs_spec.js index 561456d614e..b1119bfb150 100644 --- a/spec/frontend/vue_shared/components/navigation_tabs_spec.js +++ b/spec/frontend/vue_shared/components/navigation_tabs_spec.js @@ -1,64 +1,68 @@ -import Vue from 'vue'; -import mountComponent from 'helpers/vue_mount_component_helper'; -import navigationTabs from '~/vue_shared/components/navigation_tabs.vue'; +import { mount } from '@vue/test-utils'; +import { GlTab } from '@gitlab/ui'; +import NavigationTabs from '~/vue_shared/components/navigation_tabs.vue'; describe('navigation tabs component', () => { - let vm; - let Component; - let data; + let wrapper; - beforeEach(() => { - data = [ - { - name: 'All', - scope: 'all', - count: 1, - isActive: true, - }, - { - name: 'Pending', - scope: 'pending', - count: 0, - isActive: false, - }, - { - name: 'Running', - scope: 'running', - isActive: false, + const data = [ + { + name: 'All', + scope: 'all', + count: 1, + isActive: true, + }, + { + name: 'Pending', + scope: 'pending', + count: 0, + isActive: false, + }, + { + name: 'Running', + scope: 'running', + isActive: false, + }, + ]; + + const createComponent = () => { + wrapper = mount(NavigationTabs, { + propsData: { + tabs: data, + scope: 'pipelines', }, - ]; + }); + }; - Component = Vue.extend(navigationTabs); - vm = mountComponent(Component, { tabs: data, scope: 'pipelines' }); + beforeEach(() => { + createComponent(); }); afterEach(() => { - vm.$destroy(); + wrapper.destroy(); + wrapper = null; }); it('should render tabs', () => { - expect(vm.$el.querySelectorAll('li').length).toEqual(data.length); + expect(wrapper.findAll(GlTab)).toHaveLength(data.length); }); it('should render active tab', () => { - expect(vm.$el.querySelector('.active .js-pipelines-tab-all')).toBeDefined(); + expect(wrapper.find('.js-pipelines-tab-all').classes('active')).toBe(true); }); it('should render badge', () => { - expect(vm.$el.querySelector('.js-pipelines-tab-all .badge').textContent.trim()).toEqual('1'); - expect(vm.$el.querySelector('.js-pipelines-tab-pending .badge').textContent.trim()).toEqual( - '0', - ); + expect(wrapper.find('.js-pipelines-tab-all').text()).toContain('1'); + expect(wrapper.find('.js-pipelines-tab-pending').text()).toContain('0'); }); it('should not render badge', () => { - expect(vm.$el.querySelector('.js-pipelines-tab-running .badge')).toEqual(null); + expect(wrapper.find('.js-pipelines-tab-running .badge').exists()).toBe(false); }); - it('should trigger onTabClick', () => { - jest.spyOn(vm, '$emit').mockImplementation(() => {}); - vm.$el.querySelector('.js-pipelines-tab-pending').click(); + it('should trigger onTabClick', async () => { + await wrapper.find('.js-pipelines-tab-pending').trigger('click'); - expect(vm.$emit).toHaveBeenCalledWith('onChangeTab', 'pending'); + expect(wrapper.emitted('onChangeTab')).toEqual([['pending']]); }); }); diff --git a/spec/frontend/vue_shared/components/notes/noteable_warning_spec.js b/spec/frontend/vue_shared/components/notes/noteable_warning_spec.js index 61660f79b71..cc9f05beb06 100644 --- a/spec/frontend/vue_shared/components/notes/noteable_warning_spec.js +++ b/spec/frontend/vue_shared/components/notes/noteable_warning_spec.js @@ -10,7 +10,7 @@ describe('Issue Warning Component', () => { const findConfidentialBlock = (w = wrapper) => w.find({ ref: 'confidential' }); const findLockedAndConfidentialBlock = (w = wrapper) => w.find({ ref: 'lockedAndConfidential' }); - const createComponent = props => + const createComponent = (props) => shallowMount(NoteableWarning, { propsData: { ...props, diff --git a/spec/frontend/vue_shared/components/ordered_layout_spec.js b/spec/frontend/vue_shared/components/ordered_layout_spec.js index eec153c3792..21588569d6a 100644 --- a/spec/frontend/vue_shared/components/ordered_layout_spec.js +++ b/spec/frontend/vue_shared/components/ordered_layout_spec.js @@ -29,7 +29,7 @@ describe('Ordered Layout', () => { const verifyOrder = () => wrapper .findAll('footer,header') - .wrappers.map(x => (x.element.tagName === 'FOOTER' ? 'footer' : 'header')); + .wrappers.map((x) => (x.element.tagName === 'FOOTER' ? 'footer' : 'header')); const createComponent = (props = {}) => { wrapper = mount(TestComponent, { diff --git a/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js b/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js index 0f7c8e97635..491f783622a 100644 --- a/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js +++ b/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js @@ -124,7 +124,10 @@ describe('AlertManagementEmptyState', () => { it('renders the tabs selection with valid tabs', () => { mountComponent({ props: { - statusTabs: [{ status: 'opened', title: 'Open' }, { status: 'closed', title: 'Closed' }], + statusTabs: [ + { status: 'opened', title: 'Open' }, + { status: 'closed', title: 'Closed' }, + ], }, }); @@ -216,12 +219,7 @@ describe('AlertManagementEmptyState', () => { findPagination().vm.$emit('input', 3); await wrapper.vm.$nextTick(); - expect( - findPagination() - .findAll('.page-item') - .at(0) - .text(), - ).toBe('Prev'); + expect(findPagination().findAll('.page-item').at(0).text()).toBe('Prev'); }); it('returns prevPage number', async () => { @@ -244,12 +242,7 @@ describe('AlertManagementEmptyState', () => { findPagination().vm.$emit('input', 3); await wrapper.vm.$nextTick(); - expect( - findPagination() - .findAll('.page-item') - .at(1) - .text(), - ).toBe('Next'); + expect(findPagination().findAll('.page-item').at(1).text()).toBe('Next'); }); it('returns nextPage number', async () => { diff --git a/spec/frontend/vue_shared/components/pagination_links_spec.js b/spec/frontend/vue_shared/components/pagination_links_spec.js index bf004c83c4f..ad82aee0098 100644 --- a/spec/frontend/vue_shared/components/pagination_links_spec.js +++ b/spec/frontend/vue_shared/components/pagination_links_spec.js @@ -49,7 +49,7 @@ describe('Pagination links component', () => { }); it('should provide translated text to GitLab UI pagination', () => { - Object.entries(translations).forEach(entry => { + Object.entries(translations).forEach((entry) => { expect(glPagination.vm[entry[0]]).toBe(entry[1]); }); }); diff --git a/spec/frontend/vue_shared/components/pikaday_spec.js b/spec/frontend/vue_shared/components/pikaday_spec.js index 639b4828a09..1c6876c282c 100644 --- a/spec/frontend/vue_shared/components/pikaday_spec.js +++ b/spec/frontend/vue_shared/components/pikaday_spec.js @@ -1,42 +1,41 @@ import { shallowMount } from '@vue/test-utils'; +import { GlDatepicker } from '@gitlab/ui'; import datePicker from '~/vue_shared/components/pikaday.vue'; describe('datePicker', () => { let wrapper; - beforeEach(() => { + + const buildWrapper = (propsData = {}) => { wrapper = shallowMount(datePicker, { - propsData: { - label: 'label', - }, - attachToDocument: true, + propsData, }); - }); + }; afterEach(() => { wrapper.destroy(); wrapper = null; }); + it('should emit newDateSelected when GlDatePicker emits the input event', () => { + const minDate = new Date(); + const maxDate = new Date(); + const selectedDate = new Date(); + const theDate = selectedDate.toISOString().slice(0, 10); - it('should render label text', () => { - expect( - wrapper - .find('.dropdown-toggle-text') - .text() - .trim(), - ).toEqual('label'); - }); + buildWrapper({ minDate, maxDate, selectedDate }); - it('should show calendar', () => { - expect(wrapper.find('.pika-single').element).toBeDefined(); + expect(wrapper.find(GlDatepicker).props()).toMatchObject({ + minDate, + maxDate, + value: selectedDate, + }); + wrapper.find(GlDatepicker).vm.$emit('input', selectedDate); + expect(wrapper.emitted('newDateSelected')[0][0]).toBe(theDate); }); + it('should emit the hidePicker event when GlDatePicker emits the close event', () => { + buildWrapper(); - it('should emit hidePicker event when dropdown is clicked', () => { - // Removing the bootstrap data-toggle property, - // because it interfers with our click event - delete wrapper.find('.dropdown-menu-toggle').element.dataset.toggle; - - wrapper.find('.dropdown-menu-toggle').trigger('click'); + wrapper.find(GlDatepicker).vm.$emit('close'); - expect(wrapper.emitted('hidePicker')).toEqual([[]]); + expect(wrapper.emitted('hidePicker')).toHaveLength(1); }); }); diff --git a/spec/frontend/vue_shared/components/project_avatar/default_spec.js b/spec/frontend/vue_shared/components/project_avatar/default_spec.js index 090f8b69213..0daadeebc20 100644 --- a/spec/frontend/vue_shared/components/project_avatar/default_spec.js +++ b/spec/frontend/vue_shared/components/project_avatar/default_spec.js @@ -19,7 +19,7 @@ describe('ProjectAvatarDefault component', () => { vm.$destroy(); }); - it('renders identicon if project has no avatar_url', done => { + it('renders identicon if project has no avatar_url', (done) => { const expectedText = getFirstCharacterCapitalized(projectData.name); vm.project = { @@ -38,7 +38,7 @@ describe('ProjectAvatarDefault component', () => { .catch(done.fail); }); - it('renders avatar image if project has avatar_url', done => { + it('renders avatar image if project has avatar_url', (done) => { const avatarUrl = `${TEST_HOST}/images/home/nasa.svg`; vm.project = { diff --git a/spec/frontend/vue_shared/components/project_selector/project_selector_spec.js b/spec/frontend/vue_shared/components/project_selector/project_selector_spec.js index 6d1ebe85aa0..016622fd0bb 100644 --- a/spec/frontend/vue_shared/components/project_selector/project_selector_spec.js +++ b/spec/frontend/vue_shared/components/project_selector/project_selector_spec.js @@ -18,6 +18,13 @@ describe('ProjectSelector component', () => { selected = selected.concat(allProjects.slice(0, 3)).concat(allProjects.slice(5, 8)); const findSearchInput = () => wrapper.find(GlSearchBoxByType).find('input'); + const findLegendText = () => wrapper.find('[data-testid="legend-text"]').text(); + const search = (query) => { + const searchInput = findSearchInput(); + + searchInput.setValue(query); + searchInput.trigger('input'); + }; beforeEach(() => { wrapper = mount(Vue.extend(ProjectSelector), { @@ -31,7 +38,7 @@ describe('ProjectSelector component', () => { showSearchErrorMessage: false, totalResults: searchResults.length, }, - attachToDocument: true, + attachTo: document.body, }); ({ vm } = wrapper); @@ -48,10 +55,7 @@ describe('ProjectSelector component', () => { it(`triggers a search when the search input value changes`, () => { jest.spyOn(vm, '$emit').mockImplementation(() => {}); const query = 'my test query!'; - const searchInput = findSearchInput(); - - searchInput.setValue(query); - searchInput.trigger('input'); + search(query); expect(vm.$emit).toHaveBeenCalledWith('searched', query); }); @@ -121,15 +125,21 @@ describe('ProjectSelector component', () => { `( 'is "$expected" given $count results are showing out of $total', ({ count, total, expected }) => { + search('gitlab ui'); + wrapper.setProps({ projectSearchResults: searchResults.slice(0, count), totalResults: total, }); return wrapper.vm.$nextTick().then(() => { - expect(wrapper.text()).toContain(expected); + expect(findLegendText()).toBe(expected); }); }, ); + + it('is not rendered without searching', () => { + expect(findLegendText()).toBe(''); + }); }); }); diff --git a/spec/frontend/vue_shared/components/registry/details_row_spec.js b/spec/frontend/vue_shared/components/registry/details_row_spec.js index 16a55b84787..09dacfae363 100644 --- a/spec/frontend/vue_shared/components/registry/details_row_spec.js +++ b/spec/frontend/vue_shared/components/registry/details_row_spec.js @@ -8,7 +8,7 @@ describe('DetailsRow', () => { const findIcon = () => wrapper.find(GlIcon); const findDefaultSlot = () => wrapper.find('[data-testid="default-slot"]'); - const mountComponent = props => { + const mountComponent = (props) => { wrapper = shallowMount(component, { propsData: { icon: 'clock', diff --git a/spec/frontend/vue_shared/components/registry/list_item_spec.js b/spec/frontend/vue_shared/components/registry/list_item_spec.js index 2a48bf4f2d6..33c9c808dc3 100644 --- a/spec/frontend/vue_shared/components/registry/list_item_spec.js +++ b/spec/frontend/vue_shared/components/registry/list_item_spec.js @@ -11,7 +11,7 @@ describe('list item', () => { const findRightPrimarySlot = () => wrapper.find('[data-testid="right-primary"]'); const findRightSecondarySlot = () => wrapper.find('[data-testid="right-secondary"]'); const findRightActionSlot = () => wrapper.find('[data-testid="right-action"]'); - const findDetailsSlot = name => wrapper.find(`[data-testid="${name}"]`); + const findDetailsSlot = (name) => wrapper.find(`[data-testid="${name}"]`); const findToggleDetailsButton = () => wrapper.find(GlButton); const mountComponent = (propsData, slots) => { @@ -74,14 +74,14 @@ describe('list item', () => { findToggleDetailsButton().vm.$emit('click'); await wrapper.vm.$nextTick(); - slotNames.forEach(name => { + slotNames.forEach((name) => { expect(findDetailsSlot(name).exists()).toBe(true); }); }); it('are not visible when details are not shown', () => { mountComponent({}, slotMocks); - slotNames.forEach(name => { + slotNames.forEach((name) => { expect(findDetailsSlot(name).exists()).toBe(false); }); }); diff --git a/spec/frontend/vue_shared/components/registry/metadata_item_spec.js b/spec/frontend/vue_shared/components/registry/metadata_item_spec.js index ff968ff1831..3d3cfbe13e3 100644 --- a/spec/frontend/vue_shared/components/registry/metadata_item_spec.js +++ b/spec/frontend/vue_shared/components/registry/metadata_item_spec.js @@ -1,5 +1,6 @@ import { shallowMount } from '@vue/test-utils'; import { GlIcon, GlLink } from '@gitlab/ui'; +import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; import component from '~/vue_shared/components/registry/metadata_item.vue'; import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue'; @@ -12,6 +13,9 @@ describe('Metadata Item', () => { const mountComponent = (propsData = defaultProps) => { wrapper = shallowMount(component, { propsData, + directives: { + GlTooltip: createMockDirective(), + }, }); }; @@ -24,8 +28,9 @@ describe('Metadata Item', () => { const findLink = (w = wrapper) => w.find(GlLink); const findText = () => wrapper.find('[data-testid="metadata-item-text"]'); const findTooltipOnTruncate = (w = wrapper) => w.find(TooltipOnTruncate); + const findTextTooltip = () => wrapper.find('[data-testid="text-tooltip-container"]'); - describe.each(['xs', 's', 'm', 'l', 'xl'])('size class', size => { + describe.each(['xs', 's', 'm', 'l', 'xl'])('size class', (size) => { const className = `mw-${size}`; it(`${size} is assigned correctly to text`, () => { @@ -55,6 +60,22 @@ describe('Metadata Item', () => { expect(tooltip.exists()).toBe(true); expect(tooltip.attributes('title')).toBe(defaultProps.text); }); + + describe('with tooltip prop set to something', () => { + const textTooltip = 'foo'; + it('hides tooltip_on_truncate', () => { + mountComponent({ ...defaultProps, textTooltip }); + + expect(findTooltipOnTruncate(findText()).exists()).toBe(false); + }); + + it('set the tooltip on the text', () => { + mountComponent({ ...defaultProps, textTooltip }); + + const tooltip = getBinding(findTextTooltip().element, 'gl-tooltip'); + expect(tooltip.value.title).toBe(textTooltip); + }); + }); }); describe('link', () => { diff --git a/spec/frontend/vue_shared/components/registry/title_area_spec.js b/spec/frontend/vue_shared/components/registry/title_area_spec.js index b743a663f06..fb0009ebb8d 100644 --- a/spec/frontend/vue_shared/components/registry/title_area_spec.js +++ b/spec/frontend/vue_shared/components/registry/title_area_spec.js @@ -1,4 +1,4 @@ -import { GlAvatar, GlSprintf, GlLink } from '@gitlab/ui'; +import { GlAvatar, GlSprintf, GlLink, GlSkeletonLoader } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import component from '~/vue_shared/components/registry/title_area.vue'; @@ -9,12 +9,13 @@ describe('title area', () => { const findSubHeaderSlot = () => wrapper.find('[data-testid="sub-header"]'); const findRightActionsSlot = () => wrapper.find('[data-testid="right-actions"]'); - const findMetadataSlot = name => wrapper.find(`[data-testid="${name}"]`); + const findMetadataSlot = (name) => wrapper.find(`[data-testid="${name}"]`); const findTitle = () => wrapper.find('[data-testid="title"]'); const findAvatar = () => wrapper.find(GlAvatar); const findInfoMessages = () => wrapper.findAll('[data-testid="info-message"]'); const findDynamicSlot = () => wrapper.find(`[data-testid="${DYNAMIC_SLOT}`); const findSlotOrderElements = () => wrapper.findAll('[slot-test]'); + const findSkeletonLoader = () => wrapper.find(GlSkeletonLoader); const mountComponent = ({ propsData = { title: 'foo' }, slots } = {}) => { wrapper = shallowMount(component, { @@ -96,10 +97,33 @@ describe('title area', () => { mountComponent({ slots: slotMocks }); await wrapper.vm.$nextTick(); - slotNames.forEach(name => { + slotNames.forEach((name) => { expect(findMetadataSlot(name).exists()).toBe(true); }); }); + + it('is/are hidden when metadata-loading is true', async () => { + mountComponent({ slots: slotMocks, propsData: { title: 'foo', metadataLoading: true } }); + + await wrapper.vm.$nextTick(); + slotNames.forEach((name) => { + expect(findMetadataSlot(name).exists()).toBe(false); + }); + }); + }); + + describe('metadata skeleton loader', () => { + it('is hidden when metadata loading is false', () => { + mountComponent(); + + expect(findSkeletonLoader().exists()).toBe(false); + }); + + it('is shown when metadata loading is true', () => { + mountComponent({ propsData: { metadataLoading: true } }); + + expect(findSkeletonLoader().exists()).toBe(true); + }); }); describe('dynamic slots', () => { @@ -142,16 +166,8 @@ describe('title area', () => { await wrapper.vm.$nextTick(); - expect( - findSlotOrderElements() - .at(0) - .attributes('data-testid'), - ).toBe(DYNAMIC_SLOT); - expect( - findSlotOrderElements() - .at(1) - .attributes('data-testid'), - ).toBe('metadata-foo'); + expect(findSlotOrderElements().at(0).attributes('data-testid')).toBe(DYNAMIC_SLOT); + expect(findSlotOrderElements().at(1).attributes('data-testid')).toBe('metadata-foo'); }); }); diff --git a/spec/frontend/vue_shared/components/rich_content_editor/editor_service_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/editor_service_spec.js index d79df4d0557..51619cd9578 100644 --- a/spec/frontend/vue_shared/components/rich_content_editor/editor_service_spec.js +++ b/spec/frontend/vue_shared/components/rich_content_editor/editor_service_spec.js @@ -20,7 +20,7 @@ describe('Editor Service', () => { let mockInstance; let event; let handler; - const parseHtml = str => { + const parseHtml = (str) => { const wrapper = document.createElement('div'); wrapper.innerHTML = str; return wrapper.firstChild; diff --git a/spec/frontend/vue_shared/components/rich_content_editor/modals/add_image/upload_image_tab_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/modals/add_image/upload_image_tab_spec.js index ded490b2568..81fd059ce4f 100644 --- a/spec/frontend/vue_shared/components/rich_content_editor/modals/add_image/upload_image_tab_spec.js +++ b/spec/frontend/vue_shared/components/rich_content_editor/modals/add_image/upload_image_tab_spec.js @@ -10,7 +10,7 @@ describe('Upload Image Tab', () => { afterEach(() => wrapper.destroy()); - const triggerInputEvent = size => { + const triggerInputEvent = (size) => { const file = { size, name: 'file-name.png' }; const mockEvent = new Event('input'); diff --git a/spec/frontend/vue_shared/components/rich_content_editor/modals/insert_video_modal_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/modals/insert_video_modal_spec.js index be3a4030b1d..d59d4cc1de9 100644 --- a/spec/frontend/vue_shared/components/rich_content_editor/modals/insert_video_modal_spec.js +++ b/spec/frontend/vue_shared/components/rich_content_editor/modals/insert_video_modal_spec.js @@ -8,7 +8,7 @@ describe('Insert Video Modal', () => { const findModal = () => wrapper.find(GlModal); const findUrlInput = () => wrapper.find({ ref: 'urlInput' }); - const triggerInsertVideo = url => { + const triggerInsertVideo = (url) => { const preventDefault = jest.fn(); findUrlInput().vm.$emit('input', url); findModal().vm.$emit('primary', { preventDefault }); diff --git a/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_spec.js index cd1157a1c2e..2eb353a1801 100644 --- a/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_spec.js +++ b/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_spec.js @@ -1,5 +1,5 @@ import { shallowMount } from '@vue/test-utils'; -import { mockEditorApi } from '@toast-ui/vue-editor'; +import { Editor, mockEditorApi } from '@toast-ui/vue-editor'; import RichContentEditor from '~/vue_shared/components/rich_content_editor/rich_content_editor.vue'; import AddImageModal from '~/vue_shared/components/rich_content_editor/modals/add_image/add_image_modal.vue'; import InsertVideoModal from '~/vue_shared/components/rich_content_editor/modals/insert_video_modal.vue'; @@ -17,16 +17,17 @@ import { insertVideo, registerHTMLToMarkdownRenderer, getEditorOptions, + getMarkdown, } from '~/vue_shared/components/rich_content_editor/services/editor_service'; jest.mock('~/vue_shared/components/rich_content_editor/services/editor_service', () => ({ - ...jest.requireActual('~/vue_shared/components/rich_content_editor/services/editor_service'), addCustomEventListener: jest.fn(), removeCustomEventListener: jest.fn(), addImage: jest.fn(), insertVideo: jest.fn(), registerHTMLToMarkdownRenderer: jest.fn(), getEditorOptions: jest.fn(), + getMarkdown: jest.fn(), })); describe('Rich Content Editor', () => { @@ -38,9 +39,12 @@ describe('Rich Content Editor', () => { const findAddImageModal = () => wrapper.find(AddImageModal); const findInsertVideoModal = () => wrapper.find(InsertVideoModal); - const buildWrapper = () => { + const buildWrapper = async () => { wrapper = shallowMount(RichContentEditor, { propsData: { content, imageRoot }, + stubs: { + ToastEditor: Editor, + }, }); }; @@ -89,9 +93,8 @@ describe('Rich Content Editor', () => { it('emits an input event with the changed content', () => { const changedMarkdown = '## Changed Markdown'; - const getMarkdownMock = jest.fn().mockReturnValueOnce(changedMarkdown); + getMarkdown.mockReturnValueOnce(changedMarkdown); - findEditor().setMethods({ invoke: getMarkdownMock }); findEditor().vm.$emit('change'); expect(wrapper.emitted().input[0][0]).toBe(changedMarkdown); @@ -147,6 +150,7 @@ describe('Rich Content Editor', () => { }); it('emits load event with the markdown formatted by Toast UI', () => { + mockEditorApi.getMarkdown.mockReturnValueOnce(formattedMarkdown); expect(mockEditorApi.getMarkdown).toHaveBeenCalled(); expect(wrapper.emitted('load')[0]).toEqual([{ formattedMarkdown }]); }); diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer_spec.js index 85516eae4cf..3caf03dabba 100644 --- a/spec/frontend/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer_spec.js +++ b/spec/frontend/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer_spec.js @@ -8,9 +8,9 @@ describe('rich_content_editor/services/html_to_markdown_renderer', () => { beforeEach(() => { baseRenderer = { - trim: jest.fn(input => `trimmed ${input}`), - getSpaceCollapsedText: jest.fn(input => `space collapsed ${input}`), - getSpaceControlled: jest.fn(input => `space controlled ${input}`), + trim: jest.fn((input) => `trimmed ${input}`), + getSpaceCollapsedText: jest.fn((input) => `space collapsed ${input}`), + getSpaceControlled: jest.fn((input) => `space controlled ${input}`), convert: jest.fn(), }; diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/mock_data.js b/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/mock_data.js index 5cf3961819e..407072fb596 100644 --- a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/mock_data.js +++ b/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/mock_data.js @@ -1,12 +1,12 @@ // Node spec helpers -export const buildMockTextNode = literal => ({ literal, type: 'text' }); +export const buildMockTextNode = (literal) => ({ literal, type: 'text' }); export const normalTextNode = buildMockTextNode('This is just normal text.'); // Token spec helpers -const buildMockUneditableOpenToken = type => { +const buildMockUneditableOpenToken = (type) => { return { type: 'openTag', tagName: type, @@ -17,7 +17,7 @@ const buildMockUneditableOpenToken = type => { }; }; -const buildMockTextToken = content => { +const buildMockTextToken = (content) => { return { type: 'text', tagName: null, @@ -25,7 +25,7 @@ const buildMockTextToken = content => { }; }; -const buildMockUneditableCloseToken = type => ({ type: 'closeTag', tagName: type }); +const buildMockUneditableCloseToken = (type) => ({ type: 'closeTag', tagName: type }); export const originToken = buildMockTextToken('{:.no_toc .hidden-md .hidden-lg}'); const uneditableOpenToken = buildMockUneditableOpenToken('div'); diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_identifier_instance_text_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_identifier_instance_text_spec.js index 2897929f1bf..521885f5687 100644 --- a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_identifier_instance_text_spec.js +++ b/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_identifier_instance_text_spec.js @@ -36,7 +36,7 @@ describe('Render Identifier Instance Text renderer', () => { `( 'should return inline editable, uneditable, and editable tokens in sequence', ({ start, middle, end }) => { - const buildMockTextToken = content => ({ type: 'text', tagName: null, content }); + const buildMockTextToken = (content) => ({ type: 'text', tagName: null, content }); const startToken = buildMockTextToken(start); const middleToken = buildMockTextToken(middle); diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_identifier_paragraph_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_identifier_paragraph_spec.js index b3d9576f38b..470cf9bddaa 100644 --- a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_identifier_paragraph_spec.js +++ b/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_identifier_paragraph_spec.js @@ -2,7 +2,7 @@ import renderer from '~/vue_shared/components/rich_content_editor/services/rende import { buildMockTextNode } from './mock_data'; -const buildMockParagraphNode = literal => { +const buildMockParagraphNode = (literal) => { return { firstChild: buildMockTextNode(literal), type: 'paragraph', diff --git a/spec/frontend/vue_shared/components/rich_content_editor/toolbar_item_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/toolbar_item_spec.js index 2db15a71215..0e6f951bd53 100644 --- a/spec/frontend/vue_shared/components/rich_content_editor/toolbar_item_spec.js +++ b/spec/frontend/vue_shared/components/rich_content_editor/toolbar_item_spec.js @@ -9,7 +9,7 @@ describe('Toolbar Item', () => { const findIcon = () => wrapper.find(GlIcon); const findButton = () => wrapper.find('button'); - const buildWrapper = propsData => { + const buildWrapper = (propsData) => { wrapper = shallowMount(ToolbarItem, { propsData, directives: { diff --git a/spec/frontend/vue_shared/components/security_reports/help_icon_spec.js b/spec/frontend/vue_shared/components/security_reports/help_icon_spec.js index 60203493cbd..ae86106d86e 100644 --- a/spec/frontend/vue_shared/components/security_reports/help_icon_spec.js +++ b/spec/frontend/vue_shared/components/security_reports/help_icon_spec.js @@ -8,7 +8,7 @@ const discoverProjectSecurityPath = '/discoverProjectSecurityPath'; describe('HelpIcon component', () => { let wrapper; - const createWrapper = props => { + const createWrapper = (props) => { wrapper = shallowMount(HelpIcon, { propsData: { helpPath, diff --git a/spec/frontend/vue_shared/components/security_reports/security_summary_spec.js b/spec/frontend/vue_shared/components/security_reports/security_summary_spec.js index e57152c3cbf..f186eb848f2 100644 --- a/spec/frontend/vue_shared/components/security_reports/security_summary_spec.js +++ b/spec/frontend/vue_shared/components/security_reports/security_summary_spec.js @@ -6,7 +6,7 @@ import { groupedTextBuilder } from '~/vue_shared/security_reports/store/utils'; describe('SecuritySummary component', () => { let wrapper; - const createWrapper = message => { + const createWrapper = (message) => { wrapper = shallowMount(SecuritySummary, { propsData: { message }, stubs: { @@ -26,7 +26,7 @@ describe('SecuritySummary component', () => { groupedTextBuilder({ reportType: 'Security scanning', critical: 1, high: 0, total: 1 }), groupedTextBuilder({ reportType: 'Security scanning', critical: 0, high: 1, total: 1 }), groupedTextBuilder({ reportType: 'Security scanning', critical: 1, high: 2, total: 3 }), - ])('given the message %p', message => { + ])('given the message %p', (message) => { beforeEach(() => { createWrapper(message); }); diff --git a/spec/frontend/vue_shared/components/sidebar/collapsed_grouped_date_picker_spec.js b/spec/frontend/vue_shared/components/sidebar/collapsed_grouped_date_picker_spec.js index 08fc822577e..230442ec547 100644 --- a/spec/frontend/vue_shared/components/sidebar/collapsed_grouped_date_picker_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/collapsed_grouped_date_picker_spec.js @@ -12,7 +12,7 @@ describe('collapsedGroupedDatePicker', () => { }); describe('toggleCollapse events', () => { - beforeEach(done => { + beforeEach((done) => { jest.spyOn(vm, 'toggleSidebar').mockImplementation(() => {}); vm.minDate = new Date('07/17/2016'); Vue.nextTick(done); @@ -26,7 +26,7 @@ describe('collapsedGroupedDatePicker', () => { }); describe('minDate and maxDate', () => { - beforeEach(done => { + beforeEach((done) => { vm.minDate = new Date('07/17/2016'); vm.maxDate = new Date('07/17/2017'); Vue.nextTick(done); @@ -42,7 +42,7 @@ describe('collapsedGroupedDatePicker', () => { }); describe('minDate', () => { - beforeEach(done => { + beforeEach((done) => { vm.minDate = new Date('07/17/2016'); Vue.nextTick(done); }); @@ -56,7 +56,7 @@ describe('collapsedGroupedDatePicker', () => { }); describe('maxDate', () => { - beforeEach(done => { + beforeEach((done) => { vm.maxDate = new Date('07/17/2017'); Vue.nextTick(done); }); diff --git a/spec/frontend/vue_shared/components/sidebar/date_picker_spec.js b/spec/frontend/vue_shared/components/sidebar/date_picker_spec.js index 47edfbe3115..fc1fa3fc1c1 100644 --- a/spec/frontend/vue_shared/components/sidebar/date_picker_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/date_picker_spec.js @@ -46,12 +46,7 @@ describe('SidebarDatePicker', () => { it('should render None if there is no selectedDate', () => { mountComponent(); - expect( - wrapper - .find('.value-content span') - .text() - .trim(), - ).toEqual('None'); + expect(wrapper.find('.value-content span').text().trim()).toEqual('None'); }); it('should render date-picker when editing', () => { @@ -63,12 +58,7 @@ describe('SidebarDatePicker', () => { it('should render label', () => { const label = 'label'; mountComponent({ label }); - expect( - wrapper - .find('.title') - .text() - .trim(), - ).toEqual(label); + expect(wrapper.find('.title').text().trim()).toEqual(label); }); it('should render loading-icon when isLoading', () => { @@ -82,12 +72,7 @@ describe('SidebarDatePicker', () => { }); it('should render edit button', () => { - expect( - wrapper - .find('.title .btn-blank') - .text() - .trim(), - ).toEqual('Edit'); + expect(wrapper.find('.title .btn-blank').text().trim()).toEqual('Edit'); }); it('should enable editing when edit button is clicked', async () => { @@ -102,12 +87,7 @@ describe('SidebarDatePicker', () => { it('should render date if selectedDate', () => { mountComponent({ selectedDate: new Date('07/07/2017') }); - expect( - wrapper - .find('.value-content strong') - .text() - .trim(), - ).toEqual('Jul 7, 2017'); + expect(wrapper.find('.value-content strong').text().trim()).toEqual('Jul 7, 2017'); }); describe('selectedDate and editable', () => { @@ -116,12 +96,7 @@ describe('SidebarDatePicker', () => { }); it('should render remove button if selectedDate and editable', () => { - expect( - wrapper - .find('.value-content .btn-blank') - .text() - .trim(), - ).toEqual('remove'); + expect(wrapper.find('.value-content .btn-blank').text().trim()).toEqual('remove'); }); it('should emit saveDate with null when remove button is clicked', () => { diff --git a/spec/frontend/vue_shared/components/sidebar/issuable_move_dropdown_spec.js b/spec/frontend/vue_shared/components/sidebar/issuable_move_dropdown_spec.js index a97e26caf53..256b3cff525 100644 --- a/spec/frontend/vue_shared/components/sidebar/issuable_move_dropdown_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/issuable_move_dropdown_spec.js @@ -184,11 +184,7 @@ describe('IssuableMoveDropdown', () => { }); it('renders gl-dropdown-form component', () => { - expect( - findDropdownEl() - .find(GlDropdownForm) - .exists(), - ).toBe(true); + expect(findDropdownEl().find(GlDropdownForm).exists()).toBe(true); }); it('renders header element', () => { @@ -216,11 +212,7 @@ describe('IssuableMoveDropdown', () => { await wrapper.vm.$nextTick(); - expect( - findDropdownEl() - .find(GlLoadingIcon) - .exists(), - ).toBe(true); + expect(findDropdownEl().find(GlLoadingIcon).exists()).toBe(true); }); it('renders gl-dropdown-item components for available projects', async () => { @@ -288,10 +280,7 @@ describe('IssuableMoveDropdown', () => { await wrapper.vm.$nextTick(); expect( - wrapper - .find('[data-testid="footer"]') - .find(GlButton) - .attributes('disabled'), + wrapper.find('[data-testid="footer"]').find(GlButton).attributes('disabled'), ).not.toBeDefined(); }); }); @@ -331,10 +320,7 @@ describe('IssuableMoveDropdown', () => { }); it('close icon in dropdown header closes the dropdown when clicked', () => { - wrapper - .find('[data-testid="header"]') - .find(GlButton) - .vm.$emit('click', mockEvent); + wrapper.find('[data-testid="header"]').find(GlButton).vm.$emit('click', mockEvent); expect(wrapper.vm.$refs.dropdown.hide).toHaveBeenCalled(); }); @@ -346,10 +332,7 @@ describe('IssuableMoveDropdown', () => { await wrapper.vm.$nextTick(); - wrapper - .findAll(GlDropdownItem) - .at(0) - .vm.$emit('click', mockEvent); + wrapper.findAll(GlDropdownItem).at(0).vm.$emit('click', mockEvent); expect(wrapper.vm.selectedProject).toBe(mockProjects[0]); }); @@ -361,10 +344,7 @@ describe('IssuableMoveDropdown', () => { await wrapper.vm.$nextTick(); - wrapper - .find('[data-testid="footer"]') - .find(GlButton) - .vm.$emit('click'); + wrapper.find('[data-testid="footer"]').find(GlButton).vm.$emit('click'); expect(wrapper.vm.$refs.dropdown.hide).toHaveBeenCalled(); expect(wrapper.emitted('move-issuable')).toBeTruthy(); diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select/base_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select/base_spec.js index 596cb22fca5..a55ad37c498 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select/base_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select/base_spec.js @@ -15,7 +15,7 @@ describe('BaseComponent', () => { let wrapper; let vm; - beforeEach(done => { + beforeEach((done) => { wrapper = createComponent(); ({ vm } = wrapper); diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_create_label_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_create_label_spec.js index c2091a681f2..4b4d265800b 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_create_label_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_create_label_spec.js @@ -5,7 +5,7 @@ import dropdownCreateLabelComponent from '~/vue_shared/components/sidebar/labels import { mockSuggestedColors } from './mock_data'; -const createComponent = headerTitle => { +const createComponent = (headerTitle) => { const Component = Vue.extend(dropdownCreateLabelComponent); return mountComponent(Component, { diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed_spec.js index 71c040c6633..003f3d2b4e6 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed_spec.js @@ -37,7 +37,7 @@ describe('DropdownValueCollapsedComponent', () => { const labels = mockLabels.concat(mockLabels); const vmMoreLabels = createComponent(labels); - const expectedText = labels.map(label => label.title).join(', '); + const expectedText = labels.map((label) => label.title).join(', '); expect(vmMoreLabels.labelsList).toBe(expectedText); vmMoreLabels.$destroy(); @@ -53,7 +53,7 @@ describe('DropdownValueCollapsedComponent', () => { const expectedText = `${mockMoreLabels .slice(0, 5) - .map(label => label.title) + .map((label) => label.title) .join(', ')}, and ${mockMoreLabels.length - 5} more`; expect(vmMoreLabels.labelsList).toBe(expectedText); @@ -61,7 +61,7 @@ describe('DropdownValueCollapsedComponent', () => { }); it('returns first label name when `labels` prop has only one item present', () => { - const text = mockLabels.map(label => label.title).join(', '); + const text = mockLabels.map((label) => label.title).join(', '); expect(vm.labelsList).toBe(text); }); diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_value_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_value_spec.js index 53e8a0e1278..ecb3c3a42c8 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_value_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_value_spec.js @@ -71,12 +71,7 @@ describe('DropdownValueComponent', () => { it('render slot content inside component when `labels` prop is empty', () => { const vmEmptyLabels = createComponent([]); - expect( - vmEmptyLabels - .find('.text-secondary') - .text() - .trim(), - ).toBe(mockConfig.emptyValueText); + expect(vmEmptyLabels.find('.text-secondary').text().trim()).toBe(mockConfig.emptyValueText); vmEmptyLabels.destroy(); }); diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_create_view_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_create_view_spec.js index 04320a72be6..0f49fe4fc5b 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_create_view_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_create_view_spec.js @@ -24,7 +24,7 @@ const createComponent = (initialState = mockConfig) => { describe('DropdownContentsCreateView', () => { let wrapper; - const colors = Object.keys(mockSuggestedColors).map(color => ({ + const colors = Object.keys(mockSuggestedColors).map((color) => ({ [color]: mockSuggestedColors[color], })); @@ -125,10 +125,7 @@ describe('DropdownContentsCreateView', () => { }); it('renders dropdown back button element', () => { - const backBtnEl = wrapper - .find('.dropdown-title') - .findAll(GlButton) - .at(0); + const backBtnEl = wrapper.find('.dropdown-title').findAll(GlButton).at(0); expect(backBtnEl.exists()).toBe(true); expect(backBtnEl.attributes('aria-label')).toBe('Go back'); @@ -143,10 +140,7 @@ describe('DropdownContentsCreateView', () => { }); it('renders dropdown close button element', () => { - const closeBtnEl = wrapper - .find('.dropdown-title') - .findAll(GlButton) - .at(1); + const closeBtnEl = wrapper.find('.dropdown-title').findAll(GlButton).at(1); expect(closeBtnEl.exists()).toBe(true); expect(closeBtnEl.attributes('aria-label')).toBe('Close'); @@ -190,10 +184,7 @@ describe('DropdownContentsCreateView', () => { }); it('renders create button element', () => { - const createBtnEl = wrapper - .find('.dropdown-actions') - .findAll(GlButton) - .at(0); + const createBtnEl = wrapper.find('.dropdown-actions').findAll(GlButton).at(0); expect(createBtnEl.exists()).toBe(true); expect(createBtnEl.text()).toContain('Create'); @@ -211,10 +202,7 @@ describe('DropdownContentsCreateView', () => { }); it('renders cancel button element', () => { - const cancelBtnEl = wrapper - .find('.dropdown-actions') - .findAll(GlButton) - .at(1); + const cancelBtnEl = wrapper.find('.dropdown-actions').findAll(GlButton).at(1); expect(cancelBtnEl.exists()).toBe(true); expect(cancelBtnEl.text()).toContain('Cancel'); diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view_spec.js index 78367b3a5b4..989cd256e26 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view_spec.js @@ -371,9 +371,7 @@ describe('DropdownContentsLabelsView', () => { wrapper.vm.$store.state.allowLabelCreate = false; return wrapper.vm.$nextTick(() => { - const createLabelLink = findDropdownFooter() - .findAll(GlLink) - .at(0); + const createLabelLink = findDropdownFooter().findAll(GlLink).at(0); expect(createLabelLink.text()).not.toBe('Create label'); }); diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/actions_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/actions_spec.js index c742220ba8a..4909c43bc96 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/actions_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/actions_spec.js @@ -19,7 +19,7 @@ describe('LabelsSelect Actions', () => { }); describe('setInitialState', () => { - it('sets initial store state', done => { + it('sets initial store state', (done) => { testAction( actions.setInitialState, mockInitialState, @@ -32,7 +32,7 @@ describe('LabelsSelect Actions', () => { }); describe('toggleDropdownButton', () => { - it('toggles dropdown button', done => { + it('toggles dropdown button', (done) => { testAction( actions.toggleDropdownButton, {}, @@ -45,7 +45,7 @@ describe('LabelsSelect Actions', () => { }); describe('toggleDropdownContents', () => { - it('toggles dropdown contents', done => { + it('toggles dropdown contents', (done) => { testAction( actions.toggleDropdownContents, {}, @@ -58,7 +58,7 @@ describe('LabelsSelect Actions', () => { }); describe('toggleDropdownContentsCreateView', () => { - it('toggles dropdown create view', done => { + it('toggles dropdown create view', (done) => { testAction( actions.toggleDropdownContentsCreateView, {}, @@ -71,13 +71,13 @@ describe('LabelsSelect Actions', () => { }); describe('requestLabels', () => { - it('sets value of `state.labelsFetchInProgress` to `true`', done => { + it('sets value of `state.labelsFetchInProgress` to `true`', (done) => { testAction(actions.requestLabels, {}, state, [{ type: types.REQUEST_LABELS }], [], done); }); }); describe('receiveLabelsSuccess', () => { - it('sets provided labels to `state.labels`', done => { + it('sets provided labels to `state.labels`', (done) => { const labels = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }]; testAction( @@ -96,7 +96,7 @@ describe('LabelsSelect Actions', () => { setFixtures('<div class="flash-container"></div>'); }); - it('sets value `state.labelsFetchInProgress` to `false`', done => { + it('sets value `state.labelsFetchInProgress` to `false`', (done) => { testAction( actions.receiveLabelsFailure, {}, @@ -129,7 +129,7 @@ describe('LabelsSelect Actions', () => { }); describe('on success', () => { - it('dispatches `requestLabels` & `receiveLabelsSuccess` actions', done => { + it('dispatches `requestLabels` & `receiveLabelsSuccess` actions', (done) => { const labels = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }]; mock.onGet(/labels.json/).replyOnce(200, labels); @@ -145,7 +145,7 @@ describe('LabelsSelect Actions', () => { }); describe('on failure', () => { - it('dispatches `requestLabels` & `receiveLabelsFailure` actions', done => { + it('dispatches `requestLabels` & `receiveLabelsFailure` actions', (done) => { mock.onGet(/labels.json/).replyOnce(500, {}); testAction( @@ -161,7 +161,7 @@ describe('LabelsSelect Actions', () => { }); describe('requestCreateLabel', () => { - it('sets value `state.labelCreateInProgress` to `true`', done => { + it('sets value `state.labelCreateInProgress` to `true`', (done) => { testAction( actions.requestCreateLabel, {}, @@ -174,7 +174,7 @@ describe('LabelsSelect Actions', () => { }); describe('receiveCreateLabelSuccess', () => { - it('sets value `state.labelCreateInProgress` to `false`', done => { + it('sets value `state.labelCreateInProgress` to `false`', (done) => { testAction( actions.receiveCreateLabelSuccess, {}, @@ -191,7 +191,7 @@ describe('LabelsSelect Actions', () => { setFixtures('<div class="flash-container"></div>'); }); - it('sets value `state.labelCreateInProgress` to `false`', done => { + it('sets value `state.labelCreateInProgress` to `false`', (done) => { testAction( actions.receiveCreateLabelFailure, {}, @@ -224,7 +224,7 @@ describe('LabelsSelect Actions', () => { }); describe('on success', () => { - it('dispatches `requestCreateLabel`, `receiveCreateLabelSuccess` & `toggleDropdownContentsCreateView` actions', done => { + it('dispatches `requestCreateLabel`, `receiveCreateLabelSuccess` & `toggleDropdownContentsCreateView` actions', (done) => { const label = { id: 1 }; mock.onPost(/labels.json/).replyOnce(200, label); @@ -244,7 +244,7 @@ describe('LabelsSelect Actions', () => { }); describe('on failure', () => { - it('dispatches `requestCreateLabel` & `receiveCreateLabelFailure` actions', done => { + it('dispatches `requestCreateLabel` & `receiveCreateLabelFailure` actions', (done) => { mock.onPost(/labels.json/).replyOnce(500, {}); testAction( @@ -260,7 +260,7 @@ describe('LabelsSelect Actions', () => { }); describe('updateSelectedLabels', () => { - it('updates `state.labels` based on provided `labels` param', done => { + it('updates `state.labels` based on provided `labels` param', (done) => { const labels = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }]; testAction( diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/getters_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/getters_spec.js index 52116f757c5..1f899e84897 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/getters_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/getters_spec.js @@ -26,7 +26,10 @@ describe('LabelsSelect Getters', () => { }); it('returns first label title and remaining labels count when state.labels has more than 1 label', () => { - const labels = [{ id: 1, title: 'Foo', set: true }, { id: 2, title: 'Bar', set: true }]; + const labels = [ + { id: 1, title: 'Foo', set: true }, + { id: 2, title: 'Bar', set: true }, + ]; expect(getters.dropdownButtonText({ labels }, { isDropdownVariantSidebar: true })).toBe( 'Foo +1 more', diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js index 8081806e314..208f2f2d42d 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js @@ -93,14 +93,14 @@ describe('LabelsSelect Mutations', () => { }); it('sets provided `labels` to `state.labels` along with `set` prop based on `state.selectedLabels`', () => { - const selectedLabelIds = selectedLabels.map(label => label.id); + const selectedLabelIds = selectedLabels.map((label) => label.id); const state = { selectedLabels, labelsFetchInProgress: true, }; mutations[types.RECEIVE_SET_LABELS_SUCCESS](state, labels); - state.labels.forEach(label => { + state.labels.forEach((label) => { if (selectedLabelIds.includes(label.id)) { expect(label.set).toBe(true); } @@ -162,7 +162,7 @@ describe('LabelsSelect Mutations', () => { }; mutations[types.UPDATE_SELECTED_LABELS](state, { labels: [{ id: 2 }] }); - state.labels.forEach(label => { + state.labels.forEach((label) => { if (updatedLabelIds.includes(label.id)) { expect(label.touched).toBe(true); expect(label.set).toBe(true); diff --git a/spec/frontend/vue_shared/components/slot_switch_spec.js b/spec/frontend/vue_shared/components/slot_switch_spec.js index 73307b5573f..f25b9877aba 100644 --- a/spec/frontend/vue_shared/components/slot_switch_spec.js +++ b/spec/frontend/vue_shared/components/slot_switch_spec.js @@ -10,14 +10,14 @@ describe('SlotSwitch', () => { let wrapper; - const createComponent = propsData => { + const createComponent = (propsData) => { wrapper = shallowMount(SlotSwitch, { propsData, slots, }); }; - const getChildrenHtml = () => wrapper.findAll('* *').wrappers.map(c => c.html()); + const getChildrenHtml = () => wrapper.findAll('* *').wrappers.map((c) => c.html()); afterEach(() => { if (wrapper) { diff --git a/spec/frontend/vue_shared/components/split_button_spec.js b/spec/frontend/vue_shared/components/split_button_spec.js index e09bc073042..ad11e6519c4 100644 --- a/spec/frontend/vue_shared/components/split_button_spec.js +++ b/spec/frontend/vue_shared/components/split_button_spec.js @@ -19,18 +19,15 @@ const mockActionItems = [ describe('SplitButton', () => { let wrapper; - const createComponent = propsData => { + const createComponent = (propsData) => { wrapper = shallowMount(SplitButton, { propsData, }); }; const findDropdown = () => wrapper.find(GlDropdown); - const findDropdownItem = (index = 0) => - findDropdown() - .findAll(GlDropdownItem) - .at(index); - const selectItem = index => { + const findDropdownItem = (index = 0) => findDropdown().findAll(GlDropdownItem).at(index); + const selectItem = (index) => { findDropdownItem(index).vm.$emit('click'); return wrapper.vm.$nextTick(); @@ -87,7 +84,7 @@ describe('SplitButton', () => { const addChangeEventHandler = () => { changeEventHandler = jest.fn(); - wrapper.vm.$once('change', item => changeEventHandler(item)); + wrapper.vm.$once('change', (item) => changeEventHandler(item)); }; it('defaults to first actionItems event', () => { diff --git a/spec/frontend/vue_shared/components/stacked_progress_bar_spec.js b/spec/frontend/vue_shared/components/stacked_progress_bar_spec.js index 0786882f527..c6f01efa71a 100644 --- a/spec/frontend/vue_shared/components/stacked_progress_bar_spec.js +++ b/spec/frontend/vue_shared/components/stacked_progress_bar_spec.js @@ -3,7 +3,7 @@ import Vue from 'vue'; import mountComponent from 'helpers/vue_mount_component_helper'; import stackedProgressBarComponent from '~/vue_shared/components/stacked_progress_bar.vue'; -const createComponent = config => { +const createComponent = (config) => { const Component = Vue.extend(stackedProgressBarComponent); const defaultConfig = { successLabel: 'Synced', @@ -29,11 +29,12 @@ describe('StackedProgressBarComponent', () => { vm.$destroy(); }); - const findSuccessBarText = wrapper => wrapper.$el.querySelector('.status-green').innerText.trim(); - const findNeutralBarText = wrapper => + const findSuccessBarText = (wrapper) => + wrapper.$el.querySelector('.status-green').innerText.trim(); + const findNeutralBarText = (wrapper) => wrapper.$el.querySelector('.status-neutral').innerText.trim(); - const findFailureBarText = wrapper => wrapper.$el.querySelector('.status-red').innerText.trim(); - const findUnavailableBarText = wrapper => + const findFailureBarText = (wrapper) => wrapper.$el.querySelector('.status-red').innerText.trim(); + const findUnavailableBarText = (wrapper) => wrapper.$el.querySelector('.status-unavailable').innerText.trim(); describe('computed', () => { diff --git a/spec/frontend/vue_shared/components/table_pagination_spec.js b/spec/frontend/vue_shared/components/table_pagination_spec.js index 058dfcdbde2..12c47637358 100644 --- a/spec/frontend/vue_shared/components/table_pagination_spec.js +++ b/spec/frontend/vue_shared/components/table_pagination_spec.js @@ -6,7 +6,7 @@ describe('Pagination component', () => { let wrapper; let spy; - const mountComponent = props => { + const mountComponent = (props) => { wrapper = shallowMount(TablePagination, { propsData: props, }); diff --git a/spec/frontend/vue_shared/components/tabs/tab_spec.js b/spec/frontend/vue_shared/components/tabs/tab_spec.js index 8cf07a9177c..ee0c983c764 100644 --- a/spec/frontend/vue_shared/components/tabs/tab_spec.js +++ b/spec/frontend/vue_shared/components/tabs/tab_spec.js @@ -10,7 +10,7 @@ describe('Tab component', () => { vm = mountComponent(Component); }); - it('sets localActive to equal active', done => { + it('sets localActive to equal active', (done) => { vm.active = true; vm.$nextTick(() => { @@ -20,7 +20,7 @@ describe('Tab component', () => { }); }); - it('sets active class', done => { + it('sets active class', (done) => { vm.active = true; vm.$nextTick(() => { diff --git a/spec/frontend/vue_shared/components/tooltip_on_truncate_spec.js b/spec/frontend/vue_shared/components/tooltip_on_truncate_spec.js index 175abf5aae0..27c9b099306 100644 --- a/spec/frontend/vue_shared/components/tooltip_on_truncate_spec.js +++ b/spec/frontend/vue_shared/components/tooltip_on_truncate_spec.js @@ -18,7 +18,7 @@ describe('TooltipOnTruncate component', () => { const createComponent = ({ propsData, ...options } = {}) => { wrapper = shallowMount(TooltipOnTruncate, { - attachToDocument: true, + attachTo: document.body, propsData: { ...propsData, }, @@ -44,7 +44,7 @@ describe('TooltipOnTruncate component', () => { }, { propsData: { ...propsData }, - attachToDocument: true, + attachTo: document.body, ...options, }, ); @@ -139,7 +139,7 @@ describe('TooltipOnTruncate component', () => { createComponent({ propsData: { title: DUMMY_TEXT, - truncateTarget: el => el.childNodes[1], + truncateTarget: (el) => el.childNodes[1], }, slots: { default: [createChildElement(), createChildElement()], diff --git a/spec/frontend/vue_shared/components/user_avatar/user_avatar_image_spec.js b/spec/frontend/vue_shared/components/user_avatar/user_avatar_image_spec.js index 663d0af4cc4..2c3fc70e116 100644 --- a/spec/frontend/vue_shared/components/user_avatar/user_avatar_image_spec.js +++ b/spec/frontend/vue_shared/components/user_avatar/user_avatar_image_spec.js @@ -91,11 +91,11 @@ describe('User Avatar Image Component', () => { }); it('renders the tooltip slot', () => { - expect(wrapper.find('.js-user-avatar-image-toolip').exists()).toBe(true); + expect(wrapper.find('.js-user-avatar-image-tooltip').exists()).toBe(true); }); it('renders the tooltip content', () => { - expect(wrapper.find('.js-user-avatar-image-toolip').text()).toContain(slots.default[0]); + expect(wrapper.find('.js-user-avatar-image-tooltip').text()).toContain(slots.default[0]); }); it('does not render tooltip data attributes for on avatar image', () => { diff --git a/spec/frontend/vue_shared/components/user_avatar/user_avatar_link_spec.js b/spec/frontend/vue_shared/components/user_avatar/user_avatar_link_spec.js index 84e7a6a162e..d151cd15bc4 100644 --- a/spec/frontend/vue_shared/components/user_avatar/user_avatar_link_spec.js +++ b/spec/frontend/vue_shared/components/user_avatar/user_avatar_link_spec.js @@ -20,7 +20,7 @@ describe('User Avatar Link Component', () => { username: 'username', }; - const createWrapper = props => { + const createWrapper = (props) => { wrapper = shallowMount(UserAvatarLink, { propsData: { ...defaultProps, @@ -83,7 +83,7 @@ describe('User Avatar Link Component', () => { describe('username', () => { it('should not render avatar image tooltip', () => { - expect(wrapper.find('.js-user-avatar-image-toolip').exists()).toBe(false); + expect(wrapper.find('.js-user-avatar-image-tooltip').exists()).toBe(false); }); it('should render username prop in <span>', () => { diff --git a/spec/frontend/vue_shared/components/user_avatar/user_avatar_list_spec.js b/spec/frontend/vue_shared/components/user_avatar/user_avatar_list_spec.js index 6f66d1cafb9..e3cd2bb9aaa 100644 --- a/spec/frontend/vue_shared/components/user_avatar/user_avatar_list_spec.js +++ b/spec/frontend/vue_shared/components/user_avatar/user_avatar_list_spec.js @@ -9,13 +9,13 @@ const TEST_BREAKPOINT = 5; const TEST_EMPTY_MESSAGE = 'Lorem ipsum empty'; const DEFAULT_EMPTY_MESSAGE = 'None'; -const createUser = id => ({ +const createUser = (id) => ({ id, name: 'Lorem', web_url: `${TEST_HOST}/${id}`, avatar_url: `${TEST_HOST}/${id}/avatar`, }); -const createList = n => +const createList = (n) => Array(n) .fill(1) .map((x, id) => createUser(id)); @@ -79,10 +79,10 @@ describe('UserAvatarList', () => { factory({ propsData: { items } }); const links = wrapper.findAll(UserAvatarLink); - const linkProps = links.wrappers.map(x => x.props()); + const linkProps = links.wrappers.map((x) => x.props()); expect(linkProps).toEqual( - items.map(x => + items.map((x) => expect.objectContaining({ linkHref: x.web_url, imgSrc: x.avatar_url, diff --git a/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js b/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js index 7d58a865ba3..435c3a5406e 100644 --- a/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js +++ b/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js @@ -33,7 +33,7 @@ describe('User Popover Component', () => { wrapper.destroy(); }); - const findByTestId = testid => wrapper.find(`[data-testid="${testid}"]`); + const findByTestId = (testid) => wrapper.find(`[data-testid="${testid}"]`); const findUserStatus = () => wrapper.find('.js-user-status'); const findTarget = () => document.querySelector('.js-user-link'); const findAvailabilityStatus = () => wrapper.find(UserAvailabilityStatus); @@ -81,6 +81,7 @@ describe('User Popover Component', () => { }); it('shows icon for location', () => { + createWrapper(); const iconEl = wrapper.find(GlIcon); expect(iconEl.props('name')).toEqual('location'); @@ -147,7 +148,7 @@ describe('User Popover Component', () => { createWrapper({ user }); expect( - wrapper.findAll(GlIcon).filter(icon => icon.props('name') === 'profile').length, + wrapper.findAll(GlIcon).filter((icon) => icon.props('name') === 'profile').length, ).toEqual(1); }); @@ -159,9 +160,9 @@ describe('User Popover Component', () => { createWrapper({ user }); - expect(wrapper.findAll(GlIcon).filter(icon => icon.props('name') === 'work').length).toEqual( - 1, - ); + expect( + wrapper.findAll(GlIcon).filter((icon) => icon.props('name') === 'work').length, + ).toEqual(1); }); }); diff --git a/spec/frontend/vue_shared/directives/tooltip_spec.js b/spec/frontend/vue_shared/directives/tooltip_spec.js index 4217b8d3c02..28ec23ad4c1 100644 --- a/spec/frontend/vue_shared/directives/tooltip_spec.js +++ b/spec/frontend/vue_shared/directives/tooltip_spec.js @@ -19,7 +19,7 @@ describe('Tooltip directive', () => { data: () => ({ tooltip: text }), template, }, - { attachToDocument: true }, + { attachTo: document.body }, ); } @@ -151,11 +151,7 @@ describe('Tooltip directive', () => { }); it('should have tooltip plugin applied to all instances', () => { - expect( - $(wrapper.vm.$el) - .find('.js-look-for-tooltip') - .data('bs.tooltip'), - ).toBeDefined(); + expect($(wrapper.vm.$el).find('.js-look-for-tooltip').data('bs.tooltip')).toBeDefined(); }); }); }); diff --git a/spec/frontend/vue_shared/directives/validation_spec.js b/spec/frontend/vue_shared/directives/validation_spec.js index 814d6f43589..2764a71d204 100644 --- a/spec/frontend/vue_shared/directives/validation_spec.js +++ b/spec/frontend/vue_shared/directives/validation_spec.js @@ -36,7 +36,7 @@ describe('validation directive', () => { `, }; - wrapper = shallowMount(component, { attachToDocument: true }); + wrapper = shallowMount(component, { attachTo: document.body }); }; afterEach(() => { @@ -50,7 +50,7 @@ describe('validation directive', () => { describe.each([true, false])( 'with fields untouched and "showValidation" set to "%s"', - showValidation => { + (showValidation) => { beforeEach(() => { createComponent({ showValidation }); }); @@ -78,7 +78,7 @@ describe('validation directive', () => { `( 'with input-attributes set to $inputAttributes', ({ inputAttributes, validValue, invalidValue }) => { - const setValueAndTriggerValidation = value => { + const setValueAndTriggerValidation = (value) => { const input = findInput(); input.setValue(value); input.trigger('blur'); diff --git a/spec/frontend/vue_shared/security_reports/components/security_report_download_dropdown_spec.js b/spec/frontend/vue_shared/security_reports/components/security_report_download_dropdown_spec.js index 7e70407655a..9138d2d3f4c 100644 --- a/spec/frontend/vue_shared/security_reports/components/security_report_download_dropdown_spec.js +++ b/spec/frontend/vue_shared/security_reports/components/security_report_download_dropdown_spec.js @@ -6,7 +6,7 @@ describe('SecurityReportDownloadDropdown component', () => { let wrapper; let artifacts; - const createComponent = props => { + const createComponent = (props) => { wrapper = shallowMount(SecurityReportDownloadDropdown, { propsData: { ...props }, }); diff --git a/spec/frontend/vue_shared/security_reports/mock_data.js b/spec/frontend/vue_shared/security_reports/mock_data.js index e93ca8329e7..b3ff7daef2b 100644 --- a/spec/frontend/vue_shared/security_reports/mock_data.js +++ b/spec/frontend/vue_shared/security_reports/mock_data.js @@ -392,6 +392,33 @@ export const securityReportDownloadPathsQueryResponse = { }, __typename: 'CiJob', }, + { + name: 'all_artifacts', + artifacts: { + nodes: [ + { + downloadPath: + '/gitlab-org/secrets-detection-test/-/jobs/1402/artifacts/download?file_type=archive', + fileType: 'ARCHIVE', + __typename: 'CiJobArtifact', + }, + { + downloadPath: + '/gitlab-org/secrets-detection-test/-/jobs/1402/artifacts/download?file_type=trace', + fileType: 'TRACE', + __typename: 'CiJobArtifact', + }, + { + downloadPath: + '/gitlab-org/secrets-detection-test/-/jobs/1402/artifacts/download?file_type=metadata', + fileType: 'METADATA', + __typename: 'CiJobArtifact', + }, + ], + __typename: 'CiJobArtifactConnection', + }, + __typename: 'CiJob', + }, ], __typename: 'CiJobConnection', }, @@ -435,3 +462,51 @@ export const expectedDownloadDropdownProps = { loading: false, artifacts: [...secretDetectionArtifacts, ...sastArtifacts], }; + +/** + * These correspond to any jobs with zip archives in the securityReportDownloadPathsQueryResponse above. + */ +export const archiveArtifacts = [ + { + name: 'all_artifacts Archive', + path: '/gitlab-org/secrets-detection-test/-/jobs/1402/artifacts/download?file_type=archive', + reportType: 'ARCHIVE', + }, +]; + +/** + * These correspond to any jobs with trace data in the securityReportDownloadPathsQueryResponse above. + */ +export const traceArtifacts = [ + { + name: 'secret_detection Trace', + path: '/gitlab-org/secrets-detection-test/-/jobs/1399/artifacts/download?file_type=trace', + reportType: 'TRACE', + }, + { + name: 'bandit-sast Trace', + path: '/gitlab-org/secrets-detection-test/-/jobs/1400/artifacts/download?file_type=trace', + reportType: 'TRACE', + }, + { + name: 'eslint-sast Trace', + path: '/gitlab-org/secrets-detection-test/-/jobs/1401/artifacts/download?file_type=trace', + reportType: 'TRACE', + }, + { + name: 'all_artifacts Trace', + path: '/gitlab-org/secrets-detection-test/-/jobs/1402/artifacts/download?file_type=trace', + reportType: 'TRACE', + }, +]; + +/** + * These correspond to any jobs with metadata data in the securityReportDownloadPathsQueryResponse above. + */ +export const metadataArtifacts = [ + { + name: 'all_artifacts Metadata', + path: '/gitlab-org/secrets-detection-test/-/jobs/1402/artifacts/download?file_type=metadata', + reportType: 'METADATA', + }, +]; diff --git a/spec/frontend/vue_shared/security_reports/security_reports_app_spec.js b/spec/frontend/vue_shared/security_reports/security_reports_app_spec.js index c440081a0c4..50d1d130675 100644 --- a/spec/frontend/vue_shared/security_reports/security_reports_app_spec.js +++ b/spec/frontend/vue_shared/security_reports/security_reports_app_spec.js @@ -3,7 +3,7 @@ import MockAdapter from 'axios-mock-adapter'; import { merge } from 'lodash'; import VueApollo from 'vue-apollo'; import Vuex from 'vuex'; -import createMockApollo from 'jest/helpers/mock_apollo_helper'; +import createMockApollo from 'helpers/mock_apollo_helper'; import { trimText } from 'helpers/text_helper'; import waitForPromises from 'helpers/wait_for_promises'; import { @@ -42,7 +42,7 @@ describe('Security reports app', () => { discoverProjectSecurityPath: '/discoverProjectSecurityPath', }; - const createComponent = options => { + const createComponent = (options) => { wrapper = mount( SecurityReportsApp, merge( @@ -61,7 +61,7 @@ describe('Security reports app', () => { const pendingHandler = () => new Promise(() => {}); const successHandler = () => Promise.resolve({ data: securityReportDownloadPathsQueryResponse }); const failureHandler = () => Promise.resolve({ errors: [{ message: 'some error' }] }); - const createMockApolloProvider = handler => { + const createMockApolloProvider = (handler) => { localVue.use(VueApollo); const requestHandlers = [[securityReportDownloadPathsQuery, handler]]; @@ -74,7 +74,7 @@ describe('Security reports app', () => { const findDownloadDropdown = () => wrapper.find(SecurityReportDownloadDropdown); const findPipelinesTabAnchor = () => wrapper.find('[data-testid="show-pipelines"]'); const findHelpIconComponent = () => wrapper.find(HelpIcon); - const setupMockJobArtifact = reportType => { + const setupMockJobArtifact = (reportType) => { jest .spyOn(Api, 'pipelineJobs') .mockResolvedValue({ data: [{ artifacts: [{ file_type: reportType }] }] }); @@ -93,8 +93,8 @@ describe('Security reports app', () => { describe.each([false, true])( 'given the coreSecurityMrWidgetCounts feature flag is %p', - coreSecurityMrWidgetCounts => { - const createComponentWithFlag = options => + (coreSecurityMrWidgetCounts) => { + const createComponentWithFlag = (options) => createComponent( merge( { @@ -108,7 +108,7 @@ describe('Security reports app', () => { ), ); - describe.each(SecurityReportsApp.reportTypes)('given a report type %p', reportType => { + describe.each(SecurityReportsApp.reportTypes)('given a report type %p', (reportType) => { beforeEach(() => { window.mrTabs = { tabShown: jest.fn() }; setupMockJobArtifact(reportType); @@ -245,7 +245,7 @@ describe('Security reports app', () => { describe('given the coreSecurityMrWidgetCounts feature flag is enabled', () => { let mock; - const createComponentWithFlagEnabled = options => + const createComponentWithFlagEnabled = (options) => createComponent( merge(options, { provide: { @@ -350,7 +350,7 @@ describe('Security reports app', () => { }); describe('given coreSecurityMrWidgetDownloads feature flag is enabled', () => { - const createComponentWithFlagEnabled = options => + const createComponentWithFlagEnabled = (options) => createComponent( merge(options, { provide: { @@ -371,7 +371,7 @@ describe('Security reports app', () => { // TODO: Remove this assertion as part of // https://gitlab.com/gitlab-org/gitlab/-/issues/273431 it('initially renders nothing', () => { - expect(wrapper.isEmpty()).toBe(true); + expect(wrapper.html()).toBe(''); }); }); @@ -415,7 +415,7 @@ describe('Security reports app', () => { // TODO: Remove this assertion as part of // https://gitlab.com/gitlab-org/gitlab/-/issues/273431 it('renders nothing', () => { - expect(wrapper.isEmpty()).toBe(true); + expect(wrapper.html()).toBe(''); }); }); }); diff --git a/spec/frontend/vue_shared/security_reports/store/getters_spec.js b/spec/frontend/vue_shared/security_reports/store/getters_spec.js index 8de704be455..b146a281d7b 100644 --- a/spec/frontend/vue_shared/security_reports/store/getters_spec.js +++ b/spec/frontend/vue_shared/security_reports/store/getters_spec.js @@ -13,7 +13,7 @@ import { } from '~/vue_shared/security_reports/store/getters'; import { CRITICAL, HIGH, LOW } from '~/vulnerabilities/constants'; -const generateVuln = severity => ({ severity }); +const generateVuln = (severity) => ({ severity }); describe('Security reports getters', () => { let state; diff --git a/spec/frontend/vue_shared/security_reports/store/modules/sast/actions_spec.js b/spec/frontend/vue_shared/security_reports/store/modules/sast/actions_spec.js index a11f4e05913..c9d1db8a504 100644 --- a/spec/frontend/vue_shared/security_reports/store/modules/sast/actions_spec.js +++ b/spec/frontend/vue_shared/security_reports/store/modules/sast/actions_spec.js @@ -26,7 +26,7 @@ describe('sast report actions', () => { }); describe('setDiffEndpoint', () => { - it(`should commit ${types.SET_DIFF_ENDPOINT} with the correct path`, done => { + it(`should commit ${types.SET_DIFF_ENDPOINT} with the correct path`, (done) => { testAction( actions.setDiffEndpoint, diffEndpoint, @@ -44,13 +44,13 @@ describe('sast report actions', () => { }); describe('requestDiff', () => { - it(`should commit ${types.REQUEST_DIFF}`, done => { + it(`should commit ${types.REQUEST_DIFF}`, (done) => { testAction(actions.requestDiff, {}, state, [{ type: types.REQUEST_DIFF }], [], done); }); }); describe('receiveDiffSuccess', () => { - it(`should commit ${types.RECEIVE_DIFF_SUCCESS} with the correct response`, done => { + it(`should commit ${types.RECEIVE_DIFF_SUCCESS} with the correct response`, (done) => { testAction( actions.receiveDiffSuccess, reports, @@ -68,7 +68,7 @@ describe('sast report actions', () => { }); describe('receiveDiffError', () => { - it(`should commit ${types.RECEIVE_DIFF_ERROR} with the correct response`, done => { + it(`should commit ${types.RECEIVE_DIFF_ERROR} with the correct response`, (done) => { testAction( actions.receiveDiffError, error, @@ -107,7 +107,7 @@ describe('sast report actions', () => { .replyOnce(200, reports.enrichData); }); - it('should dispatch the `receiveDiffSuccess` action', done => { + it('should dispatch the `receiveDiffSuccess` action', (done) => { const { diff, enrichData } = reports; testAction( actions.fetchDiff, @@ -135,7 +135,7 @@ describe('sast report actions', () => { mock.onGet(diffEndpoint).replyOnce(200, reports.diff); }); - it('should dispatch the `receiveDiffSuccess` action with empty enrich data', done => { + it('should dispatch the `receiveDiffSuccess` action with empty enrich data', (done) => { const { diff } = reports; const enrichData = []; testAction( @@ -167,7 +167,7 @@ describe('sast report actions', () => { .replyOnce(404); }); - it('should dispatch the `receiveError` action', done => { + it('should dispatch the `receiveError` action', (done) => { testAction( actions.fetchDiff, {}, @@ -188,7 +188,7 @@ describe('sast report actions', () => { .replyOnce(200, reports.enrichData); }); - it('should dispatch the `receiveDiffError` action', done => { + it('should dispatch the `receiveDiffError` action', (done) => { testAction( actions.fetchDiff, {}, diff --git a/spec/frontend/vue_shared/security_reports/store/modules/secret_detection/actions_spec.js b/spec/frontend/vue_shared/security_reports/store/modules/secret_detection/actions_spec.js index bbcdfb5cd99..beda1a55438 100644 --- a/spec/frontend/vue_shared/security_reports/store/modules/secret_detection/actions_spec.js +++ b/spec/frontend/vue_shared/security_reports/store/modules/secret_detection/actions_spec.js @@ -26,7 +26,7 @@ describe('secret detection report actions', () => { }); describe('setDiffEndpoint', () => { - it(`should commit ${types.SET_DIFF_ENDPOINT} with the correct path`, done => { + it(`should commit ${types.SET_DIFF_ENDPOINT} with the correct path`, (done) => { testAction( actions.setDiffEndpoint, diffEndpoint, @@ -44,13 +44,13 @@ describe('secret detection report actions', () => { }); describe('requestDiff', () => { - it(`should commit ${types.REQUEST_DIFF}`, done => { + it(`should commit ${types.REQUEST_DIFF}`, (done) => { testAction(actions.requestDiff, {}, state, [{ type: types.REQUEST_DIFF }], [], done); }); }); describe('receiveDiffSuccess', () => { - it(`should commit ${types.RECEIVE_DIFF_SUCCESS} with the correct response`, done => { + it(`should commit ${types.RECEIVE_DIFF_SUCCESS} with the correct response`, (done) => { testAction( actions.receiveDiffSuccess, reports, @@ -68,7 +68,7 @@ describe('secret detection report actions', () => { }); describe('receiveDiffError', () => { - it(`should commit ${types.RECEIVE_DIFF_ERROR} with the correct response`, done => { + it(`should commit ${types.RECEIVE_DIFF_ERROR} with the correct response`, (done) => { testAction( actions.receiveDiffError, error, @@ -107,7 +107,7 @@ describe('secret detection report actions', () => { .replyOnce(200, reports.enrichData); }); - it('should dispatch the `receiveDiffSuccess` action', done => { + it('should dispatch the `receiveDiffSuccess` action', (done) => { const { diff, enrichData } = reports; testAction( actions.fetchDiff, @@ -135,7 +135,7 @@ describe('secret detection report actions', () => { mock.onGet(diffEndpoint).replyOnce(200, reports.diff); }); - it('should dispatch the `receiveDiffSuccess` action with empty enrich data', done => { + it('should dispatch the `receiveDiffSuccess` action with empty enrich data', (done) => { const { diff } = reports; const enrichData = []; testAction( @@ -167,7 +167,7 @@ describe('secret detection report actions', () => { .replyOnce(404); }); - it('should dispatch the `receiveDiffError` action', done => { + it('should dispatch the `receiveDiffError` action', (done) => { testAction( actions.fetchDiff, {}, @@ -188,7 +188,7 @@ describe('secret detection report actions', () => { .replyOnce(200, reports.enrichData); }); - it('should dispatch the `receiveDiffError` action', done => { + it('should dispatch the `receiveDiffError` action', (done) => { testAction( actions.fetchDiff, {}, diff --git a/spec/frontend/vue_shared/security_reports/utils_spec.js b/spec/frontend/vue_shared/security_reports/utils_spec.js index ea54644796a..7e5a27694ef 100644 --- a/spec/frontend/vue_shared/security_reports/utils_spec.js +++ b/spec/frontend/vue_shared/security_reports/utils_spec.js @@ -2,11 +2,15 @@ import { extractSecurityReportArtifacts } from '~/vue_shared/security_reports/ut import { REPORT_TYPE_SAST, REPORT_TYPE_SECRET_DETECTION, + REPORT_FILE_TYPES, } from '~/vue_shared/security_reports/constants'; import { securityReportDownloadPathsQueryResponse, sastArtifacts, secretDetectionArtifacts, + archiveArtifacts, + traceArtifacts, + metadataArtifacts, } from './mock_data'; describe('extractSecurityReportArtifacts', () => { @@ -17,6 +21,9 @@ describe('extractSecurityReportArtifacts', () => { ${[REPORT_TYPE_SAST]} | ${sastArtifacts} ${[REPORT_TYPE_SECRET_DETECTION]} | ${secretDetectionArtifacts} ${[REPORT_TYPE_SAST, REPORT_TYPE_SECRET_DETECTION]} | ${[...secretDetectionArtifacts, ...sastArtifacts]} + ${[REPORT_FILE_TYPES.ARCHIVE]} | ${archiveArtifacts} + ${[REPORT_FILE_TYPES.TRACE]} | ${traceArtifacts} + ${[REPORT_FILE_TYPES.METADATA]} | ${metadataArtifacts} `( 'returns the expected artifacts given report types $reportTypes', ({ reportTypes, expectedArtifacts }) => { |