• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MarkUsProject / Markus / 13144117366

04 Feb 2025 08:19PM UTC coverage: 91.846% (-0.003%) from 91.849%
13144117366

Pull #7394

github

web-flow
Merge c55ca3427 into 49d866480
Pull Request #7394: HTML Preview of RMarkdown Submission Files

626 of 1364 branches covered (45.89%)

Branch coverage included in aggregate %.

97 of 103 new or added lines in 9 files covered. (94.17%)

1 existing line in 1 file now uncovered.

41344 of 44332 relevant lines covered (93.26%)

120.48 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.57
/spec/controllers/annotations_controller_spec.rb
1
describe AnnotationsController do
1✔
2
  # TODO: add 'role is from a different course' shared tests to each route test below
3
  let(:annotation_text_oto) { create(:annotation_text, annotation_category: nil) }
5✔
4
  let(:annotation_text) { create(:annotation_text, annotation_category: annotation_category) }
36✔
5
  let(:annotation_category) { create(:annotation_category, assignment: assignment) }
40✔
6
  let(:notebook_submission_file) { create(:notebook_submission_file, submission: submission) }
5✔
7
  let(:rmd_submission_file) { create(:rmd_submission_file, submission: submission) }
5✔
8
  let(:pdf_submission_file) { create(:pdf_submission_file, submission: submission) }
5✔
9
  let(:image_submission_file) { create(:image_submission_file, submission: submission) }
5✔
10
  let(:submission_file) { create(:submission_file, submission: submission) }
31✔
11
  let(:course) { assignment.course }
63✔
12
  let(:assignment) { submission.assignment }
53✔
13
  let(:submission) { result.submission }
53✔
14
  let(:result) { create(:result, marking_state: Result::MARKING_STATES[:incomplete]) }
53✔
15

16
  context 'An unauthenticated user' do
1✔
17
    let(:annotation) { create(:text_annotation, result: result) }
3✔
18

19
    it 'on :add_existing_annotation' do
1✔
20
      post :add_existing_annotation, params: { course_id: course.id, submission_file_id: 1 }
1✔
21
      expect(response).to have_http_status(:redirect)
1✔
22
    end
23

24
    it 'on :create' do
1✔
25
      post :create, params: { course_id: course.id, result_id: result.id }
1✔
26
      expect(response).to have_http_status(:redirect)
1✔
27
    end
28

29
    it 'on :destroy' do
1✔
30
      delete :destroy, params: { course_id: course.id, id: annotation.id }
1✔
31
      expect(response).to have_http_status(:redirect)
1✔
32
    end
33

34
    it 'on :update' do
1✔
35
      put :update, params: { course_id: course.id, id: annotation.id }
1✔
36
      expect(response).to have_http_status(:redirect)
1✔
37
    end
38
  end
39

40
  shared_examples 'an authenticated instructor or TA' do
1✔
41
    describe '#add_existing_annotation' do
2✔
42
      it 'successfully creates a text annotation' do
2✔
43
        post_as user,
2✔
44
                :add_existing_annotation,
45
                params: { annotation_text_id: annotation_text.id, submission_file_id: submission_file.id, line_start: 1,
46
                          line_end: 1, column_start: 1, column_end: 1, result_id: result.id, course_id: course.id },
47
                format: :js
48

49
        expect(response).to have_http_status(:success)
2✔
50
        expect(result.annotations.reload.size).to eq 1
2✔
51
      end
52

53
      it 'successfully creates an image annotation' do
2✔
54
        post_as user,
2✔
55
                :add_existing_annotation,
56
                params: { annotation_text_id: annotation_text.id, submission_file_id: image_submission_file.id,
57
                          x1: 0, x2: 1, y1: 0, y2: 1, result_id: result.id, course_id: course.id },
58
                format: :js
59

60
        expect(response).to have_http_status(:success)
2✔
61
        expect(result.annotations.reload.size).to eq 1
2✔
62
      end
63

64
      it 'successfully creates an html annotation for jupyter notebook file' do
2✔
65
        post_as user,
2✔
66
                :add_existing_annotation,
67
                params: { annotation_text_id: annotation_text.id, submission_file_id: notebook_submission_file.id,
68
                          start_node: 'a', start_offset: 1, end_node: 'b', end_offset: 0, result_id: result.id,
69
                          course_id: course.id },
