issues_spec.rb 13.3 KB
Newer Older
gitlabhq's avatar
gitlabhq committed
1
2
require 'spec_helper'

Jeroen van Baarsen's avatar
Jeroen van Baarsen committed
3
describe 'Issues', feature: true do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
4
5
  include SortingHelper

6
  let(:project) { create(:project) }
gitlabhq's avatar
gitlabhq committed
7

Nihad Abbasov's avatar
Nihad Abbasov committed
8
  before do
gitlabhq's avatar
gitlabhq committed
9
    login_as :user
Riyad Preukschas's avatar
Riyad Preukschas committed
10
    user2 = create(:user)
gitlabhq's avatar
fixes    
gitlabhq committed
11

12
    project.team << [[@user, user2], :developer]
gitlabhq's avatar
gitlabhq committed
13
14
  end

Jeroen van Baarsen's avatar
Jeroen van Baarsen committed
15
  describe 'Edit issue' do
Riyad Preukschas's avatar
Riyad Preukschas committed
16
17
18
19
20
21
22
    let!(:issue) do
      create(:issue,
             author: @user,
             assignee: @user,
             project: project)
    end

Nihad Abbasov's avatar
Nihad Abbasov committed
23
    before do
24
      visit edit_namespace_project_issue_path(project.namespace, project, issue)
Phil Hughes's avatar
Phil Hughes committed
25
      click_button "Go full screen"
gitlabhq's avatar
gitlabhq committed
26
27
    end

Jeroen van Baarsen's avatar
Jeroen van Baarsen committed
28
    it 'should open new issue popup' do
29
      expect(page).to have_content("Issue ##{issue.iid}")
gitlabhq's avatar
gitlabhq committed
30
31
    end

Jeroen van Baarsen's avatar
Jeroen van Baarsen committed
32
    describe 'fill in' do
gitlabhq's avatar
gitlabhq committed
33
      before do
Jeroen van Baarsen's avatar
Jeroen van Baarsen committed
34
35
        fill_in 'issue_title', with: 'bug 345'
        fill_in 'issue_description', with: 'bug description'
gitlabhq's avatar
gitlabhq committed
36
37
      end
    end
38
39
  end

Jeroen van Baarsen's avatar
Jeroen van Baarsen committed
40
  describe 'Editing issue assignee' do
41
42
43
44
45
46
47
    let!(:issue) do
      create(:issue,
             author: @user,
             assignee: @user,
             project: project)
    end

48
    it 'allows user to select unassigned', js: true do
Vinnie Okada's avatar
Vinnie Okada committed
49
      visit edit_namespace_project_issue_path(project.namespace, project, issue)
50

51
      expect(page).to have_content "Assignee #{@user.name}"
52

53
      first('#s2id_issue_assignee_id').click
54
      sleep 2 # wait for ajax stuff to complete
55
      first('.user-result').click
56

Jeroen van Baarsen's avatar
Jeroen van Baarsen committed
57
      click_button 'Save changes'
58

59
      page.within('.assignee') do
Jacob Schatz's avatar
Jacob Schatz committed
60
        expect(page).to have_content 'No assignee - assign yourself'
61
62
      end

63
      expect(issue.reload.assignee).to be_nil
64
    end
gitlabhq's avatar
gitlabhq committed
65
  end
Adam Leonard's avatar
Adam Leonard committed
66

67
68
69
70
71
72
73
74
75
76
77
78
  describe 'Issue info' do
    it 'excludes award_emoji from comment count' do
      issue = create(:issue, author: @user, assignee: @user, project: project, title: 'foobar')
      create(:upvote_note, noteable: issue)

      visit namespace_project_issues_path(project.namespace, project, assignee_id: @user.id)

      expect(page).to have_content 'foobar'
      expect(page.all('.issue-no-comments').first.text).to eq "0"
    end
  end

Jeroen van Baarsen's avatar
Jeroen van Baarsen committed
79
  describe 'Filter issue' do
