From d44c21180248ea0e52f4c6d7b00f06c2129bb97c Mon Sep 17 00:00:00 2001 From: Samantha Ming Date: Thu, 28 Jan 2021 01:51:04 -0800 Subject: [PATCH 1/2] Convert compare revision into Vue This change is part of issue: https://gitlab.com/gitlab-org/gitlab/-/issues/14615 --- .../pages/projects/compare/index/index.js | 3 + .../projects/compare/components/app.vue | 89 +++++++++++ .../compare/components/revision_dropdown.vue | 145 ++++++++++++++++++ .../javascripts/projects/compare/index.js | 33 ++++ app/assets/stylesheets/pages/projects.scss | 14 ++ app/views/projects/compare/index.html.haml | 6 +- locale/gitlab.pot | 24 +++ .../commits/user_browses_commits_spec.rb | 9 +- spec/features/projects/compare_spec.rb | 23 +-- .../projects/compare/components/app_spec.js | 116 ++++++++++++++ .../components/revision_dropdown_spec.js | 92 +++++++++++ 11 files changed, 540 insertions(+), 14 deletions(-) create mode 100644 app/assets/javascripts/pages/projects/compare/index/index.js create mode 100644 app/assets/javascripts/projects/compare/components/app.vue create mode 100644 app/assets/javascripts/projects/compare/components/revision_dropdown.vue create mode 100644 app/assets/javascripts/projects/compare/index.js create mode 100644 spec/frontend/projects/compare/components/app_spec.js create mode 100644 spec/frontend/projects/compare/components/revision_dropdown_spec.js diff --git a/app/assets/javascripts/pages/projects/compare/index/index.js b/app/assets/javascripts/pages/projects/compare/index/index.js new file mode 100644 index 00000000000000..b86c9ec442fc1b --- /dev/null +++ b/app/assets/javascripts/pages/projects/compare/index/index.js @@ -0,0 +1,3 @@ +import initCompareSelector from '~/projects/compare'; + +initCompareSelector(); diff --git a/app/assets/javascripts/projects/compare/components/app.vue b/app/assets/javascripts/projects/compare/components/app.vue new file mode 100644 index 00000000000000..05bd0f1370b85b --- /dev/null +++ b/app/assets/javascripts/projects/compare/components/app.vue @@ -0,0 +1,89 @@ + + + diff --git a/app/assets/javascripts/projects/compare/components/revision_dropdown.vue b/app/assets/javascripts/projects/compare/components/revision_dropdown.vue new file mode 100644 index 00000000000000..1d18458a6f9148 --- /dev/null +++ b/app/assets/javascripts/projects/compare/components/revision_dropdown.vue @@ -0,0 +1,145 @@ + + + diff --git a/app/assets/javascripts/projects/compare/index.js b/app/assets/javascripts/projects/compare/index.js new file mode 100644 index 00000000000000..4337eecb667be6 --- /dev/null +++ b/app/assets/javascripts/projects/compare/index.js @@ -0,0 +1,33 @@ +import Vue from 'vue'; +import CompareApp from './components/app.vue'; + +export default function init() { + const el = document.getElementById('js-compare-selector'); + const { + refsProjectPath, + paramsFrom, + paramsTo, + projectCompareIndexPath, + projectMergeRequestPath, + createMrPath, + } = el.dataset; + + return new Vue({ + el, + components: { + CompareApp, + }, + render(createElement) { + return createElement(CompareApp, { + props: { + refsProjectPath, + paramsFrom, + paramsTo, + projectCompareIndexPath, + projectMergeRequestPath, + createMrPath, + }, + }); + }, + }); +} diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index 1648c5e0a42730..8251cdb9bbba6b 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -992,6 +992,20 @@ pre.light-well { width: auto; } } + + // Remove once gitlab/ui solution is implemented: + // https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1157 + // https://gitlab.com/gitlab-org/gitlab/-/issues/300405 + .gl-search-box-by-type-input { + width: 100%; + } + + // Remove once gitlab/ui solution is implemented + // https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1158 + // https://gitlab.com/gitlab-org/gitlab/-/issues/300405 + .gl-new-dropdown-button-text { + @include str-truncated; + } } .clearable-input { diff --git a/app/views/projects/compare/index.html.haml b/app/views/projects/compare/index.html.haml index e45ea209e8c050..3f9aa24a569eb2 100644 --- a/app/views/projects/compare/index.html.haml +++ b/app/views/projects/compare/index.html.haml @@ -13,4 +13,8 @@ = html_escape(_("Changes are shown as if the %{b_open}source%{b_close} revision was being merged into the %{b_open}target%{b_close} revision.")) % { b_open: ''.html_safe, b_close: ''.html_safe } .prepend-top-20 - = render "form" + #js-compare-selector{ data: { project_compare_index_path: project_compare_index_path(@project), + refs_project_path: refs_project_path(@project), + params_from: params[:from], params_to: params[:to], + project_merge_request_path: @merge_request.present? ? project_merge_request_path(@project, @merge_request) : '', + create_mr_path: create_mr_button? ? create_mr_path : '' } } diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 91300f92f80533..7e9a9c33950192 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -7343,6 +7343,30 @@ msgstr "" msgid "CompareBranches|There isn't anything to compare." msgstr "" +msgid "CompareRevisions|Branches" +msgstr "" + +msgid "CompareRevisions|Compare" +msgstr "" + +msgid "CompareRevisions|Create merge request" +msgstr "" + +msgid "CompareRevisions|Filter by Git revision" +msgstr "" + +msgid "CompareRevisions|Select branch/tag" +msgstr "" + +msgid "CompareRevisions|Tags" +msgstr "" + +msgid "CompareRevisions|There was an error while updating the branch/tag list. Please try again." +msgstr "" + +msgid "CompareRevisions|View open merge request" +msgstr "" + msgid "Complete" msgstr "" diff --git a/spec/features/projects/commits/user_browses_commits_spec.rb b/spec/features/projects/commits/user_browses_commits_spec.rb index 596b47737166ab..4894e2b7f3e2a5 100644 --- a/spec/features/projects/commits/user_browses_commits_spec.rb +++ b/spec/features/projects/commits/user_browses_commits_spec.rb @@ -203,10 +203,11 @@ context 'when click the compare tab' do before do + wait_for_requests click_link('Compare') end - it 'does not render create merge request button' do + it 'does not render create merge request button', :js do expect(page).not_to have_link 'Create merge request' end end @@ -236,10 +237,11 @@ context 'when click the compare tab' do before do + wait_for_requests click_link('Compare') end - it 'renders create merge request button' do + it 'renders create merge request button', :js do expect(page).to have_link 'Create merge request' end end @@ -276,10 +278,11 @@ context 'when click the compare tab' do before do + wait_for_requests click_link('Compare') end - it 'renders button to the merge request' do + it 'renders button to the merge request', :js do expect(page).not_to have_link 'Create merge request' expect(page).to have_link 'View open merge request', href: project_merge_request_path(project, merge_request) end diff --git a/spec/features/projects/compare_spec.rb b/spec/features/projects/compare_spec.rb index e387ea4d473b0c..64e9968061c533 100644 --- a/spec/features/projects/compare_spec.rb +++ b/spec/features/projects/compare_spec.rb @@ -17,10 +17,10 @@ visit project_compare_index_path(project, from: 'master', to: 'master') select_using_dropdown 'from', 'feature' - expect(find('.js-compare-from-dropdown .dropdown-toggle-text')).to have_content('feature') + expect(find('.js-compare-from-dropdown .gl-new-dropdown-button-text')).to have_content('feature') select_using_dropdown 'to', 'binary-encoding' - expect(find('.js-compare-to-dropdown .dropdown-toggle-text')).to have_content('binary-encoding') + expect(find('.js-compare-to-dropdown .gl-new-dropdown-button-text')).to have_content('binary-encoding') click_button 'Compare' @@ -32,8 +32,8 @@ it "pre-populates fields" do visit project_compare_index_path(project, from: "master", to: "master") - expect(find(".js-compare-from-dropdown .dropdown-toggle-text")).to have_content("master") - expect(find(".js-compare-to-dropdown .dropdown-toggle-text")).to have_content("master") + expect(find(".js-compare-from-dropdown .gl-new-dropdown-button-text")).to have_content("master") + expect(find(".js-compare-to-dropdown .gl-new-dropdown-button-text")).to have_content("master") end it_behaves_like 'compares branches' @@ -99,7 +99,7 @@ find(".js-compare-from-dropdown .compare-dropdown-toggle").click - expect(find(".js-compare-from-dropdown .dropdown-content")).to have_selector("li", count: 3) + expect(find(".js-compare-from-dropdown .gl-new-dropdown-contents")).to have_selector('li.gl-new-dropdown-item', count: 1) end context 'when commit has overflow', :js do @@ -125,10 +125,10 @@ visit project_compare_index_path(project, from: "master", to: "master") select_using_dropdown "from", "v1.0.0" - expect(find(".js-compare-from-dropdown .dropdown-toggle-text")).to have_content("v1.0.0") + expect(find(".js-compare-from-dropdown .gl-new-dropdown-button-text")).to have_content("v1.0.0") select_using_dropdown "to", "v1.1.0" - expect(find(".js-compare-to-dropdown .dropdown-toggle-text")).to have_content("v1.1.0") + expect(find(".js-compare-to-dropdown .gl-new-dropdown-button-text")).to have_content("v1.1.0") click_button "Compare" expect(page).to have_content "Commits" @@ -136,19 +136,22 @@ end def select_using_dropdown(dropdown_type, selection, commit: false) + wait_for_requests + dropdown = find(".js-compare-#{dropdown_type}-dropdown") dropdown.find(".compare-dropdown-toggle").click # find input before using to wait for the inputs visibility dropdown.find('.dropdown-menu') dropdown.fill_in("Filter by Git revision", with: selection) + wait_for_requests if commit - dropdown.find('input[type="search"]').send_keys(:return) + dropdown.find('.gl-search-box-by-type-input').send_keys(:return) else # find before all to wait for the items visibility - dropdown.find("a[data-ref=\"#{selection}\"]", match: :first) - dropdown.all("a[data-ref=\"#{selection}\"]").last.click + dropdown.find(".js-compare-#{dropdown_type}-dropdown .dropdown-item", text: selection, match: :first) + dropdown.all(".js-compare-#{dropdown_type}-dropdown .dropdown-item", text: selection).first.click end end end diff --git a/spec/frontend/projects/compare/components/app_spec.js b/spec/frontend/projects/compare/components/app_spec.js new file mode 100644 index 00000000000000..e265055ef1be9c --- /dev/null +++ b/spec/frontend/projects/compare/components/app_spec.js @@ -0,0 +1,116 @@ +import { shallowMount } from '@vue/test-utils'; +import { GlButton } from '@gitlab/ui'; +import CompareApp from '~/projects/compare/components/app.vue'; +import RevisionDropdown from '~/projects/compare/components/revision_dropdown.vue'; + +jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' })); + +const projectCompareIndexPath = 'some/path'; +const refsProjectPath = 'some/refs/path'; +const paramsFrom = 'master'; +const paramsTo = 'master'; + +describe('CompareApp component', () => { + let wrapper; + + const createComponent = (props = {}) => { + wrapper = shallowMount(CompareApp, { + propsData: { + projectCompareIndexPath, + refsProjectPath, + paramsFrom, + paramsTo, + projectMergeRequestPath: '', + createMrPath: '', + ...props, + }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + beforeEach(() => { + createComponent(); + }); + + it('renders component with prop', () => { + expect(wrapper.props()).toEqual( + expect.objectContaining({ + projectCompareIndexPath, + refsProjectPath, + paramsFrom, + paramsTo, + }), + ); + }); + + it('contains the correct form attributes', () => { + expect(wrapper.attributes('action')).toBe(projectCompareIndexPath); + expect(wrapper.attributes('method')).toBe('POST'); + }); + + it('has input with csrf token', () => { + expect(wrapper.find('input[name="authenticity_token"]').attributes('value')).toBe( + 'mock-csrf-token', + ); + }); + + it('has ellipsis', () => { + expect(wrapper.find('[data-testid="ellipsis"]').exists()).toBe(true); + }); + + it('render Source and Target BranchDropdown components', () => { + const branchDropdowns = wrapper.findAll(RevisionDropdown); + + expect(branchDropdowns.length).toBe(2); + expect(branchDropdowns.at(0).props('revisionText')).toBe('Source'); + expect(branchDropdowns.at(1).props('revisionText')).toBe('Target'); + }); + + describe('compare button', () => { + const findCompareButton = () => wrapper.find(GlButton); + + it('renders button', () => { + expect(findCompareButton().exists()).toBe(true); + }); + + it('submits form', () => { + findCompareButton().vm.$emit('click'); + expect(wrapper.find('form').element.submit).toHaveBeenCalled(); + }); + + it('has compare text', () => { + expect(findCompareButton().text()).toBe('Compare'); + }); + }); + + describe('merge request buttons', () => { + const findProjectMrButton = () => wrapper.find('[data-testid="projectMrButton"]'); + const findCreateMrButton = () => wrapper.find('[data-testid="createMrButton"]'); + + it('does not have merge request buttons', () => { + createComponent(); + expect(findProjectMrButton().exists()).toBe(false); + expect(findCreateMrButton().exists()).toBe(false); + }); + + it('has "View open merge request" button', () => { + createComponent({ + projectMergeRequestPath: 'some/project/merge/request/path', + }); + expect(findProjectMrButton().exists()).toBe(true); + expect(findCreateMrButton().exists()).toBe(false); + }); + + it('has "Create merge request" button', () => { + createComponent({ + createMrPath: 'some/create/create/mr/path', + }); + expect(findProjectMrButton().exists()).toBe(false); + expect(findCreateMrButton().exists()).toBe(true); + }); + }); +}); diff --git a/spec/frontend/projects/compare/components/revision_dropdown_spec.js b/spec/frontend/projects/compare/components/revision_dropdown_spec.js new file mode 100644 index 00000000000000..c9e87fb904dcd9 --- /dev/null +++ b/spec/frontend/projects/compare/components/revision_dropdown_spec.js @@ -0,0 +1,92 @@ +import { shallowMount } from '@vue/test-utils'; +import AxiosMockAdapter from 'axios-mock-adapter'; +import { GlDropdown } from '@gitlab/ui'; +import axios from '~/lib/utils/axios_utils'; +import RevisionDropdown from '~/projects/compare/components/revision_dropdown.vue'; +import createFlash from '~/flash'; + +const defaultProps = { + refsProjectPath: 'some/refs/path', + revisionText: 'Target', + paramsName: 'from', + paramsBranch: 'master', +}; + +jest.mock('~/flash'); + +describe('RevisionDropdown component', () => { + let wrapper; + let axiosMock; + + const createComponent = (props = {}) => { + wrapper = shallowMount(RevisionDropdown, { + propsData: { + ...defaultProps, + ...props, + }, + }); + }; + + beforeEach(() => { + axiosMock = new AxiosMockAdapter(axios); + }); + + afterEach(() => { + wrapper.destroy(); + axiosMock.restore(); + }); + + const findGlDropdown = () => wrapper.find(GlDropdown); + + it('sets hidden input', () => { + createComponent(); + expect(wrapper.find('input[type="hidden"]').attributes('value')).toBe( + defaultProps.paramsBranch, + ); + }); + + it('update the branches on success', async () => { + const Branches = ['branch-1', 'branch-2']; + const Tags = ['tag-1', 'tag-2', 'tag-3']; + + axiosMock.onGet(defaultProps.refsProjectPath).replyOnce(200, { + Branches, + Tags, + }); + + createComponent(); + + await axios.waitForAll(); + + expect(wrapper.vm.branches).toEqual(Branches); + expect(wrapper.vm.tags).toEqual(Tags); + }); + + it('shows flash message on error', async () => { + axiosMock.onGet('some/invalid/path').replyOnce(404); + + createComponent(); + + await wrapper.vm.fetchBranchesAndTags(); + expect(createFlash).toHaveBeenCalled(); + }); + + describe('GlDropdown component', () => { + it('renders props', () => { + createComponent(); + expect(wrapper.props()).toEqual(expect.objectContaining(defaultProps)); + }); + + it('display default text', () => { + createComponent({ + paramsBranch: null, + }); + expect(findGlDropdown().props('text')).toBe('Select branch/tag'); + }); + + it('display params branch text', () => { + createComponent(); + expect(findGlDropdown().props('text')).toBe(defaultProps.paramsBranch); + }); + }); +}); -- GitLab From a907bfe310c66a979fae03df0a4472e61a832ab4 Mon Sep 17 00:00:00 2001 From: Samantha Ming Date: Thu, 4 Feb 2021 04:50:03 +0000 Subject: [PATCH 2/2] Apply 7 suggestion(s) to 1 file(s) --- .../compare/components/revision_dropdown.vue | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/projects/compare/components/revision_dropdown.vue b/app/assets/javascripts/projects/compare/components/revision_dropdown.vue index 1d18458a6f9148..f657f36322d318 100644 --- a/app/assets/javascripts/projects/compare/components/revision_dropdown.vue +++ b/app/assets/javascripts/projects/compare/components/revision_dropdown.vue @@ -41,18 +41,18 @@ export default { }, computed: { filteredBranches() { - return this.branches?.filter((branch) => + return this.branches.filter((branch) => branch.toLowerCase().includes(this.searchTerm.toLowerCase()), ); }, hasFilteredBranches() { - return this.filteredBranches?.length; + return this.filteredBranches.length; }, filteredTags() { - return this.tags?.filter((tag) => tag.toLowerCase().includes(this.searchTerm.toLowerCase())); + return this.tags.filter((tag) => tag.toLowerCase().includes(this.searchTerm.toLowerCase())); }, hasFilteredTags() { - return this.filteredTags?.length; + return this.filteredTags.length; }, }, mounted() { @@ -97,7 +97,7 @@ export default {
- {{ s__(`CompareRevisions|${revisionText}`) }} + {{ revisionText }}
@@ -121,7 +121,7 @@ export default { @@ -133,7 +133,7 @@ export default { -- GitLab