70
                format: :js
71

72
        expect(response).to have_http_status(:success)
2✔
73
        expect(result.annotations.reload.size).to eq 1
2✔
74
      end
75

76
      context 'when rmd_convert_enabled is true', skip: !Rails.application.config.rmd_convert_enabled do
2✔
77
        it 'adds an html annotation to an RMarkdown submission file' do
2✔
78
          post_as user,
2✔
79
                  :add_existing_annotation,
80
                  params: { annotation_text_id: annotation_text.id, submission_file_id: rmd_submission_file.id,
81
                            start_node: 'a', start_offset: 1, end_node: 'b', end_offset: 0, result_id: result.id,
82
                            course_id: course.id },
83
                  format: :js
84

85
          expect(response).to have_http_status(:success)
2✔
86
          expect(result.annotations.reload.size).to eq 1
2✔
87
        end
88
      end
89

90
      context 'when rmd_convert_enabled is false', skip: Rails.application.config.rmd_convert_enabled do
2✔
91
        it 'adds a text annotation to an RMarkdown submission file' do
2✔
NEW
92
          post_as user,
×
93
                  :add_existing_annotation,
94
                  params: { annotation_text_id: annotation_text.id, submission_file_id: rmd_submission_file.id,
95
                            line_start: 1, line_end: 1, column_start: 1, column_end: 1, result_id: result.id,
96
                            course_id: course.id },
97
                  format: :js
98

NEW
99
          expect(response).to have_http_status(:success)
×
NEW
100
          expect(result.annotations.reload.size).to eq 1
×
101
        end
102
      end
103

104
      it 'successfully creates a PDF annotation' do
2✔
105
        post_as user,
2✔
106
                :add_existing_annotation,
107
                params: { annotation_text_id: annotation_text.id, submission_file_id: pdf_submission_file.id,
108
                          x1: 0, x2: 1, y1: 0, y2: 1, page: 1, result_id: result.id, course_id: course.id },
109
                format: :js
110

111
        expect(response).to have_http_status(:success)
2✔
112
        expect(result.annotations.reload.size).to eq 1
2✔
113
      end
114
    end
115

116
    describe '#create' do
2✔
117
      it 'successfully creates a text annotation' do
2✔
118
        post_as user,
2✔
119
                :create,
120
                params: { content: annotation_text.content, category_id: annotation_category.id,
121
                          submission_file_id: submission_file.id, line_start: 1, line_end: 1, column_start: 1,
122
                          column_end: 1, result_id: result.id, assignment_id: assignment.id, course_id: course.id },
123
                format: :js
124

125
        expect(response).to have_http_status(:success)
2✔
126
        expect(result.annotations.reload.size).to eq 1
2✔
127
      end
128

129
      it 'successfully uses an existing one-time-only text annotation' do
2✔
130
        post_as user,
2✔
131
                :create,
132
                params: { content: annotation_text_oto.content,
133
                          annotation_text_id: annotation_text_oto.id, category_id: nil,
134
                          submission_file_id: submission_file.id, line_start: 1, line_end: 1, column_start: 1,
135
                          column_end: 1, result_id: result.id, assignment_id: assignment.id, course_id: course.id },
136
                format: :js
137

138
        expect(response).to have_http_status(:success)
2✔
139
        expect(result.annotations.reload.size).to eq 1
2✔
140
        expect(AnnotationText.all.size).to eq 2
2✔
141

142
        post_as user,
2✔
143
                :create,
144
                params: { content: annotation_text_oto.content,
145
                          annotation_text_id: annotation_text_oto.id, category_id: nil,
146
                          submission_file_id: submission_file.id, line_start: 2, line_end: 2, column_start: 2,
147
                          column_end: 2, result_id: result.id, assignment_id: assignment.id, course_id: course.id },
148
                format: :js
149
        expect(response).to have_http_status(:success)
2✔
150
        expect(result.annotations.reload.size).to eq 2
2✔
151
        expect(AnnotationText.all.size).to eq 3
2✔
152
      end
153

154
      it 'successfully uses an existing text annotation from a category' do
2✔
155
        post_as user,
2✔
156
                :create,
157
                params: { content: annotation_text.content,
158
                          annotation_text_id: annotation_text.id, category_id: annotation_category.id,
159
                          submission_file_id: submission_file.id, line_start: 1, line_end: 1, column_start: 1,
160
                          column_end: 1, result_id: result.id, assignment_id: assignment.id, course_id: course.id },
