diff options
Diffstat (limited to 'spec/lib/banzai')
9 files changed, 441 insertions, 91 deletions
diff --git a/spec/lib/banzai/filter/design_reference_filter_spec.rb b/spec/lib/banzai/filter/design_reference_filter_spec.rb new file mode 100644 index 00000000000..8a6c2e3b3f9 --- /dev/null +++ b/spec/lib/banzai/filter/design_reference_filter_spec.rb @@ -0,0 +1,307 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Banzai::Filter::DesignReferenceFilter do + include FilterSpecHelper + include DesignManagementTestHelpers + + let_it_be(:issue) { create(:issue, iid: 10) } + let_it_be(:issue_proj_2) { create(:issue, iid: 20) } + let_it_be(:issue_b) { create(:issue, project: issue.project) } + let_it_be(:developer) { create(:user, developer_projects: [issue.project, issue_proj_2.project]) } + let_it_be(:design_a) { create(:design, :with_versions, issue: issue) } + let_it_be(:design_b) { create(:design, :with_versions, issue: issue_b) } + let_it_be(:design_proj_2) { create(:design, :with_versions, issue: issue_proj_2) } + let_it_be(:project_with_no_lfs) { create(:project, :public, lfs_enabled: false) } + + let(:design) { design_a } + let(:project) { issue.project } + let(:project_2) { issue_proj_2.project } + let(:reference) { design.to_reference } + let(:design_url) { url_for_design(design) } + let(:input_text) { "Added #{design_url}" } + let(:doc) { process_doc(input_text) } + let(:current_user) { developer } + + before do + enable_design_management + end + + shared_examples 'a no-op filter' do + it 'does nothing' do + expect(process(input_text)).to eq(baseline(input_text).to_html) + end + end + + shared_examples 'a good link reference' do + let(:link) { doc.css('a').first } + let(:href) { url_for_design(design) } + let(:title) { design.filename } + + it 'produces a good link', :aggregate_failures do + expect(link.attr('href')).to eq(href) + expect(link.attr('title')).to eq(title) + expect(link.attr('class')).to eq('gfm gfm-design has-tooltip') + expect(link.attr('data-project')).to eq(design.project.id.to_s) + expect(link.attr('data-issue')).to eq(design.issue.id.to_s) + expect(link.attr('data-original')).to eq(href) + expect(link.attr('data-reference-type')).to eq('design') + expect(link.text).to eq(design.to_reference(project)) + end + end + + describe '.call' do + it 'requires project context' do + expect { described_class.call('') }.to raise_error(ArgumentError, /:project/) + end + end + + it 'does not error when we add redaction to the pipeline' do + enable_design_management + + res = reference_pipeline(redact: true).to_document(input_text) + + expect(res.css('a').first).to be_present + end + + describe '#call' do + describe 'feature flags' do + context 'design management is not enabled' do + before do + enable_design_management(false) + end + + it_behaves_like 'a no-op filter' + end + + context 'design reference filter is not enabled' do + before do + stub_feature_flags(described_class::FEATURE_FLAG => false) + end + + it_behaves_like 'a no-op filter' + + it 'issues no queries' do + expect { process(input_text) }.not_to exceed_query_limit(0) + end + end + + context 'the filter is enabled for the context project' do + before do + stub_feature_flags(described_class::FEATURE_FLAG => project) + end + + it_behaves_like 'a good link reference' + end + end + end + + %w(pre code a style).each do |elem| + context "wrapped in a <#{elem}/>" do + let(:input_text) { "<#{elem}>Design #{url_for_design(design)}</#{elem}>" } + + it_behaves_like 'a no-op filter' + end + end + + describe '.identifier' do + where(:filename) do + [ + ['simple.png'], + ['SIMPLE.PNG'], + ['has spaces.png'], + ['has-hyphen.jpg'], + ['snake_case.svg'], + ['has "quotes".svg'], + ['has <special> characters [o].svg'] + ] + end + + with_them do + let(:design) { build(:design, issue: issue, filename: filename) } + let(:url) { url_for_design(design) } + let(:pattern) { described_class.object_class.link_reference_pattern } + let(:parsed) do + m = pattern.match(url) + described_class.identifier(m) if m + end + + it 'can parse the reference' do + expect(parsed).to have_attributes( + filename: filename, + issue_iid: issue.iid + ) + end + end + end + + describe 'static properties' do + specify do + expect(described_class).to have_attributes( + object_sym: :design, + object_class: ::DesignManagement::Design + ) + end + end + + describe '#data_attributes_for' do + let(:subject) { filter_instance.data_attributes_for(input_text, project, design) } + + specify do + is_expected.to include(issue: design.issue_id, + original: input_text, + project: project.id, + design: design.id) + end + end + + context 'a design with a quoted filename' do + let(:filename) { %q{A "very" good file.png} } + let(:design) { create(:design, :with_versions, issue: issue, filename: filename) } + + it 'links to the design' do + expect(doc.css('a').first.attr('href')) + .to eq url_for_design(design) + end + end + + context 'internal reference' do + it_behaves_like 'a reference containing an element node' + + context 'the reference is valid' do + it_behaves_like 'a good link reference' + + context 'the filename needs to be escaped' do + where(:filename) do + [ + ['with some spaces.png'], + ['with <script>console.log("pwded")<%2Fscript>.png'] + ] + end + + with_them do + let(:design) { create(:design, :with_versions, filename: filename, issue: issue) } + let(:link) { doc.css('a').first } + + it 'replaces the content with the reference, but keeps the link', :aggregate_failures do + expect(doc.text).to eq(CGI.unescapeHTML("Added #{design.to_reference}")) + expect(link.attr('title')).to eq(design.filename) + expect(link.attr('href')).to eq(design_url) + end + end + end + end + + context 'the reference is to a non-existant design' do + let(:design_url) { url_for_design(build(:design, issue: issue)) } + + it_behaves_like 'a no-op filter' + end + + context 'design management is disabled for the referenced project' do + let(:public_issue) { create(:issue, project: project_with_no_lfs) } + let(:design) { create(:design, :with_versions, issue: public_issue) } + + it_behaves_like 'a no-op filter' + end + end + + describe 'link pattern' do + let(:reference) { url_for_design(design) } + + it 'matches' do + expect(reference).to match(DesignManagement::Design.link_reference_pattern) + end + end + + context 'cross-project / cross-namespace complete reference' do + let(:design) { design_proj_2 } + + it_behaves_like 'a reference containing an element node' + + it_behaves_like 'a good link reference' + + it 'links to a valid reference' do + expect(doc.css('a').first.attr('href')).to eq(design_url) + end + + context 'design management is disabled for that project' do + let(:design) { create(:design, project: project_with_no_lfs) } + + it_behaves_like 'a no-op filter' + end + + it 'link has valid text' do + ref = "#{design.project.full_path}##{design.issue.iid}[#{design.filename}]" + + expect(doc.css('a').first.text).to eql(ref) + end + + it 'includes default classes' do + expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-design has-tooltip' + end + + context 'the reference is invalid' do + let(:design_url) { url_for_design(design).gsub(/jpg/, 'gif') } + + it_behaves_like 'a no-op filter' + end + end + + describe 'performance' do + it 'is linear in the number of projects with design management enabled each design refers to' do + design_c = build(:design, :with_versions, issue: issue) + design_d = build(:design, :with_versions, issue: issue_b) + design_e = build(:design, :with_versions, issue: build_stubbed(:issue, project: project_2)) + + one_ref_per_project = <<~MD + Design #{url_for_design(design_a)}, #{url_for_design(design_proj_2)} + MD + + multiple_references = <<~MD + Designs that affect the count: + * #{url_for_design(design_a)} + * #{url_for_design(design_b)} + * #{url_for_design(design_c)} + * #{url_for_design(design_d)} + * #{url_for_design(design_proj_2)} + * #{url_for_design(design_e)} + + Things that do not affect the count: + * #{url_for_design(build_stubbed(:design, project: project_with_no_lfs))} + * #{url_for_designs(issue)} + * #1[not a valid reference.gif] + MD + + baseline = ActiveRecord::QueryRecorder.new { process(one_ref_per_project) } + + # each project mentioned requires 2 queries: + # + # * SELECT "issues".* FROM "issues" WHERE "issues"."project_id" = 1 AND ... + # :in `parent_records'*/ + # * SELECT "_designs".* FROM "_designs" + # WHERE (issue_id = ? AND filename = ?) OR ... + # :in `parent_records'*/ + # + # In addition there is a 1 query overhead for all the projects at the + # start. Currently, the baseline for 2 projects is `2 * 2 + 1 = 5` queries + # + expect { process(multiple_references) }.not_to exceed_query_limit(baseline.count) + end + end + + private + + def process_doc(text) + reference_filter(text, project: project) + end + + def baseline(text) + null_filter(text, project: project) + end + + def process(text) + process_doc(text).to_html + end +end diff --git a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb index 78795a157f8..a70c820f97a 100644 --- a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb @@ -5,10 +5,6 @@ require 'spec_helper' describe Banzai::Filter::ExternalIssueReferenceFilter do include FilterSpecHelper - def helper - IssuesHelper - end - shared_examples_for "external issue tracker" do it_behaves_like 'a reference containing an element node' @@ -36,7 +32,7 @@ describe Banzai::Filter::ExternalIssueReferenceFilter do issue_id = doc.css('a').first.attr("data-external-issue") expect(doc.css('a').first.attr('href')) - .to eq helper.url_for_issue(issue_id, project) + .to eq project.external_issue_tracker.issue_url(issue_id) end it 'links to the external tracker' do @@ -45,7 +41,7 @@ describe Banzai::Filter::ExternalIssueReferenceFilter do link = doc.css('a').first.attr('href') issue_id = doc.css('a').first.attr("data-external-issue") - expect(link).to eq(helper.url_for_issue(issue_id, project)) + expect(link).to eq(project.external_issue_tracker.issue_url(issue_id)) end it 'links with adjacent text' do @@ -56,7 +52,7 @@ describe Banzai::Filter::ExternalIssueReferenceFilter do it 'includes a title attribute' do doc = filter("Issue #{reference}") - expect(doc.css('a').first.attr('title')).to include("Issue in #{project.issues_tracker.title}") + expect(doc.css('a').first.attr('title')).to include("Issue in #{project.external_issue_tracker.title}") end it 'escapes the title attribute' do @@ -78,7 +74,25 @@ describe Banzai::Filter::ExternalIssueReferenceFilter do link = doc.css('a').first.attr('href') issue_id = doc.css('a').first["data-external-issue"] - expect(link).to eq helper.url_for_issue(issue_id, project, only_path: true) + expect(link).to eq project.external_issue_tracker.issue_path(issue_id) + end + + it 'has an empty link if issue_url is invalid' do + expect_any_instance_of(project.external_issue_tracker.class).to receive(:issue_url) { 'javascript:alert("foo");' } + + doc = filter("Issue #{reference}") + link = doc.css('a').first.attr('href') + + expect(link).to eq '' + end + + it 'has an empty link if issue_path is invalid' do + expect_any_instance_of(project.external_issue_tracker.class).to receive(:issue_path) { 'javascript:alert("foo");' } + + doc = filter("Issue #{reference}", only_path: true) + link = doc.css('a').first.attr('href') + + expect(link).to eq '' end context 'with RequestStore enabled', :request_store do diff --git a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb index 1580177eaad..00d8b871224 100644 --- a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb +++ b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb @@ -7,11 +7,11 @@ describe Banzai::Filter::GollumTagsFilter do let(:project) { create(:project) } let(:user) { double } - let(:project_wiki) { ProjectWiki.new(project, user) } + let(:wiki) { ProjectWiki.new(project, user) } describe 'validation' do - it 'ensure that a :project_wiki key exists in context' do - expect { filter("See [[images/image.jpg]]", {}) }.to raise_error ArgumentError, "Missing context keys for Banzai::Filter::GollumTagsFilter: :project_wiki" + it 'ensure that a :wiki key exists in context' do + expect { filter("See [[images/image.jpg]]", {}) }.to raise_error ArgumentError, "Missing context keys for Banzai::Filter::GollumTagsFilter: :wiki" end end @@ -23,19 +23,19 @@ describe Banzai::Filter::GollumTagsFilter do path: 'images/image.jpg', raw_data: '') wiki_file = Gitlab::Git::WikiFile.new(gollum_file_double) - expect(project_wiki).to receive(:find_file).with('images/image.jpg').and_return(wiki_file) + expect(wiki).to receive(:find_file).with('images/image.jpg').and_return(wiki_file) tag = '[[images/image.jpg]]' - doc = filter("See #{tag}", project_wiki: project_wiki) + doc = filter("See #{tag}", wiki: wiki) - expect(doc.at_css('img')['data-src']).to eq "#{project_wiki.wiki_base_path}/images/image.jpg" + expect(doc.at_css('img')['data-src']).to eq "#{wiki.wiki_base_path}/images/image.jpg" end it 'does not creates img tag if image does not exist' do - expect(project_wiki).to receive(:find_file).with('images/image.jpg').and_return(nil) + expect(wiki).to receive(:find_file).with('images/image.jpg').and_return(nil) tag = '[[images/image.jpg]]' - doc = filter("See #{tag}", project_wiki: project_wiki) + doc = filter("See #{tag}", wiki: wiki) expect(doc.css('img').size).to eq 0 end @@ -44,14 +44,14 @@ describe Banzai::Filter::GollumTagsFilter do context 'linking external images' do it 'creates img tag for valid URL' do tag = '[[http://example.com/image.jpg]]' - doc = filter("See #{tag}", project_wiki: project_wiki) + doc = filter("See #{tag}", wiki: wiki) expect(doc.at_css('img')['data-src']).to eq "http://example.com/image.jpg" end it 'does not creates img tag for invalid URL' do tag = '[[http://example.com/image.pdf]]' - doc = filter("See #{tag}", project_wiki: project_wiki) + doc = filter("See #{tag}", wiki: wiki) expect(doc.css('img').size).to eq 0 end @@ -60,7 +60,7 @@ describe Banzai::Filter::GollumTagsFilter do context 'linking external resources' do it "the created link's text will be equal to the resource's text" do tag = '[[http://example.com]]' - doc = filter("See #{tag}", project_wiki: project_wiki) + doc = filter("See #{tag}", wiki: wiki) expect(doc.at_css('a').text).to eq 'http://example.com' expect(doc.at_css('a')['href']).to eq 'http://example.com' @@ -68,7 +68,7 @@ describe Banzai::Filter::GollumTagsFilter do it "the created link's text will be link-text" do tag = '[[link-text|http://example.com/pdfs/gollum.pdf]]' - doc = filter("See #{tag}", project_wiki: project_wiki) + doc = filter("See #{tag}", wiki: wiki) expect(doc.at_css('a').text).to eq 'link-text' expect(doc.at_css('a')['href']).to eq 'http://example.com/pdfs/gollum.pdf' @@ -78,8 +78,8 @@ describe Banzai::Filter::GollumTagsFilter do context 'linking internal resources' do it "the created link's text includes the resource's text and wiki base path" do tag = '[[wiki-slug]]' - doc = filter("See #{tag}", project_wiki: project_wiki) - expected_path = ::File.join(project_wiki.wiki_base_path, 'wiki-slug') + doc = filter("See #{tag}", wiki: wiki) + expected_path = ::File.join(wiki.wiki_base_path, 'wiki-slug') expect(doc.at_css('a').text).to eq 'wiki-slug' expect(doc.at_css('a')['href']).to eq expected_path @@ -87,15 +87,15 @@ describe Banzai::Filter::GollumTagsFilter do it "the created link's text will be link-text" do tag = '[[link-text|wiki-slug]]' - doc = filter("See #{tag}", project_wiki: project_wiki) - expected_path = ::File.join(project_wiki.wiki_base_path, 'wiki-slug') + doc = filter("See #{tag}", wiki: wiki) + expected_path = ::File.join(wiki.wiki_base_path, 'wiki-slug') expect(doc.at_css('a').text).to eq 'link-text' expect(doc.at_css('a')['href']).to eq expected_path end it "inside back ticks will be exempt from linkification" do - doc = filter('<code>[[link-in-backticks]]</code>', project_wiki: project_wiki) + doc = filter('<code>[[link-in-backticks]]</code>', wiki: wiki) expect(doc.at_css('code').text).to eq '[[link-in-backticks]]' end diff --git a/spec/lib/banzai/filter/issue_reference_filter_spec.rb b/spec/lib/banzai/filter/issue_reference_filter_spec.rb index 61c59162a30..603da2b4421 100644 --- a/spec/lib/banzai/filter/issue_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/issue_reference_filter_spec.rb @@ -11,7 +11,9 @@ describe Banzai::Filter::IssueReferenceFilter do end let(:project) { create(:project, :public) } - let(:issue) { create(:issue, project: project) } + let(:issue) { create(:issue, project: project) } + let(:issue_path) { "/#{issue.project.namespace.path}/#{issue.project.path}/-/issues/#{issue.iid}" } + let(:issue_url) { "http://#{Gitlab.config.gitlab.host}#{issue_path}" } it 'requires project context' do expect { described_class.call('') }.to raise_error(ArgumentError, /:project/) @@ -46,7 +48,7 @@ describe Banzai::Filter::IssueReferenceFilter do doc = reference_filter("Fixed #{reference}") expect(doc.css('a').first.attr('href')) - .to eq helper.url_for_issue(issue.iid, project) + .to eq issue_url end it 'links with adjacent text' do @@ -113,7 +115,7 @@ describe Banzai::Filter::IssueReferenceFilter do link = doc.css('a').first.attr('href') expect(link).not_to match %r(https?://) - expect(link).to eq helper.url_for_issue(issue.iid, project, only_path: true) + expect(link).to eq issue_path end it 'does not process links containing issue numbers followed by text' do @@ -145,7 +147,7 @@ describe Banzai::Filter::IssueReferenceFilter do doc = reference_filter("See #{reference}") expect(doc.css('a').first.attr('href')) - .to eq helper.url_for_issue(issue.iid, project2) + .to eq issue_url end it 'link has valid text' do @@ -195,7 +197,7 @@ describe Banzai::Filter::IssueReferenceFilter do doc = reference_filter("See #{reference}") expect(doc.css('a').first.attr('href')) - .to eq helper.url_for_issue(issue.iid, project2) + .to eq issue_url end it 'link has valid text' do @@ -245,7 +247,7 @@ describe Banzai::Filter::IssueReferenceFilter do doc = reference_filter("See #{reference}") expect(doc.css('a').first.attr('href')) - .to eq helper.url_for_issue(issue.iid, project2) + .to eq issue_url end it 'link has valid text' do @@ -279,7 +281,7 @@ describe Banzai::Filter::IssueReferenceFilter do let(:namespace) { create(:namespace, name: 'cross-reference') } let(:project2) { create(:project, :public, namespace: namespace) } let(:issue) { create(:issue, project: project2) } - let(:reference) { helper.url_for_issue(issue.iid, project2) + "#note_123" } + let(:reference) { issue_url + "#note_123" } it 'links to a valid reference' do doc = reference_filter("See #{reference}") @@ -314,7 +316,7 @@ describe Banzai::Filter::IssueReferenceFilter do doc = reference_filter("See #{reference_link}") expect(doc.css('a').first.attr('href')) - .to eq helper.url_for_issue(issue.iid, project2) + .to eq issue_url end it 'links with adjacent text' do @@ -336,14 +338,14 @@ describe Banzai::Filter::IssueReferenceFilter do let(:namespace) { create(:namespace, name: 'cross-reference') } let(:project2) { create(:project, :public, namespace: namespace) } let(:issue) { create(:issue, project: project2) } - let(:reference) { "#{helper.url_for_issue(issue.iid, project2) + "#note_123"}" } + let(:reference) { "#{issue_url + "#note_123"}" } let(:reference_link) { %{<a href="#{reference}">Reference</a>} } it 'links to a valid reference' do doc = reference_filter("See #{reference_link}") expect(doc.css('a').first.attr('href')) - .to eq helper.url_for_issue(issue.iid, project2) + "#note_123" + .to eq issue_url + "#note_123" end it 'links with adjacent text' do @@ -374,6 +376,16 @@ describe Banzai::Filter::IssueReferenceFilter do expect(link.attr('href')).to eq(designs_tab_url) expect(link.text).to eq("#{issue.to_reference} (designs)") end + + context 'design management is not available' do + before do + enable_design_management(false) + end + + it 'links to the issue, but not to the designs tab' do + expect(link.text).to eq(issue.to_reference) + end + end end context 'group context' do @@ -403,7 +415,7 @@ describe Banzai::Filter::IssueReferenceFilter do doc = reference_filter("See #{reference}", context) link = doc.css('a').first - expect(link.attr('href')).to eq(helper.url_for_issue(issue.iid, project)) + expect(link.attr('href')).to eq(issue_url) expect(link.text).to include("#{project.full_path}##{issue.iid}") end @@ -415,23 +427,23 @@ describe Banzai::Filter::IssueReferenceFilter do end it 'links to a valid reference for url cross-reference' do - reference = helper.url_for_issue(issue.iid, project) + "#note_123" + reference = issue_url + "#note_123" doc = reference_filter("See #{reference}", context) link = doc.css('a').first - expect(link.attr('href')).to eq(helper.url_for_issue(issue.iid, project) + "#note_123") + expect(link.attr('href')).to eq(issue_url + "#note_123") expect(link.text).to include("#{project.full_path}##{issue.iid}") end it 'links to a valid reference for cross-reference in link href' do - reference = "#{helper.url_for_issue(issue.iid, project) + "#note_123"}" + reference = "#{issue_url + "#note_123"}" reference_link = %{<a href="#{reference}">Reference</a>} doc = reference_filter("See #{reference_link}", context) link = doc.css('a').first - expect(link.attr('href')).to eq(helper.url_for_issue(issue.iid, project) + "#note_123") + expect(link.attr('href')).to eq(issue_url + "#note_123") expect(link.text).to include('Reference') end @@ -441,7 +453,7 @@ describe Banzai::Filter::IssueReferenceFilter do doc = reference_filter("See #{reference_link}", context) link = doc.css('a').first - expect(link.attr('href')).to eq(helper.url_for_issue(issue.iid, project)) + expect(link.attr('href')).to eq(issue_url) expect(link.text).to include('Reference') end end diff --git a/spec/lib/banzai/filter/label_reference_filter_spec.rb b/spec/lib/banzai/filter/label_reference_filter_spec.rb index de7a70db1ac..0b697ab2040 100644 --- a/spec/lib/banzai/filter/label_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/label_reference_filter_spec.rb @@ -47,14 +47,34 @@ describe Banzai::Filter::LabelReferenceFilter do expect(link.attr('data-label')).to eq label.id.to_s end - it 'supports an :only_path context' do + it 'includes protocol when :only_path not present' do + doc = reference_filter("Label #{reference}") + link = doc.css('a').first.attr('href') + + expect(link).to match %r(https?://) + end + + it 'does not include protocol when :only_path true' do doc = reference_filter("Label #{reference}", only_path: true) link = doc.css('a').first.attr('href') expect(link).not_to match %r(https?://) + end + + it 'links to issue list when :label_url_method is not present' do + doc = reference_filter("Label #{reference}", only_path: true) + link = doc.css('a').first.attr('href') + expect(link).to eq urls.project_issues_path(project, label_name: label.name) end + it 'links to merge request list when `label_url_method: :project_merge_requests_url`' do + doc = reference_filter("Label #{reference}", { only_path: true, label_url_method: "project_merge_requests_url" }) + link = doc.css('a').first.attr('href') + + expect(link).to eq urls.project_merge_requests_path(project, label_name: label.name) + end + context 'project that does not exist referenced' do let(:result) { reference_filter('aaa/bbb~ccc') } diff --git a/spec/lib/banzai/filter/repository_link_filter_spec.rb b/spec/lib/banzai/filter/repository_link_filter_spec.rb index 460c76acd78..81f93f885f7 100644 --- a/spec/lib/banzai/filter/repository_link_filter_spec.rb +++ b/spec/lib/banzai/filter/repository_link_filter_spec.rb @@ -12,7 +12,7 @@ describe Banzai::Filter::RepositoryLinkFilter do project: project, current_user: user, group: group, - project_wiki: project_wiki, + wiki: wiki, ref: ref, requested_path: requested_path, only_path: only_path @@ -53,7 +53,7 @@ describe Banzai::Filter::RepositoryLinkFilter do let(:project_path) { project.full_path } let(:ref) { 'markdown' } let(:commit) { project.commit(ref) } - let(:project_wiki) { nil } + let(:wiki) { nil } let(:requested_path) { '/' } let(:only_path) { true } @@ -94,8 +94,8 @@ describe Banzai::Filter::RepositoryLinkFilter do end end - context 'with a project_wiki' do - let(:project_wiki) { double('ProjectWiki') } + context 'with a wiki' do + let(:wiki) { double('ProjectWiki') } include_examples :preserve_unchanged end diff --git a/spec/lib/banzai/filter/wiki_link_filter_spec.rb b/spec/lib/banzai/filter/wiki_link_filter_spec.rb index 4587bd85939..827f38ef717 100644 --- a/spec/lib/banzai/filter/wiki_link_filter_spec.rb +++ b/spec/lib/banzai/filter/wiki_link_filter_spec.rb @@ -12,13 +12,13 @@ describe Banzai::Filter::WikiLinkFilter do let(:repository_upload_folder) { Wikis::CreateAttachmentService::ATTACHMENT_PATH } it "doesn't rewrite absolute links" do - filtered_link = filter("<a href='http://example.com:8000/'>Link</a>", project_wiki: wiki).children[0] + filtered_link = filter("<a href='http://example.com:8000/'>Link</a>", wiki: wiki).children[0] expect(filtered_link.attribute('href').value).to eq('http://example.com:8000/') end it "doesn't rewrite links to project uploads" do - filtered_link = filter("<a href='/uploads/a.test'>Link</a>", project_wiki: wiki).children[0] + filtered_link = filter("<a href='/uploads/a.test'>Link</a>", wiki: wiki).children[0] expect(filtered_link.attribute('href').value).to eq('/uploads/a.test') end @@ -26,7 +26,7 @@ describe Banzai::Filter::WikiLinkFilter do describe "when links point to the #{Wikis::CreateAttachmentService::ATTACHMENT_PATH} folder" do context 'with an "a" html tag' do it 'rewrites links' do - filtered_link = filter("<a href='#{repository_upload_folder}/a.test'>Link</a>", project_wiki: wiki).children[0] + filtered_link = filter("<a href='#{repository_upload_folder}/a.test'>Link</a>", wiki: wiki).children[0] expect(filtered_link.attribute('href').value).to eq("#{wiki.wiki_base_path}/#{repository_upload_folder}/a.test") end @@ -37,7 +37,7 @@ describe Banzai::Filter::WikiLinkFilter do context 'inside an "a" html tag' do it 'rewrites links' do - filtered_elements = filter("<a href='#{repository_upload_folder}/a.jpg'><img src='#{repository_upload_folder}/a.jpg'>example</img></a>", project_wiki: wiki) + filtered_elements = filter("<a href='#{repository_upload_folder}/a.jpg'><img src='#{repository_upload_folder}/a.jpg'>example</img></a>", wiki: wiki) expect(filtered_elements.search('img').first.attribute('src').value).to eq(path) expect(filtered_elements.search('a').first.attribute('href').value).to eq(path) @@ -46,7 +46,7 @@ describe Banzai::Filter::WikiLinkFilter do context 'outside an "a" html tag' do it 'rewrites links' do - filtered_link = filter("<img src='#{repository_upload_folder}/a.jpg'>example</img>", project_wiki: wiki).children[0] + filtered_link = filter("<img src='#{repository_upload_folder}/a.jpg'>example</img>", wiki: wiki).children[0] expect(filtered_link.attribute('src').value).to eq(path) end @@ -55,7 +55,7 @@ describe Banzai::Filter::WikiLinkFilter do context 'with "video" html tag' do it 'rewrites links' do - filtered_link = filter("<video src='#{repository_upload_folder}/a.mp4'></video>", project_wiki: wiki).children[0] + filtered_link = filter("<video src='#{repository_upload_folder}/a.mp4'></video>", wiki: wiki).children[0] expect(filtered_link.attribute('src').value).to eq("#{wiki.wiki_base_path}/#{repository_upload_folder}/a.mp4") end @@ -63,7 +63,7 @@ describe Banzai::Filter::WikiLinkFilter do context 'with "audio" html tag' do it 'rewrites links' do - filtered_link = filter("<audio src='#{repository_upload_folder}/a.wav'></audio>", project_wiki: wiki).children[0] + filtered_link = filter("<audio src='#{repository_upload_folder}/a.wav'></audio>", wiki: wiki).children[0] expect(filtered_link.attribute('src').value).to eq("#{wiki.wiki_base_path}/#{repository_upload_folder}/a.wav") end @@ -75,7 +75,7 @@ describe Banzai::Filter::WikiLinkFilter do invalid_links.each do |invalid_link| it "doesn't rewrite invalid invalid_links like #{invalid_link}" do - filtered_link = filter("<a href='#{invalid_link}'>Link</a>", project_wiki: wiki).children[0] + filtered_link = filter("<a href='#{invalid_link}'>Link</a>", wiki: wiki).children[0] expect(filtered_link.attribute('href').value).to eq(invalid_link) end diff --git a/spec/lib/banzai/pipeline/description_pipeline_spec.rb b/spec/lib/banzai/pipeline/description_pipeline_spec.rb index 5ecd3df5151..6778a273bba 100644 --- a/spec/lib/banzai/pipeline/description_pipeline_spec.rb +++ b/spec/lib/banzai/pipeline/description_pipeline_spec.rb @@ -3,12 +3,14 @@ require 'spec_helper' describe Banzai::Pipeline::DescriptionPipeline do + let_it_be(:project) { create(:project) } + def parse(html) # When we pass HTML to Redcarpet, it gets wrapped in `p` tags... # ...except when we pass it pre-wrapped text. Rabble rabble. unwrap = !html.start_with?('<p ') - output = described_class.to_html(html, project: spy) + output = described_class.to_html(html, project: project) output.gsub!(%r{\A<p dir="auto">(.*)</p>(.*)\z}, '\1\2') if unwrap diff --git a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb index 4d16c568c13..b2c24284eb9 100644 --- a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb +++ b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb @@ -3,6 +3,11 @@ require 'spec_helper' describe Banzai::Pipeline::WikiPipeline do + let_it_be(:namespace) { create(:namespace, name: "wiki_link_ns") } + let_it_be(:project) { create(:project, :public, name: "wiki_link_project", namespace: namespace) } + let_it_be(:wiki) { ProjectWiki.new(project, double(:user)) } + let_it_be(:page) { build(:wiki_page, wiki: wiki, title: 'nested/twice/start-page') } + describe 'TableOfContents' do it 'replaces the tag with the TableOfContentsFilter result' do markdown = <<-MD.strip_heredoc @@ -13,7 +18,7 @@ describe Banzai::Pipeline::WikiPipeline do Foo MD - result = described_class.call(markdown, project: spy, project_wiki: spy) + result = described_class.call(markdown, project: project, wiki: wiki) aggregate_failures do expect(result[:output].text).not_to include '[[' @@ -31,7 +36,7 @@ describe Banzai::Pipeline::WikiPipeline do Foo MD - output = described_class.to_html(markdown, project: spy, project_wiki: spy) + output = described_class.to_html(markdown, project: project, wiki: wiki) expect(output).to include('[[<em>toc</em>]]') end @@ -44,7 +49,7 @@ describe Banzai::Pipeline::WikiPipeline do Foo MD - output = described_class.to_html(markdown, project: spy, project_wiki: spy) + output = described_class.to_html(markdown, project: project, wiki: wiki) aggregate_failures do expect(output).not_to include('<ul>') @@ -54,30 +59,25 @@ describe Banzai::Pipeline::WikiPipeline do end describe "Links" do - let(:namespace) { create(:namespace, name: "wiki_link_ns") } - let(:project) { create(:project, :public, name: "wiki_link_project", namespace: namespace) } - let(:project_wiki) { ProjectWiki.new(project, double(:user)) } - let(:page) { build(:wiki_page, wiki: project_wiki, title: 'nested/twice/start-page') } - { 'when GitLab is hosted at a root URL' => '', 'when GitLab is hosted at a relative URL' => '/nested/relative/gitlab' }.each do |test_name, relative_url_root| context test_name do before do - allow(Gitlab.config.gitlab).to receive(:relative_url_root).and_return(relative_url_root) + allow(Rails.application.routes).to receive(:default_url_options).and_return(script_name: relative_url_root) end describe "linking to pages within the wiki" do context "when creating hierarchical links to the current directory" do it "rewrites non-file links to be at the scope of the current directory" do markdown = "[Page](./page)" - output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug) + output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug) expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/page\"") end it "rewrites file links to be at the scope of the current directory" do markdown = "[Link to Page](./page.md)" - output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug) + output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug) expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/page.md\"") end @@ -86,14 +86,14 @@ describe Banzai::Pipeline::WikiPipeline do context "when creating hierarchical links to the parent directory" do it "rewrites non-file links to be at the scope of the parent directory" do markdown = "[Link to Page](../page)" - output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug) + output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug) expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/nested/page\"") end it "rewrites file links to be at the scope of the parent directory" do markdown = "[Link to Page](../page.md)" - output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug) + output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug) expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/nested/page.md\"") end @@ -102,14 +102,14 @@ describe Banzai::Pipeline::WikiPipeline do context "when creating hierarchical links to a sub-directory" do it "rewrites non-file links to be at the scope of the sub-directory" do markdown = "[Link to Page](./subdirectory/page)" - output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug) + output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug) expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/subdirectory/page\"") end it "rewrites file links to be at the scope of the sub-directory" do markdown = "[Link to Page](./subdirectory/page.md)" - output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug) + output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug) expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/subdirectory/page.md\"") end @@ -118,35 +118,35 @@ describe Banzai::Pipeline::WikiPipeline do describe "when creating non-hierarchical links" do it 'rewrites non-file links to be at the scope of the wiki root' do markdown = "[Link to Page](page)" - output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug) + output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug) expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/page\"") end it 'rewrites non-file links (with spaces) to be at the scope of the wiki root' do markdown = "[Link to Page](page slug)" - output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug) + output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug) expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/page%20slug\"") end it "rewrites file links to be at the scope of the current directory" do markdown = "[Link to Page](page.md)" - output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug) + output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug) expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/page.md\"") end it 'rewrites links with anchor' do markdown = '[Link to Header](start-page#title)' - output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug) + output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug) expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/start-page#title\"") end it 'rewrites links (with spaces) with anchor' do markdown = '[Link to Header](start page#title)' - output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug) + output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug) expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/start%20page#title\"") end @@ -155,14 +155,14 @@ describe Banzai::Pipeline::WikiPipeline do describe "when creating root links" do it 'rewrites non-file links to be at the scope of the wiki root' do markdown = "[Link to Page](/page)" - output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug) + output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug) expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/page\"") end it 'rewrites file links to be at the scope of the wiki root' do markdown = "[Link to Page](/page.md)" - output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug) + output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug) expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/page.md\"") end @@ -172,7 +172,7 @@ describe Banzai::Pipeline::WikiPipeline do describe "linking to pages outside the wiki (absolute)" do it "doesn't rewrite links" do markdown = "[Link to Page](http://example.com/page)" - output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug) + output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug) expect(output).to include('href="http://example.com/page"') end @@ -188,7 +188,7 @@ describe Banzai::Pipeline::WikiPipeline do output = described_class.to_html( "[Link](./alert(1);)", project: project, - project_wiki: project_wiki, + wiki: wiki, page_slug: valid_slug ) @@ -199,7 +199,7 @@ describe Banzai::Pipeline::WikiPipeline do output = described_class.to_html( "[Link](../alert(1);)", project: project, - project_wiki: project_wiki, + wiki: wiki, page_slug: valid_slug ) @@ -236,7 +236,7 @@ describe Banzai::Pipeline::WikiPipeline do output = described_class.to_html( "[Link](./#{link})", project: project, - project_wiki: project_wiki, + wiki: wiki, page_slug: slug ) @@ -247,7 +247,7 @@ describe Banzai::Pipeline::WikiPipeline do output = described_class.to_html( "[Link](../#{link})", project: project, - project_wiki: project_wiki, + wiki: wiki, page_slug: slug ) @@ -261,35 +261,30 @@ describe Banzai::Pipeline::WikiPipeline do end describe 'videos and audio' do - let_it_be(:namespace) { create(:namespace, name: "wiki_link_ns") } - let_it_be(:project) { create(:project, :public, name: "wiki_link_project", namespace: namespace) } - let_it_be(:project_wiki) { ProjectWiki.new(project, double(:user)) } - let_it_be(:page) { build(:wiki_page, wiki: project_wiki, title: 'nested/twice/start-page') } - it 'generates video html structure' do markdown = "![video_file](video_file_name.mp4)" - output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug) + output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug) expect(output).to include('<video src="/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/video_file_name.mp4"') end it 'rewrites and replaces video links names with white spaces to %20' do markdown = "![video file](video file name.mp4)" - output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug) + output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug) expect(output).to include('<video src="/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/video%20file%20name.mp4"') end it 'generates audio html structure' do markdown = "![audio_file](audio_file_name.wav)" - output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug) + output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug) expect(output).to include('<audio src="/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/audio_file_name.wav"') end it 'rewrites and replaces audio links names with white spaces to %20' do markdown = "![audio file](audio file name.wav)" - output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug) + output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug) expect(output).to include('<audio src="/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/audio%20file%20name.wav"') end |