gitlab_markdown_helper_spec.rb 10.8 KB
Newer Older
R
Riyad Preukschas 已提交
1 2
require "spec_helper"

R
randx 已提交
3
describe GitlabMarkdownHelper do
R
Robert Speicher 已提交
4 5 6 7 8 9 10 11 12
  let!(:project) { create(:project) }

  let(:user)          { create(:user, name: 'gfm') }
  let(:commit)        { CommitDecorator.decorate(project.commit) }
  let(:issue)         { create(:issue, project: project) }
  let(:merge_request) { create(:merge_request, project: project) }
  let(:snippet)       { create(:snippet, project: project) }
  let(:member)        { project.users_projects.where(user_id: user).first }

R
Riyad Preukschas 已提交
13
  before do
R
Robert Speicher 已提交
14 15
    # Helper expects a @project instance variable
    @project = project
R
Riyad Preukschas 已提交
16 17 18
  end

  describe "#gfm" do
R
Robert Speicher 已提交
19 20 21 22 23
    it "should return unaltered text if project is nil" do
      actual = "Testing references: ##{issue.id}"

      gfm(actual).should_not == actual

24
      @project = nil
R
Robert Speicher 已提交
25 26
      gfm(actual).should == actual
    end
27

R
Robert Speicher 已提交
28 29 30 31 32 33 34 35 36 37 38 39
    it "should not alter non-references" do
      actual = expected = "_Please_ *stop* 'helping' and all the other b*$#%' you do."
      gfm(actual).should == expected
    end

    it "should not touch HTML entities" do
      actual = expected = "We'll accept good pull requests."
      gfm(actual).should == expected
    end

    it "should forward HTML options to links" do
      gfm("Fixed in #{commit.id}", class: "foo").should have_selector("a.gfm.foo")
40 41
    end

R
Riyad Preukschas 已提交
42
    describe "referencing a commit" do
R
Robert Speicher 已提交
43 44
      let(:expected) { project_commit_path(project, commit) }

R
Riyad Preukschas 已提交
45
      it "should link using a full id" do
R
Robert Speicher 已提交
46 47
        actual = "Reverts #{commit.id}"
        gfm(actual).should match(expected)
R
Riyad Preukschas 已提交
48 49 50
      end

      it "should link using a short id" do
R
Robert Speicher 已提交
51 52 53 54 55 56 57
        actual = "Backported from #{commit.short_id(6)}"
        gfm(actual).should match(expected)
      end

      it "should link with adjacent text" do
        actual = "Reverted (see #{commit.id})"
        gfm(actual).should match(expected)
R
Riyad Preukschas 已提交
58 59
      end

R
Robert Speicher 已提交
60 61 62 63
      it "should keep whitespace intact" do
        actual   = "Changes #{commit.id} dramatically"
        expected = /Changes <a.+>#{commit.id}<\/a> dramatically/
        gfm(actual).should match(expected)
R
Riyad Preukschas 已提交
64 65 66
      end

      it "should not link with an invalid id" do
R
Robert Speicher 已提交
67 68 69 70 71 72 73 74 75 76 77 78
        actual = expected = "What happened in #{commit.id.reverse}"
        gfm(actual).should == expected
      end

      it "should include a title attribute" do
        actual = "Reverts #{commit.id}"
        gfm(actual).should match(/title="#{commit.link_title}"/)
      end

      it "should include standard gfm classes" do
        actual = "Reverts #{commit.id}"
        gfm(actual).should match(/class="\s?gfm gfm-commit\s?"/)
R
Riyad Preukschas 已提交
79 80 81 82
      end
    end

    describe "referencing a team member" do
R
Robert Speicher 已提交
83 84
      let(:actual)   { "@#{user.name} you are right." }
      let(:expected) { project_team_member_path(project, member) }
R
Riyad Preukschas 已提交
85

R
Robert Speicher 已提交
86 87
      before do
        project.users << user