161
                format: :js
162

163
        expect(response).to have_http_status(:success)
2✔
164
        expect(result.annotations.reload.size).to eq 1
2✔
165
        expect(AnnotationText.all.size).to eq 1
2✔
166

167
        post_as user,
2✔
168
                :create,
169
                params: { content: annotation_text.content,
170
                          annotation_text_id: annotation_text.id, category_id: annotation_category.id,
171
                          submission_file_id: submission_file.id, line_start: 2, line_end: 2, column_start: 2,
172
                          column_end: 2, result_id: result.id, assignment_id: assignment.id, course_id: course.id },
173
                format: :js
174
        expect(response).to have_http_status(:success)
2✔
175
        expect(result.annotations.reload.size).to eq 2
2✔
176
        expect(AnnotationText.all.size).to eq 1
2✔
177
      end
178

179
      it 'successfully uses an existing one-time only text annotation and adds it to a category' do
2✔
180
        post_as user,
2✔
181
                :create,
182
                params: { content: annotation_text_oto.content,
183
                          annotation_text_id: annotation_text_oto.id, category_id: annotation_category.id,
184
                          submission_file_id: submission_file.id, line_start: 1, line_end: 1, column_start: 1,
185
                          column_end: 1, result_id: result.id, assignment_id: assignment.id, course_id: course.id },
186
                format: :js
187

188
        expect(response).to have_http_status(:success)
2✔
189
        expect(result.annotations.reload.size).to eq 1
2✔
190
        expect(annotation_text_oto.reload.annotation_category_id).to eq annotation_category.id
2✔
191
      end
192

193
      it 'successfully uses an existing text annotation switches it to a different category' do
2✔
194
        new_category = create(:annotation_category, assignment: assignment)
2✔
195
        post_as user,
2✔
196
                :create,
197
                params: { content: annotation_text.content,
198
                          annotation_text_id: annotation_text.id, category_id: new_category.id,
199
                          submission_file_id: submission_file.id, line_start: 1, line_end: 1, column_start: 1,
200
                          column_end: 1, result_id: result.id, assignment_id: assignment.id, course_id: course.id },
201
                format: :js
202

203
        expect(response).to have_http_status(:success)
2✔
204
        expect(result.annotations.reload.size).to eq 1
2✔
205
        expect(annotation_text.reload.annotation_category_id).to eq new_category.id
2✔
206
      end
207

208
      it 'successfully uses an existing text annotation to create a new one-time only annotation' do
2✔
209
        post_as user,
2✔
210
                :create,
211
                params: { content: annotation_text.content,
212
                          annotation_text_id: annotation_text.id, category_id: nil,
213
                          submission_file_id: submission_file.id, line_start: 1, line_end: 1, column_start: 1,
214
                          column_end: 1, result_id: result.id, assignment_id: assignment.id, course_id: course.id },
215
                format: :js
216

217
        expect(response).to have_http_status(:success)
2✔
218
        expect(result.annotations.reload.size).to eq 1
2✔
219
        expect(result.annotations.first.annotation_text.annotation_category_id).to be_nil
2✔
220

221
        # Existing annotation text wasn't changed
222
        expect(annotation_text.reload.annotation_category_id).to eq annotation_category.id
2✔
223
      end
224

225
      it 'successfully creates an image annotation' do
2✔
226
        post_as user,
2✔
227
                :create,
228
                params: { content: annotation_text.content, category_id: annotation_category.id,
229
                          submission_file_id: image_submission_file.id, x1: 0, x2: 1, y1: 0, y2: 1,
230
                          result_id: result.id, assignment_id: assignment.id, course_id: course.id },
231
                format: :js
232

233
        expect(response).to have_http_status(:ok)
2✔
234
        expect(result.annotations.reload.size).to eq 1
2✔
235
      end
236

237
      it 'successfully creates a PDF annotation' do
2✔
238
        post_as user,
2✔
239
                :create,
240
                params: { content: annotation_text.content, category_id: annotation_category.id,
241
                          submission_file_id: pdf_submission_file.id, x1: 0, x2: 1, y1: 0, y2: 1, page: 1,
242
                          result_id: result.id, assignment_id: assignment.id, course_id: course.id },
