notes_spec.rb 15.2 KB
Newer Older
1 2
require 'spec_helper'

3
describe API::Notes, api: true  do
4 5
  include ApiHelpers
  let(:user) { create(:user) }
6
  let!(:project) { create(:empty_project, :public, namespace: user.namespace) }
7
  let!(:issue) { create(:issue, project: project, author: user) }
8
  let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: user) }
Andrew8xx8's avatar
Andrew8xx8 committed
9
  let!(:snippet) { create(:project_snippet, project: project, author: user) }
10
  let!(:issue_note) { create(:note, noteable: issue, project: project, author: user) }
11
  let!(:merge_request_note) { create(:note, noteable: merge_request, project: project, author: user) }
12
  let!(:snippet_note) { create(:note, noteable: snippet, project: project, author: user) }
13 14 15

  # For testing the cross-reference of a private issue in a public issue
  let(:private_user)    { create(:user) }
16
  let(:private_project) do
17
    create(:empty_project, namespace: private_user.namespace).
18
    tap { |p| p.team << [private_user, :master] }
19 20 21
  end
  let(:private_issue)    { create(:issue, project: private_project) }

22
  let(:ext_proj)  { create(:empty_project, :public) }
23 24
  let(:ext_issue) { create(:issue, project: ext_proj) }

25
  let!(:cross_reference_note) do
26 27
    create :note,
    noteable: ext_issue, project: ext_proj,
28
    note: "mentioned in issue #{private_issue.to_reference(ext_proj)}",
29
    system: true
30
  end
31

Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
32
  before { project.team << [user, :reporter] }
33 34 35

  describe "GET /projects/:id/noteable/:noteable_id/notes" do
    context "when noteable is an Issue" do
36
      it "returns an array of issue notes" do
37
        get api("/projects/#{project.id}/issues/#{issue.id}/notes", user)
38

39
        expect(response).to have_http_status(200)
40
        expect(response).to include_pagination_headers
41 42
        expect(json_response).to be_an Array
        expect(json_response.first['body']).to eq(issue_note.note)
43
      end
44

45
      it "returns a 404 error when issue id not found" do
46
        get api("/projects/#{project.id}/issues/12345/notes", user)
47

48
        expect(response).to have_http_status(404)
49
      end
50

51
      context "and current user cannot view the notes" do
52
        it "returns an empty array" do
53
          get api("/projects/#{ext_proj.id}/issues/#{ext_issue.id}/notes", user)
54

55
          expect(response).to have_http_status(200)
56
          expect(response).to include_pagination_headers
57 58 59 60
          expect(json_response).to be_an Array
          expect(json_response).to be_empty
        end

61 62 63 64 65
        context "and issue is confidential" do
          before { ext_issue.update_attributes(confidential: true) }

          it "returns 404" do
            get api("/projects/#{ext_proj.id}/issues/#{ext_issue.id}/notes", user)
66

67
            expect(response).to have_http_status(404)
68 69 70
          end
        end

71
        context "and current user can view the note" do
72
          it "returns an empty array" do
73
            get api("/projects/#{ext_proj.id}/issues/#{ext_issue.id}/notes", private_user)
74

75
            expect(response).to have_http_status(200)
76
            expect(response).to include_pagination_headers
77 78 79 80 81
            expect(json_response).to be_an Array
            expect(json_response.first['body']).to eq(cross_reference_note.note)
          end
        end
      end
82 83 84
    end

    context "when noteable is a Snippet" do
85
      it "returns an array of snippet notes" do
86
        get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
87

88
        expect(response).to have_http_status(200)
89
        expect(response).to include_pagination_headers
90 91
        expect(json_response).to be_an Array
        expect(json_response.first['body']).to eq(snippet_note.note)
92
      end
93

94
      it "returns a 404 error when snippet id not found" do
95
        get api("/projects/#{project.id}/snippets/42/notes", user)
96

97
        expect(response).to have_http_status(404)
98
      end
99 100 101

      it "returns 404 when not authorized" do
        get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", private_user)
102

103
        expect(response).to have_http_status(404)
104
      end
105
    end
106 107

    context "when noteable is a Merge Request" do
108
      it "returns an array of merge_requests notes" do
109
        get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/notes", user)
110

111
        expect(response).to have_http_status(200)
112
        expect(response).to include_pagination_headers
