wiki_pipeline_spec.rb 12.4 KB
Newer Older
1 2
# frozen_string_literal: true

3
require 'spec_helper'
4

5
RSpec.describe Banzai::Pipeline::WikiPipeline do
6 7
  let_it_be(:namespace) { create(:namespace, name: "wiki_link_ns") }
  let_it_be(:project)   { create(:project, :public, name: "wiki_link_project", namespace: namespace) }
8
  let_it_be(:wiki)      { ProjectWiki.new(project, nil) }
9 10
  let_it_be(:page)      { build(:wiki_page, wiki: wiki, title: 'nested/twice/start-page') }

11 12 13 14 15 16 17 18 19 20
  describe 'TableOfContents' do
    it 'replaces the tag with the TableOfContentsFilter result' do
      markdown = <<-MD.strip_heredoc
          [[_TOC_]]

          ## Header

          Foo
      MD

21
      result = described_class.call(markdown, project: project, wiki: wiki)
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38

      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

    it 'is case-sensitive' do
      markdown = <<-MD.strip_heredoc
          [[_toc_]]

          # Header 1

          Foo
      MD

39
      output = described_class.to_html(markdown, project: project, wiki: wiki)
40 41 42 43 44 45 46 47 48 49 50 51

      expect(output).to include('[[<em>toc</em>]]')
    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

52
      output = described_class.to_html(markdown, project: project, wiki: wiki)
53 54 55

      aggregate_failures do
        expect(output).not_to include('<ul>')
56
        expect(output).not_to include('[[<em>TOC</em>]]')
57 58 59
      end
    end
  end
60 61

  describe "Links" do
Markus Koller's avatar
Markus Koller committed
62 63
    { '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|
64
      context test_name do
65
        before do
66
          allow(Rails.application.routes).to receive(:default_url_options).and_return(script_name: relative_url_root)
67 68 69
        end

        describe "linking to pages within the wiki" do
70
          context "when creating hierarchical links to the current directory" do
71 72
            it "rewrites non-file links to be at the scope of the current directory" do
              markdown = "[Page](./page)"
73
              output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
74

75
              expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/page\"")
76 77
            end

78 79
            it "rewrites file links to be at the scope of the current directory" do
              markdown = "[Link to Page](./page.md)"
80
              output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
81

82
              expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/page.md\"")
83 84 85 86
            end
          end

          context "when creating hierarchical links to the parent directory" do
87 88
            it "rewrites non-file links to be at the scope of the parent directory" do
              markdown = "[Link to Page](../page)"
89
              output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
90

91
              expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/nested/page\"")
92 93
            end

94 95
            it "rewrites file links to be at the scope of the parent directory" do
              markdown = "[Link to Page](../page.md)"
96
              output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
97

98
              expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/nested/page.md\"")
99 100 101 102
            end
          end

          context "when creating hierarchical links to a sub-directory" do
103 104
            it "rewrites non-file links to be at the scope of the sub-directory" do
              markdown = "[Link to Page](./subdirectory/page)"
105
              output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
106

107
              expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/subdirectory/page\"")
108 109
            end

110 111
            it "rewrites file links to be at the scope of the sub-directory" do
              markdown = "[Link to Page](./subdirectory/page.md)"
112
              output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
113

114
              expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/subdirectory/page.md\"")
115 116 117 118
            end
          end

          describe "when creating non-hierarchical links" do
119 120
            it 'rewrites non-file links to be at the scope of the wiki root' do
              markdown = "[Link to Page](page)"
121
              output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
122

123
              expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/page\"")
124 125
            end

126 127
            it 'rewrites non-file links (with spaces) to be at the scope of the wiki root' do
              markdown = "[Link to Page](page slug)"
128
              output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
129

130
              expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/page%20slug\"")
131 132
            end

133 134
            it "rewrites file links to be at the scope of the current directory" do
              markdown = "[Link to Page](page.md)"
135
              output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
136

137
              expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/page.md\"")
138
            end
139

140 141
            it 'rewrites links with anchor' do
              markdown = '[Link to Header](start-page#title)'
142
              output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
143

144
              expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/start-page#title\"")
145
            end
146

147 148
            it 'rewrites links (with spaces) with anchor' do
              markdown = '[Link to Header](start page#title)'
149
              output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
150

151
              expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/start%20page#title\"")
152
            end
153 154 155
          end

          describe "when creating root links" do
156 157
            it 'rewrites non-file links to be at the scope of the wiki root' do
              markdown = "[Link to Page](/page)"
158
              output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
159

160
              expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/page\"")
161 162
            end

163 164
            it 'rewrites file links to be at the scope of the wiki root' do
              markdown = "[Link to Page](/page.md)"
165
              output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
166

167
              expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/-/wikis/page.md\"")
168 169 170 171 172
            end
          end
        end

        describe "linking to pages outside the wiki (absolute)" do
173 174
          it "doesn't rewrite links" do
            markdown = "[Link to Page](http://example.com/page)"
175
            output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
176 177 178

            expect(output).to include('href="http://example.com/page"')
          end
179 180 181
        end
      end
    end
182 183 184 185 186 187 188 189 190

    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,
191
            wiki: wiki,
192 193 194 195 196 197 198 199 200 201
            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,
202
            wiki: wiki,
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
            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&#58;",
          "javascript&#0058;",
          "javascript&#x3A;",
          "javascript&#x003A;",
          "java\0script:",
          " &#14;  javascript:"
        ]

        invalid_js_links = [
          "alert(1);",
          "alert(document.location);"
        ]

        invalid_slugs.each do |slug|
233
          context "with the invalid slug #{slug.delete("\000")}" do
234 235 236 237 238
            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,
239
                  wiki: wiki,
240 241 242 243 244 245 246 247 248 249
                  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,
250
                  wiki: wiki,
251 252 253 254 255 256 257 258 259 260
                  page_slug: slug
                )

                expect(output).not_to include(slug)
              end
            end
          end
        end
      end
    end
261
  end
262

263
  describe 'videos and audio' do
264 265
    it 'generates video html structure' do
      markdown = "![video_file](video_file_name.mp4)"
266
      output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
267

268
      expect(output).to include('<video src="/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/video_file_name.mp4"')
269 270
    end

271 272
    it 'rewrites and replaces video links names with white spaces to %20' do
      markdown = "![video file](video file name.mp4)"
273
      output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
274

275
      expect(output).to include('<video src="/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/video%20file%20name.mp4"')
276
    end
277 278 279

    it 'generates audio html structure' do
      markdown = "![audio_file](audio_file_name.wav)"
280
      output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
281

282
      expect(output).to include('<audio src="/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/audio_file_name.wav"')
283 284 285 286
    end

    it 'rewrites and replaces audio links names with white spaces to %20' do
      markdown = "![audio file](audio file name.wav)"
287
      output = described_class.to_html(markdown, project: project, wiki: wiki, page_slug: page.slug)
288

289
      expect(output).to include('<audio src="/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/audio%20file%20name.wav"')
290
    end
291
  end
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316

  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',
          raw_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)

        full_path = "/wiki_link_ns/wiki_link_project/-/wikis/nested/twice/#{wiki_file.path}"
        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
317
end