243
                format: :js
244

245
        expect(response).to have_http_status(:ok)
2✔
246
        expect(result.annotations.reload.size).to eq 1
2✔
247
      end
248

249
      it 'successfully creates an html annotation for a jupyter notebook file' do
2✔
250
        post_as user,
2✔
251
                :create,
252
                params: { content: annotation_text.content, category_id: annotation_category.id,
253
                          submission_file_id: notebook_submission_file.id, start_node: 'a', start_offset: 1,
254
                          end_node: 'b', end_offset: 0, result_id: result.id, assignment_id: assignment.id,
255
                          course_id: course.id },
256
                format: :js
257

258
        expect(response).to have_http_status(:success)
2✔
259
        expect(result.annotations.reload.size).to eq 1
2✔
260
      end
261

262
      context 'when rmd_convert_enabled is true', skip: !Rails.application.config.rmd_convert_enabled do
2✔
263
        it 'adds an html annotation to an RMarkdown submission file' do
2✔
264
          post_as user,
2✔
265
                  :add_existing_annotation,
266
                  params: { annotation_text_id: annotation_text.id, submission_file_id: rmd_submission_file.id,
267
                            start_node: 'a', start_offset: 1, end_node: 'b', end_offset: 0, result_id: result.id,
268
                            course_id: course.id },
269
                  format: :js
270

271
          expect(response).to have_http_status(:success)
2✔
272
          expect(result.annotations.reload.size).to eq 1
2✔
273
        end
274
      end
275

276
      context 'when rmd_convert_enabled is false', skip: Rails.application.config.rmd_convert_enabled do
2✔
277
        it 'adds a text annotation to an RMarkdown submission file' do
2✔
NEW
278
          post_as user,
×
279
                  :add_existing_annotation,
280
                  params: { annotation_text_id: annotation_text.id, submission_file_id: rmd_submission_file.id,
281
                            line_start: 1, line_end: 1, column_start: 1, column_end: 1, result_id: result.id,
282
                            course_id: course.id },
283
                  format: :js
284

NEW
285
          expect(response).to have_http_status(:success)
×
NEW
286
          expect(result.annotations.reload.size).to eq 1
×
287
        end
288
      end
289

290
      it 'successfully creates an annotation where the deduction is not specified but a category with criterion is' do
2✔
291
        assignment = create(:assignment_with_deductive_annotations)
2✔
292
        category = assignment.annotation_categories.where.not(flexible_criterion_id: nil).first
2✔
293
        result = assignment.groupings.first.current_result
2✔
294
        submission_file = create(:submission_file, submission: result.submission)
2✔
295
        post_as user,
2✔
296
                :create,
297
                params: { content: 'I like icecream!', category_id: category.id,
298
                          submission_file_id: submission_file.id, line_start: 1, line_end: 1, column_start: 1,
299
                          column_end: 1, result_id: result.id, assignment_id: assignment.id, course_id: course.id },
300
                format: :js
301

302
        expect(response).to have_http_status(:success)
2✔
303
        expect(result.annotations.reload.size).to eq 2
2✔
304
        expect(result.annotations.joins(:annotation_text).where('annotation_texts.deduction': 0).size).to eq 1
2✔
305
      end
306
    end
307

308
    describe '#destroy' do
2✔
309
      it 'destroys the annotation when there is only one annotation for the result' do
2✔
310
        anno = create(
2✔
311
          :text_annotation,
312
          annotation_text: annotation_text,
313
          submission_file: submission_file,
314
          creator: user,
315
          result: result
316
        )
317
        delete_as user,
2✔
318
                  :destroy,
319
                  params: { id: anno.id, submission_file_id: submission_file.id, assignment_id: assignment.id,
320
                            result_id: result.id, course_id: course.id },
321
                  format: :js
322

323
        expect(response).to have_http_status(:success)
2✔
324
        expect(result.annotations.reload.size).to eq 0
2✔
325
      end
326

327
      it 'destroys an annotation when there are multiple annotations for the result' do
2✔
328
        annotations = []
2✔
329
        3.times do |_|
2✔
330
          annotations << create(
6✔
331
            :text_annotation,
332
            annotation_text: annotation_text,
333
            submission_file: submission_file,
334
            creator: user,
335
            result: result
336
          )
337
        end
338

339
        delete_as user,
2✔
340
                  :destroy,
