pipelines_spec.rb 16 KB
Newer Older
1 2
require 'spec_helper'

3
describe 'Pipelines', :js do
4
  let(:project) { create(:project) }
5

6 7
  context 'when user is logged in' do
    let(:user) { create(:user) }
8

9
    before do
10
      sign_in(user)
11
      project.team << [user, :developer]
12 13
    end

14
    describe 'GET /:project/pipelines' do
15
      let(:project) { create(:project, :repository) }
16 17 18 19 20 21 22

      let!(:pipeline) do
        create(
          :ci_empty_pipeline,
          project: project,
          ref: 'master',
          status: 'running',
23
          sha: project.commit.id
24
        )
25 26
      end

27 28 29 30 31 32 33
      context 'scope' do
        before do
          create(:ci_empty_pipeline, status: 'pending', project: project, sha: project.commit.id, ref: 'master')
          create(:ci_empty_pipeline, status: 'running', project: project, sha: project.commit.id, ref: 'master')
          create(:ci_empty_pipeline, status: 'created', project: project, sha: project.commit.id, ref: 'master')
          create(:ci_empty_pipeline, status: 'success', project: project, sha: project.commit.id, ref: 'master')
        end
34

35 36 37 38 39 40 41 42 43
        [:all, :running, :pending, :finished, :branches].each do |scope|
          context "when displaying #{scope}" do
            before do
              visit_project_pipelines(scope: scope)
            end

            it 'contains pipeline commit short SHA' do
              expect(page).to have_content(pipeline.short_sha)
            end
44

45 46 47
            it 'contains branch name' do
              expect(page).to have_content(pipeline.ref)
            end
48
          end
49
        end
Regis's avatar
Regis committed
50
      end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
51

52 53
      context 'header tabs' do
        before do
54
          visit project_pipelines_path(project)
55
          wait_for_requests
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
        end

        it 'shows a tab for All pipelines and count' do
          expect(page.find('.js-pipelines-tab-all a').text).to include('All')
          expect(page.find('.js-pipelines-tab-all .badge').text).to include('1')
        end

        it 'shows a tab for Pending pipelines and count' do
          expect(page.find('.js-pipelines-tab-pending a').text).to include('Pending')
          expect(page.find('.js-pipelines-tab-pending .badge').text).to include('0')
        end

        it 'shows a tab for Running pipelines and count' do
          expect(page.find('.js-pipelines-tab-running a').text).to include('Running')
          expect(page.find('.js-pipelines-tab-running .badge').text).to include('1')
        end

        it 'shows a tab for Finished pipelines and count' do
          expect(page.find('.js-pipelines-tab-finished a').text).to include('Finished')
          expect(page.find('.js-pipelines-tab-finished .badge').text).to include('0')
        end

        it 'shows a tab for Branches' do
          expect(page.find('.js-pipelines-tab-branches a').text).to include('Branches')
        end

        it 'shows a tab for Tags' do
          expect(page.find('.js-pipelines-tab-tags a').text).to include('Tags')
        end
      end

87 88 89 90 91 92
      context 'when pipeline is cancelable' do
        let!(:build) do
          create(:ci_build, pipeline: pipeline,
                            stage: 'test',
                            commands: 'test')
        end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
93

94 95 96 97
        before do
          build.run
          visit_project_pipelines
        end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
98

99
        it 'indicates that pipeline can be canceled' do
100
          expect(page).to have_selector('.js-pipelines-cancel-button')
101 102
          expect(page).to have_selector('.ci-running')
        end
103

104
        context 'when canceling' do
105 106
          before do
            find('.js-pipelines-cancel-button').click
107
            wait_for_requests
108
          end
109

110
          it 'indicated that pipelines was canceled' do
111
            expect(page).not_to have_selector('.js-pipelines-cancel-button')
112 113
            expect(page).to have_selector('.ci-canceled')
          end
114
        end
115
      end
116

117 118 119 120 121 122
      context 'when pipeline is retryable' do
        let!(:build) do
          create(:ci_build, pipeline: pipeline,
                            stage: 'test',
                            commands: 'test')
        end
Regis's avatar
Regis committed
123

124
        before do
125 126
          build.drop
          visit_project_pipelines
127
        end
128

129
        it 'indicates that pipeline can be retried' do
