Uses Vue app to render part of job show page
This commit is contained in:
parent
88c1cf676c
commit
9128e7849d
16 changed files with 691 additions and 472 deletions
|
@ -12,12 +12,16 @@
|
|||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
iconStatus: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
environment() {
|
||||
let environmentText;
|
||||
switch (this.deploymentStatus.status) {
|
||||
case 'latest':
|
||||
case 'last':
|
||||
environmentText = sprintf(
|
||||
__('This job is the most recent deployment to %{link}.'),
|
||||
{ link: this.environmentLink },
|
||||
|
@ -32,7 +36,7 @@
|
|||
),
|
||||
{
|
||||
environmentLink: this.environmentLink,
|
||||
deploymentLink: this.deploymentLink,
|
||||
deploymentLink: this.deploymentLink(`#${this.lastDeployment.iid}`),
|
||||
},
|
||||
false,
|
||||
);
|
||||
|
@ -56,11 +60,11 @@
|
|||
if (this.hasLastDeployment) {
|
||||
environmentText = sprintf(
|
||||
__(
|
||||
'This job is creating a deployment to %{environmentLink} and will overwrite the last %{deploymentLink}.',
|
||||
'This job is creating a deployment to %{environmentLink} and will overwrite the %{deploymentLink}.',
|
||||
),
|
||||
{
|
||||
environmentLink: this.environmentLink,
|
||||
deploymentLink: this.deploymentLink,
|
||||
deploymentLink: this.deploymentLink(__('latest deployment')),
|
||||
},
|
||||
false,
|
||||
);
|
||||
|
@ -78,32 +82,45 @@
|
|||
return environmentText;
|
||||
},
|
||||
environmentLink() {
|
||||
return sprintf(
|
||||
'%{startLink}%{name}%{endLink}',
|
||||
{
|
||||
startLink: `<a href="${this.deploymentStatus.environment.path}">`,
|
||||
name: _.escape(this.deploymentStatus.environment.name),
|
||||
endLink: '</a>',
|
||||
},
|
||||
false,
|
||||
);
|
||||
},
|
||||
deploymentLink() {
|
||||
return sprintf(
|
||||
'%{startLink}%{name}%{endLink}',
|
||||
{
|
||||
startLink: `<a href="${this.lastDeployment.path}">`,
|
||||
name: _.escape(this.lastDeployment.name),
|
||||
endLink: '</a>',
|
||||
},
|
||||
false,
|
||||
);
|
||||
if (this.hasEnvironment) {
|
||||
return sprintf(
|
||||
'%{startLink}%{name}%{endLink}',
|
||||
{
|
||||
startLink: `<a href="${
|
||||
this.deploymentStatus.environment.environment_path
|
||||
}" class="js-environment-link">`,
|
||||
name: _.escape(this.deploymentStatus.environment.name),
|
||||
endLink: '</a>',
|
||||
},
|
||||
false,
|
||||
);
|
||||
}
|
||||
return '';
|
||||
},
|
||||
hasLastDeployment() {
|
||||
return this.deploymentStatus.environment.last_deployment;
|
||||
return this.hasEnvironment && this.deploymentStatus.environment.last_deployment;
|
||||
},
|
||||
lastDeployment() {
|
||||
return this.deploymentStatus.environment.last_deployment;
|
||||
return this.hasLastDeployment ? this.deploymentStatus.environment.last_deployment : {};
|
||||
},
|
||||
hasEnvironment() {
|
||||
return !_.isEmpty(this.deploymentStatus.environment);
|
||||
},
|
||||
lastDeploymentPath() {
|
||||
return !_.isEmpty(this.lastDeployment.deployable) ? this.lastDeployment.deployable.build_path : '';
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
deploymentLink(name) {
|
||||
return sprintf(
|
||||
'%{startLink}%{name}%{endLink}',
|
||||
{
|
||||
startLink: `<a href="${this.lastDeploymentPath}" class="js-job-deployment-link">`,
|
||||
name,
|
||||
endLink: '</a>',
|
||||
},
|
||||
false,
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -111,8 +128,11 @@
|
|||
<template>
|
||||
<div class="prepend-top-default js-environment-container">
|
||||
<div class="environment-information">
|
||||
<ci-icon :status="deploymentStatus.icon" />
|
||||
<p v-html="environment"></p>
|
||||
<ci-icon :status="iconStatus"/>
|
||||
<p
|
||||
class="inline append-bottom-0"
|
||||
v-html="environment"
|
||||
></p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
<script>
|
||||
import ciHeader from '../../vue_shared/components/header_ci_component.vue';
|
||||
import callout from '../../vue_shared/components/callout.vue';
|
||||
|
||||
export default {
|
||||
name: 'JobHeaderSection',
|
||||
components: {
|
||||
ciHeader,
|
||||
callout,
|
||||
},
|
||||
props: {
|
||||
job: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
isLoading: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
actions: this.getActions(),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
status() {
|
||||
return this.job && this.job.status;
|
||||
},
|
||||
shouldRenderContent() {
|
||||
return !this.isLoading && Object.keys(this.job).length;
|
||||
},
|
||||
shouldRenderReason() {
|
||||
return !!(this.job.status && this.job.callout_message);
|
||||
},
|
||||
/**
|
||||
* When job has not started the key will be `false`
|
||||
* When job started the key will be a string with a date.
|
||||
*/
|
||||
jobStarted() {
|
||||
return !this.job.started === false;
|
||||
},
|
||||
headerTime() {
|
||||
return this.jobStarted ? this.job.started : this.job.created_at;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
job() {
|
||||
this.actions = this.getActions();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getActions() {
|
||||
const actions = [];
|
||||
|
||||
if (this.job.new_issue_path) {
|
||||
actions.push({
|
||||
label: 'New issue',
|
||||
path: this.job.new_issue_path,
|
||||
cssClass: 'js-new-issue btn btn-success btn-inverted d-none d-md-block d-lg-block d-xl-block',
|
||||
type: 'link',
|
||||
});
|
||||
}
|
||||
return actions;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<header>
|
||||
<div class="js-build-header build-header top-area">
|
||||
<ci-header
|
||||
v-if="shouldRenderContent"
|
||||
:status="status"
|
||||
:item-id="job.id"
|
||||
:time="headerTime"
|
||||
:user="job.user"
|
||||
:actions="actions"
|
||||
:has-sidebar-button="true"
|
||||
:should-render-triggered-label="jobStarted"
|
||||
item-name="Job"
|
||||
/>
|
||||
<gl-loading-icon
|
||||
v-if="isLoading"
|
||||
:size="2"
|
||||
class="prepend-top-default append-bottom-default"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<callout
|
||||
v-if="shouldRenderReason"
|
||||
:message="job.callout_message"
|
||||
/>
|
||||
</header>
|
||||
</template>
|
99
app/assets/javascripts/jobs/components/job_app.vue
Normal file
99
app/assets/javascripts/jobs/components/job_app.vue
Normal file
|
@ -0,0 +1,99 @@
|
|||
<script>
|
||||
import { mapGetters, mapState } from 'vuex';
|
||||
import CiHeader from '~/vue_shared/components/header_ci_component.vue';
|
||||
import Callout from '~/vue_shared/components/callout.vue';
|
||||
import EnvironmentsBlock from './environments_block.vue';
|
||||
import ErasedBlock from './erased_block.vue';
|
||||
import StuckBlock from './stuck_block.vue';
|
||||
|
||||
export default {
|
||||
name: 'JobPageApp',
|
||||
components: {
|
||||
CiHeader,
|
||||
Callout,
|
||||
EnvironmentsBlock,
|
||||
ErasedBlock,
|
||||
StuckBlock,
|
||||
},
|
||||
props: {
|
||||
runnerHelpUrl: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState(['isLoading', 'job']),
|
||||
...mapGetters([
|
||||
'headerActions',
|
||||
'headerTime',
|
||||
'shouldRenderCalloutMessage',
|
||||
'jobHasStarted',
|
||||
'hasEnvironment',
|
||||
'isJobStuck',
|
||||
]),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<gl-loading-icon
|
||||
v-if="isLoading"
|
||||
:size="2"
|
||||
class="prepend-top-20"
|
||||
/>
|
||||
|
||||
<template v-else>
|
||||
<!-- Header Section -->
|
||||
<header>
|
||||
<div class="js-build-header build-header top-area">
|
||||
<ci-header
|
||||
:status="job.status"
|
||||
:item-id="job.id"
|
||||
:time="headerTime"
|
||||
:user="job.user"
|
||||
:actions="headerActions"
|
||||
:has-sidebar-button="true"
|
||||
:should-render-triggered-label="jobHasStarted"
|
||||
:item-name="__('Job')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<callout
|
||||
v-if="shouldRenderCalloutMessage"
|
||||
:message="job.callout_message"
|
||||
/>
|
||||
</header>
|
||||
<!-- EO Header Section -->
|
||||
|
||||
<!-- Body Section -->
|
||||
<stuck-block
|
||||
v-if="isJobStuck"
|
||||
class="js-job-stuck"
|
||||
:has-no-runners-for-project="job.runners.available"
|
||||
:tags="job.tags"
|
||||
:runners-path="runnerHelpUrl"
|
||||
/>
|
||||
|
||||
<environments-block
|
||||
v-if="hasEnvironment"
|
||||
:deployment-status="job.deployment_status"
|
||||
:icon-status="job.status"
|
||||
/>
|
||||
|
||||
<erased-block
|
||||
v-if="job.erased"
|
||||
:user="job.erased_by"
|
||||
:erased-at="job.erased_at"
|
||||
/>
|
||||
|
||||
<!--job log -->
|
||||
<!-- EO job log -->
|
||||
|
||||
<!--empty state -->
|
||||
<!-- EO empty state -->
|
||||
|
||||
<!-- EO Body Section -->
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
|
@ -2,7 +2,7 @@ import _ from 'underscore';
|
|||
import { mapState, mapActions } from 'vuex';
|
||||
import Vue from 'vue';
|
||||
import Job from '../job';
|
||||
import JobHeader from './components/header.vue';
|
||||
import JobApp from './components/job_app.vue';
|
||||
import Sidebar from './components/sidebar.vue';
|
||||
import createStore from './store';
|
||||
|
||||
|
@ -22,17 +22,18 @@ export default () => {
|
|||
new Vue({
|
||||
el: '#js-build-header-vue',
|
||||
components: {
|
||||
JobHeader,
|
||||
JobApp,
|
||||
},
|
||||
store,
|
||||
computed: {
|
||||
...mapState(['job', 'isLoading']),
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement('job-header', {
|
||||
return createElement('job-app', {
|
||||
props: {
|
||||
isLoading: this.isLoading,
|
||||
job: this.job,
|
||||
runnerHelpUrl: dataset.runnerHelpUrl,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
|
42
app/assets/javascripts/jobs/store/getters.js
Normal file
42
app/assets/javascripts/jobs/store/getters.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
import _ from 'underscore';
|
||||
import { __ } from '~/locale';
|
||||
|
||||
export const headerActions = state => {
|
||||
if (state.job.new_issue_path) {
|
||||
return [
|
||||
{
|
||||
label: __('New issue'),
|
||||
path: state.job.new_issue_path,
|
||||
cssClass:
|
||||
'js-new-issue btn btn-success btn-inverted d-none d-md-block d-lg-block d-xl-block',
|
||||
type: 'link',
|
||||
},
|
||||
];
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
export const headerTime = state => (state.job.started ? state.job.started : state.job.created_at);
|
||||
|
||||
export const shouldRenderCalloutMessage = state =>
|
||||
!_.isEmpty(state.job.status) && !_.isEmpty(state.job.callout_message);
|
||||
|
||||
/**
|
||||
* When job has not started the key will be `false`
|
||||
* When job started the key will be a string with a date.
|
||||
*/
|
||||
export const jobHasStarted = state => !(state.job.started === false);
|
||||
|
||||
export const hasEnvironment = state => !_.isEmpty(state.job.deployment_status);
|
||||
|
||||
/**
|
||||
* When the job is pending and there are no available runners
|
||||
* we need to render the stuck block;
|
||||
*
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
export const isJobStuck = state =>
|
||||
state.job.status.group === 'pending' && state.job.runners && state.job.runners.available === false;
|
||||
|
||||
// prevent babel-plugin-rewire from generating an invalid default during karma tests
|
||||
export default () => {};
|
|
@ -2,6 +2,7 @@ import Vue from 'vue';
|
|||
import Vuex from 'vuex';
|
||||
import state from './state';
|
||||
import * as actions from './actions';
|
||||
import * as getters from './getters';
|
||||
import mutations from './mutations';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
@ -9,5 +10,6 @@ Vue.use(Vuex);
|
|||
export default () => new Vuex.Store({
|
||||
actions,
|
||||
mutations,
|
||||
getters,
|
||||
state: state(),
|
||||
});
|
||||
|
|
|
@ -9,54 +9,6 @@
|
|||
%div{ class: container_class }
|
||||
.build-page.js-build-page
|
||||
#js-build-header-vue
|
||||
- if @build.stuck?
|
||||
- unless @build.any_runners_online?
|
||||
.bs-callout.bs-callout-warning.js-build-stuck
|
||||
%p
|
||||
- if @project.any_runners?
|
||||
This job is stuck, because the project doesn't have any runners online assigned to it.
|
||||
- elsif @build.tags.any?
|
||||
This job is stuck, because you don't have any active runners online with any of these tags assigned to them:
|
||||
- @build.tags.each do |tag|
|
||||
%span.badge.badge-primary
|
||||
= tag
|
||||
- else
|
||||
This job is stuck, because you don't have any active runners that can run this job.
|
||||
|
||||
%br
|
||||
Go to
|
||||
= link_to project_runners_path(@build.project, anchor: 'js-runners-settings') do
|
||||
Runners page
|
||||
|
||||
- if @build.starts_environment?
|
||||
.prepend-top-default.js-environment-container
|
||||
.environment-information
|
||||
- if @build.outdated_deployment?
|
||||
= ci_icon_for_status('success_with_warnings')
|
||||
- else
|
||||
= ci_icon_for_status(@build.status)
|
||||
|
||||
- environment = environment_for_build(@build.project, @build)
|
||||
- if @build.success? && @build.last_deployment.present?
|
||||
- if @build.last_deployment.last?
|
||||
This job is the most recent deployment to #{environment_link_for_build(@build.project, @build)}.
|
||||
- else
|
||||
This job is an out-of-date deployment to #{environment_link_for_build(@build.project, @build)}.
|
||||
View the most recent deployment #{deployment_link(environment.last_deployment)}.
|
||||
- elsif @build.complete? && !@build.success?
|
||||
The deployment of this job to #{environment_link_for_build(@build.project, @build)} did not succeed.
|
||||
- else
|
||||
This job is creating a deployment to #{environment_link_for_build(@build.project, @build)}
|
||||
- if environment.try(:last_deployment)
|
||||
and will overwrite the #{deployment_link(environment.last_deployment, text: 'latest deployment')}
|
||||
|
||||
- if @build.erased?
|
||||
.prepend-top-default.js-build-erased
|
||||
.erased.alert.alert-warning
|
||||
- if @build.erased_by_user?
|
||||
Job has been erased by #{link_to(@build.erased_by_name, user_path(@build.erased_by))} #{time_ago_with_tooltip(@build.erased_at)}
|
||||
- else
|
||||
Job has been erased #{time_ago_with_tooltip(@build.erased_at)}
|
||||
|
||||
- if @build.running? || @build.has_trace?
|
||||
.build-trace-container.prepend-top-default
|
||||
|
|
5
changelogs/unreleased/50904-vuex-show-block.yml
Normal file
5
changelogs/unreleased/50904-vuex-show-block.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Renders Job show page in new Vue app
|
||||
merge_request:
|
||||
author:
|
||||
type: other
|
|
@ -6106,7 +6106,7 @@ msgstr ""
|
|||
msgid "This job is an out-of-date deployment to %{environmentLink}. View the most recent deployment %{deploymentLink}."
|
||||
msgstr ""
|
||||
|
||||
msgid "This job is creating a deployment to %{environmentLink} and will overwrite the last %{deploymentLink}."
|
||||
msgid "This job is creating a deployment to %{environmentLink} and will overwrite the %{deploymentLink}."
|
||||
msgstr ""
|
||||
|
||||
msgid "This job is creating a deployment to %{environmentLink}."
|
||||
|
@ -7054,6 +7054,9 @@ msgstr ""
|
|||
msgid "issue boards"
|
||||
msgstr ""
|
||||
|
||||
msgid "latest deployment"
|
||||
msgstr ""
|
||||
|
||||
msgid "latest version"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -16,7 +16,9 @@ describe 'User browses a job', :js do
|
|||
visit(project_job_path(project, build))
|
||||
end
|
||||
|
||||
it 'erases the job log' do
|
||||
it 'erases the job log', :js do
|
||||
wait_for_requests
|
||||
|
||||
expect(page).to have_content("Job ##{build.id}")
|
||||
expect(page).to have_css('#build-trace')
|
||||
|
||||
|
@ -29,9 +31,7 @@ describe 'User browses a job', :js do
|
|||
expect(build.artifacts_file.exists?).to be_falsy
|
||||
expect(build.artifacts_metadata.exists?).to be_falsy
|
||||
|
||||
page.within('.erased') do
|
||||
expect(page).to have_content('Job has been erased')
|
||||
end
|
||||
expect(page).to have_content('Job has been erased')
|
||||
end
|
||||
|
||||
context 'with a failed job' do
|
||||
|
|
|
@ -369,39 +369,167 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when job starts environment' do
|
||||
let(:environment) { create(:environment, project: project) }
|
||||
let(:pipeline) { create(:ci_pipeline, project: project) }
|
||||
context 'when job starts environment', :js do
|
||||
let(:environment) { create(:environment, name: 'production', project: project) }
|
||||
|
||||
context 'job is successfull and has deployment' do
|
||||
let(:deployment) { create(:deployment) }
|
||||
let(:job) { create(:ci_build, :success, :trace_artifact, environment: environment.name, deployments: [deployment], pipeline: pipeline) }
|
||||
context 'job is successful and has deployment' do
|
||||
let(:build) { create(:ci_build, :success, :trace_live, environment: environment.name, pipeline: pipeline) }
|
||||
let!(:deployment) { create(:deployment, environment: environment, project: environment.project, deployable: build) }
|
||||
|
||||
before do
|
||||
visit project_job_path(project, build)
|
||||
wait_for_requests
|
||||
# scroll to the top of the page first
|
||||
execute_script "window.scrollTo(0,0)"
|
||||
end
|
||||
|
||||
it 'shows a link for the job' do
|
||||
visit project_job_path(project, job)
|
||||
|
||||
expect(page).to have_link environment.name
|
||||
end
|
||||
|
||||
it 'shows deployment message' do
|
||||
expect(page).to have_content 'This job is the most recent deployment'
|
||||
expect(find('.js-environment-link')['href']).to match("environments/#{environment.id}")
|
||||
end
|
||||
end
|
||||
|
||||
context 'job is complete and not successful' do
|
||||
let(:job) { create(:ci_build, :failed, :trace_artifact, environment: environment.name, pipeline: pipeline) }
|
||||
let(:build) { create(:ci_build, :failed, :trace_artifact, environment: environment.name, pipeline: pipeline) }
|
||||
|
||||
it 'shows a link for the job' do
|
||||
visit project_job_path(project, job)
|
||||
visit project_job_path(project, build)
|
||||
wait_for_requests
|
||||
# scroll to the top of the page first
|
||||
execute_script "window.scrollTo(0,0)"
|
||||
|
||||
expect(page).to have_link environment.name
|
||||
expect(find('.js-environment-link')['href']).to match("environments/#{environment.id}")
|
||||
end
|
||||
end
|
||||
|
||||
context 'job creates a new deployment' do
|
||||
let!(:deployment) { create(:deployment, environment: environment, sha: project.commit.id) }
|
||||
let(:job) { create(:ci_build, :success, :trace_artifact, environment: environment.name, pipeline: pipeline) }
|
||||
context 'deployment still not finished' do
|
||||
let(:build) { create(:ci_build, :success, environment: environment.name, pipeline: pipeline) }
|
||||
|
||||
it 'shows a link to latest deployment' do
|
||||
visit project_job_path(project, job)
|
||||
visit project_job_path(project, build)
|
||||
wait_for_all_requests
|
||||
# scroll to the top of the page first
|
||||
execute_script "window.scrollTo(0,0)"
|
||||
|
||||
expect(page).to have_link('latest deployment')
|
||||
expect(page).to have_link environment.name
|
||||
expect(page).to have_content 'This job is creating a deployment'
|
||||
expect(find('.js-environment-link')['href']).to match("environments/#{environment.id}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'environment info in job view', :js do
|
||||
before do
|
||||
visit project_job_path(project, job)
|
||||
wait_for_requests
|
||||
# scroll to the top of the page first
|
||||
execute_script "window.scrollTo(0,0)"
|
||||
end
|
||||
|
||||
context 'job with outdated deployment' do
|
||||
let(:job) { create(:ci_build, :success, :trace_artifact, environment: 'staging', pipeline: pipeline) }
|
||||
let(:second_build) { create(:ci_build, :success, :trace_artifact, environment: 'staging', pipeline: pipeline) }
|
||||
let(:environment) { create(:environment, name: 'staging', project: project) }
|
||||
let!(:first_deployment) { create(:deployment, environment: environment, deployable: job) }
|
||||
let!(:second_deployment) { create(:deployment, environment: environment, deployable: second_build) }
|
||||
|
||||
it 'shows deployment message' do
|
||||
expected_text = 'This job is an out-of-date deployment ' \
|
||||
"to staging. View the most recent deployment ##{second_deployment.iid}."
|
||||
|
||||
expect(page).to have_css('.environment-information', text: expected_text)
|
||||
end
|
||||
|
||||
it 'renders a link to the most recent deployment' do
|
||||
expect(find('.js-environment-link')['href']).to match("environments/#{environment.id}")
|
||||
expect(find('.js-job-deployment-link')['href']).to include(second_deployment.deployable.project.path, second_deployment.deployable_id.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
context 'job failed to deploy' do
|
||||
let(:job) { create(:ci_build, :failed, :trace_artifact, environment: 'staging', pipeline: pipeline) }
|
||||
let!(:environment) { create(:environment, name: 'staging', project: project) }
|
||||
|
||||
it 'shows deployment message' do
|
||||
expected_text = 'The deployment of this job to staging did not succeed.'
|
||||
|
||||
expect(page).to have_css(
|
||||
'.environment-information', text: expected_text)
|
||||
end
|
||||
end
|
||||
|
||||
context 'job will deploy' do
|
||||
let(:job) { create(:ci_build, :running, :trace_live, environment: 'staging', pipeline: pipeline) }
|
||||
|
||||
context 'when environment exists' do
|
||||
let!(:environment) { create(:environment, name: 'staging', project: project) }
|
||||
|
||||
it 'shows deployment message' do
|
||||
expected_text = 'This job is creating a deployment to staging'
|
||||
|
||||
expect(page).to have_css(
|
||||
'.environment-information', text: expected_text)
|
||||
expect(find('.js-environment-link')['href']).to match("environments/#{environment.id}")
|
||||
end
|
||||
|
||||
context 'when it has deployment' do
|
||||
let!(:deployment) { create(:deployment, environment: environment) }
|
||||
|
||||
it 'shows that deployment will be overwritten' do
|
||||
expected_text = 'This job is creating a deployment to staging'
|
||||
|
||||
expect(page).to have_css(
|
||||
'.environment-information', text: expected_text)
|
||||
expect(page).to have_css(
|
||||
'.environment-information', text: 'latest deployment')
|
||||
expect(find('.js-environment-link')['href']).to match("environments/#{environment.id}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when environment does not exist' do
|
||||
let!(:environment) { create(:environment, name: 'staging', project: project) }
|
||||
|
||||
it 'shows deployment message' do
|
||||
expected_text = 'This job is creating a deployment to staging'
|
||||
|
||||
expect(page).to have_css(
|
||||
'.environment-information', text: expected_text)
|
||||
expect(page).not_to have_css(
|
||||
'.environment-information', text: 'latest deployment')
|
||||
expect(find('.js-environment-link')['href']).to match("environments/#{environment.id}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'job that failed to deploy and environment has not been created' do
|
||||
let(:job) { create(:ci_build, :failed, :trace_artifact, environment: 'staging', pipeline: pipeline) }
|
||||
let!(:environment) { create(:environment, name: 'staging', project: project) }
|
||||
|
||||
it 'shows deployment message' do
|
||||
expected_text = 'The deployment of this job to staging did not succeed'
|
||||
|
||||
expect(page).to have_css(
|
||||
'.environment-information', text: expected_text)
|
||||
end
|
||||
end
|
||||
|
||||
context 'job that will deploy and environment has not been created' do
|
||||
let(:job) { create(:ci_build, :running, :trace_live, environment: 'staging', pipeline: pipeline) }
|
||||
let!(:environment) { create(:environment, name: 'staging', project: project) }
|
||||
|
||||
it 'shows deployment message' do
|
||||
expected_text = 'This job is creating a deployment to staging'
|
||||
|
||||
expect(page).to have_css(
|
||||
'.environment-information', text: expected_text)
|
||||
expect(page).not_to have_css(
|
||||
'.environment-information', text: 'latest deployment')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,19 +5,16 @@ import mountComponent from '../../helpers/vue_mount_component_helper';
|
|||
describe('Environments block', () => {
|
||||
const Component = Vue.extend(component);
|
||||
let vm;
|
||||
const icon = {
|
||||
const status = {
|
||||
group: 'success',
|
||||
icon: 'status_success',
|
||||
label: 'passed',
|
||||
text: 'passed',
|
||||
tooltip: 'passed',
|
||||
};
|
||||
const deployment = {
|
||||
path: 'deployment',
|
||||
name: 'deployment name',
|
||||
};
|
||||
|
||||
const environment = {
|
||||
path: '/environment',
|
||||
environment_path: '/environment',
|
||||
name: 'environment',
|
||||
};
|
||||
|
||||
|
@ -25,15 +22,14 @@ describe('Environments block', () => {
|
|||
vm.$destroy();
|
||||
});
|
||||
|
||||
describe('with latest deployment', () => {
|
||||
describe('with last deployment', () => {
|
||||
it('renders info for most recent deployment', () => {
|
||||
vm = mountComponent(Component, {
|
||||
deploymentStatus: {
|
||||
status: 'latest',
|
||||
icon,
|
||||
deployment,
|
||||
status: 'last',
|
||||
environment,
|
||||
},
|
||||
iconStatus: status,
|
||||
});
|
||||
|
||||
expect(vm.$el.textContent.trim()).toEqual(
|
||||
|
@ -48,17 +44,17 @@ describe('Environments block', () => {
|
|||
vm = mountComponent(Component, {
|
||||
deploymentStatus: {
|
||||
status: 'out_of_date',
|
||||
icon,
|
||||
deployment,
|
||||
environment: Object.assign({}, environment, {
|
||||
last_deployment: { name: 'deployment', path: 'last_deployment' },
|
||||
last_deployment: { iid: 'deployment', deployable: { build_path: 'bar' } },
|
||||
}),
|
||||
},
|
||||
iconStatus: status,
|
||||
});
|
||||
|
||||
expect(vm.$el.textContent.trim()).toEqual(
|
||||
'This job is an out-of-date deployment to environment. View the most recent deployment deployment.',
|
||||
'This job is an out-of-date deployment to environment. View the most recent deployment #deployment.',
|
||||
);
|
||||
expect(vm.$el.querySelector('.js-job-deployment-link').getAttribute('href')).toEqual('bar');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -67,10 +63,9 @@ describe('Environments block', () => {
|
|||
vm = mountComponent(Component, {
|
||||
deploymentStatus: {
|
||||
status: 'out_of_date',
|
||||
icon,
|
||||
deployment: null,
|
||||
environment,
|
||||
},
|
||||
iconStatus: status,
|
||||
});
|
||||
|
||||
expect(vm.$el.textContent.trim()).toEqual(
|
||||
|
@ -85,10 +80,9 @@ describe('Environments block', () => {
|
|||
vm = mountComponent(Component, {
|
||||
deploymentStatus: {
|
||||
status: 'failed',
|
||||
icon,
|
||||
deployment: null,
|
||||
environment,
|
||||
},
|
||||
iconStatus: status,
|
||||
});
|
||||
|
||||
expect(vm.$el.textContent.trim()).toEqual(
|
||||
|
@ -99,21 +93,24 @@ describe('Environments block', () => {
|
|||
|
||||
describe('creating deployment', () => {
|
||||
describe('with last deployment', () => {
|
||||
it('renders info about creating deployment and overriding lastest deployment', () => {
|
||||
it('renders info about creating deployment and overriding latest deployment', () => {
|
||||
vm = mountComponent(Component, {
|
||||
deploymentStatus: {
|
||||
status: 'creating',
|
||||
icon,
|
||||
deployment,
|
||||
environment: Object.assign({}, environment, {
|
||||
last_deployment: { name: 'deployment', path: 'last_deployment' },
|
||||
last_deployment: {
|
||||
iid: 'deployment',
|
||||
deployable: { build_path: 'foo' },
|
||||
},
|
||||
}),
|
||||
},
|
||||
iconStatus: status,
|
||||
});
|
||||
|
||||
expect(vm.$el.textContent.trim()).toEqual(
|
||||
'This job is creating a deployment to environment and will overwrite the last deployment.',
|
||||
'This job is creating a deployment to environment and will overwrite the latest deployment.',
|
||||
);
|
||||
expect(vm.$el.querySelector('.js-job-deployment-link').getAttribute('href')).toEqual('foo');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -122,10 +119,9 @@ describe('Environments block', () => {
|
|||
vm = mountComponent(Component, {
|
||||
deploymentStatus: {
|
||||
status: 'creating',
|
||||
icon,
|
||||
deployment: null,
|
||||
environment,
|
||||
},
|
||||
iconStatus: status,
|
||||
});
|
||||
|
||||
expect(vm.$el.textContent.trim()).toEqual(
|
||||
|
@ -133,5 +129,18 @@ describe('Environments block', () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('without environment', () => {
|
||||
it('does not render environment link', () => {
|
||||
vm = mountComponent(Component, {
|
||||
deploymentStatus: {
|
||||
status: 'creating',
|
||||
environment: null,
|
||||
},
|
||||
iconStatus: status,
|
||||
});
|
||||
expect(vm.$el.querySelector('.js-environment-link')).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
import Vue from 'vue';
|
||||
import headerComponent from '~/jobs/components/header.vue';
|
||||
import mountComponent from 'spec/helpers/vue_mount_component_helper';
|
||||
|
||||
describe('Job details header', () => {
|
||||
let HeaderComponent;
|
||||
let vm;
|
||||
let props;
|
||||
|
||||
beforeEach(() => {
|
||||
HeaderComponent = Vue.extend(headerComponent);
|
||||
|
||||
const threeWeeksAgo = new Date();
|
||||
threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21);
|
||||
|
||||
const twoDaysAgo = new Date();
|
||||
twoDaysAgo.setDate(twoDaysAgo.getDate() - 2);
|
||||
|
||||
props = {
|
||||
job: {
|
||||
status: {
|
||||
group: 'failed',
|
||||
icon: 'status_failed',
|
||||
label: 'failed',
|
||||
text: 'failed',
|
||||
details_path: 'path',
|
||||
},
|
||||
id: 123,
|
||||
created_at: threeWeeksAgo.toISOString(),
|
||||
user: {
|
||||
web_url: 'path',
|
||||
name: 'Foo',
|
||||
username: 'foobar',
|
||||
email: 'foo@bar.com',
|
||||
avatar_url: 'link',
|
||||
},
|
||||
started: twoDaysAgo.toISOString(),
|
||||
new_issue_path: 'path',
|
||||
},
|
||||
isLoading: false,
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vm.$destroy();
|
||||
});
|
||||
|
||||
describe('job reason', () => {
|
||||
it('should not render the reason when reason is absent', () => {
|
||||
vm = mountComponent(HeaderComponent, props);
|
||||
|
||||
expect(vm.shouldRenderReason).toBe(false);
|
||||
});
|
||||
|
||||
it('should render the reason when reason is present', () => {
|
||||
props.job.callout_message = 'There is an unknown failure, please try again';
|
||||
|
||||
vm = mountComponent(HeaderComponent, props);
|
||||
|
||||
expect(vm.shouldRenderReason).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('triggered job', () => {
|
||||
beforeEach(() => {
|
||||
vm = mountComponent(HeaderComponent, props);
|
||||
});
|
||||
|
||||
it('should render provided job information', () => {
|
||||
expect(
|
||||
vm.$el
|
||||
.querySelector('.header-main-content')
|
||||
.textContent.replace(/\s+/g, ' ')
|
||||
.trim(),
|
||||
).toEqual('failed Job #123 triggered 2 days ago by Foo');
|
||||
});
|
||||
|
||||
it('should render new issue link', () => {
|
||||
expect(vm.$el.querySelector('.js-new-issue').getAttribute('href')).toEqual(
|
||||
props.job.new_issue_path,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('created job', () => {
|
||||
it('should render created key', () => {
|
||||
props.job.started = false;
|
||||
vm = mountComponent(HeaderComponent, props);
|
||||
|
||||
expect(
|
||||
vm.$el
|
||||
.querySelector('.header-main-content')
|
||||
.textContent.replace(/\s+/g, ' ')
|
||||
.trim(),
|
||||
).toEqual('failed Job #123 created 3 weeks ago by Foo');
|
||||
});
|
||||
});
|
||||
});
|
185
spec/javascripts/jobs/components/job_app_spec.js
Normal file
185
spec/javascripts/jobs/components/job_app_spec.js
Normal file
|
@ -0,0 +1,185 @@
|
|||
import Vue from 'vue';
|
||||
import jobApp from '~/jobs/components/job_app.vue';
|
||||
import createStore from '~/jobs/store';
|
||||
import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
|
||||
|
||||
describe('Job App ', () => {
|
||||
const Component = Vue.extend(jobApp);
|
||||
let store;
|
||||
let vm;
|
||||
|
||||
const threeWeeksAgo = new Date();
|
||||
threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21);
|
||||
|
||||
const twoDaysAgo = new Date();
|
||||
twoDaysAgo.setDate(twoDaysAgo.getDate() - 2);
|
||||
|
||||
const job = {
|
||||
status: {
|
||||
group: 'failed',
|
||||
icon: 'status_failed',
|
||||
label: 'failed',
|
||||
text: 'failed',
|
||||
details_path: 'path',
|
||||
},
|
||||
id: 123,
|
||||
created_at: threeWeeksAgo.toISOString(),
|
||||
user: {
|
||||
web_url: 'path',
|
||||
name: 'Foo',
|
||||
username: 'foobar',
|
||||
email: 'foo@bar.com',
|
||||
avatar_url: 'link',
|
||||
},
|
||||
started: twoDaysAgo.toISOString(),
|
||||
new_issue_path: 'path',
|
||||
runners: {
|
||||
available: false,
|
||||
},
|
||||
tags: ['docker'],
|
||||
};
|
||||
|
||||
const props = {
|
||||
runnerHelpUrl: 'help/runners',
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
store = createStore();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vm.$destroy();
|
||||
});
|
||||
|
||||
describe('Header section', () => {
|
||||
describe('job callout message', () => {
|
||||
it('should not render the reason when reason is absent', () => {
|
||||
store.dispatch('receiveJobSuccess', job);
|
||||
|
||||
vm = mountComponentWithStore(Component, {
|
||||
props,
|
||||
store,
|
||||
});
|
||||
|
||||
expect(vm.shouldRenderCalloutMessage).toBe(false);
|
||||
});
|
||||
|
||||
it('should render the reason when reason is present', () => {
|
||||
store.dispatch(
|
||||
'receiveJobSuccess',
|
||||
Object.assign({}, job, {
|
||||
callout_message: 'There is an unknown failure, please try again',
|
||||
}),
|
||||
);
|
||||
|
||||
vm = mountComponentWithStore(Component, {
|
||||
props,
|
||||
store,
|
||||
});
|
||||
|
||||
expect(vm.shouldRenderCalloutMessage).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('triggered job', () => {
|
||||
beforeEach(() => {
|
||||
store.dispatch('receiveJobSuccess', job);
|
||||
|
||||
vm = mountComponentWithStore(Component, {
|
||||
props,
|
||||
store,
|
||||
});
|
||||
});
|
||||
|
||||
it('should render provided job information', () => {
|
||||
expect(
|
||||
vm.$el
|
||||
.querySelector('.header-main-content')
|
||||
.textContent.replace(/\s+/g, ' ')
|
||||
.trim(),
|
||||
).toEqual('failed Job #123 triggered 2 days ago by Foo');
|
||||
});
|
||||
|
||||
it('should render new issue link', () => {
|
||||
expect(vm.$el.querySelector('.js-new-issue').getAttribute('href')).toEqual(
|
||||
job.new_issue_path,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('created job', () => {
|
||||
it('should render created key', () => {
|
||||
store.dispatch('receiveJobSuccess', Object.assign({}, job, { started: false }));
|
||||
|
||||
vm = mountComponentWithStore(Component, {
|
||||
props,
|
||||
store,
|
||||
});
|
||||
|
||||
expect(
|
||||
vm.$el
|
||||
.querySelector('.header-main-content')
|
||||
.textContent.replace(/\s+/g, ' ')
|
||||
.trim(),
|
||||
).toEqual('failed Job #123 created 3 weeks ago by Foo');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('stuck block', () => {
|
||||
it('renders stuck block when there are no runners', () => {
|
||||
store.dispatch(
|
||||
'receiveJobSuccess',
|
||||
Object.assign({}, job, {
|
||||
status: {
|
||||
group: 'pending',
|
||||
icon: 'status_pending',
|
||||
label: 'pending',
|
||||
text: 'pending',
|
||||
details_path: 'path',
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
vm = mountComponentWithStore(Component, {
|
||||
props,
|
||||
store,
|
||||
});
|
||||
|
||||
expect(vm.$el.querySelector('.js-job-stuck')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('renders tags in stuck block when there are no runners', () => {
|
||||
store.dispatch(
|
||||
'receiveJobSuccess',
|
||||
Object.assign({}, job, {
|
||||
status: {
|
||||
group: 'pending',
|
||||
icon: 'status_pending',
|
||||
label: 'pending',
|
||||
text: 'pending',
|
||||
details_path: 'path',
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
vm = mountComponentWithStore(Component, {
|
||||
props,
|
||||
store,
|
||||
});
|
||||
|
||||
expect(vm.$el.querySelector('.js-job-stuck').textContent).toContain(job.tags[0]);
|
||||
});
|
||||
|
||||
it(' does not renders stuck block when there are no runners', () => {
|
||||
store.dispatch('receiveJobSuccess', Object.assign({}, job, { runners: { available: true } }));
|
||||
|
||||
vm = mountComponentWithStore(Component, {
|
||||
props,
|
||||
store,
|
||||
});
|
||||
|
||||
expect(vm.$el.querySelector('.js-job-stuck')).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
121
spec/javascripts/jobs/store/getters_spec.js
Normal file
121
spec/javascripts/jobs/store/getters_spec.js
Normal file
|
@ -0,0 +1,121 @@
|
|||
import * as getters from '~/jobs/store/getters';
|
||||
import state from '~/jobs/store/state';
|
||||
|
||||
describe('Job Store Getters', () => {
|
||||
let localState;
|
||||
|
||||
beforeEach(() => {
|
||||
localState = state();
|
||||
});
|
||||
|
||||
describe('headerActions', () => {
|
||||
describe('with new issue path', () => {
|
||||
it('returns an array with action to create a new issue', () => {
|
||||
localState.job.new_issue_path = 'issues/new';
|
||||
|
||||
expect(getters.headerActions(localState)).toEqual([
|
||||
{
|
||||
label: 'New issue',
|
||||
path: localState.job.new_issue_path,
|
||||
cssClass:
|
||||
'js-new-issue btn btn-success btn-inverted d-none d-md-block d-lg-block d-xl-block',
|
||||
type: 'link',
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('without new issue path', () => {
|
||||
it('returns an empty array', () => {
|
||||
expect(getters.headerActions(localState)).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('headerTime', () => {
|
||||
describe('when the job has started key', () => {
|
||||
it('returns started key', () => {
|
||||
const started = '2018-08-31T16:20:49.023Z';
|
||||
localState.job.started = started;
|
||||
|
||||
expect(getters.headerTime(localState)).toEqual(started);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the job does not have started key', () => {
|
||||
it('returns created_at key', () => {
|
||||
const created = '2018-08-31T16:20:49.023Z';
|
||||
localState.job.created_at = created;
|
||||
expect(getters.headerTime(localState)).toEqual(created);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('shouldRenderCalloutMessage', () => {
|
||||
describe('with status and callout message', () => {
|
||||
it('returns true', () => {
|
||||
localState.job.callout_message = 'Callout message';
|
||||
localState.job.status = { icon: 'passed' };
|
||||
|
||||
expect(getters.shouldRenderCalloutMessage(localState)).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('without status & with callout message', () => {
|
||||
it('returns false', () => {
|
||||
localState.job.callout_message = 'Callout message';
|
||||
expect(getters.shouldRenderCalloutMessage(localState)).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with status & without callout message', () => {
|
||||
it('returns false', () => {
|
||||
localState.job.status = { icon: 'passed' };
|
||||
|
||||
expect(getters.shouldRenderCalloutMessage(localState)).toEqual(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('jobHasStarted', () => {
|
||||
describe('when started equals false', () => {
|
||||
it('returns false', () => {
|
||||
localState.job.started = false;
|
||||
expect(getters.jobHasStarted(localState)).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when started equals string', () => {
|
||||
it('returns true', () => {
|
||||
localState.job.started = '2018-08-31T16:20:49.023Z';
|
||||
expect(getters.jobHasStarted(localState)).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasEnvironment', () => {
|
||||
describe('without `deployment_status`', () => {
|
||||
it('returns false', () => {
|
||||
expect(getters.hasEnvironment(localState)).toEqual(false);
|
||||
});
|
||||
});
|
||||
describe('with an empty object for `deployment_status`', () => {
|
||||
it('returns false', () => {
|
||||
localState.job.deployment_status = {};
|
||||
expect(getters.hasEnvironment(localState)).toEqual(false);
|
||||
});
|
||||
});
|
||||
describe('when `deployment_status` is defined and not empty', () => {
|
||||
it('returns true', () => {
|
||||
localState.job.deployment_status = {
|
||||
status: 'creating',
|
||||
environment: {
|
||||
last_deployment: {},
|
||||
},
|
||||
};
|
||||
|
||||
expect(getters.hasEnvironment(localState)).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -18,161 +18,6 @@ describe 'projects/jobs/show' do
|
|||
allow(view).to receive(:can?).and_return(true)
|
||||
end
|
||||
|
||||
describe 'environment info in job view' do
|
||||
context 'job with latest deployment' do
|
||||
let(:build) do
|
||||
create(:ci_build, :success, :trace_artifact, environment: 'staging')
|
||||
end
|
||||
|
||||
before do
|
||||
create(:environment, name: 'staging')
|
||||
create(:deployment, deployable: build)
|
||||
end
|
||||
|
||||
it 'shows deployment message' do
|
||||
expected_text = 'This job is the most recent deployment'
|
||||
render
|
||||
|
||||
expect(rendered).to have_css(
|
||||
'.environment-information', text: expected_text)
|
||||
end
|
||||
end
|
||||
|
||||
context 'job with outdated deployment' do
|
||||
let(:build) do
|
||||
create(:ci_build, :success, :trace_artifact, environment: 'staging', pipeline: pipeline)
|
||||
end
|
||||
|
||||
let(:second_build) do
|
||||
create(:ci_build, :success, :trace_artifact, environment: 'staging', pipeline: pipeline)
|
||||
end
|
||||
|
||||
let(:environment) do
|
||||
create(:environment, name: 'staging', project: project)
|
||||
end
|
||||
|
||||
let!(:first_deployment) do
|
||||
create(:deployment, environment: environment, deployable: build)
|
||||
end
|
||||
|
||||
let!(:second_deployment) do
|
||||
create(:deployment, environment: environment, deployable: second_build)
|
||||
end
|
||||
|
||||
it 'shows deployment message' do
|
||||
expected_text = 'This job is an out-of-date deployment ' \
|
||||
"to staging.\nView the most recent deployment ##{second_deployment.iid}."
|
||||
render
|
||||
|
||||
expect(rendered).to have_css('.environment-information', text: expected_text)
|
||||
end
|
||||
end
|
||||
|
||||
context 'job failed to deploy' do
|
||||
let(:build) do
|
||||
create(:ci_build, :failed, :trace_artifact, environment: 'staging', pipeline: pipeline)
|
||||
end
|
||||
|
||||
let!(:environment) do
|
||||
create(:environment, name: 'staging', project: project)
|
||||
end
|
||||
|
||||
it 'shows deployment message' do
|
||||
expected_text = 'The deployment of this job to staging did not succeed.'
|
||||
render
|
||||
|
||||
expect(rendered).to have_css(
|
||||
'.environment-information', text: expected_text)
|
||||
end
|
||||
end
|
||||
|
||||
context 'job will deploy' do
|
||||
let(:build) do
|
||||
create(:ci_build, :running, :trace_live, environment: 'staging', pipeline: pipeline)
|
||||
end
|
||||
|
||||
context 'when environment exists' do
|
||||
let!(:environment) do
|
||||
create(:environment, name: 'staging', project: project)
|
||||
end
|
||||
|
||||
it 'shows deployment message' do
|
||||
expected_text = 'This job is creating a deployment to staging'
|
||||
render
|
||||
|
||||
expect(rendered).to have_css(
|
||||
'.environment-information', text: expected_text)
|
||||
end
|
||||
|
||||
context 'when it has deployment' do
|
||||
let!(:deployment) do
|
||||
create(:deployment, environment: environment)
|
||||
end
|
||||
|
||||
it 'shows that deployment will be overwritten' do
|
||||
expected_text = 'This job is creating a deployment to staging'
|
||||
render
|
||||
|
||||
expect(rendered).to have_css(
|
||||
'.environment-information', text: expected_text)
|
||||
expect(rendered).to have_css(
|
||||
'.environment-information', text: 'latest deployment')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when environment does not exist' do
|
||||
it 'shows deployment message' do
|
||||
expected_text = 'This job is creating a deployment to staging'
|
||||
render
|
||||
|
||||
expect(rendered).to have_css(
|
||||
'.environment-information', text: expected_text)
|
||||
expect(rendered).not_to have_css(
|
||||
'.environment-information', text: 'latest deployment')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'job that failed to deploy and environment has not been created' do
|
||||
let(:build) do
|
||||
create(:ci_build, :failed, :trace_artifact, environment: 'staging', pipeline: pipeline)
|
||||
end
|
||||
|
||||
let!(:environment) do
|
||||
create(:environment, name: 'staging', project: project)
|
||||
end
|
||||
|
||||
it 'shows deployment message' do
|
||||
expected_text = 'The deployment of this job to staging did not succeed'
|
||||
render
|
||||
|
||||
expect(rendered).to have_css(
|
||||
'.environment-information', text: expected_text)
|
||||
end
|
||||
end
|
||||
|
||||
context 'job that will deploy and environment has not been created' do
|
||||
let(:build) do
|
||||
create(:ci_build, :running, :trace_live, environment: 'staging', pipeline: pipeline)
|
||||
end
|
||||
|
||||
let!(:environment) do
|
||||
create(:environment, name: 'staging', project: project)
|
||||
end
|
||||
|
||||
it 'shows deployment message' do
|
||||
expected_text = 'This job is creating a deployment to staging'
|
||||
render
|
||||
|
||||
expect(rendered).to have_css(
|
||||
'.environment-information', text: expected_text)
|
||||
expect(rendered).not_to have_css(
|
||||
'.environment-information', text: 'latest deployment')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when job is running' do
|
||||
let(:build) { create(:ci_build, :trace_live, :running, pipeline: pipeline) }
|
||||
|
||||
|
|
Loading…
Reference in a new issue