diff options
author | Bob Van Landuyt <bob@gitlab.com> | 2019-06-20 08:02:33 +0000 |
---|---|---|
committer | Douwe Maan <douwe@gitlab.com> | 2019-06-20 08:02:33 +0000 |
commit | 406808583c2392a0b57f68f98b2418e9d23b23ab (patch) | |
tree | 98613723a6caf6dc152f9ff431e75906ebe2c5ca /spec | |
parent | adeccba13676b831335e2f12f779f77602298b31 (diff) | |
download | gitlab-ce-406808583c2392a0b57f68f98b2418e9d23b23ab.tar.gz |
Render GFM html in GraphQL
This adds a `markdown_field` to our types.
Using this helper will render a model's markdown field using the
existing `MarkupHelper` with the context of the GraphQL query
available to the helper.
Having the context available to the helper is needed for redacting
links to resources that the current user is not allowed to see.
Because rendering the HTML can cause queries, the complexity of a
these fields is raised by 5 above the default.
The markdown field helper can be used as follows:
```
markdown_field :note_html, null: false
```
This would generate a field that will render the markdown field `note`
of the model. This could be overridden by adding the `method:`
argument. Passing a symbol for the method name:
```
markdown_field :body_html, null: false, method: :note
```
It will have this description by default:
> The GitLab Flavored Markdown rendering of `note`
This could be overridden by passing a `description:` argument.
The type of a `markdown_field` is always `GraphQL::STRING_TYPE`.
Diffstat (limited to 'spec')
-rw-r--r-- | spec/graphql/types/issue_type_spec.rb | 5 | ||||
-rw-r--r-- | spec/graphql/types/label_type_spec.rb | 10 | ||||
-rw-r--r-- | spec/graphql/types/merge_request_type_spec.rb | 17 | ||||
-rw-r--r-- | spec/graphql/types/namespace_type_spec.rb | 9 | ||||
-rw-r--r-- | spec/graphql/types/notes/note_type_spec.rb | 2 | ||||
-rw-r--r-- | spec/graphql/types/project_type_spec.rb | 30 | ||||
-rw-r--r-- | spec/lib/gitlab/graphql/markdown_field/resolver_spec.rb | 33 | ||||
-rw-r--r-- | spec/lib/gitlab/graphql/markdown_field_spec.rb | 55 |
8 files changed, 143 insertions, 18 deletions
diff --git a/spec/graphql/types/issue_type_spec.rb b/spec/graphql/types/issue_type_spec.rb index 210932f8488..799a8662b94 100644 --- a/spec/graphql/types/issue_type_spec.rb +++ b/spec/graphql/types/issue_type_spec.rb @@ -10,7 +10,10 @@ describe GitlabSchema.types['Issue'] do it { expect(described_class.interfaces).to include(Types::Notes::NoteableType.to_graphql) } it 'has specific fields' do - %i[relative_position web_path web_url reference].each do |field_name| + fields = %i[title_html description_html relative_position web_path web_url + reference] + + fields.each do |field_name| expect(described_class).to have_graphql_field(field_name) end end diff --git a/spec/graphql/types/label_type_spec.rb b/spec/graphql/types/label_type_spec.rb new file mode 100644 index 00000000000..f498b32f9ed --- /dev/null +++ b/spec/graphql/types/label_type_spec.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe GitlabSchema.types['Label'] do + it 'has the correct fields' do + expected_fields = [:description, :description_html, :title, :color, :text_color] + + is_expected.to have_graphql_fields(*expected_fields) + end +end diff --git a/spec/graphql/types/merge_request_type_spec.rb b/spec/graphql/types/merge_request_type_spec.rb index fd1c782bcc5..f73bd062369 100644 --- a/spec/graphql/types/merge_request_type_spec.rb +++ b/spec/graphql/types/merge_request_type_spec.rb @@ -7,7 +7,20 @@ describe GitlabSchema.types['MergeRequest'] do it { expect(described_class.interfaces).to include(Types::Notes::NoteableType.to_graphql) } - describe 'nested head pipeline' do - it { expect(described_class).to have_graphql_field(:head_pipeline) } + it 'has the expected fields' do + expected_fields = %w[ + notes discussions user_permissions id iid title title_html description + description_html state created_at updated_at source_project target_project + project project_id source_project_id target_project_id source_branch + target_branch work_in_progress merge_when_pipeline_succeeds diff_head_sha + merge_commit_sha user_notes_count should_remove_source_branch + force_remove_source_branch merge_status in_progress_merge_commit_sha + merge_error allow_collaboration should_be_rebased rebase_commit_sha + rebase_in_progress merge_commit_message default_merge_commit_message + merge_ongoing source_branch_exists mergeable_discussions_state web_url + upvotes downvotes subscribed head_pipeline pipelines task_completion_status + ] + + is_expected.to have_graphql_fields(*expected_fields) end end diff --git a/spec/graphql/types/namespace_type_spec.rb b/spec/graphql/types/namespace_type_spec.rb index b4144cc4121..77fd590586e 100644 --- a/spec/graphql/types/namespace_type_spec.rb +++ b/spec/graphql/types/namespace_type_spec.rb @@ -5,5 +5,12 @@ require 'spec_helper' describe GitlabSchema.types['Namespace'] do it { expect(described_class.graphql_name).to eq('Namespace') } - it { expect(described_class).to have_graphql_field(:projects) } + it 'has the expected fields' do + expected_fields = %w[ + id name path full_name full_path description description_html visibility + lfs_enabled request_access_enabled projects + ] + + is_expected.to have_graphql_fields(*expected_fields) + end end diff --git a/spec/graphql/types/notes/note_type_spec.rb b/spec/graphql/types/notes/note_type_spec.rb index 8022b20f9dd..e8a58da4b17 100644 --- a/spec/graphql/types/notes/note_type_spec.rb +++ b/spec/graphql/types/notes/note_type_spec.rb @@ -5,7 +5,7 @@ describe GitlabSchema.types['Note'] do it 'exposes the expected fields' do expected_fields = [:id, :project, :author, :body, :created_at, :updated_at, :discussion, :resolvable, :position, :user_permissions, - :resolved_by, :resolved_at, :system] + :resolved_by, :resolved_at, :system, :body_html] is_expected.to have_graphql_fields(*expected_fields) end diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb index cb5ac2e3cb1..69fbc72bdf5 100644 --- a/spec/graphql/types/project_type_spec.rb +++ b/spec/graphql/types/project_type_spec.rb @@ -7,18 +7,22 @@ describe GitlabSchema.types['Project'] do it { expect(described_class).to require_graphql_authorizations(:read_project) } - describe 'nested merge request' do - it { expect(described_class).to have_graphql_field(:merge_requests) } - it { expect(described_class).to have_graphql_field(:merge_request) } + it 'has the expected fields' do + expected_fields = %w[ + user_permissions id full_path path name_with_namespace + name description description_html tag_list ssh_url_to_repo + http_url_to_repo web_url star_count forks_count + created_at last_activity_at archived visibility + container_registry_enabled shared_runners_enabled + lfs_enabled merge_requests_ff_only_enabled avatar_url + issues_enabled merge_requests_enabled wiki_enabled + snippets_enabled jobs_enabled public_jobs open_issues_count import_status + only_allow_merge_if_pipeline_succeeds request_access_enabled + only_allow_merge_if_all_discussions_are_resolved printing_merge_request_link_enabled + namespace group statistics repository merge_requests merge_request issues + issue pipelines + ] + + is_expected.to have_graphql_fields(*expected_fields) end - - describe 'nested issues' do - it { expect(described_class).to have_graphql_field(:issues) } - end - - it { is_expected.to have_graphql_field(:pipelines) } - - it { is_expected.to have_graphql_field(:repository) } - - it { is_expected.to have_graphql_field(:statistics) } end diff --git a/spec/lib/gitlab/graphql/markdown_field/resolver_spec.rb b/spec/lib/gitlab/graphql/markdown_field/resolver_spec.rb new file mode 100644 index 00000000000..b95bcdef188 --- /dev/null +++ b/spec/lib/gitlab/graphql/markdown_field/resolver_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Gitlab::Graphql::MarkdownField::Resolver do + include Gitlab::Routing + let(:resolver) { described_class.new(:note) } + + describe '#proc' do + let(:project) { create(:project, :public) } + let(:issue) { create(:issue, project: project) } + let(:note) do + create(:note, + note: "Referencing #{issue.to_reference(full: true)}") + end + + it 'renders markdown correctly' do + expect(resolver.proc.call(note, {}, {})).to include(issue_path(issue)) + end + + context 'when the issue is not publicly accessible' do + let(:project) { create(:project, :private) } + + it 'hides the references from users that are not allowed to see the reference' do + expect(resolver.proc.call(note, {}, {})).not_to include(issue_path(issue)) + end + + it 'shows the reference to users that are allowed to see it' do + expect(resolver.proc.call(note, {}, { current_user: project.owner })) + .to include(issue_path(issue)) + end + end + end +end diff --git a/spec/lib/gitlab/graphql/markdown_field_spec.rb b/spec/lib/gitlab/graphql/markdown_field_spec.rb new file mode 100644 index 00000000000..a8566aa8e1c --- /dev/null +++ b/spec/lib/gitlab/graphql/markdown_field_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Gitlab::Graphql::MarkdownField do + describe '.markdown_field' do + it 'creates the field with some default attributes' do + field = class_with_markdown_field(:test_html, null: true, method: :hello).fields['testHtml'] + + expect(field.name).to eq('testHtml') + expect(field.description).to eq('The GitLab Flavored Markdown rendering of `hello`') + expect(field.type).to eq(GraphQL::STRING_TYPE) + expect(field.to_graphql.complexity).to eq(5) + end + + context 'developer warnings' do + let(:expected_error) { /Only `method` is allowed to specify the markdown field/ } + + it 'raises when passing a resolver' do + expect { class_with_markdown_field(:test_html, null: true, resolver: 'not really') } + .to raise_error(expected_error) + end + + it 'raises when passing a resolve block' do + expect { class_with_markdown_field(:test_html, null: true, resolve: -> (_, _, _) { 'not really' } ) } + .to raise_error(expected_error) + end + end + + context 'resolving markdown' do + let(:note) { build(:note, note: '# Markdown!') } + let(:thing_with_markdown) { double('markdown thing', object: note) } + let(:expected_markdown) { '<h1 data-sourcepos="1:1-1:11" dir="auto">Markdown!</h1>' } + + it 'renders markdown from the same property as the field name without the `_html` suffix' do + field = class_with_markdown_field(:note_html, null: false).fields['noteHtml'] + + expect(field.to_graphql.resolve(thing_with_markdown, {}, {})).to eq(expected_markdown) + end + + it 'renders markdown from a specific property when a `method` argument is passed' do + field = class_with_markdown_field(:test_html, null: false, method: :note).fields['testHtml'] + + expect(field.to_graphql.resolve(thing_with_markdown, {}, {})).to eq(expected_markdown) + end + end + end + + def class_with_markdown_field(name, **args) + Class.new(GraphQL::Schema::Object) do + prepend Gitlab::Graphql::MarkdownField + + markdown_field name, **args + end + end +end |