Skip to content
Snippets Groups Projects
Commit b4da2e19 authored by Savas Vedova's avatar Savas Vedova Committed by Andrew Fontaine
Browse files

Migrate environment header to vue

parent edab8275
No related branches found
No related tags found
No related merge requests found
Showing
with 553 additions and 157 deletions
<script>
import { GlButton, GlModalDirective, GlTooltipDirective as GlTooltip, GlSprintf } from '@gitlab/ui';
import csrf from '~/lib/utils/csrf';
import { __, s__ } from '~/locale';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
import DeleteEnvironmentModal from './delete_environment_modal.vue';
import StopEnvironmentModal from './stop_environment_modal.vue';
export default {
name: 'EnvironmentsDetailHeader',
csrf,
components: {
GlButton,
GlSprintf,
TimeAgo,
DeleteEnvironmentModal,
StopEnvironmentModal,
},
directives: {
GlModalDirective,
GlTooltip,
},
mixins: [timeagoMixin],
props: {
environment: {
type: Object,
required: true,
},
canReadEnvironment: {
type: Boolean,
required: true,
},
canAdminEnvironment: {
type: Boolean,
required: true,
},
canUpdateEnvironment: {
type: Boolean,
required: true,
},
canDestroyEnvironment: {
type: Boolean,
required: true,
},
canStopEnvironment: {
type: Boolean,
required: true,
},
cancelAutoStopPath: {
type: String,
required: false,
default: '',
},
metricsPath: {
type: String,
required: false,
default: '',
},
updatePath: {
type: String,
required: false,
default: '',
},
terminalPath: {
type: String,
required: false,
default: '',
},
},
i18n: {
autoStopAtText: s__('Environments|Auto stops %{autoStopAt}'),
metricsButtonTitle: __('See metrics'),
metricsButtonText: __('Monitoring'),
editButtonText: __('Edit'),
stopButtonText: s__('Environments|Stop'),
deleteButtonText: s__('Environments|Delete'),
externalButtonTitle: s__('Environments|Open live environment'),
externalButtonText: __('View deployment'),
cancelAutoStopButtonTitle: __('Prevent environment from auto-stopping'),
},
computed: {
shouldShowCancelAutoStopButton() {
return this.environment.isAvailable && Boolean(this.environment.autoStopAt);
},
shouldShowExternalUrlButton() {
return this.canReadEnvironment && Boolean(this.environment.externalUrl);
},
shouldShowStopButton() {
return this.canStopEnvironment && this.environment.isAvailable;
},
shouldShowTerminalButton() {
return this.canAdminEnvironment && this.environment.hasTerminals;
},
},
};
</script>
<template>
<header class="top-area gl-justify-content-between">
<div class="gl-display-flex gl-flex-grow-1 gl-align-items-center">
<h3 class="page-title">
{{ environment.name }}
</h3>
<p v-if="shouldShowCancelAutoStopButton" class="gl-mb-0 gl-ml-3" data-testid="auto-stops-at">
<gl-sprintf :message="$options.i18n.autoStopAtText">
<template #autoStopAt>
<time-ago :time="environment.autoStopAt" />
</template>
</gl-sprintf>
</p>
</div>
<div class="nav-controls gl-my-1">
<form method="POST" :action="cancelAutoStopPath" data-testid="cancel-auto-stop-form">
<input :value="$options.csrf.token" type="hidden" name="authenticity_token" />
<gl-button
v-if="shouldShowCancelAutoStopButton"
v-gl-tooltip.hover
data-testid="cancel-auto-stop-button"
:title="$options.i18n.cancelAutoStopButtonTitle"
type="submit"
icon="thumbtack"
/>
</form>
<gl-button
v-if="shouldShowTerminalButton"
data-testid="terminal-button"
:href="terminalPath"
icon="terminal"
/>
<gl-button
v-if="shouldShowExternalUrlButton"
v-gl-tooltip.hover
data-testid="external-url-button"
:title="$options.i18n.externalButtonTitle"
:href="environment.externalUrl"
icon="external-link"
target="_blank"
>{{ $options.i18n.externalButtonText }}</gl-button
>
<gl-button
v-if="canReadEnvironment"
data-testid="metrics-button"
:href="metricsPath"
:title="$options.i18n.metricsButtonTitle"
icon="chart"
class="gl-mr-2"
>
{{ $options.i18n.metricsButtonText }}
</gl-button>
<gl-button v-if="canUpdateEnvironment" data-testid="edit-button" :href="updatePath">
{{ $options.i18n.editButtonText }}
</gl-button>
<gl-button
v-if="shouldShowStopButton"
v-gl-modal-directive="'stop-environment-modal'"
data-testid="stop-button"
icon="stop"
variant="danger"
>
{{ $options.i18n.stopButtonText }}
</gl-button>
<gl-button
v-if="canDestroyEnvironment"
v-gl-modal-directive="'delete-environment-modal'"
data-testid="destroy-button"
variant="danger"
>
{{ $options.i18n.deleteButtonText }}
</gl-button>
</div>
<delete-environment-modal v-if="canDestroyEnvironment" :environment="environment" />
<stop-environment-modal v-if="shouldShowStopButton" :environment="environment" />
</header>
</template>
Loading
Loading
@@ -108,7 +108,19 @@ export default {
 
this.service
.postAction(endpoint)
.then(() => this.fetchEnvironments())
.then(() => {
// Originally, the detail page buttons were implemented as <form>s that POSTed
// to the server, which would naturally result in a page refresh.
// When environment details page was converted to Vue, the buttons were updated to trigger
// HTTP requests using `axios`, which did not cause a refresh on completion.
// To preserve the original behavior, we manually reload the page when
// network requests complete successfully.
if (!this.isDetailView) {
this.fetchEnvironments();
} else {
window.location.reload();
}
})
.catch((err) => {
this.isLoading = false;
createFlash({
Loading
Loading
import Vue from 'vue';
import DeleteEnvironmentModal from './components/delete_environment_modal.vue';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import EnvironmentsDetailHeader from './components/environments_detail_header.vue';
import environmentsMixin from './mixins/environments_mixin';
 
export default () => {
const el = document.getElementById('delete-environment-modal');
export const initHeader = () => {
const el = document.getElementById('environments-detail-view-header');
const container = document.getElementById('environments-detail-view');
const dataset = convertObjectPropsToCamelCase(JSON.parse(container.dataset.details));
 
return new Vue({
el,
components: {
DeleteEnvironmentModal,
},
mixins: [environmentsMixin],
data() {
const environment = JSON.parse(JSON.stringify(container.dataset));
environment.delete_path = environment.deletePath;
environment.onSingleEnvironmentPage = true;
const environment = {
name: dataset.name,
id: Number(dataset.id),
externalUrl: dataset.externalUrl,
isAvailable: dataset.isEnvironmentAvailable,
hasTerminals: dataset.hasTerminals,
autoStopAt: dataset.autoStopAt,
onSingleEnvironmentPage: true,
// TODO: These two props are snake_case because the environments_mixin file uses
// them and the mixin is imported in several files. It would be nice to conver them to camelCase.
stop_path: dataset.environmentStopPath,
delete_path: dataset.environmentDeletePath,
};
 
return {
environment,
};
},
render(createElement) {
return createElement('delete-environment-modal', {
return createElement(EnvironmentsDetailHeader, {
props: {
environment: this.environment,
canDestroyEnvironment: dataset.canDestroyEnvironment,
canUpdateEnvironment: dataset.canUpdateEnvironment,
canReadEnvironment: dataset.canReadEnvironment,
canStopEnvironment: dataset.canStopEnvironment,
canAdminEnvironment: dataset.canAdminEnvironment,
cancelAutoStopPath: dataset.environmentCancelAutoStopPath,
terminalPath: dataset.environmentTerminalPath,
metricsPath: dataset.environmentMetricsPath,
updatePath: dataset.environmentEditPath,
},
});
},
Loading
Loading
import initShowEnvironment from '~/environments/mount_show';
import { initHeader } from '~/environments/mount_show';
 
initShowEnvironment();
initHeader();
Loading
Loading
@@ -65,4 +65,31 @@ def render_deployment_status(deployment)
content_tag(:span, text, class: klass)
end
end
def environments_detail_data(user, project, environment)
{
name: environment.name,
id: environment.id,
external_url: environment.external_url,
can_update_environment: can?(current_user, :update_environment, environment),
can_destroy_environment: can_destroy_environment?(environment),
can_read_environment: can?(current_user, :read_environment, environment),
can_stop_environment: can?(current_user, :stop_environment, environment),
can_admin_environment: can?(current_user, :admin_environment, project),
environment_metrics_path: environment_metrics_path(environment),
environments_fetch_path: project_environments_path(project, format: :json),
environment_edit_path: edit_project_environment_path(project, environment),
environment_stop_path: stop_project_environment_path(project, environment),
environment_delete_path: environment_delete_path(environment),
environment_cancel_auto_stop_path: cancel_auto_stop_project_environment_path(project, environment),
environment_terminal_path: terminal_project_environment_path(project, environment),
has_terminals: environment.has_terminals?,
is_environment_available: environment.available?,
auto_stop_at: environment.auto_stop_at
}
end
def environments_detail_data_json(user, project, environment)
environments_detail_data(user, project, environment).to_json
end
end
- if environment.external_url && can?(current_user, :read_environment, environment)
= link_to environment.external_url, target: '_blank', rel: 'noopener noreferrer', class: 'gl-button btn external-url has-tooltip qa-view-deployment', title: s_('Environments|Open live environment') do
= sprite_icon('external-link')
= _("View deployment")
- environment = local_assigns.fetch(:environment)
- return unless can?(current_user, :read_environment, environment)
= link_to environment_metrics_path(environment), title: _('See metrics'), class: 'gl-button btn metrics-button' do
= sprite_icon('chart', css_class: 'gl-mr-2')
= _("Monitoring")
- if environment.auto_stop_at? && environment.available?
= button_to cancel_auto_stop_project_environment_path(environment.project, environment), class: 'gl-button btn btn-secondary has-tooltip', title: _('Prevent environment from auto-stopping') do
= sprite_icon('thumbtack')
- if environment.has_terminals? && can?(current_user, :admin_environment, @project)
= link_to terminal_project_environment_path(@project, environment), class: 'gl-button btn terminal-button' do
= sprite_icon('terminal')
Loading
Loading
@@ -5,58 +5,8 @@
- add_page_specific_style 'page_bundles/environments'
- add_page_specific_style 'page_bundles/ci_status'
 
#environments-detail-view{ data: { name: @environment.name, id: @environment.id, delete_path: environment_delete_path(@environment)} }
- if @environment.available? && can?(current_user, :stop_environment, @environment)
#stop-environment-modal.modal.fade{ tabindex: -1 }
.modal-dialog
.modal-content
.modal-header
%h4.modal-title.d-flex.mw-100
= s_("Environments|Stopping")
%span.has-tooltip.text-truncate.ml-1.mr-1.flex-fill{ title: @environment.name, data: { container: '#stop-environment-modal' } }
#{@environment.name}?
.modal-body
%p= s_('Environments|Are you sure you want to stop this environment?')
- unless @environment.stop_action_available?
.warning_message
%p= s_('Environments|Note that this action will stop the environment, but it will %{emphasis_start}not%{emphasis_end} have an effect on any existing deployment due to no “stop environment action” being defined in the %{ci_config_link_start}.gitlab-ci.yml%{ci_config_link_end} file.').html_safe % { emphasis_start: '<strong>'.html_safe,
emphasis_end: '</strong>'.html_safe,
ci_config_link_start: '<a href="https://docs.gitlab.com/ee/ci/yaml/" target="_blank" rel="noopener noreferrer">'.html_safe,
ci_config_link_end: '</a>'.html_safe }
%a{ href: 'https://docs.gitlab.com/ee/ci/environments/index.html#stopping-an-environment',
target: '_blank',
rel: 'noopener noreferrer' }
= s_('Environments|Learn more about stopping environments')
.modal-footer
= button_tag _('Cancel'), type: 'button', class: 'gl-button btn btn-cancel', data: { dismiss: 'modal' }
= button_to stop_project_environment_path(@project, @environment), class: 'gl-button btn btn-danger has-tooltip', method: :post do
= s_('Environments|Stop environment')
- if can_destroy_environment?(@environment)
#delete-environment-modal
.top-area.justify-content-between
.d-flex
%h3.page-title= @environment.name
- if @environment.auto_stop_at?
%p.align-self-end.gl-ml-3
= s_('Environments|Auto stops %{auto_stop_time}').html_safe % {auto_stop_time: time_ago_with_tooltip(@environment.auto_stop_at)}
.nav-controls.my-2
= render 'projects/environments/pin_button', environment: @environment
= render 'projects/environments/terminal_button', environment: @environment
= render 'projects/environments/external_url', environment: @environment
= render 'projects/environments/metrics_button', environment: @environment
- if can?(current_user, :update_environment, @environment)
= link_to _('Edit'), edit_project_environment_path(@project, @environment), class: 'btn'
- if @environment.available? && can?(current_user, :stop_environment, @environment)
= button_tag class: 'gl-button btn btn-danger', type: 'button', data: { toggle: 'modal',
target: '#stop-environment-modal' } do
= sprite_icon('stop')
= s_('Environments|Stop')
- if can_destroy_environment?(@environment)
= button_tag class: 'gl-button btn btn-danger', type: 'button', data: { toggle: 'modal',
target: '#delete-environment-modal' } do
= s_('Environments|Delete')
#environments-detail-view{ data: { details: environments_detail_data_json(current_user, @project, @environment) } }
#environments-detail-view-header
 
.environments-container
- if @deployments.blank?
Loading
Loading
Loading
Loading
@@ -12445,7 +12445,7 @@ msgstr ""
msgid "Environments|Auto stop in"
msgstr ""
 
msgid "Environments|Auto stops %{auto_stop_time}"
msgid "Environments|Auto stops %{autoStopAt}"
msgstr ""
 
msgid "Environments|Commit"
Loading
Loading
@@ -12526,9 +12526,6 @@ msgstr ""
msgid "Environments|Note that this action will stop the environment, but it will %{emphasisStart}not%{emphasisEnd} have an effect on any existing deployment due to no “stop environment action” being defined in the %{ciConfigLinkStart}.gitlab-ci.yml%{ciConfigLinkEnd} file."
msgstr ""
 
msgid "Environments|Note that this action will stop the environment, but it will %{emphasis_start}not%{emphasis_end} have an effect on any existing deployment due to no “stop environment action” being defined in the %{ci_config_link_start}.gitlab-ci.yml%{ci_config_link_end} file."
msgstr ""
msgid "Environments|Open live environment"
msgstr ""
 
Loading
Loading
@@ -12571,9 +12568,6 @@ msgstr ""
msgid "Environments|Stop environment"
msgstr ""
 
msgid "Environments|Stopping"
msgstr ""
msgid "Environments|Stopping %{environmentName}"
msgstr ""
 
Loading
Loading
Loading
Loading
@@ -385,7 +385,6 @@ module Milestone
module Deployments
module Environments
autoload :Index, 'qa/page/project/deployments/environments/index'
autoload :Show, 'qa/page/project/deployments/environments/show'
end
end
 
Loading
Loading
# frozen_string_literal: true
module QA
module Page
module Project
module Deployments
module Environments
class Show < Page::Base
view 'app/views/projects/environments/_external_url.html.haml' do
element :view_deployment
end
def view_deployment(&block)
new_window = window_opened_by { click_element(:view_deployment) }
within_window(new_window, &block) if block
end
end
end
end
end
end
end
Loading
Loading
@@ -27,7 +27,7 @@
 
shared_examples 'has environment selector' do
it 'has a working environment selector', :js do
click_link('See metrics')
click_link 'Monitoring'
 
expect(page).to have_current_path(project_metrics_dashboard_path(project, environment: environment.id))
expect(page).to have_css('[data-qa-selector="environments_dropdown"]')
Loading
Loading
@@ -55,10 +55,10 @@
create(:deployment, environment: environment, deployable: build)
end
 
it 'shows metrics' do
click_link('See metrics')
it 'shows metrics', :js do
click_link 'Monitoring'
 
expect(page).to have_css('div#prometheus-graphs')
expect(page).to have_css('[data-qa-selector="prometheus_graphs"]')
end
 
it_behaves_like 'has environment selector'
Loading
Loading
Loading
Loading
@@ -27,20 +27,6 @@ def auto_stop_button_selector
visit_environment(environment)
end
 
it 'shows environment name' do
expect(page).to have_content(environment.name)
end
context 'without auto-stop' do
it 'does not show auto-stop text' do
expect(page).not_to have_content('Auto stops')
end
it 'does not show auto-stop button' do
expect(page).not_to have_selector(auto_stop_button_selector)
end
end
context 'with auto-stop' do
let!(:environment) { create(:environment, :will_auto_stop, name: 'staging', project: project) }
 
Loading
Loading
@@ -48,11 +34,11 @@ def auto_stop_button_selector
visit_environment(environment)
end
 
it 'shows auto stop info' do
it 'shows auto stop info', :js do
expect(page).to have_content('Auto stops')
end
 
it 'shows auto stop button' do
it 'shows auto stop button', :js do
expect(page).to have_selector(auto_stop_button_selector)
expect(page.find(auto_stop_button_selector).find(:xpath, '..')['action']).to have_content(cancel_auto_stop_project_environment_path(environment.project, environment))
end
Loading
Loading
@@ -80,7 +66,6 @@ def auto_stop_button_selector
it 'does show deployment SHA' do
expect(page).to have_link(deployment.short_sha)
expect(page).not_to have_link('Re-deploy')
expect(page).not_to have_terminal_button
end
end
 
Loading
Loading
@@ -186,7 +171,7 @@ def auto_stop_button_selector
let(:build) { create(:ci_build, pipeline: pipeline) }
let(:deployment) { create(:deployment, :success, environment: environment, deployable: build) }
 
it 'does show an external link button' do
it 'does show an external link button', :js do
expect(page).to have_link(nil, href: environment.external_url)
end
end
Loading
Loading
@@ -200,10 +185,6 @@ def auto_stop_button_selector
context 'for project maintainer' do
let(:role) { :maintainer }
 
it 'shows the terminal button' do
expect(page).to have_terminal_button
end
context 'web terminal', :js do
before do
# Stub #terminals as it causes js-enabled feature specs to
Loading
Loading
@@ -224,14 +205,6 @@ def auto_stop_button_selector
end
end
end
context 'for developer' do
let(:role) { :developer }
it 'does not show terminal button' do
expect(page).not_to have_terminal_button
end
end
end
end
 
Loading
Loading
@@ -259,7 +232,7 @@ def auto_stop_button_selector
click_button('Stop')
click_button('Stop environment') # confirm modal
wait_for_all_requests
expect(page).to have_content('close_app')
expect(page).to have_button('Delete')
end
end
 
Loading
Loading
@@ -269,7 +242,7 @@ def auto_stop_button_selector
name: action.ref, project: project)
end
 
it 'does not allow to stop environment' do
it 'does not allow to stop environment', :js do
expect(page).not_to have_button('Stop')
end
end
Loading
Loading
@@ -277,7 +250,7 @@ def auto_stop_button_selector
context 'for reporter' do
let(:role) { :reporter }
 
it 'does not show stop button' do
it 'does not show stop button', :js do
expect(page).not_to have_button('Stop')
end
end
Loading
Loading
@@ -287,7 +260,7 @@ def auto_stop_button_selector
context 'when environment is stopped' do
let(:environment) { create(:environment, project: project, state: :stopped) }
 
it 'does not show stop button' do
it 'does not show stop button', :js do
expect(page).not_to have_button('Stop')
end
end
Loading
Loading
@@ -323,7 +296,7 @@ def auto_stop_button_selector
ref: 'feature')
end
 
it 'user visits environment page' do
it 'user visits environment page', :js do
visit_environment(environment)
 
expect(page).to have_button('Stop')
Loading
Loading
@@ -380,8 +353,4 @@ def remove_branch_with_hooks(project, user, branch)
def visit_environment(environment)
visit project_environment_path(environment.project, environment)
end
def have_terminal_button
have_link(nil, href: terminal_project_environment_path(project, environment))
end
end
import { GlSprintf } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import DeleteEnvironmentModal from '~/environments/components/delete_environment_modal.vue';
import EnvironmentsDetailHeader from '~/environments/components/environments_detail_header.vue';
import StopEnvironmentModal from '~/environments/components/stop_environment_modal.vue';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import { createEnvironment } from './mock_data';
describe('Environments detail header component', () => {
const cancelAutoStopPath = '/my-environment/cancel/path';
const terminalPath = '/my-environment/terminal/path';
const metricsPath = '/my-environment/metrics/path';
const updatePath = '/my-environment/edit/path';
let wrapper;
const findHeader = () => wrapper.findByRole('heading');
const findAutoStopsAt = () => wrapper.findByTestId('auto-stops-at');
const findCancelAutoStopAtButton = () => wrapper.findByTestId('cancel-auto-stop-button');
const findCancelAutoStopAtForm = () => wrapper.findByTestId('cancel-auto-stop-form');
const findTerminalButton = () => wrapper.findByTestId('terminal-button');
const findExternalUrlButton = () => wrapper.findByTestId('external-url-button');
const findMetricsButton = () => wrapper.findByTestId('metrics-button');
const findEditButton = () => wrapper.findByTestId('edit-button');
const findStopButton = () => wrapper.findByTestId('stop-button');
const findDestroyButton = () => wrapper.findByTestId('destroy-button');
const findStopEnvironmentModal = () => wrapper.findComponent(StopEnvironmentModal);
const findDeleteEnvironmentModal = () => wrapper.findComponent(DeleteEnvironmentModal);
const buttons = [
['Cancel Auto Stop At', findCancelAutoStopAtButton],
['Terminal', findTerminalButton],
['External Url', findExternalUrlButton],
['Metrics', findMetricsButton],
['Edit', findEditButton],
['Stop', findStopButton],
['Destroy', findDestroyButton],
];
const createWrapper = ({ props }) => {
wrapper = shallowMountExtended(EnvironmentsDetailHeader, {
stubs: {
GlSprintf,
TimeAgo,
},
propsData: {
canReadEnvironment: false,
canAdminEnvironment: false,
canUpdateEnvironment: false,
canStopEnvironment: false,
canDestroyEnvironment: false,
...props,
},
});
};
afterEach(() => {
wrapper.destroy();
});
describe('default state with minimal access', () => {
beforeEach(() => {
createWrapper({ props: { environment: createEnvironment() } });
});
it('displays the environment name', () => {
expect(findHeader().text()).toBe('My environment');
});
it('does not display an auto stops at text', () => {
expect(findAutoStopsAt().exists()).toBe(false);
});
it.each(buttons)('does not display button: %s', (_, findSelector) => {
expect(findSelector().exists()).toBe(false);
});
it('does not display stop environment modal', () => {
expect(findStopEnvironmentModal().exists()).toBe(false);
});
it('does not display delete environment modal', () => {
expect(findDeleteEnvironmentModal().exists()).toBe(false);
});
});
describe('when auto stops at is enabled and environment is available', () => {
beforeEach(() => {
const now = new Date();
const tomorrow = new Date();
tomorrow.setDate(now.getDate() + 1);
createWrapper({
props: {
environment: createEnvironment({ autoStopAt: tomorrow.toISOString() }),
cancelAutoStopPath,
},
});
});
it('displays a text that describes when the environment is going to be stopped', () => {
expect(findAutoStopsAt().text()).toBe('Auto stops in 1 day');
});
it('displays a cancel auto stops at button with a form to make a post request', () => {
const button = findCancelAutoStopAtButton();
const form = findCancelAutoStopAtForm();
expect(form.attributes('action')).toBe(cancelAutoStopPath);
expect(form.attributes('method')).toBe('POST');
expect(button.props('icon')).toBe('thumbtack');
expect(button.attributes('type')).toBe('submit');
});
it('includes a csrf token', () => {
const input = findCancelAutoStopAtForm().find('input');
expect(input.attributes('name')).toBe('authenticity_token');
});
});
describe('when auto stops at is enabled and environment is unavailable (already stopped)', () => {
beforeEach(() => {
const now = new Date();
const tomorrow = new Date();
tomorrow.setDate(now.getDate() + 1);
createWrapper({
props: {
environment: createEnvironment({
autoStopAt: tomorrow.toISOString(),
isAvailable: false,
}),
cancelAutoStopPath,
},
});
});
it('does not display a text that describes when the environment is going to be stopped', () => {
expect(findAutoStopsAt().exists()).toBe(false);
});
it('displays a cancel auto stops at button with correct path', () => {
expect(findCancelAutoStopAtButton().exists()).toBe(false);
});
});
describe('when has a terminal', () => {
beforeEach(() => {
createWrapper({
props: {
environment: createEnvironment({ hasTerminals: true }),
canAdminEnvironment: true,
terminalPath,
},
});
});
it('displays the terminal button with correct path', () => {
expect(findTerminalButton().attributes('href')).toBe(terminalPath);
});
});
describe('when has an external url enabled', () => {
const externalUrl = 'https://example.com/my-environment/external/url';
beforeEach(() => {
createWrapper({
props: {
environment: createEnvironment({ hasTerminals: true, externalUrl }),
canReadEnvironment: true,
},
});
});
it('displays the external url button with correct path', () => {
expect(findExternalUrlButton().attributes('href')).toBe(externalUrl);
});
});
describe('when metrics are enabled', () => {
beforeEach(() => {
createWrapper({
props: {
environment: createEnvironment(),
canReadEnvironment: true,
metricsPath,
},
});
});
it('displays the metrics button with correct path', () => {
expect(findMetricsButton().attributes('href')).toBe(metricsPath);
});
});
describe('when has all admin rights', () => {
beforeEach(() => {
createWrapper({
props: {
environment: createEnvironment(),
canReadEnvironment: true,
canAdminEnvironment: true,
canStopEnvironment: true,
canUpdateEnvironment: true,
updatePath,
},
});
});
it('displays the edit button with correct path', () => {
expect(findEditButton().attributes('href')).toBe(updatePath);
});
it('displays the stop button with correct icon', () => {
expect(findStopButton().attributes('icon')).toBe('stop');
});
it('displays stop environment modal', () => {
expect(findStopEnvironmentModal().exists()).toBe(true);
});
});
describe('when the environment is unavailable and user has destroy permissions', () => {
beforeEach(() => {
createWrapper({
props: {
environment: createEnvironment({ isAvailable: false }),
canDestroyEnvironment: true,
},
});
});
it('displays a delete button', () => {
expect(findDestroyButton().exists()).toBe(true);
});
it('displays delete environment modal', () => {
expect(findDeleteEnvironmentModal().exists()).toBe(true);
});
});
});
Loading
Loading
@@ -301,4 +301,22 @@ const tableData = {
},
};
 
export { environment, environmentsList, folder, serverData, tableData, deployBoardMockData };
const createEnvironment = (data = {}) => ({
id: 1,
name: 'My environment',
externalUrl: 'my external url',
isAvailable: true,
hasTerminals: false,
autoStopAt: null,
...data,
});
export {
environment,
environmentsList,
folder,
serverData,
tableData,
deployBoardMockData,
createEnvironment,
};
Loading
Loading
@@ -22,4 +22,41 @@
end
end
end
describe '#environments_detail_data_json' do
subject { helper.environments_detail_data_json(user, project, environment) }
let_it_be(:auto_stop_at) { Time.now.utc }
let_it_be(:user) { create(:user) }
let_it_be(:project, reload: true) { create(:project, :repository) }
let_it_be(:environment) { create(:environment, project: project, auto_stop_at: auto_stop_at) }
before do
allow(helper).to receive(:current_user).and_return(user)
allow(helper).to receive(:can?).and_return(true)
end
it 'returns the correct data' do
expect(subject).to eq({
name: environment.name,
id: environment.id,
external_url: environment.external_url,
can_update_environment: true,
can_destroy_environment: true,
can_read_environment: true,
can_stop_environment: true,
can_admin_environment: true,
environment_metrics_path: environment_metrics_path(environment),
environments_fetch_path: project_environments_path(project, format: :json),
environment_edit_path: edit_project_environment_path(project, environment),
environment_stop_path: stop_project_environment_path(project, environment),
environment_delete_path: environment_delete_path(environment),
environment_cancel_auto_stop_path: cancel_auto_stop_project_environment_path(project, environment),
environment_terminal_path: terminal_project_environment_path(project, environment),
has_terminals: false,
is_environment_available: true,
auto_stop_at: auto_stop_at
}.to_json)
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment