summaryrefslogtreecommitdiff
path: root/spec/support/shared_contexts/markdown_golden_master_shared_examples.rb
blob: dea03af22484b0792a6862e15d0aadc7a123ed6c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# frozen_string_literal: true

require 'spec_helper'

# See spec/fixtures/markdown/markdown_golden_master_examples.yml for documentation on how this spec works.
RSpec.shared_context 'API::Markdown Golden Master shared context' do |markdown_yml_file_path|
  include ApiHelpers
  include WikiHelpers

  let_it_be(:user) { create(:user, username: 'gfm_user') }

  let_it_be(:group) { create(:group, :public) }
  let_it_be(:project) { create(:project, :public, :repository, group: group) }

  let_it_be(:label) { create(:label, project: project, title: 'bug') }
  let_it_be(:milestone) { create(:milestone, project: project, title: '1.1') }
  let_it_be(:issue) { create(:issue, project: project) }
  let_it_be(:merge_request) { create(:merge_request, source_project: project) }

  let_it_be(:project_wiki) { create(:project_wiki, project: project, user: user) }

  let_it_be(:project_wiki_page) { create(:wiki_page, wiki: project_wiki) }

  before(:all) do
    group.add_owner(user)
    project.add_maintainer(user)
  end

  before do
    sign_in(user)
  end

  markdown_examples = begin
    yaml = File.read(markdown_yml_file_path)
    YAML.safe_load(yaml, symbolize_names: true, aliases: true)
  end

  it "examples must be unique and alphabetized by name", :unlimited_max_formatted_output_length do
    names = markdown_examples.map { |example| example[:name] }
    expect(names).to eq(names.sort.uniq)
  end

  if focused_markdown_examples_string = ENV['FOCUSED_MARKDOWN_EXAMPLES']
    focused_markdown_examples = focused_markdown_examples_string.split(',').map(&:strip) || []
    markdown_examples.reject! {|markdown_example| !focused_markdown_examples.include?(markdown_example.fetch(:name)) }
  end

  markdown_examples.each do |markdown_example|
    name = markdown_example.fetch(:name)
    api_context = markdown_example[:api_context]

    if api_context && !name.end_with?("_for_#{api_context}")
      raise "Name must have suffix of '_for_#{api_context}' to the api_context"
    end

    context "for #{name}#{api_context ? " (api_context: #{api_context})" : ''}" do
      let(:pending_reason) do
        pending_value = markdown_example.fetch(:pending, nil)
        get_pending_reason(pending_value)
      end

      let(:example_markdown) { markdown_example.fetch(:markdown) }
      let(:example_html) { markdown_example.fetch(:html) }
      let(:substitutions) { markdown_example.fetch(:substitutions, {}) }

      it "verifies conversion of GFM to HTML", :unlimited_max_formatted_output_length do
        stub_application_setting(plantuml_enabled: true, plantuml_url: 'http://localhost:8080')
        stub_application_setting(kroki_enabled: true, kroki_url: 'http://localhost:8000')

        pending pending_reason if pending_reason

        normalized_example_html = normalize_html(example_html, substitutions)

        api_url = get_url_for_api_context(api_context)

        post api_url, params: { text: example_markdown, gfm: true }
        expect(response).to be_successful
        response_body = Gitlab::Json.parse(response.body)
        # Some requests have the HTML in the `html` key, others in the `body` key.
        response_html = response_body['body'] ? response_body.fetch('body') : response_body.fetch('html')
        normalized_response_html = normalize_html(response_html, substitutions)

        expect(normalized_response_html).to eq(normalized_example_html)
      end

      def get_pending_reason(pending_value)
        return false unless pending_value

        return pending_value if pending_value.is_a?(String)

        pending_value[:backend] || false
      end

      def normalize_html(html, substitutions)
        normalized_html = html.dup
        # Note: having the top level `substitutions` data structure be a hash of arrays
        # allows us to compose multiple substitutions via YAML anchors (YAML anchors
        # pointing to arrays can't be combined)
        substitutions.each_value do |substitution_entry|
          substitution_entry.each do |substitution|
            regex = substitution.fetch(:regex)
            replacement = substitution.fetch(:replacement)
            normalized_html.gsub!(%r{#{regex}}, replacement)
          end
        end

        normalized_html
      end
    end
  end

  def supported_api_contexts
    %w(project group project_wiki)
  end

  def get_url_for_api_context(api_context)
    case api_context
    when 'project'
      "/#{project.full_path}/preview_markdown"
    when 'group'
      "/groups/#{group.full_path}/preview_markdown"
    when 'project_wiki'
      "/#{project.full_path}/-/wikis/#{project_wiki_page.slug}/preview_markdown"
    when nil
      api "/markdown"
    else
      raise "Error: 'context' extension was '#{api_context}'. It must be one of: #{supported_api_contexts.join(',')}"
    end
  end
end