# 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) %() end def link(path) %(#{path}) 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 these methods so the file doesn't actually need to be in the repo allow_any_instance_of(described_class). to receive(:file_exists?).and_return(true) allow_any_instance_of(described_class). to receive(:image?).with(path).and_return(true) 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