113 114
        expect(json_response).to be_an Array
        expect(json_response.first['body']).to eq(merge_request_note.note)
115
      end
116

117
      it "returns a 404 error if merge request id not found" do
118
        get api("/projects/#{project.id}/merge_requests/4444/notes", user)
119

120
        expect(response).to have_http_status(404)
121
      end
122 123 124

      it "returns 404 when not authorized" do
        get api("/projects/#{project.id}/merge_requests/4444/notes", private_user)
125

126
        expect(response).to have_http_status(404)
127
      end
128
    end
129
  end
Nihad Abbasov's avatar
Nihad Abbasov committed
130 131 132

  describe "GET /projects/:id/noteable/:noteable_id/notes/:note_id" do
    context "when noteable is an Issue" do
133
      it "returns an issue note by id" do
Nihad Abbasov's avatar
Nihad Abbasov committed
134
        get api("/projects/#{project.id}/issues/#{issue.id}/notes/#{issue_note.id}", user)
135

136
        expect(response).to have_http_status(200)
137
        expect(json_response['body']).to eq(issue_note.note)
Nihad Abbasov's avatar
Nihad Abbasov committed
138
      end
139

140
      it "returns a 404 error if issue note not found" do
141
        get api("/projects/#{project.id}/issues/#{issue.id}/notes/12345", user)
142

143
        expect(response).to have_http_status(404)
144
      end
145

146
      context "and current user cannot view the note" do
147
        it "returns a 404 error" do
148
          get api("/projects/#{ext_proj.id}/issues/#{ext_issue.id}/notes/#{cross_reference_note.id}", user)
149

150
          expect(response).to have_http_status(404)
151 152
        end

153 154 155 156 157 158
        context "when issue is confidential" do
          before { issue.update_attributes(confidential: true) }

          it "returns 404" do
            get api("/projects/#{project.id}/issues/#{issue.id}/notes/#{issue_note.id}", private_user)

159
            expect(response).to have_http_status(404)
160 161 162
          end
        end

163
        context "and current user can view the note" do
164
          it "returns an issue note by id" do
165
            get api("/projects/#{ext_proj.id}/issues/#{ext_issue.id}/notes/#{cross_reference_note.id}", private_user)
166

167
            expect(response).to have_http_status(200)
168 169 170 171
            expect(json_response['body']).to eq(cross_reference_note.note)
          end
        end
      end
Nihad Abbasov's avatar
Nihad Abbasov committed
172 173 174
    end

    context "when noteable is a Snippet" do
175
      it "returns a snippet note by id" do
Nihad Abbasov's avatar
Nihad Abbasov committed
176
        get api("/projects/#{project.id}/snippets/#{snippet.id}/notes/#{snippet_note.id}", user)
177

178
        expect(response).to have_http_status(200)
179
        expect(json_response['body']).to eq(snippet_note.note)
Nihad Abbasov's avatar
Nihad Abbasov committed
180
      end
181

182
      it "returns a 404 error if snippet note not found" do
183
        get api("/projects/#{project.id}/snippets/#{snippet.id}/notes/12345", user)
184

185
        expect(response).to have_http_status(404)
186
      end
Nihad Abbasov's avatar
Nihad Abbasov committed
187 188
    end
  end
Nihad Abbasov's avatar
Nihad Abbasov committed
189 190 191

  describe "POST /projects/:id/noteable/:noteable_id/notes" do
    context "when noteable is an Issue" do
192
      it "creates a new issue note" do
Nihad Abbasov's avatar
Nihad Abbasov committed
193
        post api("/projects/#{project.id}/issues/#{issue.id}/notes", user), body: 'hi!'
194

195
        expect(response).to have_http_status(201)
196 197
        expect(json_response['body']).to eq('hi!')
        expect(json_response['author']['username']).to eq(user.username)
Nihad Abbasov's avatar
Nihad Abbasov committed
198
      end
199

200
      it "returns a 400 bad request error if body not given" do
201
        post api("/projects/#{project.id}/issues/#{issue.id}/notes", user)
202

203
        expect(response).to have_http_status(400)
204 205
      end

206
      it "returns a 401 unauthorized error if user not authenticated" do
207
        post api("/projects/#{project.id}/issues/#{issue.id}/notes"), body: 'hi!'
208

209
        expect(response).to have_http_status(401)
210
      end