R
Riyad Preukschas 已提交
88 89
      end

R
Robert Speicher 已提交
90 91 92
      it "should link using a simple name" do
        gfm(actual).should match(expected)
      end
R
Riyad Preukschas 已提交
93

R
Robert Speicher 已提交
94 95 96
      it "should link using a name with dots" do
        user.update_attributes(name: "alphA.Beta")
        gfm(actual).should match(expected)
R
Riyad Preukschas 已提交
97 98 99
      end

      it "should link using name with underscores" do
R
Robert Speicher 已提交
100 101
        user.update_attributes(name: "ping_pong_king")
        gfm(actual).should match(expected)
R
Riyad Preukschas 已提交
102 103
      end

R
Robert Speicher 已提交
104 105 106 107
      it "should link with adjacent text" do
        actual = "Mail the admin (@gfm)"
        gfm(actual).should match(expected)
      end
R
Riyad Preukschas 已提交
108

R
Robert Speicher 已提交
109 110 111 112
      it "should keep whitespace intact" do
        actual   = "Yes, @#{user.name} is right."
        expected = /Yes, <a.+>@#{user.name}<\/a> is right/
        gfm(actual).should match(expected)
R
Riyad Preukschas 已提交
113 114
      end

R
Robert Speicher 已提交
115 116 117
      it "should not link with an invalid id" do
        actual = expected = "@#{user.name.reverse} you are right."
        gfm(actual).should == expected
R
Riyad Preukschas 已提交
118 119
      end

R
Robert Speicher 已提交
120 121
      it "should include standard gfm classes" do
        gfm(actual).should match(/class="\s?gfm gfm-team_member\s?"/)
R
Riyad Preukschas 已提交
122 123 124
      end
    end

R
Robert Speicher 已提交
125 126 127 128 129 130 131 132 133 134 135 136 137 138
    # Shared examples for referencing an object
    #
    # Expects the following attributes to be available in the example group:
    #
    # - object    - The object itself
    # - reference - The object reference string (e.g., #1234, $1234, !1234)
    #
    # Currently limited to Snippets, Issues and MergeRequests
    shared_examples 'referenced object' do
      let(:actual)   { "Reference to #{reference}" }
      let(:expected) { polymorphic_path([project, object]) }

      it "should link using a valid id" do
        gfm(actual).should match(expected)
R
Riyad Preukschas 已提交
139 140
      end

R
Robert Speicher 已提交
141 142 143
      it "should link with adjacent text" do
        # Wrap the reference in parenthesis
        gfm(actual.gsub(reference, "(#{reference})")).should match(expected)
R
Riyad Preukschas 已提交
144

R
Robert Speicher 已提交
145 146
        # Append some text to the end of the reference
        gfm(actual.gsub(reference, "#{reference}, right?")).should match(expected)
R
Riyad Preukschas 已提交
147 148
      end

R
Robert Speicher 已提交
149 150 151 152
      it "should keep whitespace intact" do
        actual   = "Referenced #{reference} already."
        expected = /Referenced <a.+>[^\s]+<\/a> already/
        gfm(actual).should match(expected)
R
Riyad Preukschas 已提交
153 154
      end

R
Robert Speicher 已提交
155 156 157 158
      it "should not link with an invalid id" do
        # Modify the reference string so it's still parsed, but is invalid
        reference.gsub!(/^(.)(\d+)$/, '\1' + ('\2' * 2))
        gfm(actual).should == actual
R
Riyad Preukschas 已提交
159 160
      end

R
Robert Speicher 已提交
161 162 163
      it "should include a title attribute" do
        title = "#{object.class.to_s.titlecase}: #{object.title}"
        gfm(actual).should match(/title="#{title}"/)
R
Riyad Preukschas 已提交
164 165
      end

R
Robert Speicher 已提交
166 167 168
      it "should include standard gfm classes" do
        css = object.class.to_s.underscore
        gfm(actual).should match(/class="\s?gfm gfm-#{css}\s?"/)
