diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-02-25 00:11:16 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-02-25 00:11:16 +0300 |
commit | 1631d8a2e0eef291f1d0b9486ee35ed6b52a176a (patch) | |
tree | afb91d1d2e0c62d987242e7870d6976a66b9461f /spec | |
parent | 22dc7bdafcf442b96ace849341fb87bca7160614 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
9 files changed, 175 insertions, 188 deletions
diff --git a/spec/features/merge_request/user_toggles_whitespace_changes_spec.rb b/spec/features/merge_request/user_toggles_whitespace_changes_spec.rb index 05f4c16ef60..b72ac071ecb 100644 --- a/spec/features/merge_request/user_toggles_whitespace_changes_spec.rb +++ b/spec/features/merge_request/user_toggles_whitespace_changes_spec.rb @@ -21,13 +21,13 @@ RSpec.describe 'Merge request > User toggles whitespace changes', :js do describe 'clicking "Hide whitespace changes" button' do it 'toggles the "Hide whitespace changes" button' do - find('#show-whitespace').click + find('[data-testid="show-whitespace"]').click visit diffs_project_merge_request_path(project, merge_request) find('.js-show-diff-settings').click - expect(find('#show-whitespace')).not_to be_checked + expect(find('[data-testid="show-whitespace"]')).not_to be_checked end end end diff --git a/spec/features/projects/merge_request_button_spec.rb b/spec/features/projects/merge_request_button_spec.rb index 2a486e6e5e1..9547ba8a390 100644 --- a/spec/features/projects/merge_request_button_spec.rb +++ b/spec/features/projects/merge_request_button_spec.rb @@ -24,7 +24,7 @@ RSpec.describe 'Merge Request button' do project.add_developer(user) end - it 'shows Create merge request button' do + it 'shows Create merge request button', :js do href = project_new_merge_request_path( project, merge_request: { @@ -83,7 +83,7 @@ RSpec.describe 'Merge Request button' do end context 'on own fork of project' do - it 'shows Create merge request button' do + it 'shows Create merge request button', :js do href = project_new_merge_request_path( forked_project, merge_request: { @@ -120,7 +120,7 @@ RSpec.describe 'Merge Request button' do let(:fork_url) { project_compare_path(forked_project, from: 'master', to: 'feature') } end - it 'shows the correct merge request button when viewing across forks' do + it 'shows the correct merge request button when viewing across forks', :js do sign_in(user) project.add_developer(user) diff --git a/spec/frontend/diffs/components/settings_dropdown_spec.js b/spec/frontend/diffs/components/settings_dropdown_spec.js index 33f965f47df..feac88cb802 100644 --- a/spec/frontend/diffs/components/settings_dropdown_spec.js +++ b/spec/frontend/diffs/components/settings_dropdown_spec.js @@ -1,79 +1,66 @@ -import { mount, createLocalVue } from '@vue/test-utils'; -import Vuex from 'vuex'; +import { mount } from '@vue/test-utils'; + +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; + import SettingsDropdown from '~/diffs/components/settings_dropdown.vue'; import { PARALLEL_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE } from '~/diffs/constants'; import eventHub from '~/diffs/event_hub'; -import diffModule from '~/diffs/store/modules'; -const localVue = createLocalVue(); -localVue.use(Vuex); +import createDiffsStore from '../create_diffs_store'; describe('Diff settings dropdown component', () => { let wrapper; let vm; - let actions; + let store; function createComponent(extendStore = () => {}) { - const store = new Vuex.Store({ - modules: { - diffs: { - namespaced: true, - actions, - state: diffModule().state, - getters: diffModule().getters, - }, - }, - }); + store = createDiffsStore(); extendStore(store); - wrapper = mount(SettingsDropdown, { - localVue, - store, - }); + wrapper = extendedWrapper( + mount(SettingsDropdown, { + store, + }), + ); vm = wrapper.vm; } function getFileByFileCheckbox(vueWrapper) { - return vueWrapper.find('[data-testid="file-by-file"]'); + return vueWrapper.findByTestId('file-by-file'); + } + + function setup({ storeUpdater } = {}) { + createComponent(storeUpdater); + jest.spyOn(store, 'dispatch').mockImplementation(() => {}); } beforeEach(() => { - actions = { - setInlineDiffViewType: jest.fn(), - setParallelDiffViewType: jest.fn(), - setRenderTreeList: jest.fn(), - setShowWhitespace: jest.fn(), - setFileByFile: jest.fn(), - }; + setup(); }); afterEach(() => { + store.dispatch.mockRestore(); wrapper.destroy(); }); describe('tree view buttons', () => { it('list view button dispatches setRenderTreeList with false', () => { - createComponent(); - wrapper.find('.js-list-view').trigger('click'); - expect(actions.setRenderTreeList).toHaveBeenCalledWith(expect.anything(), false); + expect(store.dispatch).toHaveBeenCalledWith('diffs/setRenderTreeList', false); }); it('tree view button dispatches setRenderTreeList with true', () => { - createComponent(); - wrapper.find('.js-tree-view').trigger('click'); - expect(actions.setRenderTreeList).toHaveBeenCalledWith(expect.anything(), true); + expect(store.dispatch).toHaveBeenCalledWith('diffs/setRenderTreeList', true); }); it('sets list button as selected when renderTreeList is false', () => { - createComponent((store) => { - Object.assign(store.state.diffs, { - renderTreeList: false, - }); + setup({ + storeUpdater: (origStore) => + Object.assign(origStore.state.diffs, { renderTreeList: false }), }); expect(wrapper.find('.js-list-view').classes('selected')).toBe(true); @@ -81,10 +68,8 @@ describe('Diff settings dropdown component', () => { }); it('sets tree button as selected when renderTreeList is true', () => { - createComponent((store) => { - Object.assign(store.state.diffs, { - renderTreeList: true, - }); + setup({ + storeUpdater: (origStore) => Object.assign(origStore.state.diffs, { renderTreeList: true }), }); expect(wrapper.find('.js-list-view').classes('selected')).toBe(false); @@ -94,10 +79,9 @@ describe('Diff settings dropdown component', () => { describe('compare changes', () => { it('sets inline button as selected', () => { - createComponent((store) => { - Object.assign(store.state.diffs, { - diffViewType: INLINE_DIFF_VIEW_TYPE, - }); + setup({ + storeUpdater: (origStore) => + Object.assign(origStore.state.diffs, { diffViewType: INLINE_DIFF_VIEW_TYPE }), }); expect(wrapper.find('.js-inline-diff-button').classes('selected')).toBe(true); @@ -105,10 +89,9 @@ describe('Diff settings dropdown component', () => { }); it('sets parallel button as selected', () => { - createComponent((store) => { - Object.assign(store.state.diffs, { - diffViewType: PARALLEL_DIFF_VIEW_TYPE, - }); + setup({ + storeUpdater: (origStore) => + Object.assign(origStore.state.diffs, { diffViewType: PARALLEL_DIFF_VIEW_TYPE }), }); expect(wrapper.find('.js-inline-diff-button').classes('selected')).toBe(false); @@ -116,53 +99,49 @@ describe('Diff settings dropdown component', () => { }); it('calls setInlineDiffViewType when clicking inline button', () => { - createComponent(); - wrapper.find('.js-inline-diff-button').trigger('click'); - expect(actions.setInlineDiffViewType).toHaveBeenCalled(); + expect(store.dispatch).toHaveBeenCalledWith('diffs/setInlineDiffViewType', expect.anything()); }); it('calls setParallelDiffViewType when clicking parallel button', () => { - createComponent(); - wrapper.find('.js-parallel-diff-button').trigger('click'); - expect(actions.setParallelDiffViewType).toHaveBeenCalled(); + expect(store.dispatch).toHaveBeenCalledWith( + 'diffs/setParallelDiffViewType', + expect.anything(), + ); }); }); describe('whitespace toggle', () => { it('does not set as checked when showWhitespace is false', () => { - createComponent((store) => { - Object.assign(store.state.diffs, { - showWhitespace: false, - }); + setup({ + storeUpdater: (origStore) => + Object.assign(origStore.state.diffs, { showWhitespace: false }), }); - expect(wrapper.find('#show-whitespace').element.checked).toBe(false); + expect(wrapper.findByTestId('show-whitespace').element.checked).toBe(false); }); it('sets as checked when showWhitespace is true', () => { - createComponent((store) => { - Object.assign(store.state.diffs, { - showWhitespace: true, - }); + setup({ + storeUpdater: (origStore) => Object.assign(origStore.state.diffs, { showWhitespace: true }), }); - expect(wrapper.find('#show-whitespace').element.checked).toBe(true); + expect(wrapper.findByTestId('show-whitespace').element.checked).toBe(true); }); - it('calls setShowWhitespace on change', () => { - createComponent(); + it('calls setShowWhitespace on change', async () => { + const checkbox = wrapper.findByTestId('show-whitespace'); + const { checked } = checkbox.element; - const checkbox = wrapper.find('#show-whitespace'); + checkbox.trigger('click'); - checkbox.element.checked = true; - checkbox.trigger('change'); + await vm.$nextTick(); - expect(actions.setShowWhitespace).toHaveBeenCalledWith(expect.anything(), { - showWhitespace: true, + expect(store.dispatch).toHaveBeenCalledWith('diffs/setShowWhitespace', { + showWhitespace: !checked, pushState: true, }); }); @@ -179,15 +158,12 @@ describe('Diff settings dropdown component', () => { ${false} | ${false} `( 'sets the checkbox to { checked: $checked } if the fileByFile setting is $fileByFile', - async ({ fileByFile, checked }) => { - createComponent((store) => { - Object.assign(store.state.diffs, { - viewDiffsFileByFile: fileByFile, - }); + ({ fileByFile, checked }) => { + setup({ + storeUpdater: (origStore) => + Object.assign(origStore.state.diffs, { viewDiffsFileByFile: fileByFile }), }); - await vm.$nextTick(); - expect(getFileByFileCheckbox(wrapper).element.checked).toBe(checked); }, ); @@ -199,19 +175,16 @@ describe('Diff settings dropdown component', () => { `( 'when the file by file setting starts as $start, toggling the checkbox should call setFileByFile with $setting', async ({ start, setting }) => { - createComponent((store) => { - Object.assign(store.state.diffs, { - viewDiffsFileByFile: start, - }); + setup({ + storeUpdater: (origStore) => + Object.assign(origStore.state.diffs, { viewDiffsFileByFile: start }), }); - await vm.$nextTick(); - getFileByFileCheckbox(wrapper).trigger('click'); await vm.$nextTick(); - expect(actions.setFileByFile).toHaveBeenLastCalledWith(expect.anything(), { + expect(store.dispatch).toHaveBeenCalledWith('diffs/setFileByFile', { fileByFile: setting, }); }, diff --git a/spec/frontend/issue_spec.js b/spec/frontend/issue_spec.js index fb6caef41e2..19f7e6bd5a9 100644 --- a/spec/frontend/issue_spec.js +++ b/spec/frontend/issue_spec.js @@ -1,91 +1,94 @@ +import { getByText } from '@testing-library/dom'; import MockAdapter from 'axios-mock-adapter'; -import $ from 'jquery'; -import Issue from '~/issue'; +import Issue, { EVENT_ISSUABLE_VUE_APP_CHANGE } from '~/issue'; import axios from '~/lib/utils/axios_utils'; -import '~/lib/utils/text_utility'; describe('Issue', () => { - let $boxClosed; - let $boxOpen; let testContext; + let mock; - beforeEach(() => { - testContext = {}; + beforeAll(() => { + preloadFixtures('issues/closed-issue.html'); + preloadFixtures('issues/open-issue.html'); }); - preloadFixtures('issues/closed-issue.html'); - preloadFixtures('issues/open-issue.html'); - - function expectVisibility($element, shouldBeVisible) { - if (shouldBeVisible) { - expect($element).not.toHaveClass('hidden'); - } else { - expect($element).toHaveClass('hidden'); - } - } - - function expectIssueState(isIssueOpen) { - expectVisibility($boxClosed, !isIssueOpen); - expectVisibility($boxOpen, isIssueOpen); - } + beforeEach(() => { + mock = new MockAdapter(axios); + mock.onGet(/(.*)\/related_branches$/).reply(200, {}); - function findElements() { - $boxClosed = $('div.status-box-issue-closed'); + testContext = {}; + testContext.issue = new Issue(); + }); - expect($boxClosed).toExist(); - expect($boxClosed).toHaveText('Closed'); + afterEach(() => { + mock.restore(); + testContext.issue.dispose(); + }); - $boxOpen = $('div.status-box-open'); + const getIssueCounter = () => document.querySelector('.issue_counter'); + const getOpenStatusBox = () => + getByText(document, (_, el) => el.textContent.match(/Open/), { + selector: '.status-box-open', + }); + const getClosedStatusBox = () => + getByText(document, (_, el) => el.textContent.match(/Closed/), { + selector: '.status-box-issue-closed', + }); - expect($boxOpen).toExist(); - expect($boxOpen).toHaveText('Open'); - } + describe.each` + desc | isIssueInitiallyOpen | expectedCounterText + ${'with an initially open issue'} | ${true} | ${'1,000'} + ${'with an initially closed issue'} | ${false} | ${'1,002'} + `('$desc', ({ isIssueInitiallyOpen, expectedCounterText }) => { + beforeEach(() => { + if (isIssueInitiallyOpen) { + loadFixtures('issues/open-issue.html'); + } else { + loadFixtures('issues/closed-issue.html'); + } - [true, false].forEach((isIssueInitiallyOpen) => { - describe(`with ${isIssueInitiallyOpen ? 'open' : 'closed'} issue`, () => { - const action = isIssueInitiallyOpen ? 'close' : 'reopen'; - let mock; + testContext.issueCounter = getIssueCounter(); + testContext.statusBoxClosed = getClosedStatusBox(); + testContext.statusBoxOpen = getOpenStatusBox(); - function setup() { - testContext.issue = new Issue(); - expectIssueState(isIssueInitiallyOpen); + testContext.issueCounter.textContent = '1,001'; + }); - testContext.$projectIssuesCounter = $('.issue_counter').first(); - testContext.$projectIssuesCounter.text('1,001'); + it(`has the proper visible status box when ${isIssueInitiallyOpen ? 'open' : 'closed'}`, () => { + if (isIssueInitiallyOpen) { + expect(testContext.statusBoxClosed).toHaveClass('hidden'); + expect(testContext.statusBoxOpen).not.toHaveClass('hidden'); + } else { + expect(testContext.statusBoxClosed).not.toHaveClass('hidden'); + expect(testContext.statusBoxOpen).toHaveClass('hidden'); } + }); + describe('when vue app triggers change', () => { beforeEach(() => { - if (isIssueInitiallyOpen) { - loadFixtures('issues/open-issue.html'); - } else { - loadFixtures('issues/closed-issue.html'); - } - - mock = new MockAdapter(axios); - mock.onGet(/(.*)\/related_branches$/).reply(200, {}); - jest.spyOn(axios, 'get'); - - findElements(isIssueInitiallyOpen); - }); - - afterEach(() => { - mock.restore(); - $('div.flash-alert').remove(); - }); - - it(`${action}s the issue on dispatch of issuable_vue_app:change event`, () => { - setup(); - document.dispatchEvent( - new CustomEvent('issuable_vue_app:change', { + new CustomEvent(EVENT_ISSUABLE_VUE_APP_CHANGE, { detail: { data: { id: 1 }, isClosed: isIssueInitiallyOpen, }, }), ); + }); + + it('displays correct status box', () => { + if (isIssueInitiallyOpen) { + expect(testContext.statusBoxClosed).not.toHaveClass('hidden'); + expect(testContext.statusBoxOpen).toHaveClass('hidden'); + } else { + expect(testContext.statusBoxClosed).toHaveClass('hidden'); + expect(testContext.statusBoxOpen).not.toHaveClass('hidden'); + } + }); - expectIssueState(!isIssueInitiallyOpen); + it('updates issueCounter text', () => { + expect(testContext.issueCounter).toBeVisible(); + expect(testContext.issueCounter).toHaveText(expectedCounterText); }); }); }); diff --git a/spec/frontend/pipelines/pipelines_actions_spec.js b/spec/frontend/pipelines/pipelines_actions_spec.js index 1e6c9e50a7e..a481b1cb850 100644 --- a/spec/frontend/pipelines/pipelines_actions_spec.js +++ b/spec/frontend/pipelines/pipelines_actions_spec.js @@ -1,5 +1,5 @@ import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; -import { shallowMount, mount } from '@vue/test-utils'; +import { shallowMount } from '@vue/test-utils'; import MockAdapter from 'axios-mock-adapter'; import waitForPromises from 'helpers/wait_for_promises'; import { TEST_HOST } from 'spec/test_constants'; @@ -63,10 +63,6 @@ describe('Pipelines Actions dropdown', () => { }); describe('on click', () => { - beforeEach(() => { - createComponent({ actions: mockActions }, mount); - }); - it('makes a request and toggles the loading state', async () => { mock.onPost(mockActions.path).reply(200); diff --git a/spec/frontend/pipelines/pipelines_artifacts_spec.js b/spec/frontend/pipelines/pipelines_artifacts_spec.js index f077833ae16..d4a2db08d97 100644 --- a/spec/frontend/pipelines/pipelines_artifacts_spec.js +++ b/spec/frontend/pipelines/pipelines_artifacts_spec.js @@ -1,24 +1,27 @@ -import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; -import { mount } from '@vue/test-utils'; +import { GlDropdown, GlDropdownItem, GlSprintf } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; import PipelineArtifacts from '~/pipelines/components/pipelines_list/pipelines_artifacts.vue'; describe('Pipelines Artifacts dropdown', () => { let wrapper; const createComponent = () => { - wrapper = mount(PipelineArtifacts, { + wrapper = shallowMount(PipelineArtifacts, { propsData: { artifacts: [ { - name: 'artifact', + name: 'job my-artifact', path: '/download/path', }, { - name: 'artifact two', + name: 'job-2 my-artifact-2', path: '/download/path-two', }, ], }, + stubs: { + GlSprintf, + }, }); }; @@ -39,8 +42,8 @@ describe('Pipelines Artifacts dropdown', () => { }); it('should render a link with the provided path', () => { - expect(findFirstGlDropdownItem().find('a').attributes('href')).toEqual('/download/path'); + expect(findFirstGlDropdownItem().attributes('href')).toBe('/download/path'); - expect(findFirstGlDropdownItem().text()).toContain('artifact'); + expect(findFirstGlDropdownItem().text()).toBe('Download job my-artifact artifact'); }); }); diff --git a/spec/frontend/pipelines/pipelines_table_row_spec.js b/spec/frontend/pipelines/pipelines_table_row_spec.js index ff997912384..56da636bb3d 100644 --- a/spec/frontend/pipelines/pipelines_table_row_spec.js +++ b/spec/frontend/pipelines/pipelines_table_row_spec.js @@ -1,4 +1,5 @@ import { mount } from '@vue/test-utils'; +import waitForPromises from 'helpers/wait_for_promises'; import PipelinesTableRowComponent from '~/pipelines/components/pipelines_list/pipelines_table_row.vue'; import eventHub from '~/pipelines/event_hub'; @@ -181,10 +182,16 @@ describe('Pipelines Table Row', () => { expect(wrapper.find('.js-pipelines-retry-button').attributes('title')).toMatch('Retry'); expect(wrapper.find('.js-pipelines-cancel-button').exists()).toBe(true); expect(wrapper.find('.js-pipelines-cancel-button').attributes('title')).toMatch('Cancel'); + }); + + it('should render the manual actions', async () => { + const manualActions = wrapper.find('[data-testid="pipelines-manual-actions-dropdown"]'); - const actionsMenu = wrapper.find('[data-testid="pipelines-manual-actions-dropdown"]'); + // Click on the dropdown and wait for `lazy` dropdown items + manualActions.find('.dropdown-toggle').trigger('click'); + await waitForPromises(); - expect(actionsMenu.text()).toContain(scheduledJobAction.name); + expect(manualActions.text()).toContain(scheduledJobAction.name); }); it('emits `retryPipeline` event when retry button is clicked and toggles loading', () => { diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_value_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_value_spec.js index 0d1d6ebcfe5..c90e63313b2 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_value_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_value_spec.js @@ -11,32 +11,31 @@ import { mockConfig, mockRegularLabel, mockScopedLabel } from './mock_data'; const localVue = createLocalVue(); localVue.use(Vuex); -const createComponent = (initialState = mockConfig, slots = {}) => { - const store = new Vuex.Store(labelsSelectModule()); - - store.dispatch('setInitialState', initialState); - - return shallowMount(DropdownValue, { - localVue, - store, - slots, - }); -}; - describe('DropdownValue', () => { let wrapper; - beforeEach(() => { - wrapper = createComponent(); - }); + const createComponent = (initialState = {}, slots = {}) => { + const store = new Vuex.Store(labelsSelectModule()); + + store.dispatch('setInitialState', { ...mockConfig, ...initialState }); + + wrapper = shallowMount(DropdownValue, { + localVue, + store, + slots, + }); + }; afterEach(() => { wrapper.destroy(); + wrapper = null; }); describe('methods', () => { describe('labelFilterUrl', () => { it('returns a label filter URL based on provided label param', () => { + createComponent(); + expect(wrapper.vm.labelFilterUrl(mockRegularLabel)).toBe( '/gitlab-org/my-project/issues?label_name[]=Foo%20Label', ); @@ -44,6 +43,10 @@ describe('DropdownValue', () => { }); describe('scopedLabel', () => { + beforeEach(() => { + createComponent(); + }); + it('returns `true` when provided label param is a scoped label', () => { expect(wrapper.vm.scopedLabel(mockScopedLabel)).toBe(true); }); @@ -56,28 +59,29 @@ describe('DropdownValue', () => { describe('template', () => { it('renders class `has-labels` on component container element when `selectedLabels` is not empty', () => { + createComponent(); + expect(wrapper.attributes('class')).toContain('has-labels'); }); it('renders element containing `None` when `selectedLabels` is empty', () => { - const wrapperNoLabels = createComponent( + createComponent( { - ...mockConfig, selectedLabels: [], }, { default: 'None', }, ); - const noneEl = wrapperNoLabels.find('span.text-secondary'); + const noneEl = wrapper.find('span.text-secondary'); expect(noneEl.exists()).toBe(true); expect(noneEl.text()).toBe('None'); - - wrapperNoLabels.destroy(); }); it('renders labels when `selectedLabels` is not empty', () => { + createComponent(); + expect(wrapper.findAll(GlLabel).length).toBe(2); }); }); diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js index 85a14226585..f293b8422e7 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js @@ -47,6 +47,7 @@ export const mockConfig = { labelsFetchPath: '/gitlab-org/my-project/-/labels.json', labelsManagePath: '/gitlab-org/my-project/-/labels', labelsFilterBasePath: '/gitlab-org/my-project/issues', + labelsFilterParam: 'label_name', }; export const mockSuggestedColors = { |