130
          expect(page).to have_selector('.js-pipelines-retry-button')
131 132
          expect(page).to have_selector('.ci-failed')
        end
133 134

        context 'when retrying' do
135 136
          before do
            find('.js-pipelines-retry-button').click
137
            wait_for_requests
138
          end
139

140
          it 'shows running pipeline that is not retryable' do
141
            expect(page).not_to have_selector('.js-pipelines-retry-button')
142 143
            expect(page).to have_selector('.ci-running')
          end
144
        end
145 146
      end

147 148 149 150 151
      context 'when pipeline has configuration errors' do
        let(:pipeline) do
          create(:ci_pipeline, :invalid, project: project)
        end

152 153 154
        before do
          visit_project_pipelines
        end
155

156
        it 'contains badge that indicates errors' do
157 158 159 160 161 162 163 164
          expect(page).to have_content 'yaml invalid'
        end

        it 'contains badge with tooltip which contains error' do
          expect(pipeline).to have_yaml_errors
          expect(page).to have_selector(
            %Q{span[data-original-title="#{pipeline.yaml_errors}"]})
        end
165 166 167 168 169 170 171 172 173 174

        it 'contains badge that indicates failure reason' do
          expect(page).to have_content 'error'
        end

        it 'contains badge with tooltip which contains failure reason' do
          expect(pipeline.failure_reason?).to eq true
          expect(page).to have_selector(
            %Q{span[data-original-title="#{pipeline.present.failure_reason}"]})
        end
175 176
      end

177 178 179
      context 'with manual actions' do
        let!(:manual) do
          create(:ci_build, :manual,
Regis's avatar
Regis committed
180
            pipeline: pipeline,
181 182 183
            name: 'manual build',
            stage: 'test',
            commands: 'test')
Regis's avatar
Regis committed
184
        end
185

186 187 188
        before do
          visit_project_pipelines
        end
189

190
        it 'has a dropdown with play button' do
191
          expect(page).to have_selector('.dropdown-new.btn.btn-default .icon-play')
192 193
        end

194 195 196
        it 'has link to the manual action' do
          find('.js-pipeline-dropdown-manual-actions').click

197
          expect(page).to have_button('manual build')
198
        end
199

200 201 202
        context 'when manual action was played' do
          before do
            find('.js-pipeline-dropdown-manual-actions').click
203
            click_button('manual build')
204
          end
205

206
          it 'enqueues manual action job' do
207
            expect(page).to have_selector('.js-pipeline-dropdown-manual-actions:disabled')
208
          end
209
        end
210 211
      end

212 213 214 215 216 217
      context 'for generic statuses' do
        context 'when running' do
          let!(:running) do
            create(:generic_commit_status,
              status: 'running',
              pipeline: pipeline,
218
              stage: 'test')
219
          end
220

221 222 223
          before do
            visit_project_pipelines
          end
224 225

          it 'is cancelable' do
226
            expect(page).to have_selector('.js-pipelines-cancel-button')
227
          end
228

229 230 231 232 233
          it 'has pipeline running' do
            expect(page).to have_selector('.ci-running')
          end

          context 'when canceling' do
234 235 236
            before do
              find('.js-pipelines-cancel-button').trigger('click')
            end
237

238
            it 'indicates that pipeline was canceled' do
239
              expect(page).not_to have_selector('.js-pipelines-cancel-button')
240 241
              expect(page).to have_selector('.ci-canceled')
            end
242
          end
243 244
        end

245 246 247 248 249 250 251 252 253 254 255 256 257
        context 'when failed' do
          let!(:status) do
            create(:generic_commit_status, :pending,
              pipeline: pipeline,
              stage: 'test')
          end

          before do
            status.drop
            visit_project_pipelines
          end

          it 'is not retryable' do
258
            expect(page).not_to have_selector('.js-pipelines-retry-button')
259 260 261 262 263
          end

          it 'has failed pipeline' do
            expect(page).to have_selector('.ci-failed')
          end
264 265 266
        end
      end

267 268 269 270 271 272 273 274 275
      context 'downloadable pipelines' do
        context 'with artifacts' do
          let!(:with_artifacts) do
            create(:ci_build, :artifacts, :success,
              pipeline: pipeline,
              name: 'rspec tests',
              stage: 'test')
          end