211 212 213 214 215 216

      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.id}/notes", user),
            body: 'hi!', created_at: creation_time
217

218
          expect(response).to have_http_status(201)
219 220
          expect(json_response['body']).to eq('hi!')
          expect(json_response['author']['username']).to eq(user.username)
221
          expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time)
222 223
        end
      end
224

barthc's avatar
barthc committed
225 226 227
      context 'when the user is posting an award emoji on an issue created by someone else' do
        let(:issue2) { create(:issue, project: project) }

228
        it 'returns an award emoji' do
barthc's avatar
barthc committed
229 230 231 232 233 234 235 236 237
          post api("/projects/#{project.id}/issues/#{issue2.id}/notes", user), body: ':+1:'

          expect(response).to have_http_status(201)
          expect(json_response['awardable_id']).to eq issue2.id
        end
      end

      context 'when the user is posting an award emoji on his/her own issue' do
        it 'creates a new issue note' do
238 239 240
          post api("/projects/#{project.id}/issues/#{issue.id}/notes", user), body: ':+1:'

          expect(response).to have_http_status(201)
barthc's avatar
barthc committed
241
          expect(json_response['body']).to eq(':+1:')
242 243
        end
      end
Nihad Abbasov's avatar
Nihad Abbasov committed
244 245 246
    end

    context "when noteable is a Snippet" do
247
      it "creates a new snippet note" do
Nihad Abbasov's avatar
Nihad Abbasov committed
248
        post api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user), body: 'hi!'
249

250
        expect(response).to have_http_status(201)
251 252
        expect(json_response['body']).to eq('hi!')
        expect(json_response['author']['username']).to eq(user.username)
Nihad Abbasov's avatar
Nihad Abbasov committed
253
      end
254

255
      it "returns a 400 bad request error if body not given" do
256
        post api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
257

258
        expect(response).to have_http_status(400)
259 260
      end

261
      it "returns a 401 unauthorized error if user not authenticated" do
262
        post api("/projects/#{project.id}/snippets/#{snippet.id}/notes"), body: 'hi!'
263

264
        expect(response).to have_http_status(401)
265 266
      end
    end
267

268 269 270 271 272 273 274 275 276 277 278 279
    context 'when user does not have access to read the noteable' do
      it 'responds with 404' do
        project = create(:empty_project, :private) { |p| p.add_guest(user) }
        issue = create(:issue, :confidential, project: project)

        post api("/projects/#{project.id}/issues/#{issue.id}/notes", user),
          body: 'Foo'

        expect(response).to have_http_status(404)
      end
    end

280
    context 'when user does not have access to create noteable' do
281
      let(:private_issue) { create(:issue, project: create(:empty_project, :private)) }
282 283 284 285 286 287 288 289 290 291

      ##
      # 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/#{project.id}/issues/#{private_issue.id}/notes", user),
             body: 'Hi!'
      end

292 293
      it 'responds with resource not found error' do
        expect(response.status).to eq 404
294 295 296 297 298 299
      end

      it 'does not create new note' do
        expect(private_issue.notes.reload).to be_empty
      end
    end
Nihad Abbasov's avatar
Nihad Abbasov committed
300
  end
301 302

  describe "POST /projects/:id/noteable/:noteable_id/notes to test observer on create" do
303
    it "creates an activity event when an issue note is created" do
304
      expect(Event).to receive(:create)
305 306 307 308

      post api("/projects/#{project.id}/issues/#{issue.id}/notes", user), body: 'hi!'
    end
  end
309 310 311

  describe 'PUT /projects/:id/noteable/:noteable_id/notes/:note_id' do
    context 'when noteable is an Issue' do
312
      it 'returns modified note' do
313 314
        put api("/projects/#{project.id}/issues/#{issue.id}/"\
                  "notes/#{issue_note.id}", user), body: 'Hello!'
315

316
        expect(response).to have_http_status(200)
317
        expect(json_response['body']).to eq('Hello!')
318 319
      end

320
      it 'returns a 404 error when note id not found' do
321
        put api("/projects/#{project.id}/issues/#{issue.id}/notes/12345", user),
322
                body: 'Hello!'
323

324
        expect(response).to have_http_status(404)
325 326
      end

327
      it 'returns a 400 bad request error if body not given' do
328 329
        put api("/projects/#{project.id}/issues/#{issue.id}/"\
                  "notes/#{issue_note.id}", user)
