2019-10-12 21:52:04 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2019-12-04 20:38:33 +05:30
|
|
|
require 'spec_helper'
|
2016-06-02 11:05:42 +05:30
|
|
|
|
2023-04-23 21:23:45 +05:30
|
|
|
RSpec.describe Banzai::Pipeline::WikiPipeline, feature_category: :wiki do
|
2023-07-09 08:55:56 +05:30
|
|
|
let_it_be(:namespace) { create(:namespace) }
|
|
|
|
let_it_be(:project) { create(:project, :public, namespace: namespace) }
|
2020-10-24 23:57:45 +05:30
|
|
|
let_it_be(:wiki) { ProjectWiki.new(project, nil) }
|
2020-06-23 00:09:42 +05:30
|
|
|
let_it_be(:page) { build(:wiki_page, wiki: wiki, title: 'nested/twice/start-page') }
|
|
|
|
|
2016-06-02 11:05:42 +05:30
|
|
|
describe 'TableOfContents' do
|
|
|
|
it 'replaces the tag with the TableOfContentsFilter result' do
|
|
|
|
markdown = <<-MD.strip_heredoc
|
|
|
|
[[_TOC_]]
|
|
|
|
|
|
|
|
## Header
|
|
|
|
|
|
|
|
Foo
|
|
|
|
MD
|
|
|
|
|
2020-06-23 00:09:42 +05:30
|
|
|
result = described_class.call(markdown, project: project, wiki: wiki)
|
2016-06-02 11:05:42 +05:30
|
|
|
|
|
|
|
aggregate_failures do
|
|
|
|
expect(result[:output].text).not_to include '[['
|
|
|
|
expect(result[:output].text).not_to include 'TOC'
|
|
|
|
expect(result[:output].to_html).to include(result[:toc])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-10-27 15:23:28 +05:30
|
|
|
it 'is not case-sensitive' do
|
2016-06-02 11:05:42 +05:30
|
|
|
markdown = <<-MD.strip_heredoc
|
|
|
|
[[_toc_]]
|
|
|
|
|
|
|
|
# Header 1
|
|
|
|
|
|
|
|
Foo
|
|
|
|
MD
|
|
|
|
|
2021-10-27 15:23:28 +05:30
|
|
|
result = described_class.call(markdown, project: project, wiki: wiki)
|
|
|
|
|
|
|
|
expect(result[:output].to_html).to include(result[:toc])
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'works with alternative [toc] tag' do
|
|
|
|
markdown = <<-MD.strip_heredoc
|
|
|
|
[toc]
|
2016-06-02 11:05:42 +05:30
|
|
|
|
2021-10-27 15:23:28 +05:30
|
|
|
# Header 1
|
|
|
|
|
|
|
|
Foo
|
|
|
|
MD
|
|
|
|
|
|
|
|
result = described_class.call(markdown, project: project, wiki: wiki)
|
|
|
|
expect(result[:output].to_html).to include(result[:toc])
|
2016-06-02 11:05:42 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it 'handles an empty pipeline result' do
|
|
|
|
# No Markdown headers in this doc, so `result[:toc]` will be empty
|
|
|
|
markdown = <<-MD.strip_heredoc
|
|
|
|
[[_TOC_]]
|
|
|
|
|
|
|
|
Foo
|
|
|
|
MD
|
|
|
|
|
2020-06-23 00:09:42 +05:30
|
|
|
output = described_class.to_html(markdown, project: project, wiki: wiki)
|
2016-06-02 11:05:42 +05:30
|
|
|
|
|
|
|
aggregate_failures do
|
|
|
|
expect(output).not_to include('<ul>')
|
|
|
|
expect(output).not_to include('[[<em>TOC</em>]]')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2016-06-16 23:09:34 +05:30
|
|
|
|
|
|
|
describe "Links" do
|
2020-05-24 23:13:21 +05:30
|
|
|
{ '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|
|
2016-06-16 23:09:34 +05:30
|
|
|
context test_name do
|
|
|
|
before do
|
2020-06-23 00:09:42 +05:30
|
|
|
allow(Rails.application.routes).to receive(:default_url_options).and_return(script_name: relative_url_root)
|
2016-06-16 23:09:34 +05:30
|
|
|
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)"
|
2020-06-23 00:09:42 +05:30
|
|
|
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
2016-06-16 23:09:34 +05:30
|
|
|
|
2023-07-09 08:55:56 +05:30
|
|
|
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/nested/twice/page\"")
|
2016-06-16 23:09:34 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it "rewrites file links to be at the scope of the current directory" do
|
|
|
|
markdown = "[Link to Page](./page.md)"
|
2020-06-23 00:09:42 +05:30
|
|
|
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
2016-06-16 23:09:34 +05:30
|
|
|
|
2023-07-09 08:55:56 +05:30
|
|
|
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/nested/twice/page.md\"")
|
2016-06-16 23:09:34 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
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)"
|
2020-06-23 00:09:42 +05:30
|
|
|
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
2016-06-16 23:09:34 +05:30
|
|
|
|
2023-07-09 08:55:56 +05:30
|
|
|
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/nested/page\"")
|
2016-06-16 23:09:34 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it "rewrites file links to be at the scope of the parent directory" do
|
|
|
|
markdown = "[Link to Page](../page.md)"
|
2020-06-23 00:09:42 +05:30
|
|
|
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
2016-06-16 23:09:34 +05:30
|
|
|
|
2023-07-09 08:55:56 +05:30
|
|
|
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/nested/page.md\"")
|
2016-06-16 23:09:34 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
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)"
|
2020-06-23 00:09:42 +05:30
|
|
|
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
2016-06-16 23:09:34 +05:30
|
|
|
|
2023-07-09 08:55:56 +05:30
|
|
|
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/nested/twice/subdirectory/page\"")
|
2016-06-16 23:09:34 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it "rewrites file links to be at the scope of the sub-directory" do
|
|
|
|
markdown = "[Link to Page](./subdirectory/page.md)"
|
2020-06-23 00:09:42 +05:30
|
|
|
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
2016-06-16 23:09:34 +05:30
|
|
|
|
2023-07-09 08:55:56 +05:30
|
|
|
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/nested/twice/subdirectory/page.md\"")
|
2016-06-16 23:09:34 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
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)"
|
2020-06-23 00:09:42 +05:30
|
|
|
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
2016-06-16 23:09:34 +05:30
|
|
|
|
2023-07-09 08:55:56 +05:30
|
|
|
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/page\"")
|
2016-06-16 23:09:34 +05:30
|
|
|
end
|
|
|
|
|
2018-11-20 20:47:30 +05:30
|
|
|
it 'rewrites non-file links (with spaces) to be at the scope of the wiki root' do
|
|
|
|
markdown = "[Link to Page](page slug)"
|
2020-06-23 00:09:42 +05:30
|
|
|
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
2018-11-20 20:47:30 +05:30
|
|
|
|
2023-07-09 08:55:56 +05:30
|
|
|
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/page%20slug\"")
|
2018-11-20 20:47:30 +05:30
|
|
|
end
|
|
|
|
|
2016-06-16 23:09:34 +05:30
|
|
|
it "rewrites file links to be at the scope of the current directory" do
|
|
|
|
markdown = "[Link to Page](page.md)"
|
2020-06-23 00:09:42 +05:30
|
|
|
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
2016-06-16 23:09:34 +05:30
|
|
|
|
2023-07-09 08:55:56 +05:30
|
|
|
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/nested/twice/page.md\"")
|
2016-06-16 23:09:34 +05:30
|
|
|
end
|
2016-09-29 09:46:39 +05:30
|
|
|
|
|
|
|
it 'rewrites links with anchor' do
|
|
|
|
markdown = '[Link to Header](start-page#title)'
|
2020-06-23 00:09:42 +05:30
|
|
|
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
2016-09-29 09:46:39 +05:30
|
|
|
|
2023-07-09 08:55:56 +05:30
|
|
|
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/start-page#title\"")
|
2016-09-29 09:46:39 +05:30
|
|
|
end
|
2018-11-20 20:47:30 +05:30
|
|
|
|
|
|
|
it 'rewrites links (with spaces) with anchor' do
|
|
|
|
markdown = '[Link to Header](start page#title)'
|
2020-06-23 00:09:42 +05:30
|
|
|
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
2018-11-20 20:47:30 +05:30
|
|
|
|
2023-07-09 08:55:56 +05:30
|
|
|
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/start%20page#title\"")
|
2018-11-20 20:47:30 +05:30
|
|
|
end
|
2016-06-16 23:09:34 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
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)"
|
2020-06-23 00:09:42 +05:30
|
|
|
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
2016-06-16 23:09:34 +05:30
|
|
|
|
2023-07-09 08:55:56 +05:30
|
|
|
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/page\"")
|
2016-06-16 23:09:34 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it 'rewrites file links to be at the scope of the wiki root' do
|
|
|
|
markdown = "[Link to Page](/page.md)"
|
2020-06-23 00:09:42 +05:30
|
|
|
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
2016-06-16 23:09:34 +05:30
|
|
|
|
2023-07-09 08:55:56 +05:30
|
|
|
expect(output).to include("href=\"#{relative_url_root}/#{project.full_path}/-/wikis/page.md\"")
|
2016-06-16 23:09:34 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "linking to pages outside the wiki (absolute)" do
|
|
|
|
it "doesn't rewrite links" do
|
|
|
|
markdown = "[Link to Page](http://example.com/page)"
|
2020-06-23 00:09:42 +05:30
|
|
|
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
2016-06-16 23:09:34 +05:30
|
|
|
|
|
|
|
expect(output).to include('href="http://example.com/page"')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2019-07-31 22:56:46 +05:30
|
|
|
|
|
|
|
describe "checking slug validity when assembling links" do
|
|
|
|
context "with a valid slug" do
|
|
|
|
let(:valid_slug) { "http://example.com" }
|
|
|
|
|
|
|
|
it "includes the slug in a (.) relative link" do
|
|
|
|
output = described_class.to_html(
|
|
|
|
"[Link](./alert(1);)",
|
|
|
|
project: project,
|
2020-06-23 00:09:42 +05:30
|
|
|
wiki: wiki,
|
2019-07-31 22:56:46 +05:30
|
|
|
page_slug: valid_slug
|
|
|
|
)
|
|
|
|
|
|
|
|
expect(output).to include(valid_slug)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "includeds the slug in a (..) relative link" do
|
|
|
|
output = described_class.to_html(
|
|
|
|
"[Link](../alert(1);)",
|
|
|
|
project: project,
|
2020-06-23 00:09:42 +05:30
|
|
|
wiki: wiki,
|
2019-07-31 22:56:46 +05:30
|
|
|
page_slug: valid_slug
|
|
|
|
)
|
|
|
|
|
|
|
|
expect(output).to include(valid_slug)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "when the slug is deemed unsafe or invalid" do
|
|
|
|
invalid_slugs = [
|
|
|
|
"javascript:",
|
|
|
|
"JaVaScRiPt:",
|
|
|
|
"\u0001java\u0003script:",
|
|
|
|
"javascript :",
|
|
|
|
"javascript: ",
|
|
|
|
"javascript : ",
|
|
|
|
":javascript:",
|
|
|
|
"javascript:",
|
|
|
|
"javascript:",
|
|
|
|
"javascript:",
|
|
|
|
"javascript:",
|
|
|
|
"java\0script:",
|
|
|
|
"  javascript:"
|
|
|
|
]
|
|
|
|
|
|
|
|
invalid_js_links = [
|
|
|
|
"alert(1);",
|
|
|
|
"alert(document.location);"
|
|
|
|
]
|
|
|
|
|
|
|
|
invalid_slugs.each do |slug|
|
2020-03-13 15:44:24 +05:30
|
|
|
context "with the invalid slug #{slug.delete("\000")}" do
|
2019-07-31 22:56:46 +05:30
|
|
|
invalid_js_links.each do |link|
|
|
|
|
it "doesn't include a prohibited slug in a (.) relative link '#{link}'" do
|
|
|
|
output = described_class.to_html(
|
|
|
|
"[Link](./#{link})",
|
|
|
|
project: project,
|
2020-06-23 00:09:42 +05:30
|
|
|
wiki: wiki,
|
2019-07-31 22:56:46 +05:30
|
|
|
page_slug: slug
|
|
|
|
)
|
|
|
|
|
|
|
|
expect(output).not_to include(slug)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "doesn't include a prohibited slug in a (..) relative link '#{link}'" do
|
|
|
|
output = described_class.to_html(
|
|
|
|
"[Link](../#{link})",
|
|
|
|
project: project,
|
2020-06-23 00:09:42 +05:30
|
|
|
wiki: wiki,
|
2019-07-31 22:56:46 +05:30
|
|
|
page_slug: slug
|
|
|
|
)
|
|
|
|
|
|
|
|
expect(output).not_to include(slug)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2016-06-16 23:09:34 +05:30
|
|
|
end
|
2018-11-20 20:47:30 +05:30
|
|
|
|
2019-12-21 20:55:43 +05:30
|
|
|
describe 'videos and audio' do
|
2018-11-20 20:47:30 +05:30
|
|
|
it 'generates video html structure' do
|
|
|
|
markdown = "![video_file](video_file_name.mp4)"
|
2020-06-23 00:09:42 +05:30
|
|
|
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
2018-11-20 20:47:30 +05:30
|
|
|
|
2023-07-09 08:55:56 +05:30
|
|
|
expect(output).to include(%(<video src="/#{project.full_path}/-/wikis/nested/twice/video_file_name.mp4"))
|
2018-11-20 20:47:30 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it 'rewrites and replaces video links names with white spaces to %20' do
|
|
|
|
markdown = "![video file](video file name.mp4)"
|
2020-06-23 00:09:42 +05:30
|
|
|
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
2018-11-20 20:47:30 +05:30
|
|
|
|
2023-07-09 08:55:56 +05:30
|
|
|
expect(output).to include(%(<video src="/#{project.full_path}/-/wikis/nested/twice/video%20file%20name.mp4"))
|
2018-11-20 20:47:30 +05:30
|
|
|
end
|
2019-12-21 20:55:43 +05:30
|
|
|
|
|
|
|
it 'generates audio html structure' do
|
|
|
|
markdown = "![audio_file](audio_file_name.wav)"
|
2020-06-23 00:09:42 +05:30
|
|
|
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
2019-12-21 20:55:43 +05:30
|
|
|
|
2023-07-09 08:55:56 +05:30
|
|
|
expect(output).to include(%(<audio src="/#{project.full_path}/-/wikis/nested/twice/audio_file_name.wav"))
|
2019-12-21 20:55:43 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
it 'rewrites and replaces audio links names with white spaces to %20' do
|
|
|
|
markdown = "![audio file](audio file name.wav)"
|
2020-06-23 00:09:42 +05:30
|
|
|
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
2019-12-21 20:55:43 +05:30
|
|
|
|
2023-07-09 08:55:56 +05:30
|
|
|
expect(output).to include(%(<audio src="/#{project.full_path}/-/wikis/nested/twice/audio%20file%20name.wav"))
|
2019-12-21 20:55:43 +05:30
|
|
|
end
|
2018-11-20 20:47:30 +05:30
|
|
|
end
|
2021-04-29 21:17:54 +05:30
|
|
|
|
|
|
|
describe 'gollum tag filters' do
|
|
|
|
context 'when local image file exists' do
|
|
|
|
it 'sets the proper attributes for the image' do
|
|
|
|
gollum_file_double = double('Gollum::File',
|
|
|
|
mime_type: 'image/jpeg',
|
|
|
|
name: 'images/image.jpg',
|
|
|
|
path: 'images/image.jpg',
|
|
|
|
data: '')
|
|
|
|
|
|
|
|
wiki_file = Gitlab::Git::WikiFile.new(gollum_file_double)
|
|
|
|
markdown = "[[#{wiki_file.path}]]"
|
|
|
|
|
|
|
|
expect(wiki).to receive(:find_file).with(wiki_file.path, load_content: false).and_return(wiki_file)
|
|
|
|
|
|
|
|
output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
|
|
|
|
doc = Nokogiri::HTML::DocumentFragment.parse(output)
|
|
|
|
|
2023-07-09 08:55:56 +05:30
|
|
|
full_path = "/#{project.full_path}/-/wikis/nested/twice/#{wiki_file.path}"
|
2021-04-29 21:17:54 +05:30
|
|
|
expect(doc.css('a')[0].attr('href')).to eq(full_path)
|
|
|
|
expect(doc.css('img')[0].attr('class')).to eq('gfm lazy')
|
|
|
|
expect(doc.css('img')[0].attr('data-src')).to eq(full_path)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2016-06-02 11:05:42 +05:30
|
|
|
end
|