80
81
    before do
      ['foobar', 'barbaz', 'gitlab'].each do |title|
Riyad Preukschas's avatar
Riyad Preukschas committed
82
83
84
85
86
        create(:issue,
               author: @user,
               assignee: @user,
               project: project,
               title: title)
87
88
      end

Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
89
      @issue = Issue.find_by(title: 'foobar')
90
91
92
      @issue.milestone = create(:milestone, project: project)
      @issue.assignee = nil
      @issue.save
93
94
    end

95
    let(:issue) { @issue }
Riyad Preukschas's avatar
Riyad Preukschas committed
96

Jeroen van Baarsen's avatar
Jeroen van Baarsen committed
97
    it 'should allow filtering by issues with no specified assignee' do
98
      visit namespace_project_issues_path(project.namespace, project, assignee_id: IssuableFinder::NONE)
99

100
101
102
      expect(page).to have_content 'foobar'
      expect(page).not_to have_content 'barbaz'
      expect(page).not_to have_content 'gitlab'
103
104
    end

Jeroen van Baarsen's avatar
Jeroen van Baarsen committed
105
    it 'should allow filtering by a specified assignee' do
Vinnie Okada's avatar
Vinnie Okada committed
106
      visit namespace_project_issues_path(project.namespace, project, assignee_id: @user.id)
107

108
109
110
      expect(page).not_to have_content 'foobar'
      expect(page).to have_content 'barbaz'
      expect(page).to have_content 'gitlab'
111
    end
112
  end
113
114

  describe 'filter issue' do
Rémy Coutable's avatar
Rémy Coutable committed
115
    titles = %w[foo bar baz]
116
    titles.each_with_index do |title, index|
Jeroen van Baarsen's avatar
Jeroen van Baarsen committed
117
118
119
120
121
      let!(title.to_sym) do
        create(:issue, title: title,
                       project: project,
                       created_at: Time.now - (index * 60))
      end
122
    end
123
124
    let(:newer_due_milestone) { create(:milestone, due_date: '2013-12-11') }
    let(:later_due_milestone) { create(:milestone, due_date: '2013-12-12') }
125
126

    it 'sorts by newest' do
Vinnie Okada's avatar
Vinnie Okada committed
127
      visit namespace_project_issues_path(project.namespace, project, sort: sort_value_recently_created)
128

129
130
      expect(first_issue).to include('baz')
      expect(last_issue).to include('foo')
131
132
133
    end

    it 'sorts by oldest' do
Vinnie Okada's avatar
Vinnie Okada committed
134
      visit namespace_project_issues_path(project.namespace, project, sort: sort_value_oldest_created)
135

136
137
      expect(first_issue).to include('foo')
      expect(last_issue).to include('baz')
138
139
140
141
142
    end

    it 'sorts by most recently updated' do
      baz.updated_at = Time.now + 100
      baz.save
Vinnie Okada's avatar
Vinnie Okada committed
143
      visit namespace_project_issues_path(project.namespace, project, sort: sort_value_recently_updated)
144

Jeroen van Baarsen's avatar
Jeroen van Baarsen committed
145
      expect(first_issue).to include('baz')
146
147
148
149
150
    end

    it 'sorts by least recently updated' do
      baz.updated_at = Time.now - 100
      baz.save
Vinnie Okada's avatar
Vinnie Okada committed
151
      visit namespace_project_issues_path(project.namespace, project, sort: sort_value_oldest_updated)
152

Jeroen van Baarsen's avatar
Jeroen van Baarsen committed
153
      expect(first_issue).to include('baz')
154
155
    end

156
    describe 'sorting by due date' do
157
      before do
Rémy Coutable's avatar
Rémy Coutable committed
158
159
        foo.update(due_date: 1.day.from_now)
        bar.update(due_date: 6.days.from_now)