R
Riyad Preukschas 已提交
169
      end
R
Robert Speicher 已提交
170
    end
R
Riyad Preukschas 已提交
171

R
Robert Speicher 已提交
172 173 174
    describe "referencing an issue" do
      let(:object)    { issue }
      let(:reference) { "##{issue.id}" }
R
Riyad Preukschas 已提交
175

R
Robert Speicher 已提交
176 177
      include_examples 'referenced object'
    end
R
Riyad Preukschas 已提交
178

R
Robert Speicher 已提交
179 180 181 182 183
    describe "referencing a merge request" do
      let(:object)    { merge_request }
      let(:reference) { "!#{merge_request.id}" }

      include_examples 'referenced object'
R
Riyad Preukschas 已提交
184 185 186
    end

    describe "referencing a snippet" do
R
Robert Speicher 已提交
187 188
      let(:object)    { snippet }
      let(:reference) { "$#{snippet.id}" }
R
Riyad Preukschas 已提交
189

R
Robert Speicher 已提交
190 191
      include_examples 'referenced object'
    end
R
Riyad Preukschas 已提交
192

R
Robert Speicher 已提交
193 194 195 196 197 198
    describe "referencing multiple objects" do
      let(:actual) { "!#{merge_request.id} -> #{commit.id} -> ##{issue.id}" }

      it "should link to the merge request" do
        expected = project_merge_request_path(project, merge_request)
        gfm(actual).should match(expected)
R
Riyad Preukschas 已提交
199 200
      end

R
Robert Speicher 已提交
201 202 203
      it "should link to the commit" do
        expected = project_commit_path(project, commit)
        gfm(actual).should match(expected)
R
Riyad Preukschas 已提交
204 205
      end

R
Robert Speicher 已提交
206 207 208
      it "should link to the issue" do
        expected = project_issue_path(project, issue)
        gfm(actual).should match(expected)
R
Riyad Preukschas 已提交
209 210
      end
    end
R
Robert Speicher 已提交
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244

    describe "emoji" do
      it "matches at the start of a string" do
        gfm(":+1:").should match(/<img/)
      end

      it "matches at the end of a string" do
        gfm("This gets a :-1:").should match(/<img/)
      end

      it "matches with adjacent text" do
        gfm("+1 (:+1:)").should match(/<img/)
      end

      it "has a title attribute" do
        gfm(":-1:").should match(/title=":-1:"/)
      end

      it "has an alt attribute" do
        gfm(":-1:").should match(/alt=":-1:"/)
      end

      it "has an emoji class" do
        gfm(":+1:").should match('class="emoji"')
      end

      it "keeps whitespace intact" do
        gfm("This deserves a :+1: big time.").should match(/deserves a <img.+\/> big time/)
      end

      it "ignores invalid emoji" do
        gfm(":invalid-emoji:").should_not match(/<img/)
      end
    end
R
Robert Speicher 已提交
245
  end
R
Riyad Preukschas 已提交
246

R
Robert Speicher 已提交
247 248 249
  describe "#link_to_gfm" do
    let(:commit_path) { project_commit_path(project, commit) }
    let(:issues)      { create_list(:issue, 2, project: project) }
R
Riyad Preukschas 已提交
250

R
Robert Speicher 已提交
251 252
    it "should handle references nested in links with all the text" do
      actual = link_to_gfm("This should finally fix ##{issues[0].id} and ##{issues[1].id} for real", commit_path)
R
Riyad Preukschas 已提交
253

R
Robert Speicher 已提交
254 255 256
      # Break the result into groups of links with their content, without
      # closing tags
      groups = actual.split("</a>")
R
Riyad Preukschas 已提交
257

R
Robert Speicher 已提交
258 259 260
      # Leading commit link
      groups[0].should match(/href="#{commit_path}"/)
      groups[0].should match(/This should finally fix $/)