330

331
        expect(response).to have_http_status(400)
332 333 334 335
      end
    end

    context 'when noteable is a Snippet' do
336
      it 'returns modified note' do
337 338
        put api("/projects/#{project.id}/snippets/#{snippet.id}/"\
                  "notes/#{snippet_note.id}", user), body: 'Hello!'
339

340
        expect(response).to have_http_status(200)
341
        expect(json_response['body']).to eq('Hello!')
342 343
      end

344
      it 'returns a 404 error when note id not found' do
345
        put api("/projects/#{project.id}/snippets/#{snippet.id}/"\
346
                  "notes/12345", user), body: "Hello!"
347

348
        expect(response).to have_http_status(404)
349 350 351 352
      end
    end

    context 'when noteable is a Merge Request' do
353
      it 'returns modified note' do
354 355
        put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/"\
                  "notes/#{merge_request_note.id}", user), body: 'Hello!'
356

357
        expect(response).to have_http_status(200)
358
        expect(json_response['body']).to eq('Hello!')
359 360
      end

361
      it 'returns a 404 error when note id not found' do
362
        put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/"\
363
                  "notes/12345", user), body: "Hello!"
364

365
        expect(response).to have_http_status(404)
366 367 368 369
      end
    end
  end

370
  describe 'DELETE /projects/:id/noteable/:noteable_id/notes/:note_id' do
Robert Schilling's avatar
Robert Schilling committed
371
    context 'when noteable is an Issue' do
372
      it 'deletes a note' do
Robert Schilling's avatar
Robert Schilling committed
373 374
        delete api("/projects/#{project.id}/issues/#{issue.id}/"\
                   "notes/#{issue_note.id}", user)
375

376
        expect(response).to have_http_status(204)
377 378 379
        # Check if note is really deleted
        delete api("/projects/#{project.id}/issues/#{issue.id}/"\
                   "notes/#{issue_note.id}", user)
380
        expect(response).to have_http_status(404)
Robert Schilling's avatar
Robert Schilling committed
381 382
      end

383
      it 'returns a 404 error when note id not found' do
384
        delete api("/projects/#{project.id}/issues/#{issue.id}/notes/12345", user)
385

386
        expect(response).to have_http_status(404)
Robert Schilling's avatar
Robert Schilling committed
387 388 389 390
      end
    end

    context 'when noteable is a Snippet' do
391
      it 'deletes a note' do
Robert Schilling's avatar
Robert Schilling committed
392 393
        delete api("/projects/#{project.id}/snippets/#{snippet.id}/"\
                   "notes/#{snippet_note.id}", user)
394

395
        expect(response).to have_http_status(204)
396 397 398
        # Check if note is really deleted
        delete api("/projects/#{project.id}/snippets/#{snippet.id}/"\
                   "notes/#{snippet_note.id}", user)
399
        expect(response).to have_http_status(404)
Robert Schilling's avatar
Robert Schilling committed
400 401
      end

402
      it 'returns a 404 error when note id not found' do
Robert Schilling's avatar
Robert Schilling committed
403
        delete api("/projects/#{project.id}/snippets/#{snippet.id}/"\
404
                   "notes/12345", user)
405

406
        expect(response).to have_http_status(404)
Robert Schilling's avatar
Robert Schilling committed
407 408 409 410
      end
    end

    context 'when noteable is a Merge Request' do
411
      it 'deletes a note' do
Robert Schilling's avatar
Robert Schilling committed
412 413
        delete api("/projects/#{project.id}/merge_requests/"\
                   "#{merge_request.id}/notes/#{merge_request_note.id}", user)
414

415
        expect(response).to have_http_status(204)
416 417 418
        # Check if note is really deleted
        delete api("/projects/#{project.id}/merge_requests/"\
                   "#{merge_request.id}/notes/#{merge_request_note.id}", user)
419
        expect(response).to have_http_status(404)
Robert Schilling's avatar
Robert Schilling committed
420 421
      end

422
      it 'returns a 404 error when note id not found' do
Robert Schilling's avatar
Robert Schilling committed
423
        delete api("/projects/#{project.id}/merge_requests/"\
424
                   "#{merge_request.id}/notes/12345", user)
425

426
        expect(response).to have_http_status(404)
Robert Schilling's avatar
Robert Schilling committed
427 428 429
      end
    end
  end
430
end