160
161
162
163
      end

      it 'sorts by recently due date' do
        visit namespace_project_issues_path(project.namespace, project, sort: sort_value_due_date_soon)
Rémy Coutable's avatar
Rémy Coutable committed
164

165
166
167
168
169
        expect(first_issue).to include('foo')
      end

      it 'sorts by least recently due date' do
        visit namespace_project_issues_path(project.namespace, project, sort: sort_value_due_date_later)
Rémy Coutable's avatar
Rémy Coutable committed
170

171
172
173
174
175
        expect(first_issue).to include('bar')
      end

      it 'sorts by least recently due date by excluding nil due dates' do
        bar.update(due_date: nil)
Rémy Coutable's avatar
Rémy Coutable committed
176

177
        visit namespace_project_issues_path(project.namespace, project, sort: sort_value_due_date_later)
Rémy Coutable's avatar
Rémy Coutable committed
178

179
180
        expect(first_issue).to include('foo')
      end
181
182
183
184
185
186
187
188
189
190
191
192
193

      context 'with a filter on labels' do
        let(:label) { create(:label, project: project) }
        before { create(:label_link, label: label, target: foo) }

        it 'sorts by least recently due date by excluding nil due dates' do
          bar.update(due_date: nil)

          visit namespace_project_issues_path(project.namespace, project, label_names: [label.name], sort: sort_value_due_date_later)

          expect(first_issue).to include('foo')
        end
      end
194
195
196
    end

    describe 'filtering by due date' do
Rémy Coutable's avatar
Rémy Coutable committed
197
198
199
      before do
        foo.update(due_date: 1.day.from_now)
        bar.update(due_date: 6.days.from_now)
200
201
202
      end

      it 'filters by none' do
203
        visit namespace_project_issues_path(project.namespace, project, due_date: Issue::NoDueDate.name)
Rémy Coutable's avatar
Rémy Coutable committed
204
205
206
207

        expect(page).not_to have_content('foo')
        expect(page).not_to have_content('bar')
        expect(page).to have_content('baz')
208
209
210
      end

      it 'filters by any' do
211
        visit namespace_project_issues_path(project.namespace, project, due_date: Issue::AnyDueDate.name)
Rémy Coutable's avatar
Rémy Coutable committed
212
213
214
215

        expect(page).to have_content('foo')
        expect(page).to have_content('bar')
        expect(page).to have_content('baz')
216
217
      end

218
219
220
221
      it 'filters by due this week' do
        foo.update(due_date: Date.today.beginning_of_week + 2.days)
        bar.update(due_date: Date.today.end_of_week)
        baz.update(due_date: Date.today - 8.days)
Rémy Coutable's avatar
Rémy Coutable committed
222

223
        visit namespace_project_issues_path(project.namespace, project, due_date: Issue::DueThisWeek.name)
Rémy Coutable's avatar
Rémy Coutable committed
224
225
226
227

        expect(page).to have_content('foo')
        expect(page).to have_content('bar')
        expect(page).not_to have_content('baz')
228
229
      end

230
231
232
233
      it 'filters by due this month' do
        foo.update(due_date: Date.today.beginning_of_month + 2.days)
        bar.update(due_date: Date.today.end_of_month)
        baz.update(due_date: Date.today - 50.days)
Rémy Coutable's avatar
Rémy Coutable committed
234

235
        visit namespace_project_issues_path(project.namespace, project, due_date: Issue::DueThisMonth.name)
Rémy Coutable's avatar
Rémy Coutable committed
236
237
238
239

        expect(page).to have_content('foo')
        expect(page).to have_content('bar')
        expect(page).not_to have_content('baz')
240
241
      end

242
243
244
245
246
      it 'filters by overdue' do
        foo.update(due_date: Date.today + 2.days)
        bar.update(due_date: Date.today + 20.days)
        baz.update(due_date: Date.yesterday)

