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

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

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

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

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

      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 54
      context 'header tabs' do
        before do
          visit namespace_project_pipelines_path(project.namespace, 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 152 153
      context 'when pipeline has configuration errors' do
        let(:pipeline) do
          create(:ci_pipeline, :invalid, project: project)
        end

        before { visit_project_pipelines }

154
        it 'contains badge that indicates errors' do
155 156 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
      end

165 166 167
      context 'with manual actions' do
        let!(:manual) do
          create(:ci_build, :manual,
Regis's avatar
Regis committed
168
            pipeline: pipeline,
169 170 171
            name: 'manual build',
            stage: 'test',
            commands: 'test')
Regis's avatar
Regis committed
172
        end
173

174
        before { visit_project_pipelines }
175

176 177
        it 'has a dropdown with play button' do
          expect(page).to have_selector('.dropdown-toggle.btn.btn-default .icon-play')
178 179
        end

180 181 182
        it 'has link to the manual action' do
          find('.js-pipeline-dropdown-manual-actions').click

183
          expect(page).to have_button('manual build')
184
        end
185

186 187 188
        context 'when manual action was played' do
          before do
            find('.js-pipeline-dropdown-manual-actions').click
189
            click_button('manual build')
190
          end
191

192
          it 'enqueues manual action job' do
193
            expect(page).to have_selector('.js-pipeline-dropdown-manual-actions:disabled')
194
          end
195
        end
196 197
      end

198 199 200 201 202 203
      context 'for generic statuses' do
        context 'when running' do
          let!(:running) do
            create(:generic_commit_status,
              status: 'running',
              pipeline: pipeline,
204
              stage: 'test')
205
          end
206

207 208 209
          before { visit_project_pipelines }

          it 'is cancelable' do
210
            expect(page).to have_selector('.js-pipelines-cancel-button')
211
          end
212

213 214 215 216 217
          it 'has pipeline running' do
            expect(page).to have_selector('.ci-running')
          end

          context 'when canceling' do
218
            before { find('.js-pipelines-cancel-button').trigger('click') }
219

220
            it 'indicates that pipeline was canceled' do
221
              expect(page).not_to have_selector('.js-pipelines-cancel-button')
222 223
              expect(page).to have_selector('.ci-canceled')
            end
224
          end
225 226
        end

227 228 229 230 231 232 233 234 235 236 237 238 239
        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
240
            expect(page).not_to have_selector('.js-pipelines-retry-button')
241 242 243 244 245
          end

          it 'has failed pipeline' do
            expect(page).to have_selector('.ci-failed')
          end
246 247 248
        end
      end

249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
      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

          before { visit_project_pipelines }

          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
269 270 271 272 273 274 275 276

          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
277
        end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
278

279 280 281 282 283 284 285
        context 'with artifacts expired' do
          let!(:with_artifacts_expired) do
            create(:ci_build, :artifacts_expired, :success,
              pipeline: pipeline,
              name: 'rspec',
              stage: 'test')
          end
286

287 288 289
          before { visit_project_pipelines }

          it { expect(page).not_to have_selector('.build-artifacts') }
290 291
        end

292 293 294 295 296 297 298 299 300
        context 'without artifacts' do
          let!(:without_artifacts) do
            create(:ci_build, :success,
              pipeline: pipeline,
              name: 'rspec',
              stage: 'test')
          end

          before { visit_project_pipelines }
301

302
          it { expect(page).not_to have_selector('.build-artifacts') }
303
        end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
304
      end
305

306
      context 'mini pipeline graph' do
307
        let!(:build) do
308 309 310
          create(:ci_build, :pending, pipeline: pipeline,
                                      stage: 'build',
                                      name: 'build')
Regis's avatar
Regis committed
311
        end
312

313
        before { visit_project_pipelines }
314

315 316 317 318 319
        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

320
        context 'when clicking a stage badge' do
321 322
          it 'should open a dropdown' do
            find('.js-builds-dropdown-button').trigger('click')
323

324 325
            expect(page).to have_link build.name
          end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
326

327
          it 'should be possible to cancel pending build' do
328
            find('.js-builds-dropdown-button').trigger('click')
329
            find('a.js-ci-action-icon').trigger('click')
330

331 332
            expect(page).to have_content('canceled')
            expect(build.reload).to be_canceled
333 334
          end
        end
335 336 337 338 339 340 341 342 343 344 345 346

        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
347
      end
348 349 350

      context 'with pagination' do
        before do
351 352
          allow(Ci::Pipeline).to receive(:default_per_page).and_return(1)
          create(:ci_empty_pipeline,  project: project)
353 354 355 356
        end

        it 'should render pagination' do
          visit namespace_project_pipelines_path(project.namespace, project)
357
          wait_for_requests
358

359
          expect(page).to have_selector('.gl-pagination')
360 361
        end

362
        it 'should render second page of pipelines' do
363
          visit namespace_project_pipelines_path(project.namespace, project, page: '2')
364
          wait_for_requests
365

366
          expect(page).to have_selector('.gl-pagination .page', count: 2)
367 368
        end
      end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
369
    end
370

371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
    describe 'GET /:project/pipelines/show' do
      let(:project) { create(:project) }

      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)

        visit namespace_project_pipeline_path(project.namespace, project, pipeline)
