diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-03-08 21:08:14 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-03-08 21:08:14 +0300 |
commit | 9885b7e33ece32ac3bfbf077bb2dc53c459dbc0e (patch) | |
tree | bcbabc83286e8852df225b2117b28d4dc8678a7f /spec/frontend | |
parent | 684838d4bea13af1dac9c2f32b99985bf0f9f8e2 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
-rw-r--r-- | spec/frontend/blob/components/blob_header_spec.js | 170 | ||||
-rw-r--r-- | spec/frontend/search/mock_data.js | 7 | ||||
-rw-r--r-- | spec/frontend/search/store/utils_spec.js | 22 | ||||
-rw-r--r-- | spec/frontend/work_items/components/notes/work_item_note_actions_spec.js | 98 |
4 files changed, 195 insertions, 102 deletions
diff --git a/spec/frontend/blob/components/blob_header_spec.js b/spec/frontend/blob/components/blob_header_spec.js index 46740958090..47e09bb38bc 100644 --- a/spec/frontend/blob/components/blob_header_spec.js +++ b/spec/frontend/blob/components/blob_header_spec.js @@ -1,9 +1,14 @@ import { shallowMount, mount } from '@vue/test-utils'; -import { nextTick } from 'vue'; +import { mountExtended } from 'helpers/vue_test_utils_helper'; import BlobHeader from '~/blob/components/blob_header.vue'; import DefaultActions from '~/blob/components/blob_header_default_actions.vue'; import BlobFilepath from '~/blob/components/blob_header_filepath.vue'; import ViewerSwitcher from '~/blob/components/blob_header_viewer_switcher.vue'; +import { + RICH_BLOB_VIEWER_TITLE, + SIMPLE_BLOB_VIEWER, + SIMPLE_BLOB_VIEWER_TITLE, +} from '~/blob/components/constants'; import TableContents from '~/blob/components/table_contents.vue'; import { Blob } from './mock_data'; @@ -11,12 +16,26 @@ import { Blob } from './mock_data'; describe('Blob Header Default Actions', () => { let wrapper; - function createComponent(blobProps = {}, options = {}, propsData = {}, shouldMount = false) { - const method = shouldMount ? mount : shallowMount; - const blobHash = 'foo-bar'; - wrapper = method.call(this, BlobHeader, { + const defaultProvide = { + blobHash: 'foo-bar', + }; + + const findDefaultActions = () => wrapper.findComponent(DefaultActions); + const findTableContents = () => wrapper.findComponent(TableContents); + const findViewSwitcher = () => wrapper.findComponent(ViewerSwitcher); + const findBlobFilePath = () => wrapper.findComponent(BlobFilepath); + const findRichTextEditorBtn = () => wrapper.findByLabelText(RICH_BLOB_VIEWER_TITLE); + const findSimpleTextEditorBtn = () => wrapper.findByLabelText(SIMPLE_BLOB_VIEWER_TITLE); + + function createComponent({ + blobProps = {}, + options = {}, + propsData = {}, + mountFn = shallowMount, + } = {}) { + wrapper = mountFn(BlobHeader, { provide: { - blobHash, + ...defaultProvide, }, propsData: { blob: { ...Blob, ...blobProps }, @@ -26,143 +45,123 @@ describe('Blob Header Default Actions', () => { }); } - afterEach(() => { - wrapper.destroy(); - }); - describe('rendering', () => { - const findDefaultActions = () => wrapper.findComponent(DefaultActions); - - const slots = { - prepend: 'Foo Prepend', - actions: 'Actions Bar', - }; - it('matches the snapshot', () => { createComponent(); expect(wrapper.element).toMatchSnapshot(); }); - it('renders all components', () => { - createComponent(); - expect(wrapper.findComponent(TableContents).exists()).toBe(true); - expect(wrapper.findComponent(ViewerSwitcher).exists()).toBe(true); - expect(findDefaultActions().exists()).toBe(true); - expect(wrapper.findComponent(BlobFilepath).exists()).toBe(true); + describe('default render', () => { + it.each` + findComponent | componentName + ${findTableContents} | ${'TableContents'} + ${findViewSwitcher} | ${'ViewSwitcher'} + ${findDefaultActions} | ${'DefaultActions'} + ${findBlobFilePath} | ${'BlobFilePath'} + `('renders $componentName component by default', ({ findComponent }) => { + createComponent(); + + expect(findComponent().exists()).toBe(true); + }); }); it('does not render viewer switcher if the blob has only the simple viewer', () => { createComponent({ - richViewer: null, + blobProps: { + richViewer: null, + }, }); - expect(wrapper.findComponent(ViewerSwitcher).exists()).toBe(false); + expect(findViewSwitcher().exists()).toBe(false); }); it('does not render viewer switcher if a corresponding prop is passed', () => { - createComponent( - {}, - {}, - { + createComponent({ + propsData: { hideViewerSwitcher: true, }, - ); - expect(wrapper.findComponent(ViewerSwitcher).exists()).toBe(false); + }); + expect(findViewSwitcher().exists()).toBe(false); }); it('does not render default actions is corresponding prop is passed', () => { - createComponent( - {}, - {}, - { + createComponent({ + propsData: { hideDefaultActions: true, }, - ); - expect(wrapper.findComponent(DefaultActions).exists()).toBe(false); + }); + expect(findDefaultActions().exists()).toBe(false); }); - Object.keys(slots).forEach((slot) => { - it('renders the slots', () => { - const slotContent = slots[slot]; - createComponent( - {}, - { - scopedSlots: { - [slot]: `<span>${slotContent}</span>`, - }, + it.each` + slotContent | key + ${'Foo Prepend'} | ${'prepend'} + ${'Actions Bar'} | ${'actions'} + `('renders the slot $key', ({ key, slotContent }) => { + createComponent({ + options: { + scopedSlots: { + [key]: `<span>${slotContent}</span>`, }, - {}, - true, - ); - expect(wrapper.text()).toContain(slotContent); + }, + mountFn: mount, }); + expect(wrapper.text()).toContain(slotContent); }); it('passes information about render error down to default actions', () => { - createComponent( - {}, - {}, - { + createComponent({ + propsData: { hasRenderError: true, }, - ); + }); expect(findDefaultActions().props('hasRenderError')).toBe(true); }); it('passes the correct isBinary value to default actions when viewing a binary file', () => { - createComponent({}, {}, { isBinary: true }); + createComponent({ propsData: { isBinary: true } }); expect(findDefaultActions().props('isBinary')).toBe(true); }); }); describe('functionality', () => { - const newViewer = 'Foo Bar'; - const activeViewerType = 'Alpha Beta'; - const factory = (hideViewerSwitcher = false) => { - createComponent( - {}, - {}, - { - activeViewerType, + createComponent({ + propsData: { + activeViewerType: SIMPLE_BLOB_VIEWER, hideViewerSwitcher, }, - ); + mountFn: mountExtended, + }); }; - it('by default sets viewer data based on activeViewerType', () => { + it('shows the correctly selected view by default', () => { factory(); - expect(wrapper.vm.viewer).toBe(activeViewerType); + + expect(findViewSwitcher().exists()).toBe(true); + expect(findRichTextEditorBtn().props().selected).toBe(false); + expect(findSimpleTextEditorBtn().props().selected).toBe(true); }); - it('sets viewer to null if the viewer switcher should be hidden', () => { + it('Does not show the viewer switcher should be hidden', () => { factory(true); - expect(wrapper.vm.viewer).toBe(null); + + expect(findViewSwitcher().exists()).toBe(false); }); it('watches the changes in viewer data and emits event when the change is registered', async () => { factory(); - jest.spyOn(wrapper.vm, '$emit'); - wrapper.vm.viewer = newViewer; - await nextTick(); - expect(wrapper.vm.$emit).toHaveBeenCalledWith('viewer-changed', newViewer); - }); - - it('does not emit event if the switcher is not rendered', async () => { - factory(true); - - expect(wrapper.vm.showViewerSwitcher).toBe(false); - jest.spyOn(wrapper.vm, '$emit'); - wrapper.vm.viewer = newViewer; + await findRichTextEditorBtn().trigger('click'); - await nextTick(); - expect(wrapper.vm.$emit).not.toHaveBeenCalled(); + expect(wrapper.emitted('viewer-changed')).toBeDefined(); }); it('sets different icons depending on the blob file type', async () => { factory(); - expect(wrapper.vm.blobSwitcherDocIcon).toBe('document'); + + expect(findViewSwitcher().props('docIcon')).toBe('document'); + await wrapper.setProps({ blob: { ...Blob, @@ -172,7 +171,8 @@ describe('Blob Header Default Actions', () => { }, }, }); - expect(wrapper.vm.blobSwitcherDocIcon).toBe('table'); + + expect(findViewSwitcher().props('docIcon')).toBe('table'); }); }); }); diff --git a/spec/frontend/search/mock_data.js b/spec/frontend/search/mock_data.js index fb9c0a93907..0aa4f0e1c84 100644 --- a/spec/frontend/search/mock_data.js +++ b/spec/frontend/search/mock_data.js @@ -653,3 +653,10 @@ export const TEST_FILTER_DATA = { JSON: { label: 'JSON', value: 'JSON', count: 15 }, }, }; + +export const SMALL_MOCK_AGGREGATIONS = [ + { + name: 'language', + buckets: TEST_RAW_BUCKETS, + }, +]; diff --git a/spec/frontend/search/store/utils_spec.js b/spec/frontend/search/store/utils_spec.js index 8c4a17f0a5d..dfe4e801f11 100644 --- a/spec/frontend/search/store/utils_spec.js +++ b/spec/frontend/search/store/utils_spec.js @@ -7,6 +7,7 @@ import { isSidebarDirty, formatSearchResultCount, getAggregationsUrl, + prepareSearchAggregations, } from '~/search/store/utils'; import { useMockLocationHelper } from 'helpers/mock_window_location_helper'; import { @@ -15,6 +16,9 @@ import { MOCK_INFLATED_DATA, FRESH_STORED_DATA, STALE_STORED_DATA, + MOCK_AGGREGATIONS, + SMALL_MOCK_AGGREGATIONS, + TEST_RAW_BUCKETS, } from '../mock_data'; const PREV_TIME = new Date().getTime() - 1; @@ -266,4 +270,22 @@ describe('Global Search Store Utils', () => { expect(getAggregationsUrl()).toStrictEqual(`${testURL}search/aggregations`); }); }); + + const TEST_LANGUAGE_QUERY = ['Markdown', 'JSON']; + const TEST_EXPECTED_ORDERED_BUCKETS = [ + TEST_RAW_BUCKETS.find((x) => x.key === 'Markdown'), + TEST_RAW_BUCKETS.find((x) => x.key === 'JSON'), + ...TEST_RAW_BUCKETS.filter((x) => !TEST_LANGUAGE_QUERY.includes(x.key)), + ]; + + describe('prepareSearchAggregations', () => { + it.each` + description | query | data | result + ${'has no query'} | ${undefined} | ${MOCK_AGGREGATIONS} | ${MOCK_AGGREGATIONS} + ${'has query'} | ${{ language: TEST_LANGUAGE_QUERY }} | ${SMALL_MOCK_AGGREGATIONS} | ${[{ ...SMALL_MOCK_AGGREGATIONS[0], buckets: TEST_EXPECTED_ORDERED_BUCKETS }]} + ${'has bad query'} | ${{ language: ['sdf', 'wrt'] }} | ${SMALL_MOCK_AGGREGATIONS} | ${SMALL_MOCK_AGGREGATIONS} + `('$description', ({ query, data, result }) => { + expect(prepareSearchAggregations({ query }, data)).toStrictEqual(result); + }); + }); }); diff --git a/spec/frontend/work_items/components/notes/work_item_note_actions_spec.js b/spec/frontend/work_items/components/notes/work_item_note_actions_spec.js index d85cd46c1c3..b293127b6af 100644 --- a/spec/frontend/work_items/components/notes/work_item_note_actions_spec.js +++ b/spec/frontend/work_items/components/notes/work_item_note_actions_spec.js @@ -1,52 +1,116 @@ import { shallowMount } from '@vue/test-utils'; +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import createMockApollo from 'helpers/mock_apollo_helper'; +import EmojiPicker from '~/emoji/components/picker.vue'; +import waitForPromises from 'helpers/wait_for_promises'; import ReplyButton from '~/notes/components/note_actions/reply_button.vue'; import WorkItemNoteActions from '~/work_items/components/notes/work_item_note_actions.vue'; +import addAwardEmojiMutation from '~/work_items/graphql/notes/work_item_note_add_award_emoji.mutation.graphql'; + +Vue.use(VueApollo); describe('Work Item Note Actions', () => { let wrapper; + const noteId = '1'; const findReplyButton = () => wrapper.findComponent(ReplyButton); const findEditButton = () => wrapper.find('[data-testid="edit-work-item-note"]'); + const findEmojiButton = () => wrapper.find('[data-testid="note-emoji-button"]'); + + const addEmojiMutationResolver = jest.fn().mockResolvedValue({ + data: { + errors: [], + }, + }); + + const EmojiPickerStub = { + props: EmojiPicker.props, + template: '<div></div>', + }; - const createComponent = ({ showReply = true, showEdit = true } = {}) => { + const createComponent = ({ showReply = true, showEdit = true, showAwardEmoji = true } = {}) => { wrapper = shallowMount(WorkItemNoteActions, { propsData: { showReply, showEdit, + noteId, + showAwardEmoji, + }, + provide: { + glFeatures: { + workItemsMvc2: true, + }, }, + stubs: { + EmojiPicker: EmojiPickerStub, + }, + apolloProvider: createMockApollo([[addAwardEmojiMutation, addEmojiMutationResolver]]), }); }; - describe('Default', () => { - it('Should show the reply button by default', () => { + describe('reply button', () => { + it('is visible by default', () => { createComponent(); + expect(findReplyButton().exists()).toBe(true); }); - }); - describe('When the reply button needs to be hidden', () => { - it('Should show the reply button by default', () => { + it('is hidden when showReply false', () => { createComponent({ showReply: false }); + expect(findReplyButton().exists()).toBe(false); }); }); - it('shows edit button when `showEdit` prop is true', () => { - createComponent(); + describe('edit button', () => { + it('is visible when `showEdit` prop is true', () => { + createComponent(); - expect(findEditButton().exists()).toBe(true); - }); + expect(findEditButton().exists()).toBe(true); + }); + + it('is hidden when `showEdit` prop is false', () => { + createComponent({ showEdit: false }); + + expect(findEditButton().exists()).toBe(false); + }); - it('does not show edit button when `showEdit` prop is false', () => { - createComponent({ showEdit: false }); + it('emits `startEditing` event when clicked', () => { + createComponent(); + findEditButton().vm.$emit('click'); - expect(findEditButton().exists()).toBe(false); + expect(wrapper.emitted('startEditing')).toEqual([[]]); + }); }); - it('emits `startEditing` event when edit button is clicked', () => { - createComponent(); - findEditButton().vm.$emit('click'); + describe('emoji picker', () => { + it('is visible when `showAwardEmoji` prop is true', () => { + createComponent(); + + expect(findEmojiButton().exists()).toBe(true); + }); + + it('is hidden when `showAwardEmoji` prop is false', () => { + createComponent({ showAwardEmoji: false }); - expect(wrapper.emitted('startEditing')).toEqual([[]]); + expect(findEmojiButton().exists()).toBe(false); + }); + + it('commits mutation on click', async () => { + const awardName = 'carrot'; + + createComponent(); + + findEmojiButton().vm.$emit('click', awardName); + + await waitForPromises(); + + expect(findEmojiButton().emitted('errors')).toEqual(undefined); + expect(addEmojiMutationResolver).toHaveBeenCalledWith({ + awardableId: noteId, + name: awardName, + }); + }); }); }); |