341
                  params: { id: annotations[1].id, submission_file_id: submission_file.id, assignment_id: assignment.id,
342
                            result_id: result.id, course_id: course.id },
343
                  format: :js
344

345
        expect(response).to have_http_status(:success)
2✔
346

347
        # Check that there are only two annotations remaining.
348
        expect(result.annotations.reload.size).to eq 2
2✔
349

350
        # Check that the annotations were renumbered.
351
        expect(result.annotations.pluck(:annotation_number).sort).to eq [1, 2]
2✔
352
      end
353

354
      it 'does not destroy the associated annotation text if the text belongs to an annotation category' do
2✔
355
        anno = create(
2✔
356
          :text_annotation,
357
          annotation_text: annotation_text,
358
          submission_file: submission_file,
359
          creator: user,
360
          result: result
361
        )
362
        delete_as user,
2✔
363
                  :destroy,
364
                  params: { id: anno.id, submission_file_id: submission_file.id, assignment_id: assignment.id,
365
                            result_id: result.id, course_id: course.id },
366
                  format: :js
367

368
        expect(AnnotationText.exists?(annotation_text.id)).to be true
2✔
369
      end
370

371
      it 'destroys the associated annotation text if the text is one time only' do
2✔
372
        new_text = create(:annotation_text, annotation_category: nil)
2✔
373
        anno = create(
2✔
374
          :text_annotation,
375
          annotation_text: new_text,
376
          submission_file: submission_file,
377
          creator: user,
378
          result: result
379
        )
380
        delete_as user,
2✔
381
                  :destroy,
382
                  params: { id: anno.id, submission_file_id: submission_file.id, assignment_id: assignment.id,
383
                            result_id: result.id, course_id: course.id },
384
                  format: :js
385

386
        expect(AnnotationText.exists?(new_text.id)).to be false
2✔
387
      end
388
    end
389

390
    describe '#update' do
2✔
391
      it 'successfully updates annotation text' do
2✔
392
        anno = create(
2✔
393
          :text_annotation,
394
          submission_file: submission_file,
395
          creator: user,
396
          result: result
397
        )
398
        put_as user,
2✔
399
               :update,
400
               params: { id: anno.id, assignment_id: assignment.id, submission_file_id: submission_file.id,
401
                         result_id: result.id, content: 'new content', course_id: course.id },
402
               format: :js
403
        expect(response).to have_http_status(:success)
2✔
404
        expect(anno.annotation_text.reload.content).to eq 'new content'
2✔
405
      end
406

407
      it 'successfully updates a singular annotation text' do
2✔
408
        anno_text = create(:annotation_text, annotation_category: annotation_category)
2✔
409
        anno1 = create(
2✔
410
          :text_annotation,
411
          annotation_text: anno_text,
412
          submission_file: submission_file,
413
          creator: user,
414
          result: result
415
        )
416
        anno2 = create(
2✔
417
          :text_annotation,
418
          annotation_text: anno_text,
419
          submission_file: submission_file,
420
          creator: user,
421
          result: result
422
        )
423
        put_as user,
2✔
424
               :update,
425
               params: { id: anno1.id, assignment_id: assignment.id, submission_file_id: submission_file.id,
426
                         result_id: result.id, content: 'new content', annotation_text: { change_all: '0' },
427
                         course_id: course.id },
428
               format: :js
429
        expect(response).to have_http_status(:success)
2✔
430
        expect(anno1.reload.annotation_text.reload.content).to eq 'new content'
2✔
431
        expect(anno2.reload.annotation_text.reload.content).not_to eq 'new content'
2✔
432
      end
433
    end
434
  end
435

436
  describe 'an authenticated instructor' do
1✔
437
    let!(:user) { create(:instructor) }
27✔
438

439
    include_examples 'an authenticated instructor or TA'
1✔
440

441
    describe 'accessing annotations for results in an assignment with deductive annotations' do
1✔
442
      let(:assignment) { create(:assignment_with_deductive_annotations) }
5✔
443
      let(:result) { assignment.groupings.first.current_result }
5✔
444
      let(:annotation) { result.annotations.first }
5✔
445

446
      it 'can update a deductive annotation\'s content' do
1✔
447
        post_as user,
1✔
448
                :update,
