Commit ee294618 authored by Matthias Käppler's avatar Matthias Käppler

Merge branch 'blob-show-spec' into 'master'

Blob refactor: Fix/update blob show specs

See merge request gitlab-org/gitlab!78541
parents 84ff263c 9e1369c1
......@@ -42,6 +42,11 @@ export default {
required: false,
default: false,
},
showPath: {
type: Boolean,
required: false,
default: true,
},
},
data() {
return {
......@@ -55,6 +60,9 @@ export default {
showDefaultActions() {
return !this.hideDefaultActions;
},
isEmpty() {
return this.blob.rawSize === 0;
},
},
watch: {
viewer(newVal, oldVal) {
......@@ -74,7 +82,7 @@ export default {
<div class="js-file-title file-title-flex-parent">
<div class="gl-display-flex">
<table-of-contents class="gl-pr-2" />
<blob-filepath :blob="blob">
<blob-filepath :blob="blob" :show-path="showPath">
<template #filepath-prepend>
<slot name="prepend"></slot>
</template>
......@@ -88,12 +96,13 @@ export default {
<default-actions
v-if="showDefaultActions"
:raw-path="blob.rawPath"
:raw-path="blob.externalStorageUrl || blob.rawPath"
:active-viewer="viewer"
:has-render-error="hasRenderError"
:is-binary="isBinary"
:environment-name="blob.environmentFormattedExternalUrl"
:environment-path="blob.environmentExternalUrlForRouteMap"
:is-empty="isEmpty"
@copy="proxyCopyRequest"
/>
</div>
......
......@@ -48,6 +48,11 @@ export default {
required: false,
default: null,
},
isEmpty: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
downloadUrl() {
......@@ -87,6 +92,7 @@ export default {
icon="copy-to-clipboard"
category="primary"
variant="default"
class="js-copy-blob-source-btn"
/>
<gl-button
v-if="!isBinary"
......@@ -100,6 +106,7 @@ export default {
variant="default"
/>
<gl-button
v-if="!isEmpty"
v-gl-tooltip.hover
:aria-label="$options.BTN_DOWNLOAD_TITLE"
:title="$options.BTN_DOWNLOAD_TITLE"
......
......@@ -15,6 +15,11 @@ export default {
type: Object,
required: true,
},
showPath: {
type: Boolean,
required: false,
default: true,
},
},
computed: {
blobSize() {
......@@ -26,6 +31,13 @@ export default {
showLfsBadge() {
return this.blob.storedExternally && this.blob.externalStorage === 'lfs';
},
fileName() {
if (this.showPath) {
return this.blob.path;
}
return this.blob.name;
},
},
};
</script>
......@@ -33,12 +45,12 @@ export default {
<div class="file-header-content d-flex align-items-center lh-100">
<slot name="filepath-prepend"></slot>
<template v-if="blob.path">
<file-icon :file-name="blob.path" :size="16" aria-hidden="true" css-classes="mr-2" />
<template v-if="fileName">
<file-icon :file-name="fileName" :size="16" aria-hidden="true" css-classes="mr-2" />
<strong
class="file-title-name mr-1 js-blob-header-filepath"
data-qa-selector="file_title_content"
>{{ blob.path }}</strong
>{{ fileName }}</strong
>
</template>
......
......@@ -153,7 +153,7 @@ export default {
},
blobViewer() {
const { fileType } = this.viewer;
return loadViewer(fileType);
return loadViewer(fileType, this.isUsingLfs);
},
viewerProps() {
const { fileType } = this.viewer;
......@@ -185,6 +185,9 @@ export default {
? this.blobInfo.ideForkAndEditPath
: this.blobInfo.forkAndEditPath;
},
isUsingLfs() {
return this.blobInfo.storedExternally && this.blobInfo.externalStorage === 'lfs';
},
},
methods: {
loadLegacyViewer(type) {
......@@ -245,10 +248,11 @@ export default {
<div v-if="blobInfo && !isLoading" class="file-holder">
<blob-header
:blob="blobInfo"
:hide-viewer-switcher="!hasRichViewer || isBinaryFileType"
:hide-viewer-switcher="!hasRichViewer || isBinaryFileType || isUsingLfs"
:is-binary="isBinaryFileType"
:active-viewer-type="viewer.type"
:has-render-error="hasRenderError"
:show-path="false"
@viewer-changed="switchViewer"
>
<template #actions>
......
export const loadViewer = (type) => {
switch (type) {
case 'empty':
return () => import(/* webpackChunkName: 'blob_empty_viewer' */ './empty_viewer.vue');
case 'text':
return gon.features.highlightJs
? () =>
import(
/* webpackChunkName: 'blob_text_viewer' */ '~/vue_shared/components/source_viewer.vue'
)
: null;
case 'download':
return () => import(/* webpackChunkName: 'blob_download_viewer' */ './download_viewer.vue');
case 'image':
return () => import(/* webpackChunkName: 'blob_image_viewer' */ './image_viewer.vue');
case 'video':
return () => import(/* webpackChunkName: 'blob_video_viewer' */ './video_viewer.vue');
case 'pdf':
return () => import(/* webpackChunkName: 'blob_pdf_viewer' */ './pdf_viewer.vue');
default:
return null;
const viewers = {
download: () => import('./download_viewer.vue'),
image: () => import('./image_viewer.vue'),
video: () => import('./video_viewer.vue'),
empty: () => import('./empty_viewer.vue'),
text: () => import('~/vue_shared/components/source_viewer.vue'),
pdf: () => import('./pdf_viewer.vue'),
lfs: () => import('./lfs_viewer.vue'),
};
export const loadViewer = (type, isUsingLfs) => {
let viewer = viewers[type];
if (!viewer && isUsingLfs) {
viewer = viewers.lfs;
}
return viewer;
};
export const viewerProps = (type, blob) => {
return {
const props = {
text: {
content: blob.rawTextBlob,
autoDetect: true, // We'll eventually disable autoDetect and pass the language explicitly to reduce the footprint (https://gitlab.com/gitlab-org/gitlab/-/issues/348145)
......@@ -44,5 +40,11 @@ export const viewerProps = (type, blob) => {
url: blob.rawPath,
fileSize: blob.rawSize,
},
}[type];
lfs: {
fileName: blob.name,
filePath: blob.rawPath,
},
};
return props[type] || props[blob.externalStorage];
};
<script>
import { GlLink, GlSprintf } from '@gitlab/ui';
import { __ } from '~/locale';
export default {
i18n: {
lfsText: __(
'This content could not be displayed because it is stored in LFS. You can %{linkStart}download it%{linkEnd} instead.',
),
},
components: {
GlLink,
GlSprintf,
},
props: {
fileName: {
type: String,
required: true,
},
filePath: {
type: String,
required: true,
},
},
};
</script>
<template>
<div class="gl-text-center gl-py-13 gl-bg-gray-50" data-type="lfs">
<gl-sprintf :message="$options.i18n.lfsText">
<template #link="{ content }">
<gl-link :href="filePath" :download="fileName" target="_blank">{{ content }}</gl-link>
</template>
</gl-sprintf>
</div>
</template>
......@@ -32,6 +32,7 @@ query getBlobInfo($projectPath: ID!, $filePath: String!, $ref: String!) {
archived
storedExternally
externalStorage
externalStorageUrl
rawPath
replacePath
pipelineEditorPath
......
......@@ -115,7 +115,12 @@ export default {
};
</script>
<template>
<div class="file-content code js-syntax-highlight" :class="$options.userColorScheme">
<div
class="file-content code js-syntax-highlight blob-content"
:class="$options.userColorScheme"
data-type="simple"
data-qa-selector="blob_viewer_file_content"
>
<line-numbers :lines="lineNumbers" />
<pre class="code"><code v-safe-html="highlightedContent"></code>
</pre>
......
......@@ -125,7 +125,7 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated
def external_storage_url
return unless static_objects_external_storage_enabled?
external_storage_url_or_path(url_helpers.project_raw_url(project, ref_qualified_path))
external_storage_url_or_path(url_helpers.project_raw_url(project, ref_qualified_path), project)
end
private
......
......@@ -36578,6 +36578,9 @@ msgstr ""
msgid "This content could not be displayed because %{reason}. You can %{options} instead."
msgstr ""
msgid "This content could not be displayed because it is stored in LFS. You can %{linkStart}download it%{linkEnd} instead."
msgstr ""
msgid "This credential has expired"
msgstr ""
......
......@@ -22,6 +22,10 @@ module QA
element :copy_contents_button
end
base.view 'app/assets/javascripts/vue_shared/components/source_viewer.vue' do
element :blob_viewer_file_content
end
base.view 'app/views/projects/blob/_header_content.html.haml' do
element :file_name_content
end
......
......@@ -29,443 +29,421 @@ RSpec.describe 'File blob', :js do
).execute
end
before do
stub_feature_flags(refactor_blob_viewer: false) # This stub will be removed in https://gitlab.com/gitlab-org/gitlab/-/issues/350455
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
context 'with refactor_blob_viewer feature flag enabled' do
context 'Ruby file' do
before do
visit_blob('files/markdown/ruby-style-guide.md')
visit_blob('files/ruby/popen.rb')
wait_for_requests
end
it 'displays the blob using the rich viewer' do
it 'displays the blob' 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 highlighted Ruby code
expect(page).to have_css(".js-syntax-highlight")
expect(page).to have_content("require 'fileutils'")
# shows 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')
# shows 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')
end
end
context 'switching to the simple viewer' do
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
find('.js-blob-viewer-switch-btn[data-viewer=simple]').click
visit_blob('files/markdown/ruby-style-guide.md')
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).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
# 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 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
context 'switching to the rich viewer again' do
context 'switching to the simple viewer' do
before do
find('.js-blob-viewer-switch-btn[data-viewer=rich]').click
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).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
expect(page).to have_selector('.blob-viewer[data-type="rich"]')
# 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 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
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
context 'switching to the rich viewer again' do
before do
find('.js-blob-viewer-switch-btn[data-viewer=rich]').click
it 'displays single highlighted line number of different ref' do
visit_blob('files/js/application.js', anchor: 'L1')
wait_for_requests
end
switch_ref_to('feature')
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"]')
page.within '.blob-content' do
expect(find_by_id('LC1')[:class]).to include("hll")
# shows a disabled copy button
expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
end
end
end
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')
context 'when ref switch' do
def switch_ref_to(ref_name)
first('.qa-branches-select').click # rubocop:disable QA/SelectorUsage
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")
page.within '.project-refs-form' do
click_link ref_name
wait_for_requests
end
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')
page.within '.blob-content' do
expect(page).not_to have_css('.hll')
end
end
end
context 'successfully change ref of similar name' do
before do
project.repository.create_branch('dev')
project.repository.create_branch('development')
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')
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')
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 '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 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')
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
it 'successfully changes ref when the ref name matches the project name' do
project.repository.create_branch(project.name)
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')
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')
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 'visiting with a line number anchor' do
context 'Markdown rendering' do
before do
visit_blob('files/markdown/ruby-style-guide.md', anchor: 'L1')
end
project.add_maintainer(project.creator)
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)
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
# highlights the line in question
expect(page).to have_selector('#LC1.hll')
context 'when rendering default markdown' do
before do
visit_blob('files/commonmark/file.md')
# 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/)")
wait_for_requests
end
# shows an enabled copy button
expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
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
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
context 'Markdown file (stored in LFS)' do
before do
visit_blob('files/commonmark/file.md')
wait_for_requests
end
project.add_maintainer(project.creator)
it 'renders using CommonMark' do
aggregate_failures do
expect(page).to have_content("sublist")
expect(page).not_to have_xpath("//ol//li//ul")
end
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
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)
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')
visit_blob('files/lfs/file.md')
wait_for_requests
end
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"]')
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('The rendered file could not be displayed because it is stored in LFS. You can download it instead.')
# 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.')
# shows 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')
# 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')
# shows a download button
expect(page).to have_link('Download')
end
end
end
context 'switching to the simple viewer' do
context 'when LFS is disabled on the project' do
before do
find('.js-blob-viewer-switcher .js-blob-viewer-switch-btn[data-viewer=simple]').click
visit_blob('files/lfs/file.md')
wait_for_requests
end
it 'displays an error' do
it 'displays the blob' 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 text
expect(page).to have_content('size 1575078')
# 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 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 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 'when LFS is disabled on the project' do
context 'PDF file' do
before do
visit_blob('files/lfs/file.md')
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 text
expect(page).to have_content('size 1575078')
# 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')
# shows an enabled copy button
expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
# does not show a copy button
expect(page).not_to have_selector('.js-copy-blob-source-btn')
# shows a raw button
expect(page).to have_link('Open raw')
# shows a download button
expect(page).to have_link('Download')
end
end
end
end
context 'PDF file' do
before do
project.add_maintainer(project.creator)
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
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/basic.ipynb')
visit_blob('files/test.pdf')
wait_for_requests
end
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')
it 'displays the blob' do
aggregate_failures do
# shows rendered PDF
expect(page).to have_selector('.js-pdf-viewer')
# show a disabled copy button
expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
# does not show a viewer switcher
expect(page).not_to have_selector('.js-blob-viewer-switcher')
# shows a raw button
expect(page).to have_link('Open raw')
# 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')
# 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 'Jupiter Notebook file' do
before do
project.add_maintainer(project.creator)
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)
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/lfs/lfs_object.iso')
visit_blob('files/basic.ipynb')
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)')
# 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
it 'displays the blob' do
aggregate_failures do
# shows rendered notebook
expect(page).to have_selector('.js-notebook-viewer-mounted')
context 'when LFS is disabled on the project' do
before do
visit_blob('files/lfs/lfs_object.iso')
# does show a viewer switcher
expect(page).to have_selector('.js-blob-viewer-switcher')
wait_for_requests
end
# show a disabled copy button
expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
it 'displays the blob' do
aggregate_failures do
# shows text
expect(page).to have_content('size 1575078')
# shows a raw button
expect(page).to have_link('Open raw')
# does not show a viewer switcher
expect(page).not_to have_selector('.js-blob-viewer-switcher')
# shows a download button
expect(page).to have_link('Download')
# shows an enabled copy button
expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
# shows the rendered notebook
expect(page).to have_content('test')
# shows a raw button
expect(page).to have_link('Open raw')
end
end
end
end
end
context 'ISO file (stored in LFS)' do
context 'when LFS is enabled on the project' do
context 'ZIP file' 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')
visit_blob('Gemfile.zip')
wait_for_requests
end
......@@ -473,7 +451,7 @@ RSpec.describe 'File blob', :js do
it 'displays the blob' do
aggregate_failures do
# shows a download link
expect(page).to have_link('Download (1.5 MB)')
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')
......@@ -487,578 +465,703 @@ RSpec.describe 'File blob', :js do
end
end
context 'when LFS is disabled on the project' do
context 'empty file' do
before do
visit_blob('files/lfs/lfs_object.iso')
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 the blob' do
it 'displays an error' do
aggregate_failures do
# shows text
expect(page).to have_content('size 1575078')
# 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')
# shows an enabled copy button
expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
# does not show a copy button
expect(page).not_to have_selector('.js-copy-blob-source-btn')
# shows a raw button
expect(page).to have_link('Open raw')
# 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
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')
context 'files with auxiliary viewers' do
describe '.gitlab-ci.yml' do
before do
project.add_maintainer(project.creator)
# shows a download button
expect(page).to have_link('Download')
end
end
end
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
context 'empty file' do
before do
project.add_maintainer(project.creator)
visit_blob('.gitlab-ci.yml')
end
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
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.')
visit_blob('files/empty.md')
# shows a learn more link
expect(page).to have_link('Learn more')
end
end
end
wait_for_requests
end
describe '.gitlab/route-map.yml' do
before do
project.add_maintainer(project.creator)
it 'displays an error' do
aggregate_failures do
# shows an error message
expect(page).to have_content('Empty file')
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
# does not show a viewer switcher
expect(page).not_to have_selector('.js-blob-viewer-switcher')
visit_blob('.gitlab/route-map.yml')
end
# does not show a copy button
expect(page).not_to have_selector('.js-copy-blob-source-btn')
it 'displays an auxiliary viewer' do
aggregate_failures do
# shows that map is valid
expect(page).to have_content('This Route Map is valid.')
# 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
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
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
it 'displays the blob' do
aggregate_failures do
# shows a download link
expect(page).to have_link('Download (23.8 KB)')
context 'valid dashboard file' do
let(:file_content) { File.read(Rails.root.join('config/prometheus/common_metrics.yml')) }
# does not show a viewer switcher
expect(page).not_to have_selector('.js-blob-viewer-switcher')
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.')
# 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 a learn more link
expect(page).to have_link('Learn more')
end
end
end
# shows an enabled copy button, incorrectly
expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
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 raw button, incorrectly
expect(page).to have_link('Open raw')
# shows a learn more link
expect(page).to have_link('Learn more')
end
end
end
end
end
end
end
context 'files with auxiliary viewers' do
before do
stub_feature_flags(refactor_blob_viewer: true)
end
context 'LICENSE' do
before do
visit_blob('LICENSE')
end
describe '.gitlab-ci.yml' do
before do
project.add_maintainer(project.creator)
it 'displays an auxiliary viewer' do
aggregate_failures do
# shows license
expect(page).to have_content('This project is licensed under the MIT License.')
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
# 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)
visit_blob('.gitlab-ci.yml')
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
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.')
context 'CONTRIBUTING.md' do
before do
file_name = 'CONTRIBUTING.md'
# shows a learn more link
expect(page).to have_link('Learn more')
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
end
describe '.gitlab/route-map.yml' do
before do
project.add_maintainer(project.creator)
context 'CHANGELOG.md' do
before do
file_name = 'CHANGELOG.md'
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
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
visit_blob('.gitlab/route-map.yml')
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
it 'displays an auxiliary viewer' do
aggregate_failures do
# shows that map is valid
expect(page).to have_content('This Route Map is valid.')
context 'package.json' do
before do
file_name = 'package.json'
# shows a learn more link
expect(page).to have_link('Learn more')
create_file(file_name, '
{
"name": "my-awesome-package",
"version": "1.0.0"
}
')
visit_blob(file_name)
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
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 'with metrics_dashboard_exhaustive_validations feature flag off' do
context 'podfile' 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')) }
file_name = 'podfile'
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.')
create_file(file_name, 'platform :ios, "8.0"')
visit_blob(file_name)
end
# shows a learn more link
expect(page).to have_link('Learn more')
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 'invalid dashboard file' do
let(:file_content) { "dashboard: 'invalid'" }
context 'test.podspec' do
before do
file_name = 'test.podspec'
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")
create_file(file_name, '
Pod::Spec.new do |s|
s.name = "TensorFlowLiteC"
')
visit_blob(file_name)
end
# shows a learn more link
expect(page).to have_link('Learn more')
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 'with metrics_dashboard_exhaustive_validations feature flag on' do
context 'JSON.podspec.json' 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')) }
file_name = 'JSON.podspec.json'
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.')
create_file(file_name, '
{
"name": "JSON"
}
')
visit_blob(file_name)
end
# shows a learn more link
expect(page).to have_link('Learn more')
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 'invalid dashboard file' do
let(:file_content) { "dashboard: 'invalid'" }
context 'requirements.txt' do
before do
file_name = 'requirements.txt'
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")
create_file(file_name, 'Project requirements')
visit_blob(file_name)
end
# shows a learn more link
expect(page).to have_link('Learn more')
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
end
context 'LICENSE' do
before do
visit_blob('LICENSE')
end
context 'yarn.lock' do
before do
file_name = 'yarn.lock'
it 'displays an auxiliary viewer' do
aggregate_failures do
# shows license
expect(page).to have_content('This project is licensed under the MIT License.')
create_file(file_name, '
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
')
visit_blob(file_name)
end
# shows a learn more link
expect(page).to have_link('Learn more', href: 'http://choosealicense.com/licenses/mit/')
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 '*.gemspec' do
context 'realtime pipelines' 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
start_branch: 'feature',
branch_name: 'feature',
commit_message: "Add ruby file",
file_path: 'files/ruby/test.rb',
file_content: "# Awesome content"
).execute
visit_blob('activerecord.gemspec')
create(:ci_pipeline, status: 'running', project: project, ref: 'feature', sha: project.commit('feature').sha)
visit_blob('files/ruby/test.rb', ref: 'feature')
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/')
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 'CONTRIBUTING.md' do
before do
file_name = 'CONTRIBUTING.md'
context 'for subgroups' do
let(:group) { create(:group) }
let(:subgroup) { create(:group, parent: group) }
let(:project) { create(:project, :public, :repository, group: subgroup) }
create_file(file_name, '## Contribution guidelines')
visit_blob(file_name)
end
it 'renders tree table without errors' do
visit_blob('README.md')
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
expect(page).to have_selector('.file-content')
expect(page).not_to have_selector('.flash-alert')
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 a GPG badge' do
visit_blob('CONTRIBUTING.md', ref: '33f3729a45c02fc67d00adb1b8bca394b0e761d9')
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
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 '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 'on signed merge commit' do
it 'displays a GPG badge' do
visit_blob('conflicting-file.md', ref: '6101e87e575de14b38b4e1ce180519a813671e10')
it 'displays an auxiliary viewer' do
aggregate_failures do
expect(page).to have_content("This project manages its dependencies using Cargo.")
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 'Cartfile' do
context 'when static objects external storage is enabled' 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)
stub_application_setting(static_objects_external_storage_url: 'https://cdn.gitlab.com')
end
it 'displays an auxiliary viewer' do
aggregate_failures do
expect(page).to have_content("This project manages its dependencies using Carthage.")
context 'public project' do
before do
visit_blob('README.md')
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 '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"
it 'displays an auxiliary viewer' do
aggregate_failures do
expect(page).to have_content("This project manages its dependencies using Composer.")
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
context 'Gemfile' do
before do
file_name = 'Gemfile'
context 'with refactor_blob_viewer feature flag disabled' do
before do
stub_feature_flags(refactor_blob_viewer: false)
end
create_file(file_name, '
source "https://rubygems.org"
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
# Gems here
')
visit_blob(file_name)
end
def switch_ref_to(ref_name)
first('.qa-branches-select').click # rubocop:disable QA/SelectorUsage
it 'displays an auxiliary viewer' do
aggregate_failures do
expect(page).to have_content("This project manages its dependencies using Bundler.")
page.within '.project-refs-form' do
click_link ref_name
wait_for_requests
end
end
end
context 'Godeps.json' do
before do
file_name = 'Godeps.json'
context 'when highlighting lines' do
it 'displays single highlighted line number of different ref' do
visit_blob('files/js/application.js', anchor: 'L1')
create_file(file_name, '
{
"GoVersion": "go1.6"
}
')
visit_blob(file_name)
end
switch_ref_to('feature')
it 'displays an auxiliary viewer' do
aggregate_failures do
expect(page).to have_content("This project manages its dependencies using godep.")
page.within '.blob-content' do
expect(find_by_id('LC1')[:class]).to include("hll")
end
end
end
end
context 'go.mod' do
before do
file_name = 'go.mod'
create_file(file_name, '
module example.com/mymodule
it 'displays multiple highlighted line numbers of different ref' do
visit_blob('files/js/application.js', anchor: 'L1-3')
go 1.14
')
visit_blob(file_name)
end
switch_ref_to('feature')
it 'displays an auxiliary viewer' do
aggregate_failures do
expect(page).to have_content("This project manages its dependencies using Go Modules.")
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 'package.json' do
before do
file_name = 'package.json'
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
create_file(file_name, '
{
"name": "my-awesome-package",
"version": "1.0.0"
}
')
visit_blob(file_name)
before do
visit_blob('files/markdown/ruby-style-guide.md', anchor: 'L1')
end
it 'displays an auxiliary viewer' do
it 'displays the blob using the simple viewer' do
aggregate_failures do
expect(page).to have_content("This project manages its dependencies using npm.")
end
end
end
# 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"]')
context 'podfile' do
before do
file_name = 'podfile'
# highlights the line in question
expect(page).to have_selector('#LC1.hll')
create_file(file_name, 'platform :ios, "8.0"')
visit_blob(file_name)
end
# 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/)")
it 'displays an auxiliary viewer' do
aggregate_failures do
expect(page).to have_content("This project manages its dependencies using CocoaPods.")
# shows an enabled copy button
expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
end
end
end
context 'test.podspec' do
before do
file_name = 'test.podspec'
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
create_file(file_name, '
Pod::Spec.new do |s|
s.name = "TensorFlowLiteC"
')
visit_blob(file_name)
before do
visit_blob('encoding/binary-1.bin', ref: 'binary-encoding')
end
it 'displays an auxiliary viewer' do
it 'displays the blob' do
aggregate_failures do
expect(page).to have_content("This project manages its dependencies using CocoaPods.")
# 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 'JSON.podspec.json' do
before do
file_name = 'JSON.podspec.json'
create_file(file_name, '
{
"name": "JSON"
}
')
visit_blob(file_name)
end
context 'when static objects external storage is enabled' 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/351555
it 'displays an auxiliary viewer' do
aggregate_failures do
expect(page).to have_content("This project manages its dependencies using CocoaPods.")
end
before do
stub_application_setting(static_objects_external_storage_url: 'https://cdn.gitlab.com')
end
end
context 'requirements.txt' do
before do
file_name = 'requirements.txt'
context 'private project' do
let_it_be(:project) { create(:project, :repository, :private) }
let_it_be(:user) { create(:user) }
create_file(file_name, 'Project requirements')
visit_blob(file_name)
end
before do
project.add_developer(user)
it 'displays an auxiliary viewer' do
aggregate_failures do
expect(page).to have_content("This project manages its dependencies using pip.")
sign_in(user)
visit_blob('README.md')
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 '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}"
it 'displays an auxiliary viewer' do
aggregate_failures do
expect(page).to have_content("This project manages its dependencies using Yarn.")
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 'when refactor_blob_viewer is disabled' do
before do
stub_feature_flags(refactor_blob_viewer: false)
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
......@@ -1554,104 +1657,4 @@ RSpec.describe 'File blob', :js do
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('.flash-alert')
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
......@@ -13,6 +13,7 @@ exports[`Blob Header Default Actions rendering matches the snapshot 1`] = `
<blob-filepath-stub
blob="[object Object]"
showpath="true"
/>
</div>
......
......@@ -236,7 +236,7 @@ describe('Blob content viewer component', () => {
await waitForPromises();
expect(loadViewer).toHaveBeenCalledWith(viewer);
expect(loadViewer).toHaveBeenCalledWith(viewer, false);
expect(wrapper.findComponent(loadViewerReturnValue).exists()).toBe(true);
},
);
......
import { GlLink, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import LfsViewer from '~/repository/components/blob_viewers/lfs_viewer.vue';
describe('LFS Viewer', () => {
let wrapper;
const DEFAULT_PROPS = {
fileName: 'file_name.js',
filePath: '/some/file/path',
};
const createComponent = () => {
wrapper = shallowMount(LfsViewer, {
propsData: { ...DEFAULT_PROPS },
stubs: { GlSprintf },
});
};
const findLink = () => wrapper.findComponent(GlLink);
beforeEach(() => createComponent());
afterEach(() => wrapper.destroy());
it('renders the correct text', () => {
expect(wrapper.text()).toBe(
'This content could not be displayed because it is stored in LFS. You can download it instead.',
);
});
it('renders download link', () => {
const { filePath, fileName } = DEFAULT_PROPS;
expect(findLink().attributes()).toMatchObject({
target: '_blank',
href: filePath,
download: fileName,
});
});
});
......@@ -17,6 +17,7 @@ export const simpleViewerMock = {
canCurrentUserPushToBranch: true,
archived: false,
storedExternally: false,
externalStorageUrl: '',
externalStorage: 'lfs',
rawPath: 'some_file.js',
replacePath: 'some_file.js/replace',
......
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