Rémy Coutable's avatar
Rémy Coutable committed
247
248
249
250
251
252
        visit namespace_project_issues_path(project.namespace, project, due_date: Issue::Overdue.name)

        expect(page).not_to have_content('foo')
        expect(page).not_to have_content('bar')
        expect(page).to have_content('baz')
      end
253
254
    end

255
    describe 'sorting by milestone' do
Rémy Coutable's avatar
Rémy Coutable committed
256
      before do
257
258
259
260
261
262
263
        foo.milestone = newer_due_milestone
        foo.save
        bar.milestone = later_due_milestone
        bar.save
      end

      it 'sorts by recently due milestone' do
Vinnie Okada's avatar
Vinnie Okada committed
264
        visit namespace_project_issues_path(project.namespace, project, sort: sort_value_milestone_soon)
265

Jeroen van Baarsen's avatar
Jeroen van Baarsen committed
266
        expect(first_issue).to include('foo')
267
        expect(last_issue).to include('baz')
268
269
270
      end

      it 'sorts by least recently due milestone' do
Vinnie Okada's avatar
Vinnie Okada committed
271
        visit namespace_project_issues_path(project.namespace, project, sort: sort_value_milestone_later)
272

Jeroen van Baarsen's avatar
Jeroen van Baarsen committed
273
        expect(first_issue).to include('bar')
274
        expect(last_issue).to include('baz')
275
276
277
278
279
280
      end
    end

    describe 'combine filter and sort' do
      let(:user2) { create(:user) }

Rémy Coutable's avatar
Rémy Coutable committed
281
      before do
282
283
284
285
286
287
288
        foo.assignee = user2
        foo.save
        bar.assignee = user2
        bar.save
      end

      it 'sorts with a filter applied' do
Vinnie Okada's avatar
Vinnie Okada committed
289
290
291
        visit namespace_project_issues_path(project.namespace, project,
                                            sort: sort_value_oldest_created,
                                            assignee_id: user2.id)
292

293
294
        expect(first_issue).to include('foo')
        expect(last_issue).to include('bar')
295
        expect(page).not_to have_content 'baz'
296
297
298
      end
    end
  end
299

300
  describe 'update assignee from issue#show' do
Jacob Schatz's avatar
Jacob Schatz committed
301
    let(:issue) { create(:issue, project: project, author: @user, assignee: @user) }
302

303
    context 'by authorized user' do
304

Jacob Schatz's avatar
Jacob Schatz committed
305
      it 'allows user to select unassigned', js: true do
Vinnie Okada's avatar
Vinnie Okada committed
306
        visit namespace_project_issue_path(project.namespace, project, issue)
307

Jacob Schatz's avatar
Jacob Schatz committed
308
309
310
311
312
313
314
315
316
317
318
        page.within('.assignee') do
          expect(page).to have_content "#{@user.name}"
        end

        find('.block.assignee .edit-link').click
        sleep 2 # wait for ajax stuff to complete
        first('.dropdown-menu-user-link').click
        sleep 2
        page.within('.assignee') do
          expect(page).to have_content 'No assignee'
        end
319

Jacob Schatz's avatar
Jacob Schatz committed
320
        expect(issue.reload.assignee).to be_nil
321
      end
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342

      it 'allows user to select an assignee', js: true do
        issue2 = create(:issue, project: project, author: @user)
        visit namespace_project_issue_path(project.namespace, project, issue2)

        page.within('.assignee') do
          expect(page).to have_content "No assignee"
        end

        page.within '.assignee' do
          click_link 'Edit'
        end
        
        page.within '.dropdown-menu-user' do
          click_link @user.name
        end

        page.within('.assignee') do
          expect(page).to have_content @user.name
        end
      end
343
344
345
    end

    context 'by unauthorized user' do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
346

347
      let(:guest) { create(:user) }
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
348

Rémy Coutable's avatar
Rémy Coutable committed
349
      before do
350
351
352
        project.team << [[guest], :guest]
      end

