summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorJan Provaznik <jprovaznik@gitlab.com>2018-02-28 08:48:23 +0100
committerJan Provaznik <jprovaznik@gitlab.com>2018-03-07 12:27:50 +0100
commitdcdfa04b322db3905f6871a6857e7055c556547f (patch)
treeb3d006e8410b7182c63bfd620b99a71392c77aff /spec
parent8a0052c037f025b64159ca8cfe0d3451261c1edb (diff)
downloadgitlab-ce-dcdfa04b322db3905f6871a6857e7055c556547f.tar.gz
Add discussion APIjprovazn-api
* adds basic discussions API for issues and snippets * reorganizes notes specs (so same tests can be used for all noteable types - issues, MRs, snippets)
Diffstat (limited to 'spec')
-rw-r--r--spec/factories/notes.rb8
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/notes.json1
-rw-r--r--spec/requests/api/discussions_spec.rb33
-rw-r--r--spec/requests/api/notes_spec.rb590
-rw-r--r--spec/support/shared_examples/requests/api/discussions.rb169
-rw-r--r--spec/support/shared_examples/requests/api/notes.rb206
6 files changed, 502 insertions, 505 deletions
diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb
index 3f4e408b3a6..857333f222d 100644
--- a/spec/factories/notes.rb
+++ b/spec/factories/notes.rb
@@ -16,6 +16,8 @@ FactoryBot.define do
factory :note_on_personal_snippet, traits: [:on_personal_snippet]
factory :system_note, traits: [:system]
+ factory :discussion_note, class: DiscussionNote
+
factory :discussion_note_on_merge_request, traits: [:on_merge_request], class: DiscussionNote do
association :project, :repository
@@ -31,6 +33,8 @@ FactoryBot.define do
factory :discussion_note_on_personal_snippet, traits: [:on_personal_snippet], class: DiscussionNote
+ factory :discussion_note_on_snippet, traits: [:on_snippet], class: DiscussionNote
+
factory :legacy_diff_note_on_commit, traits: [:on_commit, :legacy_diff_note], class: LegacyDiffNote
factory :legacy_diff_note_on_merge_request, traits: [:on_merge_request, :legacy_diff_note], class: LegacyDiffNote do
@@ -96,6 +100,10 @@ FactoryBot.define do
noteable { create(:issue, project: project) }
end
+ trait :on_snippet do
+ noteable { create(:snippet, project: project) }
+ end
+
trait :on_merge_request do
noteable { create(:merge_request, source_project: project) }
end
diff --git a/spec/fixtures/api/schemas/public_api/v4/notes.json b/spec/fixtures/api/schemas/public_api/v4/notes.json
index 6525f7c2c80..4c4ca3b582f 100644
--- a/spec/fixtures/api/schemas/public_api/v4/notes.json
+++ b/spec/fixtures/api/schemas/public_api/v4/notes.json
@@ -4,6 +4,7 @@
"type": "object",
"properties" : {
"id": { "type": "integer" },
+ "type": { "type": ["string", "null"] },
"body": { "type": "string" },
"attachment": { "type": ["string", "null"] },
"author": {
diff --git a/spec/requests/api/discussions_spec.rb b/spec/requests/api/discussions_spec.rb
new file mode 100644
index 00000000000..4a44b219a67
--- /dev/null
+++ b/spec/requests/api/discussions_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+
+describe API::Discussions do
+ let(:user) { create(:user) }
+ let!(:project) { create(:project, :public, namespace: user.namespace) }
+ let(:private_user) { create(:user) }
+
+ before do
+ project.add_reporter(user)
+ end
+
+ context "when noteable is an Issue" do
+ let!(:issue) { create(:issue, project: project, author: user) }
+ let!(:issue_note) { create(:discussion_note_on_issue, noteable: issue, project: project, author: user) }
+
+ it_behaves_like "discussions API", 'projects', 'issues', 'iid' do
+ let(:parent) { project }
+ let(:noteable) { issue }
+ let(:note) { issue_note }
+ end
+ end
+
+ context "when noteable is a Snippet" do
+ let!(:snippet) { create(:project_snippet, project: project, author: user) }
+ let!(:snippet_note) { create(:discussion_note_on_snippet, noteable: snippet, project: project, author: user) }
+
+ it_behaves_like "discussions API", 'projects', 'snippets', 'id' do
+ let(:parent) { project }
+ let(:noteable) { snippet }
+ let(:note) { snippet_note }
+ end
+ end
+end
diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb
index 981c9c27325..dd568c24c72 100644
--- a/spec/requests/api/notes_spec.rb
+++ b/spec/requests/api/notes_spec.rb
@@ -3,117 +3,86 @@ require 'spec_helper'
describe API::Notes do
let(:user) { create(:user) }
let!(:project) { create(:project, :public, namespace: user.namespace) }
- let!(:issue) { create(:issue, project: project, author: user) }
- let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: user) }
- let!(:snippet) { create(:project_snippet, project: project, author: user) }
- let!(:issue_note) { create(:note, noteable: issue, project: project, author: user) }
- let!(:merge_request_note) { create(:note, noteable: merge_request, project: project, author: user) }
- let!(:snippet_note) { create(:note, noteable: snippet, project: project, author: user) }
-
- # For testing the cross-reference of a private issue in a public issue
let(:private_user) { create(:user) }
- let(:private_project) do
- create(:project, namespace: private_user.namespace)
- .tap { |p| p.add_master(private_user) }
- end
- let(:private_issue) { create(:issue, project: private_project) }
-
- let(:ext_proj) { create(:project, :public) }
- let(:ext_issue) { create(:issue, project: ext_proj) }
-
- let!(:cross_reference_note) do
- create :note,
- noteable: ext_issue, project: ext_proj,
- note: "mentioned in issue #{private_issue.to_reference(ext_proj)}",
- system: true
- end
before do
project.add_reporter(user)
end
- describe "GET /projects/:id/noteable/:noteable_id/notes" do
- context "when noteable is an Issue" do
- context 'sorting' do
- before do
- create_list(:note, 3, noteable: issue, project: project, author: user)
- end
-
- it 'sorts by created_at in descending order by default' do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes", user)
-
- response_dates = json_response.map { |noteable| noteable['created_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort.reverse)
- end
-
- it 'sorts by ascending order when requested' do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes?sort=asc", user)
-
- response_dates = json_response.map { |noteable| noteable['created_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort)
- end
-
- it 'sorts by updated_at in descending order when requested' do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes?order_by=updated_at", user)
-
- response_dates = json_response.map { |noteable| noteable['updated_at'] }
+ context "when noteable is an Issue" do
+ let!(:issue) { create(:issue, project: project, author: user) }
+ let!(:issue_note) { create(:note, noteable: issue, project: project, author: user) }
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort.reverse)
- end
+ it_behaves_like "noteable API", 'projects', 'issues', 'iid' do
+ let(:parent) { project }
+ let(:noteable) { issue }
+ let(:note) { issue_note }
+ end
- it 'sorts by updated_at in ascending order when requested' do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes??order_by=updated_at&sort=asc", user)
+ context 'when user does not have access to create noteable' do
+ let(:private_issue) { create(:issue, project: create(:project, :private)) }
- response_dates = json_response.map { |noteable| noteable['updated_at'] }
+ ##
+ # We are posting to project user has access to, but we use issue id
+ # from a different project, see #15577
+ #
+ before do
+ post api("/projects/#{private_issue.project.id}/issues/#{private_issue.iid}/notes", user),
+ body: 'Hi!'
+ end
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort)
- end
+ it 'responds with resource not found error' do
+ expect(response.status).to eq 404
end
- it "returns an array of issue notes" do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes", user)
+ it 'does not create new note' do
+ expect(private_issue.notes.reload).to be_empty
+ end
+ end
- expect(response).to have_gitlab_http_status(200)
- expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
- expect(json_response.first['body']).to eq(issue_note.note)
+ context "when referencing other project" do
+ # For testing the cross-reference of a private issue in a public project
+ let(:private_project) do
+ create(:project, namespace: private_user.namespace)
+ .tap { |p| p.add_master(private_user) }
end
+ let(:private_issue) { create(:issue, project: private_project) }
- it "returns a 404 error when issue id not found" do
- get api("/projects/#{project.id}/issues/12345/notes", user)
+ let(:ext_proj) { create(:project, :public) }
+ let(:ext_issue) { create(:issue, project: ext_proj) }
- expect(response).to have_gitlab_http_status(404)
+ let!(:cross_reference_note) do
+ create :note,
+ noteable: ext_issue, project: ext_proj,
+ note: "mentioned in issue #{private_issue.to_reference(ext_proj)}",
+ system: true
end
- context "and current user cannot view the notes" do
- it "returns an empty array" do
- get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes", user)
-
- expect(response).to have_gitlab_http_status(200)
- expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
- expect(json_response).to be_empty
- end
+ describe "GET /projects/:id/noteable/:noteable_id/notes" do
+ context "current user cannot view the notes" do
+ it "returns an empty array" do
+ get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes", user)
- context "and issue is confidential" do
- before do
- ext_issue.update_attributes(confidential: true)
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response).to be_empty
end
- it "returns 404" do
- get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes", user)
+ context "issue is confidential" do
+ before do
+ ext_issue.update_attributes(confidential: true)
+ end
- expect(response).to have_gitlab_http_status(404)
+ it "returns 404" do
+ get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
end
end
- context "and current user can view the note" do
+ context "current user can view the note" do
it "returns an empty array" do
get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes", private_user)
@@ -124,172 +93,29 @@ describe API::Notes do
end
end
end
- end
-
- context "when noteable is a Snippet" do
- context 'sorting' do
- before do
- create_list(:note, 3, noteable: snippet, project: project, author: user)
- end
-
- it 'sorts by created_at in descending order by default' do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
-
- response_dates = json_response.map { |noteable| noteable['created_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort.reverse)
- end
-
- it 'sorts by ascending order when requested' do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes?sort=asc", user)
-
- response_dates = json_response.map { |noteable| noteable['created_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort)
- end
-
- it 'sorts by updated_at in descending order when requested' do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes?order_by=updated_at", user)
-
- response_dates = json_response.map { |noteable| noteable['updated_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort.reverse)
- end
- it 'sorts by updated_at in ascending order when requested' do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes??order_by=updated_at&sort=asc", user)
+ describe "GET /projects/:id/noteable/:noteable_id/notes/:note_id" do
+ context "current user cannot view the notes" do
+ it "returns a 404 error" do
+ get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes/#{cross_reference_note.id}", user)
- response_dates = json_response.map { |noteable| noteable['updated_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort)
- end
- end
- it "returns an array of snippet notes" do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
-
- expect(response).to have_gitlab_http_status(200)
- expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
- expect(json_response.first['body']).to eq(snippet_note.note)
- end
-
- it "returns a 404 error when snippet id not found" do
- get api("/projects/#{project.id}/snippets/42/notes", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- it "returns 404 when not authorized" do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", private_user)
-
- expect(response).to have_gitlab_http_status(404)
- end
- end
-
- context "when noteable is a Merge Request" do
- context 'sorting' do
- before do
- create_list(:note, 3, noteable: merge_request, project: project, author: user)
- end
-
- it 'sorts by created_at in descending order by default' do
- get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes", user)
-
- response_dates = json_response.map { |noteable| noteable['created_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort.reverse)
- end
-
- it 'sorts by ascending order when requested' do
- get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes?sort=asc", user)
-
- response_dates = json_response.map { |noteable| noteable['created_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort)
- end
-
- it 'sorts by updated_at in descending order when requested' do
- get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes?order_by=updated_at", user)
-
- response_dates = json_response.map { |noteable| noteable['updated_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort.reverse)
- end
-
- it 'sorts by updated_at in ascending order when requested' do
- get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes??order_by=updated_at&sort=asc", user)
-
- response_dates = json_response.map { |noteable| noteable['updated_at'] }
-
- expect(json_response.length).to eq(4)
- expect(response_dates).to eq(response_dates.sort)
- end
- end
- it "returns an array of merge_requests notes" do
- get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes", user)
-
- expect(response).to have_gitlab_http_status(200)
- expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
- expect(json_response.first['body']).to eq(merge_request_note.note)
- end
-
- it "returns a 404 error if merge request id not found" do
- get api("/projects/#{project.id}/merge_requests/4444/notes", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- it "returns 404 when not authorized" do
- get api("/projects/#{project.id}/merge_requests/4444/notes", private_user)
-
- expect(response).to have_gitlab_http_status(404)
- end
- end
- end
-
- describe "GET /projects/:id/noteable/:noteable_id/notes/:note_id" do
- context "when noteable is an Issue" do
- it "returns an issue note by id" do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{issue_note.id}", user)
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response['body']).to eq(issue_note.note)
- end
-
- it "returns a 404 error if issue note not found" do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes/12345", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- context "and current user cannot view the note" do
- it "returns a 404 error" do
- get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes/#{cross_reference_note.id}", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- context "when issue is confidential" do
- before do
- issue.update_attributes(confidential: true)
+ expect(response).to have_gitlab_http_status(404)
end
- it "returns 404" do
- get api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{issue_note.id}", private_user)
+ context "when issue is confidential" do
+ before do
+ issue.update_attributes(confidential: true)
+ end
- expect(response).to have_gitlab_http_status(404)
+ it "returns 404" do
+ get api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{issue_note.id}", private_user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
end
end
- context "and current user can view the note" do
+ context "current user can view the note" do
it "returns an issue note by id" do
get api("/projects/#{ext_proj.id}/issues/#{ext_issue.iid}/notes/#{cross_reference_note.id}", private_user)
@@ -299,132 +125,27 @@ describe API::Notes do
end
end
end
-
- context "when noteable is a Snippet" do
- it "returns a snippet note by id" do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes/#{snippet_note.id}", user)
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response['body']).to eq(snippet_note.note)
- end
-
- it "returns a 404 error if snippet note not found" do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes/12345", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
- end
end
- describe "POST /projects/:id/noteable/:noteable_id/notes" do
- context "when noteable is an Issue" do
- it "creates a new issue note" do
- post api("/projects/#{project.id}/issues/#{issue.iid}/notes", user), body: 'hi!'
-
- expect(response).to have_gitlab_http_status(201)
- expect(json_response['body']).to eq('hi!')
- expect(json_response['author']['username']).to eq(user.username)
- end
-
- it "returns a 400 bad request error if body not given" do
- post api("/projects/#{project.id}/issues/#{issue.iid}/notes", user)
-
- expect(response).to have_gitlab_http_status(400)
- end
-
- it "returns a 401 unauthorized error if user not authenticated" do
- post api("/projects/#{project.id}/issues/#{issue.iid}/notes"), body: 'hi!'
-
- expect(response).to have_gitlab_http_status(401)
- end
-
- context 'when an admin or owner makes the request' do
- it 'accepts the creation date to be set' do
- creation_time = 2.weeks.ago
- post api("/projects/#{project.id}/issues/#{issue.iid}/notes", user),
- body: 'hi!', created_at: creation_time
-
- expect(response).to have_gitlab_http_status(201)
- expect(json_response['body']).to eq('hi!')
- expect(json_response['author']['username']).to eq(user.username)
- expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time)
- end
- end
-
- context 'when the user is posting an award emoji on an issue created by someone else' do
- let(:issue2) { create(:issue, project: project) }
-
- it 'creates a new issue note' do
- post api("/projects/#{project.id}/issues/#{issue2.iid}/notes", user), body: ':+1:'
-
- expect(response).to have_gitlab_http_status(201)
- expect(json_response['body']).to eq(':+1:')
- end
- end
-
- context 'when the user is posting an award emoji on his/her own issue' do
- it 'creates a new issue note' do
- post api("/projects/#{project.id}/issues/#{issue.iid}/notes", user), body: ':+1:'
-
- expect(response).to have_gitlab_http_status(201)
- expect(json_response['body']).to eq(':+1:')
- end
- end
- end
-
- context "when noteable is a Snippet" do
- it "creates a new snippet note" do
- post api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user), body: 'hi!'
+ context "when noteable is a Snippet" do
+ let!(:snippet) { create(:project_snippet, project: project, author: user) }
+ let!(:snippet_note) { create(:note, noteable: snippet, project: project, author: user) }
- expect(response).to have_gitlab_http_status(201)
- expect(json_response['body']).to eq('hi!')
- expect(json_response['author']['username']).to eq(user.username)
- end
-
- it "returns a 400 bad request error if body not given" do
- post api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
-
- expect(response).to have_gitlab_http_status(400)
- end
-
- it "returns a 401 unauthorized error if user not authenticated" do
- post api("/projects/#{project.id}/snippets/#{snippet.id}/notes"), body: 'hi!'
-
- expect(response).to have_gitlab_http_status(401)
- end
+ it_behaves_like "noteable API", 'projects', 'snippets', 'id' do
+ let(:parent) { project }
+ let(:noteable) { snippet }
+ let(:note) { snippet_note }
end
+ end
- context 'when user does not have access to read the noteable' do
- it 'responds with 404' do
- project = create(:project, :private) { |p| p.add_guest(user) }
- issue = create(:issue, :confidential, project: project)
-
- post api("/projects/#{project.id}/issues/#{issue.iid}/notes", user),
- body: 'Foo'
-
- expect(response).to have_gitlab_http_status(404)
- end
- end
-
- context 'when user does not have access to create noteable' do
- let(:private_issue) { create(:issue, project: create(:project, :private)) }
-
- ##
- # We are posting to project user has access to, but we use issue id
- # from a different project, see #15577
- #
- before do
- post api("/projects/#{private_issue.project.id}/issues/#{private_issue.iid}/notes", user),
- body: 'Hi!'
- end
-
- it 'responds with resource not found error' do
- expect(response.status).to eq 404
- end
+ context "when noteable is a Merge Request" do
+ let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: user) }
+ let!(:merge_request_note) { create(:note, noteable: merge_request, project: project, author: user) }
- it 'does not create new note' do
- expect(private_issue.notes.reload).to be_empty
- end
+ it_behaves_like "noteable API", 'projects', 'merge_requests', 'iid' do
+ let(:parent) { project }
+ let(:noteable) { merge_request }
+ let(:note) { merge_request_note }
end
context 'when the merge request discussion is locked' do
@@ -461,145 +182,4 @@ describe API::Notes do
end
end
end
-
- describe "POST /projects/:id/noteable/:noteable_id/notes to test observer on create" do
- it "creates an activity event when an issue note is created" do
- expect(Event).to receive(:create!)
-
- post api("/projects/#{project.id}/issues/#{issue.iid}/notes", user), body: 'hi!'
- end
- end
-
- describe 'PUT /projects/:id/noteable/:noteable_id/notes/:note_id' do
- context 'when noteable is an Issue' do
- it 'returns modified note' do
- put api("/projects/#{project.id}/issues/#{issue.iid}/"\
- "notes/#{issue_note.id}", user), body: 'Hello!'
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response['body']).to eq('Hello!')
- end
-
- it 'returns a 404 error when note id not found' do
- put api("/projects/#{project.id}/issues/#{issue.iid}/notes/12345", user),
- body: 'Hello!'
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- it 'returns a 400 bad request error if body not given' do
- put api("/projects/#{project.id}/issues/#{issue.iid}/"\
- "notes/#{issue_note.id}", user)
-
- expect(response).to have_gitlab_http_status(400)
- end
- end
-
- context 'when noteable is a Snippet' do
- it 'returns modified note' do
- put api("/projects/#{project.id}/snippets/#{snippet.id}/"\
- "notes/#{snippet_note.id}", user), body: 'Hello!'
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response['body']).to eq('Hello!')
- end
-
- it 'returns a 404 error when note id not found' do
- put api("/projects/#{project.id}/snippets/#{snippet.id}/"\
- "notes/12345", user), body: "Hello!"
-
- expect(response).to have_gitlab_http_status(404)
- end
- end
-
- context 'when noteable is a Merge Request' do
- it 'returns modified note' do
- put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/"\
- "notes/#{merge_request_note.id}", user), body: 'Hello!'
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response['body']).to eq('Hello!')
- end
-
- it 'returns a 404 error when note id not found' do
- put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/"\
- "notes/12345", user), body: "Hello!"
-
- expect(response).to have_gitlab_http_status(404)
- end
- end
- end
-
- describe 'DELETE /projects/:id/noteable/:noteable_id/notes/:note_id' do
- context 'when noteable is an Issue' do
- it 'deletes a note' do
- delete api("/projects/#{project.id}/issues/#{issue.iid}/"\
- "notes/#{issue_note.id}", user)
-
- expect(response).to have_gitlab_http_status(204)
- # Check if note is really deleted
- delete api("/projects/#{project.id}/issues/#{issue.iid}/"\
- "notes/#{issue_note.id}", user)
- expect(response).to have_gitlab_http_status(404)
- end
-
- it 'returns a 404 error when note id not found' do
- delete api("/projects/#{project.id}/issues/#{issue.iid}/notes/12345", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- it_behaves_like '412 response' do
- let(:request) { api("/projects/#{project.id}/issues/#{issue.iid}/notes/#{issue_note.id}", user) }
- end
- end
-
- context 'when noteable is a Snippet' do
- it 'deletes a note' do
- delete api("/projects/#{project.id}/snippets/#{snippet.id}/"\
- "notes/#{snippet_note.id}", user)
-
- expect(response).to have_gitlab_http_status(204)
- # Check if note is really deleted
- delete api("/projects/#{project.id}/snippets/#{snippet.id}/"\
- "notes/#{snippet_note.id}", user)
- expect(response).to have_gitlab_http_status(404)
- end
-
- it 'returns a 404 error when note id not found' do
- delete api("/projects/#{project.id}/snippets/#{snippet.id}/"\
- "notes/12345", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- it_behaves_like '412 response' do
- let(:request) { api("/projects/#{project.id}/snippets/#{snippet.id}/notes/#{snippet_note.id}", user) }
- end
- end
-
- context 'when noteable is a Merge Request' do
- it 'deletes a note' do
- delete api("/projects/#{project.id}/merge_requests/"\
- "#{merge_request.iid}/notes/#{merge_request_note.id}", user)
-
- expect(response).to have_gitlab_http_status(204)
- # Check if note is really deleted
- delete api("/projects/#{project.id}/merge_requests/"\
- "#{merge_request.iid}/notes/#{merge_request_note.id}", user)
- expect(response).to have_gitlab_http_status(404)
- end
-
- it 'returns a 404 error when note id not found' do
- delete api("/projects/#{project.id}/merge_requests/"\
- "#{merge_request.iid}/notes/12345", user)
-
- expect(response).to have_gitlab_http_status(404)
- end
-
- it_behaves_like '412 response' do
- let(:request) { api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes/#{merge_request_note.id}", user) }
- end
- end
- end
end
diff --git a/spec/support/shared_examples/requests/api/discussions.rb b/spec/support/shared_examples/requests/api/discussions.rb
new file mode 100644
index 00000000000..b6aeb30d69c
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/discussions.rb
@@ -0,0 +1,169 @@
+shared_examples 'discussions API' do |parent_type, noteable_type, id_name|
+ describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions" do
+ it "returns an array of discussions" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.first['id']).to eq(note.discussion_id)
+ end
+
+ it "returns a 404 error when noteable id not found" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/12345/discussions", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it "returns 404 when not authorized" do
+ parent.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", private_user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id" do
+ it "returns a discussion by id" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions/#{note.discussion_id}", user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['id']).to eq(note.discussion_id)
+ expect(json_response['notes'].first['body']).to eq(note.note)
+ end
+
+ it "returns a 404 error if discussion not found" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions/12345", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ describe "POST /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions" do
+ it "creates a new note" do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user), body: 'hi!'
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['notes'].first['body']).to eq('hi!')
+ expect(json_response['notes'].first['author']['username']).to eq(user.username)
+ end
+
+ it "returns a 400 bad request error if body not given" do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it "returns a 401 unauthorized error if user not authenticated" do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions"), body: 'hi!'
+
+ expect(response).to have_gitlab_http_status(401)
+ end
+
+ context 'when an admin or owner makes the request' do
+ it 'accepts the creation date to be set' do
+ creation_time = 2.weeks.ago
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user),
+ body: 'hi!', created_at: creation_time
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['notes'].first['body']).to eq('hi!')
+ expect(json_response['notes'].first['author']['username']).to eq(user.username)
+ expect(Time.parse(json_response['notes'].first['created_at'])).to be_like_time(creation_time)
+ end
+ end
+
+ context 'when user does not have access to read the discussion' do
+ before do
+ parent.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+ end
+
+ it 'responds with 404' do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", private_user),
+ body: 'Foo'
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+ end
+
+ describe "POST /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id/notes" do
+ it 'adds a new note to the discussion' do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes", user), body: 'Hello!'
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['body']).to eq('Hello!')
+ expect(json_response['type']).to eq('DiscussionNote')
+ end
+
+ it 'returns a 400 bad request error if body not given' do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes", user)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it "returns a 400 bad request error if discussion is individual note" do
+ note.update_attribute(:type, nil)
+
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes", user), body: 'hi!'
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+ end
+
+ describe "PUT /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id/notes/:note_id" do
+ it 'returns modified note' do
+ put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes/#{note.id}", user), body: 'Hello!'
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['body']).to eq('Hello!')
+ end
+
+ it 'returns a 404 error when note id not found' do
+ put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes/12345", user),
+ body: 'Hello!'
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it 'returns a 400 bad request error if body not given' do
+ put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes/#{note.id}", user)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+ end
+
+ describe "DELETE /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id/notes/:note_id" do
+ it 'deletes a note' do
+ delete api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes/#{note.id}", user)
+
+ expect(response).to have_gitlab_http_status(204)
+ # Check if note is really deleted
+ delete api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes/#{note.id}", user)
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it 'returns a 404 error when note id not found' do
+ delete api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes/12345", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it_behaves_like '412 response' do
+ let(:request) do
+ api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "discussions/#{note.discussion_id}/notes/#{note.id}", user)
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/notes.rb b/spec/support/shared_examples/requests/api/notes.rb
new file mode 100644
index 00000000000..79b2196660c
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/notes.rb
@@ -0,0 +1,206 @@
+shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
+ describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes" do
+ context 'sorting' do
+ before do
+ params = { noteable: noteable, author: user }
+ params[:project] = parent if parent.is_a?(Project)
+
+ create_list(:note, 3, params)
+ end
+
+ it 'sorts by created_at in descending order by default' do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user)
+
+ response_dates = json_response.map { |note| note['created_at'] }
+
+ expect(json_response.length).to eq(4)
+ expect(response_dates).to eq(response_dates.sort.reverse)
+ end
+
+ it 'sorts by ascending order when requested' do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes?sort=asc", user)
+
+ response_dates = json_response.map { |note| note['created_at'] }
+
+ expect(json_response.length).to eq(4)
+ expect(response_dates).to eq(response_dates.sort)
+ end
+
+ it 'sorts by updated_at in descending order when requested' do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes?order_by=updated_at", user)
+
+ response_dates = json_response.map { |note| note['updated_at'] }
+
+ expect(json_response.length).to eq(4)
+ expect(response_dates).to eq(response_dates.sort.reverse)
+ end
+
+ it 'sorts by updated_at in ascending order when requested' do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes?order_by=updated_at&sort=asc", user)
+
+ response_dates = json_response.map { |note| note['updated_at'] }
+
+ expect(json_response.length).to eq(4)
+ expect(response_dates).to eq(response_dates.sort)
+ end
+ end
+
+ it "returns an array of notes" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.first['body']).to eq(note.note)
+ end
+
+ it "returns a 404 error when noteable id not found" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/12345/notes", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it "returns 404 when not authorized" do
+ parent.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", private_user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ describe "GET /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes/:note_id" do
+ it "returns a note by id" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/#{note.id}", user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['body']).to eq(note.note)
+ end
+
+ it "returns a 404 error if note not found" do
+ get api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/12345", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ describe "POST /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes" do
+ it "creates a new note" do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), body: 'hi!'
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['body']).to eq('hi!')
+ expect(json_response['author']['username']).to eq(user.username)
+ end
+
+ it "returns a 400 bad request error if body not given" do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it "returns a 401 unauthorized error if user not authenticated" do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes"), body: 'hi!'
+
+ expect(response).to have_gitlab_http_status(401)
+ end
+
+ it "creates an activity event when a note is created" do
+ expect(Event).to receive(:create!)
+
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), body: 'hi!'
+ end
+
+ context 'when an admin or owner makes the request' do
+ it 'accepts the creation date to be set' do
+ creation_time = 2.weeks.ago
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user),
+ body: 'hi!', created_at: creation_time
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['body']).to eq('hi!')
+ expect(json_response['author']['username']).to eq(user.username)
+ expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time)
+ end
+ end
+
+ context 'when the user is posting an award emoji on a noteable created by someone else' do
+ it 'creates a new note' do
+ parent.add_developer(private_user)
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", private_user), body: ':+1:'
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['body']).to eq(':+1:')
+ end
+ end
+
+ context 'when the user is posting an award emoji on his/her own noteable' do
+ it 'creates a new note' do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), body: ':+1:'
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['body']).to eq(':+1:')
+ end
+ end
+
+ context 'when user does not have access to read the noteable' do
+ before do
+ parent.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+ end
+
+ it 'responds with 404' do
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", private_user),
+ body: 'Foo'
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+ end
+
+ describe "PUT /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes/:note_id" do
+ it 'returns modified note' do
+ put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "notes/#{note.id}", user), body: 'Hello!'
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response['body']).to eq('Hello!')
+ end
+
+ it 'returns a 404 error when note id not found' do
+ put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/12345", user),
+ body: 'Hello!'
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it 'returns a 400 bad request error if body not given' do
+ put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "notes/#{note.id}", user)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+ end
+
+ describe "DELETE /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes/:note_id" do
+ it 'deletes a note' do
+ delete api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "notes/#{note.id}", user)
+
+ expect(response).to have_gitlab_http_status(204)
+ # Check if note is really deleted
+ delete api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
+ "notes/#{note.id}", user)
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it 'returns a 404 error when note id not found' do
+ delete api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/12345", user)
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it_behaves_like '412 response' do
+ let(:request) { api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/#{note.id}", user) }
+ end
+ end
+end