diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-03-21 15:08:46 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-03-21 15:08:46 +0300 |
commit | 7f521d27811b472c43203ed3d1bde4460a617f89 (patch) | |
tree | 47f1a10b776991e86c6db002bc6e03e83acc356a /spec/frontend | |
parent | 83e3316a189d3b709b23af30647b5f9ea5377bac (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
13 files changed, 131 insertions, 248 deletions
diff --git a/spec/frontend/authentication/two_factor_auth/components/manage_two_factor_form_spec.js b/spec/frontend/authentication/two_factor_auth/components/manage_two_factor_form_spec.js index 694c16a85c4..66f1ca2b32a 100644 --- a/spec/frontend/authentication/two_factor_auth/components/manage_two_factor_form_spec.js +++ b/spec/frontend/authentication/two_factor_auth/components/manage_two_factor_form_spec.js @@ -19,7 +19,6 @@ describe('ManageTwoFactorForm', () => { wrapper = mountExtended(ManageTwoFactorForm, { provide: { ...defaultProvide, - webauthnEnabled: options?.webauthnEnabled ?? false, isCurrentPasswordRequired: options?.currentPasswordRequired ?? true, }, stubs: { @@ -91,17 +90,7 @@ describe('ManageTwoFactorForm', () => { describe('when clicked', () => { itShowsValidationMessageIfCurrentPasswordFieldIsEmpty(findDisableButton); - itShowsConfirmationModal(i18n.confirm); - - describe('when webauthnEnabled', () => { - beforeEach(() => { - createComponent({ - webauthnEnabled: true, - }); - }); - - itShowsConfirmationModal(i18n.confirmWebAuthn); - }); + itShowsConfirmationModal(i18n.confirmWebAuthn); it('modifies the form action and method when submitted through the button', async () => { const form = findForm(); diff --git a/spec/frontend/design_management/components/design_overlay_spec.js b/spec/frontend/design_management/components/design_overlay_spec.js index 2807fe7727f..3eb47fdb97e 100644 --- a/spec/frontend/design_management/components/design_overlay_spec.js +++ b/spec/frontend/design_management/components/design_overlay_spec.js @@ -1,6 +1,6 @@ -import { shallowMount } from '@vue/test-utils'; import Vue, { nextTick } from 'vue'; import VueApollo from 'vue-apollo'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; import DesignOverlay from '~/design_management/components/design_overlay.vue'; @@ -16,22 +16,20 @@ describe('Design overlay component', () => { const mockDimensions = { width: 100, height: 100 }; - const findOverlay = () => wrapper.find('[data-testid="design-overlay"]'); - const findAllNotes = () => wrapper.findAll('[data-testid="note-pin"]'); - const findCommentBadge = () => wrapper.find('[data-testid="comment-badge"]'); + const findOverlay = () => wrapper.findByTestId('design-overlay'); + const findAllNotes = () => wrapper.findAllByTestId('note-pin'); + const findCommentBadge = () => wrapper.findByTestId('comment-badge'); const findBadgeAtIndex = (noteIndex) => findAllNotes().at(noteIndex); const findFirstBadge = () => findBadgeAtIndex(0); const findSecondBadge = () => findBadgeAtIndex(1); - const clickAndDragBadge = async (elem, fromPoint, toPoint) => { + const clickAndDragBadge = (elem, fromPoint, toPoint) => { elem.vm.$emit( 'mousedown', new MouseEvent('click', { clientX: fromPoint.x, clientY: fromPoint.y }), ); findOverlay().trigger('mousemove', { clientX: toPoint.x, clientY: toPoint.y }); - await nextTick(); elem.vm.$emit('mouseup', new MouseEvent('click', { clientX: toPoint.x, clientY: toPoint.y })); - await nextTick(); }; function createComponent(props = {}, data = {}) { @@ -47,7 +45,7 @@ describe('Design overlay component', () => { }, }); - wrapper = shallowMount(DesignOverlay, { + wrapper = shallowMountExtended(DesignOverlay, { apolloProvider, propsData: { dimensions: mockDimensions, @@ -80,7 +78,7 @@ describe('Design overlay component', () => { expect(wrapper.attributes().style).toBe('width: 100px; height: 100px; top: 0px; left: 0px;'); }); - it('should emit `openCommentForm` when clicking on overlay', async () => { + it('should emit `openCommentForm` when clicking on overlay', () => { createComponent(); const newCoordinates = { x: 10, @@ -90,7 +88,7 @@ describe('Design overlay component', () => { wrapper .find('[data-qa-selector="design_image_button"]') .trigger('mouseup', { offsetX: newCoordinates.x, offsetY: newCoordinates.y }); - await nextTick(); + expect(wrapper.emitted('openCommentForm')).toEqual([ [{ x: newCoordinates.x, y: newCoordinates.y }], ]); @@ -175,25 +173,15 @@ describe('Design overlay component', () => { }); }); - it('should recalculate badges positions on window resize', async () => { + it('should calculate badges positions based on dimensions', () => { createComponent({ notes, dimensions: { - width: 400, - height: 400, - }, - }); - - expect(findFirstBadge().props('position')).toEqual({ left: '40px', top: '60px' }); - - wrapper.setProps({ - dimensions: { width: 200, height: 200, }, }); - await nextTick(); expect(findFirstBadge().props('position')).toEqual({ left: '20px', top: '30px' }); }); @@ -216,7 +204,6 @@ describe('Design overlay component', () => { new MouseEvent('click', { clientX: position.x, clientY: position.y }), ); - await nextTick(); findFirstBadge().vm.$emit( 'mouseup', new MouseEvent('click', { clientX: position.x, clientY: position.y }), @@ -290,7 +277,7 @@ describe('Design overlay component', () => { }); describe('when moving the comment badge', () => { - it('should update badge style when note-moving action ends', async () => { + it('should update badge style when note-moving action ends', () => { const { position } = notes[0]; createComponent({ currentCommentForm: { @@ -298,19 +285,15 @@ describe('Design overlay component', () => { }, }); - const commentBadge = findCommentBadge(); + expect(findCommentBadge().props('position')).toEqual({ left: '10px', top: '15px' }); + const toPoint = { x: 20, y: 20 }; - await clickAndDragBadge(commentBadge, { x: position.x, y: position.y }, toPoint); - commentBadge.vm.$emit('mouseup', new MouseEvent('click')); - // simulates the currentCommentForm being updated in index.vue component, and - // propagated back down to this prop - wrapper.setProps({ + createComponent({ currentCommentForm: { height: position.height, width: position.width, ...toPoint }, }); - await nextTick(); - expect(commentBadge.props('position')).toEqual({ left: '20px', top: '20px' }); + expect(findCommentBadge().props('position')).toEqual({ left: '20px', top: '20px' }); }); it('should emit `openCommentForm` event when mouseleave fired on overlay element', async () => { @@ -330,8 +313,7 @@ describe('Design overlay component', () => { newCoordinates, ); - wrapper.trigger('mouseleave'); - await nextTick(); + findOverlay().vm.$emit('mouseleave'); expect(wrapper.emitted('openCommentForm')).toEqual([[newCoordinates]]); }); diff --git a/spec/frontend/diffs/components/diff_line_note_form_spec.js b/spec/frontend/diffs/components/diff_line_note_form_spec.js index bd0e3455872..eb895bd9057 100644 --- a/spec/frontend/diffs/components/diff_line_note_form_spec.js +++ b/spec/frontend/diffs/components/diff_line_note_form_spec.js @@ -1,7 +1,6 @@ import { shallowMount } from '@vue/test-utils'; import { nextTick } from 'vue'; import Vuex from 'vuex'; -import Autosave from '~/autosave'; import DiffLineNoteForm from '~/diffs/components/diff_line_note_form.vue'; import { createModules } from '~/mr_notes/stores'; import NoteForm from '~/notes/components/note_form.vue'; @@ -11,7 +10,6 @@ import { noteableDataMock } from 'jest/notes/mock_data'; import { getDiffFileMock } from '../mock_data/diff_file'; jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal'); -jest.mock('~/autosave'); describe('DiffLineNoteForm', () => { let wrapper; @@ -77,7 +75,6 @@ describe('DiffLineNoteForm', () => { const findCommentForm = () => wrapper.findComponent(MultilineCommentForm); beforeEach(() => { - Autosave.mockClear(); createComponent(); }); @@ -100,19 +97,6 @@ describe('DiffLineNoteForm', () => { }); }); - it('should init autosave', () => { - // we're using shallow mount here so there's no element to pass to Autosave - expect(Autosave).toHaveBeenCalledWith(undefined, [ - 'Note', - 'Issue', - 98, - undefined, - 'DiffNote', - undefined, - '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_2', - ]); - }); - describe('when cancelling form', () => { afterEach(() => { confirmAction.mockReset(); @@ -146,7 +130,6 @@ describe('DiffLineNoteForm', () => { await nextTick(); expect(getSelectedLine().hasForm).toBe(false); - expect(Autosave.mock.instances[0].reset).toHaveBeenCalled(); }); }); diff --git a/spec/frontend/lib/utils/error_message_spec.js b/spec/frontend/lib/utils/error_message_spec.js index 17b5168c32f..54c630b8ba0 100644 --- a/spec/frontend/lib/utils/error_message_spec.js +++ b/spec/frontend/lib/utils/error_message_spec.js @@ -1,65 +1,43 @@ import { parseErrorMessage, USER_FACING_ERROR_MESSAGE_PREFIX } from '~/lib/utils/error_message'; -const defaultErrorMessage = 'Something caused this error'; -const userFacingErrorMessage = 'User facing error message'; -const nonUserFacingErrorMessage = 'NonUser facing error message'; -const genericErrorMessage = 'Some error message'; - -describe('error message', () => { - describe('when given an errormessage object', () => { - const errorMessageObject = { - options: { - cause: defaultErrorMessage, - }, - filename: 'error.js', - linenumber: 7, - }; - - it('returns the correct values for userfacing errors', () => { - const userFacingObject = errorMessageObject; - userFacingObject.message = `${USER_FACING_ERROR_MESSAGE_PREFIX} ${userFacingErrorMessage}`; - - expect(parseErrorMessage(userFacingObject)).toEqual({ - message: userFacingErrorMessage, - userFacing: true, - }); - }); - - it('returns the correct values for non userfacing errors', () => { - const nonUserFacingObject = errorMessageObject; - nonUserFacingObject.message = nonUserFacingErrorMessage; - - expect(parseErrorMessage(nonUserFacingObject)).toEqual({ - message: nonUserFacingErrorMessage, - userFacing: false, - }); - }); - }); - - describe('when given an errormessage string', () => { - it('returns the correct values for userfacing errors', () => { - expect( - parseErrorMessage(`${USER_FACING_ERROR_MESSAGE_PREFIX} ${genericErrorMessage}`), - ).toEqual({ - message: genericErrorMessage, - userFacing: true, - }); - }); - - it('returns the correct values for non userfacing errors', () => { - expect(parseErrorMessage(genericErrorMessage)).toEqual({ - message: genericErrorMessage, - userFacing: false, - }); - }); - }); - - describe('when given nothing', () => { - it('returns an empty error message', () => { - expect(parseErrorMessage()).toEqual({ - message: '', - userFacing: false, - }); - }); - }); +const defaultErrorMessage = 'Default error message'; +const errorMessage = 'Returned error message'; + +const generateErrorWithMessage = (message) => { + return { + message, + }; +}; + +describe('parseErrorMessage', () => { + it.each` + error | expectedResult + ${`${USER_FACING_ERROR_MESSAGE_PREFIX} ${errorMessage}`} | ${errorMessage} + ${`${errorMessage} ${USER_FACING_ERROR_MESSAGE_PREFIX}`} | ${defaultErrorMessage} + ${errorMessage} | ${defaultErrorMessage} + ${undefined} | ${defaultErrorMessage} + ${''} | ${defaultErrorMessage} + `( + 'properly parses "$error" error object and returns "$expectedResult"', + ({ error, expectedResult }) => { + const errorObject = generateErrorWithMessage(error); + expect(parseErrorMessage(errorObject, defaultErrorMessage)).toEqual(expectedResult); + }, + ); + + it.each` + error | defaultMessage | expectedResult + ${undefined} | ${defaultErrorMessage} | ${defaultErrorMessage} + ${''} | ${defaultErrorMessage} | ${defaultErrorMessage} + ${{}} | ${defaultErrorMessage} | ${defaultErrorMessage} + ${generateErrorWithMessage(errorMessage)} | ${undefined} | ${''} + ${generateErrorWithMessage(`${USER_FACING_ERROR_MESSAGE_PREFIX} ${errorMessage}`)} | ${undefined} | ${errorMessage} + ${generateErrorWithMessage(errorMessage)} | ${''} | ${''} + ${generateErrorWithMessage(`${USER_FACING_ERROR_MESSAGE_PREFIX} ${errorMessage}`)} | ${''} | ${errorMessage} + `( + 'properly handles the edge case of error="$error" and defaultMessage="$defaultMessage"', + ({ error, defaultMessage, expectedResult }) => { + expect(parseErrorMessage(error, defaultMessage)).toEqual(expectedResult); + }, + ); }); diff --git a/spec/frontend/notes/components/comment_form_spec.js b/spec/frontend/notes/components/comment_form_spec.js index 062cd098640..891b5c751fb 100644 --- a/spec/frontend/notes/components/comment_form_spec.js +++ b/spec/frontend/notes/components/comment_form_spec.js @@ -5,6 +5,7 @@ import MockAdapter from 'axios-mock-adapter'; import Vue, { nextTick } from 'vue'; import Vuex from 'vuex'; import { extendedWrapper } from 'helpers/vue_test_utils_helper'; +import { useLocalStorageSpy } from 'helpers/local_storage_helper'; import batchComments from '~/batch_comments/stores/modules/batch_comments'; import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests'; import { createAlert } from '~/alert'; @@ -27,6 +28,8 @@ jest.mock('~/alert'); Vue.use(Vuex); describe('issue_comment_form component', () => { + useLocalStorageSpy(); + let store; let wrapper; let axiosMock; diff --git a/spec/frontend/notes/components/note_body_spec.js b/spec/frontend/notes/components/note_body_spec.js index b4f185004bb..c4f8e50b969 100644 --- a/spec/frontend/notes/components/note_body_spec.js +++ b/spec/frontend/notes/components/note_body_spec.js @@ -7,10 +7,7 @@ import NoteAwardsList from '~/notes/components/note_awards_list.vue'; import NoteForm from '~/notes/components/note_form.vue'; import createStore from '~/notes/stores'; import notes from '~/notes/stores/modules/index'; -import Autosave from '~/autosave'; - import Suggestions from '~/vue_shared/components/markdown/suggestions.vue'; - import { noteableDataMock, notesDataMock, note } from '../mock_data'; jest.mock('~/autosave'); @@ -82,11 +79,6 @@ describe('issue_note_body component', () => { expect(wrapper.findComponent(NoteForm).props('saveButtonTitle')).toBe(buttonText); }); - it('adds autosave', () => { - // passing undefined instead of an element because of shallowMount - expect(Autosave).toHaveBeenCalledWith(undefined, ['Note', note.noteable_type, note.id]); - }); - describe('isInternalNote', () => { beforeEach(() => { wrapper.setProps({ isInternalNote: true }); diff --git a/spec/frontend/notes/components/note_form_spec.js b/spec/frontend/notes/components/note_form_spec.js index 59362e18098..12c3b154fc7 100644 --- a/spec/frontend/notes/components/note_form_spec.js +++ b/spec/frontend/notes/components/note_form_spec.js @@ -2,7 +2,6 @@ import { GlLink } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; import { nextTick } from 'vue'; import batchComments from '~/batch_comments/stores/modules/batch_comments'; -import { getDraft, updateDraft } from '~/lib/utils/autosave'; import NoteForm from '~/notes/components/note_form.vue'; import createStore from '~/notes/stores'; import MarkdownField from '~/vue_shared/components/markdown/field.vue'; @@ -12,30 +11,25 @@ import { noteableDataMock, notesDataMock, discussionMock, note } from '../mock_d jest.mock('~/lib/utils/autosave'); describe('issue_note_form component', () => { - const dummyAutosaveKey = 'some-autosave-key'; - const dummyDraft = 'dummy draft content'; - let store; let wrapper; let props; + let features; const createComponentWrapper = () => { return mount(NoteForm, { store, propsData: props, + provide: { + glFeatures: features || {}, + }, }); }; const findCancelButton = () => wrapper.find('[data-testid="cancel"]'); beforeEach(() => { - getDraft.mockImplementation((key) => { - if (key === dummyAutosaveKey) { - return dummyDraft; - } - - return null; - }); + features = {}; store = createStore(); store.dispatch('setNoteableData', noteableDataMock); @@ -68,6 +62,20 @@ describe('issue_note_form component', () => { }); }); + it('hides content editor switcher if feature flag content_editor_on_issues is off', () => { + features = { contentEditorOnIssues: false }; + wrapper = createComponentWrapper(); + + expect(wrapper.text()).not.toContain('Rich text'); + }); + + it('shows content editor switcher if feature flag content_editor_on_issues is on', () => { + features = { contentEditorOnIssues: true }; + wrapper = createComponentWrapper(); + + expect(wrapper.text()).toContain('Rich text'); + }); + describe('conflicts editing', () => { beforeEach(() => { wrapper = createComponentWrapper(); @@ -117,13 +125,15 @@ describe('issue_note_form component', () => { ${true} | ${'Write an internal note or drag your files hereā¦'} `( 'should set correct textarea placeholder text when discussion confidentiality is $internal', - ({ internal, placeholder }) => { + async ({ internal, placeholder }) => { props.note = { ...note, internal, }; wrapper = createComponentWrapper(); + await nextTick(); + expect(wrapper.find('textarea').attributes('placeholder')).toBe(placeholder); }, ); @@ -204,7 +214,7 @@ describe('issue_note_form component', () => { }); await nextTick(); - const textareaEl = wrapper.vm.$refs.textarea; + const textareaEl = wrapper.vm.$refs.markdownEditor.$el.querySelector('textarea'); const cancelButton = findCancelButton(); textareaEl.classList.add(AT_WHO_ACTIVE_CLASS); cancelButton.vm.$emit('click'); @@ -229,78 +239,6 @@ describe('issue_note_form component', () => { }); }); - describe('with autosaveKey', () => { - describe('with draft', () => { - beforeEach(() => { - Object.assign(props, { - noteBody: '', - autosaveKey: dummyAutosaveKey, - }); - wrapper = createComponentWrapper(); - - return nextTick(); - }); - - it('displays the draft in textarea', () => { - const textarea = wrapper.find('textarea'); - - expect(textarea.element.value).toBe(dummyDraft); - }); - }); - - describe('without draft', () => { - beforeEach(() => { - Object.assign(props, { - noteBody: '', - autosaveKey: 'some key without draft', - }); - wrapper = createComponentWrapper(); - - return nextTick(); - }); - - it('leaves the textarea empty', () => { - const textarea = wrapper.find('textarea'); - - expect(textarea.element.value).toBe(''); - }); - }); - - it('updates the draft if textarea content changes', () => { - Object.assign(props, { - noteBody: '', - autosaveKey: dummyAutosaveKey, - }); - wrapper = createComponentWrapper(); - const textarea = wrapper.find('textarea'); - const dummyContent = 'some new content'; - - textarea.setValue(dummyContent); - - expect(updateDraft).toHaveBeenCalledWith(dummyAutosaveKey, dummyContent); - }); - - it('does not save draft when ctrl+enter is pressed', () => { - const options = { - noteBody: '', - autosaveKey: dummyAutosaveKey, - }; - - props = { ...props, ...options }; - wrapper = createComponentWrapper(); - - // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details - // eslint-disable-next-line no-restricted-syntax - wrapper.setData({ isSubmittingWithKeydown: true }); - - const textarea = wrapper.find('textarea'); - textarea.setValue('some content'); - textarea.trigger('keydown.enter', { metaKey: true }); - - expect(updateDraft).not.toHaveBeenCalled(); - }); - }); - describe('with batch comments', () => { beforeEach(() => { store.registerModule('batchComments', batchComments()); diff --git a/spec/frontend/security_configuration/components/app_spec.js b/spec/frontend/security_configuration/components/app_spec.js index 0ca350f9ed7..ae5316eb12f 100644 --- a/spec/frontend/security_configuration/components/app_spec.js +++ b/spec/frontend/security_configuration/components/app_spec.js @@ -26,8 +26,6 @@ import { REPORT_TYPE_LICENSE_COMPLIANCE, REPORT_TYPE_SAST, } from '~/vue_shared/security_reports/constants'; -import { USER_FACING_ERROR_MESSAGE_PREFIX } from '~/lib/utils/error_message'; -import { manageViaMRErrorMessage } from '../constants'; const upgradePath = '/upgrade'; const autoDevopsHelpPagePath = '/autoDevopsHelpPagePath'; @@ -202,21 +200,20 @@ describe('App component', () => { }); }); - describe('when user facing error occurs', () => { + describe('when error occurs', () => { + const errorMessage = 'There was a manage via MR error'; + it('should show Alert with error Message', async () => { expect(findManageViaMRErrorAlert().exists()).toBe(false); - // Prefixed with USER_FACING_ERROR_MESSAGE_PREFIX as used in lib/gitlab/utils/error_message.rb to indicate a user facing error - findFeatureCards() - .at(1) - .vm.$emit('error', `${USER_FACING_ERROR_MESSAGE_PREFIX} ${manageViaMRErrorMessage}`); + findFeatureCards().at(1).vm.$emit('error', errorMessage); await nextTick(); expect(findManageViaMRErrorAlert().exists()).toBe(true); - expect(findManageViaMRErrorAlert().text()).toEqual(manageViaMRErrorMessage); + expect(findManageViaMRErrorAlert().text()).toBe(errorMessage); }); it('should hide Alert when it is dismissed', async () => { - findFeatureCards().at(1).vm.$emit('error', manageViaMRErrorMessage); + findFeatureCards().at(1).vm.$emit('error', errorMessage); await nextTick(); expect(findManageViaMRErrorAlert().exists()).toBe(true); @@ -226,17 +223,6 @@ describe('App component', () => { expect(findManageViaMRErrorAlert().exists()).toBe(false); }); }); - - describe('when non-user facing error occurs', () => { - it('should show Alert with generic error Message', async () => { - expect(findManageViaMRErrorAlert().exists()).toBe(false); - findFeatureCards().at(1).vm.$emit('error', manageViaMRErrorMessage); - - await nextTick(); - expect(findManageViaMRErrorAlert().exists()).toBe(true); - expect(findManageViaMRErrorAlert().text()).toEqual(i18n.genericErrorText); - }); - }); }); describe('Auto DevOps hint alert', () => { diff --git a/spec/frontend/super_sidebar/components/context_switcher_spec.js b/spec/frontend/super_sidebar/components/context_switcher_spec.js index 538e87cf843..92df8129799 100644 --- a/spec/frontend/super_sidebar/components/context_switcher_spec.js +++ b/spec/frontend/super_sidebar/components/context_switcher_spec.js @@ -5,6 +5,7 @@ import * as Sentry from '@sentry/browser'; import { s__ } from '~/locale'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import ContextSwitcher from '~/super_sidebar/components/context_switcher.vue'; +import NavItem from '~/super_sidebar/components/nav_item.vue'; import ProjectsList from '~/super_sidebar/components/projects_list.vue'; import GroupsList from '~/super_sidebar/components/groups_list.vue'; import createMockApollo from 'helpers/mock_apollo_helper'; @@ -23,6 +24,7 @@ jest.mock('~/super_sidebar/utils', () => ({ trackContextAccess: jest.fn(), })); +const persistentLinks = [{ title: 'Explore', link: '/explore', icon: 'compass' }]; const username = 'root'; const projectsPath = 'projectsPath'; const groupsPath = 'groupsPath'; @@ -33,6 +35,7 @@ describe('ContextSwitcher component', () => { let wrapper; let mockApollo; + const findNavItems = () => wrapper.findAllComponents(NavItem); const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType); const findProjectsList = () => wrapper.findComponent(ProjectsList); const findGroupsList = () => wrapper.findComponent(GroupsList); @@ -60,6 +63,7 @@ describe('ContextSwitcher component', () => { wrapper = shallowMountExtended(ContextSwitcher, { apolloProvider: mockApollo, propsData: { + persistentLinks, username, projectsPath, groupsPath, @@ -84,6 +88,12 @@ describe('ContextSwitcher component', () => { createWrapper(); }); + it('renders the persistent links', () => { + const navItems = findNavItems(); + expect(navItems.length).toBe(persistentLinks.length); + expect(navItems.at(0).props('item')).toBe(persistentLinks[0]); + }); + it('passes the placeholder to the search box', () => { expect(findSearchBox().props('placeholder')).toBe( s__('Navigation|Search for projects or groups'), @@ -138,6 +148,10 @@ describe('ContextSwitcher component', () => { return triggerSearchQuery(); }); + it('hides persistent links', () => { + expect(findNavItems().length).toBe(0); + }); + it('triggers the search query on search', () => { expect(searchUserProjectsAndGroupsHandlerSuccess).toHaveBeenCalled(); }); diff --git a/spec/frontend/super_sidebar/components/search_results_spec.js b/spec/frontend/super_sidebar/components/search_results_spec.js index dd48935c138..daec5c2a9b4 100644 --- a/spec/frontend/super_sidebar/components/search_results_spec.js +++ b/spec/frontend/super_sidebar/components/search_results_spec.js @@ -1,7 +1,9 @@ +import { GlCollapse } from '@gitlab/ui'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { s__ } from '~/locale'; import SearchResults from '~/super_sidebar/components/search_results.vue'; import ItemsList from '~/super_sidebar/components/items_list.vue'; +import { stubComponent } from 'helpers/stub_component'; const title = s__('Navigation|PROJECTS'); const noResultsText = s__('Navigation|No project matches found'); @@ -9,7 +11,8 @@ const noResultsText = s__('Navigation|No project matches found'); describe('SearchResults component', () => { let wrapper; - const findListTitle = () => wrapper.findByTestId('list-title'); + const findSearchResultsToggle = () => wrapper.findByTestId('search-results-toggle'); + const findCollapsibleSection = () => wrapper.findComponent(GlCollapse); const findItemsList = () => wrapper.findComponent(ItemsList); const findEmptyText = () => wrapper.findByTestId('empty-text'); @@ -20,6 +23,11 @@ describe('SearchResults component', () => { noResultsText, ...props, }, + stubs: { + GlCollapse: stubComponent(GlCollapse, { + props: ['visible'], + }), + }, }); }; @@ -29,7 +37,11 @@ describe('SearchResults component', () => { }); it("renders the list's title", () => { - expect(findListTitle().text()).toBe(title); + expect(findSearchResultsToggle().text()).toBe(title); + }); + + it('is expanded', () => { + expect(findCollapsibleSection().props('visible')).toBe(true); }); it('renders the empty text', () => { diff --git a/spec/frontend/super_sidebar/mock_data.js b/spec/frontend/super_sidebar/mock_data.js index b540f85d9fe..8c70693465f 100644 --- a/spec/frontend/super_sidebar/mock_data.js +++ b/spec/frontend/super_sidebar/mock_data.js @@ -86,6 +86,7 @@ export const sidebarData = { gitlab_version_check: { severity: 'success' }, gitlab_com_and_canary: false, canary_toggle_com_url: 'https://next.gitlab.com', + context_switcher_links: [], }; export const userMenuMockStatus = { diff --git a/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js b/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js index 681ff6c8dd3..7bda37bcaa8 100644 --- a/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js +++ b/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js @@ -275,7 +275,7 @@ describe('vue_shared/component/markdown/markdown_editor', () => { await findTextarea().setValue(newValue); - expect(wrapper.emitted('input')).toEqual([[newValue]]); + expect(wrapper.emitted('input')).toEqual([[value], [newValue]]); }); it('autosaves the markdown value to local storage', async () => { @@ -370,7 +370,7 @@ describe('vue_shared/component/markdown/markdown_editor', () => { await findContentEditor().vm.$emit('change', { markdown: newValue }); - expect(wrapper.emitted('input')).toEqual([[newValue]]); + expect(wrapper.emitted('input')).toEqual([[value], [newValue]]); }); it('autosaves the content editor value to local storage', async () => { diff --git a/spec/frontend/vue_shared/security_reports/components/manage_via_mr_spec.js b/spec/frontend/vue_shared/security_reports/components/manage_via_mr_spec.js index 6345393951c..646b37d334b 100644 --- a/spec/frontend/vue_shared/security_reports/components/manage_via_mr_spec.js +++ b/spec/frontend/vue_shared/security_reports/components/manage_via_mr_spec.js @@ -8,7 +8,9 @@ import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import waitForPromises from 'helpers/wait_for_promises'; import { humanize } from '~/lib/utils/text_utility'; import { redirectTo } from '~/lib/utils/url_utility'; -import ManageViaMr from '~/vue_shared/security_configuration/components/manage_via_mr.vue'; +import ManageViaMr, { + i18n, +} from '~/vue_shared/security_configuration/components/manage_via_mr.vue'; import { REPORT_TYPE_SAST } from '~/vue_shared/security_reports/constants'; import { buildConfigureSecurityFeatureMockFactory } from './apollo_mocks'; @@ -77,10 +79,11 @@ describe('ManageViaMr component', () => { buildConfigureSecurityFeatureMock({ successPath: '', }); - const errorHandler = async () => - buildConfigureSecurityFeatureMock({ - errors: ['foo'], + const errorHandler = async (message = 'foo') => { + return buildConfigureSecurityFeatureMock({ + errors: [message], }); + }; const pendingHandler = () => new Promise(() => {}); describe('when feature is configured', () => { @@ -147,9 +150,11 @@ describe('ManageViaMr component', () => { }); describe.each` - handler | message - ${noSuccessPathHandler} | ${`${featureName} merge request creation mutation failed`} - ${errorHandler} | ${'foo'} + handler | message + ${noSuccessPathHandler} | ${`${featureName} merge request creation mutation failed`} + ${errorHandler.bind(null, 'UF: message')} | ${'message'} + ${errorHandler.bind(null, 'message')} | ${i18n.genericErrorText} + ${errorHandler} | ${i18n.genericErrorText} `('given an error response', ({ handler, message }) => { beforeEach(() => { const apolloProvider = createMockApolloProvider(mutation, handler); |