summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorRobert Speicher <rspeicher@gmail.com>2015-07-22 21:22:57 -0400
committerRobert Speicher <rspeicher@gmail.com>2015-07-28 18:56:27 -0400
commit05f9a6a9c44c094d281d3dc8d80eb30c4e7dff27 (patch)
treefaa30eb8ab5b30f649794254fe7e4736098d1ff8 /spec
parent0673ca36812ac3f709032938b77e5ab6e1d63885 (diff)
downloadgitlab-ce-05f9a6a9c44c094d281d3dc8d80eb30c4e7dff27.tar.gz
Update Markdown feature to allow for multiple pipelines
Diffstat (limited to 'spec')
-rw-r--r--spec/features/markdown_spec.rb216
-rw-r--r--spec/support/matchers/markdown_matchers.rb156
2 files changed, 209 insertions, 163 deletions
diff --git a/spec/features/markdown_spec.rb b/spec/features/markdown_spec.rb
index 46814fdfb8e..ddef2317e1c 100644
--- a/spec/features/markdown_spec.rb
+++ b/spec/features/markdown_spec.rb
@@ -17,16 +17,8 @@ require 'erb'
# -> Post-process HTML
# -> `gfm_with_options` helper
# -> HTML::Pipeline
-# -> Sanitize
-# -> RelativeLink
-# -> Emoji
-# -> Table of Contents
-# -> Autolinks
-# -> Rinku (http, https, ftp)
-# -> Other schemes
-# -> ExternalLink
-# -> References
-# -> TaskList
+# -> SanitizationFilter
+# -> Other filters, depending on pipeline
# -> `html_safe`
# -> Template
#
@@ -35,6 +27,7 @@ require 'erb'
describe 'GitLab Markdown', feature: true do
include Capybara::Node::Matchers
include GitlabMarkdownHelper
+ include MarkdownMatchers
# Let's only parse this thing once
before(:all) do
@@ -42,50 +35,37 @@ describe 'GitLab Markdown', feature: true do
# `gfm_with_options` depends on a `@project` variable
@project = @feat.project
-
- @html = markdown(@feat.raw_markdown)
end
after(:all) do
@feat.teardown
end
- def doc
- @doc ||= Nokogiri::HTML::DocumentFragment.parse(@html)
+ def doc(html = @html)
+ Nokogiri::HTML::DocumentFragment.parse(html)
end
- # Given a header ID, goes to that element's parent (the header itself), then
- # its next sibling element (the body).
- def get_section(id)
- doc.at_css("##{id}").parent.next_element
+ # Sometimes it can be useful to see the parsed output of the Markdown document
+ # for debugging. Call this method to write the output to
+ # `tmp/capybara/<filename>.html`.
+ def write_markdown(filename = 'markdown_spec')
+ File.open(Rails.root.join("tmp/capybara/#{filename}.html"), 'w') do |file|
+ file.puts @html
+ end
end
- # Sometimes it can be useful to see the parsed output of the Markdown document
- # for debugging. Uncomment this block to write the output to
- # tmp/capybara/markdown_spec.html.
- #
- # it 'writes to a file' do
- # File.open(Rails.root.join('tmp/capybara/markdown_spec.html'), 'w') do |file|
- # file.puts @html
- # end
- # end
-
- describe 'Redcarpet extensions' do
- describe 'No Intra Emphasis' do
+ # Shared behavior that all pipelines should exhibit
+ shared_examples 'all pipelines' do
+ describe 'Redcarpet extensions' do
it 'does not parse emphasis inside of words' do
- body = get_section('no-intra-emphasis')
- expect(body.to_html).not_to match('foo<em>bar</em>baz')
+ expect(doc.to_html).not_to match('foo<em>bar</em>baz')
end
- end
- describe 'Tables' do
it 'parses table Markdown' do
- body = get_section('tables')
-
aggregate_failures do
- expect(body).to have_selector('th:contains("Header")')
- expect(body).to have_selector('th:contains("Row")')
- expect(body).to have_selector('th:contains("Example")')
+ expect(doc).to have_selector('th:contains("Header")')
+ expect(doc).to have_selector('th:contains("Row")')
+ expect(doc).to have_selector('th:contains("Example")')
end
end
@@ -93,36 +73,23 @@ describe 'GitLab Markdown', feature: true do
expect(doc.at_css('td:contains("Baz")').children.to_html).
to eq '<strong>Baz</strong>'
end
- end
- describe 'Fenced Code Blocks' do
it 'parses fenced code blocks' do
aggregate_failures do
expect(doc).to have_selector('pre.code.highlight.white.c')
expect(doc).to have_selector('pre.code.highlight.white.python')
end
end
- end
- describe 'Strikethrough' do
it 'parses strikethroughs' do
expect(doc).to have_selector(%{del:contains("and this text doesn't")})
end
- end
- describe 'Superscript' do
it 'parses superscript' do
- body = get_section('superscript')
-
- aggregate_failures do
- expect(body.to_html).to match('1<sup>st</sup>')
- expect(body.to_html).to match('2<sup>nd</sup>')
- end
+ expect(doc).to have_selector('sup', count: 2)
end
end
- end
- describe 'HTML::Pipeline' do
describe 'SanitizationFilter' do
it 'permits b elements' do
expect(doc).to have_selector('b:contains("b tag")')
@@ -207,133 +174,56 @@ describe 'GitLab Markdown', feature: true do
end
end
- describe 'EmojiFilter' do
- it 'parses Emoji' do
- expect(doc).to have_selector('img.emoji', count: 10)
- end
- end
-
- describe 'TableOfContentsFilter' do
- it 'creates anchors inside header elements' do
- aggregate_failures do
- expect(doc).to have_selector('h1 a#gitlab-markdown')
- expect(doc).to have_selector('h2 a#markdown')
- expect(doc).to have_selector('h3 a#autolinkfilter')
- end
- end
- end
-
- describe 'AutolinkFilter' do
- def body
- get_section('autolinkfilter').next_element
- end
-
- # Override Capybara's `have_link` matcher to simplify our use case
- def have_link(link)
- super(link, href: link)
- end
-
- it 'autolinks http://' do
- expect(body).to have_link('http://about.gitlab.com/')
- end
-
- it 'autolinks https://' do
- expect(body).to have_link('https://google.com/')
- end
-
- it 'autolinks ftp://' do
- expect(body).to have_link('ftp://ftp.us.debian.org/debian/')
- end
-
- it 'autolinks smb://' do
- expect(body).to have_link('smb://foo/bar/baz')
- end
-
- it 'autolinks irc://' do
- expect(body).to have_link('irc://irc.freenode.net/git')
- end
-
- it 'autolinks short, invalid URLs' do
- expect(body).to have_link('http://localhost:3000')
- end
-
- %w(code a kbd).each do |elem|
- it "ignores links inside '#{elem}' element" do
- expect(body).not_to have_selector("#{elem} a")
- end
- end
- end
-
describe 'ExternalLinkFilter' do
- let(:links) { get_section('externallinkfilter').next_element }
-
it 'adds nofollow to external link' do
- expect(links.css('a').first.to_html).to match 'nofollow'
+ link = doc.at_css('a:contains("Google")')
+ expect(link.attr('rel')).to match 'nofollow'
end
it 'ignores internal link' do
- expect(links.css('a').last.to_html).not_to match 'nofollow'
+ link = doc.at_css('a:contains("GitLab Root")')
+ expect(link.attr('rel')).not_to match 'nofollow'
end
end
+ end
- describe 'ReferenceFilter' do
- it 'handles references in headers' do
- header = doc.at_css('#reference-filters-eg-1').parent
-
- expect(header.css('a').size).to eq 2
- end
-
- it "handles references in Markdown" do
- body = get_section('reference-filters-eg-1')
- expect(body).to have_selector('em a.gfm-merge_request', count: 1)
- end
-
- it 'parses user references' do
- body = get_section('userreferencefilter')
- expect(body).to have_selector('a.gfm.gfm-project_member', count: 3)
- end
+ context 'default pipeline' do
+ before(:all) do
+ @html = markdown(@feat.raw_markdown)
+ end
- it 'parses issue references' do
- body = get_section('issuereferencefilter')
- expect(body).to have_selector('a.gfm.gfm-issue', count: 2)
- end
+ it_behaves_like 'all pipelines'
- it 'parses merge request references' do
- body = get_section('mergerequestreferencefilter')
- expect(body).to have_selector('a.gfm.gfm-merge_request', count: 2)
- end
+ it 'includes RelativeLinkFilter' do
+ expect(doc).to parse_relative_links
+ end
- it 'parses snippet references' do
- body = get_section('snippetreferencefilter')
- expect(body).to have_selector('a.gfm.gfm-snippet', count: 2)
- end
+ it 'includes EmojiFilter' do
+ expect(doc).to parse_emoji
+ end
- it 'parses commit range references' do
- body = get_section('commitrangereferencefilter')
- expect(body).to have_selector('a.gfm.gfm-commit_range', count: 2)
- end
+ it 'includes TableOfContentsFilter' do
+ expect(doc).to create_header_links
+ end
- it 'parses commit references' do
- body = get_section('commitreferencefilter')
- expect(body).to have_selector('a.gfm.gfm-commit', count: 2)
- end
+ it 'includes AutolinkFilter' do
+ expect(doc).to create_autolinks
+ end
- it 'parses label references' do
- body = get_section('labelreferencefilter')
- expect(body).to have_selector('a.gfm.gfm-label', count: 3)
+ it 'includes all reference filters' do
+ aggregate_failures do
+ expect(doc).to reference_users
+ expect(doc).to reference_issues
+ expect(doc).to reference_merge_requests
+ expect(doc).to reference_snippets
+ expect(doc).to reference_commit_ranges
+ expect(doc).to reference_commits
+ expect(doc).to reference_labels
end
end
- describe 'Task Lists' do
- it 'generates task lists' do
- body = get_section('task-lists')
-
- aggregate_failures do
- expect(body).to have_selector('ul.task-list', count: 2)
- expect(body).to have_selector('li.task-list-item', count: 7)
- expect(body).to have_selector('input[checked]', count: 3)
- end
- end
+ it 'includes TaskListFilter' do
+ expect(doc).to parse_task_lists
end
end
diff --git a/spec/support/matchers/markdown_matchers.rb b/spec/support/matchers/markdown_matchers.rb
new file mode 100644
index 00000000000..9df226c3af8
--- /dev/null
+++ b/spec/support/matchers/markdown_matchers.rb
@@ -0,0 +1,156 @@
+# MarkdownMatchers
+#
+# Custom matchers for our custom HTML::Pipeline filters. These are used to test
+# that specific filters are or are not used by our defined pipelines.
+#
+# Must be included manually.
+module MarkdownMatchers
+ extend RSpec::Matchers::DSL
+ include Capybara::Node::Matchers
+
+ # RelativeLinkFilter
+ matcher :parse_relative_links do
+ set_default_markdown_messages
+
+ match do |actual|
+ link = actual.at_css('a:contains("Relative Link")')
+ image = actual.at_css('img[alt="Relative Image"]')
+
+ expect(link['href']).to end_with('master/doc/README.md')
+ expect(image['src']).to end_with('master/app/assets/images/touch-icon-ipad.png')
+ end
+ end
+
+ # EmojiFilter
+ matcher :parse_emoji do
+ set_default_markdown_messages
+
+ match do |actual|
+ expect(actual).to have_selector('img.emoji', count: 10)
+ end
+ end
+
+ # TableOfContentsFilter
+ matcher :create_header_links do
+ set_default_markdown_messages
+
+ match do |actual|
+ expect(actual).to have_selector('h1 a#gitlab-markdown')
+ expect(actual).to have_selector('h2 a#markdown')
+ expect(actual).to have_selector('h3 a#autolinkfilter')
+ end
+ end
+
+ # AutolinkFilter
+ matcher :create_autolinks do
+ def have_autolink(link)
+ have_link(link, href: link)
+ end
+
+ set_default_markdown_messages
+
+ match do |actual|
+ expect(actual).to have_autolink('http://about.gitlab.com/')
+ expect(actual).to have_autolink('https://google.com/')
+ expect(actual).to have_autolink('ftp://ftp.us.debian.org/debian/')
+ expect(actual).to have_autolink('smb://foo/bar/baz')
+ expect(actual).to have_autolink('irc://irc.freenode.net/git')
+ expect(actual).to have_autolink('http://localhost:3000')
+
+ %w(code a kbd).each do |elem|
+ expect(body).not_to have_selector("#{elem} a")
+ end
+ end
+ end
+
+ # UserReferenceFilter
+ matcher :reference_users do
+ set_default_markdown_messages
+
+ match do |actual|
+ expect(actual).to have_selector('a.gfm.gfm-project_member', count: 3)
+ end
+ end
+
+ # IssueReferenceFilter
+ matcher :reference_issues do
+ set_default_markdown_messages
+
+ match do |actual|
+ expect(actual).to have_selector('a.gfm.gfm-issue', count: 3)
+ end
+ end
+
+ # MergeRequestReferenceFilter
+ matcher :reference_merge_requests do
+ set_default_markdown_messages
+
+ match do |actual|
+ expect(actual).to have_selector('a.gfm.gfm-merge_request', count: 3)
+ expect(actual).to have_selector('em a.gfm-merge_request')
+ end
+ end
+
+ # SnippetReferenceFilter
+ matcher :reference_snippets do
+ set_default_markdown_messages
+
+ match do |actual|
+ expect(actual).to have_selector('a.gfm.gfm-snippet', count: 2)
+ end
+ end
+
+ # CommitRangeReferenceFilter
+ matcher :reference_commit_ranges do
+ set_default_markdown_messages
+
+ match do |actual|
+ expect(actual).to have_selector('a.gfm.gfm-commit_range', count: 2)
+ end
+ end
+
+ # CommitReferenceFilter
+ matcher :reference_commits do
+ set_default_markdown_messages
+
+ match do |actual|
+ expect(actual).to have_selector('a.gfm.gfm-commit', count: 2)
+ end
+ end
+
+ # LabelReferenceFilter
+ matcher :reference_labels do
+ set_default_markdown_messages
+
+ match do |actual|
+ expect(actual).to have_selector('a.gfm.gfm-label', count: 3)
+ end
+ end
+
+ # TaskListFilter
+ matcher :parse_task_lists do
+ set_default_markdown_messages
+
+ match do |actual|
+ expect(actual).to have_selector('ul.task-list', count: 2)
+ expect(actual).to have_selector('li.task-list-item', count: 7)
+ expect(actual).to have_selector('input[checked]', count: 3)
+ end
+ end
+end
+
+# Monkeypatch the matcher DSL so that we can reduce some noisy duplication for
+# setting the failure messages for these matchers
+module RSpec::Matchers::DSL::Macros
+ def set_default_markdown_messages
+ failure_message do
+ # expected to parse emoji, but didn't
+ "expected to #{description}, but didn't"
+ end
+
+ failure_message_when_negated do
+ # expected not to parse task lists, but did
+ "expected not to #{description}, but did"
+ end
+ end
+end