diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-20 18:40:28 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-20 18:40:28 +0300 |
commit | b595cb0c1dec83de5bdee18284abe86614bed33b (patch) | |
tree | 8c3d4540f193c5ff98019352f554e921b3a41a72 /spec/features/projects | |
parent | 2f9104a328fc8a4bddeaa4627b595166d24671d0 (diff) |
Add latest changes from gitlab-org/gitlab@15-2-stable-eev15.2.0-rc42
Diffstat (limited to 'spec/features/projects')
30 files changed, 1152 insertions, 1147 deletions
diff --git a/spec/features/projects/blobs/blame_spec.rb b/spec/features/projects/blobs/blame_spec.rb index bb3b5cd931c..3b2b74b469e 100644 --- a/spec/features/projects/blobs/blame_spec.rb +++ b/spec/features/projects/blobs/blame_spec.rb @@ -49,6 +49,12 @@ RSpec.describe 'File blame', :js do expect(page).to have_css('#L3') expect(find('.page-link.active')).to have_text('2') end + + it 'correctly redirects to the prior blame page' do + find('.version-link').click + + expect(find('.page-link.active')).to have_text('2') + end end context 'when feature flag disabled' do @@ -64,4 +70,37 @@ RSpec.describe 'File blame', :js do end end end + + context 'when blob length is over global max page limit' do + before do + stub_const('Projects::BlameService::PER_PAGE', 200) + end + + let(:path) { 'files/markdown/ruby-style-guide.md' } + + it 'displays two hundred lines of the file with pagination' do + visit_blob_blame(path) + + expect(page).to have_css('.blame-commit') + expect(page).to have_css('.gl-pagination') + + expect(page).to have_css('#L1') + expect(page).not_to have_css('#L201') + expect(find('.page-link.active')).to have_text('1') + end + + context 'when user clicks on the next button' do + before do + visit_blob_blame(path) + + find('.js-next-button').click + end + + it 'displays next two hundred lines of the file with pagination' do + expect(page).not_to have_css('#L1') + expect(page).to have_css('#L201') + expect(find('.page-link.active')).to have_text('2') + end + end + end end diff --git a/spec/features/projects/blobs/blob_show_spec.rb b/spec/features/projects/blobs/blob_show_spec.rb index 76baad63cc2..f5cafa2b2ec 100644 --- a/spec/features/projects/blobs/blob_show_spec.rb +++ b/spec/features/projects/blobs/blob_show_spec.rb @@ -29,176 +29,162 @@ RSpec.describe 'File blob', :js do ).execute end - context 'with refactor_blob_viewer feature flag enabled' do - context 'Ruby file' do + context 'Ruby file' do + before do + visit_blob('files/ruby/popen.rb') + + wait_for_requests + end + + it 'displays the blob' do + aggregate_failures do + # shows highlighted Ruby code + expect(page).to have_css(".js-syntax-highlight") + expect(page).to have_content("require 'fileutils'") + + # does not show a viewer switcher + expect(page).not_to have_selector('.js-blob-viewer-switcher') + + # shows an enabled copy button + expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)') + + # shows a raw button + expect(page).to have_link('Open raw') + end + end + + it 'displays file actions on all screen sizes' do + file_actions_selector = '.file-actions' + + resize_screen_sm + expect(page).to have_selector(file_actions_selector, visible: true) + + resize_screen_xs + expect(page).to have_selector(file_actions_selector, visible: true) + end + end + + context 'Markdown file' do + context 'visiting directly' do before do - visit_blob('files/ruby/popen.rb') + visit_blob('files/markdown/ruby-style-guide.md') wait_for_requests end - it 'displays the blob' do + it 'displays the blob using the rich viewer' do aggregate_failures do - # shows highlighted Ruby code - expect(page).to have_css(".js-syntax-highlight") - expect(page).to have_content("require 'fileutils'") + # hides the simple viewer + expect(page).not_to have_selector('.blob-viewer[data-type="simple"]') + expect(page).to have_selector('.blob-viewer[data-type="rich"]') - # does not show a viewer switcher - expect(page).not_to have_selector('.js-blob-viewer-switcher') + # shows rendered Markdown + expect(page).to have_link("PEP-8") - # shows an enabled copy button - expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)') + # shows a viewer switcher + expect(page).to have_selector('.js-blob-viewer-switcher') + + # shows a disabled copy button + expect(page).to have_selector('.js-copy-blob-source-btn.disabled') # shows a raw button expect(page).to have_link('Open raw') end end - it 'displays file actions on all screen sizes' do - file_actions_selector = '.file-actions' - - resize_screen_sm - expect(page).to have_selector(file_actions_selector, visible: true) - - resize_screen_xs - expect(page).to have_selector(file_actions_selector, visible: true) - end - end - - context 'Markdown file' do - context 'visiting directly' do + context 'switching to the simple viewer' do before do - visit_blob('files/markdown/ruby-style-guide.md') + find('.js-blob-viewer-switch-btn[data-viewer=simple]').click wait_for_requests end - it 'displays the blob using the rich viewer' do + it 'displays the blob using the simple viewer' do aggregate_failures do - # hides the simple viewer - expect(page).not_to have_selector('.blob-viewer[data-type="simple"]') - expect(page).to have_selector('.blob-viewer[data-type="rich"]') - - # shows rendered Markdown - expect(page).to have_link("PEP-8") - - # shows a viewer switcher - expect(page).to have_selector('.js-blob-viewer-switcher') + # hides the rich viewer + expect(page).to have_selector('.blob-viewer[data-type="simple"]') + expect(page).not_to have_selector('.blob-viewer[data-type="rich"]') - # shows a disabled copy button - expect(page).to have_selector('.js-copy-blob-source-btn.disabled') + # shows highlighted Markdown code + expect(page).to have_css(".js-syntax-highlight") + expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)") - # shows a raw button - expect(page).to have_link('Open raw') + # shows an enabled copy button + expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)') end end - context 'switching to the simple viewer' do + context 'switching to the rich viewer again' do before do - find('.js-blob-viewer-switch-btn[data-viewer=simple]').click + find('.js-blob-viewer-switch-btn[data-viewer=rich]').click wait_for_requests end - it 'displays the blob using the simple viewer' do + it 'displays the blob using the rich viewer' do aggregate_failures do - # hides the rich viewer - expect(page).to have_selector('.blob-viewer[data-type="simple"]') - expect(page).not_to have_selector('.blob-viewer[data-type="rich"]') + # hides the simple viewer + expect(page).not_to have_selector('.blob-viewer[data-type="simple"]') + expect(page).to have_selector('.blob-viewer[data-type="rich"]') - # shows highlighted Markdown code - expect(page).to have_css(".js-syntax-highlight") - expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)") - - # shows an enabled copy button - expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)') - end - end - - context 'switching to the rich viewer again' do - before do - find('.js-blob-viewer-switch-btn[data-viewer=rich]').click - - wait_for_requests - end - - it 'displays the blob using the rich viewer' do - aggregate_failures do - # hides the simple viewer - expect(page).not_to have_selector('.blob-viewer[data-type="simple"]') - expect(page).to have_selector('.blob-viewer[data-type="rich"]') - - # shows a disabled copy button - expect(page).to have_selector('.js-copy-blob-source-btn.disabled') - end + # shows a disabled copy button + expect(page).to have_selector('.js-copy-blob-source-btn.disabled') end end end end + end - context 'when ref switch' do - def switch_ref_to(ref_name) - first('.qa-branches-select').click # rubocop:disable QA/SelectorUsage + context 'when ref switch' do + def switch_ref_to(ref_name) + first('.qa-branches-select').click # rubocop:disable QA/SelectorUsage - page.within '.project-refs-form' do - click_link ref_name - wait_for_requests - end + page.within '.project-refs-form' do + click_link ref_name + wait_for_requests end + end - it 'displays no highlighted number of different ref' do - Files::UpdateService.new( - project, - project.first_owner, - commit_message: 'Update', - start_branch: 'feature', - branch_name: 'feature', - file_path: 'files/js/application.js', - file_content: 'new content' - ).execute + it 'displays no highlighted number of different ref' do + Files::UpdateService.new( + project, + project.first_owner, + commit_message: 'Update', + start_branch: 'feature', + branch_name: 'feature', + file_path: 'files/js/application.js', + file_content: 'new content' + ).execute - project.commit('feature').diffs.diff_files.first + project.commit('feature').diffs.diff_files.first - visit_blob('files/js/application.js', anchor: 'L3') - switch_ref_to('feature') + visit_blob('files/js/application.js', anchor: 'L3') + switch_ref_to('feature') - page.within '.blob-content' do - expect(page).not_to have_css('.hll') - end + page.within '.blob-content' do + expect(page).not_to have_css('.hll') end + end - context 'successfully change ref of similar name' do - before do - project.repository.create_branch('dev') - project.repository.create_branch('development') - end - - it 'switch ref from longer to shorter ref name' do - visit_blob('files/js/application.js', ref: 'development') - switch_ref_to('dev') - - aggregate_failures do - expect(page.find('.file-title-name').text).to eq('application.js') - expect(page).not_to have_css('flash-container') - end - end + context 'successfully change ref of similar name' do + before do + project.repository.create_branch('dev') + project.repository.create_branch('development') + end - it 'switch ref from shorter to longer ref name' do - visit_blob('files/js/application.js', ref: 'dev') - switch_ref_to('development') + it 'switch ref from longer to shorter ref name' do + visit_blob('files/js/application.js', ref: 'development') + switch_ref_to('dev') - aggregate_failures do - expect(page.find('.file-title-name').text).to eq('application.js') - expect(page).not_to have_css('flash-container') - end + aggregate_failures do + expect(page.find('.file-title-name').text).to eq('application.js') + expect(page).not_to have_css('flash-container') end end - it 'successfully changes ref when the ref name matches the project name' do - project.repository.create_branch(project.name) - - visit_blob('files/js/application.js', ref: project.name) - switch_ref_to('master') + it 'switch ref from shorter to longer ref name' do + visit_blob('files/js/application.js', ref: 'dev') + switch_ref_to('development') aggregate_failures do expect(page.find('.file-title-name').text).to eq('application.js') @@ -206,133 +192,216 @@ RSpec.describe 'File blob', :js do end end end + + it 'successfully changes ref when the ref name matches the project name' do + project.repository.create_branch(project.name) + + visit_blob('files/js/application.js', ref: project.name) + switch_ref_to('master') + + aggregate_failures do + expect(page.find('.file-title-name').text).to eq('application.js') + expect(page).not_to have_css('flash-container') + end + end + end + end + + context 'Markdown rendering' do + before do + project.add_maintainer(project.creator) + + Files::CreateService.new( + project, + project.creator, + start_branch: 'master', + branch_name: 'master', + commit_message: "Add RedCarpet and CommonMark Markdown ", + file_path: 'files/commonmark/file.md', + file_content: "1. one\n - sublist\n" + ).execute end - context 'Markdown rendering' do + context 'when rendering default markdown' do before do - project.add_maintainer(project.creator) + visit_blob('files/commonmark/file.md') - Files::CreateService.new( - project, - project.creator, - start_branch: 'master', - branch_name: 'master', - commit_message: "Add RedCarpet and CommonMark Markdown ", - file_path: 'files/commonmark/file.md', - file_content: "1. one\n - sublist\n" - ).execute + wait_for_requests end - context 'when rendering default markdown' do - before do - visit_blob('files/commonmark/file.md') - - wait_for_requests + it 'renders using CommonMark' do + aggregate_failures do + expect(page).to have_content("sublist") + expect(page).not_to have_xpath("//ol//li//ul") end + end + end + end - it 'renders using CommonMark' do - aggregate_failures do - expect(page).to have_content("sublist") - expect(page).not_to have_xpath("//ol//li//ul") - end + context 'Markdown file (stored in LFS)' do + before do + project.add_maintainer(project.creator) + + Files::CreateService.new( + project, + project.creator, + start_branch: 'master', + branch_name: 'master', + commit_message: "Add Markdown in LFS", + file_path: 'files/lfs/file.md', + file_content: project.repository.blob_at('master', 'files/lfs/lfs_object.iso').data + ).execute + end + + context 'when LFS is enabled on the project' do + before do + allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) + project.update_attribute(:lfs_enabled, true) + + visit_blob('files/lfs/file.md') + + wait_for_requests + end + + it 'displays an error' do + aggregate_failures do + # hides the simple viewer + expect(page).not_to have_selector('.blob-viewer[data-type="simple"]') + expect(page).not_to have_selector('.blob-viewer[data-type="rich"]') + + # shows an error message + expect(page).to have_content('This content could not be displayed because it is stored in LFS. You can download it instead.') + + # does not show a viewer switcher + expect(page).not_to have_selector('.js-blob-viewer-switcher') + + # does not show a copy button + expect(page).not_to have_selector('.js-copy-blob-source-btn') + + # shows a download button + expect(page).to have_link('Download') end end end - context 'Markdown file (stored in LFS)' do + context 'when LFS is disabled on the project' do before do - project.add_maintainer(project.creator) + visit_blob('files/lfs/file.md') - Files::CreateService.new( - project, - project.creator, - start_branch: 'master', - branch_name: 'master', - commit_message: "Add Markdown in LFS", - file_path: 'files/lfs/file.md', - file_content: project.repository.blob_at('master', 'files/lfs/lfs_object.iso').data - ).execute + wait_for_requests end - context 'when LFS is enabled on the project' do - before do - allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) - project.update_attribute(:lfs_enabled, true) + it 'displays the blob' do + aggregate_failures do + # shows text + expect(page).to have_content('size 1575078') + + # does not show a viewer switcher + expect(page).not_to have_selector('.js-blob-viewer-switcher') - visit_blob('files/lfs/file.md') + # shows an enabled copy button + expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)') - wait_for_requests + # shows a raw button + expect(page).to have_link('Open raw') end + end + end + end - it 'displays an error' do - aggregate_failures do - # hides the simple viewer - expect(page).not_to have_selector('.blob-viewer[data-type="simple"]') - expect(page).not_to have_selector('.blob-viewer[data-type="rich"]') + context 'PDF file' do + before do + project.add_maintainer(project.creator) - # shows an error message - expect(page).to have_content('This content could not be displayed because it is stored in LFS. You can download it instead.') + Files::CreateService.new( + project, + project.creator, + start_branch: 'master', + branch_name: 'master', + commit_message: "Add PDF", + file_path: 'files/test.pdf', + file_content: project.repository.blob_at('add-pdf-file', 'files/pdf/test.pdf').data + ).execute - # does not show a viewer switcher - expect(page).not_to have_selector('.js-blob-viewer-switcher') + visit_blob('files/test.pdf') - # does not show a copy button - expect(page).not_to have_selector('.js-copy-blob-source-btn') + wait_for_requests + end - # shows a download button - expect(page).to have_link('Download') - end - end + it 'displays the blob' do + aggregate_failures do + # shows rendered PDF + expect(page).to have_selector('.js-pdf-viewer') + + # does not show a viewer switcher + expect(page).not_to have_selector('.js-blob-viewer-switcher') + + # does not show a copy button + expect(page).not_to have_selector('.js-copy-blob-source-btn') + + # shows a download button + expect(page).to have_link('Download') end + end + end - context 'when LFS is disabled on the project' do - before do - visit_blob('files/lfs/file.md') + context 'Jupiter Notebook file' do + before do + project.add_maintainer(project.creator) - wait_for_requests - end + Files::CreateService.new( + project, + project.creator, + start_branch: 'master', + branch_name: 'master', + commit_message: "Add Jupiter Notebook", + file_path: 'files/basic.ipynb', + file_content: project.repository.blob_at('add-ipython-files', 'files/ipython/basic.ipynb').data + ).execute - it 'displays the blob' do - aggregate_failures do - # shows text - expect(page).to have_content('size 1575078') + visit_blob('files/basic.ipynb') - # does not show a viewer switcher - expect(page).not_to have_selector('.js-blob-viewer-switcher') + wait_for_requests + end - # shows an enabled copy button - expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)') + it 'displays the blob' do + aggregate_failures do + # shows rendered notebook + expect(page).to have_selector('.js-notebook-viewer-mounted') - # shows a raw button - expect(page).to have_link('Open raw') - end - end + # does show a viewer switcher + expect(page).to have_selector('.js-blob-viewer-switcher') + + # show a disabled copy button + expect(page).to have_selector('.js-copy-blob-source-btn.disabled') + + # shows a raw button + expect(page).to have_link('Open raw') + + # shows a download button + expect(page).to have_link('Download') + + # shows the rendered notebook + expect(page).to have_content('test') end end + end - context 'PDF file' do + context 'ISO file (stored in LFS)' do + context 'when LFS is enabled on the project' do before do - project.add_maintainer(project.creator) - - Files::CreateService.new( - project, - project.creator, - start_branch: 'master', - branch_name: 'master', - commit_message: "Add PDF", - file_path: 'files/test.pdf', - file_content: project.repository.blob_at('add-pdf-file', 'files/pdf/test.pdf').data - ).execute + allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) + project.update_attribute(:lfs_enabled, true) - visit_blob('files/test.pdf') + visit_blob('files/lfs/lfs_object.iso') wait_for_requests end it 'displays the blob' do aggregate_failures do - # shows rendered PDF - expect(page).to have_selector('.js-pdf-viewer') + # shows a download link + expect(page).to have_link('Download (1.50 MiB)') # does not show a viewer switcher expect(page).not_to have_selector('.js-blob-viewer-switcher') @@ -346,126 +415,108 @@ RSpec.describe 'File blob', :js do end end - context 'Jupiter Notebook file' do + context 'when LFS is disabled on the project' do before do - project.add_maintainer(project.creator) - - Files::CreateService.new( - project, - project.creator, - start_branch: 'master', - branch_name: 'master', - commit_message: "Add Jupiter Notebook", - file_path: 'files/basic.ipynb', - file_content: project.repository.blob_at('add-ipython-files', 'files/ipython/basic.ipynb').data - ).execute - - visit_blob('files/basic.ipynb') + visit_blob('files/lfs/lfs_object.iso') wait_for_requests end it 'displays the blob' do aggregate_failures do - # shows rendered notebook - expect(page).to have_selector('.js-notebook-viewer-mounted') + # shows text + expect(page).to have_content('size 1575078') - # does show a viewer switcher - expect(page).to have_selector('.js-blob-viewer-switcher') + # does not show a viewer switcher + expect(page).not_to have_selector('.js-blob-viewer-switcher') - # show a disabled copy button - expect(page).to have_selector('.js-copy-blob-source-btn.disabled') + # shows an enabled copy button + expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)') # shows a raw button expect(page).to have_link('Open raw') - - # shows a download button - expect(page).to have_link('Download') - - # shows the rendered notebook - expect(page).to have_content('test') end end end + end - context 'ISO file (stored in LFS)' do - context 'when LFS is enabled on the project' do - before do - allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) - project.update_attribute(:lfs_enabled, true) - - visit_blob('files/lfs/lfs_object.iso') + context 'ZIP file' do + before do + visit_blob('Gemfile.zip') - wait_for_requests - end + wait_for_requests + end - it 'displays the blob' do - aggregate_failures do - # shows a download link - expect(page).to have_link('Download (1.50 MiB)') + it 'displays the blob' do + aggregate_failures do + # shows a download link + expect(page).to have_link('Download (2.11 KiB)') - # does not show a viewer switcher - expect(page).not_to have_selector('.js-blob-viewer-switcher') + # does not show a viewer switcher + expect(page).not_to have_selector('.js-blob-viewer-switcher') - # does not show a copy button - expect(page).not_to have_selector('.js-copy-blob-source-btn') + # does not show a copy button + expect(page).not_to have_selector('.js-copy-blob-source-btn') - # shows a download button - expect(page).to have_link('Download') - end - end + # shows a download button + expect(page).to have_link('Download') end + end + end - context 'when LFS is disabled on the project' do - before do - visit_blob('files/lfs/lfs_object.iso') + context 'binary file that appears to be text in the first 1024 bytes' do + before do + visit_blob('encoding/binary-1.bin', ref: 'binary-encoding') + end - wait_for_requests - end + it 'displays the blob' do + expect(page).to have_link('Download (23.81 KiB)') + # does not show a viewer switcher + expect(page).not_to have_selector('.js-blob-viewer-switcher') + expect(page).not_to have_selector('.js-copy-blob-source-btn:not(.disabled)') + expect(page).not_to have_link('Open raw') + end + end - it 'displays the blob' do - aggregate_failures do - # shows text - expect(page).to have_content('size 1575078') + context 'empty file' do + before do + project.add_maintainer(project.creator) - # does not show a viewer switcher - expect(page).not_to have_selector('.js-blob-viewer-switcher') + Files::CreateService.new( + project, + project.creator, + start_branch: 'master', + branch_name: 'master', + commit_message: "Add empty file", + file_path: 'files/empty.md', + file_content: '' + ).execute - # shows an enabled copy button - expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)') + visit_blob('files/empty.md') - # shows a raw button - expect(page).to have_link('Open raw') - end - end - end + wait_for_requests end - context 'ZIP file' do - before do - visit_blob('Gemfile.zip') + it 'displays an error' do + aggregate_failures do + # shows an error message + expect(page).to have_content('Empty file') - wait_for_requests - end - - it 'displays the blob' do - aggregate_failures do - # shows a download link - expect(page).to have_link('Download (2.11 KiB)') - - # does not show a viewer switcher - expect(page).not_to have_selector('.js-blob-viewer-switcher') + # does not show a viewer switcher + expect(page).not_to have_selector('.js-blob-viewer-switcher') - # does not show a copy button - expect(page).not_to have_selector('.js-copy-blob-source-btn') + # does not show a copy button + expect(page).not_to have_selector('.js-copy-blob-source-btn') - # shows a download button - expect(page).to have_link('Download') - end + # does not show a download or raw button + expect(page).not_to have_link('Download') + expect(page).not_to have_link('Open raw') end end + end - context 'empty file' do + context 'files with auxiliary viewers' do + describe '.gitlab-ci.yml' do before do project.add_maintainer(project.creator) @@ -474,660 +525,586 @@ RSpec.describe 'File blob', :js do project.creator, start_branch: 'master', branch_name: 'master', - commit_message: "Add empty file", - file_path: 'files/empty.md', - file_content: '' + commit_message: "Add .gitlab-ci.yml", + file_path: '.gitlab-ci.yml', + file_content: File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) ).execute - visit_blob('files/empty.md') - - wait_for_requests + visit_blob('.gitlab-ci.yml') end - it 'displays an error' do + it 'displays an auxiliary viewer' do aggregate_failures do - # shows an error message - expect(page).to have_content('Empty file') + # shows that configuration is valid + expect(page).to have_content('This GitLab CI configuration is valid.') - # does not show a viewer switcher - expect(page).not_to have_selector('.js-blob-viewer-switcher') - - # does not show a copy button - expect(page).not_to have_selector('.js-copy-blob-source-btn') - - # does not show a download or raw button - expect(page).not_to have_link('Download') - expect(page).not_to have_link('Open raw') + # shows a learn more link + expect(page).to have_link('Learn more') end end end - context 'files with auxiliary viewers' do - describe '.gitlab-ci.yml' do - before do - project.add_maintainer(project.creator) - - Files::CreateService.new( - project, - project.creator, - start_branch: 'master', - branch_name: 'master', - commit_message: "Add .gitlab-ci.yml", - file_path: '.gitlab-ci.yml', - file_content: File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) - ).execute - - visit_blob('.gitlab-ci.yml') - end + describe '.gitlab/route-map.yml' do + before do + project.add_maintainer(project.creator) - it 'displays an auxiliary viewer' do - aggregate_failures do - # shows that configuration is valid - expect(page).to have_content('This GitLab CI configuration is valid.') + Files::CreateService.new( + project, + project.creator, + start_branch: 'master', + branch_name: 'master', + commit_message: "Add .gitlab/route-map.yml", + file_path: '.gitlab/route-map.yml', + file_content: <<-MAP.strip_heredoc + # Team data + - source: 'data/team.yml' + public: 'team/' + MAP + ).execute - # shows a learn more link - expect(page).to have_link('Learn more') - end - end + visit_blob('.gitlab/route-map.yml') end - describe '.gitlab/route-map.yml' do - before do - project.add_maintainer(project.creator) - - Files::CreateService.new( - project, - project.creator, - start_branch: 'master', - branch_name: 'master', - commit_message: "Add .gitlab/route-map.yml", - file_path: '.gitlab/route-map.yml', - file_content: <<-MAP.strip_heredoc - # Team data - - source: 'data/team.yml' - public: 'team/' - MAP - ).execute - - visit_blob('.gitlab/route-map.yml') + it 'displays an auxiliary viewer' do + aggregate_failures do + # shows that map is valid + expect(page).to have_content('This Route Map is valid.') + + # shows a learn more link + expect(page).to have_link('Learn more') end + end + end - it 'displays an auxiliary viewer' do - aggregate_failures do - # shows that map is valid - expect(page).to have_content('This Route Map is valid.') + describe '.gitlab/dashboards/custom-dashboard.yml' do + before do + project.add_maintainer(project.creator) - # shows a learn more link - expect(page).to have_link('Learn more') - end - end + Files::CreateService.new( + project, + project.creator, + start_branch: 'master', + branch_name: 'master', + commit_message: "Add .gitlab/dashboards/custom-dashboard.yml", + file_path: '.gitlab/dashboards/custom-dashboard.yml', + file_content: file_content + ).execute end - describe '.gitlab/dashboards/custom-dashboard.yml' do + context 'with metrics_dashboard_exhaustive_validations feature flag off' do before do - project.add_maintainer(project.creator) - - Files::CreateService.new( - project, - project.creator, - start_branch: 'master', - branch_name: 'master', - commit_message: "Add .gitlab/dashboards/custom-dashboard.yml", - file_path: '.gitlab/dashboards/custom-dashboard.yml', - file_content: file_content - ).execute + stub_feature_flags(metrics_dashboard_exhaustive_validations: false) + visit_blob('.gitlab/dashboards/custom-dashboard.yml') end - context 'with metrics_dashboard_exhaustive_validations feature flag off' do - before do - stub_feature_flags(metrics_dashboard_exhaustive_validations: false) - visit_blob('.gitlab/dashboards/custom-dashboard.yml') - end + context 'valid dashboard file' do + let(:file_content) { File.read(Rails.root.join('config/prometheus/common_metrics.yml')) } - context 'valid dashboard file' do - let(:file_content) { File.read(Rails.root.join('config/prometheus/common_metrics.yml')) } - - it 'displays an auxiliary viewer' do - aggregate_failures do - # shows that dashboard yaml is valid - expect(page).to have_content('Metrics Dashboard YAML definition is valid.') + it 'displays an auxiliary viewer' do + aggregate_failures do + # shows that dashboard yaml is valid + expect(page).to have_content('Metrics Dashboard YAML definition is valid.') - # shows a learn more link - expect(page).to have_link('Learn more') - end + # shows a learn more link + expect(page).to have_link('Learn more') end end + end - context 'invalid dashboard file' do - let(:file_content) { "dashboard: 'invalid'" } + context 'invalid dashboard file' do + let(:file_content) { "dashboard: 'invalid'" } - it 'displays an auxiliary viewer' do - aggregate_failures do - # shows that dashboard yaml is invalid - expect(page).to have_content('Metrics Dashboard YAML definition is invalid:') - expect(page).to have_content("panel_groups: should be an array of panel_groups objects") + it 'displays an auxiliary viewer' do + aggregate_failures do + # shows that dashboard yaml is invalid + expect(page).to have_content('Metrics Dashboard YAML definition is invalid:') + expect(page).to have_content("panel_groups: should be an array of panel_groups objects") - # shows a learn more link - expect(page).to have_link('Learn more') - end + # shows a learn more link + expect(page).to have_link('Learn more') end end end + end - context 'with metrics_dashboard_exhaustive_validations feature flag on' do - before do - stub_feature_flags(metrics_dashboard_exhaustive_validations: true) - visit_blob('.gitlab/dashboards/custom-dashboard.yml') - end + context 'with metrics_dashboard_exhaustive_validations feature flag on' do + before do + stub_feature_flags(metrics_dashboard_exhaustive_validations: true) + visit_blob('.gitlab/dashboards/custom-dashboard.yml') + end - context 'valid dashboard file' do - let(:file_content) { File.read(Rails.root.join('config/prometheus/common_metrics.yml')) } + context 'valid dashboard file' do + let(:file_content) { File.read(Rails.root.join('config/prometheus/common_metrics.yml')) } - it 'displays an auxiliary viewer' do - aggregate_failures do - # shows that dashboard yaml is valid - expect(page).to have_content('Metrics Dashboard YAML definition is valid.') + it 'displays an auxiliary viewer' do + aggregate_failures do + # shows that dashboard yaml is valid + expect(page).to have_content('Metrics Dashboard YAML definition is valid.') - # shows a learn more link - expect(page).to have_link('Learn more') - end + # shows a learn more link + expect(page).to have_link('Learn more') end end + end - context 'invalid dashboard file' do - let(:file_content) { "dashboard: 'invalid'" } + context 'invalid dashboard file' do + let(:file_content) { "dashboard: 'invalid'" } - it 'displays an auxiliary viewer' do - aggregate_failures do - # shows that dashboard yaml is invalid - expect(page).to have_content('Metrics Dashboard YAML definition is invalid:') - expect(page).to have_content("root is missing required keys: panel_groups") + it 'displays an auxiliary viewer' do + aggregate_failures do + # shows that dashboard yaml is invalid + expect(page).to have_content('Metrics Dashboard YAML definition is invalid:') + expect(page).to have_content("root is missing required keys: panel_groups") - # shows a learn more link - expect(page).to have_link('Learn more') - end + # shows a learn more link + expect(page).to have_link('Learn more') end end end end + end - context 'LICENSE' do - before do - visit_blob('LICENSE') - end + context 'LICENSE' do + before do + visit_blob('LICENSE') + end - it 'displays an auxiliary viewer' do - aggregate_failures do - # shows license - expect(page).to have_content('This project is licensed under the MIT License.') + it 'displays an auxiliary viewer' do + aggregate_failures do + # shows license + expect(page).to have_content('This project is licensed under the MIT License.') - # shows a learn more link - expect(page).to have_link('Learn more', href: 'http://choosealicense.com/licenses/mit/') - end + # shows a learn more link + expect(page).to have_link('Learn more', href: 'http://choosealicense.com/licenses/mit/') end end + end - context '*.gemspec' do - before do - project.add_maintainer(project.creator) - - Files::CreateService.new( - project, - project.creator, - start_branch: 'master', - branch_name: 'master', - commit_message: "Add activerecord.gemspec", - file_path: 'activerecord.gemspec', - file_content: <<-SPEC.strip_heredoc - Gem::Specification.new do |s| - s.platform = Gem::Platform::RUBY - s.name = "activerecord" - end - SPEC - ).execute - - visit_blob('activerecord.gemspec') - end + context '*.gemspec' do + before do + project.add_maintainer(project.creator) - it 'displays an auxiliary viewer' do - aggregate_failures do - # shows names of dependency manager and package - expect(page).to have_content('This project manages its dependencies using RubyGems.') + Files::CreateService.new( + project, + project.creator, + start_branch: 'master', + branch_name: 'master', + commit_message: "Add activerecord.gemspec", + file_path: 'activerecord.gemspec', + file_content: <<-SPEC.strip_heredoc + Gem::Specification.new do |s| + s.platform = Gem::Platform::RUBY + s.name = "activerecord" + end + SPEC + ).execute - # shows a learn more link - expect(page).to have_link('Learn more', href: 'https://rubygems.org/') - end - end + visit_blob('activerecord.gemspec') end - context 'CONTRIBUTING.md' do - before do - file_name = 'CONTRIBUTING.md' + it 'displays an auxiliary viewer' do + aggregate_failures do + # shows names of dependency manager and package + expect(page).to have_content('This project manages its dependencies using RubyGems.') - create_file(file_name, '## Contribution guidelines') - visit_blob(file_name) + # shows a learn more link + expect(page).to have_link('Learn more', href: 'https://rubygems.org/') end + end + end - it 'displays an auxiliary viewer' do - aggregate_failures do - expect(page).to have_content("After you've reviewed these contribution guidelines, you'll be all set to contribute to this project.") - end + context 'CONTRIBUTING.md' do + before do + file_name = 'CONTRIBUTING.md' + + create_file(file_name, '## Contribution guidelines') + visit_blob(file_name) + end + + it 'displays an auxiliary viewer' do + aggregate_failures do + expect(page).to have_content("After you've reviewed these contribution guidelines, you'll be all set to contribute to this project.") end end + end - context 'CHANGELOG.md' do - before do - file_name = 'CHANGELOG.md' + context 'CHANGELOG.md' do + before do + file_name = 'CHANGELOG.md' - create_file(file_name, '## Changelog for v1.0.0') - visit_blob(file_name) - end + create_file(file_name, '## Changelog for v1.0.0') + visit_blob(file_name) + end - it 'displays an auxiliary viewer' do - aggregate_failures do - expect(page).to have_content("To find the state of this project's repository at the time of any of these versions, check out the tags.") - end + it 'displays an auxiliary viewer' do + aggregate_failures do + expect(page).to have_content("To find the state of this project's repository at the time of any of these versions, check out the tags.") end end + end - context 'Cargo.toml' do - before do - file_name = 'Cargo.toml' - - create_file(file_name, ' - [package] - name = "hello_world" # the name of the package - version = "0.1.0" # the current version, obeying semver - authors = ["Alice <a@example.com>", "Bob <b@example.com>"] - ') - visit_blob(file_name) - end + context 'Cargo.toml' do + before do + file_name = 'Cargo.toml' + + create_file(file_name, ' + [package] + name = "hello_world" # the name of the package + version = "0.1.0" # the current version, obeying semver + authors = ["Alice <a@example.com>", "Bob <b@example.com>"] + ') + visit_blob(file_name) + end - it 'displays an auxiliary viewer' do - aggregate_failures do - expect(page).to have_content("This project manages its dependencies using Cargo.") - end + it 'displays an auxiliary viewer' do + aggregate_failures do + expect(page).to have_content("This project manages its dependencies using Cargo.") end end + end - context 'Cartfile' do - before do - file_name = 'Cartfile' + context 'Cartfile' do + before do + file_name = 'Cartfile' - create_file(file_name, ' - gitlab "Alamofire/Alamofire" == 4.9.0 - gitlab "Alamofire/AlamofireImage" ~> 3.4 - ') - visit_blob(file_name) - end + create_file(file_name, ' + gitlab "Alamofire/Alamofire" == 4.9.0 + gitlab "Alamofire/AlamofireImage" ~> 3.4 + ') + visit_blob(file_name) + end - it 'displays an auxiliary viewer' do - aggregate_failures do - expect(page).to have_content("This project manages its dependencies using Carthage.") - end + it 'displays an auxiliary viewer' do + aggregate_failures do + expect(page).to have_content("This project manages its dependencies using Carthage.") end end + end - context 'composer.json' do - before do - file_name = 'composer.json' - - create_file(file_name, ' - { - "license": "MIT" - } - ') - visit_blob(file_name) - end + context 'composer.json' do + before do + file_name = 'composer.json' + + create_file(file_name, ' + { + "license": "MIT" + } + ') + visit_blob(file_name) + end - it 'displays an auxiliary viewer' do - aggregate_failures do - expect(page).to have_content("This project manages its dependencies using Composer.") - end + it 'displays an auxiliary viewer' do + aggregate_failures do + expect(page).to have_content("This project manages its dependencies using Composer.") end end + end - context 'Gemfile' do - before do - file_name = 'Gemfile' + context 'Gemfile' do + before do + file_name = 'Gemfile' - create_file(file_name, ' - source "https://rubygems.org" + create_file(file_name, ' + source "https://rubygems.org" - # Gems here - ') - visit_blob(file_name) - end + # Gems here + ') + visit_blob(file_name) + end - it 'displays an auxiliary viewer' do - aggregate_failures do - expect(page).to have_content("This project manages its dependencies using Bundler.") - end + it 'displays an auxiliary viewer' do + aggregate_failures do + expect(page).to have_content("This project manages its dependencies using Bundler.") end end + end - context 'Godeps.json' do - before do - file_name = 'Godeps.json' - - create_file(file_name, ' - { - "GoVersion": "go1.6" - } - ') - visit_blob(file_name) - end + context 'Godeps.json' do + before do + file_name = 'Godeps.json' + + create_file(file_name, ' + { + "GoVersion": "go1.6" + } + ') + visit_blob(file_name) + end - it 'displays an auxiliary viewer' do - aggregate_failures do - expect(page).to have_content("This project manages its dependencies using godep.") - end + it 'displays an auxiliary viewer' do + aggregate_failures do + expect(page).to have_content("This project manages its dependencies using godep.") end end + end - context 'go.mod' do - before do - file_name = 'go.mod' + context 'go.mod' do + before do + file_name = 'go.mod' - create_file(file_name, ' - module example.com/mymodule + create_file(file_name, ' + module example.com/mymodule - go 1.14 - ') - visit_blob(file_name) - end + go 1.14 + ') + visit_blob(file_name) + end - it 'displays an auxiliary viewer' do - aggregate_failures do - expect(page).to have_content("This project manages its dependencies using Go Modules.") - end + it 'displays an auxiliary viewer' do + aggregate_failures do + expect(page).to have_content("This project manages its dependencies using Go Modules.") end end + end - context 'package.json' do - before do - file_name = 'package.json' - - create_file(file_name, ' - { - "name": "my-awesome-package", - "version": "1.0.0" - } - ') - visit_blob(file_name) - end + context 'package.json' do + before do + file_name = 'package.json' + + create_file(file_name, ' + { + "name": "my-awesome-package", + "version": "1.0.0" + } + ') + visit_blob(file_name) + end - it 'displays an auxiliary viewer' do - aggregate_failures do - expect(page).to have_content("This project manages its dependencies using npm.") - end + it 'displays an auxiliary viewer' do + aggregate_failures do + expect(page).to have_content("This project manages its dependencies using npm.") end end + end - context 'podfile' do - before do - file_name = 'podfile' + context 'podfile' do + before do + file_name = 'podfile' - create_file(file_name, 'platform :ios, "8.0"') - visit_blob(file_name) - end + create_file(file_name, 'platform :ios, "8.0"') + visit_blob(file_name) + end - it 'displays an auxiliary viewer' do - aggregate_failures do - expect(page).to have_content("This project manages its dependencies using CocoaPods.") - end + it 'displays an auxiliary viewer' do + aggregate_failures do + expect(page).to have_content("This project manages its dependencies using CocoaPods.") end end + end - context 'test.podspec' do - before do - file_name = 'test.podspec' - - create_file(file_name, ' - Pod::Spec.new do |s| - s.name = "TensorFlowLiteC" - ') - visit_blob(file_name) - end + context 'test.podspec' do + before do + file_name = 'test.podspec' - it 'displays an auxiliary viewer' do - aggregate_failures do - expect(page).to have_content("This project manages its dependencies using CocoaPods.") - end - end + create_file(file_name, ' + Pod::Spec.new do |s| + s.name = "TensorFlowLiteC" + ') + visit_blob(file_name) end - context 'JSON.podspec.json' do - before do - file_name = 'JSON.podspec.json' - - create_file(file_name, ' - { - "name": "JSON" - } - ') - visit_blob(file_name) - end - - it 'displays an auxiliary viewer' do - aggregate_failures do - expect(page).to have_content("This project manages its dependencies using CocoaPods.") - end + it 'displays an auxiliary viewer' do + aggregate_failures do + expect(page).to have_content("This project manages its dependencies using CocoaPods.") end end + end - context 'requirements.txt' do - before do - file_name = 'requirements.txt' - - create_file(file_name, 'Project requirements') - visit_blob(file_name) - end + context 'JSON.podspec.json' do + before do + file_name = 'JSON.podspec.json' + + create_file(file_name, ' + { + "name": "JSON" + } + ') + visit_blob(file_name) + end - it 'displays an auxiliary viewer' do - aggregate_failures do - expect(page).to have_content("This project manages its dependencies using pip.") - end + it 'displays an auxiliary viewer' do + aggregate_failures do + expect(page).to have_content("This project manages its dependencies using CocoaPods.") end end + end - context 'yarn.lock' do - before do - file_name = 'yarn.lock' + context 'requirements.txt' do + before do + file_name = 'requirements.txt' - create_file(file_name, ' - # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. - # yarn lockfile v1 - ') - visit_blob(file_name) - end + create_file(file_name, 'Project requirements') + visit_blob(file_name) + end - it 'displays an auxiliary viewer' do - aggregate_failures do - expect(page).to have_content("This project manages its dependencies using Yarn.") - end + it 'displays an auxiliary viewer' do + aggregate_failures do + expect(page).to have_content("This project manages its dependencies using pip.") end end + end - context 'openapi.yml' do - before do - file_name = 'openapi.yml' - - create_file(file_name, ' - swagger: \'2.0\' - info: - title: Classic API Resource Documentation - description: | - <div class="foo-bar" style="background-color: red;" data-foo-bar="baz"> - <h1>Swagger API documentation</h1> - </div> - version: production - basePath: /JSSResource/ - produces: - - application/xml - - application/json - consumes: - - application/xml - - application/json - security: - - basicAuth: [] - paths: - /accounts: - get: - responses: - \'200\': - description: No response was specified - tags: - - accounts - operationId: findAccounts - summary: Finds all accounts - ') - visit_blob(file_name, useUnsafeMarkdown: '1') - click_button('Display rendered file') + context 'yarn.lock' do + before do + file_name = 'yarn.lock' - wait_for_requests - end + create_file(file_name, ' + # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. + # yarn lockfile v1 + ') + visit_blob(file_name) + end - it 'removes `style`, `class`, and `data-*`` attributes from HTML' do - expect(page).to have_css('h1', text: 'Swagger API documentation') - expect(page).not_to have_css('.foo-bar') - expect(page).not_to have_css('[style="background-color: red;"]') - expect(page).not_to have_css('[data-foo-bar="baz"]') + it 'displays an auxiliary viewer' do + aggregate_failures do + expect(page).to have_content("This project manages its dependencies using Yarn.") end end end - context 'realtime pipelines' do + context 'openapi.yml' do before do - Files::CreateService.new( - project, - project.creator, - start_branch: 'feature', - branch_name: 'feature', - commit_message: "Add ruby file", - file_path: 'files/ruby/test.rb', - file_content: "# Awesome content" - ).execute + file_name = 'openapi.yml' + + create_file(file_name, ' + swagger: \'2.0\' + info: + title: Classic API Resource Documentation + description: | + <div class="foo-bar" style="background-color: red;" data-foo-bar="baz"> + <h1>Swagger API documentation</h1> + </div> + version: production + basePath: /JSSResource/ + produces: + - application/xml + - application/json + consumes: + - application/xml + - application/json + security: + - basicAuth: [] + paths: + /accounts: + get: + responses: + \'200\': + description: No response was specified + tags: + - accounts + operationId: findAccounts + summary: Finds all accounts + ') + visit_blob(file_name, useUnsafeMarkdown: '1') + click_button('Display rendered file') - create(:ci_pipeline, status: 'running', project: project, ref: 'feature', sha: project.commit('feature').sha) - visit_blob('files/ruby/test.rb', ref: 'feature') + wait_for_requests end - it 'shows the realtime pipeline status' do - page.within('.commit-actions') do - expect(page).to have_css('.ci-status-icon') - expect(page).to have_css('.ci-status-icon-running') - expect(page).to have_css('.js-ci-status-icon-running') - end + it 'removes `style`, `class`, and `data-*`` attributes from HTML' do + expect(page).to have_css('h1', text: 'Swagger API documentation') + expect(page).not_to have_css('.foo-bar') + expect(page).not_to have_css('[style="background-color: red;"]') + expect(page).not_to have_css('[data-foo-bar="baz"]') end end + end - context 'for subgroups' do - let(:group) { create(:group) } - let(:subgroup) { create(:group, parent: group) } - let(:project) { create(:project, :public, :repository, group: subgroup) } - - it 'renders tree table without errors' do - visit_blob('README.md') + context 'realtime pipelines' do + before do + Files::CreateService.new( + project, + project.creator, + start_branch: 'feature', + branch_name: 'feature', + commit_message: "Add ruby file", + file_path: 'files/ruby/test.rb', + file_content: "# Awesome content" + ).execute + + create(:ci_pipeline, status: 'running', project: project, ref: 'feature', sha: project.commit('feature').sha) + visit_blob('files/ruby/test.rb', ref: 'feature') + end - expect(page).to have_selector('.file-content') - expect(page).not_to have_selector('[data-testid="alert-danger"]') + it 'shows the realtime pipeline status' do + page.within('.commit-actions') do + expect(page).to have_css('.ci-status-icon') + expect(page).to have_css('.ci-status-icon-running') + expect(page).to have_css('.js-ci-status-icon-running') end + end + end - it 'displays a GPG badge' do - visit_blob('CONTRIBUTING.md', ref: '33f3729a45c02fc67d00adb1b8bca394b0e761d9') + context 'for subgroups' do + let(:group) { create(:group) } + let(:subgroup) { create(:group, parent: group) } + let(:project) { create(:project, :public, :repository, group: subgroup) } - expect(page).not_to have_selector '.gpg-status-box.js-loading-gpg-badge' - expect(page).to have_selector '.gpg-status-box.invalid' - end + it 'renders tree table without errors' do + visit_blob('README.md') + + expect(page).to have_selector('.file-content') + expect(page).not_to have_selector('[data-testid="alert-danger"]') end - context 'on signed merge commit' do - it 'displays a GPG badge' do - visit_blob('conflicting-file.md', ref: '6101e87e575de14b38b4e1ce180519a813671e10') + it 'displays a GPG badge' do + visit_blob('CONTRIBUTING.md', ref: '33f3729a45c02fc67d00adb1b8bca394b0e761d9') - expect(page).not_to have_selector '.gpg-status-box.js-loading-gpg-badge' - expect(page).to have_selector '.gpg-status-box.invalid' - end + expect(page).not_to have_selector '.gpg-status-box.js-loading-gpg-badge' + expect(page).to have_selector '.gpg-status-box.invalid' end + end - context 'when static objects external storage is enabled' do - before do - stub_application_setting(static_objects_external_storage_url: 'https://cdn.gitlab.com') - end + context 'on signed merge commit' do + it 'displays a GPG badge' do + visit_blob('conflicting-file.md', ref: '6101e87e575de14b38b4e1ce180519a813671e10') - context 'private project' do - let_it_be(:project) { create(:project, :repository, :private) } - let_it_be(:user) { create(:user, static_object_token: 'ABCD1234') } + expect(page).not_to have_selector '.gpg-status-box.js-loading-gpg-badge' + expect(page).to have_selector '.gpg-status-box.invalid' + end + end - before do - project.add_developer(user) + context 'when static objects external storage is enabled' do + before do + stub_application_setting(static_objects_external_storage_url: 'https://cdn.gitlab.com') + end - sign_in(user) - visit_blob('README.md') - end + context 'private project' do + let_it_be(:project) { create(:project, :repository, :private) } + let_it_be(:user) { create(:user, static_object_token: 'ABCD1234') } - it 'shows open raw and download buttons with external storage URL prepended and user token appended to their href' do - path = project_raw_path(project, 'master/README.md') - raw_uri = "https://cdn.gitlab.com#{path}?token=#{user.static_object_token}" - download_uri = "https://cdn.gitlab.com#{path}?token=#{user.static_object_token}&inline=false" + before do + project.add_developer(user) - aggregate_failures do - expect(page).to have_link 'Open raw', href: raw_uri - expect(page).to have_link 'Download', href: download_uri - end - end + sign_in(user) + visit_blob('README.md') end - context 'public project' do - before do - visit_blob('README.md') - end + it 'shows open raw and download buttons with external storage URL prepended and user token appended to their href' do + path = project_raw_path(project, 'master/README.md') + raw_uri = "https://cdn.gitlab.com#{path}?token=#{user.static_object_token}" + download_uri = "https://cdn.gitlab.com#{path}?token=#{user.static_object_token}&inline=false" - it 'shows open raw and download buttons with external storage URL prepended to their href' do - path = project_raw_path(project, 'master/README.md') - raw_uri = "https://cdn.gitlab.com#{path}" - download_uri = "https://cdn.gitlab.com#{path}?inline=false" - - aggregate_failures do - expect(page).to have_link 'Open raw', href: raw_uri - expect(page).to have_link 'Download', href: download_uri - end + aggregate_failures do + expect(page).to have_link 'Open raw', href: raw_uri + expect(page).to have_link 'Download', href: download_uri end end end - end - - context 'with refactor_blob_viewer feature flag disabled' do - before do - stub_feature_flags(refactor_blob_viewer: false) - end - - context 'binary file that appears to be text in the first 1024 bytes' do - # We need to unsre that this test runs with the refactor_blob_viewer feature flag enabled - # This will be addressed in https://gitlab.com/gitlab-org/gitlab/-/issues/351559 + context 'public project' do before do - visit_blob('encoding/binary-1.bin', ref: 'binary-encoding') + visit_blob('README.md') end - it 'displays the blob' do + + it 'shows open raw and download buttons with external storage URL prepended to their href' do + path = project_raw_path(project, 'master/README.md') + raw_uri = "https://cdn.gitlab.com#{path}" + download_uri = "https://cdn.gitlab.com#{path}?inline=false" + aggregate_failures do - # shows a download link - expect(page).to have_link('Download (23.8 KB)') - # does not show a viewer switcher - expect(page).not_to have_selector('.js-blob-viewer-switcher') - # The specs below verify an arguably incorrect result, but since we only - # learn that the file is not actually text once the text viewer content - # is loaded asynchronously, there is no straightforward way to get these - # synchronously loaded elements to display correctly. - # - # Clicking the copy button will result in nothing being copied. - # Clicking the raw button will result in the binary file being downloaded, - # as expected. - # shows an enabled copy button, incorrectly - expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)') - # shows a raw button, incorrectly - expect(page).to have_link('Open raw') + expect(page).to have_link 'Open raw', href: raw_uri + expect(page).to have_link 'Download', href: download_uri end end end diff --git a/spec/features/projects/branches_spec.rb b/spec/features/projects/branches_spec.rb index d906bb396be..727f9aa486e 100644 --- a/spec/features/projects/branches_spec.rb +++ b/spec/features/projects/branches_spec.rb @@ -233,6 +233,8 @@ RSpec.describe 'Branches' do end context 'with one or more pipeline', :js do + let(:project) { create(:project, :public, :empty_repo) } + before do sha = create_file(branch_name: "branch") create(:ci_pipeline, diff --git a/spec/features/projects/ci/secure_files_spec.rb b/spec/features/projects/ci/secure_files_spec.rb index a0e9d663d35..412330eb5d6 100644 --- a/spec/features/projects/ci/secure_files_spec.rb +++ b/spec/features/projects/ci/secure_files_spec.rb @@ -14,7 +14,7 @@ RSpec.describe 'Secure Files', :js do it 'user sees the Secure Files list component' do visit project_ci_secure_files_path(project) - expect(page).to have_content('There are no records to show') + expect(page).to have_content('There are no secure files yet.') end it 'prompts the user to confirm before deleting a file' do @@ -37,7 +37,7 @@ RSpec.describe 'Secure Files', :js do it 'displays an uploaded file in the file list' do visit project_ci_secure_files_path(project) - expect(page).to have_content('There are no records to show') + expect(page).to have_content('There are no secure files yet.') page.attach_file('spec/fixtures/ci_secure_files/upload-keystore.jks') do click_button 'Upload File' diff --git a/spec/features/projects/commits/multi_view_diff_spec.rb b/spec/features/projects/commits/multi_view_diff_spec.rb index 282112a3767..5af2e367aed 100644 --- a/spec/features/projects/commits/multi_view_diff_spec.rb +++ b/spec/features/projects/commits/multi_view_diff_spec.rb @@ -46,28 +46,28 @@ RSpec.describe 'Multiple view Diffs', :js do end context 'opening a diff with ipynb' do - it 'loads the rendered diff as hidden' do + it 'loads the raw diff as hidden' do diff = page.find('.diff-file, .file-holder', match: :first) - expect(diff).not_to have_selector '[data-diff-toggle-entity="toHide"]' - expect(diff).to have_selector '[data-diff-toggle-entity="toShow"]' + expect(diff).not_to have_selector '[data-diff-toggle-entity="rawViewer"]' + expect(diff).to have_selector '[data-diff-toggle-entity="renderedViewer"]' - expect(classes_for_element(diff, 'toHide', visible: false)).to include('hidden') - expect(classes_for_element(diff, 'toShow')).not_to include('hidden') + expect(classes_for_element(diff, 'rawViewer', visible: false)).to include('hidden') + expect(classes_for_element(diff, 'renderedViewer')).not_to include('hidden') - expect(classes_for_element(diff, 'toShowBtn')).to include('selected') - expect(classes_for_element(diff, 'toHideBtn')).not_to include('selected') + expect(classes_for_element(diff, 'renderedButton')).to include('selected') + expect(classes_for_element(diff, 'rawButton')).not_to include('selected') end - it 'displays the rendered diff and hides after selection changes' do + it 'displays the raw diff and hides after selection changes' do diff = page.find('.diff-file, .file-holder', match: :first) - diff.find('[data-diff-toggle-entity="toShowBtn"]').click + diff.find('[data-diff-toggle-entity="rawButton"]').click - expect(diff).to have_selector '[data-diff-toggle-entity="toShow"]' - expect(diff).not_to have_selector '[data-diff-toggle-entity="toHide"]' + expect(diff).to have_selector '[data-diff-toggle-entity="rawViewer"]' + expect(diff).not_to have_selector '[data-diff-toggle-entity="renderedViewer"]' - expect(classes_for_element(diff, 'toHideBtn')).not_to include('selected') - expect(classes_for_element(diff, 'toShowBtn')).to include('selected') + expect(classes_for_element(diff, 'renderedButton')).not_to include('selected') + expect(classes_for_element(diff, 'rawButton')).to include('selected') end it 'transforms the diff' do diff --git a/spec/features/projects/deploy_keys_spec.rb b/spec/features/projects/deploy_keys_spec.rb index bf705cf875b..06462263f5a 100644 --- a/spec/features/projects/deploy_keys_spec.rb +++ b/spec/features/projects/deploy_keys_spec.rb @@ -3,22 +3,38 @@ require 'spec_helper' RSpec.describe 'Project deploy keys', :js do - let(:user) { create(:user) } - let(:project) { create(:project_empty_repo) } + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project_empty_repo) } + let_it_be(:deploy_keys_project) { create(:deploy_keys_project, project: project) } + let_it_be(:deploy_key) { deploy_keys_project.deploy_key } before do project.add_maintainer(user) sign_in(user) end + context 'editing key' do + it 'shows fingerprints' do + visit edit_project_deploy_key_path(project, deploy_key) + + expect(page).to have_content('Fingerprint (SHA256)') + expect(find('#deploy_key_fingerprint_sha256').value).to eq(deploy_key.fingerprint_sha256) + + if Gitlab::FIPS.enabled? + expect(page).not_to have_content('Fingerprint (MD5)') + else + expect(page).to have_content('Fingerprint (MD5)') + expect(find('#deploy_key_fingerprint').value).to eq(deploy_key.fingerprint) + end + end + end + describe 'removing key' do before do - create(:deploy_keys_project, project: project) + visit project_settings_repository_path(project) end it 'removes association between project and deploy key' do - visit project_settings_repository_path(project) - page.within(find('.rspec-deploy-keys-settings')) do expect(page).to have_selector('.deploy-key', count: 1) diff --git a/spec/features/projects/diffs/diff_show_spec.rb b/spec/features/projects/diffs/diff_show_spec.rb index 56506ada3ce..dcd6f1239bb 100644 --- a/spec/features/projects/diffs/diff_show_spec.rb +++ b/spec/features/projects/diffs/diff_show_spec.rb @@ -169,8 +169,8 @@ RSpec.describe 'Diff file viewer', :js, :with_clean_rails_cache do wait_for_requests end - it 'shows there is no preview' do - expect(page).to have_content('No preview for this file type') + it 'shows that file was added' do + expect(page).to have_content('File added') end end end diff --git a/spec/features/projects/environments_pod_logs_spec.rb b/spec/features/projects/environments_pod_logs_spec.rb deleted file mode 100644 index 531eae1d638..00000000000 --- a/spec/features/projects/environments_pod_logs_spec.rb +++ /dev/null @@ -1,68 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'Environment > Pod Logs', :js, :kubeclient do - include KubernetesHelpers - - let(:pod_names) { %w(kube-pod) } - let(:pod_name) { pod_names.first } - let(:project) { create(:project, :repository) } - let(:environment) { create(:environment, project: project) } - let(:service) { create(:cluster_platform_kubernetes, :configured) } - - before do - cluster = create(:cluster, :provided_by_gcp, environment_scope: '*', projects: [project]) - create(:deployment, :success, environment: environment) - - stub_kubeclient_pods(environment.deployment_namespace) - stub_kubeclient_logs(pod_name, environment.deployment_namespace, container: 'container-0') - stub_kubeclient_deployments(environment.deployment_namespace) - stub_kubeclient_ingresses(environment.deployment_namespace) - stub_kubeclient_nodes_and_nodes_metrics(cluster.platform.api_url) - - sign_in(project.first_owner) - end - - it "shows environments in dropdown" do - create(:environment, project: project) - - visit project_logs_path(environment.project, environment_name: environment.name, pod_name: pod_name) - - wait_for_requests - - page.within('.js-environments-dropdown') do - toggle = find(".dropdown-toggle:not([disabled])") - - expect(toggle).to have_content(environment.name) - - toggle.click - - dropdown_items = find(".dropdown-menu").all(".dropdown-item") - expect(dropdown_items.first).to have_content(environment.name) - expect(dropdown_items.size).to eq(2) - end - end - - context 'with logs', :use_clean_rails_memory_store_caching do - it "shows pod logs", :sidekiq_might_not_need_inline do - visit project_logs_path(environment.project, environment_name: environment.name, pod_name: pod_name) - - wait_for_requests - - page.within('.qa-pods-dropdown') do # rubocop:disable QA/SelectorUsage - find(".dropdown-toggle:not([disabled])").click - - dropdown_items = find(".dropdown-menu").all(".dropdown-item:not([disabled])") - expect(dropdown_items.size).to eq(1) - - dropdown_items.each_with_index do |item, i| - expect(item.text).to eq(pod_names[i]) - end - end - expect(page).to have_content("kube-pod | Log 1") - expect(page).to have_content("kube-pod | Log 2") - expect(page).to have_content("kube-pod | Log 3") - end - end -end diff --git a/spec/features/projects/files/dockerfile_dropdown_spec.rb b/spec/features/projects/files/dockerfile_dropdown_spec.rb index 3a0cc61d9c6..dd1635c900e 100644 --- a/spec/features/projects/files/dockerfile_dropdown_spec.rb +++ b/spec/features/projects/files/dockerfile_dropdown_spec.rb @@ -26,6 +26,6 @@ RSpec.describe 'Projects > Files > User wants to add a Dockerfile file', :js do wait_for_requests expect(page).to have_css('.dockerfile-selector .dropdown-toggle-text', text: 'Apply a template') - expect(editor_get_value).to have_content('COPY ./ /usr/local/apache2/htdocs/') + expect(find('.monaco-editor')).to have_content('COPY ./ /usr/local/apache2/htdocs/') end end diff --git a/spec/features/projects/files/gitignore_dropdown_spec.rb b/spec/features/projects/files/gitignore_dropdown_spec.rb index 4a92216f46c..a86adf951d8 100644 --- a/spec/features/projects/files/gitignore_dropdown_spec.rb +++ b/spec/features/projects/files/gitignore_dropdown_spec.rb @@ -26,7 +26,7 @@ RSpec.describe 'Projects > Files > User wants to add a .gitignore file', :js do wait_for_requests expect(page).to have_css('.gitignore-selector .dropdown-toggle-text', text: 'Apply a template') - expect(editor_get_value).to have_content('/.bundle') - expect(editor_get_value).to have_content('config/initializers/secret_token.rb') + expect(find('.monaco-editor')).to have_content('/.bundle') + expect(find('.monaco-editor')).to have_content('config/initializers/secret_token.rb') end end diff --git a/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb b/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb index cdf6c219ea5..46ac0dee7eb 100644 --- a/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb +++ b/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb @@ -30,8 +30,8 @@ RSpec.describe 'Projects > Files > User wants to add a .gitlab-ci.yml file', :js wait_for_requests expect(page).to have_css('.gitlab-ci-yml-selector .dropdown-toggle-text', text: 'Apply a template') - expect(editor_get_value).to have_content('This file is a template, and might need editing before it works on your project') - expect(editor_get_value).to have_content('jekyll build -d test') + expect(find('.monaco-editor')).to have_content('This file is a template, and might need editing before it works on your project') + expect(find('.monaco-editor')).to have_content('jekyll build -d test') end context 'when template param is provided' do @@ -41,8 +41,8 @@ RSpec.describe 'Projects > Files > User wants to add a .gitlab-ci.yml file', :js wait_for_requests expect(page).to have_css('.gitlab-ci-yml-selector .dropdown-toggle-text', text: 'Apply a template') - expect(editor_get_value).to have_content('This file is a template, and might need editing before it works on your project') - expect(editor_get_value).to have_content('jekyll build -d test') + expect(find('.monaco-editor')).to have_content('This file is a template, and might need editing before it works on your project') + expect(find('.monaco-editor')).to have_content('jekyll build -d test') end end @@ -53,7 +53,7 @@ RSpec.describe 'Projects > Files > User wants to add a .gitlab-ci.yml file', :js wait_for_requests expect(page).to have_css('.gitlab-ci-yml-selector .dropdown-toggle-text', text: 'Apply a template') - expect(editor_get_value).to have_content('') + expect(find('.monaco-editor')).to have_content('') end end @@ -64,7 +64,7 @@ RSpec.describe 'Projects > Files > User wants to add a .gitlab-ci.yml file', :js it 'leaves the editor empty' do wait_for_requests - expect(editor_get_value).to have_content('') + expect(find('.monaco-editor')).to have_content('') end end end diff --git a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb index 0e87622d3c2..6b1e60db5b1 100644 --- a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb +++ b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb @@ -22,8 +22,10 @@ RSpec.describe 'Projects > Files > Project owner sees a link to create a license select_template('MIT License') - expect(ide_editor_value).to have_content('MIT License') - expect(ide_editor_value).to have_content("Copyright (c) #{Time.zone.now.year} #{project.namespace.human_name}") + file_content = "Copyright (c) #{Time.zone.now.year} #{project.namespace.human_name}" + + expect(find('.monaco-editor')).to have_content('MIT License') + expect(find('.monaco-editor')).to have_content(file_content) ide_commit @@ -33,7 +35,7 @@ RSpec.describe 'Projects > Files > Project owner sees a link to create a license license_file = project.repository.blob_at('master', 'LICENSE').data expect(license_file).to have_content('MIT License') - expect(license_file).to have_content("Copyright (c) #{Time.zone.now.year} #{project.namespace.human_name}") + expect(license_file).to have_content(file_content) end def select_template(template) diff --git a/spec/features/projects/jobs/permissions_spec.rb b/spec/features/projects/jobs/permissions_spec.rb index a904ba770dd..b6019944071 100644 --- a/spec/features/projects/jobs/permissions_spec.rb +++ b/spec/features/projects/jobs/permissions_spec.rb @@ -12,8 +12,6 @@ RSpec.describe 'Project Jobs Permissions' do let_it_be(:job) { create(:ci_build, :running, :coverage, :trace_artifact, pipeline: pipeline) } before do - stub_feature_flags(jobs_table_vue: false) - sign_in(user) project.enable_ci @@ -96,8 +94,8 @@ RSpec.describe 'Project Jobs Permissions' do end it_behaves_like 'project jobs page responds with status', 200 do - it 'renders job' do - page.within('.build') do + it 'renders job', :js do + page.within('[data-testid="jobs-table"]') do expect(page).to have_content("##{job.id}") .and have_content(job.sha[0..7]) .and have_content(job.ref) diff --git a/spec/features/projects/jobs/user_browses_job_spec.rb b/spec/features/projects/jobs/user_browses_job_spec.rb index 6a2d2c36521..6a0cfcde812 100644 --- a/spec/features/projects/jobs/user_browses_job_spec.rb +++ b/spec/features/projects/jobs/user_browses_job_spec.rb @@ -90,4 +90,27 @@ RSpec.describe 'User browses a job', :js do end end end + + context 'job log search' do + before do + visit(project_job_path(project, build)) + wait_for_all_requests + end + + it 'searches for supplied substring' do + find('[data-testid="job-log-search-box"] input').set('GroupsHelper') + + find('[data-testid="search-button"]').click + + expect(page).to have_content('26 results found for GroupsHelper') + end + + it 'shows no results for supplied substring' do + find('[data-testid="job-log-search-box"] input').set('YouWontFindMe') + + find('[data-testid="search-button"]').click + + expect(page).to have_content('No search results found') + end + end end diff --git a/spec/features/projects/jobs/user_browses_jobs_spec.rb b/spec/features/projects/jobs/user_browses_jobs_spec.rb index 07b7a54974a..bb44b70bb3a 100644 --- a/spec/features/projects/jobs/user_browses_jobs_spec.rb +++ b/spec/features/projects/jobs/user_browses_jobs_spec.rb @@ -9,48 +9,11 @@ def visit_jobs_page end RSpec.describe 'User browses jobs' do - describe 'with jobs_table_vue feature flag turned off' do - let!(:build) { create(:ci_build, :coverage, pipeline: pipeline) } - let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') } - let(:project) { create(:project, :repository, namespace: user.namespace) } - let(:user) { create(:user) } - - before do - stub_feature_flags(jobs_table_vue: false) - project.add_maintainer(user) - project.enable_ci - build.update!(coverage_regex: '/Coverage (\d+)%/') - - sign_in(user) - - visit(project_jobs_path(project)) - end - - it 'shows the coverage' do - page.within('td.coverage') do - expect(page).to have_content('99.9%') - end - end - - context 'with a failed job' do - let!(:build) { create(:ci_build, :coverage, :failed, pipeline: pipeline) } - - it 'displays a tooltip with the failure reason' do - page.within('.ci-table') do - failed_job_link = page.find('.ci-failed') - expect(failed_job_link[:title]).to eq('Failed - (unknown failure)') - end - end - end - end - - describe 'with jobs_table_vue feature flag turned on', :js do + describe 'Jobs', :js do let(:project) { create(:project, :repository) } let(:user) { create(:user) } before do - stub_feature_flags(jobs_table_vue: true) - project.add_maintainer(user) project.enable_ci @@ -135,6 +98,26 @@ RSpec.describe 'User browses jobs' do end end + context 'with a coverage job' do + let!(:job) do + create(:ci_build, :coverage, pipeline: pipeline) + end + + before do + job.update!(coverage_regex: '/Coverage (\d+)%/') + + visit_jobs_page + + wait_for_requests + end + + it 'shows the coverage' do + page.within('[data-testid="job-coverage"]') do + expect(page).to have_content('99.9%') + end + end + end + context 'with a scheduled job' do let!(:scheduled_job) { create(:ci_build, :scheduled, pipeline: pipeline, name: 'build') } diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index f0d41c1dd11..84c75752bc1 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -20,7 +20,6 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do end before do - stub_feature_flags(jobs_table_vue: false) project.add_role(user, user_access_level) sign_in(user) end @@ -29,9 +28,11 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do context 'with no jobs' do before do visit project_jobs_path(project) + + wait_for_requests end - it 'shows the empty state page' do + it 'shows the empty state page', :js do expect(page).to have_content('Use jobs to automate your tasks') expect(page).to have_link('Create CI/CD configuration file', href: project_ci_pipeline_editor_path(project)) end @@ -40,59 +41,6 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do context 'with a job' do let!(:job) { create(:ci_build, pipeline: pipeline) } - context "Pending scope" do - before do - visit project_jobs_path(project, scope: :pending) - end - - it "shows Pending tab jobs" do - expect(page).to have_selector('[data-testid="jobs-tabs"] a.active', text: 'Pending') - expect(page).to have_content job.short_sha - expect(page).to have_content job.ref - expect(page).to have_content job.name - end - end - - context "Running scope" do - before do - job.run! - visit project_jobs_path(project, scope: :running) - end - - it "shows Running tab jobs" do - expect(page).to have_selector('[data-testid="jobs-tabs"] a.active', text: 'Running') - expect(page).to have_content job.short_sha - expect(page).to have_content job.ref - expect(page).to have_content job.name - end - end - - context "Finished scope" do - before do - job.run! - visit project_jobs_path(project, scope: :finished) - end - - it "shows Finished tab jobs" do - expect(page).to have_selector('[data-testid="jobs-tabs"] a.active', text: 'Finished') - expect(page).to have_content('Use jobs to automate your tasks') - end - end - - context "All jobs" do - before do - project.builds.running_or_pending.each(&:success) - visit project_jobs_path(project) - end - - it "shows All tab jobs" do - expect(page).to have_selector('[data-testid="jobs-tabs"] a.active', text: 'All') - expect(page).to have_content job.short_sha - expect(page).to have_content job.ref - expect(page).to have_content job.name - end - end - context "when visiting old URL" do let(:jobs_url) do project_jobs_path(project) @@ -1207,22 +1155,4 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do it { expect(page.status_code).to eq(404) } end end - - describe "GET /:project/jobs/:id/status" do - context "Job from project" do - before do - visit status_project_job_path(project, job) - end - - it { expect(page.status_code).to eq(200) } - end - - context "Job from other project" do - before do - visit status_project_job_path(project, job2) - end - - it { expect(page.status_code).to eq(404) } - end - end end diff --git a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb index bd0874316ac..c92e8bc2954 100644 --- a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb +++ b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb @@ -32,7 +32,7 @@ RSpec.describe 'Projects > Members > Maintainer adds member with expiration date end it 'changes expiration date' do - project.team.add_users([new_member.id], :developer, expires_at: three_days_from_now) + project.team.add_members([new_member.id], :developer, expires_at: three_days_from_now) visit project_project_members_path(project) page.within find_member_row(new_member) do @@ -46,7 +46,7 @@ RSpec.describe 'Projects > Members > Maintainer adds member with expiration date end it 'clears expiration date' do - project.team.add_users([new_member.id], :developer, expires_at: five_days_from_now) + project.team.add_members([new_member.id], :developer, expires_at: five_days_from_now) visit project_project_members_path(project) page.within find_member_row(new_member) do diff --git a/spec/features/projects/navbar_spec.rb b/spec/features/projects/navbar_spec.rb index 023601b0b1e..e07a5d09405 100644 --- a/spec/features/projects/navbar_spec.rb +++ b/spec/features/projects/navbar_spec.rb @@ -49,7 +49,7 @@ RSpec.describe 'Project navbar' do stub_config(pages: { enabled: true }) insert_after_sub_nav_item( - _('CI/CD'), + _('Packages & Registries'), within: _('Settings'), new_sub_nav_item_name: _('Pages') ) @@ -60,18 +60,22 @@ RSpec.describe 'Project navbar' do it_behaves_like 'verified navigation bar' end + context 'when package registry is available' do + before do + stub_config(packages: { enabled: true }) + + visit project_path(project) + end + + it_behaves_like 'verified navigation bar' + end + context 'when container registry is available' do before do stub_config(registry: { enabled: true }) insert_container_nav - insert_after_sub_nav_item( - _('CI/CD'), - within: _('Settings'), - new_sub_nav_item_name: _('Packages & Registries') - ) - visit project_path(project) end diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb index a1e92a79516..9d2d1454d77 100644 --- a/spec/features/projects/new_project_spec.rb +++ b/spec/features/projects/new_project_spec.rb @@ -61,15 +61,15 @@ RSpec.describe 'New project', :js do expect(page).to have_link('GitLab export') end - describe 'github import option' do + shared_examples 'renders importer link' do |params| context 'with user namespace' do before do visit new_project_path click_link 'Import project' end - it 'renders link to github importer' do - expect(page).to have_link(href: new_import_github_path) + it "renders link to #{params[:name]} importer" do + expect(page).to have_link(href: Rails.application.routes.url_helpers.send(params[:route])) end end @@ -82,21 +82,56 @@ RSpec.describe 'New project', :js do click_link 'Import project' end - it 'renders link to github importer including namespace id' do - expect(page).to have_link(href: new_import_github_path(namespace_id: group.id)) + it "renders link to #{params[:name]} importer including namespace id" do + expect(page).to have_link(href: Rails.application.routes.url_helpers.send(params[:route], namespace_id: group.id)) end end end - describe 'manifest import option' do - before do - visit new_project_path + describe 'importer links' do + shared_examples 'link to importers' do + let(:importer_routes) do + { + 'github': :new_import_github_path, + 'bitbucket': :status_import_bitbucket_path, + 'bitbucket server': :status_import_bitbucket_server_path, + 'gitlab.com': :status_import_gitlab_path, + 'fogbugz': :new_import_fogbugz_path, + 'gitea': :new_import_gitea_path, + 'manifest': :new_import_manifest_path, + 'phabricator': :new_import_phabricator_path + } + end + + it 'renders links to several importers', :aggregate_failures do + importer_routes.each_value do |route| + expect(page).to have_link(href: Rails.application.routes.url_helpers.send(route, link_params)) + end + end + end - click_link 'Import project' + context 'with user namespace' do + let(:link_params) { {} } + + before do + visit new_project_path + click_link 'Import project' + end + + include_examples 'link to importers' end - it 'has Manifest file' do - expect(page).to have_link('Manifest file') + context 'with group namespace' do + let(:group) { create(:group, :private) } + let(:link_params) { { namespace_id: group.id } } + + before do + group.add_owner(user) + visit new_project_path(namespace_id: group.id) + click_link 'Import project' + end + + include_examples 'link to importers' end end diff --git a/spec/features/projects/pipelines/legacy_pipelines_spec.rb b/spec/features/projects/pipelines/legacy_pipelines_spec.rb index 3f89e344c51..15d889933bf 100644 --- a/spec/features/projects/pipelines/legacy_pipelines_spec.rb +++ b/spec/features/projects/pipelines/legacy_pipelines_spec.rb @@ -357,6 +357,10 @@ RSpec.describe 'Pipelines', :js do end it 'enqueues the delayed job', :js do + find('[data-testid="mini-pipeline-graph-dropdown"]').click + + within('[data-testid="mini-pipeline-graph-dropdown"]') { find('.ci-status-icon-pending') } + expect(delayed_job.reload).to be_pending end end diff --git a/spec/features/projects/releases/user_creates_release_spec.rb b/spec/features/projects/releases/user_creates_release_spec.rb index 9e428a0623d..10c4395da81 100644 --- a/spec/features/projects/releases/user_creates_release_spec.rb +++ b/spec/features/projects/releases/user_creates_release_spec.rb @@ -111,6 +111,27 @@ RSpec.describe 'User creates release', :js do end end + context 'when tag name supplied in the parameters' do + let(:new_page_url) { new_project_release_path(project, tag_name: 'v1.1.0') } + + it 'creates release with preselected tag' do + page.within '[data-testid="tag-name-field"]' do + expect(page).to have_text('v1.1.0') + end + + expect(page).not_to have_selector('[data-testid="create-from-field"]') + + fill_release_title("test release") + click_button('Create release') + + wait_for_all_requests + + release = project.releases.last + + expect(release.tag).to eq('v1.1.0') + end + end + def fill_out_form_and_submit select_new_tag_name(tag_name) diff --git a/spec/features/projects/settings/registry_settings_spec.rb b/spec/features/projects/settings/registry_settings_spec.rb index ff28d59ed08..9468540736f 100644 --- a/spec/features/projects/settings/registry_settings_spec.rb +++ b/spec/features/projects/settings/registry_settings_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration policy', :js do +RSpec.describe 'Project > Settings > Packages & Registries > Container registry tag expiration policy', :js do let_it_be(:user) { create(:user) } let_it_be(:project, reload: true) { create(:project, namespace: user.namespace) } @@ -23,14 +23,15 @@ RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration p it 'shows available section' do subject - settings_block = find('[data-testid="registry-settings-app"]') + settings_block = find('[data-testid="container-expiration-policy-project-settings"]') expect(settings_block).to have_text 'Clean up image tags' end it 'saves cleanup policy submit the form' do subject - within '[data-testid="registry-settings-app"]' do + within '[data-testid="container-expiration-policy-project-settings"]' do + click_button('Expand') select('Every day', from: 'Run cleanup') select('50 tags per image name', from: 'Keep the most recent:') fill_in('Keep tags matching:', with: 'stable') @@ -48,7 +49,8 @@ RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration p it 'does not save cleanup policy submit form with invalid regex' do subject - within '[data-testid="registry-settings-app"]' do + within '[data-testid="container-expiration-policy-project-settings"]' do + click_button('Expand') fill_in('Remove tags matching:', with: '*-production') submit_button = find('[data-testid="save-button"') @@ -73,7 +75,8 @@ RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration p it 'displays the related section' do subject - within '[data-testid="registry-settings-app"]' do + within '[data-testid="container-expiration-policy-project-settings"]' do + click_button('Expand') expect(find('[data-testid="enable-toggle"]')).to have_content('Disabled - Tags will not be automatically deleted.') end end @@ -87,7 +90,8 @@ RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration p it 'does not display the related section' do subject - within '[data-testid="registry-settings-app"]' do + within '[data-testid="container-expiration-policy-project-settings"]' do + click_button('Expand') expect(find('.gl-alert-title')).to have_content('Cleanup policy for tags is disabled') end end @@ -100,7 +104,7 @@ RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration p it 'does not exists' do subject - expect(page).not_to have_selector('[data-testid="registry-settings-app"]') + expect(page).not_to have_selector('[data-testid="container-expiration-policy-project-settings"]') end end @@ -110,7 +114,7 @@ RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration p it 'does not exists' do subject - expect(page).not_to have_selector('[data-testid="registry-settings-app"]') + expect(page).not_to have_selector('[data-testid="container-expiration-policy-project-settings"]') end end end diff --git a/spec/features/projects/settings/repository_settings_spec.rb b/spec/features/projects/settings/repository_settings_spec.rb index 72ada356225..ddfed73e2ca 100644 --- a/spec/features/projects/settings/repository_settings_spec.rb +++ b/spec/features/projects/settings/repository_settings_spec.rb @@ -179,7 +179,6 @@ RSpec.describe 'Projects > Settings > Repository settings' do expect(page).to have_css(".js-mirror-url-hidden[value=\"#{ssh_url}\"]", visible: false) select 'SSH public key', from: 'Authentication method' - select_direction Sidekiq::Testing.fake! do diff --git a/spec/features/projects/settings/secure_files_settings_spec.rb b/spec/features/projects/settings/secure_files_settings_spec.rb deleted file mode 100644 index c7c9cafc420..00000000000 --- a/spec/features/projects/settings/secure_files_settings_spec.rb +++ /dev/null @@ -1,46 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'Secure Files Settings' do - let_it_be(:maintainer) { create(:user) } - let_it_be(:project) { create(:project, creator_id: maintainer.id) } - - before_all do - project.add_maintainer(maintainer) - end - - context 'when the :ci_secure_files feature flag is enabled' do - before do - stub_feature_flags(ci_secure_files: true) - - sign_in(user) - visit project_settings_ci_cd_path(project) - end - - context 'authenticated user with admin permissions' do - let(:user) { maintainer } - - it 'shows the secure files settings' do - expect(page).to have_content('Secure Files') - end - end - end - - context 'when the :ci_secure_files feature flag is disabled' do - before do - stub_feature_flags(ci_secure_files: false) - - sign_in(user) - visit project_settings_ci_cd_path(project) - end - - context 'authenticated user with admin permissions' do - let(:user) { maintainer } - - it 'does not shows the secure files settings' do - expect(page).not_to have_content('Secure Files') - end - end - end -end diff --git a/spec/features/projects/settings/secure_files_spec.rb b/spec/features/projects/settings/secure_files_spec.rb new file mode 100644 index 00000000000..ee38acf1953 --- /dev/null +++ b/spec/features/projects/settings/secure_files_spec.rb @@ -0,0 +1,101 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Secure Files', :js do + let(:project) { create(:project) } + let(:user) { create(:user) } + + before do + stub_feature_flags(ci_secure_files_read_only: false) + project.add_maintainer(user) + sign_in(user) + end + + context 'when the :ci_secure_files feature flag is enabled' do + before do + stub_feature_flags(ci_secure_files: true) + + visit project_settings_ci_cd_path(project) + end + + context 'authenticated user with admin permissions' do + it 'shows the secure files settings' do + expect(page).to have_content('Secure Files') + end + end + end + + context 'when the :ci_secure_files feature flag is disabled' do + before do + stub_feature_flags(ci_secure_files: false) + + visit project_settings_ci_cd_path(project) + end + + context 'authenticated user with admin permissions' do + it 'does not shows the secure files settings' do + expect(page).not_to have_content('Secure Files') + end + end + end + + it 'user sees the Secure Files list component' do + visit project_settings_ci_cd_path(project) + + within '#js-secure-files' do + expect(page).to have_content('There are no secure files yet.') + end + end + + it 'prompts the user to confirm before deleting a file' do + file = create(:ci_secure_file, project: project) + + visit project_settings_ci_cd_path(project) + + within '#js-secure-files' do + expect(page).to have_content(file.name) + + find('button.btn-danger-secondary').click + end + + expect(page).to have_content("Delete #{file.name}?") + + click_on('Delete secure file') + + visit project_settings_ci_cd_path(project) + + within '#js-secure-files' do + expect(page).not_to have_content(file.name) + end + end + + it 'displays an uploaded file in the file list' do + visit project_settings_ci_cd_path(project) + + within '#js-secure-files' do + expect(page).to have_content('There are no secure files yet.') + + page.attach_file('spec/fixtures/ci_secure_files/upload-keystore.jks') do + click_button 'Upload File' + end + + expect(page).to have_content('upload-keystore.jks') + end + end + + it 'displays an error when a duplicate file upload is attempted' do + create(:ci_secure_file, project: project, name: 'upload-keystore.jks') + visit project_settings_ci_cd_path(project) + + within '#js-secure-files' do + expect(page).to have_content('upload-keystore.jks') + + page.attach_file('spec/fixtures/ci_secure_files/upload-keystore.jks') do + click_button 'Upload File' + end + + expect(page).to have_content('A file with this name already exists.') + end + end +end diff --git a/spec/features/projects/settings/visibility_settings_spec.rb b/spec/features/projects/settings/visibility_settings_spec.rb index becb30c02b7..fc78b5b5769 100644 --- a/spec/features/projects/settings/visibility_settings_spec.rb +++ b/spec/features/projects/settings/visibility_settings_spec.rb @@ -16,7 +16,7 @@ RSpec.describe 'Projects > Settings > Visibility settings', :js do visibility_select_container = find('.project-visibility-setting') expect(visibility_select_container.find('select').value).to eq project.visibility_level.to_s - expect(visibility_select_container).to have_content 'The project can be accessed by anyone, regardless of authentication.' + expect(visibility_select_container).to have_content 'Accessible by anyone, regardless of authentication.' end it 'project visibility description updates on change' do @@ -25,7 +25,7 @@ RSpec.describe 'Projects > Settings > Visibility settings', :js do visibility_select.select('Private') expect(visibility_select.value).to eq '0' - expect(visibility_select_container).to have_content 'Access must be granted explicitly to each user.' + expect(visibility_select_container).to have_content 'Only accessible by project members. Membership must be explicitly granted to each user.' end context 'merge requests select' do @@ -86,7 +86,7 @@ RSpec.describe 'Projects > Settings > Visibility settings', :js do visibility_select_container = find('.project-visibility-setting') expect(visibility_select_container).to have_selector 'select[name="project[visibility_level]"]:disabled' - expect(visibility_select_container).to have_content 'The project can be accessed by anyone, regardless of authentication.' + expect(visibility_select_container).to have_content 'Accessible by anyone, regardless of authentication.' end context 'disable email notifications' do diff --git a/spec/features/projects/show/user_interacts_with_auto_devops_banner_spec.rb b/spec/features/projects/show/user_interacts_with_auto_devops_banner_spec.rb index 59f1bc94226..262885e09b3 100644 --- a/spec/features/projects/show/user_interacts_with_auto_devops_banner_spec.rb +++ b/spec/features/projects/show/user_interacts_with_auto_devops_banner_spec.rb @@ -7,7 +7,7 @@ RSpec.describe 'Project > Show > User interacts with auto devops implicitly enab let(:user) { create(:user) } before do - project.add_user(user, role) + project.add_member(user, role) sign_in(user) end diff --git a/spec/features/projects/show/user_sees_collaboration_links_spec.rb b/spec/features/projects/show/user_sees_collaboration_links_spec.rb index 552f068ecc7..fb2f0539558 100644 --- a/spec/features/projects/show/user_sees_collaboration_links_spec.rb +++ b/spec/features/projects/show/user_sees_collaboration_links_spec.rb @@ -90,7 +90,7 @@ RSpec.describe 'Projects > Show > Collaboration links', :js do with_them do before do project.project_feature.update!({ merge_requests_access_level: merge_requests_access_level }) - project.add_user(user, user_level) + project.add_member(user, user_level) visit project_path(project) end diff --git a/spec/features/projects/tags/user_edits_tags_spec.rb b/spec/features/projects/tags/user_edits_tags_spec.rb index 17080043b6d..c8438b73dc3 100644 --- a/spec/features/projects/tags/user_edits_tags_spec.rb +++ b/spec/features/projects/tags/user_edits_tags_spec.rb @@ -5,17 +5,58 @@ require 'spec_helper' RSpec.describe 'Project > Tags', :js do include DropzoneHelper - let(:user) { create(:user) } - let(:role) { :developer } - let(:project) { create(:project, :repository) } + let_it_be(:user) { create(:user) } + let_it_be(:role) { :developer } + let_it_be(:project) { create(:project, :repository) } before do sign_in(user) project.add_role(user, role) end + shared_examples "can create and update release" do + it 'can create new release' do + visit page_url + page.find("a[href=\"#{new_project_release_path(project, tag_name: 'v1.1.0')}\"]").click + + fill_in "Release notes", with: "new release from tag" + expect(page).not_to have_field("Create from") + click_button "Create release" + + expect(page).to have_current_path(project_release_path(project, 'v1.1.0')) + expect(Release.last.description).to eq("new release from tag") + end + + it 'can edit existing release' do + release = create(:release, project: project, tag: 'v1.1.0') + + visit page_url + page.find("a[href=\"#{edit_project_release_path(project, release)}\"]").click + + fill_in "Release notes", with: "updated release desc" + click_button "Save changes" + + expect(page).to have_current_path(project_release_path(project, 'v1.1.0')) + expect(release.reload.description).to eq("updated release desc") + end + end + + context 'when visiting tags index page' do + let(:page_url) { project_tags_path(project) } + + include_examples "can create and update release" + end + + context 'when visiting individual tag page' do + let(:page_url) { project_tag_path(project, 'v1.1.0') } + + include_examples "can create and update release" + end + + # TODO: remove most of these together with FF https://gitlab.com/gitlab-org/gitlab/-/issues/366244 describe 'when opening project tags' do before do + stub_feature_flags(edit_tag_release_notes_via_release_page: false) visit project_tags_path(project) end diff --git a/spec/features/projects/tracings_spec.rb b/spec/features/projects/tracings_spec.rb deleted file mode 100644 index b79a0427ef6..00000000000 --- a/spec/features/projects/tracings_spec.rb +++ /dev/null @@ -1,60 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'Tracings Content Security Policy' do - include ContentSecurityPolicyHelpers - - let_it_be(:project) { create(:project) } - let_it_be(:user) { create(:user) } - - subject { response_headers['Content-Security-Policy'] } - - before_all do - project.add_maintainer(user) - end - - before do - sign_in(user) - end - - context 'when there is no global config' do - before do - setup_csp_for_controller(Projects::TracingsController) - end - - it 'does not add CSP directives' do - visit project_tracing_path(project) - - is_expected.to be_blank - end - end - - context 'when a global CSP config exists' do - before do - csp = ActionDispatch::ContentSecurityPolicy.new do |p| - p.frame_src 'https://global-policy.com' - end - - setup_existing_csp_for_controller(Projects::TracingsController, csp) - end - - context 'when external_url is set' do - let!(:project_tracing_setting) { create(:project_tracing_setting, project: project) } - - it 'overwrites frame-src' do - visit project_tracing_path(project) - - is_expected.to eq("frame-src https://example.com") - end - end - - context 'when external_url is not set' do - it 'uses global policy' do - visit project_tracing_path(project) - - is_expected.to eq("frame-src https://global-policy.com") - end - end - end -end |