Commit e8ecb4b5 authored by Paul Slaughter's avatar Paul Slaughter

Merge branch 'fj-195517-single-blob-snippet-view-render' into 'master'

Render first snippet blob in the views

See merge request gitlab-org/gitlab!23848
parents 6323f17e ead199f4
......@@ -6,20 +6,18 @@ module SnippetsActions
def edit
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def raw
disposition = params[:inline] == 'false' ? 'attachment' : 'inline'
workhorse_set_content_type!
send_data(
convert_line_endings(@snippet.content),
convert_line_endings(blob.data),
type: 'text/plain; charset=utf-8',
disposition: disposition,
filename: @snippet.sanitized_file_name
filename: Snippet.sanitized_file_name(blob.name)
)
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
def js_request?
request.format.js?
......
......@@ -66,7 +66,6 @@ class Projects::SnippetsController < Projects::ApplicationController
end
def show
blob = @snippet.blob
conditionally_expand_blob(blob)
respond_to do |format|
......@@ -115,6 +114,16 @@ class Projects::SnippetsController < Projects::ApplicationController
alias_method :awardable, :snippet
alias_method :spammable, :snippet
def blob
return unless snippet
@blob ||= if Feature.enabled?(:version_snippets, current_user) && !snippet.repository.empty?
snippet.blobs.first
else
snippet.blob
end
end
def spammable_path
project_snippet_path(@project, @snippet)
end
......
......@@ -68,17 +68,15 @@ class SnippetsController < ApplicationController
end
def show
blob = @snippet.blob
conditionally_expand_blob(blob)
respond_to do |format|
format.html do
@note = Note.new(noteable: @snippet)
@noteable = @snippet
@discussions = @snippet.discussions
@notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes), @noteable)
respond_to do |format|
format.html do
render 'show'
end
......@@ -121,6 +119,16 @@ class SnippetsController < ApplicationController
alias_method :awardable, :snippet
alias_method :spammable, :snippet
def blob
return unless snippet
@blob ||= if Feature.enabled?(:version_snippets, current_user) && !snippet.repository.empty?
snippet.blobs.first
else
snippet.blob
end
end
def spammable_path
snippet_path(@snippet)
end
......
......@@ -62,6 +62,7 @@ module Types
field :blob, type: Types::Snippets::BlobType,
description: 'Snippet blob',
calls_gitaly: true,
null: false
markdown_field :description_html, null: true, method: :description
......
# frozen_string_literal: true
# Applicable for blob classes with project attribute
module BlobLanguageFromGitAttributes
extend ActiveSupport::Concern
def language_from_gitattributes
return unless project
return unless repository&.exists?
repository = project.repository
repository.gitattribute(path, 'gitlab-language')
end
end
......@@ -197,7 +197,11 @@ class Snippet < ApplicationRecord
end
def blob
@blob ||= Blob.decorate(SnippetBlob.new(self), nil)
@blob ||= Blob.decorate(SnippetBlob.new(self), self)
end
def blobs
repository.ls_files(repository.root_ref).map { |file| Blob.lazy(self, repository.root_ref, file) }
end
def hook_attrs
......@@ -208,7 +212,7 @@ class Snippet < ApplicationRecord
super.to_s
end
def sanitized_file_name
def self.sanitized_file_name(file_name)
file_name.gsub(/[^a-zA-Z0-9_\-\.]+/, '')
end
......
......@@ -32,7 +32,7 @@ class SnippetBlobPresenter < BlobPresenter
end
def snippet
blob.snippet
blob.container
end
def language
......
......@@ -27,6 +27,14 @@ class SnippetPresenter < Gitlab::View::Presenter::Delegated
snippet.submittable_as_spam_by?(current_user)
end
def blob
if Feature.enabled?(:version_snippets, current_user) && !snippet.repository.empty?
snippet.blobs.first
else
snippet.blob
end
end
private
def can_access_resource?(ability_prefix)
......
......@@ -9,8 +9,7 @@
= render 'shared/snippets/header'
.project-snippets
%article.file-holder.snippet-file-content
= render 'shared/snippets/blob'
= render 'shared/snippets/blob', blob: @blob
.row-content-block.top-block.content-component-block
= render 'award_emoji/awards_block', awardable: @snippet, inline: true
......
- blob = @snippet.blob
.js-file-title.file-title-flex-parent
%article.file-holder.snippet-file-content
.js-file-title.file-title-flex-parent
= render 'projects/blob/header_content', blob: blob
.file-actions.d-none.d-sm-block
......@@ -10,4 +10,4 @@
= open_raw_blob_button(blob)
= download_raw_snippet_button(@snippet)
= render 'projects/blob/content', blob: blob
= render 'projects/blob/content', blob: blob
- blob = @snippet.blob
.gitlab-embed-snippets
.js-file-title.file-title-flex-parent
.file-header-content
......@@ -6,10 +5,10 @@
%strong.file-title-name
%a.gitlab-embedded-snippets-title{ href: url_for(only_path: false, overwrite_params: nil) }
= blob.name
= @blob.name
%small
= number_to_human_size(blob.raw_size)
= number_to_human_size(@blob.raw_size)
%a.gitlab-logo-wrapper{ href: url_for(only_path: false, overwrite_params: nil), title: 'view on gitlab' }
%img.gitlab-logo{ src: image_url('ext_snippet_icons/logo.svg'), alt: "GitLab logo" }
......@@ -19,4 +18,4 @@
= embedded_snippet_download_button
%article.file-holder.snippet-file-content
= render 'projects/blob/viewer', viewer: @snippet.blob.simple_viewer, load_async: false, external_embed: true
= render 'projects/blob/viewer', viewer: @blob.simple_viewer, load_async: false, external_embed: true
......@@ -10,8 +10,7 @@
= render 'shared/snippets/header'
.personal-snippets
%article.file-holder.snippet-file-content
= render 'shared/snippets/blob'
= render 'shared/snippets/blob', blob: @blob
.row-content-block.top-block.content-component-block
= render 'award_emoji/awards_block', awardable: @snippet, inline: true
......
---
title: Render single snippet blob in repository
merge_request: 23848
author:
type: added
......@@ -155,7 +155,7 @@ module Gitlab
end
def repository
@repository ||= project.repository
@repository ||= project&.repository
end
end
end
......
......@@ -3,9 +3,11 @@
require 'spec_helper'
describe Projects::SnippetsController do
include Gitlab::Routing
let_it_be(:user) { create(:user) }
let_it_be(:user2) { create(:user) }
let(:project) { create(:project_empty_repo, :public) }
let(:user) { create(:user) }
let(:user2) { create(:user) }
before do
project.add_maintainer(user)
......@@ -318,14 +320,45 @@ describe Projects::SnippetsController do
end
end
shared_examples 'successful response' do
it 'renders the snippet' do
subject
expect(assigns(:snippet)).to eq(project_snippet)
expect(response).to have_gitlab_http_status(:ok)
end
it 'renders the blob from the repository' do
subject
expect(assigns(:blob)).to eq(project_snippet.blobs.first)
end
context 'when feature flag version_snippets is disabled' do
before do
stub_feature_flags(version_snippets: false)
end
it 'returns the snippet database content' do
subject
blob = assigns(:blob)
expect(blob.data).to eq(project_snippet.content)
end
end
end
%w[show raw].each do |action|
describe "GET ##{action}" do
context 'when the project snippet is private' do
let(:project_snippet) { create(:project_snippet, :private, project: project, author: user) }
let(:project_snippet) { create(:project_snippet, :private, :repository, project: project, author: user) }
subject { get action, params: { namespace_id: project.namespace, project_id: project, id: project_snippet.to_param } }
context 'when anonymous' do
it 'responds with status 404' do
get action, params: { namespace_id: project.namespace, project_id: project, id: project_snippet.to_param }
subject
expect(response).to have_gitlab_http_status(:not_found)
end
......@@ -336,12 +369,7 @@ describe Projects::SnippetsController do
sign_in(user)
end
it 'renders the snippet' do
get action, params: { namespace_id: project.namespace, project_id: project, id: project_snippet.to_param }
expect(assigns(:snippet)).to eq(project_snippet)
expect(response).to have_gitlab_http_status(:ok)
end
it_behaves_like 'successful response'
end
context 'when signed in as a project member' do
......@@ -349,19 +377,16 @@ describe Projects::SnippetsController do
sign_in(user2)
end
it 'renders the snippet' do
get action, params: { namespace_id: project.namespace, project_id: project, id: project_snippet.to_param }
expect(assigns(:snippet)).to eq(project_snippet)
expect(response).to have_gitlab_http_status(:ok)
end
it_behaves_like 'successful response'
end
end
context 'when the project snippet does not exist' do
subject { get action, params: { namespace_id: project.namespace, project_id: project, id: 42 } }
context 'when anonymous' do
it 'responds with status 404' do
get action, params: { namespace_id: project.namespace, project_id: project, id: 42 }
subject
expect(response).to have_gitlab_http_status(:not_found)
end
......@@ -373,7 +398,7 @@ describe Projects::SnippetsController do
end
it 'responds with status 404' do
get action, params: { namespace_id: project.namespace, project_id: project, id: 42 }
subject
expect(response).to have_gitlab_http_status(:not_found)
end
......@@ -383,18 +408,20 @@ describe Projects::SnippetsController do
end
describe "GET #show for embeddable content" do
let(:project_snippet) { create(:project_snippet, snippet_permission, project: project, author: user) }
let(:project_snippet) { create(:project_snippet, :repository, snippet_permission, project: project, author: user) }
before do
sign_in(user)
get :show, params: { namespace_id: project.namespace, project_id: project, id: project_snippet.to_param }, format: :js
end
subject { get :show, params: { namespace_id: project.namespace, project_id: project, id: project_snippet.to_param }, format: :js }
context 'when snippet is private' do
let(:snippet_permission) { :private }
it 'responds with status 404' do
subject
expect(response).to have_gitlab_http_status(:not_found)
end
end
......@@ -402,10 +429,7 @@ describe Projects::SnippetsController do
context 'when snippet is public' do
let(:snippet_permission) { :public }
it 'responds with status 200' do
expect(assigns(:snippet)).to eq(project_snippet)
expect(response).to have_gitlab_http_status(:ok)
end
it_behaves_like 'successful response'
end
context 'when the project is private' do
......@@ -415,6 +439,8 @@ describe Projects::SnippetsController do
let(:project_snippet) { create(:project_snippet, :public, project: project, author: user) }
it 'responds with status 404' do
subject
expect(assigns(:snippet)).to eq(project_snippet)
expect(response).to have_gitlab_http_status(:not_found)
end
......@@ -423,14 +449,17 @@ describe Projects::SnippetsController do
end
describe 'GET #raw' do
let(:content) { "first line\r\nsecond line\r\nthird line" }
let(:formatted_content) { content.gsub(/\r\n/, "\n") }
let(:project_snippet) do
create(
:project_snippet, :public,
:project_snippet, :public, :repository,
project: project,
author: user,
content: "first line\r\nsecond line\r\nthird line"
content: content
)
end
let(:blob) { project_snippet.blobs.first }
context 'CRLF line ending' do
let(:params) do
......@@ -441,16 +470,22 @@ describe Projects::SnippetsController do
}
end
before do
allow_next_instance_of(Blob) do |instance|
allow(instance).to receive(:data).and_return(content)
end
end
it 'returns LF line endings by default' do
get :raw, params: params
expect(response.body).to eq("first line\nsecond line\nthird line")
expect(response.body).to eq(formatted_content)
end
it 'does not convert line endings when parameter present' do
get :raw, params: params.merge(line_ending: :raw)
expect(response.body).to eq("first line\r\nsecond line\r\nthird line")
expect(response.body).to eq(content)
end
end
end
......
......@@ -3,11 +3,9 @@
require 'spec_helper'
describe SnippetsController do
let(:user) { create(:user) }
let_it_be(:user) { create(:user) }
describe 'GET #index' do
let(:user) { create(:user) }
context 'when username parameter is present' do
it_behaves_like 'paginated collection' do
let(:collection) { Snippet.all }
......@@ -75,8 +73,37 @@ describe SnippetsController do
end
describe 'GET #show' do
shared_examples 'successful response' do
it 'renders the snippet' do
subject
expect(assigns(:snippet)).to eq(personal_snippet)
expect(response).to have_gitlab_http_status(:ok)
end
it 'renders the blob from the repository' do
subject
expect(assigns(:blob)).to eq(personal_snippet.blobs.first)
end
context 'when feature flag version_snippets is disabled' do
before do
stub_feature_flags(version_snippets: false)
end
it 'returns the snippet database content' do
subject
blob = assigns(:blob)
expect(blob.data).to eq(personal_snippet.content)
end
end
end
context 'when the personal snippet is private' do
let(:personal_snippet) { create(:personal_snippet, :private, author: user) }
let_it_be(:personal_snippet) { create(:personal_snippet, :private, :repository, author: user) }
context 'when signed in' do
before do
......@@ -95,11 +122,8 @@ describe SnippetsController do
end
context 'when signed in user is the author' do
it 'renders the snippet' do
get :show, params: { id: personal_snippet.to_param }
expect(assigns(:snippet)).to eq(personal_snippet)
expect(response).to have_gitlab_http_status(:ok)
it_behaves_like 'successful response' do
subject { get :show, params: { id: personal_snippet.to_param } }
end
it 'responds with status 404 when embeddable content is requested' do
......@@ -120,18 +144,15 @@ describe SnippetsController do
end
context 'when the personal snippet is internal' do
let(:personal_snippet) { create(:personal_snippet, :internal, author: user) }
let_it_be(:personal_snippet) { create(:personal_snippet, :internal, :repository, author: user) }
context 'when signed in' do
before do
sign_in(user)
end
it 'renders the snippet' do
get :show, params: { id: personal_snippet.to_param }
expect(assigns(:snippet)).to eq(personal_snippet)
expect(response).to have_gitlab_http_status(:ok)
it_behaves_like 'successful response' do
subject { get :show, params: { id: personal_snippet.to_param } }
end
it 'responds with status 404 when embeddable content is requested' do
......@@ -151,18 +172,15 @@ describe SnippetsController do
end
context 'when the personal snippet is public' do
let(:personal_snippet) { create(:personal_snippet, :public, author: user) }
let_it_be(:personal_snippet) { create(:personal_snippet, :public, :repository, author: user) }
context 'when signed in' do
before do
sign_in(user)
end
it 'renders the snippet' do
get :show, params: { id: personal_snippet.to_param }
expect(assigns(:snippet)).to eq(personal_snippet)
expect(response).to have_gitlab_http_status(:ok)
it_behaves_like 'successful response' do
subject { get :show, params: { id: personal_snippet.to_param } }
end
it 'responds with status 200 when embeddable content is requested' do
......@@ -481,8 +499,82 @@ describe SnippetsController do
end
describe "GET #raw" do
shared_examples '200 status' do
before do
subject
end
it 'responds with status 200' do
expect(assigns(:snippet)).to eq(snippet)
expect(response).to have_gitlab_http_status(:ok)
end
it 'has expected headers' do
expect(response.header['Content-Type']).to eq('text/plain; charset=utf-8')
expect(response.header['Content-Disposition']).to match(/inline/)
end
it "sets #{Gitlab::Workhorse::DETECT_HEADER} header" do
expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq 'true'
end
end
shared_examples 'CRLF line ending' do
let(:content) { "first line\r\nsecond line\r\nthird line" }
let(:formatted_content) { content.gsub(/\r\n/, "\n") }
let(:snippet) do
create(:personal_snippet, :public, :repository, author: user, content: content)
end
before do
allow_next_instance_of(Blob) do |instance|
allow(instance).to receive(:data).and_return(content)
end
subject
end
it 'returns LF line endings by default' do
expect(response.body).to eq(formatted_content)
end
context 'when parameter present' do
let(:params) { { id: snippet.to_param, line_ending: :raw } }
it 'does not convert line endings when parameter present' do
expect(response.body).to eq(content)
end
end
end
shared_examples 'successful response' do
it_behaves_like '200 status'
it_behaves_like 'CRLF line ending'
it 'returns snippet first blob data' do
subject
expect(response.body).to eq snippet.blobs.first.data
end
context 'when feature flag version_snippets is disabled' do
before do
stub_feature_flags(version_snippets: false)
end
it_behaves_like '200 status'
it_behaves_like 'CRLF line ending'
it 'returns snippet database content' do
subject
expect(response.body).to eq snippet.content
end
end
end
context 'when the personal snippet is private' do
let(:personal_snippet) { create(:personal_snippet, :private, author: user) }
let_it_be(:personal_snippet) { create(:personal_snippet, :private, :repository, author: user) }
context 'when signed in' do
before do
......@@ -501,24 +593,11 @@ describe SnippetsController do
end
context 'when signed in user is the author' do
before do
get :raw, params: { id: personal_snippet.to_param }
end
it 'responds with status 200' do
expect(assigns(:snippet)).to eq(personal_snippet)
expect(response).to have_gitlab_http_status(:ok)
end
it_behaves_like 'successful response' do
let(:snippet) { personal_snippet }
let(:params) { { id: snippet.to_param } }
it 'has expected headers' do
expect(response.header['Content-Type']).to eq('text/plain; charset=utf-8')
expect(response.header['Content-Disposition']).to match(/inline/)
end
it "sets #{Gitlab::Workhorse::DETECT_HEADER} header" do
expect(response).to have_gitlab_http_status(:ok)
expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
subject { get :raw, params: params }
end
end
end
......@@ -533,18 +612,18 @@ describe SnippetsController do
end
context 'when the personal snippet is internal' do
let(:personal_snippet) { create(:personal_snippet, :internal, author: user) }
let_it_be(:personal_snippet) { create(:personal_snippet, :internal, :repository, author: user) }
context 'when signed in' do
before do
sign_in(user)
end
it 'responds with status 200' do
get :raw, params: { id: personal_snippet.to_param }
it_behaves_like 'successful response' do
let(:snippet) { personal_snippet }
let(:params) { { id: snippet.to_param } }
expect(assigns(:snippet)).to eq(personal_snippet)
expect(response).to have_gitlab_http_status(:ok)
subject { get :raw, params: params }
end
end
......@@ -558,36 +637,18 @@ describe SnippetsController do
end
context 'when the personal snippet is public' do
let(:personal_snippet) { create(:personal_snippet, :public, author: user) }
let_it_be(:personal_snippet) { create(:personal_snippet, :public, :repository, author: user) }
context 'when signed in' do
before do
sign_in(user)
end
it 'responds with status 200' do
get :raw, params: { id: personal_snippet.to_param }
it_behaves_like 'successful response' do
let(:snippet) { personal_snippet }
let(:params) { { id: snippet.to_param } }
expect(assigns(:snippet)).to eq(personal_snippet)
expect(response).to have_gitlab_http_status(:ok)
end
context 'CRLF line ending' do
let(:personal_snippet) do
create(:personal_snippet, :public, author: user, content: "first line\r\nsecond line\r\nthird line")
end
it 'returns LF line endings by default' do
get :raw, params: { id: personal_snippet.to_param }
expect(response.body).to eq("first line\nsecond line\nthird line")
end
it 'does not convert line endings when parameter present' do
get :raw, params: { id: personal_snippet.to_param, line_ending: :raw }
expect(response.body).to eq("first line\r\nsecond line\r\nthird line")
end
subject { get :raw, params: params }
end
end
......
......@@ -3,9 +3,9 @@
require 'spec_helper'
describe 'Thread Comments Snippet', :js do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:snippet) { create(:project_snippet, :private, project: project, author: user) }
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:snippet) { create(:project_snippet, :private, :repository, project: project, author: user) }
before do
stub_feature_flags(snippets_vue: false)
......
......@@ -5,8 +5,8 @@ require 'spec_helper'
describe 'Projects > Snippets > Create Snippet', :js do
include DropzoneHelper
let(:user) { create(:user) }
let(:project) { create(:project, :public) }
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public) }
def description_field
find('.js-description-input input,textarea')
......@@ -102,7 +102,7 @@ describe 'Projects > Snippets > Create Snippet', :js do
end
it 'shows a public snippet on the index page but not the New snippet button' do
snippet = create(:project_snippet, :public, project: project)
snippet = create(:project_snippet, :public, :repository, project: project)
visit project_snippets_path(project)
......
......@@ -3,9 +3,9 @@
require 'spec_helper'
describe 'Projects > Snippets > User comments on a snippet', :js do
let(:project) { create(:project) }
let!(:snippet) { create(:project_snippet, project: project, author: user) }
let(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:snippet) { create(:project_snippet, :repository, project: project, author: user) }
before do
stub_feature_flags(snippets_vue: false)
......
......@@ -3,8 +3,8 @@
require 'spec_helper'
describe 'Reportable note on snippets', :js do
let(:user) { create(:user) }
let(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
before do
stub_feature_flags(snippets_vue: false)
......@@ -13,8 +13,8 @@ describe 'Reportable note on snippets', :js do
end
describe 'on project snippet' do
let(:snippet) { create(:project_snippet, :public, project: project, author: user) }
let!(:note) { create(:note_on_project_snippet, noteable: snippet, project: project) }
let_it_be(:snippet) { create(:project_snippet, :public, :repository, project: project, author: user) }
let_it_be(:note) { create(:note_on_project_snippet, noteable: snippet, project: project) }
before do
visit project_snippet_path(project, snippet)
......
......@@ -16,4 +16,47 @@ describe GitlabSchema.types['Snippet'] do
describe 'authorizations' do
it { expect(described_class).to require_graphql_authorizations(:read_snippet) }
end
describe '#blob' do
let_it_be(:user) { create(:user) }
let(:query_blob) { subject.dig('data', 'snippets', 'edges')[0]['node']['blob'] }
let(:query) do
%(
{
snippets {
edges {
node {
blob {
name
path
}
}
}
}
}
)
end
subject { GitlabSchema.execute(query, context: { current_user: user }).as_json }
context 'when snippet has repository' do
let!(:snippet) { create(:personal_snippet, :repository, :public, author: user) }
let(:blob) { snippet.blobs.first }
it 'returns blob from the repository' do
expect(query_blob['name']).to eq blob.name
expect(query_blob['path']).to eq blob.path
end
end
context 'when snippet does not have a repository' do
let!(:snippet) { create(:personal_snippet, :public, author: user) }
let(:blob) { snippet.blob }
it 'returns SnippetBlob type' do
expect(query_blob['name']).to eq blob.name
expect(query_blob['path']).to eq blob.path
end
end
end
end
......@@ -11,13 +11,20 @@ describe BlobLanguageFromGitAttributes do
subject(:blob) { fake_blob(path: 'file.md') }
it 'returns return value from gitattribute' do
expect(blob.project.repository).to receive(:gitattribute).with(blob.path, 'gitlab-language').and_return('erb?parent=json')
allow(blob.repository).to receive(:exists?).and_return(true)
expect(blob.repository).to receive(:gitattribute).with(blob.path, 'gitlab-language').and_return('erb?parent=json')
expect(blob.language_from_gitattributes).to eq('erb?parent=json')
end
it 'returns nil if project is absent' do
allow(blob).to receive(:project).and_return(nil)
it 'returns nil if repository is absent' do
allow(blob).to receive(:repository).and_return(nil)
expect(blob.language_from_gitattributes).to eq(nil)
end
it 'returns nil if repository does not exist' do
allow(blob.repository).to receive(:exists?).and_return(false)
expect(blob.language_from_gitattributes).to eq(nil)
end
......
......@@ -76,18 +76,18 @@ describe SnippetBlobPresenter do
context 'with ProjectSnippet' do
let!(:project) { create(:project) }
let(:snippet) { build(:project_snippet, project: project, id: 1) }
let(:snippet) { create(:project_snippet, project: project) }
it 'returns the raw path' do
expect(subject).to eq "/#{snippet.project.full_path}/snippets/1/raw"
expect(subject).to eq "/#{snippet.project.full_path}/snippets/#{snippet.id}/raw"
end
end
context 'with PersonalSnippet' do
let(:snippet) { build(:personal_snippet, id: 1) }
let(:snippet) { create(:personal_snippet) }
it 'returns the raw path' do
expect(subject).to eq "/snippets/1/raw"
expect(subject).to eq "/snippets/#{snippet.id}/raw"
end
end
end
......
......@@ -143,4 +143,24 @@ describe SnippetPresenter do
expect(subject).to be_truthy
end
end
describe '#blob' do
let(:snippet) { personal_snippet }
subject { presenter.blob }
context 'when snippet does not have a repository' do
it 'returns SnippetBlob' do
expect(subject).to eq snippet.blob
end
end
context 'when snippet has a repository' do
let(:snippet) { create(:snippet, :repository, author: user) }
it 'returns repository first blob' do
expect(subject).to eq snippet.blobs.first
end
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