R
Riyad Preukschas 已提交
261

R
Robert Speicher 已提交
262 263 264
      # First issue link
      groups[1].should match(/href="#{project_issue_path(project, issues[0])}"/)
      groups[1].should match(/##{issues[0].id}$/)
265

R
Robert Speicher 已提交
266 267 268
      # Internal commit link
      groups[2].should match(/href="#{commit_path}"/)
      groups[2].should match(/ and /)
269

R
Robert Speicher 已提交
270 271 272 273 274 275 276
      # Second issue link
      groups[3].should match(/href="#{project_issue_path(project, issues[1])}"/)
      groups[3].should match(/##{issues[1].id}$/)

      # Trailing commit link
      groups[4].should match(/href="#{commit_path}"/)
      groups[4].should match(/ for real$/)
277 278 279
    end

    it "should forward HTML options" do
R
Robert Speicher 已提交
280 281
      actual = link_to_gfm("Fixed in #{commit.id}", commit_path, class: 'foo')
      actual.should have_selector 'a.gfm.gfm-commit.foo'
282 283
    end
  end
284 285 286

  describe "#markdown" do
    it "should handle references in paragraphs" do
R
Robert Speicher 已提交
287
      markdown("\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. #{commit.id} Nam pulvinar sapien eget odio adipiscing at faucibus orci vestibulum.\n").should == "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. #{link_to commit.id, project_commit_path(project, commit), title: commit.link_title, class: "gfm gfm-commit "} Nam pulvinar sapien eget odio adipiscing at faucibus orci vestibulum.</p>\n"
288 289 290
    end

    it "should handle references in headers" do
R
Robert Speicher 已提交
291 292 293 294
      actual = "\n# Working around ##{issue.id}\n## Apply !#{merge_request.id}"

      markdown(actual).should match(%r{<h1[^<]*>Working around <a.+>##{issue.id}</a></h1>})
      markdown(actual).should match(%r{<h2[^<]*>Apply <a.+>!#{merge_request.id}</a></h2>})
295 296 297
    end

    it "should handle references in lists" do
R
Robert Speicher 已提交
298 299 300 301 302 303
      project.users << user

      actual = "\n* dark: ##{issue.id}\n* light by @#{member.user_name}"

      markdown(actual).should match(%r{<li>dark: <a.+>##{issue.id}</a></li>})
      markdown(actual).should match(%r{<li>light by <a.+>@#{member.user_name}</a></li>})
304 305 306
    end

    it "should handle references in <em>" do
R
Robert Speicher 已提交
307 308 309
      actual = "Apply _!#{merge_request.id}_ ASAP"

      markdown(actual).should match(%r{Apply <em><a.+>!#{merge_request.id}</a></em>})
310 311 312
    end

    it "should leave code blocks untouched" do
R
Robert Speicher 已提交
313
      markdown("\n    some code from $#{snippet.id}\n    here too\n").should == "<div class=\"highlight\"><pre><span class=\"n\">some</span> <span class=\"n\">code</span> <span class=\"n\">from</span> $#{snippet.id}\n<span class=\"n\">here</span> <span class=\"n\">too</span>\n</pre>\n</div>\n"
314

R
Robert Speicher 已提交
315
      markdown("\n```\nsome code from $#{snippet.id}\nhere too\n```\n").should == "<div class=\"highlight\"><pre><span class=\"n\">some</span> <span class=\"n\">code</span> <span class=\"n\">from</span> $#{snippet.id}\n<span class=\"n\">here</span> <span class=\"n\">too</span>\n</pre>\n</div>\n"
316 317 318
    end

    it "should leave inline code untouched" do
R
Robert Speicher 已提交
319
      markdown("\nDon't use `$#{snippet.id}` here.\n").should == "<p>Don&#39;t use <code>$#{snippet.id}</code> here.</p>\n"
320 321
    end
  end
R
Riyad Preukschas 已提交
322
end