require 'spec_helper' describe 'Environments page', :js do let(:project) { create(:project) } let(:user) { create(:user) } let(:role) { :developer } before do project.add_role(user, role) sign_in(user) end def stop_button_selector %q{button[data-original-title="Stop environment"]} end describe 'page tabs' do it 'shows "Available" and "Stopped" tab with links' do visit_environments(project) expect(page).to have_selector('.js-environments-tab-available') expect(page).to have_content('Available') expect(page).to have_selector('.js-environments-tab-stopped') expect(page).to have_content('Stopped') end describe 'with one available environment' do before do create(:environment, project: project, state: :available) end describe 'in available tab page' do it 'shows one environment' do visit_environments(project, scope: 'available') expect(page).to have_css('.environments-container') expect(page.all('.environment-name').length).to eq(1) end end describe 'with environments spanning multiple pages', :js do before do allow(Kaminari.config).to receive(:default_per_page).and_return(3) create_list(:environment, 4, project: project, state: :available) end it 'renders second page of pipelines' do visit_environments(project, scope: 'available') find('.js-next-button').click wait_for_requests expect(page).to have_selector('.gl-pagination .page', count: 2) expect(find('.gl-pagination .page-item.active .page-link').text).to eq("2") end end describe 'in stopped tab page' do it 'shows no environments' do visit_environments(project, scope: 'stopped') expect(page).to have_css('.environments-container') expect(page).to have_content('You don\'t have any environments right now') end end context 'when cluster is not reachable' do let!(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) } let!(:application_prometheus) { create(:clusters_applications_prometheus, :installed, cluster: cluster) } before do allow_any_instance_of(Kubeclient::Client).to receive(:proxy_url).and_raise(Kubeclient::HttpError.new(401, 'Unauthorized', nil)) end it 'shows one environment without error' do visit_environments(project, scope: 'available') expect(page).to have_css('.environments-container') expect(page.all('.environment-name').length).to eq(1) end end end describe 'with one stopped environment' do before do create(:environment, project: project, state: :stopped) end describe 'in available tab page' do it 'shows no environments' do visit_environments(project, scope: 'available') expect(page).to have_css('.environments-container') expect(page).to have_content('You don\'t have any environments right now') end end describe 'in stopped tab page' do it 'shows one environment' do visit_environments(project, scope: 'stopped') expect(page).to have_css('.environments-container') expect(page.all('.environment-name').length).to eq(1) end end end end context 'without environments' do before do visit_environments(project) end it 'does not show environments and counters are set to zero' do expect(page).to have_content('You don\'t have any environments right now') expect(page.find('.js-environments-tab-available .badge').text).to eq('0') expect(page.find('.js-environments-tab-stopped .badge').text).to eq('0') end end describe 'environments table' do let!(:environment) do create(:environment, project: project, state: :available) end context 'when there are no deployments' do before do visit_environments(project) end it 'shows environments names and counters' do expect(page).to have_link(environment.name) expect(page.find('.js-environments-tab-available .badge').text).to eq('1') expect(page.find('.js-environments-tab-stopped .badge').text).to eq('0') end it 'does not show deployments' do expect(page).to have_content('No deployments yet') end it 'does not show stip button when environment is not stoppable' do expect(page).not_to have_selector(stop_button_selector) end end context 'when there are successful deployments' do let(:project) { create(:project, :repository) } let!(:deployment) do create(:deployment, :success, environment: environment, sha: project.commit.id) end it 'shows deployment SHA and internal ID' do visit_environments(project) expect(page).to have_link(deployment.short_sha) expect(page).to have_content(deployment.iid) end context 'when builds and manual actions are present' do let!(:pipeline) { create(:ci_pipeline, project: project) } let!(:build) { create(:ci_build, pipeline: pipeline) } let!(:action) do create(:ci_build, :manual, pipeline: pipeline, name: 'deploy to production') end let!(:deployment) do create(:deployment, :success, environment: environment, deployable: build, sha: project.commit.id) end before do visit_environments(project) end it 'shows a play button' do find('.js-environment-actions-dropdown').click expect(page).to have_content(action.name) end it 'allows to play a manual action', :js do expect(action).to be_manual find('.js-environment-actions-dropdown').click expect(page).to have_content(action.name) expect { find('.js-manual-action-link').click } .not_to change { Ci::Pipeline.count } end it 'shows build name and id' do expect(page).to have_link("#{build.name} ##{build.id}") end it 'shows a stop button' do expect(page).not_to have_selector(stop_button_selector) end it 'does not show external link button' do expect(page).not_to have_css('external-url') end it 'does not show terminal button' do expect(page).not_to have_terminal_button end context 'with external_url' do let(:environment) { create(:environment, project: project, external_url: 'https://git.gitlab.com') } let(:build) { create(:ci_build, pipeline: pipeline) } let(:deployment) { create(:deployment, :success, environment: environment, deployable: build) } it 'shows an external link button' do expect(page).to have_link(nil, href: environment.external_url) end end context 'with stop action' do let(:action) do create(:ci_build, :manual, pipeline: pipeline, name: 'close_app') end let(:deployment) do create(:deployment, :success, environment: environment, deployable: build, on_stop: 'close_app') end it 'shows a stop button' do expect(page).to have_selector(stop_button_selector) end context 'when user is a reporter' do let(:role) { :reporter } it 'does not show stop button' do expect(page).not_to have_selector(stop_button_selector) end end end context 'when kubernetes terminal is available' do context 'when user configured kubernetes from CI/CD > Clusters' do let(:cluster) { create(:cluster, :provided_by_gcp, projects: [create(:project, :repository)]) } let(:project) { cluster.project } context 'for project maintainer' do let(:role) { :maintainer } it 'shows the terminal button' do expect(page).to have_terminal_button end end context 'when user is a developer' do let(:role) { :developer } it 'does not show terminal button' do expect(page).not_to have_terminal_button end end end end end context 'when there is a delayed job' do let!(:pipeline) { create(:ci_pipeline, project: project) } let!(:build) { create(:ci_build, pipeline: pipeline) } let!(:delayed_job) do create(:ci_build, :scheduled, pipeline: pipeline, name: 'delayed job', stage: 'test') end let!(:deployment) do create(:deployment, :success, environment: environment, deployable: build, sha: project.commit.id) end before do visit_environments(project) end it 'has a dropdown for actionable jobs' do expect(page).to have_selector('.dropdown-new.btn.btn-default .ic-play') end it "has link to the delayed job's action" do find('.js-environment-actions-dropdown').click expect(page).to have_button('delayed job') expect(page).to have_content(/\d{2}:\d{2}:\d{2}/) end context 'when delayed job is expired already' do let!(:delayed_job) do create(:ci_build, :expired_scheduled, pipeline: pipeline, name: 'delayed job', stage: 'test') end it "shows 00:00:00 as the remaining time" do find('.js-environment-actions-dropdown').click expect(page).to have_content("00:00:00") end end context 'when user played a delayed job immediately' do before do find('.js-environment-actions-dropdown').click page.accept_confirm { click_button('delayed job') } wait_for_requests end it 'enqueues the delayed job', :js do expect(delayed_job.reload).to be_pending end end end end context 'when there is a failed deployment' do let(:project) { create(:project, :repository) } let!(:deployment) do create(:deployment, :failed, environment: environment, sha: project.commit.id) end it 'does not show deployments' do visit_environments(project) expect(page).to have_content('No deployments yet') end end end it 'does have a new environment button' do visit_environments(project) expect(page).to have_link('New environment') end describe 'creating a new environment' do before do visit_environments(project) end context 'user is a developer' do let(:role) { :developer } it 'developer creates a new environment with a valid name' do within(".top-area") { click_link 'New environment' } fill_in('Name', with: 'production') click_on 'Save' expect(page).to have_content('production') end it 'developer creates a new environmetn with invalid name' do within(".top-area") { click_link 'New environment' } fill_in('Name', with: 'name,with,commas') click_on 'Save' expect(page).to have_content('Name can contain only letters') end end context 'user is a reporter' do let(:role) { :reporter } it 'reporters tries to create a new environment' do expect(page).not_to have_link('New environment') end end end describe 'environments folders' do before do create(:environment, project: project, name: 'staging/review-1', state: :available) create(:environment, project: project, name: 'staging/review-2', state: :available) end it 'users unfurls an environment folder' do visit_environments(project) expect(page).not_to have_content 'review-1' expect(page).not_to have_content 'review-2' expect(page).to have_content 'staging 2' within('.folder-row') do find('.folder-name', text: 'staging').click end expect(page).to have_content 'review-1' expect(page).to have_content 'review-2' end end describe 'environments folders view' do before do create(:environment, project: project, name: 'staging.review/review-1', state: :available) create(:environment, project: project, name: 'staging.review/review-2', state: :available) end it 'user opens folder view' do visit folder_project_environments_path(project, 'staging.review') wait_for_requests expect(page).to have_content('Environments / staging.review') expect(page).to have_content('review-1') expect(page).to have_content('review-2') end end def have_terminal_button have_link(nil, href: terminal_project_environment_path(project, environment)) end def visit_environments(project, **opts) visit project_environments_path(project, **opts) wait_for_requests end end