2012-08-01 20:26:21 -04:00
require " spec_helper "
2012-08-08 04:52:09 -04:00
describe GitlabMarkdownHelper do
2013-01-16 16:37:39 -05:00
include ApplicationHelper
2013-01-23 09:13:28 -05:00
include IssuesHelper
2013-01-16 16:37:39 -05:00
2013-04-01 12:06:47 -04:00
let! ( :project ) { create ( :project_with_code ) }
2012-09-02 02:13:13 -04:00
2012-12-06 22:40:42 -05:00
let ( :user ) { create ( :user , username : 'gfm' ) }
2013-04-01 11:16:08 -04:00
let ( :commit ) { project . repository . commit }
2012-09-02 02:13:13 -04:00
let ( :issue ) { create ( :issue , project : project ) }
2013-04-25 10:15:33 -04:00
let ( :merge_request ) { create ( :merge_request , source_project : project , target_project : project ) }
2013-03-25 03:20:14 -04:00
let ( :snippet ) { create ( :project_snippet , project : project ) }
2012-09-02 02:13:13 -04:00
let ( :member ) { project . users_projects . where ( user_id : user ) . first }
2012-08-01 20:26:21 -04:00
before do
2012-09-02 02:13:13 -04:00
# Helper expects a @project instance variable
@project = project
2012-08-01 20:26:21 -04:00
end
describe " # gfm " do
2012-09-02 02:13:13 -04:00
it " should return unaltered text if project is nil " do
2013-08-20 09:56:05 -04:00
actual = " Testing references: # #{ issue . iid } "
2012-09-02 02:13:13 -04:00
gfm ( actual ) . should_not == actual
2012-08-05 20:32:17 -04:00
@project = nil
2012-09-02 02:13:13 -04:00
gfm ( actual ) . should == actual
end
2012-08-05 20:32:17 -04:00
2012-09-02 02:13:13 -04:00
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
2012-09-13 15:20:00 -04:00
@project . issues . stub ( :where ) . with ( id : '39' ) . and_return ( [ issue ] )
2012-09-02 02:13:13 -04:00
actual = expected = " We& # 39;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 " )
2012-08-05 20:32:17 -04:00
end
2012-08-01 20:26:21 -04:00
describe " referencing a commit " do
2012-09-02 02:13:13 -04:00
let ( :expected ) { project_commit_path ( project , commit ) }
2012-08-01 20:26:21 -04:00
it " should link using a full id " do
2012-09-02 02:13:13 -04:00
actual = " Reverts #{ commit . id } "
gfm ( actual ) . should match ( expected )
2012-08-01 20:26:21 -04:00
end
it " should link using a short id " do
2012-09-02 02:13:13 -04:00
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 )
2012-08-01 20:26:21 -04:00
end
2012-09-02 02:13:13 -04:00
it " should keep whitespace intact " do
actual = " Changes #{ commit . id } dramatically "
expected = / Changes <a.+> #{ commit . id } < \/ a> dramatically /
gfm ( actual ) . should match ( expected )
2012-08-01 20:26:21 -04:00
end
it " should not link with an invalid id " do
2012-09-02 02:13:13 -04:00
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?" / )
2012-08-01 20:26:21 -04:00
end
end
describe " referencing a team member " do
2012-12-06 22:40:42 -05:00
let ( :actual ) { " @ #{ user . username } you are right. " }
2013-03-20 07:41:18 -04:00
let ( :expected ) { user_path ( user ) }
2012-08-01 20:26:21 -04:00
2012-09-02 02:13:13 -04:00
before do
2013-01-04 11:50:31 -05:00
project . team << [ user , :master ]
2012-08-01 20:26:21 -04:00
end
2012-09-02 02:13:13 -04:00
it " should link using a simple name " do
gfm ( actual ) . should match ( expected )
end
2012-08-01 20:26:21 -04:00
2012-09-02 02:13:13 -04:00
it " should link using a name with dots " do
user . update_attributes ( name : " alphA.Beta " )
gfm ( actual ) . should match ( expected )
2012-08-01 20:26:21 -04:00
end
it " should link using name with underscores " do
2012-09-02 02:13:13 -04:00
user . update_attributes ( name : " ping_pong_king " )
gfm ( actual ) . should match ( expected )
2012-08-01 20:26:21 -04:00
end
2012-09-02 02:13:13 -04:00
it " should link with adjacent text " do
2012-12-06 22:40:42 -05:00
actual = " Mail the admin (@ #{ user . username } ) "
2012-09-02 02:13:13 -04:00
gfm ( actual ) . should match ( expected )
end
2012-08-01 20:26:21 -04:00
2012-09-02 02:13:13 -04:00
it " should keep whitespace intact " do
2012-12-06 22:40:42 -05:00
actual = " Yes, @ #{ user . username } is right. "
expected = / Yes, <a.+>@ #{ user . username } < \/ a> is right /
2012-09-02 02:13:13 -04:00
gfm ( actual ) . should match ( expected )
2012-08-01 20:26:21 -04:00
end
2012-09-02 02:13:13 -04:00
it " should not link with an invalid id " do
2012-12-06 22:40:42 -05:00
actual = expected = " @ #{ user . username . reverse } you are right. "
2012-09-02 02:13:13 -04:00
gfm ( actual ) . should == expected
2012-08-01 20:26:21 -04:00
end
2012-09-02 02:13:13 -04:00
it " should include standard gfm classes " do
gfm ( actual ) . should match ( / class=" \ s?gfm gfm-team_member \ s?" / )
2012-08-01 20:26:21 -04:00
end
end
2012-09-02 02:13:13 -04:00
# 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 )
2012-08-01 20:26:21 -04:00
end
2012-09-02 02:13:13 -04:00
it " should link with adjacent text " do
# Wrap the reference in parenthesis
gfm ( actual . gsub ( reference , " ( #{ reference } ) " ) ) . should match ( expected )
2012-08-01 20:26:21 -04:00
2012-09-02 02:13:13 -04:00
# Append some text to the end of the reference
gfm ( actual . gsub ( reference , " #{ reference } , right? " ) ) . should match ( expected )
2012-08-01 20:26:21 -04:00
end
2012-09-02 02:13:13 -04:00
it " should keep whitespace intact " do
actual = " Referenced #{ reference } already. "
expected = / Referenced <a.+>[^ \ s]+< \/ a> already /
gfm ( actual ) . should match ( expected )
2012-08-01 20:26:21 -04:00
end
2012-09-02 02:13:13 -04:00
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
2012-08-01 20:26:21 -04:00
end
2012-09-02 02:13:13 -04:00
it " should include a title attribute " do
title = " #{ object . class . to_s . titlecase } : #{ object . title } "
gfm ( actual ) . should match ( / title=" #{ title } " / )
2012-08-01 20:26:21 -04:00
end
2012-09-02 02:13:13 -04:00
it " should include standard gfm classes " do
css = object . class . to_s . underscore
gfm ( actual ) . should match ( / class=" \ s?gfm gfm- #{ css } \ s?" / )
2012-08-01 20:26:21 -04:00
end
2012-09-02 02:13:13 -04:00
end
2012-08-01 20:26:21 -04:00
2012-09-02 02:13:13 -04:00
describe " referencing an issue " do
let ( :object ) { issue }
2013-08-20 09:56:05 -04:00
let ( :reference ) { " # #{ issue . iid } " }
2012-08-01 20:26:21 -04:00
2012-09-02 02:13:13 -04:00
include_examples 'referenced object'
end
2012-08-01 20:26:21 -04:00
2012-09-02 02:13:13 -04:00
describe " referencing a merge request " do
let ( :object ) { merge_request }
2013-08-20 09:56:05 -04:00
let ( :reference ) { " ! #{ merge_request . iid } " }
2012-09-02 02:13:13 -04:00
include_examples 'referenced object'
2012-08-01 20:26:21 -04:00
end
describe " referencing a snippet " do
2012-09-02 02:13:13 -04:00
let ( :object ) { snippet }
let ( :reference ) { " $ #{ snippet . id } " }
2013-03-25 03:20:14 -04:00
let ( :actual ) { " Reference to #{ reference } " }
let ( :expected ) { project_snippet_path ( project , object ) }
it " should link using a valid id " do
gfm ( actual ) . should match ( expected )
end
it " should link with adjacent text " do
# Wrap the reference in parenthesis
gfm ( actual . gsub ( reference , " ( #{ reference } ) " ) ) . should match ( expected )
# Append some text to the end of the reference
gfm ( actual . gsub ( reference , " #{ reference } , right? " ) ) . should match ( expected )
end
it " should keep whitespace intact " do
actual = " Referenced #{ reference } already. "
expected = / Referenced <a.+>[^ \ s]+< \/ a> already /
gfm ( actual ) . should match ( expected )
end
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
end
it " should include a title attribute " do
title = " Snippet: #{ object . title } "
gfm ( actual ) . should match ( / title=" #{ title } " / )
end
it " should include standard gfm classes " do
css = object . class . to_s . underscore
gfm ( actual ) . should match ( / class=" \ s?gfm gfm-snippet \ s?" / )
end
2012-08-01 20:26:21 -04:00
2012-09-02 02:13:13 -04:00
end
2012-08-01 20:26:21 -04:00
2012-09-02 02:13:13 -04:00
describe " referencing multiple objects " do
2013-08-20 09:56:05 -04:00
let ( :actual ) { " ! #{ merge_request . iid } -> #{ commit . id } -> # #{ issue . iid } " }
2012-09-02 02:13:13 -04:00
it " should link to the merge request " do
expected = project_merge_request_path ( project , merge_request )
gfm ( actual ) . should match ( expected )
2012-08-01 20:26:21 -04:00
end
2012-09-02 02:13:13 -04:00
it " should link to the commit " do
expected = project_commit_path ( project , commit )
gfm ( actual ) . should match ( expected )
2012-08-01 20:26:21 -04:00
end
2012-09-02 02:13:13 -04:00
it " should link to the issue " do
expected = project_issue_path ( project , issue )
gfm ( actual ) . should match ( expected )
2012-08-01 20:26:21 -04:00
end
end
2012-09-05 16:05:20 -04:00
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
2012-09-05 16:14:54 -04:00
it " sets height and width " do
actual = gfm ( " :+1: " )
actual . should match ( / width="20" / )
actual . should match ( / height="20" / )
end
2012-09-05 16:05:20 -04:00
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
2012-09-07 18:49:17 -04:00
2013-07-29 06:46:00 -04:00
it " should work independent of reference links (i.e. without @project being set) " do
2012-09-07 18:49:17 -04:00
@project = nil
gfm ( " :+1: " ) . should match ( / <img / )
end
2012-09-05 16:05:20 -04:00
end
2012-09-02 02:13:13 -04:00
end
2012-08-01 20:26:21 -04:00
2012-09-02 02:13:13 -04:00
describe " # link_to_gfm " do
let ( :commit_path ) { project_commit_path ( project , commit ) }
let ( :issues ) { create_list ( :issue , 2 , project : project ) }
2012-08-01 20:26:21 -04:00
2012-09-02 02:13:13 -04:00
it " should handle references nested in links with all the text " do
2013-08-20 09:56:05 -04:00
actual = link_to_gfm ( " This should finally fix # #{ issues [ 0 ] . iid } and # #{ issues [ 1 ] . iid } for real " , commit_path )
2012-08-01 20:26:21 -04:00
2012-09-02 02:13:13 -04:00
# Break the result into groups of links with their content, without
# closing tags
groups = actual . split ( " </a> " )
2012-08-01 20:26:21 -04:00
2012-09-02 02:13:13 -04:00
# Leading commit link
groups [ 0 ] . should match ( / href=" #{ commit_path } " / )
groups [ 0 ] . should match ( / This should finally fix $ / )
2012-08-01 20:26:21 -04:00
2012-09-02 02:13:13 -04:00
# First issue link
2013-01-16 16:08:01 -05:00
groups [ 1 ] . should match ( / href=" #{ project_issue_url ( project , issues [ 0 ] ) } " / )
2013-08-20 09:56:05 -04:00
groups [ 1 ] . should match ( / # #{ issues [ 0 ] . iid } $ / )
2012-08-01 20:28:50 -04:00
2012-09-02 02:13:13 -04:00
# Internal commit link
groups [ 2 ] . should match ( / href=" #{ commit_path } " / )
groups [ 2 ] . should match ( / and / )
2012-08-01 20:28:50 -04:00
2012-09-02 02:13:13 -04:00
# Second issue link
2013-01-16 16:08:01 -05:00
groups [ 3 ] . should match ( / href=" #{ project_issue_url ( project , issues [ 1 ] ) } " / )
2013-08-20 09:56:05 -04:00
groups [ 3 ] . should match ( / # #{ issues [ 1 ] . iid } $ / )
2012-09-02 02:13:13 -04:00
# Trailing commit link
groups [ 4 ] . should match ( / href=" #{ commit_path } " / )
groups [ 4 ] . should match ( / for real$ / )
2012-08-01 20:28:50 -04:00
end
it " should forward HTML options " do
2012-09-02 02:13:13 -04:00
actual = link_to_gfm ( " Fixed in #{ commit . id } " , commit_path , class : 'foo' )
actual . should have_selector 'a.gfm.gfm-commit.foo'
2012-08-01 20:28:50 -04:00
end
2012-09-19 19:42:26 -04:00
it " escapes HTML passed in as the body " do
2013-08-20 09:56:05 -04:00
actual = " This is a <h1>test</h1> - see # #{ issues [ 0 ] . iid } "
2012-09-19 19:42:26 -04:00
link_to_gfm ( actual , commit_path ) . should match ( '<h1>test</h1>' )
end
2012-08-01 20:28:50 -04:00
end
2012-08-01 20:29:15 -04:00
describe " # markdown " do
it " should handle references in paragraphs " do
2012-09-19 19:42:26 -04:00
actual = " \n \n Lorem ipsum dolor sit amet. #{ commit . id } Nam pulvinar sapien eget. \n "
expected = project_commit_path ( project , commit )
markdown ( actual ) . should match ( expected )
2012-08-01 20:29:15 -04:00
end
it " should handle references in headers " do
2013-08-20 09:56:05 -04:00
actual = " \n # Working around # #{ issue . iid } \n # # Apply ! #{ merge_request . iid } "
2012-09-02 02:13:13 -04:00
2013-08-20 09:56:05 -04:00
markdown ( actual ) . should match ( %r{ <h1[^<]*>Working around <a.+> # #{ issue . iid } </a></h1> } )
markdown ( actual ) . should match ( %r{ <h2[^<]*>Apply <a.+>! #{ merge_request . iid } </a></h2> } )
2012-08-01 20:29:15 -04:00
end
it " should handle references in lists " do
2013-01-04 11:50:31 -05:00
project . team << [ user , :master ]
2012-09-02 02:13:13 -04:00
2013-08-20 09:56:05 -04:00
actual = " \n * dark: # #{ issue . iid } \n * light by @ #{ member . user . username } "
2012-09-02 02:13:13 -04:00
2013-08-20 09:56:05 -04:00
markdown ( actual ) . should match ( %r{ <li>dark: <a.+> # #{ issue . iid } </a></li> } )
2012-12-06 22:40:42 -05:00
markdown ( actual ) . should match ( %r{ <li>light by <a.+>@ #{ member . user . username } </a></li> } )
2012-08-01 20:29:15 -04:00
end
it " should handle references in <em> " do
2013-08-20 09:56:05 -04:00
actual = " Apply _! #{ merge_request . iid } _ ASAP "
2012-09-02 02:13:13 -04:00
2013-08-20 09:56:05 -04:00
markdown ( actual ) . should match ( %r{ Apply <em><a.+>! #{ merge_request . iid } </a></em> } )
2012-08-01 20:29:15 -04:00
end
2013-08-26 08:07:07 -04:00
it " should handle tables " do
actual = %Q{ | header 1 | header 2 |
| - - - - - - - - | - - - - - - - - |
| cell 1 | cell 2 |
| cell 3 | cell 4 | }
markdown ( actual ) . should match ( / \ A<table / )
end
2012-08-01 20:29:15 -04:00
it " should leave code blocks untouched " do
2012-11-28 10:05:11 -05:00
helper . stub ( :user_color_scheme_class ) . and_return ( :white )
2012-08-01 20:29:15 -04:00
2012-12-22 07:18:40 -05:00
helper . markdown ( " \n some code from $ #{ snippet . id } \n here too \n " ) . should include ( " <div class= \" white \" ><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></div></div> " )
2012-11-28 10:05:11 -05:00
2012-12-22 07:18:40 -05:00
helper . markdown ( " \n ``` \n some code from $ #{ snippet . id } \n here too \n ``` \n " ) . should include ( " <div class= \" white \" ><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></div></div> " )
2012-08-01 20:29:15 -04:00
end
it " should leave inline code untouched " do
2012-09-02 02:13:13 -04:00
markdown ( " \n Don't use `$ #{ snippet . id } ` here. \n " ) . should == " <p>Don& # 39;t use <code>$ #{ snippet . id } </code> here.</p> \n "
2012-08-01 20:29:15 -04:00
end
2013-01-16 16:08:01 -05:00
2013-01-16 16:37:39 -05:00
it " should leave ref-like autolinks untouched " do
2013-08-20 09:56:05 -04:00
markdown ( " look at http://example.tld/ # ! #{ merge_request . iid } " ) . should == " <p>look at <a href= \" http://example.tld/ # ! #{ merge_request . iid } \" >http://example.tld/ # ! #{ merge_request . iid } </a></p> \n "
2013-01-16 16:37:39 -05:00
end
it " should leave ref-like href of 'manual' links untouched " do
2013-08-20 09:56:05 -04:00
markdown ( " why not [inspect ! #{ merge_request . iid } ](http://example.tld/ # ! #{ merge_request . iid } ) " ) . should == " <p>why not <a href= \" http://example.tld/ # ! #{ merge_request . iid } \" >inspect </a><a href= \" #{ project_merge_request_url ( project , merge_request ) } \" class= \" gfm gfm-merge_request \" title= \" Merge Request: #{ merge_request . title } \" >! #{ merge_request . iid } </a><a href= \" http://example.tld/ # ! #{ merge_request . iid } \" ></a></p> \n "
2013-01-16 16:37:39 -05:00
end
it " should leave ref-like src of images untouched " do
2013-08-20 09:56:05 -04:00
markdown ( " screen shot: ![some image](http://example.tld/ # ! #{ merge_request . iid } ) " ) . should == " <p>screen shot: <img src= \" http://example.tld/ # ! #{ merge_request . iid } \" alt= \" some image \" ></p> \n "
2013-01-16 16:37:39 -05:00
end
2013-01-16 16:08:01 -05:00
it " should generate absolute urls for refs " do
2013-08-20 09:56:05 -04:00
markdown ( " # #{ issue . iid } " ) . should include ( project_issue_url ( project , issue ) )
2013-01-16 16:08:01 -05:00
end
2013-01-16 16:39:45 -05:00
it " should generate absolute urls for emoji " do
markdown ( " :smile: " ) . should include ( " src= \" #{ url_to_image ( " emoji/smile " ) } " )
end
2013-10-09 09:01:02 -04:00
it " should handle relative urls for a file in master " do
actual = " [GitLab API doc](doc/api/README.md) \n "
expected = " <p><a href= \" / #{ project . path_with_namespace } /blob/master/doc/api/README.md \" >GitLab API doc</a></p> \n "
markdown ( actual ) . should match ( expected )
end
it " should handle relative urls for a directory in master " do
actual = " [GitLab API doc](doc/api) \n "
expected = " <p><a href= \" / #{ project . path_with_namespace } /tree/master/doc/api \" >GitLab API doc</a></p> \n "
markdown ( actual ) . should match ( expected )
end
it " should handle absolute urls " do
actual = " [GitLab](https://www.gitlab.com) \n "
expected = " <p><a href= \" https://www.gitlab.com \" >GitLab</a></p> \n "
markdown ( actual ) . should match ( expected )
end
it " should handle wiki urls " do
actual = " [Link](test/link) \n "
expected = " <p><a href= \" / #{ project . path_with_namespace } /wikis/test/link \" >Link</a></p> \n "
markdown ( actual ) . should match ( expected )
end
2012-08-01 20:29:15 -04:00
end
2013-03-14 02:31:08 -04:00
describe " # render_wiki_content " do
before do
@wiki = stub ( 'WikiPage' )
@wiki . stub ( :content ) . and_return ( 'wiki content' )
end
2013-05-19 05:13:39 -04:00
it " should use GitLab Flavored Markdown for markdown files " do
2013-03-14 02:31:08 -04:00
@wiki . stub ( :format ) . and_return ( :markdown )
helper . should_receive ( :markdown ) . with ( 'wiki content' )
helper . render_wiki_content ( @wiki )
end
it " should use the Gollum renderer for all other file types " do
@wiki . stub ( :format ) . and_return ( :rdoc )
formatted_content_stub = stub ( 'formatted_content' )
formatted_content_stub . should_receive ( :html_safe )
@wiki . stub ( :formatted_content ) . and_return ( formatted_content_stub )
helper . render_wiki_content ( @wiki )
end
end
2012-08-01 20:26:21 -04:00
end