Commit 2fd86671 authored by Mark Lapierre's avatar Mark Lapierre

Merge branch '353393-blob-refactor-disabled-coverage' into 'master'

Ensure we have sufficient test coverage for viewing blobs

See merge request gitlab-org/gitlab!81510
parents 50cec3d8 eb83eeb6
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Path Locks', :js do
let(:user) { create(:user) }
let(:project) { create(:project, :repository, namespace: user.namespace) }
let(:tree_path) { project_tree_path(project, project.repository.root_ref) }
before do
allow(project).to receive(:feature_available?).with(:file_locks) { true }
stub_feature_flags(bootstrap_confirmation_modals: false)
stub_feature_flags(refactor_blob_viewer: false)
project.add_maintainer(user)
sign_in(user)
visit tree_path
wait_for_requests
end
it 'locking folders' do
within '.tree-content-holder' do
click_link "encoding"
end
find('.js-path-lock').click
wait_for_requests
page.within '.modal' do
expect(page).to have_selector('.modal-body', visible: true)
expect(page).to have_css('.modal-body', text: 'Are you sure you want to lock this directory?')
click_button "OK"
end
expect(page).to have_link('Unlock')
end
it 'locking files' do
page_tree = find('.tree-content-holder')
within page_tree do
click_link "VERSION"
end
within '.file-actions' do
click_link "Lock"
end
page.within '.modal' do
expect(page).to have_css('.modal-body', text: 'Are you sure you want to lock VERSION?')
click_button "OK"
end
expect(page).to have_link('Unlock')
end
it 'unlocking files' do
page_tree = find('.tree-content-holder')
within page_tree do
click_link "VERSION"
end
within '.file-actions' do
click_link "Lock"
end
page.within '.modal' do
expect(page).to have_css('.modal-body', text: 'Are you sure you want to lock VERSION?')
click_button "OK"
end
expect(page).to have_link('Lock')
end
it 'managing of lock list' do
create :path_lock, path: 'encoding', user: user, project: project
click_link "Locked Files"
within '.locks' do
expect(page).to have_content('encoding')
accept_confirm(text: 'Are you sure you want to unlock encoding?') { click_link "Unlock" }
expect(page).not_to have_content('encoding')
end
end
end
......@@ -1033,71 +1033,6 @@ RSpec.describe 'File blob', :js do
stub_feature_flags(refactor_blob_viewer: false)
end
context 'when ref switch' 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/351558
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
end
context 'when highlighting lines' do
it 'displays single highlighted line number of different ref' do
visit_blob('files/js/application.js', anchor: 'L1')
switch_ref_to('feature')
page.within '.blob-content' do
expect(find_by_id('LC1')[:class]).to include("hll")
end
end
it 'displays multiple highlighted line numbers of different ref' do
visit_blob('files/js/application.js', anchor: 'L1-3')
switch_ref_to('feature')
page.within '.blob-content' do
expect(find_by_id('LC1')[:class]).to include("hll")
expect(find_by_id('LC2')[:class]).to include("hll")
expect(find_by_id('LC3')[:class]).to include("hll")
end
end
end
end
context 'visiting with a line number anchor' 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/351558
before do
visit_blob('files/markdown/ruby-style-guide.md', anchor: 'L1')
end
it 'displays the blob using the simple 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"]')
# highlights the line in question
expect(page).to have_selector('#LC1.hll')
# 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
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
......@@ -1158,503 +1093,5 @@ RSpec.describe 'File blob', :js do
end
end
end
context 'files with auxiliary viewers' do
# This context is the same as the other 'files with auxiliary viewers' in this file, we just ensure that the auxiliary viewers still work this the refactor_blob_viewer disabled
# It should be safe to remove once we rollout the refactored blob viewer
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
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.')
# shows a learn more link
expect(page).to have_link('Learn more')
end
end
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')
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.')
# shows a learn more link
expect(page).to have_link('Learn more')
end
end
end
describe '.gitlab/dashboards/custom-dashboard.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/dashboards/custom-dashboard.yml",
file_path: '.gitlab/dashboards/custom-dashboard.yml',
file_content: file_content
).execute
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')) }
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
end
end
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")
# 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 '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.')
# 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'" }
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
end
end
end
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.')
# 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
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.')
# shows a learn more link
expect(page).to have_link('Learn more', href: 'https://rubygems.org/')
end
end
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'
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
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
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'
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
end
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
end
end
context 'Gemfile' do
before do
file_name = 'Gemfile'
create_file(file_name, '
source "https://rubygems.org"
# 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
end
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
end
end
context 'go.mod' do
before do
file_name = 'go.mod'
create_file(file_name, '
module example.com/mymodule
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
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
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'
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
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
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 '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
end
end
context 'requirements.txt' do
before do
file_name = 'requirements.txt'
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 pip.")
end
end
end
context 'yarn.lock' do
before do
file_name = 'yarn.lock'
create_file(file_name, '
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
')
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
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')
wait_for_requests
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
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Balsamiq file blob', :js do
let(:project) { create(:project, :public, :repository) }
before do
stub_feature_flags(refactor_blob_viewer: false)
visit project_blob_path(project, 'add-balsamiq-file/files/images/balsamiq.bmpr')
wait_for_requests
end
it 'displays Balsamiq file content' do
expect(page).to have_content("Mobile examples")
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Blob button line permalinks (BlobLinePermalinkUpdater)', :js do
include TreeHelper
let(:project) { create(:project, :public, :repository) }
let(:path) { 'CHANGELOG' }
let(:sha) { project.repository.commit.sha }
before do
stub_feature_flags(refactor_blob_viewer: false)
end
describe 'On a file(blob)' do
def get_absolute_url(path = "")
"http://#{page.server.host}:#{page.server.port}#{path}"
end
def visit_blob(fragment = nil)
visit project_blob_path(project, tree_join('master', path), anchor: fragment)
end
describe 'Click "Permalink" button' do
it 'works with no initial line number fragment hash' do
visit_blob
expect(find('.js-data-file-blob-permalink-url')['href']).to eq(get_absolute_url(project_blob_path(project, tree_join(sha, path))))
end
it 'maintains intitial fragment hash' do
fragment = "L3"
visit_blob(fragment)
expect(find('.js-data-file-blob-permalink-url')['href']).to eq(get_absolute_url(project_blob_path(project, tree_join(sha, path), anchor: fragment)))
end
it 'changes fragment hash if line number clicked' do
ending_fragment = "L5"
visit_blob
find('#L3').click
find("##{ending_fragment}").click
expect(find('.js-data-file-blob-permalink-url')['href']).to eq(get_absolute_url(project_blob_path(project, tree_join(sha, path), anchor: ending_fragment)))
end
it 'with initial fragment hash, changes fragment hash if line number clicked' do
fragment = "L1"
ending_fragment = "L5"
visit_blob(fragment)
find('#L3').click
find("##{ending_fragment}").click
expect(find('.js-data-file-blob-permalink-url')['href']).to eq(get_absolute_url(project_blob_path(project, tree_join(sha, path), anchor: ending_fragment)))
end
end
describe 'Click "Blame" button' do
it 'works with no initial line number fragment hash' do
visit_blob
expect(find('.js-blob-blame-link')['href']).to eq(get_absolute_url(project_blame_path(project, tree_join('master', path))))
end
it 'maintains intitial fragment hash' do
fragment = "L3"
visit_blob(fragment)
expect(find('.js-blob-blame-link')['href']).to eq(get_absolute_url(project_blame_path(project, tree_join('master', path), anchor: fragment)))
end
it 'changes fragment hash if line number clicked' do
ending_fragment = "L5"
visit_blob
find('#L3').click
find("##{ending_fragment}").click
expect(find('.js-blob-blame-link')['href']).to eq(get_absolute_url(project_blame_path(project, tree_join('master', path), anchor: ending_fragment)))
end
it 'with initial fragment hash, changes fragment hash if line number clicked' do
fragment = "L1"
ending_fragment = "L5"
visit_blob(fragment)
find('#L3').click
find("##{ending_fragment}").click
expect(find('.js-blob-blame-link')['href']).to eq(get_absolute_url(project_blame_path(project, tree_join('master', path), anchor: ending_fragment)))
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'File blob', :js do
include MobileHelpers
let(:project) { create(:project, :public, :repository) }
before do
stub_feature_flags(refactor_blob_viewer: false)
end
def visit_blob(path, anchor: nil, ref: 'master', **additional_args)
visit project_blob_path(project, File.join(ref, path), anchor: anchor, **additional_args)
wait_for_requests
end
def create_file(file_name, content)
project.add_maintainer(project.creator)
Files::CreateService.new(
project,
project.creator,
start_branch: 'master',
branch_name: 'master',
commit_message: "Add #{file_name}",
file_path: file_name,
file_content: <<-SPEC.strip_heredoc
#{content}
SPEC
).execute
end
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/markdown/ruby-style-guide.md')
wait_for_requests
end
it 'displays the blob using the rich viewer' do
aggregate_failures do
# hides the simple viewer
expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
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')
# 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
context 'switching to the simple viewer' do
before do
find('.js-blob-viewer-switch-btn[data-viewer=simple]').click
wait_for_requests
end
it 'displays the blob using the simple viewer' do
aggregate_failures do
# hides the rich viewer
expect(page).to have_selector('.blob-viewer[data-type="simple"]')
expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
# 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).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
expect(page).to have_selector('.blob-viewer[data-type="rich"]')
# shows an enabled copy button
expect(page).to have_selector('.js-copy-blob-source-btn:not(.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
page.within '.project-refs-form' do
click_link ref_name
wait_for_requests
end
end
it 'displays single highlighted line number of different ref' do
visit_blob('files/js/application.js', anchor: 'L1')
switch_ref_to('feature')
page.within '.blob-content' do
expect(find_by_id('LC1')[:class]).to include("hll")
end
end
it 'displays multiple highlighted line numbers of different ref' do
visit_blob('files/js/application.js', anchor: 'L1-3')
switch_ref_to('feature')
page.within '.blob-content' do
expect(find_by_id('LC1')[:class]).to include("hll")
expect(find_by_id('LC2')[:class]).to include("hll")
expect(find_by_id('LC3')[:class]).to include("hll")
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
project.commit('feature').diffs.diff_files.first
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
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
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')
expect(page).not_to have_css('flash-container')
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
context 'visiting with a line number anchor' do
before do
visit_blob('files/markdown/ruby-style-guide.md', anchor: 'L1')
end
it 'displays the blob using the simple viewer' do
aggregate_failures do
# hides the rich viewer
expect(page).to have_selector('.blob-viewer[data-type="simple"]')
expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
# highlights the line in question
expect(page).to have_selector('#LC1.hll')
# 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
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 'when rendering default markdown' do
before do
visit_blob('files/commonmark/file.md')
wait_for_requests
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
end
end
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).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
expect(page).to have_selector('.blob-viewer[data-type="rich"]')
# shows an error message
expect(page).to have_content('The rendered file could not be displayed because it is stored in LFS. You can download it instead.')
# shows a viewer switcher
expect(page).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
context 'switching to the simple viewer' do
before do
find('.js-blob-viewer-switcher .js-blob-viewer-switch-btn[data-viewer=simple]').click
wait_for_requests
end
it 'displays an error' do
aggregate_failures do
# hides the rich viewer
expect(page).to have_selector('.blob-viewer[data-type="simple"]')
expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
# shows an error message
expect(page).to have_content('The source could not be displayed because it is stored in LFS. You can download it instead.')
# does not show a copy button
expect(page).not_to have_selector('.js-copy-blob-source-btn')
end
end
end
end
context 'when LFS is disabled on the project' do
before do
visit_blob('files/lfs/file.md')
wait_for_requests
end
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')
# 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
end
end
context 'PDF file' 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
visit_blob('files/test.pdf')
wait_for_requests
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 'Jupiter Notebook file' 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')
wait_for_requests
end
it 'displays the blob' do
aggregate_failures do
# shows rendered notebook
expect(page).to have_selector('.js-notebook-viewer-mounted')
# 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 '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')
wait_for_requests
end
it 'displays the blob' do
aggregate_failures do
# shows a download link
expect(page).to have_link('Download (1.5 MB)')
# 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/lfs_object.iso')
wait_for_requests
end
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')
# 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
end
end
context 'ZIP file' do
before do
visit_blob('Gemfile.zip')
wait_for_requests
end
it 'displays the blob' do
aggregate_failures do
# shows a download link
expect(page).to have_link('Download (2.11 KB)')
# 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 'empty file' do
before do
project.add_maintainer(project.creator)
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
visit_blob('files/empty.md')
wait_for_requests
end
it 'displays an error' do
aggregate_failures do
# shows an error message
expect(page).to have_content('Empty file')
# 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')
end
end
end
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
it 'displays the blob' do
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')
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
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.')
# shows a learn more link
expect(page).to have_link('Learn more')
end
end
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')
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.')
# shows a learn more link
expect(page).to have_link('Learn more')
end
end
end
describe '.gitlab/dashboards/custom-dashboard.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/dashboards/custom-dashboard.yml",
file_path: '.gitlab/dashboards/custom-dashboard.yml',
file_content: file_content
).execute
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')) }
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
end
end
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")
# 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 '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.')
# 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'" }
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
end
end
end
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.')
# 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
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.')
# shows a learn more link
expect(page).to have_link('Learn more', href: 'https://rubygems.org/')
end
end
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'
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
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
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'
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
end
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
end
end
context 'Gemfile' do
before do
file_name = 'Gemfile'
create_file(file_name, '
source "https://rubygems.org"
# 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
end
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
end
end
context 'go.mod' do
before do
file_name = 'go.mod'
create_file(file_name, '
module example.com/mymodule
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
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
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'
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
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
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 '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
end
end
context 'requirements.txt' do
before do
file_name = 'requirements.txt'
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 pip.")
end
end
end
context 'yarn.lock' do
before do
file_name = 'yarn.lock'
create_file(file_name, '
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
')
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
end
end
end
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
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
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')
expect(page).to have_selector('.file-content')
expect(page).not_to have_selector('[data-testid="alert-danger"]')
end
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
end
context 'on signed merge commit' do
it 'displays a GPG badge' do
visit_blob('conflicting-file.md', ref: '6101e87e575de14b38b4e1ce180519a813671e10')
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 'private project' do
let_it_be(:project) { create(:project, :repository, :private) }
let_it_be(:user) { create(:user) }
before do
project.add_developer(user)
sign_in(user)
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}?inline=false&token=#{user.static_object_token}"
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
context 'public project' do
before do
visit_blob('README.md')
end
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
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Editing file blob', :js do
include TreeHelper
include BlobSpecHelpers
let(:project) { create(:project, :public, :repository) }
let(:merge_request) { create(:merge_request, source_project: project, source_branch: 'feature', target_branch: 'master') }
let(:branch) { 'master' }
let(:file_path) { project.repository.ls_files(project.repository.root_ref)[1] }
let(:readme_file_path) { 'README.md' }
before do
stub_feature_flags(refactor_blob_viewer: false)
end
context 'as a developer' do
let(:user) { create(:user) }
let(:role) { :developer }
before do
project.add_role(user, role)
sign_in(user)
end
def edit_and_commit(commit_changes: true, is_diff: false)
set_default_button('edit')
refresh
wait_for_requests
if is_diff
first('.js-diff-more-actions').click
click_link('Edit in single-file editor')
else
click_link('Edit')
end
fill_editor(content: 'class NextFeature\\nend\\n')
if commit_changes
click_button 'Commit changes'
end
end
def fill_editor(content: 'class NextFeature\\nend\\n')
wait_for_requests
execute_script("monaco.editor.getModels()[0].setValue('#{content}')")
end
context 'from MR diff' do
before do
visit diffs_project_merge_request_path(project, merge_request)
edit_and_commit(is_diff: true)
end
it 'returns me to the mr' do
expect(page).to have_content(merge_request.title)
end
end
it 'updates the content of file with a number as file path' do
project.repository.create_file(user, '1', 'test', message: 'testing', branch_name: branch)
visit project_blob_path(project, tree_join(branch, '1'))
edit_and_commit
expect(page).to have_content 'NextFeature'
end
it 'editing a template file in a sub directory does not change path' do
project.repository.create_file(user, 'ci/.gitlab-ci.yml', 'test', message: 'testing', branch_name: branch)
visit project_edit_blob_path(project, tree_join(branch, 'ci/.gitlab-ci.yml'))
expect(find_by_id('file_path').value).to eq('ci/.gitlab-ci.yml')
end
it 'updating file path updates syntax highlighting' do
visit project_edit_blob_path(project, tree_join(branch, readme_file_path))
expect(find('#editor')['data-mode-id']).to eq('markdown')
find('#file_path').send_keys('foo.txt') do
expect(find('#editor')['data-mode-id']).to eq('plaintext')
end
end
context 'from blob file path' do
before do
visit project_blob_path(project, tree_join(branch, file_path))
end
it 'updates content' do
edit_and_commit
expect(page).to have_content 'successfully committed'
expect(page).to have_content 'NextFeature'
end
it 'previews content' do
edit_and_commit(commit_changes: false)
click_link 'Preview changes'
wait_for_requests
old_line_count = page.all('.line_holder.old').size
new_line_count = page.all('.line_holder.new').size
expect(old_line_count).to be > 0
expect(new_line_count).to be > 0
end
end
context 'when rendering the preview' do
it 'renders content with CommonMark' do
visit project_edit_blob_path(project, tree_join(branch, readme_file_path))
fill_editor(content: '1. one\\n - sublist\\n')
click_link 'Preview'
wait_for_requests
# the above generates two separate lists (not embedded) in CommonMark
expect(page).to have_content('sublist')
expect(page).not_to have_xpath('//ol//li//ul')
end
end
end
context 'visit blob edit' do
context 'redirects to sign in and returns' do
context 'as developer' do
let(:user) { create(:user) }
before do
project.add_developer(user)
visit project_edit_blob_path(project, tree_join(branch, file_path))
end
it 'redirects to sign in and returns' do
expect(page).to have_current_path(new_user_session_path)
gitlab_sign_in(user)
expect(page).to have_current_path(project_edit_blob_path(project, tree_join(branch, file_path)))
end
end
context 'as guest' do
let(:user) { create(:user) }
before do
visit project_edit_blob_path(project, tree_join(branch, file_path))
end
it 'redirects to sign in and returns' do
expect(page).to have_current_path(new_user_session_path)
gitlab_sign_in(user)
expect(page).to have_current_path(project_blob_path(project, tree_join(branch, file_path)))
end
end
end
context 'as developer' do
let(:user) { create(:user) }
let(:protected_branch) { 'protected-branch' }
before do
project.add_developer(user)
project.repository.add_branch(user, protected_branch, 'master')
create(:protected_branch, project: project, name: protected_branch)
sign_in(user)
end
context 'on some branch' do
before do
visit project_edit_blob_path(project, tree_join(branch, file_path))
end
it 'shows blob editor with same branch' do
expect(page).to have_current_path(project_edit_blob_path(project, tree_join(branch, file_path)))
expect(find('.js-branch-name').value).to eq(branch)
end
end
context 'with protected branch' do
it 'shows blob editor with patch branch' do
freeze_time do
visit project_edit_blob_path(project, tree_join(protected_branch, file_path))
epoch = Time.zone.now.strftime('%s%L').last(5)
expect(find('.js-branch-name').value).to eq "#{user.username}-protected-branch-patch-#{epoch}"
end
end
end
end
context 'as maintainer' do
let(:user) { create(:user) }
before do
project.add_maintainer(user)
sign_in(user)
visit project_edit_blob_path(project, tree_join(branch, file_path))
end
it 'shows blob editor with same branch' do
expect(page).to have_current_path(project_edit_blob_path(project, tree_join(branch, file_path)))
expect(find('.js-branch-name').value).to eq(branch)
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Blob shortcuts', :js do
include TreeHelper
let(:project) { create(:project, :public, :repository) }
let(:path) { project.repository.ls_files(project.repository.root_ref)[0] }
let(:sha) { project.repository.commit.sha }
before do
stub_feature_flags(refactor_blob_viewer: false)
end
describe 'On a file(blob)', :js do
def get_absolute_url(path = "")
"http://#{page.server.host}:#{page.server.port}#{path}"
end
def visit_blob(fragment = nil)
visit project_blob_path(project, tree_join('master', path), anchor: fragment)
end
describe 'pressing "y"' do
it 'redirects to permalink with commit sha' do
visit_blob
wait_for_requests
find('body').native.send_key('y')
expect(page).to have_current_path(get_absolute_url(project_blob_path(project, tree_join(sha, path))), url: true)
end
it 'maintains fragment hash when redirecting' do
fragment = "L1"
visit_blob(fragment)
wait_for_requests
find('body').native.send_key('y')
expect(page).to have_current_path(get_absolute_url(project_blob_path(project, tree_join(sha, path), anchor: fragment)), url: true)
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'User creates new blob', :js do
include WebIdeSpecHelpers
let(:user) { create(:user) }
let(:project) { create(:project, :empty_repo) }
before do
stub_feature_flags(refactor_blob_viewer: false)
end
shared_examples 'creating a file' do
it 'allows the user to add a new file in Web IDE' do
visit project_path(project)
click_link 'New file'
wait_for_requests
ide_create_new_file('dummy-file', content: "Hello world\n")
ide_commit
expect(page).to have_content('All changes are committed')
expect(project.repository.blob_at('master', 'dummy-file').data).to eql("Hello world\n")
end
end
describe 'as a maintainer' do
before do
project.add_maintainer(user)
sign_in(user)
end
it_behaves_like 'creating a file'
end
describe 'as an admin' do
let(:user) { create(:user, :admin) }
before do
sign_in(user)
gitlab_enable_admin_mode_sign_in(user)
end
it_behaves_like 'creating a file'
end
describe 'as a developer' do
before do
project.add_developer(user)
sign_in(user)
visit project_path(project)
end
it 'does not allow pushing to the default branch' do
expect(page).not_to have_content('New file')
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'User follows pipeline suggest nudge spec when feature is enabled', :js do
include CookieHelper
let(:project) { create(:project, :empty_repo) }
let(:user) { project.first_owner }
before do
stub_feature_flags(refactor_blob_viewer: false)
end
describe 'viewing the new blob page' do
before do
sign_in(user)
end
context 'when the page is loaded from the link using the suggest_gitlab_ci_yml param' do
before do
visit namespace_project_new_blob_path(namespace_id: project.namespace, project_id: project, id: 'master', suggest_gitlab_ci_yml: 'true')
end
it 'pre-fills .gitlab-ci.yml for file name' do
file_name = page.find_by_id('file_name')
expect(file_name.value).to have_content('.gitlab-ci.yml')
end
it 'chooses the .gitlab-ci.yml Template Type' do
template_type = page.find(:css, '.template-type-selector .dropdown-toggle-text')
expect(template_type.text).to have_content('.gitlab-ci.yml')
end
it 'displays suggest_gitlab_ci_yml popover' do
page.find(:css, '.gitlab-ci-yml-selector').click
popover_selector = '.suggest-gitlab-ci-yml'
expect(page).to have_css(popover_selector, visible: true)
page.within(popover_selector) do
expect(page).to have_content('1/2: Choose a template')
end
end
it 'sets the commit cookie when the Commit button is clicked' do
click_button 'Commit changes'
expect(get_cookie("suggest_gitlab_ci_yml_commit_#{project.id}")).to be_present
end
end
context 'when the page is visited without the param' do
before do
visit namespace_project_new_blob_path(namespace_id: project.namespace, project_id: project, id: 'master')
end
it 'does not pre-fill .gitlab-ci.yml for file name' do
file_name = page.find_by_id('file_name')
expect(file_name.value).not_to have_content('.gitlab-ci.yml')
end
it 'does not choose the .gitlab-ci.yml Template Type' do
template_type = page.find(:css, '.template-type-selector .dropdown-toggle-text')
expect(template_type.text).to have_content('Select a template type')
end
it 'does not display suggest_gitlab_ci_yml popover' do
popover_selector = '.b-popover.suggest-gitlab-ci-yml'
expect(page).not_to have_css(popover_selector, visible: true)
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'User views pipeline editor button on root ci config file', :js do
include BlobSpecHelpers
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public, :repository) }
before do
stub_feature_flags(refactor_blob_viewer: false)
end
context "when the ci config is the root file" do
before do
project.add_developer(user)
sign_in(user)
end
it 'shows the button to the Pipeline Editor' do
project.update!(ci_config_path: '.my-config.yml')
project.repository.create_file(user, project.ci_config_path_or_default, 'test', message: 'testing', branch_name: 'master')
visit project_blob_path(project, File.join('master', '.my-config.yml'))
expect(page).to have_content('Edit in pipeline editor')
end
it 'does not shows the Pipeline Editor button' do
project.repository.create_file(user, '.my-sub-config.yml', 'test', message: 'testing', branch_name: 'master')
visit project_blob_path(project, File.join('master', '.my-sub-config.yml'))
expect(page).not_to have_content('Edit in pipeline editor')
end
end
context "when user cannot collaborate" do
before do
sign_in(user)
end
it 'does not shows the Pipeline Editor button' do
visit project_blob_path(project, File.join('master', '.my-config.yml'))
expect(page).not_to have_content('Edit in pipeline editor')
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Projects > Files > User wants to edit a file' do
let(:project) { create(:project, :repository) }
let(:user) { project.first_owner }
let(:commit_params) do
{
start_branch: project.default_branch,
branch_name: project.default_branch,
commit_message: "Committing First Update",
file_path: ".gitignore",
file_content: "First Update",
last_commit_sha: Gitlab::Git::Commit.last_for_path(project.repository, project.default_branch,
".gitignore").sha
}
end
before do
stub_feature_flags(refactor_blob_viewer: false)
sign_in user
visit project_edit_blob_path(project,
File.join(project.default_branch, '.gitignore'))
end
it 'file has been updated since the user opened the edit page' do
Files::UpdateService.new(project, user, commit_params).execute
click_button 'Commit changes'
expect(page).to have_content 'Someone edited the file the same time you did.'
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Projects > Files > Find file keyboard shortcuts', :js do
let(:project) { create(:project, :repository) }
let(:user) { project.first_owner }
before do
stub_feature_flags(refactor_blob_viewer: false)
sign_in user
visit project_find_file_path(project, project.repository.root_ref)
wait_for_requests
end
it 'opens file when pressing enter key' do
fill_in 'file_find', with: 'CHANGELOG'
find('#file_find').native.send_keys(:enter)
expect(page).to have_selector('.blob-content-holder')
page.within('.js-file-title') do
expect(page).to have_content('CHANGELOG')
end
end
it 'navigates files with arrow keys' do
fill_in 'file_find', with: 'application.'
find('#file_find').native.send_keys(:down)
find('#file_find').native.send_keys(:enter)
expect(page).to have_selector('.blob-content-holder')
page.within('.js-file-title') do
expect(page).to have_content('application.js')
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Projects > Files > Project owner creates a license file', :js do
let(:project) { create(:project, :repository) }
let(:project_maintainer) { project.first_owner }
before do
stub_feature_flags(refactor_blob_viewer: false)
project.repository.delete_file(project_maintainer, 'LICENSE',
message: 'Remove LICENSE', branch_name: 'master')
sign_in(project_maintainer)
visit project_path(project)
end
it 'project maintainer creates a license file manually from a template' do
visit project_tree_path(project, project.repository.root_ref)
find('.add-to-tree').click
click_link 'New file'
fill_in :file_name, with: 'LICENSE'
expect(page).to have_selector('.license-selector')
select_template('MIT License')
file_content = first('.file-editor')
expect(file_content).to have_content('MIT License')
expect(file_content).to have_content("Copyright (c) #{Time.zone.now.year} #{project.namespace.human_name}")
fill_in :commit_message, with: 'Add a LICENSE file', visible: true
click_button 'Commit changes'
expect(page).to have_current_path(
project_blob_path(project, 'master/LICENSE'), ignore_query: true)
expect(page).to have_content('MIT License')
expect(page).to have_content("Copyright (c) #{Time.zone.now.year} #{project.namespace.human_name}")
end
it 'project maintainer creates a license file from the "Add license" link' do
click_link 'Add LICENSE'
expect(page).to have_content('New file')
expect(page).to have_current_path(
project_new_blob_path(project, 'master'), ignore_query: true)
expect(find('#file_name').value).to eq('LICENSE')
expect(page).to have_selector('.license-selector')
select_template('MIT License')
file_content = first('.file-editor')
expect(file_content).to have_content('MIT License')
expect(file_content).to have_content("Copyright (c) #{Time.zone.now.year} #{project.namespace.human_name}")
fill_in :commit_message, with: 'Add a LICENSE file', visible: true
click_button 'Commit changes'
expect(page).to have_current_path(
project_blob_path(project, 'master/LICENSE'), ignore_query: true)
expect(page).to have_content('MIT License')
expect(page).to have_content("Copyright (c) #{Time.zone.now.year} #{project.namespace.human_name}")
end
def select_template(template)
page.within('.js-license-selector-wrap') do
click_button 'Apply a template'
click_link template
wait_for_requests
end
end
end
# frozen_string_literal: true
require "spec_helper"
RSpec.describe "User browses files", :js do
include RepoHelpers
let(:fork_message) do
"You're not allowed to make changes to this project directly. "\
"A fork of this project has been created that you can make changes in, so you can submit a merge request."
end
let(:project) { create(:project, :repository, name: "Shop") }
let(:project2) { create(:project, :repository, name: "Another Project", path: "another-project") }
let(:tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) }
let(:user) { project.first_owner }
before do
stub_feature_flags(refactor_blob_viewer: false)
sign_in(user)
end
it "shows last commit for current directory", :js do
visit(tree_path_root_ref)
click_link("files")
last_commit = project.repository.last_commit_for_path(project.default_branch, "files")
page.within(".commit-detail") do
expect(page).to have_content(last_commit.short_id).and have_content(last_commit.author_name)
end
end
context "when browsing the master branch", :js do
before do
visit(tree_path_root_ref)
end
it "shows files from a repository" do
expect(page).to have_content("VERSION")
.and have_content(".gitignore")
.and have_content("LICENSE")
end
it "shows the `Browse Directory` link" do
click_link("files")
page.within('.repo-breadcrumb') do
expect(page).to have_link('files')
end
click_link("History")
expect(page).to have_link("Browse Directory").and have_no_link("Browse Code")
end
it "shows the `Browse File` link" do
page.within(".tree-table") do
click_link("README.md")
end
click_link("History")
expect(page).to have_link("Browse File").and have_no_link("Browse Files")
end
it "shows the `Browse Files` link" do
click_link("History")
expect(page).to have_link("Browse Files").and have_no_link("Browse Directory")
end
it "redirects to the permalink URL" do
click_link(".gitignore")
click_link("Permalink")
permalink_path = project_blob_path(project, "#{project.repository.commit.sha}/.gitignore")
expect(page).to have_current_path(permalink_path, ignore_query: true)
end
end
context "when browsing the `markdown` branch", :js do
context "when browsing the root" do
before do
visit(project_tree_path(project, "markdown"))
end
it "shows correct files and links" do
expect(page).to have_current_path(project_tree_path(project, "markdown"), ignore_query: true)
expect(page).to have_content("README.md")
.and have_content("CHANGELOG")
.and have_content("Welcome to GitLab GitLab is a free project and repository management application")
.and have_link("GitLab API doc")
.and have_link("GitLab API website")
.and have_link("Rake tasks")
.and have_link("backup and restore procedure")
.and have_link("GitLab API doc directory")
.and have_link("Maintenance")
.and have_header_with_correct_id_and_link(2, "Application details", "application-details")
.and have_link("empty", href: "")
.and have_link("#id", href: "#id")
.and have_link("/#id", href: project_blob_path(project, "markdown/README.md", anchor: "id"))
.and have_link("README.md#id", href: project_blob_path(project, "markdown/README.md", anchor: "id"))
.and have_link("d/README.md#id", href: project_blob_path(project, "markdown/db/README.md", anchor: "id"))
end
it "shows correct content of file" do
click_link("GitLab API doc")
expect(page).to have_current_path(project_blob_path(project, "markdown/doc/api/README.md"), ignore_query: true)
expect(page).to have_content("All API requests require authentication")
.and have_content("Contents")
.and have_link("Users")
.and have_link("Rake tasks")
.and have_header_with_correct_id_and_link(1, "GitLab API", "gitlab-api")
click_link("Users")
expect(page).to have_current_path(project_blob_path(project, "markdown/doc/api/users.md"), ignore_query: true)
expect(page).to have_content("Get a list of users.")
page.go_back
click_link("Rake tasks")
expect(page).to have_current_path(project_tree_path(project, "markdown/doc/raketasks"), ignore_query: true)
expect(page).to have_content("backup_restore.md").and have_content("maintenance.md")
click_link("maintenance.md")
expect(page).to have_current_path(project_blob_path(project, "markdown/doc/raketasks/maintenance.md"), ignore_query: true)
expect(page).to have_content("bundle exec rake gitlab:env:info RAILS_ENV=production")
click_link("shop")
page.within(".tree-table") do
click_link("README.md")
end
page.go_back
page.within(".tree-table") do
click_link("d")
end
expect(page).to have_link("..", href: project_tree_path(project, "markdown/"))
page.within(".tree-table") do
click_link("README.md")
end
expect(page).to have_link("empty", href: "")
end
it "shows correct content of directory" do
click_link("GitLab API doc directory")
expect(page).to have_current_path(project_tree_path(project, "markdown/doc/api"), ignore_query: true)
expect(page).to have_content("README.md").and have_content("users.md")
click_link("Users")
expect(page).to have_current_path(project_blob_path(project, "markdown/doc/api/users.md"), ignore_query: true)
expect(page).to have_content("List users").and have_content("Get a list of users.")
end
end
end
context 'when commit message has markdown', :js do
before do
project.repository.create_file(user, 'index', 'test', message: ':star: testing', branch_name: 'master')
visit(project_tree_path(project, "master"))
end
it 'renders emojis' do
expect(page).to have_selector('gl-emoji', count: 2)
end
end
context "when browsing a `improve/awesome` branch", :js do
before do
visit(project_tree_path(project, "improve/awesome"))
end
it "shows files from a repository" do
expect(page).to have_content("VERSION")
.and have_content(".gitignore")
.and have_content("LICENSE")
click_link("files")
page.within('.repo-breadcrumb') do
expect(page).to have_link('files')
end
click_link("html")
page.within('.repo-breadcrumb') do
expect(page).to have_link('html')
end
expect(page).to have_link('500.html')
end
end
context "when browsing a `Ääh-test-utf-8` branch", :js do
before do
project.repository.create_branch('Ääh-test-utf-8', project.repository.root_ref)
visit(project_tree_path(project, "Ääh-test-utf-8"))
end
it "shows files from a repository" do
expect(page).to have_content("VERSION")
.and have_content(".gitignore")
.and have_content("LICENSE")
click_link("files")
page.within('.repo-breadcrumb') do
expect(page).to have_link('files')
end
click_link("html")
page.within('.repo-breadcrumb') do
expect(page).to have_link('html')
end
expect(page).to have_link('500.html')
end
end
context "when browsing a `test-#` branch", :js do
before do
project.repository.create_branch('test-#', project.repository.root_ref)
visit(project_tree_path(project, "test-#"))
end
it "shows files from a repository" do
expect(page).to have_content("VERSION")
.and have_content(".gitignore")
.and have_content("LICENSE")
click_link("files")
page.within('.repo-breadcrumb') do
expect(page).to have_link('files')
end
click_link("html")
page.within('.repo-breadcrumb') do
expect(page).to have_link('html')
end
expect(page).to have_link('500.html')
end
end
context "when browsing a specific ref", :js do
let(:ref) { project_tree_path(project, "6d39438") }
before do
visit(ref)
end
it "shows files from a repository for `6d39438`" do
expect(page).to have_current_path(ref, ignore_query: true)
expect(page).to have_content(".gitignore").and have_content("LICENSE")
end
it "shows files from a repository with apostroph in its name" do
first(".js-project-refs-dropdown").click
page.within(".project-refs-form") do
click_link("'test'")
end
expect(page).to have_selector(".dropdown-toggle-text", text: "'test'")
visit(project_tree_path(project, "'test'"))
expect(page).not_to have_selector(".tree-commit .animation-container")
end
it "shows the code with a leading dot in the directory" do
first(".js-project-refs-dropdown").click
page.within(".project-refs-form") do
click_link("fix")
end
visit(project_tree_path(project, "fix/.testdir"))
expect(page).not_to have_selector(".tree-commit .animation-container")
end
it "does not show the permalink link" do
click_link(".gitignore")
expect(page).not_to have_link("permalink")
end
end
context "when browsing a file content", :js do
before do
visit(tree_path_root_ref)
wait_for_requests
click_link(".gitignore")
end
it "shows a file content" do
expect(page).to have_content("*.rbc")
end
it "is possible to blame" do
click_link("Blame")
expect(page).to have_content("*.rb")
.and have_content("Dmitriy Zaporozhets")
.and have_content("Initial commit")
.and have_content("Ignore DS files")
previous_commit_anchor = "//a[@title='Ignore DS files']/parent::span/following-sibling::span/a"
find(:xpath, previous_commit_anchor).click
expect(page).to have_content("*.rb")
.and have_content("Dmitriy Zaporozhets")
.and have_content("Initial commit")
expect(page).not_to have_content("Ignore DS files")
end
end
context "when browsing a file with pathspec characters" do
let(:filename) { ':wq' }
let(:newrev) { project.repository.commit('master').sha }
before do
create_file_in_repo(project, 'master', 'master', filename, 'Test file')
path = File.join('master', filename)
visit(project_blob_path(project, path))
wait_for_requests
end
it "shows raw file content in a new tab" do
new_tab = window_opened_by {click_link 'Open raw'}
within_window new_tab do
expect(page).to have_content("Test file")
end
end
end
context "when browsing a raw file" do
before do
visit(tree_path_root_ref)
wait_for_requests
click_link(".gitignore")
wait_for_requests
end
it "shows raw file content in a new tab" do
new_tab = window_opened_by {click_link 'Open raw'}
within_window new_tab do
expect(page).to have_content("*.rbc")
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Projects > Files > User browses LFS files' do
let(:project) { create(:project, :repository) }
let(:user) { project.first_owner }
before do
stub_feature_flags(refactor_blob_viewer: false)
sign_in(user)
end
context 'when LFS is disabled', :js do
before do
allow_next_found_instance_of(Project) do |project|
allow(project).to receive(:lfs_enabled?).and_return(false)
end
visit project_tree_path(project, 'lfs')
wait_for_requests
end
it 'is possible to see raw content of LFS pointer' do
click_link 'files'
page.within('.repo-breadcrumb') do
expect(page).to have_link('files')
end
click_link 'lfs'
page.within('.repo-breadcrumb') do
expect(page).to have_link('lfs')
end
click_link 'lfs_object.iso'
expect(page).to have_content 'version https://git-lfs.github.com/spec/v1'
expect(page).to have_content 'oid sha256:91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897'
expect(page).to have_content 'size 1575078'
expect(page).not_to have_content 'Download (1.5 MB)'
end
end
context 'when LFS is enabled', :js do
before do
allow_next_found_instance_of(Project) do |project|
allow(project).to receive(:lfs_enabled?).and_return(true)
end
visit project_tree_path(project, 'lfs')
wait_for_requests
end
it 'shows an LFS object' do
click_link('files')
page.within('.repo-breadcrumb') do
expect(page).to have_link('files')
end
click_link('lfs')
click_link('lfs_object.iso')
expect(page).to have_content('Download (1.5 MB)')
expect(page).not_to have_content('version https://git-lfs.github.com/spec/v1')
expect(page).not_to have_content('oid sha256:91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897')
expect(page).not_to have_content('size 1575078')
page.within('.content') do
expect(page).to have_content('Delete')
expect(page).to have_content('History')
expect(page).to have_content('Permalink')
expect(page).to have_content('Replace')
expect(page).to have_link('Download')
expect(page).not_to have_content('Annotate')
expect(page).not_to have_content('Blame')
expect(page).not_to have_selector(:link_or_button, text: /^Edit$/)
expect(page).to have_selector(:link_or_button, 'Open in Web IDE')
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Projects > Files > User deletes files', :js do
let(:fork_message) do
"You're not allowed to make changes to this project directly. "\
"A fork of this project has been created that you can make changes in, so you can submit a merge request."
end
let(:project) { create(:project, :repository, name: 'Shop') }
let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') }
let(:project_tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) }
let(:project2_tree_path_root_ref) { project_tree_path(project2, project2.repository.root_ref) }
let(:user) { create(:user) }
before do
stub_feature_flags(refactor_blob_viewer: false)
sign_in(user)
end
context 'when an user has write access' do
before do
project.add_maintainer(user)
visit(project_tree_path_root_ref)
wait_for_requests
end
it 'deletes the file', :js do
click_link('.gitignore')
expect(page).to have_content('.gitignore')
click_on('Delete')
fill_in(:commit_message, with: 'New commit message', visible: true)
click_button('Delete file')
expect(page).to have_current_path(project_tree_path(project, 'master/'), ignore_query: true)
expect(page).not_to have_content('.gitignore')
end
end
context 'when an user does not have write access', :js do
before do
project2.add_reporter(user)
visit(project2_tree_path_root_ref)
wait_for_requests
end
it 'deletes the file in a forked project', :js, :sidekiq_might_not_need_inline do
click_link('.gitignore')
expect(page).to have_content('.gitignore')
click_on('Delete')
expect(page).to have_link('Fork')
expect(page).to have_button('Cancel')
click_link('Fork')
expect(page).to have_content(fork_message)
click_on('Delete')
fill_in(:commit_message, with: 'New commit message', visible: true)
click_button('Delete file')
fork = user.fork_of(project2.reload)
expect(page).to have_current_path(project_new_merge_request_path(fork), ignore_query: true)
expect(page).to have_content('New commit message')
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Projects > Files > User edits files', :js do
include ProjectForksHelper
include BlobSpecHelpers
let(:project) { create(:project, :repository, name: 'Shop') }
let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') }
let(:project_tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) }
let(:project2_tree_path_root_ref) { project_tree_path(project2, project2.repository.root_ref) }
let(:user) { create(:user) }
before do
stub_feature_flags(refactor_blob_viewer: false)
sign_in(user)
end
after do
unset_default_button
end
shared_examples 'unavailable for an archived project' do
it 'does not show the edit link for an archived project', :js do
project.update!(archived: true)
visit project_tree_path(project, project.repository.root_ref)
click_link('.gitignore')
aggregate_failures 'available edit buttons' do
expect(page).not_to have_text('Edit')
expect(page).not_to have_text('Web IDE')
expect(page).not_to have_text('Replace')
expect(page).not_to have_text('Delete')
end
end
end
context 'when an user has write access', :js do
before do
project.add_maintainer(user)
visit(project_tree_path_root_ref)
wait_for_requests
end
it 'inserts a content of a file' do
set_default_button('edit')
click_link('.gitignore')
click_link_or_button('Edit')
find('.file-editor', match: :first)
find('#editor')
set_editor_value('*.rbca')
expect(editor_value).to eq('*.rbca')
end
it 'does not show the edit link if a file is binary' do
binary_file = File.join(project.repository.root_ref, 'files/images/logo-black.png')
visit(project_blob_path(project, binary_file))
wait_for_requests
page.within '.content' do
expect(page).not_to have_link('edit')
end
end
it 'commits an edited file' do
set_default_button('edit')
click_link('.gitignore')
click_link_or_button('Edit')
find('.file-editor', match: :first)
find('#editor')
set_editor_value('*.rbca')
fill_in(:commit_message, with: 'New commit message', visible: true)
click_button('Commit changes')
expect(page).to have_current_path(project_blob_path(project, 'master/.gitignore'), ignore_query: true)
wait_for_requests
expect(page).to have_content('*.rbca')
end
it 'commits an edited file to a new branch' do
set_default_button('edit')
click_link('.gitignore')
click_link_or_button('Edit')
find('.file-editor', match: :first)
find('#editor')
set_editor_value('*.rbca')
fill_in(:commit_message, with: 'New commit message', visible: true)
fill_in(:branch_name, with: 'new_branch_name', visible: true)
click_button('Commit changes')
expect(page).to have_current_path(project_new_merge_request_path(project), ignore_query: true)
click_link('Changes')
expect(page).to have_content('*.rbca')
end
it 'shows the diff of an edited file' do
set_default_button('edit')
click_link('.gitignore')
click_link_or_button('Edit')
find('.file-editor', match: :first)
find('#editor')
set_editor_value('*.rbca')
click_link('Preview changes')
expect(page).to have_css('.line_holder.new')
end
it_behaves_like 'unavailable for an archived project'
end
context 'when an user does not have write access', :js do
before do
project2.add_reporter(user)
visit(project2_tree_path_root_ref)
wait_for_requests
end
def expect_fork_prompt
expect(page).to have_selector(:link_or_button, 'Fork')
expect(page).to have_selector(:link_or_button, 'Cancel')
expect(page).to have_content(
"You can’t edit files directly in this project. "\
"Fork this project and submit a merge request with your changes."
)
end
def expect_fork_status
expect(page).to have_content(
"You're not allowed to make changes to this project directly. "\
"A fork of this project has been created that you can make changes in, so you can submit a merge request."
)
end
it 'inserts a content of a file in a forked project', :sidekiq_might_not_need_inline do
set_default_button('edit')
click_link('.gitignore')
click_link_or_button('Edit')
expect_fork_prompt
click_link_or_button('Fork project')
expect_fork_status
find('.file-editor', match: :first)
find('#editor')
set_editor_value('*.rbca')
expect(editor_value).to eq('*.rbca')
end
it 'commits an edited file in a forked project', :sidekiq_might_not_need_inline do
set_default_button('edit')
click_link('.gitignore')
click_link_or_button('Edit')
expect_fork_prompt
click_link_or_button('Fork project')
find('.file-editor', match: :first)
find('#editor')
set_editor_value('*.rbca')
fill_in(:commit_message, with: 'New commit message', visible: true)
click_button('Commit changes')
fork = user.fork_of(project2.reload)
expect(page).to have_current_path(project_new_merge_request_path(fork), ignore_query: true)
wait_for_requests
expect(page).to have_content('New commit message')
end
context 'when the user already had a fork of the project', :js do
let!(:forked_project) { fork_project(project2, user, namespace: user.namespace, repository: true) }
before do
visit(project2_tree_path_root_ref)
wait_for_requests
end
it 'links to the forked project for editing', :sidekiq_might_not_need_inline do
set_default_button('edit')
click_link('.gitignore')
click_link_or_button('Edit')
expect(page).not_to have_link('Fork project')
find('#editor')
set_editor_value('*.rbca')
fill_in(:commit_message, with: 'Another commit', visible: true)
click_button('Commit changes')
fork = user.fork_of(project2)
expect(page).to have_current_path(project_new_merge_request_path(fork), ignore_query: true)
wait_for_requests
expect(page).to have_content('Another commit')
expect(page).to have_content("From #{forked_project.full_path}")
expect(page).to have_content("into #{project2.full_path}")
end
it_behaves_like 'unavailable for an archived project' do
let(:project) { project2 }
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Projects > Files > User replaces files', :js do
include DropzoneHelper
let(:fork_message) do
"You're not allowed to make changes to this project directly. "\
"A fork of this project has been created that you can make changes in, so you can submit a merge request."
end
let(:project) { create(:project, :repository, name: 'Shop') }
let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') }
let(:project_tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) }
let(:project2_tree_path_root_ref) { project_tree_path(project2, project2.repository.root_ref) }
let(:user) { create(:user) }
before do
stub_feature_flags(refactor_blob_viewer: false)
sign_in(user)
end
context 'when an user has write access' do
before do
project.add_maintainer(user)
visit(project_tree_path_root_ref)
wait_for_requests
end
it 'replaces an existed file with a new one' do
click_link('.gitignore')
expect(page).to have_content('.gitignore')
click_on('Replace')
drop_in_dropzone(File.join(Rails.root, 'spec', 'fixtures', 'doc_sample.txt'))
page.within('#modal-upload-blob') do
fill_in(:commit_message, with: 'Replacement file commit message')
end
click_button('Replace file')
expect(page).to have_content('Lorem ipsum dolor sit amet')
expect(page).to have_content('Sed ut perspiciatis unde omnis')
expect(page).to have_content('Replacement file commit message')
end
end
context 'when an user does not have write access' do
before do
project2.add_reporter(user)
visit(project2_tree_path_root_ref)
wait_for_requests
end
it 'replaces an existed file with a new one in a forked project', :sidekiq_might_not_need_inline do
click_link('.gitignore')
expect(page).to have_content('.gitignore')
click_on('Replace')
expect(page).to have_link('Fork')
expect(page).to have_button('Cancel')
click_link('Fork')
expect(page).to have_content(fork_message)
click_on('Replace')
drop_in_dropzone(File.join(Rails.root, 'spec', 'fixtures', 'doc_sample.txt'))
page.within('#modal-upload-blob') do
fill_in(:commit_message, with: 'Replacement file commit message')
end
click_button('Replace file')
expect(page).to have_content('Replacement file commit message')
fork = user.fork_of(project2.reload)
expect(page).to have_current_path(project_new_merge_request_path(fork), ignore_query: true)
click_link('Changes')
expect(page).to have_content('Lorem ipsum dolor sit amet')
expect(page).to have_content('Sed ut perspiciatis unde omnis')
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment