From 4e1649f5c67c1fbeb29f9c7dfaf751bb15c89efb Mon Sep 17 00:00:00 2001 From: Chaoyue Zhao Date: Thu, 22 May 2025 17:39:36 -0400 Subject: [PATCH 1/4] Add feature flag and boilerplate for commit list refactor - Add a new feature flag `project_commits_refactor` for commit list refactor work - Add a new entry point from app/views/projects/commits/show.html.haml to initiate a new Vue app - Set up a Vue root component (commit_list_app.vue) with basic structure - Create placeholder components for: `commit_list_header.vue`, `commit_list_item.vue` --- .../pages/projects/commits/show/index.js | 8 +- .../commits/components/commit_list_app.vue | 54 +++ .../commits/components/commit_list_header.vue | 97 +++++ .../commits/components/commit_list_item.vue | 49 +++ .../projects/commits/components/mock_data.js | 103 +++++ .../projects/commits/init_commit_list_app.js | 23 + app/views/projects/commits/show.html.haml | 36 +- .../wip/project_commits_refactor.yml | 9 + spec/features/projects/commits/rss_spec.rb | 30 +- .../commits/user_browses_commits_spec.rb | 410 +++++++++--------- .../projects/files/user_browses_files_spec.rb | 117 ++--- .../projects/merge_request_button_spec.rb | 14 +- .../commits/components/commit_header_spec.js | 119 +++++ .../components/commit_list_app_spec.js | 61 +++ .../components/commit_list_item_spec.js | 74 ++++ .../projects/commits/show.html.haml_spec.rb | 2 + 16 files changed, 918 insertions(+), 288 deletions(-) create mode 100644 app/assets/javascripts/projects/commits/components/commit_list_app.vue create mode 100644 app/assets/javascripts/projects/commits/components/commit_list_header.vue create mode 100644 app/assets/javascripts/projects/commits/components/commit_list_item.vue create mode 100644 app/assets/javascripts/projects/commits/components/mock_data.js create mode 100644 app/assets/javascripts/projects/commits/init_commit_list_app.js create mode 100644 config/feature_flags/wip/project_commits_refactor.yml create mode 100644 spec/frontend/projects/commits/components/commit_header_spec.js create mode 100644 spec/frontend/projects/commits/components/commit_list_app_spec.js create mode 100644 spec/frontend/projects/commits/components/commit_list_item_spec.js diff --git a/app/assets/javascripts/pages/projects/commits/show/index.js b/app/assets/javascripts/pages/projects/commits/show/index.js index 5d6bccc88ae967..011759a5f1cd6f 100644 --- a/app/assets/javascripts/pages/projects/commits/show/index.js +++ b/app/assets/javascripts/pages/projects/commits/show/index.js @@ -4,8 +4,14 @@ import CommitsList from '~/commits'; import GpgBadges from '~/gpg_badges'; import { mountCommits, initCommitsRefSwitcher } from '~/projects/commits'; import initAmbiguousRefModal from '~/ref/init_ambiguous_ref_modal'; +import initCommitListApp from '~/projects/commits/init_commit_list_app'; + +if (document.querySelector('.js-project-commits-show')) { + new CommitsList(document.querySelector('.js-project-commits-show').dataset.commitsLimit); // eslint-disable-line no-new +} else { + initCommitListApp(); +} -new CommitsList(document.querySelector('.js-project-commits-show').dataset.commitsLimit); // eslint-disable-line no-new addShortcutsExtension(ShortcutsNavigation); GpgBadges.fetch(); mountCommits(document.getElementById('js-author-dropdown')); diff --git a/app/assets/javascripts/projects/commits/components/commit_list_app.vue b/app/assets/javascripts/projects/commits/components/commit_list_app.vue new file mode 100644 index 00000000000000..03c1e78589c2c9 --- /dev/null +++ b/app/assets/javascripts/projects/commits/components/commit_list_app.vue @@ -0,0 +1,54 @@ + + + diff --git a/app/assets/javascripts/projects/commits/components/commit_list_header.vue b/app/assets/javascripts/projects/commits/components/commit_list_header.vue new file mode 100644 index 00000000000000..8c20df8b8f5280 --- /dev/null +++ b/app/assets/javascripts/projects/commits/components/commit_list_header.vue @@ -0,0 +1,97 @@ + + + diff --git a/app/assets/javascripts/projects/commits/components/commit_list_item.vue b/app/assets/javascripts/projects/commits/components/commit_list_item.vue new file mode 100644 index 00000000000000..73b8bd49dd2aa7 --- /dev/null +++ b/app/assets/javascripts/projects/commits/components/commit_list_item.vue @@ -0,0 +1,49 @@ + + + diff --git a/app/assets/javascripts/projects/commits/components/mock_data.js b/app/assets/javascripts/projects/commits/components/mock_data.js new file mode 100644 index 00000000000000..07760118da628b --- /dev/null +++ b/app/assets/javascripts/projects/commits/components/mock_data.js @@ -0,0 +1,103 @@ +/* eslint-disable @gitlab/require-i18n-strings */ +const mockCommit = { + data: { + project: { + __typename: 'Project', + id: 'gid://gitlab/Project/3', + repository: { + __typename: 'Repository', + lastCommit: { + __typename: 'Commit', + id: 'gid://gitlab/Commit/c6214205ec8f1bcafe3c91bda2e5fa1219df5866', + sha: 'c6214205ec8f1bcafe3c91bda2e5fa1219df5866', + title: "Revert \"Merge branch 'pb-ci-ruby-version-3-4-2' into 'main'\"", + titleHtml: "Revert \"Merge branch 'pb-ci-ruby-version-3-4-2' into 'main'\"", + descriptionHtml: '\u0026#x000A;This reverts merge request !1248', + message: + "Revert \"Merge branch 'pb-ci-ruby-version-3-4-2' into 'main'\"\n\nThis reverts merge request !1248", + webPath: '/gitlab-org/gitlab-shell/-/commit/c6214205ec8f1bcafe3c91bda2e5fa1219df5866', + authoredDate: '2025-03-07T04:32:27+00:00', + authorName: 'Patrick Bajao', + authorGravatar: + 'https://secure.gravatar.com/avatar/5d6ebe280312e168c9fef4762a5a890d74e8060b07217312c1bf1adb761119b9?s=80\u0026d=identicon', + author: null, + signature: { + __typename: 'SshSignature', + verificationStatus: 'UNKNOWN_KEY', + keyFingerprintSha256: '', + }, + pipelines: { + __typename: 'PipelineConnection', + edges: [], + }, + }, + }, + }, + }, +}; + +export const mockCommits = Array(20) + .fill() + .map((_, index) => ({ + ...mockCommit.data.project.repository.lastCommit, + id: `${mockCommit.data.project.repository.lastCommit.id}-${index}`, // Make IDs unique + sha: `${mockCommit.data.project.repository.lastCommit.sha.substring(0, 8)}${index}`, // Make SHAs unique + })); + +export const mockDataset = { + ref: 'main', + refType: 'heads', + projectId: '3', + projectPath: 'gitlab-org/gitlab-shell', + currentPath: '.gitlab-ci.yml', + sortOptions: [ + { + id: 1, + title: 'Created date', + sortDirection: { ascending: 'CREATED_DATE_ASC', descending: 'CREATED_DATE_DESC' }, + }, + ], +}; + +export const mockCrumbs = [ + { + text: 'gitlab-shell', + href: '/gitlab-org/gitlab-shell/-/tree/main', + path: '/', + to: '/-/tree/main', + }, + { + text: '.gitlab-ci.yml', + href: '/gitlab-org/gitlab-shell/-/blob/main/.gitlab-ci.yml', + path: '.gitlab-ci.yml', + to: '/-/blob/main/.gitlab-ci.yml', + }, +]; + +export const mockTokens = [ + { + type: 'author', + title: 'Author', + icon: 'pencil', + dataType: 'user', + defaultUsers: [], + operators: [ + { value: '=', description: 'is' }, + { value: '!=', description: 'is not one of' }, + { value: '||', description: 'is one of' }, + ], + fullPath: 'gitlab-org/gitlab-shell', + isProject: true, + recentSuggestionsStorageKey: 'gitlab-org/gitlab-shell-commits-recent-tokens-author', + preloadedUsers: [ + { + id: 'gid://gitlab/User/1', + name: 'Administrator', + username: 'root', + avatar_url: + 'https://secure.gravatar.com/avatar/7272d4da0ca779e0ca6fdb7fdc7a17b232462e054839e1060934d03f6ded8609?s=80&d=identicon', + }, + ], + multiSelect: true, + }, +]; diff --git a/app/assets/javascripts/projects/commits/init_commit_list_app.js b/app/assets/javascripts/projects/commits/init_commit_list_app.js new file mode 100644 index 00000000000000..acb4791b0debad --- /dev/null +++ b/app/assets/javascripts/projects/commits/init_commit_list_app.js @@ -0,0 +1,23 @@ +import Vue from 'vue'; +import CommitListApp from './components/commit_list_app.vue'; +import { mockDataset } from './components/mock_data'; + +export default function initCommitListApp() { + const commitListEl = document.getElementById('js-commit-list'); + if (commitListEl) { + const { ref } = mockDataset; + + // eslint-disable-next-line no-new + new Vue({ + el: commitListEl, + provide: { + // TODO - replace with real data + ...mockDataset, + currentRef: ref, + }, + render(h) { + return h(CommitListApp, {}); + }, + }); + } +} diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml index a481e4ad3f579e..eb37ae2dbe2bf3 100644 --- a/app/views/projects/commits/show.html.haml +++ b/app/views/projects/commits/show.html.haml @@ -9,12 +9,16 @@ = content_for :meta_tags do = auto_discovery_link_tag(:atom, project_commits_path(@project, @ref, rss_url_options), title: "#{@project.name}:#{@ref} commits") -.js-project-commits-show{ 'data-commits-limit' => @limit } - .tree-holder.gl-mt-5 - .nav-block - .tree-ref-container - .tree-ref-holder.gl-max-w-26 - #js-project-commits-ref-switcher{ data: { "project-id" => @project.id, "ref" => @ref, "commits_path": project_commits_path(@project), "ref_type": @ref_type.to_s, "tree_path": @path } } +- if Feature.enabled?(:project_commits_refactor, @project) + #js-commit-list + +- else + .js-project-commits-show{ 'data-commits-limit' => @limit } + .tree-holder.gl-mt-5 + .nav-block + .tree-ref-container + .tree-ref-holder.gl-max-w-26 + #js-project-commits-ref-switcher{ data: { "project-id" => @project.id, "ref" => @ref, "commits_path": project_commits_path(@project), "ref_type": @ref_type.to_s, "tree_path": @path } } %ul.breadcrumb.repo-breadcrumb = commits_breadcrumbs @@ -30,18 +34,18 @@ = render Pajamas::ButtonComponent.new(variant: :confirm, href: create_mr_path(from: @ref, source_project: @project)) do = _("Create merge request") - .control - = form_tag(project_commits_path(@project, @id, ref_type: @ref_type), method: :get, class: 'commits-search-form js-signature-container', data: { 'signatures-path' => namespace_project_signatures_path(ref_type: @ref_type)}) do - = search_field_tag :search, params[:search], { placeholder: _('Search by message'), id: 'commits-search', class: 'form-control gl-form-input input-short gl-mt-3 sm:gl-mt-0 gl-min-w-full', spellcheck: false } - .control.gl-hidden.md:gl-block - = link_button_to nil, project_commits_path(@project, @id, rss_url_options), title: _("Commits feed"), icon: 'rss' + .control + = form_tag(project_commits_path(@project, @id, ref_type: @ref_type), method: :get, class: 'commits-search-form js-signature-container', data: { 'signatures-path' => namespace_project_signatures_path(ref_type: @ref_type)}) do + = search_field_tag :search, params[:search], { placeholder: _('Search by message'), id: 'commits-search', class: 'form-control gl-form-input input-short gl-mt-3 sm:gl-mt-0 gl-min-w-full', spellcheck: false } + .control.gl-hidden.md:gl-block + = link_button_to nil, project_commits_path(@project, @id, rss_url_options), title: _("Commits feed"), icon: 'rss' - = render_if_exists 'projects/commits/mirror_status' + = render_if_exists 'projects/commits/mirror_status' - %div{ id: dom_id(@project) } - %ol#commits-list.list-unstyled.content_list - = render 'commits', project: @project, ref: @ref, is_commits_page: true - = gl_loading_icon(size: 'lg', css_class: 'loading hide') + %div{ id: dom_id(@project) } + %ol#commits-list.list-unstyled.content_list + = render 'commits', project: @project, ref: @ref, is_commits_page: true + = gl_loading_icon(size: 'lg', css_class: 'loading hide') -# https://gitlab.com/gitlab-org/gitlab/-/issues/408388#note_1578533983 #js-ambiguous-ref-modal{ data: { ambiguous: @is_ambiguous_ref.to_s, ref: current_ref } } diff --git a/config/feature_flags/wip/project_commits_refactor.yml b/config/feature_flags/wip/project_commits_refactor.yml new file mode 100644 index 00000000000000..a116ea0259a98b --- /dev/null +++ b/config/feature_flags/wip/project_commits_refactor.yml @@ -0,0 +1,9 @@ +--- +name: project_commits_refactor +feature_issue_url: https://gitlab.com/groups/gitlab-org/-/epics/17482 +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/192147 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/545170 +milestone: '18.1' +group: group::source code +type: wip +default_enabled: false diff --git a/spec/features/projects/commits/rss_spec.rb b/spec/features/projects/commits/rss_spec.rb index 49da0727fbd9e1..de23339cc62f54 100644 --- a/spec/features/projects/commits/rss_spec.rb +++ b/spec/features/projects/commits/rss_spec.rb @@ -7,23 +7,29 @@ let(:project) { create(:project, :repository, visibility_level: Gitlab::VisibilityLevel::PUBLIC) } let(:path) { project_commits_path(project, :master) } - context 'when signed in' do + context 'when project_commits_refactor feature flag is disabled' do before do - project.add_developer(user) - sign_in(user) - visit path + stub_feature_flags(project_commits_refactor: false) end - it_behaves_like "it has an RSS button with current_user's feed token" - it_behaves_like "an autodiscoverable RSS feed with current_user's feed token" - end + context 'when signed in' do + before do + project.add_developer(user) + sign_in(user) + visit path + end - context 'when signed out' do - before do - visit path + it_behaves_like "it has an RSS button with current_user's feed token" + it_behaves_like "an autodiscoverable RSS feed with current_user's feed token" end - it_behaves_like "it has an RSS button without a feed token" - it_behaves_like "an autodiscoverable RSS feed without a feed token" + context 'when signed out' do + before do + visit path + end + + it_behaves_like "it has an RSS button without a feed token" + it_behaves_like "an autodiscoverable RSS feed without a feed token" + end end end diff --git a/spec/features/projects/commits/user_browses_commits_spec.rb b/spec/features/projects/commits/user_browses_commits_spec.rb index 84feb1a43d64cb..efea326b106ffb 100644 --- a/spec/features/projects/commits/user_browses_commits_spec.rb +++ b/spec/features/projects/commits/user_browses_commits_spec.rb @@ -12,256 +12,214 @@ sign_in(user) end - it 'renders commit', :js do - visit project_commit_path(project, sample_commit.id) - - expect(page).to have_content(sample_commit.message.gsub(/\s+/, ' ')) - .and have_content("Showing #{sample_commit.files_changed_count} changed files") - .and have_content('Side-by-side') - end - - it 'fill commit sha when click new tag from commit page', :js do - dropdown_selector = '[data-testid="commit-options-dropdown"]' - visit project_commit_path(project, sample_commit.id) - find(dropdown_selector).click - - page.within(dropdown_selector) do - click_link 'Tag' + context 'when project_commits_refactor feature flag is disabled' do + before do + stub_feature_flags(project_commits_refactor: false) end - expect(page).to have_selector("input[value='#{sample_commit.id}']", visible: false) - end - - it 'renders inline diff button when click side-by-side diff button' do - visit project_commit_path(project, sample_commit.id) - find('#parallel-diff-btn').click - - expect(page).to have_content 'Inline' - end - - it 'renders breadcrumbs on specific commit path' do - visit project_commits_path(project, project.repository.root_ref + '/files/ruby/regex.rb', limit: 5) - - expect(page).to have_selector('#content-body ul.breadcrumb') - .and have_selector('#content-body ul.breadcrumb a', count: 4) - end - - it 'renders diff links to both the previous and current image', :js do - visit project_commit_path(project, sample_image_commit.id) + it 'renders commit', :js do + visit project_commit_path(project, sample_commit.id) - links = page.all('.file-actions a') - expect(links[0]['href']).to match %r{blob/#{sample_image_commit.old_blob_id}} - expect(links[1]['href']).to match %r{blob/#{sample_image_commit.new_blob_id}} - end + expect(page).to have_content(sample_commit.message.gsub(/\s+/, ' ')) + .and have_content("Showing #{sample_commit.files_changed_count} changed files") + .and have_content('Side-by-side') + end - context 'when commit has ci status' do - let(:pipeline) { create(:ci_pipeline, project: project, sha: sample_commit.id) } + it 'fill commit sha when click new tag from commit page', :js do + dropdown_selector = '[data-testid="commit-options-dropdown"]' + visit project_commit_path(project, sample_commit.id) + find(dropdown_selector).click - before do - project.enable_ci + page.within(dropdown_selector) do + click_link 'Tag' + end - create(:ci_build, pipeline: pipeline) + expect(page).to have_selector("input[value='#{sample_commit.id}']", visible: false) end - it 'renders commit ci info' do + it 'renders inline diff button when click side-by-side diff button' do visit project_commit_path(project, sample_commit.id) - wait_for_requests + find('#parallel-diff-btn').click - expect(page).to have_selector('.js-commit-box-pipeline-summary') + expect(page).to have_content 'Inline' end - end - - context 'primary email' do - it 'finds a commit by a primary email' do - user = create(:user, email: 'dmitriy.zaporozhets@gmail.com') - visit(project_commit_path(project, sample_commit.id)) + it 'renders breadcrumbs on specific commit path' do + visit project_commits_path(project, project.repository.root_ref + '/files/ruby/regex.rb', limit: 5) - check_author_link(sample_commit.author_email, user) + expect(page).to have_selector('#content-body ul.breadcrumb') + .and have_selector('#content-body ul.breadcrumb a', count: 4) end - end - - context 'secondary email' do - let(:user) { create(:user) } - it 'finds a commit by a secondary email' do - create(:email, :confirmed, user: user, email: 'dmitriy.zaporozhets@gmail.com') + it 'renders diff links to both the previous and current image', :js do + visit project_commit_path(project, sample_image_commit.id) - visit(project_commit_path(project, sample_commit.parent_id)) - - check_author_link(sample_commit.author_email, user) + links = page.all('.file-actions a') + expect(links[0]['href']).to match %r{blob/#{sample_image_commit.old_blob_id}} + expect(links[1]['href']).to match %r{blob/#{sample_image_commit.new_blob_id}} end - it 'links to an unverified e-mail address instead of the user' do - create(:email, user: user, email: 'dmitriy.zaporozhets@gmail.com') + context 'when commit has ci status' do + let(:pipeline) { create(:ci_pipeline, project: project, sha: sample_commit.id) } - visit(project_commit_path(project, sample_commit.parent_id)) + before do + project.enable_ci - check_author_email(sample_commit.author_email) - end - end + create(:ci_build, pipeline: pipeline) + end - context 'when the blob does not exist' do - let(:commit) { create(:commit, project: project) } + it 'renders commit ci info' do + visit project_commit_path(project, sample_commit.id) + wait_for_requests - it 'renders successfully', :js do - allow_next_instance_of(Gitlab::Diff::File) do |instance| - allow(instance).to receive(:blob).and_return(nil) - end - allow_next_instance_of(Gitlab::Diff::File) do |instance| - allow(instance).to receive(:binary?).and_return(true) + expect(page).to have_selector('.js-commit-box-pipeline-summary') end + end - visit(project_commit_path(project, commit)) + context 'primary email' do + it 'finds a commit by a primary email' do + user = create(:user, email: 'dmitriy.zaporozhets@gmail.com') - click_button '2 changed files' + visit(project_commit_path(project, sample_commit.id)) - expect(find_by_testid('diff-stats-dropdown')).to have_content('files/ruby/popen.rb') - end - end - - describe 'commits list' do - let(:visit_commits_page) do - visit project_commits_path(project, project.repository.root_ref, limit: 5) + check_author_link(sample_commit.author_email, user) + end end - it 'searches commit', :js do - visit_commits_page - fill_in 'commits-search', with: 'submodules' + context 'secondary email' do + let(:user) { create(:user) } - expect(page).to have_content 'More submodules' - expect(page).not_to have_content 'Change some files' - end + it 'finds a commit by a secondary email' do + create(:email, :confirmed, user: user, email: 'dmitriy.zaporozhets@gmail.com') - it 'renders commits atom feed' do - visit_commits_page - click_link('Commits feed') + visit(project_commit_path(project, sample_commit.parent_id)) - commit = project.repository.commit + check_author_link(sample_commit.author_email, user) + end - expect(response_headers['Content-Type']).to have_content("application/atom+xml") - expect(body).to have_selector('title', text: "#{project.name}:master commits") - .and have_selector('author email', text: commit.author_email) - .and have_selector('entry summary', text: commit.description[0..10].delete("\r\n")) - end + it 'links to an unverified e-mail address instead of the user' do + create(:email, user: user, email: 'dmitriy.zaporozhets@gmail.com') - context "when commit has a filename with pathspec characters" do - let(:path) { ':wq' } - let(:filename) { File.join(path, 'test.txt') } - let(:ref) { project.repository.root_ref } - let(:newrev) { project.repository.commit('master').sha } - let(:short_newrev) { project.repository.commit('master').short_id } - let(:message) { 'Glob characters' } + visit(project_commit_path(project, sample_commit.parent_id)) - before do - create_file_in_repo(project, ref, ref, filename, 'Test file', commit_message: message) - visit project_commits_path(project, "#{ref}/#{path}", limit: 1) - wait_for_requests + check_author_email(sample_commit.author_email) end + end - it 'searches commit', :js do - expect(page).to have_content(message) + context 'when the blob does not exist' do + let(:commit) { create(:commit, project: project) } - fill_in 'commits-search', with: 'bogus12345' + it 'renders successfully', :js do + allow_next_instance_of(Gitlab::Diff::File) do |instance| + allow(instance).to receive(:blob).and_return(nil) + end + allow_next_instance_of(Gitlab::Diff::File) do |instance| + allow(instance).to receive(:binary?).and_return(true) + end - expect(page).to have_content "No results found" + visit(project_commit_path(project, commit)) - fill_in 'commits-search', with: 'Glob' + click_button '2 changed files' - expect(page).to have_content message + expect(find_by_testid('diff-stats-dropdown')).to have_content('files/ruby/popen.rb') end end - context 'when a commit links to a confidential issue' do - let(:confidential_issue) { create(:issue, confidential: true, title: 'Secret issue!', project: project) } - - before do - project.repository.create_file( - user, - 'dummy-file', - 'dummy content', - branch_name: 'feature', - message: "Linking #{confidential_issue.to_reference}" - ) + describe 'commits list' do + let(:visit_commits_page) do + visit project_commits_path(project, project.repository.root_ref, limit: 5) end - context 'when the user cannot see confidential issues but was cached with a link', :use_clean_rails_memory_store_fragment_caching do - it 'does not render the confidential issue' do - visit project_commits_path(project, 'feature') - sign_in(create(:user)) - visit project_commits_path(project, 'feature') + it 'searches commit', :js do + visit_commits_page + fill_in 'commits-search', with: 'submodules' - expect(page).not_to have_link(href: project_issue_path(project, confidential_issue)) - end + expect(page).to have_content 'More submodules' + expect(page).not_to have_content 'Change some files' end - end - context 'master branch', :js do - before do + it 'renders commits atom feed' do visit_commits_page - end + click_link('Commits feed') - it 'renders project commits' do commit = project.repository.commit - expect(page).to have_content(project.name) - .and have_content(commit.message[0..20]) - .and have_content(commit.short_id) + expect(response_headers['Content-Type']).to have_content("application/atom+xml") + expect(body).to have_selector('title', text: "#{project.name}:master commits") + .and have_selector('author email', text: commit.author_email) + .and have_selector('entry summary', text: commit.description[0..10].delete("\r\n")) end - it 'does not render create merge request button' do - expect(page).not_to have_link 'Create merge request' - end - - it 'shows ref switcher with correct text', :js do - expect(find('.ref-selector')).to have_text('master') - end + context "when commit has a filename with pathspec characters" do + let(:path) { ':wq' } + let(:filename) { File.join(path, 'test.txt') } + let(:ref) { project.repository.root_ref } + let(:newrev) { project.repository.commit('master').sha } + let(:short_newrev) { project.repository.commit('master').short_id } + let(:message) { 'Glob characters' } - context 'when click the compare tab' do before do + create_file_in_repo(project, ref, ref, filename, 'Test file', commit_message: message) + visit project_commits_path(project, "#{ref}/#{path}", limit: 1) wait_for_requests - click_link('Compare') end - it 'does not render create merge request button', :js do - expect(page).not_to have_link 'Create merge request' + it 'searches commit', :js do + expect(page).to have_content(message) + + fill_in 'commits-search', with: 'bogus12345' + + expect(page).to have_content "No results found" + + fill_in 'commits-search', with: 'Glob' + + expect(page).to have_content message end end - end - context 'feature branch', :js do - let(:visit_commits_page) do - visit project_commits_path(project) + context 'when a commit links to a confidential issue' do + let(:confidential_issue) { create(:issue, confidential: true, title: 'Secret issue!', project: project) } - find('.ref-selector').click - wait_for_requests + before do + project.repository.create_file( + user, + 'dummy-file', + 'dummy content', + branch_name: 'feature', + message: "Linking #{confidential_issue.to_reference}" + ) + end - page.within('.ref-selector') do - fill_in 'Search by Git revision', with: 'feature' - wait_for_requests - find('li', text: 'feature', match: :prefer_exact).click + context 'when the user cannot see confidential issues but was cached with a link', :use_clean_rails_memory_store_fragment_caching do + it 'does not render the confidential issue' do + visit project_commits_path(project, 'feature') + sign_in(create(:user)) + visit project_commits_path(project, 'feature') + + expect(page).not_to have_link(href: project_issue_path(project, confidential_issue)) + end end end - context 'when project does not have open merge requests' do + context 'master branch', :js do before do visit_commits_page end - it 'shows ref switcher with correct text' do - expect(find('.ref-selector')).to have_text('feature') - end - it 'renders project commits' do - commit = project.repository.commit('0b4bc9a') + commit = project.repository.commit expect(page).to have_content(project.name) - .and have_content(commit.message[0..12]) - .and have_content(commit.short_id) + .and have_content(commit.message[0..20]) + .and have_content(commit.short_id) end - it 'renders create merge request button' do - expect(page).to have_link 'Create merge request' + it 'does not render create merge request button' do + expect(page).not_to have_link 'Create merge request' + end + + it 'shows ref switcher with correct text', :js do + expect(find('.ref-selector')).to have_text('master') end context 'when click the compare tab' do @@ -270,51 +228,99 @@ click_link('Compare') end - it 'renders create merge request button', :js do - expect(page).to have_link 'Create merge request' + it 'does not render create merge request button', :js do + expect(page).not_to have_link 'Create merge request' end end end - context 'when project have open merge request' do - let!(:merge_request) do - create( - :merge_request, - title: 'Feature', - source_project: project, - source_branch: 'feature', - target_branch: 'master', - author: project.users.first - ) - end + context 'feature branch', :js do + let(:visit_commits_page) do + visit project_commits_path(project) - before do - visit_commits_page + find('.ref-selector').click + wait_for_requests + + page.within('.ref-selector') do + fill_in 'Search by Git revision', with: 'feature' + wait_for_requests + find('li', text: 'feature', match: :prefer_exact).click + end end - it 'renders project commits' do - commit = project.repository.commit('0b4bc9a') + context 'when project does not have open merge requests' do + before do + visit_commits_page + end - expect(page).to have_content(project.name) - .and have_content(commit.message[0..12]) - .and have_content(commit.short_id) - end + it 'shows ref switcher with correct text' do + expect(find('.ref-selector')).to have_text('feature') + end - it 'renders button to the merge request' 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) + it 'renders project commits' do + commit = project.repository.commit('0b4bc9a') + + expect(page).to have_content(project.name) + .and have_content(commit.message[0..12]) + .and have_content(commit.short_id) + end + + it 'renders create merge request button' do + expect(page).to have_link 'Create merge request' + end + + context 'when click the compare tab' do + before do + wait_for_requests + click_link('Compare') + end + + it 'renders create merge request button', :js do + expect(page).to have_link 'Create merge request' + end + end end - context 'when click the compare tab' do + context 'when project have open merge request' do + let!(:merge_request) do + create( + :merge_request, + title: 'Feature', + source_project: project, + source_branch: 'feature', + target_branch: 'master', + author: project.users.first + ) + end + before do - wait_for_requests - click_link('Compare') + visit_commits_page end - it 'renders button to the merge request', :js do + it 'renders project commits' do + commit = project.repository.commit('0b4bc9a') + + expect(page).to have_content(project.name) + .and have_content(commit.message[0..12]) + .and have_content(commit.short_id) + end + + it 'renders button to the merge request' 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 + + context 'when click the compare tab' do + before do + wait_for_requests + click_link('Compare') + end + + 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 + end end end end diff --git a/spec/features/projects/files/user_browses_files_spec.rb b/spec/features/projects/files/user_browses_files_spec.rb index 86cd9842a41deb..b79ae090639b24 100644 --- a/spec/features/projects/files/user_browses_files_spec.rb +++ b/spec/features/projects/files/user_browses_files_spec.rb @@ -32,58 +32,62 @@ end context "when browsing a branch", :js do - before do - visit(tree_path_root_ref) - end - - it "shows files from a repository" do - expect(page).to have_content("VERSION") - .and have_content(".gitignore") - .and have_content("LICENSE") - end + context 'when project_commits_refactor feature flag is disabled' do + before do + stub_feature_flags(project_commits_refactor: false) - it "shows the `Browse Directory` link" do - click_link("files") + visit(tree_path_root_ref) + end - page.within('.repo-breadcrumb') do - expect(page).to have_link('files') + it "shows files from a repository" do + expect(page).to have_content("VERSION") + .and have_content(".gitignore") + .and have_content("LICENSE") end - click_link("History") + it "shows the `Browse Directory` link" do + click_link("files") - history_path = project_commits_path(project, "master/files") - expect(page).to have_current_path(history_path) - expect(page).to have_link("Browse Directory").and have_no_link("Browse Code") - end - - it "shows the `Browse File` link" do - page.within(".tree-table") do - click_link("README.md") - end + page.within('.repo-breadcrumb') do + expect(page).to have_link('files') + end - page.within(".commit-actions") do click_link("History") + + history_path = project_commits_path(project, "master/files") + expect(page).to have_current_path(history_path) + expect(page).to have_link("Browse Directory").and have_no_link("Browse Code") end - history_path = project_commits_path(project, "master/README.md") - expect(page).to have_current_path(history_path) - expect(page).to have_link("Browse File").and have_no_link("Browse Files") - end + it "shows the `Browse File` link" do + page.within(".tree-table") do + click_link("README.md") + end - it "shows the `Browse Files` link" do - click_link("History") + page.within(".commit-actions") do + click_link("History") + end - history_path = project_commits_path(project, "master") - expect(page).to have_current_path(history_path) - expect(page).to have_link("Browse Files").and have_no_link("Browse Directory") - end + history_path = project_commits_path(project, "master/README.md") + expect(page).to have_current_path(history_path) + expect(page).to have_link("Browse File").and have_no_link("Browse Files") + end - it "copies permalink URL" do - click_link(".gitignore") - click_button("File actions") - click_button("Copy permalink") + it "shows the `Browse Files` link" do + click_link("History") + + history_path = project_commits_path(project, "master") + expect(page).to have_current_path(history_path) + expect(page).to have_link("Browse Files").and have_no_link("Browse Directory") + end + + it "copies permalink URL" do + click_link(".gitignore") + click_button("File actions") + click_button("Copy permalink") - expect(page).to have_text("Permalink copied to clipboard.") + expect(page).to have_text("Permalink copied to clipboard.") + end end end @@ -137,16 +141,19 @@ context "when browsing the `markdown` branch", :js do context "when browsing the root" do - before do - visit(project_tree_path(project, "markdown")) - end + context 'when project_commits_refactor feature flag is disabled' do + before do + stub_feature_flags(project_commits_refactor: false) + visit(project_tree_path(project, "markdown")) + end - it "copies permalink URL" do - click_link(".gitignore") - click_button("File actions") - click_button("Copy permalink") + it "copies permalink URL" do + click_link(".gitignore") + click_button("File actions") + click_button("Copy permalink") - expect(page).to have_text("Permalink copied to clipboard.") + expect(page).to have_text("Permalink copied to clipboard.") + end end it "shows correct files and links" do @@ -233,14 +240,18 @@ end context 'when commit message has markdown', :js do - before do - project.repository.create_file(user, 'index', 'test', message: ':star: testing', branch_name: 'master') + context 'when project_commits_refactor feature flag is disabled' do + before do + stub_feature_flags(project_commits_refactor: false) - visit(project_tree_path(project, "master")) - end + project.repository.create_file(user, 'index', 'test', message: ':star: testing', branch_name: 'master') - it 'renders emojis' do - expect(page).to have_selector('gl-emoji', count: 2) + visit(project_tree_path(project, "master")) + end + + it 'renders emojis' do + expect(page).to have_selector('gl-emoji', count: 2) + end end end diff --git a/spec/features/projects/merge_request_button_spec.rb b/spec/features/projects/merge_request_button_spec.rb index 6d6d850342ad7b..8bc67a0441e3f9 100644 --- a/spec/features/projects/merge_request_button_spec.rb +++ b/spec/features/projects/merge_request_button_spec.rb @@ -149,10 +149,16 @@ end context 'on commits page' do - it_behaves_like 'Merge request button only shown when allowed' do - let(:label) { 'Create merge request' } - let(:url) { project_commits_path(project, 'feature') } - let(:fork_url) { project_commits_path(forked_project, 'feature') } + context 'when project_commits_refactor feature flag is disabled' do + before do + stub_feature_flags(project_commits_refactor: false) + end + + it_behaves_like 'Merge request button only shown when allowed' do + let(:label) { 'Create merge request' } + let(:url) { project_commits_path(project, 'feature') } + let(:fork_url) { project_commits_path(forked_project, 'feature') } + end end end end diff --git a/spec/frontend/projects/commits/components/commit_header_spec.js b/spec/frontend/projects/commits/components/commit_header_spec.js new file mode 100644 index 00000000000000..864aba8f32f2db --- /dev/null +++ b/spec/frontend/projects/commits/components/commit_header_spec.js @@ -0,0 +1,119 @@ +import { GlBreadcrumb } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import { nextTick } from 'vue'; +import CommitListHeader from '~/projects/commits/components/commit_list_header.vue'; +import RefSelector from '~/ref/components/ref_selector.vue'; +import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; +import { mockCrumbs, mockTokens } from '~/projects/commits/components/mock_data'; + +describe('Commit Header', () => { + let wrapper; + const projectId = '123'; + const projectPath = 'group/project'; + const currentRef = 'main'; + const refType = 'heads'; + const currentPath = 'path/to/directory'; + const sortOptions = [ + { value: 'CREATED_DATE_DESC', text: 'Created date' }, + { value: 'UPDATED_DATE_DESC', text: 'Updated date' }, + ]; + + const createComponent = (props = {}) => { + wrapper = shallowMount(CommitListHeader, { + provide: { + projectId, + projectPath, + currentRef, + refType, + currentPath, + sortOptions, + ...props, + }, + }); + }; + + beforeEach(() => { + createComponent(); + }); + + const findRefSelector = () => wrapper.findComponent(RefSelector); + const findBreadcrumb = () => wrapper.findComponent(GlBreadcrumb); + const findFilteredSearchBar = () => wrapper.findComponent(FilteredSearchBar); + const findDirectoryHeading = () => wrapper.find('h1'); + + describe('ref selector', () => { + it('passes correct props to ref selector', () => { + expect(findRefSelector().props()).toMatchObject({ + projectId, + value: 'refs/heads/main', + useSymbolicRefNames: true, + queryParams: { sort: 'updated_desc' }, + }); + }); + + it('emits ref-change event when ref is changed', () => { + const newRef = 'feature-branch'; + findRefSelector().vm.$emit('input', newRef); + + expect(wrapper.emitted('ref-change')).toEqual([[newRef]]); + }); + + it('constructs correct ref value when refType is not provided', async () => { + createComponent({ refType: null }); + + await nextTick(); + expect(findRefSelector().props('value')).toBe(currentRef); + }); + }); + + describe('breadcrumb', () => { + it('renders breadcrumb with correct items', () => { + expect(findBreadcrumb().props('items')).toEqual(mockCrumbs); + }); + + it('sets correct data-current-path attribute', () => { + expect(findBreadcrumb().attributes('data-current-path')).toBe(currentPath); + }); + }); + + describe('directory heading', () => { + it('displays the directory name from currentPath', () => { + expect(findDirectoryHeading().text()).toBe('directory'); + }); + + it('displays the project name when currentPath is not provided', async () => { + createComponent({ currentPath: '' }); + + await nextTick(); + expect(findDirectoryHeading().text()).toBe('project'); + }); + }); + + describe('filtered search bar', () => { + it('passes correct props to filtered search bar', () => { + expect(findFilteredSearchBar().props()).toMatchObject({ + namespace: 'commits', + tokens: mockTokens, + recentSearchesStorageKey: 'commits', + searchInputPlaceholder: 'Search or filter commits...', + initialFilterValue: [], + initialSortBy: 'CREATED_DATE_DESC', + sortOptions, + }); + }); + + it('emits search event when filter is applied', () => { + const filterValue = ['author:John']; + findFilteredSearchBar().vm.$emit('onFilter', filterValue); + + expect(wrapper.emitted('search')).toEqual([[filterValue]]); + }); + + it('emits sort event when sort changes', () => { + const sortValue = 'CREATED_DATE_ASC'; + findFilteredSearchBar().vm.$emit('onSort', sortValue); + + expect(wrapper.emitted('sort')).toEqual([[sortValue]]); + }); + }); +}); diff --git a/spec/frontend/projects/commits/components/commit_list_app_spec.js b/spec/frontend/projects/commits/components/commit_list_app_spec.js new file mode 100644 index 00000000000000..d7eb9719a4f8b7 --- /dev/null +++ b/spec/frontend/projects/commits/components/commit_list_app_spec.js @@ -0,0 +1,61 @@ +import { GlKeysetPagination } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import CommitListApp from '~/projects/commits/components/commit_list_app.vue'; +import CommitListHeader from '~/projects/commits/components/commit_list_header.vue'; +import CommitListItem from '~/projects/commits/components/commit_list_item.vue'; +import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue'; +import PageSizeSelector from '~/vue_shared/components/page_size_selector.vue'; +import { mockCommits } from '~/projects/commits/components/mock_data'; + +describe('Commit List App', () => { + let wrapper; + const createComponent = (provide = {}) => { + wrapper = shallowMount(CommitListApp, { + provide: { + ...provide, + }, + }); + }; + + beforeEach(() => { + createComponent(); + }); + + const findCommitHeader = () => wrapper.findComponent(CommitListHeader); + const findCommitListItems = () => wrapper.findAllComponents(CommitListItem); + const findKeysetPagination = () => wrapper.findComponent(GlKeysetPagination); + const findLocalStorageSync = () => wrapper.findComponent(LocalStorageSync); + const findPageSizeSelector = () => wrapper.findComponent(PageSizeSelector); + + describe('commit header', () => { + it('renders the commit header component', () => { + expect(findCommitHeader().exists()).toBe(true); + }); + }); + + describe('commit list items', () => { + it('passes the correct commit data to each commit list item', () => { + const commitListItems = findCommitListItems(); + + mockCommits.forEach((commit, index) => { + expect(commitListItems.at(index).props('commit')).toEqual(commit); + }); + }); + }); + + describe('pagination', () => { + it('renders the keyset pagination component', () => { + expect(findKeysetPagination().exists()).toBe(true); + }); + }); + + describe('page size selector', () => { + it('renders the local storage sync component', () => { + expect(findLocalStorageSync().exists()).toBe(true); + }); + + it('renders the page size selector component', () => { + expect(findPageSizeSelector().exists()).toBe(true); + }); + }); +}); diff --git a/spec/frontend/projects/commits/components/commit_list_item_spec.js b/spec/frontend/projects/commits/components/commit_list_item_spec.js new file mode 100644 index 00000000000000..25583cfb95a127 --- /dev/null +++ b/spec/frontend/projects/commits/components/commit_list_item_spec.js @@ -0,0 +1,74 @@ +import { shallowMount } from '@vue/test-utils'; +import CommitListItem from '~/projects/commits/components/commit_list_item.vue'; +import CommitInfo from '~/repository/components/commit_info.vue'; +import SignatureBadge from '~/commit/components/signature_badge.vue'; +import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; + +describe('Commit List Item', () => { + let wrapper; + + const mockCommit = { + id: '123', + sha: 'abcdef1234567890', + title: 'Fix bug in feature X', + message: 'Fix bug in feature X\n\nDetailed description', + author_name: 'John Doe', + author_email: 'john@example.com', + authored_date: '2023-01-01T12:00:00Z', + committer_name: 'Jane Smith', + committer_email: 'jane@example.com', + committed_date: '2023-01-02T12:00:00Z', + web_url: 'https://gitlab.com/group/project/-/commit/abcdef1234567890', + signature: { + verification_status: 'verified', + gpg_key_primary_keyid: '', + gpg_key_user_name: 'John Doe', + gpg_key_user_email: 'john@example.com', + }, + }; + + const createComponent = (props = {}) => { + wrapper = shallowMount(CommitListItem, { + propsData: { + commit: mockCommit, + ...props, + }, + }); + }; + + beforeEach(() => { + createComponent(); + }); + + const findCommitInfo = () => wrapper.findComponent(CommitInfo); + const findSignatureBadge = () => wrapper.findComponent(SignatureBadge); + const findCommitIdButton = () => wrapper.find('[data-testid="last-commit-id-label"]'); + const findClipboardButton = () => wrapper.findComponent(ClipboardButton); + + describe('component rendering', () => { + it('renders the commit info component with correct props', () => { + expect(findCommitInfo().props('commit')).toEqual(mockCommit); + }); + + it('renders the signature badge when commit has signature', () => { + expect(findSignatureBadge().props('signature')).toEqual(mockCommit.signature); + }); + + it('does not render signature badge when commit has no signature', () => { + createComponent({ + commit: { ...mockCommit, signature: null }, + }); + + expect(findSignatureBadge().exists()).toBe(false); + }); + + it('renders the commit ID button with truncated SHA', () => { + expect(findCommitIdButton().text()).toBe('abcdef12'); + }); + + it('renders the clipboard button with full SHA', () => { + expect(findClipboardButton().props('text')).toBe(mockCommit.sha); + expect(findClipboardButton().props('title')).toBe('Copy commit SHA'); + }); + }); +}); diff --git a/spec/views/projects/commits/show.html.haml_spec.rb b/spec/views/projects/commits/show.html.haml_spec.rb index 96806aada13152..f0765710bad0fa 100644 --- a/spec/views/projects/commits/show.html.haml_spec.rb +++ b/spec/views/projects/commits/show.html.haml_spec.rb @@ -11,6 +11,8 @@ let(:ref) { "master" } before do + stub_feature_flags(project_commits_refactor: false) + assign(:project, project) assign(:path, path) assign(:id, path) -- GitLab From ea3590810e0fc6b6dc9a251bdaec351f97c8bca1 Mon Sep 17 00:00:00 2001 From: Chaoyue Zhao Date: Wed, 28 May 2025 23:26:16 -0400 Subject: [PATCH 2/4] Remove unconfirmed components Since design is not yet finalized, keep the MR to just set up boilerplate. --- .../commits/components/commit_list_app.vue | 33 +---- .../commits/components/commit_list_header.vue | 89 +------------ .../commits/components/commit_list_item.vue | 38 +----- .../projects/commits/init_commit_list_app.js | 8 +- app/views/projects/commits/show.html.haml | 2 +- .../commits/components/commit_header_spec.js | 119 ------------------ .../components/commit_list_app_spec.js | 25 +--- .../components/commit_list_item_spec.js | 74 ----------- .../projects/commits/components/mock_data.js | 59 --------- 9 files changed, 13 insertions(+), 434 deletions(-) delete mode 100644 spec/frontend/projects/commits/components/commit_header_spec.js delete mode 100644 spec/frontend/projects/commits/components/commit_list_item_spec.js rename {app/assets/javascripts => spec/frontend}/projects/commits/components/mock_data.js (54%) diff --git a/app/assets/javascripts/projects/commits/components/commit_list_app.vue b/app/assets/javascripts/projects/commits/components/commit_list_app.vue index 03c1e78589c2c9..80f79814b5dc0e 100644 --- a/app/assets/javascripts/projects/commits/components/commit_list_app.vue +++ b/app/assets/javascripts/projects/commits/components/commit_list_app.vue @@ -1,54 +1,25 @@ diff --git a/app/assets/javascripts/projects/commits/components/commit_list_header.vue b/app/assets/javascripts/projects/commits/components/commit_list_header.vue index 8c20df8b8f5280..ff8e38a3169934 100644 --- a/app/assets/javascripts/projects/commits/components/commit_list_header.vue +++ b/app/assets/javascripts/projects/commits/components/commit_list_header.vue @@ -1,97 +1,12 @@ diff --git a/app/assets/javascripts/projects/commits/components/commit_list_item.vue b/app/assets/javascripts/projects/commits/components/commit_list_item.vue index 73b8bd49dd2aa7..33a634d0040b33 100644 --- a/app/assets/javascripts/projects/commits/components/commit_list_item.vue +++ b/app/assets/javascripts/projects/commits/components/commit_list_item.vue @@ -1,49 +1,17 @@ diff --git a/app/assets/javascripts/projects/commits/init_commit_list_app.js b/app/assets/javascripts/projects/commits/init_commit_list_app.js index acb4791b0debad..73ea2740550192 100644 --- a/app/assets/javascripts/projects/commits/init_commit_list_app.js +++ b/app/assets/javascripts/projects/commits/init_commit_list_app.js @@ -1,19 +1,17 @@ import Vue from 'vue'; import CommitListApp from './components/commit_list_app.vue'; -import { mockDataset } from './components/mock_data'; export default function initCommitListApp() { const commitListEl = document.getElementById('js-commit-list'); if (commitListEl) { - const { ref } = mockDataset; + const { projectPath, currentPath } = commitListEl.dataset; // eslint-disable-next-line no-new new Vue({ el: commitListEl, provide: { - // TODO - replace with real data - ...mockDataset, - currentRef: ref, + projectPath, + currentPath, }, render(h) { return h(CommitListApp, {}); diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml index eb37ae2dbe2bf3..ca1a03d2527c26 100644 --- a/app/views/projects/commits/show.html.haml +++ b/app/views/projects/commits/show.html.haml @@ -10,7 +10,7 @@ = auto_discovery_link_tag(:atom, project_commits_path(@project, @ref, rss_url_options), title: "#{@project.name}:#{@ref} commits") - if Feature.enabled?(:project_commits_refactor, @project) - #js-commit-list + #js-commit-list{ data: { "project-path" => @project.path } } - else .js-project-commits-show{ 'data-commits-limit' => @limit } diff --git a/spec/frontend/projects/commits/components/commit_header_spec.js b/spec/frontend/projects/commits/components/commit_header_spec.js deleted file mode 100644 index 864aba8f32f2db..00000000000000 --- a/spec/frontend/projects/commits/components/commit_header_spec.js +++ /dev/null @@ -1,119 +0,0 @@ -import { GlBreadcrumb } from '@gitlab/ui'; -import { shallowMount } from '@vue/test-utils'; -import { nextTick } from 'vue'; -import CommitListHeader from '~/projects/commits/components/commit_list_header.vue'; -import RefSelector from '~/ref/components/ref_selector.vue'; -import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; -import { mockCrumbs, mockTokens } from '~/projects/commits/components/mock_data'; - -describe('Commit Header', () => { - let wrapper; - const projectId = '123'; - const projectPath = 'group/project'; - const currentRef = 'main'; - const refType = 'heads'; - const currentPath = 'path/to/directory'; - const sortOptions = [ - { value: 'CREATED_DATE_DESC', text: 'Created date' }, - { value: 'UPDATED_DATE_DESC', text: 'Updated date' }, - ]; - - const createComponent = (props = {}) => { - wrapper = shallowMount(CommitListHeader, { - provide: { - projectId, - projectPath, - currentRef, - refType, - currentPath, - sortOptions, - ...props, - }, - }); - }; - - beforeEach(() => { - createComponent(); - }); - - const findRefSelector = () => wrapper.findComponent(RefSelector); - const findBreadcrumb = () => wrapper.findComponent(GlBreadcrumb); - const findFilteredSearchBar = () => wrapper.findComponent(FilteredSearchBar); - const findDirectoryHeading = () => wrapper.find('h1'); - - describe('ref selector', () => { - it('passes correct props to ref selector', () => { - expect(findRefSelector().props()).toMatchObject({ - projectId, - value: 'refs/heads/main', - useSymbolicRefNames: true, - queryParams: { sort: 'updated_desc' }, - }); - }); - - it('emits ref-change event when ref is changed', () => { - const newRef = 'feature-branch'; - findRefSelector().vm.$emit('input', newRef); - - expect(wrapper.emitted('ref-change')).toEqual([[newRef]]); - }); - - it('constructs correct ref value when refType is not provided', async () => { - createComponent({ refType: null }); - - await nextTick(); - expect(findRefSelector().props('value')).toBe(currentRef); - }); - }); - - describe('breadcrumb', () => { - it('renders breadcrumb with correct items', () => { - expect(findBreadcrumb().props('items')).toEqual(mockCrumbs); - }); - - it('sets correct data-current-path attribute', () => { - expect(findBreadcrumb().attributes('data-current-path')).toBe(currentPath); - }); - }); - - describe('directory heading', () => { - it('displays the directory name from currentPath', () => { - expect(findDirectoryHeading().text()).toBe('directory'); - }); - - it('displays the project name when currentPath is not provided', async () => { - createComponent({ currentPath: '' }); - - await nextTick(); - expect(findDirectoryHeading().text()).toBe('project'); - }); - }); - - describe('filtered search bar', () => { - it('passes correct props to filtered search bar', () => { - expect(findFilteredSearchBar().props()).toMatchObject({ - namespace: 'commits', - tokens: mockTokens, - recentSearchesStorageKey: 'commits', - searchInputPlaceholder: 'Search or filter commits...', - initialFilterValue: [], - initialSortBy: 'CREATED_DATE_DESC', - sortOptions, - }); - }); - - it('emits search event when filter is applied', () => { - const filterValue = ['author:John']; - findFilteredSearchBar().vm.$emit('onFilter', filterValue); - - expect(wrapper.emitted('search')).toEqual([[filterValue]]); - }); - - it('emits sort event when sort changes', () => { - const sortValue = 'CREATED_DATE_ASC'; - findFilteredSearchBar().vm.$emit('onSort', sortValue); - - expect(wrapper.emitted('sort')).toEqual([[sortValue]]); - }); - }); -}); diff --git a/spec/frontend/projects/commits/components/commit_list_app_spec.js b/spec/frontend/projects/commits/components/commit_list_app_spec.js index d7eb9719a4f8b7..f4b5633271e7a2 100644 --- a/spec/frontend/projects/commits/components/commit_list_app_spec.js +++ b/spec/frontend/projects/commits/components/commit_list_app_spec.js @@ -1,11 +1,9 @@ -import { GlKeysetPagination } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import CommitListApp from '~/projects/commits/components/commit_list_app.vue'; import CommitListHeader from '~/projects/commits/components/commit_list_header.vue'; import CommitListItem from '~/projects/commits/components/commit_list_item.vue'; -import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue'; -import PageSizeSelector from '~/vue_shared/components/page_size_selector.vue'; -import { mockCommits } from '~/projects/commits/components/mock_data'; + +import { mockCommits } from './mock_data'; describe('Commit List App', () => { let wrapper; @@ -23,9 +21,6 @@ describe('Commit List App', () => { const findCommitHeader = () => wrapper.findComponent(CommitListHeader); const findCommitListItems = () => wrapper.findAllComponents(CommitListItem); - const findKeysetPagination = () => wrapper.findComponent(GlKeysetPagination); - const findLocalStorageSync = () => wrapper.findComponent(LocalStorageSync); - const findPageSizeSelector = () => wrapper.findComponent(PageSizeSelector); describe('commit header', () => { it('renders the commit header component', () => { @@ -42,20 +37,4 @@ describe('Commit List App', () => { }); }); }); - - describe('pagination', () => { - it('renders the keyset pagination component', () => { - expect(findKeysetPagination().exists()).toBe(true); - }); - }); - - describe('page size selector', () => { - it('renders the local storage sync component', () => { - expect(findLocalStorageSync().exists()).toBe(true); - }); - - it('renders the page size selector component', () => { - expect(findPageSizeSelector().exists()).toBe(true); - }); - }); }); diff --git a/spec/frontend/projects/commits/components/commit_list_item_spec.js b/spec/frontend/projects/commits/components/commit_list_item_spec.js deleted file mode 100644 index 25583cfb95a127..00000000000000 --- a/spec/frontend/projects/commits/components/commit_list_item_spec.js +++ /dev/null @@ -1,74 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; -import CommitListItem from '~/projects/commits/components/commit_list_item.vue'; -import CommitInfo from '~/repository/components/commit_info.vue'; -import SignatureBadge from '~/commit/components/signature_badge.vue'; -import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; - -describe('Commit List Item', () => { - let wrapper; - - const mockCommit = { - id: '123', - sha: 'abcdef1234567890', - title: 'Fix bug in feature X', - message: 'Fix bug in feature X\n\nDetailed description', - author_name: 'John Doe', - author_email: 'john@example.com', - authored_date: '2023-01-01T12:00:00Z', - committer_name: 'Jane Smith', - committer_email: 'jane@example.com', - committed_date: '2023-01-02T12:00:00Z', - web_url: 'https://gitlab.com/group/project/-/commit/abcdef1234567890', - signature: { - verification_status: 'verified', - gpg_key_primary_keyid: '', - gpg_key_user_name: 'John Doe', - gpg_key_user_email: 'john@example.com', - }, - }; - - const createComponent = (props = {}) => { - wrapper = shallowMount(CommitListItem, { - propsData: { - commit: mockCommit, - ...props, - }, - }); - }; - - beforeEach(() => { - createComponent(); - }); - - const findCommitInfo = () => wrapper.findComponent(CommitInfo); - const findSignatureBadge = () => wrapper.findComponent(SignatureBadge); - const findCommitIdButton = () => wrapper.find('[data-testid="last-commit-id-label"]'); - const findClipboardButton = () => wrapper.findComponent(ClipboardButton); - - describe('component rendering', () => { - it('renders the commit info component with correct props', () => { - expect(findCommitInfo().props('commit')).toEqual(mockCommit); - }); - - it('renders the signature badge when commit has signature', () => { - expect(findSignatureBadge().props('signature')).toEqual(mockCommit.signature); - }); - - it('does not render signature badge when commit has no signature', () => { - createComponent({ - commit: { ...mockCommit, signature: null }, - }); - - expect(findSignatureBadge().exists()).toBe(false); - }); - - it('renders the commit ID button with truncated SHA', () => { - expect(findCommitIdButton().text()).toBe('abcdef12'); - }); - - it('renders the clipboard button with full SHA', () => { - expect(findClipboardButton().props('text')).toBe(mockCommit.sha); - expect(findClipboardButton().props('title')).toBe('Copy commit SHA'); - }); - }); -}); diff --git a/app/assets/javascripts/projects/commits/components/mock_data.js b/spec/frontend/projects/commits/components/mock_data.js similarity index 54% rename from app/assets/javascripts/projects/commits/components/mock_data.js rename to spec/frontend/projects/commits/components/mock_data.js index 07760118da628b..d9d87918da3b73 100644 --- a/app/assets/javascripts/projects/commits/components/mock_data.js +++ b/spec/frontend/projects/commits/components/mock_data.js @@ -1,4 +1,3 @@ -/* eslint-disable @gitlab/require-i18n-strings */ const mockCommit = { data: { project: { @@ -43,61 +42,3 @@ export const mockCommits = Array(20) id: `${mockCommit.data.project.repository.lastCommit.id}-${index}`, // Make IDs unique sha: `${mockCommit.data.project.repository.lastCommit.sha.substring(0, 8)}${index}`, // Make SHAs unique })); - -export const mockDataset = { - ref: 'main', - refType: 'heads', - projectId: '3', - projectPath: 'gitlab-org/gitlab-shell', - currentPath: '.gitlab-ci.yml', - sortOptions: [ - { - id: 1, - title: 'Created date', - sortDirection: { ascending: 'CREATED_DATE_ASC', descending: 'CREATED_DATE_DESC' }, - }, - ], -}; - -export const mockCrumbs = [ - { - text: 'gitlab-shell', - href: '/gitlab-org/gitlab-shell/-/tree/main', - path: '/', - to: '/-/tree/main', - }, - { - text: '.gitlab-ci.yml', - href: '/gitlab-org/gitlab-shell/-/blob/main/.gitlab-ci.yml', - path: '.gitlab-ci.yml', - to: '/-/blob/main/.gitlab-ci.yml', - }, -]; - -export const mockTokens = [ - { - type: 'author', - title: 'Author', - icon: 'pencil', - dataType: 'user', - defaultUsers: [], - operators: [ - { value: '=', description: 'is' }, - { value: '!=', description: 'is not one of' }, - { value: '||', description: 'is one of' }, - ], - fullPath: 'gitlab-org/gitlab-shell', - isProject: true, - recentSuggestionsStorageKey: 'gitlab-org/gitlab-shell-commits-recent-tokens-author', - preloadedUsers: [ - { - id: 'gid://gitlab/User/1', - name: 'Administrator', - username: 'root', - avatar_url: - 'https://secure.gravatar.com/avatar/7272d4da0ca779e0ca6fdb7fdc7a17b232462e054839e1060934d03f6ded8609?s=80&d=identicon', - }, - ], - multiSelect: true, - }, -]; -- GitLab From b2f3b958962ed73288d47591531f3d9a9d97fcd3 Mon Sep 17 00:00:00 2001 From: Chaoyue Zhao Date: Fri, 30 May 2025 12:57:53 -0400 Subject: [PATCH 3/4] Fix more tests --- .../commits/user_view_commits_spec.rb | 81 ++-- spec/features/commits_spec.rb | 376 +++++++++--------- .../markdown/gitlab_flavored_markdown_spec.rb | 28 +- .../projects/files/user_browses_files_spec.rb | 119 +++--- .../components/commit_list_app_spec.js | 14 - .../projects/commits/components/mock_data.js | 44 -- 6 files changed, 309 insertions(+), 353 deletions(-) delete mode 100644 spec/frontend/projects/commits/components/mock_data.js diff --git a/spec/features/commits/user_view_commits_spec.rb b/spec/features/commits/user_view_commits_spec.rb index 8257295deddbde..69ef41fe0bec5c 100644 --- a/spec/features/commits/user_view_commits_spec.rb +++ b/spec/features/commits/user_view_commits_spec.rb @@ -15,46 +15,52 @@ end describe 'Commits List' do - context 'when project is public' do - let_it_be(:project) { create_default(:project, :public, :repository, group: group) } - + context 'when project_commits_refactor feature flag is disabled' do before do - visit project_commits_path(project) + stub_feature_flags(project_commits_refactor: false) end - it_behaves_like 'can view commits' - end - - context 'when project is public with private repository' do - let_it_be(:project) { create_default(:project, :public, :repository, :repository_private, group: group) } - - context 'and user is an inherited member from the group' do - context 'and user is a guest' do - before do - group.add_guest(user) - sign_in(user) - visit project_commits_path(project) - end + context 'when project is public' do + let_it_be(:project) { create_default(:project, :public, :repository, group: group) } - it_behaves_like 'can view commits' + before do + visit project_commits_path(project) end + + it_behaves_like 'can view commits' end - end - context 'when project is private' do - let_it_be(:project) { create_default(:project, :private, :repository, group: group) } + context 'when project is public with private repository' do + let_it_be(:project) { create_default(:project, :public, :repository, :repository_private, group: group) } + + context 'and user is an inherited member from the group' do + context 'and user is a guest' do + before do + group.add_guest(user) + sign_in(user) + visit project_commits_path(project) + end - context 'and user is an inherited member from the group' do - context 'and user is a guest' do - before do - group.add_guest(user) - sign_in(user) - visit project_commits_path(project) + it_behaves_like 'can view commits' end + end + end - it 'renders not found' do - expect(page).to have_title('Not Found') - expect(page).to have_content('Page not found') + context 'when project is private' do + let_it_be(:project) { create_default(:project, :private, :repository, group: group) } + + context 'and user is an inherited member from the group' do + context 'and user is a guest' do + before do + group.add_guest(user) + sign_in(user) + visit project_commits_path(project) + end + + it 'renders not found' do + expect(page).to have_title('Not Found') + expect(page).to have_content('Page not found') + end end end end @@ -65,14 +71,19 @@ let_it_be(:project) { create_default(:project, :public, :repository, group: group) } let_it_be(:sha) { sample_commit.sha } - it 'passes axe automated accessibility testing' do - visit project_commit_path(project, sha) + context 'when project_commits_refactor feature flag is disabled' do + before do + stub_feature_flags(project_commits_refactor: false) + end + + it 'passes axe automated accessibility testing' do + visit project_commit_path(project, sha) wait_for_requests - expect(page).to be_axe_clean.within('#content-body').skipping :'color-contrast', :'link-in-text-block', - :'link-name', :'valid-lang' - end + expect(page).to be_axe_clean.within('#content-body').skipping :'color-contrast', :'link-in-text-block', + :'link-name', :'valid-lang' + end context 'when displayed with rapid_diffs' do let_it_be(:diffs) { project.commit(sha).diffs } diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 6a6c497fa6d604..38891b56becbdb 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -6,264 +6,270 @@ let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user) } - describe 'CI' do + context 'when project_commits_refactor feature flag is disabled' do before do - sign_in(user) - stub_ci_pipeline_to_return_yaml_file + stub_feature_flags(project_commits_refactor: false) end - let(:creator) { create(:user, developer_of: project) } - let!(:pipeline) do - create( - :ci_pipeline, - project: project, - user: creator, - ref: project.default_branch, - sha: project.commit.sha, - status: :success, - created_at: 5.months.ago - ) - end - - context 'commit status is Generic Commit Status' do - let(:stage) { create(:ci_stage, pipeline: pipeline, name: 'external') } - let!(:status) { create(:generic_commit_status, pipeline: pipeline, ref: pipeline.ref, ci_stage: stage) } - + describe 'CI' do before do - project.add_reporter(user) + sign_in(user) + stub_ci_pipeline_to_return_yaml_file end - describe 'Commit builds', :js do - before do - visit builds_project_pipeline_path(project, pipeline) + let(:creator) { create(:user, developer_of: project) } + let!(:pipeline) do + create( + :ci_pipeline, + project: project, + user: creator, + ref: project.default_branch, + sha: project.commit.sha, + status: :success, + created_at: 5.months.ago + ) + end - wait_for_requests + context 'commit status is Generic Commit Status' do + let(:stage) { create(:ci_stage, pipeline: pipeline, name: 'external') } + let!(:status) { create(:generic_commit_status, pipeline: pipeline, ref: pipeline.ref, ci_stage: stage) } + + before do + project.add_reporter(user) end - it 'contains commit short id' do - within_testid('pipeline-header') do - expect(page).to have_content pipeline.sha[0..7] + describe 'Commit builds', :js do + before do + visit builds_project_pipeline_path(project, pipeline) + + wait_for_requests end - end - it 'contains generic commit status build' do - within_testid('jobs-tab-table') do - expect(page).to have_content "##{status.id}" # build id - expect(page).to have_content 'generic' # build name + it 'contains commit short id' do + within_testid('pipeline-header') do + expect(page).to have_content pipeline.sha[0..7] + end + end + + it 'contains generic commit status build' do + within_testid('jobs-tab-table') do + expect(page).to have_content "##{status.id}" # build id + expect(page).to have_content 'generic' # build name + end end end end - end - context 'commit status is Ci Build' do - let!(:build) { create(:ci_build, pipeline: pipeline) } - let(:artifacts_file) { fixture_file_upload('spec/fixtures/banana_sample.gif', 'image/gif') } + context 'commit status is Ci Build' do + let!(:build) { create(:ci_build, pipeline: pipeline) } + let(:artifacts_file) { fixture_file_upload('spec/fixtures/banana_sample.gif', 'image/gif') } - context 'when logged as developer' do - before do - project.add_developer(user) - end - - describe 'Project commits' do - let!(:pipeline_from_other_branch) do - create( - :ci_pipeline, - project: project, - ref: 'fix', - sha: project.commit.sha, - status: :failed - ) + context 'when logged as developer' do + before do + project.add_developer(user) end - before do - visit project_commits_path(project, :master) + describe 'Project commits' do + let!(:pipeline_from_other_branch) do + create( + :ci_pipeline, + project: project, + ref: 'fix', + sha: project.commit.sha, + status: :failed + ) + end + + before do + visit project_commits_path(project, :master) + end + + it 'shows correct build status from default branch' do + page.within("//li[@id='commit-#{pipeline.short_sha}']") do + expect(page).to have_css("[data-testid='ci-icon']") + expect(page).to have_css('[data-testid="status_success_borderless-icon"]') + end + end end - it 'shows correct build status from default branch' do - page.within("//li[@id='commit-#{pipeline.short_sha}']") do - expect(page).to have_css("[data-testid='ci-icon']") - expect(page).to have_css('[data-testid="status_success_borderless-icon"]') + describe 'Commit builds', :js do + before do + project.add_developer(user) + visit pipeline_path(pipeline) + end + + it 'shows pipeline data' do + expect(page).to have_content pipeline.sha[0..7] + expect(page).to have_content pipeline.user.name end end - end - describe 'Commit builds', :js do - before do - project.add_developer(user) - visit pipeline_path(pipeline) + context 'Download artifacts', :js do + before do + create(:ci_job_artifact, :archive, file: artifacts_file, job: build) + end + + it do + visit builds_project_pipeline_path(project, pipeline) + wait_for_requests + expect(page).to have_link('Download artifacts', href: download_project_job_artifacts_path(project, build, file_type: :archive)) + end end - it 'shows pipeline data' do - expect(page).to have_content pipeline.sha[0..7] - expect(page).to have_content pipeline.user.name + describe 'Cancel jobs' do + let!(:pipeline) do + create( + :ci_pipeline, + project: project, + user: creator, + ref: project.default_branch, + sha: project.commit.sha, + status: :running, + created_at: 5.months.ago + ) + end + + before do + visit pipeline_path(pipeline) + wait_for_requests + click_on 'Cancel pipeline' + wait_for_requests + end + + it 'cancels pipeline and jobs', :js, :sidekiq_might_not_need_inline do + expect(page).to have_content 'Canceled' + end end end - context 'Download artifacts', :js do + context "when logged as reporter", :js do before do + project.add_reporter(user) create(:ci_job_artifact, :archive, file: artifacts_file, job: build) - end - - it do visit builds_project_pipeline_path(project, pipeline) wait_for_requests - expect(page).to have_link('Download artifacts', href: download_project_job_artifacts_path(project, build, file_type: :archive)) end - end - describe 'Cancel jobs' do - let!(:pipeline) do - create( - :ci_pipeline, - project: project, - user: creator, - ref: project.default_branch, - sha: project.commit.sha, - status: :running, - created_at: 5.months.ago - ) + it 'renders header' do + expect(page).to have_content pipeline.sha[0..7] + expect(page).to have_content pipeline.user.name + expect(page).not_to have_link('Cancel pipeline') + expect(page).not_to have_link('Retry') end + it do + expect(page).to have_link('Download artifacts') + end + end + + context 'when accessing internal project with disallowed access', :js do before do + project.add_reporter(user) + project.update!( + visibility_level: Gitlab::VisibilityLevel::INTERNAL, + public_builds: false) + create(:ci_job_artifact, :archive, file: artifacts_file, job: build) visit pipeline_path(pipeline) - wait_for_requests - click_on 'Cancel pipeline' - wait_for_requests end - it 'cancels pipeline and jobs', :js, :sidekiq_might_not_need_inline do - expect(page).to have_content 'Canceled' + it do + expect(page).to have_content pipeline.sha[0..7] + expect(page).to have_content pipeline.user.name + + expect(page).not_to have_link('Cancel pipeline') + expect(page).not_to have_link('Retry') end end end + end - context "when logged as reporter", :js do - before do - project.add_reporter(user) - create(:ci_job_artifact, :archive, file: artifacts_file, job: build) - visit builds_project_pipeline_path(project, pipeline) - wait_for_requests - end + context 'viewing commits for a branch' do + let(:branch_name) { 'master' } + let(:ref_selector) { '.ref-selector' } + let(:ref_with_hash) { 'ref-#-hash' } - it 'renders header' do - expect(page).to have_content pipeline.sha[0..7] - expect(page).to have_content pipeline.user.name - expect(page).not_to have_link('Cancel pipeline') - expect(page).not_to have_link('Retry') - end + def switch_ref_to(ref_name) + first(ref_selector).click + wait_for_requests - it do - expect(page).to have_link('Download artifacts') + page.within ref_selector do + fill_in 'Search by Git revision', with: ref_name + wait_for_requests + find('li', text: ref_name, match: :prefer_exact).click end end - context 'when accessing internal project with disallowed access', :js do - before do - project.add_reporter(user) - project.update!( - visibility_level: Gitlab::VisibilityLevel::INTERNAL, - public_builds: false) - create(:ci_job_artifact, :archive, file: artifacts_file, job: build) - visit pipeline_path(pipeline) - end - - it do - expect(page).to have_content pipeline.sha[0..7] - expect(page).to have_content pipeline.user.name + before do + project.add_maintainer(user) + sign_in(user) + project.repository.create_branch(ref_with_hash, branch_name) + visit project_commits_path(project, branch_name) + end - expect(page).not_to have_link('Cancel pipeline') - expect(page).not_to have_link('Retry') + it 'includes a date on which the commits were authored' do + commits = project.repository.commits(branch_name, limit: 40) + commits.chunk { |c| c.committed_date.in_time_zone.to_date }.each do |day, _daily_commits| + expect(page).to have_content(day.strftime("%b %d, %Y")) end end - end - end - context 'viewing commits for a branch' do - let(:branch_name) { 'master' } - let(:ref_selector) { '.ref-selector' } - let(:ref_with_hash) { 'ref-#-hash' } + it 'includes the committed_date for each commit' do + commits = project.repository.commits(branch_name, limit: 40) - def switch_ref_to(ref_name) - first(ref_selector).click - wait_for_requests - - page.within ref_selector do - fill_in 'Search by Git revision', with: ref_name - wait_for_requests - find('li', text: ref_name, match: :prefer_exact).click + commits.each do |commit| + expect(page).to have_content("authored #{commit.authored_date.strftime('%b %d, %Y')}") + end end - end - before do - project.add_maintainer(user) - sign_in(user) - project.repository.create_branch(ref_with_hash, branch_name) - visit project_commits_path(project, branch_name) - end + it 'switches ref to ref containing a hash', :js do + switch_ref_to(ref_with_hash) - it 'includes a date on which the commits were authored' do - commits = project.repository.commits(branch_name, limit: 40) - commits.chunk { |c| c.committed_date.in_time_zone.to_date }.each do |day, _daily_commits| - expect(page).to have_content(day.strftime("%b %d, %Y")) + expect(page).to have_selector ref_selector, text: ref_with_hash end - end - it 'includes the committed_date for each commit' do - commits = project.repository.commits(branch_name, limit: 40) + it 'shows the ref switcher with the multi-file editor enabled', :js do + set_cookie('new_repo', 'true') + visit project_commits_path(project, branch_name) - commits.each do |commit| - expect(page).to have_content("authored #{commit.authored_date.strftime('%b %d, %Y')}") + expect(find(ref_selector)).to have_content branch_name end end - it 'switches ref to ref containing a hash', :js do - switch_ref_to(ref_with_hash) - - expect(page).to have_selector ref_selector, text: ref_with_hash - end - - it 'shows the ref switcher with the multi-file editor enabled', :js do - set_cookie('new_repo', 'true') - visit project_commits_path(project, branch_name) - - expect(find(ref_selector)).to have_content branch_name - end - end + context 'viewing commits for an author' do + let(:author_commit) { project.repository.commits(nil, limit: 1).first } + let(:commits) { project.repository.commits(nil, author: author, limit: 40) } - context 'viewing commits for an author' do - let(:author_commit) { project.repository.commits(nil, limit: 1).first } - let(:commits) { project.repository.commits(nil, author: author, limit: 40) } - - before do - project.add_maintainer(user) - sign_in(user) - visit project_commits_path(project, nil, author: author) - end + before do + project.add_maintainer(user) + sign_in(user) + visit project_commits_path(project, nil, author: author) + end - shared_examples 'show commits by author' do - it "includes the author's commits" do - commits.each do |commit| - expect(page).to have_content("#{author_commit.author_name} authored #{commit.authored_date.strftime('%b %d, %Y')}") + shared_examples 'show commits by author' do + it "includes the author's commits" do + commits.each do |commit| + expect(page).to have_content("#{author_commit.author_name} authored #{commit.authored_date.strftime('%b %d, %Y')}") + end end end - end - context 'author is complete' do - let(:author) { "#{author_commit.author_name} <#{author_commit.author_email}>" } + context 'author is complete' do + let(:author) { "#{author_commit.author_name} <#{author_commit.author_email}>" } - it_behaves_like 'show commits by author' - end + it_behaves_like 'show commits by author' + end - context 'author is just a name' do - let(:author) { author_commit.author_name.to_s } + context 'author is just a name' do + let(:author) { author_commit.author_name.to_s } - it_behaves_like 'show commits by author' - end + it_behaves_like 'show commits by author' + end - context 'author is just an email' do - let(:author) { author_commit.author_email.to_s } + context 'author is just an email' do + let(:author) { author_commit.author_email.to_s } - it_behaves_like 'show commits by author' + it_behaves_like 'show commits by author' + end end end end diff --git a/spec/features/markdown/gitlab_flavored_markdown_spec.rb b/spec/features/markdown/gitlab_flavored_markdown_spec.rb index 20eef55d2545cc..09fa6fee076259 100644 --- a/spec/features/markdown/gitlab_flavored_markdown_spec.rb +++ b/spec/features/markdown/gitlab_flavored_markdown_spec.rb @@ -34,22 +34,28 @@ ) end - it "renders title in commits#index" do - visit project_commits_path(project, 'master', limit: 1) + context 'when project_commits_refactor feature flag is disabled' do + before do + stub_feature_flags(project_commits_refactor: false) + end - expect(page).to have_link(issue.to_reference) - end + it "renders title in commits#index" do + visit project_commits_path(project, 'master', limit: 1) - it "renders title in commits#show" do - visit project_commit_path(project, commit) + expect(page).to have_link(issue.to_reference) + end - expect(page).to have_link(issue.to_reference) - end + it "renders title in commits#show" do + visit project_commit_path(project, commit) - it "renders description in commits#show" do - visit project_commit_path(project, commit) + expect(page).to have_link(issue.to_reference) + end - expect(page).to have_link(fred.to_reference) + it "renders description in commits#show" do + visit project_commit_path(project, commit) + + expect(page).to have_link(fred.to_reference) + end end it "renders title in repositories#branches" do diff --git a/spec/features/projects/files/user_browses_files_spec.rb b/spec/features/projects/files/user_browses_files_spec.rb index b79ae090639b24..d52dfaebc2079f 100644 --- a/spec/features/projects/files/user_browses_files_spec.rb +++ b/spec/features/projects/files/user_browses_files_spec.rb @@ -16,6 +16,8 @@ let(:user) { project.first_owner } before do + # TODO - remove this stub once commit list refactor is complete + stub_feature_flags(project_commits_refactor: false) sign_in(user) end @@ -32,62 +34,58 @@ end context "when browsing a branch", :js do - context 'when project_commits_refactor feature flag is disabled' do - before do - stub_feature_flags(project_commits_refactor: false) - - visit(tree_path_root_ref) - end - - it "shows files from a repository" do - expect(page).to have_content("VERSION") - .and have_content(".gitignore") - .and have_content("LICENSE") - end - - it "shows the `Browse Directory` link" do - click_link("files") + before do + visit(tree_path_root_ref) + end - page.within('.repo-breadcrumb') do - expect(page).to have_link('files') - end + it "shows files from a repository" do + expect(page).to have_content("VERSION") + .and have_content(".gitignore") + .and have_content("LICENSE") + end - click_link("History") + it "shows the `Browse Directory` link" do + click_link("files") - history_path = project_commits_path(project, "master/files") - expect(page).to have_current_path(history_path) - expect(page).to have_link("Browse Directory").and have_no_link("Browse Code") + page.within('.repo-breadcrumb') do + expect(page).to have_link('files') end - it "shows the `Browse File` link" do - page.within(".tree-table") do - click_link("README.md") - end + click_link("History") - page.within(".commit-actions") do - click_link("History") - end + history_path = project_commits_path(project, "master/files") + expect(page).to have_current_path(history_path) + expect(page).to have_link("Browse Directory").and have_no_link("Browse Code") + end - history_path = project_commits_path(project, "master/README.md") - expect(page).to have_current_path(history_path) - expect(page).to have_link("Browse File").and have_no_link("Browse Files") + it "shows the `Browse File` link" do + page.within(".tree-table") do + click_link("README.md") end - it "shows the `Browse Files` link" do + page.within(".commit-actions") do click_link("History") - - history_path = project_commits_path(project, "master") - expect(page).to have_current_path(history_path) - expect(page).to have_link("Browse Files").and have_no_link("Browse Directory") end - it "copies permalink URL" do - click_link(".gitignore") - click_button("File actions") - click_button("Copy permalink") + history_path = project_commits_path(project, "master/README.md") + expect(page).to have_current_path(history_path) + expect(page).to have_link("Browse File").and have_no_link("Browse Files") + end - expect(page).to have_text("Permalink copied to clipboard.") - end + it "shows the `Browse Files` link" do + click_link("History") + + history_path = project_commits_path(project, "master") + expect(page).to have_current_path(history_path) + expect(page).to have_link("Browse Files").and have_no_link("Browse Directory") + end + + it "copies permalink URL" do + click_link(".gitignore") + click_button("File actions") + click_button("Copy permalink") + + expect(page).to have_text("Permalink copied to clipboard.") end end @@ -141,19 +139,16 @@ context "when browsing the `markdown` branch", :js do context "when browsing the root" do - context 'when project_commits_refactor feature flag is disabled' do - before do - stub_feature_flags(project_commits_refactor: false) - visit(project_tree_path(project, "markdown")) - end + before do + visit(project_tree_path(project, "markdown")) + end - it "copies permalink URL" do - click_link(".gitignore") - click_button("File actions") - click_button("Copy permalink") + it "copies permalink URL" do + click_link(".gitignore") + click_button("File actions") + click_button("Copy permalink") - expect(page).to have_text("Permalink copied to clipboard.") - end + expect(page).to have_text("Permalink copied to clipboard.") end it "shows correct files and links" do @@ -240,18 +235,14 @@ end context 'when commit message has markdown', :js do - context 'when project_commits_refactor feature flag is disabled' do - before do - stub_feature_flags(project_commits_refactor: false) - - project.repository.create_file(user, 'index', 'test', message: ':star: testing', branch_name: 'master') + before do + project.repository.create_file(user, 'index', 'test', message: ':star: testing', branch_name: 'master') - visit(project_tree_path(project, "master")) - end + visit(project_tree_path(project, "master")) + end - it 'renders emojis' do - expect(page).to have_selector('gl-emoji', count: 2) - end + it 'renders emojis' do + expect(page).to have_selector('gl-emoji', count: 2) end end diff --git a/spec/frontend/projects/commits/components/commit_list_app_spec.js b/spec/frontend/projects/commits/components/commit_list_app_spec.js index f4b5633271e7a2..ccca13512a0430 100644 --- a/spec/frontend/projects/commits/components/commit_list_app_spec.js +++ b/spec/frontend/projects/commits/components/commit_list_app_spec.js @@ -1,9 +1,6 @@ import { shallowMount } from '@vue/test-utils'; import CommitListApp from '~/projects/commits/components/commit_list_app.vue'; import CommitListHeader from '~/projects/commits/components/commit_list_header.vue'; -import CommitListItem from '~/projects/commits/components/commit_list_item.vue'; - -import { mockCommits } from './mock_data'; describe('Commit List App', () => { let wrapper; @@ -20,21 +17,10 @@ describe('Commit List App', () => { }); const findCommitHeader = () => wrapper.findComponent(CommitListHeader); - const findCommitListItems = () => wrapper.findAllComponents(CommitListItem); describe('commit header', () => { it('renders the commit header component', () => { expect(findCommitHeader().exists()).toBe(true); }); }); - - describe('commit list items', () => { - it('passes the correct commit data to each commit list item', () => { - const commitListItems = findCommitListItems(); - - mockCommits.forEach((commit, index) => { - expect(commitListItems.at(index).props('commit')).toEqual(commit); - }); - }); - }); }); diff --git a/spec/frontend/projects/commits/components/mock_data.js b/spec/frontend/projects/commits/components/mock_data.js deleted file mode 100644 index d9d87918da3b73..00000000000000 --- a/spec/frontend/projects/commits/components/mock_data.js +++ /dev/null @@ -1,44 +0,0 @@ -const mockCommit = { - data: { - project: { - __typename: 'Project', - id: 'gid://gitlab/Project/3', - repository: { - __typename: 'Repository', - lastCommit: { - __typename: 'Commit', - id: 'gid://gitlab/Commit/c6214205ec8f1bcafe3c91bda2e5fa1219df5866', - sha: 'c6214205ec8f1bcafe3c91bda2e5fa1219df5866', - title: "Revert \"Merge branch 'pb-ci-ruby-version-3-4-2' into 'main'\"", - titleHtml: "Revert \"Merge branch 'pb-ci-ruby-version-3-4-2' into 'main'\"", - descriptionHtml: '\u0026#x000A;This reverts merge request !1248', - message: - "Revert \"Merge branch 'pb-ci-ruby-version-3-4-2' into 'main'\"\n\nThis reverts merge request !1248", - webPath: '/gitlab-org/gitlab-shell/-/commit/c6214205ec8f1bcafe3c91bda2e5fa1219df5866', - authoredDate: '2025-03-07T04:32:27+00:00', - authorName: 'Patrick Bajao', - authorGravatar: - 'https://secure.gravatar.com/avatar/5d6ebe280312e168c9fef4762a5a890d74e8060b07217312c1bf1adb761119b9?s=80\u0026d=identicon', - author: null, - signature: { - __typename: 'SshSignature', - verificationStatus: 'UNKNOWN_KEY', - keyFingerprintSha256: '', - }, - pipelines: { - __typename: 'PipelineConnection', - edges: [], - }, - }, - }, - }, - }, -}; - -export const mockCommits = Array(20) - .fill() - .map((_, index) => ({ - ...mockCommit.data.project.repository.lastCommit, - id: `${mockCommit.data.project.repository.lastCommit.id}-${index}`, // Make IDs unique - sha: `${mockCommit.data.project.repository.lastCommit.sha.substring(0, 8)}${index}`, // Make SHAs unique - })); -- GitLab From 5cdfdc0c487826629dcde49d97fcb05464f2cdc8 Mon Sep 17 00:00:00 2001 From: Chaoyue Zhao Date: Tue, 17 Jun 2025 16:44:12 -0400 Subject: [PATCH 4/4] Address review comments - Fix haml indentation after rebasing - Refactor to stub FF off globally --- .../projects/commits/init_commit_list_app.js | 29 +- app/views/projects/commits/show.html.haml | 26 +- .../commits/user_view_commits_spec.rb | 81 ++-- spec/features/commits_spec.rb | 376 ++++++++-------- .../markdown/gitlab_flavored_markdown_spec.rb | 28 +- spec/features/projects/commits/rss_spec.rb | 30 +- .../commits/user_browses_commits_spec.rb | 410 +++++++++--------- .../projects/files/user_browses_files_spec.rb | 2 - .../projects/merge_request_button_spec.rb | 14 +- spec/spec_helper.rb | 5 + .../projects/commits/show.html.haml_spec.rb | 2 - 11 files changed, 482 insertions(+), 521 deletions(-) diff --git a/app/assets/javascripts/projects/commits/init_commit_list_app.js b/app/assets/javascripts/projects/commits/init_commit_list_app.js index 73ea2740550192..ff69f19d87fc2a 100644 --- a/app/assets/javascripts/projects/commits/init_commit_list_app.js +++ b/app/assets/javascripts/projects/commits/init_commit_list_app.js @@ -3,19 +3,20 @@ import CommitListApp from './components/commit_list_app.vue'; export default function initCommitListApp() { const commitListEl = document.getElementById('js-commit-list'); - if (commitListEl) { - const { projectPath, currentPath } = commitListEl.dataset; - // eslint-disable-next-line no-new - new Vue({ - el: commitListEl, - provide: { - projectPath, - currentPath, - }, - render(h) { - return h(CommitListApp, {}); - }, - }); - } + if (!commitListEl) return; + + const { projectPath, currentPath } = commitListEl.dataset; + + // eslint-disable-next-line no-new + new Vue({ + el: commitListEl, + provide: { + projectPath, + currentPath, + }, + render(h) { + return h(CommitListApp, {}); + }, + }); } diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml index ca1a03d2527c26..261bca63c81798 100644 --- a/app/views/projects/commits/show.html.haml +++ b/app/views/projects/commits/show.html.haml @@ -20,19 +20,19 @@ .tree-ref-holder.gl-max-w-26 #js-project-commits-ref-switcher{ data: { "project-id" => @project.id, "ref" => @ref, "commits_path": project_commits_path(@project), "ref_type": @ref_type.to_s, "tree_path": @path } } - %ul.breadcrumb.repo-breadcrumb - = commits_breadcrumbs - #js-author-dropdown{ data: { 'commits_path': project_commits_path(@project), 'project_id': @project.id } } - .tree-controls - .control - = link_button_to _('Browse files'), path_to_browse_file_or_directory(@project, @ref, @path) - - if @merge_request.present? - .control.gl-hidden.md:gl-block - = link_button_to _("View open merge request"), project_merge_request_path(@project, @merge_request) - - elsif create_mr_button?(from: @ref, source_project: @project) - .control.gl-hidden.md:gl-block - = render Pajamas::ButtonComponent.new(variant: :confirm, href: create_mr_path(from: @ref, source_project: @project)) do - = _("Create merge request") + %ul.breadcrumb.repo-breadcrumb + = commits_breadcrumbs + #js-author-dropdown{ data: { 'commits_path': project_commits_path(@project), 'project_id': @project.id } } + .tree-controls + .control + = link_button_to _('Browse files'), path_to_browse_file_or_directory(@project, @ref, @path) + - if @merge_request.present? + .control.gl-hidden.md:gl-block + = link_button_to _("View open merge request"), project_merge_request_path(@project, @merge_request) + - elsif create_mr_button?(from: @ref, source_project: @project) + .control.gl-hidden.md:gl-block + = render Pajamas::ButtonComponent.new(variant: :confirm, href: create_mr_path(from: @ref, source_project: @project)) do + = _("Create merge request") .control = form_tag(project_commits_path(@project, @id, ref_type: @ref_type), method: :get, class: 'commits-search-form js-signature-container', data: { 'signatures-path' => namespace_project_signatures_path(ref_type: @ref_type)}) do diff --git a/spec/features/commits/user_view_commits_spec.rb b/spec/features/commits/user_view_commits_spec.rb index 69ef41fe0bec5c..8257295deddbde 100644 --- a/spec/features/commits/user_view_commits_spec.rb +++ b/spec/features/commits/user_view_commits_spec.rb @@ -15,52 +15,46 @@ end describe 'Commits List' do - context 'when project_commits_refactor feature flag is disabled' do + context 'when project is public' do + let_it_be(:project) { create_default(:project, :public, :repository, group: group) } + before do - stub_feature_flags(project_commits_refactor: false) + visit project_commits_path(project) end - context 'when project is public' do - let_it_be(:project) { create_default(:project, :public, :repository, group: group) } + it_behaves_like 'can view commits' + end - before do - visit project_commits_path(project) - end + context 'when project is public with private repository' do + let_it_be(:project) { create_default(:project, :public, :repository, :repository_private, group: group) } - it_behaves_like 'can view commits' - end + context 'and user is an inherited member from the group' do + context 'and user is a guest' do + before do + group.add_guest(user) + sign_in(user) + visit project_commits_path(project) + end - context 'when project is public with private repository' do - let_it_be(:project) { create_default(:project, :public, :repository, :repository_private, group: group) } + it_behaves_like 'can view commits' + end + end + end - context 'and user is an inherited member from the group' do - context 'and user is a guest' do - before do - group.add_guest(user) - sign_in(user) - visit project_commits_path(project) - end + context 'when project is private' do + let_it_be(:project) { create_default(:project, :private, :repository, group: group) } - it_behaves_like 'can view commits' + context 'and user is an inherited member from the group' do + context 'and user is a guest' do + before do + group.add_guest(user) + sign_in(user) + visit project_commits_path(project) end - end - end - context 'when project is private' do - let_it_be(:project) { create_default(:project, :private, :repository, group: group) } - - context 'and user is an inherited member from the group' do - context 'and user is a guest' do - before do - group.add_guest(user) - sign_in(user) - visit project_commits_path(project) - end - - it 'renders not found' do - expect(page).to have_title('Not Found') - expect(page).to have_content('Page not found') - end + it 'renders not found' do + expect(page).to have_title('Not Found') + expect(page).to have_content('Page not found') end end end @@ -71,19 +65,14 @@ let_it_be(:project) { create_default(:project, :public, :repository, group: group) } let_it_be(:sha) { sample_commit.sha } - context 'when project_commits_refactor feature flag is disabled' do - before do - stub_feature_flags(project_commits_refactor: false) - end - - it 'passes axe automated accessibility testing' do - visit project_commit_path(project, sha) + it 'passes axe automated accessibility testing' do + visit project_commit_path(project, sha) wait_for_requests - expect(page).to be_axe_clean.within('#content-body').skipping :'color-contrast', :'link-in-text-block', - :'link-name', :'valid-lang' - end + expect(page).to be_axe_clean.within('#content-body').skipping :'color-contrast', :'link-in-text-block', + :'link-name', :'valid-lang' + end context 'when displayed with rapid_diffs' do let_it_be(:diffs) { project.commit(sha).diffs } diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 38891b56becbdb..6a6c497fa6d604 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -6,270 +6,264 @@ let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user) } - context 'when project_commits_refactor feature flag is disabled' do + describe 'CI' do before do - stub_feature_flags(project_commits_refactor: false) + sign_in(user) + stub_ci_pipeline_to_return_yaml_file end - describe 'CI' do - before do - sign_in(user) - stub_ci_pipeline_to_return_yaml_file - end + let(:creator) { create(:user, developer_of: project) } + let!(:pipeline) do + create( + :ci_pipeline, + project: project, + user: creator, + ref: project.default_branch, + sha: project.commit.sha, + status: :success, + created_at: 5.months.ago + ) + end - let(:creator) { create(:user, developer_of: project) } - let!(:pipeline) do - create( - :ci_pipeline, - project: project, - user: creator, - ref: project.default_branch, - sha: project.commit.sha, - status: :success, - created_at: 5.months.ago - ) - end + context 'commit status is Generic Commit Status' do + let(:stage) { create(:ci_stage, pipeline: pipeline, name: 'external') } + let!(:status) { create(:generic_commit_status, pipeline: pipeline, ref: pipeline.ref, ci_stage: stage) } - context 'commit status is Generic Commit Status' do - let(:stage) { create(:ci_stage, pipeline: pipeline, name: 'external') } - let!(:status) { create(:generic_commit_status, pipeline: pipeline, ref: pipeline.ref, ci_stage: stage) } + before do + project.add_reporter(user) + end + describe 'Commit builds', :js do before do - project.add_reporter(user) - end + visit builds_project_pipeline_path(project, pipeline) - describe 'Commit builds', :js do - before do - visit builds_project_pipeline_path(project, pipeline) - - wait_for_requests - end + wait_for_requests + end - it 'contains commit short id' do - within_testid('pipeline-header') do - expect(page).to have_content pipeline.sha[0..7] - end + it 'contains commit short id' do + within_testid('pipeline-header') do + expect(page).to have_content pipeline.sha[0..7] end + end - it 'contains generic commit status build' do - within_testid('jobs-tab-table') do - expect(page).to have_content "##{status.id}" # build id - expect(page).to have_content 'generic' # build name - end + it 'contains generic commit status build' do + within_testid('jobs-tab-table') do + expect(page).to have_content "##{status.id}" # build id + expect(page).to have_content 'generic' # build name end end end + end - context 'commit status is Ci Build' do - let!(:build) { create(:ci_build, pipeline: pipeline) } - let(:artifacts_file) { fixture_file_upload('spec/fixtures/banana_sample.gif', 'image/gif') } - - context 'when logged as developer' do - before do - project.add_developer(user) - end - - describe 'Project commits' do - let!(:pipeline_from_other_branch) do - create( - :ci_pipeline, - project: project, - ref: 'fix', - sha: project.commit.sha, - status: :failed - ) - end - - before do - visit project_commits_path(project, :master) - end - - it 'shows correct build status from default branch' do - page.within("//li[@id='commit-#{pipeline.short_sha}']") do - expect(page).to have_css("[data-testid='ci-icon']") - expect(page).to have_css('[data-testid="status_success_borderless-icon"]') - end - end - end + context 'commit status is Ci Build' do + let!(:build) { create(:ci_build, pipeline: pipeline) } + let(:artifacts_file) { fixture_file_upload('spec/fixtures/banana_sample.gif', 'image/gif') } - describe 'Commit builds', :js do - before do - project.add_developer(user) - visit pipeline_path(pipeline) - end + context 'when logged as developer' do + before do + project.add_developer(user) + end - it 'shows pipeline data' do - expect(page).to have_content pipeline.sha[0..7] - expect(page).to have_content pipeline.user.name - end + describe 'Project commits' do + let!(:pipeline_from_other_branch) do + create( + :ci_pipeline, + project: project, + ref: 'fix', + sha: project.commit.sha, + status: :failed + ) end - context 'Download artifacts', :js do - before do - create(:ci_job_artifact, :archive, file: artifacts_file, job: build) - end - - it do - visit builds_project_pipeline_path(project, pipeline) - wait_for_requests - expect(page).to have_link('Download artifacts', href: download_project_job_artifacts_path(project, build, file_type: :archive)) - end + before do + visit project_commits_path(project, :master) end - describe 'Cancel jobs' do - let!(:pipeline) do - create( - :ci_pipeline, - project: project, - user: creator, - ref: project.default_branch, - sha: project.commit.sha, - status: :running, - created_at: 5.months.ago - ) - end - - before do - visit pipeline_path(pipeline) - wait_for_requests - click_on 'Cancel pipeline' - wait_for_requests - end - - it 'cancels pipeline and jobs', :js, :sidekiq_might_not_need_inline do - expect(page).to have_content 'Canceled' + it 'shows correct build status from default branch' do + page.within("//li[@id='commit-#{pipeline.short_sha}']") do + expect(page).to have_css("[data-testid='ci-icon']") + expect(page).to have_css('[data-testid="status_success_borderless-icon"]') end end end - context "when logged as reporter", :js do + describe 'Commit builds', :js do before do - project.add_reporter(user) - create(:ci_job_artifact, :archive, file: artifacts_file, job: build) - visit builds_project_pipeline_path(project, pipeline) - wait_for_requests + project.add_developer(user) + visit pipeline_path(pipeline) end - it 'renders header' do + it 'shows pipeline data' do expect(page).to have_content pipeline.sha[0..7] expect(page).to have_content pipeline.user.name - expect(page).not_to have_link('Cancel pipeline') - expect(page).not_to have_link('Retry') + end + end + + context 'Download artifacts', :js do + before do + create(:ci_job_artifact, :archive, file: artifacts_file, job: build) end it do - expect(page).to have_link('Download artifacts') + visit builds_project_pipeline_path(project, pipeline) + wait_for_requests + expect(page).to have_link('Download artifacts', href: download_project_job_artifacts_path(project, build, file_type: :archive)) end end - context 'when accessing internal project with disallowed access', :js do + describe 'Cancel jobs' do + let!(:pipeline) do + create( + :ci_pipeline, + project: project, + user: creator, + ref: project.default_branch, + sha: project.commit.sha, + status: :running, + created_at: 5.months.ago + ) + end + before do - project.add_reporter(user) - project.update!( - visibility_level: Gitlab::VisibilityLevel::INTERNAL, - public_builds: false) - create(:ci_job_artifact, :archive, file: artifacts_file, job: build) visit pipeline_path(pipeline) + wait_for_requests + click_on 'Cancel pipeline' + wait_for_requests end - it do - expect(page).to have_content pipeline.sha[0..7] - expect(page).to have_content pipeline.user.name - - expect(page).not_to have_link('Cancel pipeline') - expect(page).not_to have_link('Retry') + it 'cancels pipeline and jobs', :js, :sidekiq_might_not_need_inline do + expect(page).to have_content 'Canceled' end end end - end - - context 'viewing commits for a branch' do - let(:branch_name) { 'master' } - let(:ref_selector) { '.ref-selector' } - let(:ref_with_hash) { 'ref-#-hash' } - def switch_ref_to(ref_name) - first(ref_selector).click - wait_for_requests - - page.within ref_selector do - fill_in 'Search by Git revision', with: ref_name + context "when logged as reporter", :js do + before do + project.add_reporter(user) + create(:ci_job_artifact, :archive, file: artifacts_file, job: build) + visit builds_project_pipeline_path(project, pipeline) wait_for_requests - find('li', text: ref_name, match: :prefer_exact).click end - end - before do - project.add_maintainer(user) - sign_in(user) - project.repository.create_branch(ref_with_hash, branch_name) - visit project_commits_path(project, branch_name) - end + it 'renders header' do + expect(page).to have_content pipeline.sha[0..7] + expect(page).to have_content pipeline.user.name + expect(page).not_to have_link('Cancel pipeline') + expect(page).not_to have_link('Retry') + end - it 'includes a date on which the commits were authored' do - commits = project.repository.commits(branch_name, limit: 40) - commits.chunk { |c| c.committed_date.in_time_zone.to_date }.each do |day, _daily_commits| - expect(page).to have_content(day.strftime("%b %d, %Y")) + it do + expect(page).to have_link('Download artifacts') end end - it 'includes the committed_date for each commit' do - commits = project.repository.commits(branch_name, limit: 40) + context 'when accessing internal project with disallowed access', :js do + before do + project.add_reporter(user) + project.update!( + visibility_level: Gitlab::VisibilityLevel::INTERNAL, + public_builds: false) + create(:ci_job_artifact, :archive, file: artifacts_file, job: build) + visit pipeline_path(pipeline) + end - commits.each do |commit| - expect(page).to have_content("authored #{commit.authored_date.strftime('%b %d, %Y')}") + it do + expect(page).to have_content pipeline.sha[0..7] + expect(page).to have_content pipeline.user.name + + expect(page).not_to have_link('Cancel pipeline') + expect(page).not_to have_link('Retry') end end + end + end + + context 'viewing commits for a branch' do + let(:branch_name) { 'master' } + let(:ref_selector) { '.ref-selector' } + let(:ref_with_hash) { 'ref-#-hash' } - it 'switches ref to ref containing a hash', :js do - switch_ref_to(ref_with_hash) + def switch_ref_to(ref_name) + first(ref_selector).click + wait_for_requests - expect(page).to have_selector ref_selector, text: ref_with_hash + page.within ref_selector do + fill_in 'Search by Git revision', with: ref_name + wait_for_requests + find('li', text: ref_name, match: :prefer_exact).click end + end - it 'shows the ref switcher with the multi-file editor enabled', :js do - set_cookie('new_repo', 'true') - visit project_commits_path(project, branch_name) + before do + project.add_maintainer(user) + sign_in(user) + project.repository.create_branch(ref_with_hash, branch_name) + visit project_commits_path(project, branch_name) + end - expect(find(ref_selector)).to have_content branch_name + it 'includes a date on which the commits were authored' do + commits = project.repository.commits(branch_name, limit: 40) + commits.chunk { |c| c.committed_date.in_time_zone.to_date }.each do |day, _daily_commits| + expect(page).to have_content(day.strftime("%b %d, %Y")) end end - context 'viewing commits for an author' do - let(:author_commit) { project.repository.commits(nil, limit: 1).first } - let(:commits) { project.repository.commits(nil, author: author, limit: 40) } + it 'includes the committed_date for each commit' do + commits = project.repository.commits(branch_name, limit: 40) - before do - project.add_maintainer(user) - sign_in(user) - visit project_commits_path(project, nil, author: author) + commits.each do |commit| + expect(page).to have_content("authored #{commit.authored_date.strftime('%b %d, %Y')}") end + end - shared_examples 'show commits by author' do - it "includes the author's commits" do - commits.each do |commit| - expect(page).to have_content("#{author_commit.author_name} authored #{commit.authored_date.strftime('%b %d, %Y')}") - end + it 'switches ref to ref containing a hash', :js do + switch_ref_to(ref_with_hash) + + expect(page).to have_selector ref_selector, text: ref_with_hash + end + + it 'shows the ref switcher with the multi-file editor enabled', :js do + set_cookie('new_repo', 'true') + visit project_commits_path(project, branch_name) + + expect(find(ref_selector)).to have_content branch_name + end + end + + context 'viewing commits for an author' do + let(:author_commit) { project.repository.commits(nil, limit: 1).first } + let(:commits) { project.repository.commits(nil, author: author, limit: 40) } + + before do + project.add_maintainer(user) + sign_in(user) + visit project_commits_path(project, nil, author: author) + end + + shared_examples 'show commits by author' do + it "includes the author's commits" do + commits.each do |commit| + expect(page).to have_content("#{author_commit.author_name} authored #{commit.authored_date.strftime('%b %d, %Y')}") end end + end - context 'author is complete' do - let(:author) { "#{author_commit.author_name} <#{author_commit.author_email}>" } + context 'author is complete' do + let(:author) { "#{author_commit.author_name} <#{author_commit.author_email}>" } - it_behaves_like 'show commits by author' - end + it_behaves_like 'show commits by author' + end - context 'author is just a name' do - let(:author) { author_commit.author_name.to_s } + context 'author is just a name' do + let(:author) { author_commit.author_name.to_s } - it_behaves_like 'show commits by author' - end + it_behaves_like 'show commits by author' + end - context 'author is just an email' do - let(:author) { author_commit.author_email.to_s } + context 'author is just an email' do + let(:author) { author_commit.author_email.to_s } - it_behaves_like 'show commits by author' - end + it_behaves_like 'show commits by author' end end end diff --git a/spec/features/markdown/gitlab_flavored_markdown_spec.rb b/spec/features/markdown/gitlab_flavored_markdown_spec.rb index 09fa6fee076259..20eef55d2545cc 100644 --- a/spec/features/markdown/gitlab_flavored_markdown_spec.rb +++ b/spec/features/markdown/gitlab_flavored_markdown_spec.rb @@ -34,28 +34,22 @@ ) end - context 'when project_commits_refactor feature flag is disabled' do - before do - stub_feature_flags(project_commits_refactor: false) - end + it "renders title in commits#index" do + visit project_commits_path(project, 'master', limit: 1) - it "renders title in commits#index" do - visit project_commits_path(project, 'master', limit: 1) - - expect(page).to have_link(issue.to_reference) - end + expect(page).to have_link(issue.to_reference) + end - it "renders title in commits#show" do - visit project_commit_path(project, commit) + it "renders title in commits#show" do + visit project_commit_path(project, commit) - expect(page).to have_link(issue.to_reference) - end + expect(page).to have_link(issue.to_reference) + end - it "renders description in commits#show" do - visit project_commit_path(project, commit) + it "renders description in commits#show" do + visit project_commit_path(project, commit) - expect(page).to have_link(fred.to_reference) - end + expect(page).to have_link(fred.to_reference) end it "renders title in repositories#branches" do diff --git a/spec/features/projects/commits/rss_spec.rb b/spec/features/projects/commits/rss_spec.rb index de23339cc62f54..49da0727fbd9e1 100644 --- a/spec/features/projects/commits/rss_spec.rb +++ b/spec/features/projects/commits/rss_spec.rb @@ -7,29 +7,23 @@ let(:project) { create(:project, :repository, visibility_level: Gitlab::VisibilityLevel::PUBLIC) } let(:path) { project_commits_path(project, :master) } - context 'when project_commits_refactor feature flag is disabled' do + context 'when signed in' do before do - stub_feature_flags(project_commits_refactor: false) + project.add_developer(user) + sign_in(user) + visit path end - context 'when signed in' do - before do - project.add_developer(user) - sign_in(user) - visit path - end + it_behaves_like "it has an RSS button with current_user's feed token" + it_behaves_like "an autodiscoverable RSS feed with current_user's feed token" + end - it_behaves_like "it has an RSS button with current_user's feed token" - it_behaves_like "an autodiscoverable RSS feed with current_user's feed token" + context 'when signed out' do + before do + visit path end - context 'when signed out' do - before do - visit path - end - - it_behaves_like "it has an RSS button without a feed token" - it_behaves_like "an autodiscoverable RSS feed without a feed token" - end + it_behaves_like "it has an RSS button without a feed token" + it_behaves_like "an autodiscoverable RSS feed without a feed token" end end diff --git a/spec/features/projects/commits/user_browses_commits_spec.rb b/spec/features/projects/commits/user_browses_commits_spec.rb index efea326b106ffb..84feb1a43d64cb 100644 --- a/spec/features/projects/commits/user_browses_commits_spec.rb +++ b/spec/features/projects/commits/user_browses_commits_spec.rb @@ -12,214 +12,256 @@ sign_in(user) end - context 'when project_commits_refactor feature flag is disabled' do - before do - stub_feature_flags(project_commits_refactor: false) - end + it 'renders commit', :js do + visit project_commit_path(project, sample_commit.id) - it 'renders commit', :js do - visit project_commit_path(project, sample_commit.id) + expect(page).to have_content(sample_commit.message.gsub(/\s+/, ' ')) + .and have_content("Showing #{sample_commit.files_changed_count} changed files") + .and have_content('Side-by-side') + end - expect(page).to have_content(sample_commit.message.gsub(/\s+/, ' ')) - .and have_content("Showing #{sample_commit.files_changed_count} changed files") - .and have_content('Side-by-side') + it 'fill commit sha when click new tag from commit page', :js do + dropdown_selector = '[data-testid="commit-options-dropdown"]' + visit project_commit_path(project, sample_commit.id) + find(dropdown_selector).click + + page.within(dropdown_selector) do + click_link 'Tag' end - it 'fill commit sha when click new tag from commit page', :js do - dropdown_selector = '[data-testid="commit-options-dropdown"]' - visit project_commit_path(project, sample_commit.id) - find(dropdown_selector).click + expect(page).to have_selector("input[value='#{sample_commit.id}']", visible: false) + end - page.within(dropdown_selector) do - click_link 'Tag' - end + it 'renders inline diff button when click side-by-side diff button' do + visit project_commit_path(project, sample_commit.id) + find('#parallel-diff-btn').click + + expect(page).to have_content 'Inline' + end + + it 'renders breadcrumbs on specific commit path' do + visit project_commits_path(project, project.repository.root_ref + '/files/ruby/regex.rb', limit: 5) + + expect(page).to have_selector('#content-body ul.breadcrumb') + .and have_selector('#content-body ul.breadcrumb a', count: 4) + end + + it 'renders diff links to both the previous and current image', :js do + visit project_commit_path(project, sample_image_commit.id) - expect(page).to have_selector("input[value='#{sample_commit.id}']", visible: false) + links = page.all('.file-actions a') + expect(links[0]['href']).to match %r{blob/#{sample_image_commit.old_blob_id}} + expect(links[1]['href']).to match %r{blob/#{sample_image_commit.new_blob_id}} + end + + context 'when commit has ci status' do + let(:pipeline) { create(:ci_pipeline, project: project, sha: sample_commit.id) } + + before do + project.enable_ci + + create(:ci_build, pipeline: pipeline) end - it 'renders inline diff button when click side-by-side diff button' do + it 'renders commit ci info' do visit project_commit_path(project, sample_commit.id) - find('#parallel-diff-btn').click + wait_for_requests - expect(page).to have_content 'Inline' + expect(page).to have_selector('.js-commit-box-pipeline-summary') end + end + + context 'primary email' do + it 'finds a commit by a primary email' do + user = create(:user, email: 'dmitriy.zaporozhets@gmail.com') - it 'renders breadcrumbs on specific commit path' do - visit project_commits_path(project, project.repository.root_ref + '/files/ruby/regex.rb', limit: 5) + visit(project_commit_path(project, sample_commit.id)) - expect(page).to have_selector('#content-body ul.breadcrumb') - .and have_selector('#content-body ul.breadcrumb a', count: 4) + check_author_link(sample_commit.author_email, user) end + end + + context 'secondary email' do + let(:user) { create(:user) } - it 'renders diff links to both the previous and current image', :js do - visit project_commit_path(project, sample_image_commit.id) + it 'finds a commit by a secondary email' do + create(:email, :confirmed, user: user, email: 'dmitriy.zaporozhets@gmail.com') - links = page.all('.file-actions a') - expect(links[0]['href']).to match %r{blob/#{sample_image_commit.old_blob_id}} - expect(links[1]['href']).to match %r{blob/#{sample_image_commit.new_blob_id}} + visit(project_commit_path(project, sample_commit.parent_id)) + + check_author_link(sample_commit.author_email, user) end - context 'when commit has ci status' do - let(:pipeline) { create(:ci_pipeline, project: project, sha: sample_commit.id) } + it 'links to an unverified e-mail address instead of the user' do + create(:email, user: user, email: 'dmitriy.zaporozhets@gmail.com') - before do - project.enable_ci + visit(project_commit_path(project, sample_commit.parent_id)) - create(:ci_build, pipeline: pipeline) - end + check_author_email(sample_commit.author_email) + end + end - it 'renders commit ci info' do - visit project_commit_path(project, sample_commit.id) - wait_for_requests + context 'when the blob does not exist' do + let(:commit) { create(:commit, project: project) } - expect(page).to have_selector('.js-commit-box-pipeline-summary') + it 'renders successfully', :js do + allow_next_instance_of(Gitlab::Diff::File) do |instance| + allow(instance).to receive(:blob).and_return(nil) + end + allow_next_instance_of(Gitlab::Diff::File) do |instance| + allow(instance).to receive(:binary?).and_return(true) end - end - context 'primary email' do - it 'finds a commit by a primary email' do - user = create(:user, email: 'dmitriy.zaporozhets@gmail.com') + visit(project_commit_path(project, commit)) - visit(project_commit_path(project, sample_commit.id)) + click_button '2 changed files' - check_author_link(sample_commit.author_email, user) - end + expect(find_by_testid('diff-stats-dropdown')).to have_content('files/ruby/popen.rb') + end + end + + describe 'commits list' do + let(:visit_commits_page) do + visit project_commits_path(project, project.repository.root_ref, limit: 5) end - context 'secondary email' do - let(:user) { create(:user) } + it 'searches commit', :js do + visit_commits_page + fill_in 'commits-search', with: 'submodules' - it 'finds a commit by a secondary email' do - create(:email, :confirmed, user: user, email: 'dmitriy.zaporozhets@gmail.com') + expect(page).to have_content 'More submodules' + expect(page).not_to have_content 'Change some files' + end - visit(project_commit_path(project, sample_commit.parent_id)) + it 'renders commits atom feed' do + visit_commits_page + click_link('Commits feed') - check_author_link(sample_commit.author_email, user) - end + commit = project.repository.commit - it 'links to an unverified e-mail address instead of the user' do - create(:email, user: user, email: 'dmitriy.zaporozhets@gmail.com') + expect(response_headers['Content-Type']).to have_content("application/atom+xml") + expect(body).to have_selector('title', text: "#{project.name}:master commits") + .and have_selector('author email', text: commit.author_email) + .and have_selector('entry summary', text: commit.description[0..10].delete("\r\n")) + end - visit(project_commit_path(project, sample_commit.parent_id)) + context "when commit has a filename with pathspec characters" do + let(:path) { ':wq' } + let(:filename) { File.join(path, 'test.txt') } + let(:ref) { project.repository.root_ref } + let(:newrev) { project.repository.commit('master').sha } + let(:short_newrev) { project.repository.commit('master').short_id } + let(:message) { 'Glob characters' } - check_author_email(sample_commit.author_email) + before do + create_file_in_repo(project, ref, ref, filename, 'Test file', commit_message: message) + visit project_commits_path(project, "#{ref}/#{path}", limit: 1) + wait_for_requests end - end - context 'when the blob does not exist' do - let(:commit) { create(:commit, project: project) } + it 'searches commit', :js do + expect(page).to have_content(message) - it 'renders successfully', :js do - allow_next_instance_of(Gitlab::Diff::File) do |instance| - allow(instance).to receive(:blob).and_return(nil) - end - allow_next_instance_of(Gitlab::Diff::File) do |instance| - allow(instance).to receive(:binary?).and_return(true) - end + fill_in 'commits-search', with: 'bogus12345' - visit(project_commit_path(project, commit)) + expect(page).to have_content "No results found" - click_button '2 changed files' + fill_in 'commits-search', with: 'Glob' - expect(find_by_testid('diff-stats-dropdown')).to have_content('files/ruby/popen.rb') + expect(page).to have_content message end end - describe 'commits list' do - let(:visit_commits_page) do - visit project_commits_path(project, project.repository.root_ref, limit: 5) + context 'when a commit links to a confidential issue' do + let(:confidential_issue) { create(:issue, confidential: true, title: 'Secret issue!', project: project) } + + before do + project.repository.create_file( + user, + 'dummy-file', + 'dummy content', + branch_name: 'feature', + message: "Linking #{confidential_issue.to_reference}" + ) end - it 'searches commit', :js do - visit_commits_page - fill_in 'commits-search', with: 'submodules' + context 'when the user cannot see confidential issues but was cached with a link', :use_clean_rails_memory_store_fragment_caching do + it 'does not render the confidential issue' do + visit project_commits_path(project, 'feature') + sign_in(create(:user)) + visit project_commits_path(project, 'feature') - expect(page).to have_content 'More submodules' - expect(page).not_to have_content 'Change some files' + expect(page).not_to have_link(href: project_issue_path(project, confidential_issue)) + end end + end - it 'renders commits atom feed' do + context 'master branch', :js do + before do visit_commits_page - click_link('Commits feed') + end + it 'renders project commits' do commit = project.repository.commit - expect(response_headers['Content-Type']).to have_content("application/atom+xml") - expect(body).to have_selector('title', text: "#{project.name}:master commits") - .and have_selector('author email', text: commit.author_email) - .and have_selector('entry summary', text: commit.description[0..10].delete("\r\n")) + expect(page).to have_content(project.name) + .and have_content(commit.message[0..20]) + .and have_content(commit.short_id) end - context "when commit has a filename with pathspec characters" do - let(:path) { ':wq' } - let(:filename) { File.join(path, 'test.txt') } - let(:ref) { project.repository.root_ref } - let(:newrev) { project.repository.commit('master').sha } - let(:short_newrev) { project.repository.commit('master').short_id } - let(:message) { 'Glob characters' } + it 'does not render create merge request button' do + expect(page).not_to have_link 'Create merge request' + end + + it 'shows ref switcher with correct text', :js do + expect(find('.ref-selector')).to have_text('master') + end + context 'when click the compare tab' do before do - create_file_in_repo(project, ref, ref, filename, 'Test file', commit_message: message) - visit project_commits_path(project, "#{ref}/#{path}", limit: 1) wait_for_requests + click_link('Compare') end - it 'searches commit', :js do - expect(page).to have_content(message) - - fill_in 'commits-search', with: 'bogus12345' - - expect(page).to have_content "No results found" - - fill_in 'commits-search', with: 'Glob' - - expect(page).to have_content message + it 'does not render create merge request button', :js do + expect(page).not_to have_link 'Create merge request' end end + end - context 'when a commit links to a confidential issue' do - let(:confidential_issue) { create(:issue, confidential: true, title: 'Secret issue!', project: project) } - - before do - project.repository.create_file( - user, - 'dummy-file', - 'dummy content', - branch_name: 'feature', - message: "Linking #{confidential_issue.to_reference}" - ) - end + context 'feature branch', :js do + let(:visit_commits_page) do + visit project_commits_path(project) - context 'when the user cannot see confidential issues but was cached with a link', :use_clean_rails_memory_store_fragment_caching do - it 'does not render the confidential issue' do - visit project_commits_path(project, 'feature') - sign_in(create(:user)) - visit project_commits_path(project, 'feature') + find('.ref-selector').click + wait_for_requests - expect(page).not_to have_link(href: project_issue_path(project, confidential_issue)) - end + page.within('.ref-selector') do + fill_in 'Search by Git revision', with: 'feature' + wait_for_requests + find('li', text: 'feature', match: :prefer_exact).click end end - context 'master branch', :js do + context 'when project does not have open merge requests' do before do visit_commits_page end + it 'shows ref switcher with correct text' do + expect(find('.ref-selector')).to have_text('feature') + end + it 'renders project commits' do - commit = project.repository.commit + commit = project.repository.commit('0b4bc9a') expect(page).to have_content(project.name) - .and have_content(commit.message[0..20]) - .and have_content(commit.short_id) + .and have_content(commit.message[0..12]) + .and have_content(commit.short_id) end - it 'does not render create merge request button' do - expect(page).not_to have_link 'Create merge request' - end - - it 'shows ref switcher with correct text', :js do - expect(find('.ref-selector')).to have_text('master') + it 'renders create merge request button' do + expect(page).to have_link 'Create merge request' end context 'when click the compare tab' do @@ -228,99 +270,51 @@ click_link('Compare') end - it 'does not render create merge request button', :js do - expect(page).not_to have_link 'Create merge request' + it 'renders create merge request button', :js do + expect(page).to have_link 'Create merge request' end end end - context 'feature branch', :js do - let(:visit_commits_page) do - visit project_commits_path(project) - - find('.ref-selector').click - wait_for_requests - - page.within('.ref-selector') do - fill_in 'Search by Git revision', with: 'feature' - wait_for_requests - find('li', text: 'feature', match: :prefer_exact).click - end + context 'when project have open merge request' do + let!(:merge_request) do + create( + :merge_request, + title: 'Feature', + source_project: project, + source_branch: 'feature', + target_branch: 'master', + author: project.users.first + ) end - context 'when project does not have open merge requests' do - before do - visit_commits_page - end - - it 'shows ref switcher with correct text' do - expect(find('.ref-selector')).to have_text('feature') - end - - it 'renders project commits' do - commit = project.repository.commit('0b4bc9a') - - expect(page).to have_content(project.name) - .and have_content(commit.message[0..12]) - .and have_content(commit.short_id) - end - - it 'renders create merge request button' do - expect(page).to have_link 'Create merge request' - end + before do + visit_commits_page + end - context 'when click the compare tab' do - before do - wait_for_requests - click_link('Compare') - end + it 'renders project commits' do + commit = project.repository.commit('0b4bc9a') - it 'renders create merge request button', :js do - expect(page).to have_link 'Create merge request' - end - end + expect(page).to have_content(project.name) + .and have_content(commit.message[0..12]) + .and have_content(commit.short_id) end - context 'when project have open merge request' do - let!(:merge_request) do - create( - :merge_request, - title: 'Feature', - source_project: project, - source_branch: 'feature', - target_branch: 'master', - author: project.users.first - ) - end + it 'renders button to the merge request' 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 + context 'when click the compare tab' do before do - visit_commits_page - end - - it 'renders project commits' do - commit = project.repository.commit('0b4bc9a') - - expect(page).to have_content(project.name) - .and have_content(commit.message[0..12]) - .and have_content(commit.short_id) + 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 - - context 'when click the compare tab' do - before do - wait_for_requests - click_link('Compare') - end - - 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 - end end end end diff --git a/spec/features/projects/files/user_browses_files_spec.rb b/spec/features/projects/files/user_browses_files_spec.rb index d52dfaebc2079f..86cd9842a41deb 100644 --- a/spec/features/projects/files/user_browses_files_spec.rb +++ b/spec/features/projects/files/user_browses_files_spec.rb @@ -16,8 +16,6 @@ let(:user) { project.first_owner } before do - # TODO - remove this stub once commit list refactor is complete - stub_feature_flags(project_commits_refactor: false) sign_in(user) end diff --git a/spec/features/projects/merge_request_button_spec.rb b/spec/features/projects/merge_request_button_spec.rb index 8bc67a0441e3f9..6d6d850342ad7b 100644 --- a/spec/features/projects/merge_request_button_spec.rb +++ b/spec/features/projects/merge_request_button_spec.rb @@ -149,16 +149,10 @@ end context 'on commits page' do - context 'when project_commits_refactor feature flag is disabled' do - before do - stub_feature_flags(project_commits_refactor: false) - end - - it_behaves_like 'Merge request button only shown when allowed' do - let(:label) { 'Create merge request' } - let(:url) { project_commits_path(project, 'feature') } - let(:fork_url) { project_commits_path(forked_project, 'feature') } - end + it_behaves_like 'Merge request button only shown when allowed' do + let(:label) { 'Create merge request' } + let(:url) { project_commits_path(project, 'feature') } + let(:fork_url) { project_commits_path(forked_project, 'feature') } end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 1ae63a7abd3723..073b86f878724b 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -341,6 +341,10 @@ # Please see https://gitlab.com/groups/gitlab-org/-/epics/17781 for tracking the progress. stub_feature_flags(repository_file_tree_browser: false) + # Since we are very early in development of this feature, it might cause unexpected behaviors when the flag is enabled + # Please see https://gitlab.com/groups/gitlab-org/-/epics/17482 for tracking the progress. + stub_feature_flags(project_commits_refactor: false) + # New issue page can cause tests to fail if they link to issue or issue list page # Default false while we make it compatible stub_feature_flags(work_item_view_for_issues: false) @@ -351,6 +355,7 @@ # New personal homepage is still a WIP and not functional. stub_feature_flags(personal_homepage: false) + else unstub_all_feature_flags end diff --git a/spec/views/projects/commits/show.html.haml_spec.rb b/spec/views/projects/commits/show.html.haml_spec.rb index f0765710bad0fa..96806aada13152 100644 --- a/spec/views/projects/commits/show.html.haml_spec.rb +++ b/spec/views/projects/commits/show.html.haml_spec.rb @@ -11,8 +11,6 @@ let(:ref) { "master" } before do - stub_feature_flags(project_commits_refactor: false) - assign(:project, project) assign(:path, path) assign(:id, path) -- GitLab