Jeroen van Baarsen's avatar
Jeroen van Baarsen committed
353
      it 'shows assignee text', js: true do
354
355
356
        logout
        login_with guest

Vinnie Okada's avatar
Vinnie Okada committed
357
        visit namespace_project_issue_path(project.namespace, project, issue)
358
        expect(page).to have_content issue.assignee.name
359
360
361
362
363
364
365
366
367
368
369
      end
    end
  end

  describe 'update milestone from issue#show' do
    let!(:issue) { create(:issue, project: project, author: @user) }
    let!(:milestone) { create(:milestone, project: project) }

    context 'by authorized user' do


Jacob Schatz's avatar
Jacob Schatz committed
370
371
      it 'allows user to select unassigned', js: true do
        visit namespace_project_issue_path(project.namespace, project, issue)
372

Jacob Schatz's avatar
Jacob Schatz committed
373
374
375
        page.within('.milestone') do
          expect(page).to have_content "None"
        end
376

Jacob Schatz's avatar
Jacob Schatz committed
377
378
379
380
        find('.block.milestone .edit-link').click
        sleep 2 # wait for ajax stuff to complete
        first('.dropdown-content li').click
        sleep 2
381
        page.within('.milestone') do
Jacob Schatz's avatar
Jacob Schatz committed
382
          expect(page).to have_content 'None'
383
384
        end

Jacob Schatz's avatar
Jacob Schatz committed
385
        expect(issue.reload.milestone).to be_nil
386
387
388
389
390
      end
    end

    context 'by unauthorized user' do
      let(:guest) { create(:user) }
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
391

Rémy Coutable's avatar
Rémy Coutable committed
392
      before do
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
393
        project.team << [guest, :guest]
394
395
396
397
        issue.milestone = milestone
        issue.save
      end

Jeroen van Baarsen's avatar
Jeroen van Baarsen committed
398
      it 'shows milestone text', js: true do
399
400
401
        logout
        login_with guest

Vinnie Okada's avatar
Vinnie Okada committed
402
        visit namespace_project_issue_path(project.namespace, project, issue)
403
        expect(page).to have_content milestone.title
404
405
      end
    end
406
407
408
409

    describe 'removing assignee' do
      let(:user2) { create(:user) }

Rémy Coutable's avatar
Rémy Coutable committed
410
      before do
411
412
413
414
        issue.assignee = user2
        issue.save
      end
    end
415
416
  end

417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
  describe 'new issue' do
    context 'dropzone upload file', js: true do
      before do
        visit new_namespace_project_issue_path(project.namespace, project)
      end

      it 'should upload file when dragging into textarea' do
        drop_in_dropzone test_image_file

        # Wait for the file to upload
        sleep 1

        expect(page.find_field("issue_description").value).to have_content 'banana_sample'
      end
    end
  end

434
  def first_issue
Douwe Maan's avatar
Douwe Maan committed
435
    page.all('ul.issues-list > li').first.text
436
437
438
  end

  def last_issue
Douwe Maan's avatar
Douwe Maan committed
439
    page.all('ul.issues-list > li').last.text
440
  end
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461

  def drop_in_dropzone(file_path)
    # Generate a fake input selector
    page.execute_script <<-JS
      var fakeFileInput = window.$('<input/>').attr(
        {id: 'fakeFileInput', type: 'file'}
      ).appendTo('body');
    JS
    # Attach the file to the fake input selector with Capybara
    attach_file("fakeFileInput", file_path)
    # Add the file to a fileList array and trigger the fake drop event
    page.execute_script <<-JS
      var fileList = [$('#fakeFileInput')[0].files[0]];
      var e = jQuery.Event('drop', { dataTransfer : { files : fileList } });
      $('.div-dropzone')[0].dropzone.listeners[0].events.drop(e);
    JS
  end

  def test_image_file
    File.join(Rails.root, 'spec', 'fixtures', 'banana_sample.gif')
  end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
462
end