449
                params: { content: 'New content!',
450
                          id: annotation.id,
451
                          result_id: result.id,
452
                          course_id: course.id,
453
                          assignment_id: assignment.id },
454
                format: :js
455
        expect(annotation.reload.annotation_text.content).to eq 'New content!'
1✔
456
      end
457

458
      it 'cannot update deductive annotation content if that content has been applied to released results' do
1✔
459
        assignment.groupings.first.current_result.update(released_to_students: true)
1✔
460
        other_grouping = assignment.reload.groupings.joins(submissions: :results)
1✔
461
                                   .where(results: { released_to_students: false }).first
462
        post_as user,
1✔
463
                :update,
464
                params: { content: 'New content!',
465
                          id: annotation.id,
466
                          course_id: course.id,
467
                          result_id: other_grouping.current_result.id,
468
                          assignment_id: assignment.id },
469
                format: :js
470
        expect(response).to have_http_status(:bad_request)
1✔
471
        expect(annotation.reload.annotation_text.content).not_to eq 'New content!'
1✔
472
      end
473

474
      it 'can destroy a deductive annotation' do
1✔
475
        post_as user,
1✔
476
                :destroy,
477
                params: { id: annotation.id,
478
                          result_id: result.id,
479
                          course_id: course.id,
480
                          assignment_id: assignment.id },
481
                format: :js
482
        expect(result.reload.annotations.size).to eq 0
1✔
483
      end
484

485
      it 'can destroy a deductive annotation when criteria assigned to graders' do
1✔
486
        assignment.assignment_properties.update(assign_graders_to_criteria: true)
1✔
487
        post_as user,
1✔
488
                :destroy,
489
                params: { id: annotation.id,
490
                          result_id: result.id,
491
                          course_id: course.id,
492
                          assignment_id: assignment.id },
493
                format: :js
494
        expect(result.reload.annotations.size).to eq 0
1✔
495
      end
496
    end
497
  end
498

499
  describe 'an authenticated TA' do
1✔
500
    let!(:user) { create(:ta) }
29✔
501

502
    include_examples 'an authenticated instructor or TA'
1✔
503

504
    describe 'accessing annotations for results in an assignment with deductive annotations' do
1✔
505
      let(:assignment) { create(:assignment_with_deductive_annotations) }
7✔
506
      let(:result) { assignment.groupings.first.current_result }
7✔
507
      let(:annotation) { result.annotations.first }
7✔
508

509
      it 'cannot update a deductive annotation' do
1✔
510
        post_as user,
1✔
511
                :update,
512
                params: { content: 'New content!',
513
                          id: annotation.id,
514
                          result_id: result.id,
515
                          course_id: course.id,
516
                          assignment_id: assignment.id },
517
                format: :js
518
        expect(response).to have_http_status(:bad_request)
1✔
519
        expect(annotation.reload.annotation_text.content).not_to eq 'New content!'
1✔
520
      end
521

522
      it 'cannot update a deductive annotation even if assigned to its criterion' do
1✔
523
        assignment.assignment_properties.update(assign_graders_to_criteria: true)
1✔
524
        create(:criterion_ta_association,
1✔
525
               criterion: annotation.annotation_text.annotation_category.flexible_criterion,
526
               ta: user)
527
        post_as user,
1✔
528
                :update,
529
                params: { content: 'New content!',
530
                          id: annotation.id,
531
                          result_id: result.id,
532
                          course_id: course.id,
533
                          assignment_id: assignment.id },
534
                format: :js
535
        expect(response).to have_http_status(:bad_request)
1✔
536
        expect(annotation.reload.annotation_text.content).not_to eq 'New content!'
1✔
537
      end
538

539
      it 'cannot destroy a deductive annotation if unassigned to the annotation\'s criterion' do
1✔
540
        other_criterion = create(:rubric_criterion, assignment: assignment)
1✔
541
        assignment.assignment_properties.update(assign_graders_to_criteria: true)
1✔
542
        create(:criterion_ta_association, criterion: other_criterion, ta: user)
1✔
543
        post_as user,
1✔
544
                :destroy,
545
                params: { id: annotation.id,
546
                          result_id: result.id,
547
                          course_id: course.id,
548
                          assignment_id: assignment.id },
549
                format: :js
550
        expect(response).to have_http_status(:bad_request)
1✔
551
        expect(result.reload.annotations.size).to eq 1
1✔
552
      end
553