276 277 278
          before do
            visit_project_pipelines
          end
279 280 281 282 283 284 285 286 287 288

          it 'has artifats' do
            expect(page).to have_selector('.build-artifacts')
          end

          it 'has artifacts download dropdown' do
            find('.js-pipeline-dropdown-download').click

            expect(page).to have_link(with_artifacts.name)
          end
289 290 291 292 293 294 295 296

          it 'has download attribute on download links' do
            find('.js-pipeline-dropdown-download').click
            expect(page).to have_selector('a', text: 'Download')
            page.all('.build-artifacts a', text: 'Download').each do |link|
              expect(link[:download]).to eq ''
            end
          end
Regis's avatar
Regis committed
297
        end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
298

299 300 301 302 303 304 305
        context 'with artifacts expired' do
          let!(:with_artifacts_expired) do
            create(:ci_build, :artifacts_expired, :success,
              pipeline: pipeline,
              name: 'rspec',
              stage: 'test')
          end
306

307 308 309
          before do
            visit_project_pipelines
          end
310 311

          it { expect(page).not_to have_selector('.build-artifacts') }
312 313
        end

314 315 316 317 318 319 320 321
        context 'without artifacts' do
          let!(:without_artifacts) do
            create(:ci_build, :success,
              pipeline: pipeline,
              name: 'rspec',
              stage: 'test')
          end

322 323 324
          before do
            visit_project_pipelines
          end
325

326
          it { expect(page).not_to have_selector('.build-artifacts') }
327
        end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
328
      end
329

330
      context 'mini pipeline graph' do
331
        let!(:build) do
332 333 334
          create(:ci_build, :pending, pipeline: pipeline,
                                      stage: 'build',
                                      name: 'build')
Regis's avatar
Regis committed
335
        end
336

337 338 339
        before do
          visit_project_pipelines
        end
340

341 342 343 344 345
        it 'should render a mini pipeline graph' do
          expect(page).to have_selector('.js-mini-pipeline-graph')
          expect(page).to have_selector('.js-builds-dropdown-button')
        end

346
        context 'when clicking a stage badge' do
347 348
          it 'should open a dropdown' do
            find('.js-builds-dropdown-button').trigger('click')
349

350 351
            expect(page).to have_link build.name
          end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
352

353
          it 'should be possible to cancel pending build' do
354
            find('.js-builds-dropdown-button').trigger('click')
355
            find('a.js-ci-action-icon').trigger('click')
356

357 358
            expect(page).to have_content('canceled')
            expect(build.reload).to be_canceled
359 360
          end
        end
361 362 363 364 365 366 367 368 369 370 371 372

        context 'dropdown jobs list' do
          it 'should keep the dropdown open when the user ctr/cmd + clicks in the job name' do
            find('.js-builds-dropdown-button').trigger('click')

            execute_script('var e = $.Event("keydown", { keyCode: 64 }); $("body").trigger(e);')

            find('.mini-pipeline-graph-dropdown-item').trigger('click')

            expect(page).to have_selector('.js-ci-action-icon')
          end
        end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
373
      end
374 375 376

      context 'with pagination' do
        before do
377 378
          allow(Ci::Pipeline).to receive(:default_per_page).and_return(1)
          create(:ci_empty_pipeline,  project: project)
379 380 381
        end

        it 'should render pagination' do
382
          visit project_pipelines_path(project)
383
          wait_for_requests
384

385
          expect(page).to have_selector('.gl-pagination')
386 387
        end

388
        it 'should render second page of pipelines' do
389
          visit project_pipelines_path(project, page: '2')
390
          wait_for_requests
391

392
          expect(page).to have_selector('.gl-pagination .page', count: 2)
393 394
        end
      end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
395
    end
396

397
    describe 'GET /:project/pipelines/show' do
398
      let(:project) { create(:project, :repository) }
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417

      let(:pipeline) do
        create(:ci_empty_pipeline,
              project: project,
              sha: project.commit.id,
              user: user)
      end

      before do
        create_build('build', 0, 'build', :success)
        create_build('test', 1, 'rspec 0:2', :pending)
        create_build('test', 1, 'rspec 1:2', :running)
        create_build('test', 1, 'spinach 0:2', :created)
        create_build('test', 1, 'spinach 1:2', :created)
        create_build('test', 1, 'audit', :created)
        create_build('deploy', 2, 'production', :created)

        create(:generic_commit_status, pipeline: pipeline, stage: 'external', name: 'jenkins', stage_idx: 3)