393
        wait_for_requests
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
      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
413
        expect(page).to have_text('rspec')
414 415 416 417 418 419 420 421 422
        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

423 424 425 426 427
    describe 'POST /:project/pipelines' do
      let(:project) { create(:project) }

      before do
        visit new_namespace_project_pipeline_path(project.namespace, project)
428 429
      end

430 431 432 433 434 435 436 437
      context 'for valid commit', js: true do
        before do
          click_button project.default_branch

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

439 440
        context 'with gitlab-ci.yml' do
          before { stub_ci_pipeline_to_return_yaml_file }
441

442 443 444
          it 'creates a new pipeline' do
            expect { click_on 'Create pipeline' }
              .to change { Ci::Pipeline.count }.by(1)
445 446

            expect(Ci::Pipeline.last).to be_web
447
          end
448 449
        end

450 451
        context 'without gitlab-ci.yml' do
          before { click_on 'Create pipeline' }
452

453
          it { expect(page).to have_content('Missing .gitlab-ci.yml file') }
454 455
        end
      end
Regis's avatar
Regis committed
456
    end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
457

458 459
    describe 'Create pipelines' do
      let(:project) { create(:project) }
460

461 462 463
      before do
        visit new_namespace_project_pipeline_path(project.namespace, project)
      end
464

465 466
      describe 'new pipeline page' do
        it 'has field to add a new pipeline' do
467 468
          expect(page).to have_selector('.js-branch-select')
          expect(find('.js-branch-select')).to have_content project.default_branch
469
          expect(page).to have_content('Create for')
Regis's avatar
Regis committed
470
        end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
471
      end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
472

473 474
      describe 'find pipelines' do
        it 'shows filtered pipelines', js: true do
475
          click_button project.default_branch
476

477 478 479 480 481 482
          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
483 484
          end
        end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
485 486
      end
    end
487
  end
ubudzisz's avatar
ubudzisz committed
488

489
  context 'when user is not logged in' do
ubudzisz's avatar
ubudzisz committed
490
    before do
491
      visit namespace_project_pipelines_path(project.namespace, project)
ubudzisz's avatar
ubudzisz committed
492 493
    end

494 495 496
    context 'when project is public' do
      let(:project) { create(:project, :public) }

497
      it { expect(page).to have_content 'Build with confidence' }
498
      it { expect(page).to have_http_status(:success) }
ubudzisz's avatar
ubudzisz committed
499 500
    end

501 502
    context 'when project is private' do
      let(:project) { create(:project, :private) }
ubudzisz's avatar
ubudzisz committed
503

504
      it { expect(page).to have_content 'You need to sign in' }
ubudzisz's avatar
ubudzisz committed
505 506
    end
  end
507 508 509

  def visit_project_pipelines(**query)
    visit namespace_project_pipelines_path(project.namespace, project, query)
510
    wait_for_requests
511
  end
512
end