554
      it 'can destroy a deductive annotation if assigned to the annotation\'s criterion' do
1✔
555
        assignment.assignment_properties.update(assign_graders_to_criteria: true)
1✔
556
        create(:criterion_ta_association, criterion: assignment.criteria
1✔
557
                                                       .where(type: 'FlexibleCriterion').first, ta: user)
558
        post_as user,
1✔
559
                :destroy,
560
                params: { id: annotation.id,
561
                          result_id: result.id,
562
                          course_id: course.id,
563
                          assignment_id: assignment.id },
564
                format: :js
565
        expect(result.reload.annotations.size).to eq 0
1✔
566
      end
567

568
      it 'cannot destroy a deductive annotation if unassigned to any criteria when assignment does assign criteria' do
1✔
569
        assignment.assignment_properties.update(assign_graders_to_criteria: true)
1✔
570
        post_as user,
1✔
571
                :destroy,
572
                params: { id: annotation.id,
573
                          result_id: result.id,
574
                          course_id: course.id,
575
                          assignment_id: assignment.id },
576
                format: :js
577
        expect(response).to have_http_status(:bad_request)
1✔
578
        expect(result.reload.annotations.size).to eq 1
1✔
579
      end
580

581
      it 'can destroy a deductive annotation when assignment does not assign criteria' do
1✔
582
        post_as user,
1✔
583
                :destroy,
584
                params: { id: annotation.id,
585
                          result_id: result.id,
586
                          course_id: course.id,
587
                          assignment_id: assignment.id },
588
                format: :js
589
        expect(result.reload.annotations.size).to eq 0
1✔
590
      end
591
    end
592
  end
593

594
  context 'An authenticated and authorized Student doing a POST' do
1✔
595
    let(:user) { create(:student) }
5✔
596

597
    describe '#add_existing_annotation' do
1✔
598
      it 'returns a :not_found status code' do
1✔
599
        post_as user,
1✔
600
                :add_existing_annotation,
601
                params: { annotation_text_id: annotation_text.id, submission_file_id: submission_file.id, line_start: 1,
602
                          line_end: 1, column_start: 1, column_end: 1, result_id: result.id, course_id: course.id },
603
                format: :js
604

605
        expect(subject).to respond_with(:forbidden)
1✔
606
        expect(result.annotations.reload.size).to eq 0
1✔
607
      end
608
    end
609

610
    describe '#create' do
1✔
611
      it 'returns a :not_found status code' do
1✔
612
        post_as user,
1✔
613
                :create,
614
                params: { content: annotation_text.content, category_id: annotation_category.id,
615
                          submission_file_id: submission_file.id, line_start: 1, line_end: 1, column_start: 1,
616
                          column_end: 1, result_id: result.id, assignment_id: assignment.id, course_id: course.id },
617
                format: :js
618

619
        expect(subject).to respond_with(:forbidden)
1✔
620
        expect(result.annotations.reload.size).to eq 0
1✔
621
      end
622
    end
623

624
    describe '#destroy' do
1✔
625
      it 'returns a :not_found status code' do
1✔
626
        anno = create(
1✔
627
          :text_annotation,
628
          annotation_text: annotation_text,
629
          submission_file: submission_file,
630
          result: result
631
        )
632
        delete_as user,
1✔
633
                  :destroy,
634
                  params: { id: anno.id, submission_file_id: submission_file.id, assignment_id: assignment.id,
635
                            result_id: result.id, course_id: course.id },
636
                  format: :js
637

638
        expect(subject).to respond_with(:forbidden)
1✔
639
        expect(result.annotations.reload.size).to eq 1
1✔
640
      end
641
    end
642

643
    describe '#update' do
1✔
644
      it 'returns a :not_found status code' do
1✔
645
        anno = create(
1✔
646
          :text_annotation,
647
          submission_file: submission_file,
648
          creator: user,
649
          result: result
650
        )
651
        put_as user,
1✔
652
               :update,
653
               params: { id: anno.id, assignment_id: assignment.id, submission_file_id: submission_file.id,
654
                         result_id: result.id, content: 'new content', course_id: course.id },
655
               format: :js
656
        expect(subject).to respond_with(:forbidden)
1✔
657
        expect(anno.annotation_text.reload.content).not_to eq 'new content'
1✔
658
      end
659
    end
660
  end
661
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc