summaryrefslogtreecommitdiff
path: root/spec/lib/banzai/filter/relative_link_filter_spec.rb
blob: b9e4a4eaf0ecd54ce4ed5306f2f6956e8be37160 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# encoding: UTF-8

require 'spec_helper'

describe Banzai::Filter::RelativeLinkFilter, lib: true do
  def filter(doc, contexts = {})
    contexts.reverse_merge!({
      commit:         project.commit,
      project:        project,
      project_wiki:   project_wiki,
      ref:            ref,
      requested_path: requested_path
    })

    described_class.call(doc, contexts)
  end

  def image(path)
    %(<img src="#{path}" />)
  end

  def link(path)
    %(<a href="#{path}">#{path}</a>)
  end

  let(:project)        { create(:project) }
  let(:project_path)   { project.path_with_namespace }
  let(:ref)            { 'markdown' }
  let(:project_wiki)   { nil }
  let(:requested_path) { '/' }

  shared_examples :preserve_unchanged do
    it 'does not modify any relative URL in anchor' do
      doc = filter(link('README.md'))
      expect(doc.at_css('a')['href']).to eq 'README.md'
    end

    it 'does not modify any relative URL in image' do
      doc = filter(image('files/images/logo-black.png'))
      expect(doc.at_css('img')['src']).to eq 'files/images/logo-black.png'
    end
  end

  shared_examples :relative_to_requested do
    it 'rebuilds URL relative to the requested path' do
      doc = filter(link('users.md'))
      expect(doc.at_css('a')['href']).
        to eq "/#{project_path}/blob/#{ref}/doc/api/users.md"
    end
  end

  context 'with a project_wiki' do
    let(:project_wiki) { double('ProjectWiki') }
    include_examples :preserve_unchanged
  end

  context 'without a repository' do
    let(:project) { create(:empty_project) }
    include_examples :preserve_unchanged
  end

  context 'with an empty repository' do
    let(:project) { create(:project_empty_repo) }
    include_examples :preserve_unchanged
  end

  it 'does not raise an exception on invalid URIs' do
    act = link("://foo")
    expect { filter(act) }.not_to raise_error
  end

  context 'with a valid repository' do
    it 'rebuilds relative URL for a file in the repo' do
      doc = filter(link('doc/api/README.md'))
      expect(doc.at_css('a')['href']).
        to eq "/#{project_path}/blob/#{ref}/doc/api/README.md"
    end

    it 'rebuilds relative URL for a file in the repo up one directory' do
      relative_link = link('../api/README.md')
      doc = filter(relative_link, requested_path: 'doc/update/7.14-to-8.0.md')

      expect(doc.at_css('a')['href']).
        to eq "/#{project_path}/blob/#{ref}/doc/api/README.md"
    end

    it 'rebuilds relative URL for a file in the repo up multiple directories' do
      relative_link = link('../../../api/README.md')
      doc = filter(relative_link, requested_path: 'doc/foo/bar/baz/README.md')

      expect(doc.at_css('a')['href']).
        to eq "/#{project_path}/blob/#{ref}/doc/api/README.md"
    end

    it 'rebuilds relative URL for a file in the repository root' do
      relative_link = link('../README.md')
      doc = filter(relative_link, requested_path: 'doc/some-file.md')

      expect(doc.at_css('a')['href']).
        to eq "/#{project_path}/blob/#{ref}/README.md"
    end

    it 'rebuilds relative URL for a file in the repo with an anchor' do
      doc = filter(link('README.md#section'))
      expect(doc.at_css('a')['href']).
        to eq "/#{project_path}/blob/#{ref}/README.md#section"
    end

    it 'rebuilds relative URL for a directory in the repo' do
      doc = filter(link('doc/api/'))
      expect(doc.at_css('a')['href']).
        to eq "/#{project_path}/tree/#{ref}/doc/api"
    end

    it 'rebuilds relative URL for an image in the repo' do
      doc = filter(link('files/images/logo-black.png'))
      expect(doc.at_css('a')['href']).
        to eq "/#{project_path}/raw/#{ref}/files/images/logo-black.png"
    end

    it 'does not modify relative URL with an anchor only' do
      doc = filter(link('#section-1'))
      expect(doc.at_css('a')['href']).to eq '#section-1'
    end

    it 'does not modify absolute URL' do
      doc = filter(link('http://example.com'))
      expect(doc.at_css('a')['href']).to eq 'http://example.com'
    end

    it 'supports Unicode filenames' do
      path = 'files/images/한글.png'
      escaped = Addressable::URI.escape(path)

      # Stub this method so the file doesn't actually need to be in the repo
      allow_any_instance_of(described_class).to receive(:uri_type).and_return(:raw)

      doc = filter(image(escaped))
      expect(doc.at_css('img')['src']).to match '/raw/'
    end

    context 'when requested path is a file in the repo' do
      let(:requested_path) { 'doc/api/README.md' }
      include_examples :relative_to_requested
    end

    context 'when requested path is a directory in the repo' do
      let(:requested_path) { 'doc/api' }
      include_examples :relative_to_requested
    end
  end
end