418
        visit project_pipeline_path(project, pipeline)
419
        wait_for_requests
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
      end

      it 'shows a graph with grouped stages' do
        expect(page).to have_css('.js-pipeline-graph')

        # header
        expect(page).to have_text("##{pipeline.id}")
        expect(page).to have_selector(%Q(img[alt$="#{pipeline.user.name}'s avatar"]))
        expect(page).to have_link(pipeline.user.name, href: user_path(pipeline.user))

        # stages
        expect(page).to have_text('Build')
        expect(page).to have_text('Test')
        expect(page).to have_text('Deploy')
        expect(page).to have_text('External')

        # builds
        expect(page).to have_text('rspec')
        expect(page).to have_text('spinach')
Z.J. van de Weg's avatar
Z.J. van de Weg committed
439
        expect(page).to have_text('rspec')
440 441 442 443 444 445 446 447 448
        expect(page).to have_text('production')
        expect(page).to have_text('jenkins')
      end

      def create_build(stage, stage_idx, name, status)
        create(:ci_build, pipeline: pipeline, stage: stage, stage_idx: stage_idx, name: name, status: status)
      end
    end

449
    describe 'POST /:project/pipelines' do
450
      let(:project) { create(:project, :repository) }
451 452

      before do
453
        visit new_project_pipeline_path(project)
454 455
      end

456
      context 'for valid commit', :js do
457 458 459 460 461 462 463
        before do
          click_button project.default_branch

          page.within '.dropdown-menu' do
            click_link 'master'
          end
        end
464

465
        context 'with gitlab-ci.yml' do
466 467 468
          before do
            stub_ci_pipeline_to_return_yaml_file
          end
469

470 471 472
          it 'creates a new pipeline' do
            expect { click_on 'Create pipeline' }
              .to change { Ci::Pipeline.count }.by(1)
473 474

            expect(Ci::Pipeline.last).to be_web
475
          end
476 477
        end

478
        context 'without gitlab-ci.yml' do
479 480 481
          before do
            click_on 'Create pipeline'
          end
482

483
          it { expect(page).to have_content('Missing .gitlab-ci.yml file') }
484 485
        end
      end
Regis's avatar
Regis committed
486
    end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
487

488
    describe 'Create pipelines' do
489
      let(:project) { create(:project, :repository) }
490

491
      before do
492
        visit new_project_pipeline_path(project)
493
      end
494

495 496
      describe 'new pipeline page' do
        it 'has field to add a new pipeline' do
497 498
          expect(page).to have_selector('.js-branch-select')
          expect(find('.js-branch-select')).to have_content project.default_branch
499
          expect(page).to have_content('Create for')
Regis's avatar
Regis committed
500
        end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
501
      end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
502

503
      describe 'find pipelines' do
504
        it 'shows filtered pipelines', :js do
505
          click_button project.default_branch
506

507 508 509 510 511 512
          page.within '.dropdown-menu' do
            find('.dropdown-input-field').native.send_keys('fix')

            page.within '.dropdown-content' do
              expect(page).to have_content('fix')
            end
513 514
          end
        end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
515 516
      end
    end
517
  end
ubudzisz's avatar
ubudzisz committed
518

519
  context 'when user is not logged in' do
ubudzisz's avatar
ubudzisz committed
520
    before do
521
      visit project_pipelines_path(project)
ubudzisz's avatar
ubudzisz committed
522 523
    end

524
    context 'when project is public' do
525
      let(:project) { create(:project, :public, :repository) }
526

527
      it { expect(page).to have_content 'Build with confidence' }
528
      it { expect(page).to have_http_status(:success) }
ubudzisz's avatar
ubudzisz committed
529 530
    end

531
    context 'when project is private' do
532
      let(:project) { create(:project, :private, :repository) }
ubudzisz's avatar
ubudzisz committed
533

534
      it { expect(page).to have_content 'You need to sign in' }
ubudzisz's avatar
ubudzisz committed
535 536
    end
  end
537 538

  def visit_project_pipelines(**query)
539
    visit project_pipelines_path(project, query)
540
    wait_for_requests
541
  end
542
end