From bc3448fc48a289342948ec155fa9c7f2d49ca2bd Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Mon, 16 Jan 2017 18:11:15 -0500 Subject: [PATCH] Improve spec --- app/assets/javascripts/copy_as_gfm.js.es6 | 7 +- lib/banzai/pipeline/gfm_pipeline.rb | 7 +- spec/features/copy_as_gfm_spec.rb | 298 +++++++++++----------- 3 files changed, 159 insertions(+), 153 deletions(-) diff --git a/app/assets/javascripts/copy_as_gfm.js.es6 b/app/assets/javascripts/copy_as_gfm.js.es6 index f9098c7041c..7c666697cdf 100644 --- a/app/assets/javascripts/copy_as_gfm.js.es6 +++ b/app/assets/javascripts/copy_as_gfm.js.es6 @@ -3,9 +3,10 @@ (() => { const gfmRules = { - // Should have an entry for every filter in lib/banzai/pipeline/gfm_pipeline.rb, - // in reverse order. - // Should have test coverage in spec/features/copy_as_gfm_spec.rb. + // The filters referenced in lib/banzai/pipeline/gfm_pipeline.rb convert GitLab Flavored Markdown (GFM) to HTML. + // These handlers consequently convert that same HTML to GFM to be copied to the clipboard. + // Every filter in lib/banzai/pipeline/gfm_pipeline.rb that generates HTML from GFM should have a handler here, in reverse order. + // The GFM-to-HTML-to-GFM cycle is tested in spec/features/copy_as_gfm_spec.rb. InlineDiffFilter: { 'span.idiff.addition'(el, text) { return `{+${text}+}`; diff --git a/lib/banzai/pipeline/gfm_pipeline.rb b/lib/banzai/pipeline/gfm_pipeline.rb index 09038d38b1f..7b652aa79ec 100644 --- a/lib/banzai/pipeline/gfm_pipeline.rb +++ b/lib/banzai/pipeline/gfm_pipeline.rb @@ -1,9 +1,10 @@ module Banzai module Pipeline class GfmPipeline < BasePipeline - # Every filter should have an entry in app/assets/javascripts/copy_as_gfm.js.es6, - # in reverse order. - # Should have test coverage in spec/features/copy_as_gfm_spec.rb. + # These filters convert GitLab Flavored Markdown (GFM) to HTML. + # The handlers defined in app/assets/javascripts/copy_as_gfm.js.es6 consequently convert that same HTML to GFM to be copied to the clipboard. + # Every filter that generates HTML from GFM should have a handler in app/assets/javascripts/copy_as_gfm.js.es6, in reverse order. + # The GFM-to-HTML-to-GFM cycle is tested in spec/features/copy_as_gfm_spec.rb. def self.filters @filters ||= FilterArray[ Filter::SyntaxHighlightFilter, diff --git a/spec/features/copy_as_gfm_spec.rb b/spec/features/copy_as_gfm_spec.rb index 8e8c0ecb282..dd22f92c5c8 100644 --- a/spec/features/copy_as_gfm_spec.rb +++ b/spec/features/copy_as_gfm_spec.rb @@ -13,117 +13,135 @@ describe 'Copy as GFM', feature: true, js: true do visit namespace_project_issue_path(@project.namespace, @project, @feat.issue) end - # Should have an entry for every filter in lib/banzai/pipeline/gfm_pipeline.rb - # and app/assets/javascripts/copy_as_gfm.js.es6 - filters = { - 'any filter' => [ - [ - 'crazy nesting', - '> 1. [x] **[$`2 + 2`$ {-=-}{+=+} 2^2 ~~:thumbsup:~~](http://google.com)**' - ], - [ - 'real world example from the gitlab-ce README', - <<-GFM.strip_heredoc - # GitLab + # The filters referenced in lib/banzai/pipeline/gfm_pipeline.rb convert GitLab Flavored Markdown (GFM) to HTML. + # The handlers defined in app/assets/javascripts/copy_as_gfm.js.es6 consequently convert that same HTML to GFM. + # To make sure these filters and handlers are properly aligned, this spec tests the GFM-to-HTML-to-GFM cycle + # by verifying (`html_to_gfm(gfm_to_html(gfm)) == gfm`) for a number of examples of GFM for every filter. - [![Build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master) - [![CE coverage report](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=coverage)](https://gitlab-org.gitlab.io/gitlab-ce/coverage-ruby) - [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq) - [![Core Infrastructure Initiative Best Practices](https://bestpractices.coreinfrastructure.org/projects/42/badge)](https://bestpractices.coreinfrastructure.org/projects/42) + it 'supports nesting' do + verify '> 1. [x] **[$`2 + 2`$ {-=-}{+=+} 2^2 ~~:thumbsup:~~](http://google.com)**' + end - ## Canonical source + it 'supports a real world example from the gitlab-ce README' do + verify <<-GFM.strip_heredoc + # GitLab - The canonical source of GitLab Community Edition is [hosted on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/). + [![Build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master) + [![CE coverage report](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=coverage)](https://gitlab-org.gitlab.io/gitlab-ce/coverage-ruby) + [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq) + [![Core Infrastructure Initiative Best Practices](https://bestpractices.coreinfrastructure.org/projects/42/badge)](https://bestpractices.coreinfrastructure.org/projects/42) - ## Open source software to collaborate on code + ## Canonical source - To see how GitLab looks please see the [features page on our website](https://about.gitlab.com/features/). + The canonical source of GitLab Community Edition is [hosted on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/). + + ## Open source software to collaborate on code + + To see how GitLab looks please see the [features page on our website](https://about.gitlab.com/features/). - - Manage Git repositories with fine grained access controls that keep your code secure + - Manage Git repositories with fine grained access controls that keep your code secure - - Perform code reviews and enhance collaboration with merge requests + - Perform code reviews and enhance collaboration with merge requests - - Complete continuous integration (CI) and CD pipelines to builds, test, and deploy your applications + - Complete continuous integration (CI) and CD pipelines to builds, test, and deploy your applications - - Each project can also have an issue tracker, issue board, and a wiki + - Each project can also have an issue tracker, issue board, and a wiki - - Used by more than 100,000 organizations, GitLab is the most popular solution to manage Git repositories on-premises + - Used by more than 100,000 organizations, GitLab is the most popular solution to manage Git repositories on-premises - - Completely free and open source (MIT Expat license) - GFM - ] - ], - 'InlineDiffFilter' => [ + - Completely free and open source (MIT Expat license) + GFM + end + + it 'supports InlineDiffFilter' do + verify( '{-Deleted text-}', '{+Added text+}' - ], - 'TaskListFilter' => [ + ) + end + + it 'supports TaskListFilter' do + verify( '- [ ] Unchecked task', '- [x] Checked task', '1. [ ] Unchecked numbered task', '1. [x] Checked numbered task' - ], - 'ReferenceFilter' => [ - ['issue reference', -> { @feat.issue.to_reference }], - ['full issue reference', -> { @feat.issue.to_reference(full: true) }], - ['issue URL', -> { namespace_project_issue_url(@project.namespace, @project, @feat.issue) }], - ['issue URL with note anchor', -> { namespace_project_issue_url(@project.namespace, @project, @feat.issue, anchor: 'note_123') }], - ['issue link', -> { "[Issue](#{namespace_project_issue_url(@project.namespace, @project, @feat.issue)})" }], - ['issue link with note anchor', -> { "[Issue](#{namespace_project_issue_url(@project.namespace, @project, @feat.issue, anchor: 'note_123')})" }], - ], - 'AutolinkFilter' => [ - 'https://example.com' - ], - 'TableOfContentsFilter' => [ - '[[_TOC_]]' - ], - 'EmojiFilter' => [ - ':thumbsup:' - ], - 'ImageLinkFilter' => [ - '![Image](https://example.com/image.png)' - ], - 'VideoLinkFilter' => [ - '![Video](https://example.com/video.mp4)' - ], - 'MathFilter' => [ + ) + end + + it 'supports ReferenceFilter' do + verify( + # issue reference + @feat.issue.to_reference, + # full issue reference + @feat.issue.to_reference(full: true), + # issue URL + namespace_project_issue_url(@project.namespace, @project, @feat.issue), + # issue URL with note anchor + namespace_project_issue_url(@project.namespace, @project, @feat.issue, anchor: 'note_123'), + # issue link + "[Issue](#{namespace_project_issue_url(@project.namespace, @project, @feat.issue)})", + # issue link with note anchor + "[Issue](#{namespace_project_issue_url(@project.namespace, @project, @feat.issue, anchor: 'note_123')})", + ) + end + + it 'supports AutolinkFilter' do + verify 'https://example.com' + end + + it 'supports TableOfContentsFilter' do + verify '[[_TOC_]]' + end + + it 'supports EmojiFilter' do + verify ':thumbsup:' + end + + it 'supports ImageLinkFilter' do + verify '![Image](https://example.com/image.png)' + end + + it 'supports VideoLinkFilter' do + verify '![Video](https://example.com/video.mp4)' + end + + it 'supports MathFilter' do + verify( '$`c = \pm\sqrt{a^2 + b^2}`$', - [ - 'math block', - <<-GFM.strip_heredoc - ```math - c = \pm\sqrt{a^2 + b^2} - ``` - GFM - ] - ], - 'SyntaxHighlightFilter' => [ - [ - 'code block', - <<-GFM.strip_heredoc - ```ruby - def foo - bar - end - ``` - GFM - ] - ], - 'MarkdownFilter' => [ + # math block + <<-GFM.strip_heredoc + ```math + c = \pm\sqrt{a^2 + b^2} + ``` + GFM + ) + end + + it 'supports SyntaxHighlightFilter' do + verify <<-GFM.strip_heredoc + ```ruby + def foo + bar + end + ``` + GFM + end + + it 'supports MarkdownFilter' do + verify( '`code`', '`` code with ` ticks ``', '> Quote', - [ - 'multiline quote', - <<-GFM.strip_heredoc, - > Multiline - > Quote - > - > With multiple paragraphs - GFM - ], + # multiline quote + <<-GFM.strip_heredoc, + > Multiline + > Quote + > + > With multiple paragraphs + GFM '![Image](https://example.com/image.png)', @@ -132,39 +150,36 @@ describe 'Copy as GFM', feature: true, js: true do '[Link](https://example.com)', '- List item', - [ - 'multiline list item', - <<-GFM.strip_heredoc, - - Multiline - List item - GFM - ], - [ - 'nested lists', - <<-GFM.strip_heredoc, - - Nested + + # multiline list item + <<-GFM.strip_heredoc, + - Multiline + List item + GFM + + # nested lists + <<-GFM.strip_heredoc, + - Nested - - Lists - GFM - ], + - Lists + GFM + '1. Numbered list item', - [ - 'multiline numbered list item', - <<-GFM.strip_heredoc, - 1. Multiline - Numbered list item - GFM - ], - [ - 'nested numbered list', - <<-GFM.strip_heredoc, - 1. Nested + + # multiline numbered list item + <<-GFM.strip_heredoc, + 1. Multiline + Numbered list item + GFM + + # nested numbered list + <<-GFM.strip_heredoc, + 1. Nested - 1. Numbered lists - GFM - ], + 1. Numbered lists + GFM '# Heading', '## Heading', @@ -183,39 +198,18 @@ describe 'Copy as GFM', feature: true, js: true do '-----', - [ - 'table', - <<-GFM.strip_heredoc, - | Centered | Right | Left | - | :------: | ----: | ---- | - | Foo | Bar | **Baz** | - | Foo | Bar | **Baz** | - GFM - ] - ] - } - - filters.each do |filter, examples| - context filter do - examples.each do |ex| - if ex.is_a?(String) - desc = "'#{ex}'" - gfm = ex - else - desc, gfm = ex - end - - it "transforms #{desc} to HTML and back to GFM" do - gfm = instance_exec(&gfm) if gfm.is_a?(Proc) - - html = markdown(gfm) - gfm2 = html_to_gfm(html) - expect(gfm2.strip).to eq(gfm.strip) - end - end - end + # table + <<-GFM.strip_heredoc, + | Centered | Right | Left | + | :------: | ----: | ---- | + | Foo | Bar | **Baz** | + | Foo | Bar | **Baz** | + GFM + ) end + alias_method :gfm_to_html, :markdown + def html_to_gfm(html) js = <<-JS.strip_heredoc (function(html) { @@ -227,6 +221,16 @@ describe 'Copy as GFM', feature: true, js: true do page.evaluate_script(js) end + def verify(*gfms) + aggregate_failures do + gfms.each do |gfm| + html = gfm_to_html(gfm) + output_gfm = html_to_gfm(html) + expect(output_gfm.strip).to eq(gfm.strip) + end + end + end + # Fake a `current_user` helper def current_user @feat.user