Commit 698f7df2 authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch...

Merge branch '209105-cluster-page-disable-the-save-button-if-there-are-no-edits-to-the-form-in-cluster-details' into 'master'

Disable Save button if no edits to GitLab integration form

Closes #209105

See merge request gitlab-org/gitlab!37753
parents 66e3288b 806855d6
...@@ -8,14 +8,7 @@ import Flash from '../flash'; ...@@ -8,14 +8,7 @@ import Flash from '../flash';
import Poll from '../lib/utils/poll'; import Poll from '../lib/utils/poll';
import initSettingsPanels from '../settings_panels'; import initSettingsPanels from '../settings_panels';
import eventHub from './event_hub'; import eventHub from './event_hub';
import { import { APPLICATION_STATUS, CROSSPLANE, KNATIVE, FLUENTD } from './constants';
APPLICATION_STATUS,
INGRESS,
INGRESS_DOMAIN_SUFFIX,
CROSSPLANE,
KNATIVE,
FLUENTD,
} from './constants';
import ClustersService from './services/clusters_service'; import ClustersService from './services/clusters_service';
import ClustersStore from './stores/clusters_store'; import ClustersStore from './stores/clusters_store';
import Applications from './components/applications.vue'; import Applications from './components/applications.vue';
...@@ -120,10 +113,6 @@ export default class Clusters { ...@@ -120,10 +113,6 @@ export default class Clusters {
this.errorReasonContainer = this.errorContainer.querySelector('.js-error-reason'); this.errorReasonContainer = this.errorContainer.querySelector('.js-error-reason');
this.successApplicationContainer = document.querySelector('.js-cluster-application-notice'); this.successApplicationContainer = document.querySelector('.js-cluster-application-notice');
this.tokenField = document.querySelector('.js-cluster-token'); this.tokenField = document.querySelector('.js-cluster-token');
this.ingressDomainHelpText = document.querySelector('.js-ingress-domain-help-text');
this.ingressDomainSnippet =
this.ingressDomainHelpText &&
this.ingressDomainHelpText.querySelector('.js-ingress-domain-snippet');
initProjectSelectDropdown(); initProjectSelectDropdown();
Clusters.initDismissableCallout(); Clusters.initDismissableCallout();
...@@ -327,13 +316,6 @@ export default class Clusters { ...@@ -327,13 +316,6 @@ export default class Clusters {
this.checkForNewInstalls(prevApplicationMap, this.store.state.applications); this.checkForNewInstalls(prevApplicationMap, this.store.state.applications);
this.updateContainer(prevStatus, this.store.state.status, this.store.state.statusReason); this.updateContainer(prevStatus, this.store.state.status, this.store.state.statusReason);
if (this.ingressDomainHelpText) {
this.toggleIngressDomainHelpText(
prevApplicationMap[INGRESS],
this.store.state.applications[INGRESS],
);
}
if (this.store.state.applications[KNATIVE]?.status === APPLICATION_STATUS.INSTALLED) { if (this.store.state.applications[KNATIVE]?.status === APPLICATION_STATUS.INSTALLED) {
initServerlessSurveyBanner(); initServerlessSurveyBanner();
} }
...@@ -505,13 +487,6 @@ export default class Clusters { ...@@ -505,13 +487,6 @@ export default class Clusters {
}); });
} }
toggleIngressDomainHelpText({ externalIp }, { externalIp: newExternalIp }) {
if (externalIp !== newExternalIp) {
this.ingressDomainHelpText.classList.toggle('hide', !newExternalIp);
this.ingressDomainSnippet.textContent = `${newExternalIp}${INGRESS_DOMAIN_SUFFIX}`;
}
}
saveKnativeDomain(data) { saveKnativeDomain(data) {
const appId = data.id; const appId = data.id;
this.store.updateApplication(appId); this.store.updateApplication(appId);
......
<script> <script>
import { GlFormGroup, GlToggle, GlTooltipDirective } from '@gitlab/ui'; import {
GlFormGroup,
GlFormInput,
GlToggle,
GlTooltipDirective,
GlSprintf,
GlLink,
GlButton,
} from '@gitlab/ui';
import { mapState } from 'vuex'; import { mapState } from 'vuex';
export default { export default {
components: { components: {
GlFormGroup, GlFormGroup,
GlToggle, GlToggle,
GlFormInput,
GlSprintf,
GlLink,
GlButton,
}, },
directives: { directives: {
GlTooltip: GlTooltipDirective, GlTooltip: GlTooltipDirective,
}, },
inject: {
autoDevopsHelpPath: {
type: String,
},
externalEndpointHelpPath: {
type: String,
},
},
data() { data() {
return { return {
toggleEnabled: true, toggleEnabled: true,
envScope: '*',
baseDomainField: '',
externalIp: '',
}; };
}, },
computed: { computed: {
...mapState(['enabled', 'editable']), ...mapState([
'enabled',
'editable',
'environmentScope',
'baseDomain',
'applicationIngressExternalIp',
]),
canSubmit() {
return (
this.enabled !== this.toggleEnabled ||
this.environmentScope !== this.envScope ||
this.baseDomain !== this.baseDomainField
);
},
}, },
mounted() { mounted() {
this.toggleEnabled = this.enabled; this.toggleEnabled = this.enabled;
this.envScope = this.environmentScope;
this.baseDomainField = this.baseDomain;
this.externalIp = this.applicationIngressExternalIp;
}, },
}; };
</script> </script>
<template> <template>
<div class="d-flex align-items-center"> <div class="d-flex gl-flex-direction-column">
<gl-form-group> <gl-form-group>
<div class="gl-display-flex gl-align-items-center"> <div class="gl-display-flex gl-align-items-center">
<h4 class="gl-pr-3 gl-m-0 ">{{ s__('ClusterIntegration|GitLab Integration') }}</h4> <h4 class="gl-pr-3 gl-m-0">{{ s__('ClusterIntegration|GitLab Integration') }}</h4>
<input
id="cluster_enabled" <div class="js-cluster-enable-toggle-area">
class="js-project-feature-toggle-input"
type="hidden"
:value="toggleEnabled"
name="cluster[enabled]"
/>
<div id="tooltipcontainer" class="js-cluster-enable-toggle-area">
<gl-toggle <gl-toggle
id="toggleCluster"
v-model="toggleEnabled" v-model="toggleEnabled"
v-gl-tooltip:tooltipcontainer v-gl-tooltip:tooltipcontainer
name="cluster[enabled]"
class="gl-mb-0 js-project-feature-toggle" class="gl-mb-0 js-project-feature-toggle"
data-qa-selector="integration_status_toggle" data-qa-selector="integration_status_toggle"
:aria-describedby="__('Toggle Kubernetes cluster')" aria-describedby="toggleCluster"
:disabled="!editable" :disabled="!editable"
:is_checked="toggleEnabled"
:title=" :title="
s__( s__(
'ClusterIntegration|Enable or disable GitLab\'s connection to your Kubernetes cluster.', 'ClusterIntegration|Enable or disable GitLab\'s connection to your Kubernetes cluster.',
...@@ -54,5 +88,76 @@ export default { ...@@ -54,5 +88,76 @@ export default {
</div> </div>
</div> </div>
</gl-form-group> </gl-form-group>
<gl-form-group
:label="s__('ClusterIntegration|Environment scope')"
label-size="sm"
label-for="cluster_environment_scope"
:description="
s__('ClusterIntegration|Choose which of your environments will use this cluster.')
"
>
<gl-form-input
id="cluster_environment_scope"
v-model="envScope"
name="cluster[environment_scope]"
class="col-md-6"
type="text"
/>
</gl-form-group>
<gl-form-group
:label="s__('ClusterIntegration|Base domain')"
label-size="sm"
label-for="cluster_base_domain"
>
<gl-form-input
id="cluster_base_domain"
v-model="baseDomainField"
name="cluster[base_domain]"
data-qa-selector="base_domain_field"
class="col-md-6"
type="text"
/>
<div class="form-text text-muted inline">
<gl-sprintf
:message="
s__(
'ClusterIntegration|Specifying a domain will allow you to use Auto Review Apps and Auto Deploy stages for %{linkStart}Auto DevOps.%{linkEnd} The domain should have a wildcard DNS configured matching the domain. ',
)
"
>
<template #link="{ content }">
<gl-link :href="autoDevopsHelpPath" target="_blank">{{ content }}</gl-link>
</template>
</gl-sprintf>
<div v-if="applicationIngressExternalIp" class="js-ingress-domain-help-text inline">
{{ s__('ClusterIntegration|Alternatively, ') }}
<gl-sprintf :message="s__('ClusterIntegration|%{externalIp}.nip.io')">
<template #externalIp>{{ externalIp }}</template>
</gl-sprintf>
{{ s__('ClusterIntegration|can be used instead of a custom domain. ') }}
</div>
<gl-sprintf
class="inline"
:message="s__('ClusterIntegration|%{linkStart}More information%{linkEnd}')"
>
<template #link="{ content }">
<gl-link :href="externalEndpointHelpPath" target="_blank">{{ content }}</gl-link>
</template>
</gl-sprintf>
</div>
</gl-form-group>
<div v-if="editable" class="form group gl-display-flex gl-justify-content-end">
<gl-button
category="primary"
variant="success"
type="submit"
:disabled="!canSubmit"
:aria-disabled="!canSubmit"
data-qa-selector="save_changes_button"
>{{ s__('ClusterIntegration|Save changes') }}</gl-button
>
</div>
</div> </div>
</template> </template>
...@@ -9,13 +9,19 @@ export default () => { ...@@ -9,13 +9,19 @@ export default () => {
return; return;
} }
const { autoDevopsHelpPath, externalEndpointHelpPath } = entryPoint.dataset;
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
new Vue({ new Vue({
el: entryPoint, el: entryPoint,
store: createStore(entryPoint.dataset), store: createStore(entryPoint.dataset),
provide: {
autoDevopsHelpPath,
externalEndpointHelpPath,
},
render(createElement) { render(createElement) {
return createElement(IntegrationForm); return createElement(IntegrationForm, {});
}, },
}); });
}; };
...@@ -4,5 +4,10 @@ export default (initialState = {}) => { ...@@ -4,5 +4,10 @@ export default (initialState = {}) => {
return { return {
enabled: parseBoolean(initialState.enabled), enabled: parseBoolean(initialState.enabled),
editable: parseBoolean(initialState.editable), editable: parseBoolean(initialState.editable),
environmentScope: initialState.environmentScope,
baseDomain: initialState.baseDomain,
applicationIngressExternalIp: initialState.applicationIngressExternalIp,
autoDevopsHelpPath: initialState.autoDevopsHelpPath,
externalEndpointHelpPath: initialState.externalEndpointHelpPath,
}; };
}; };
# frozen_string_literal: true # frozen_string_literal: true
module ClustersHelper module ClustersHelper
def has_multiple_clusters?
true
end
def create_new_cluster_label(provider: nil) def create_new_cluster_label(provider: nil)
case provider case provider
when 'aws' when 'aws'
...@@ -31,7 +27,12 @@ module ClustersHelper ...@@ -31,7 +27,12 @@ module ClustersHelper
def js_cluster_form_data(cluster, can_edit) def js_cluster_form_data(cluster, can_edit)
{ {
enabled: cluster.enabled?.to_s, enabled: cluster.enabled?.to_s,
editable: can_edit.to_s editable: can_edit.to_s,
environment_scope: cluster.environment_scope,
base_domain: cluster.base_domain,
application_ingress_external_ip: cluster.application_ingress_external_ip,
auto_devops_help_path: help_page_path('topics/autodevops/index'),
external_endpoint_help_path: help_page_path('user/clusters/applications.md', anchor: 'pointing-your-dns-at-the-external-endpoint')
} }
end end
......
= form_for @cluster, url: clusterable.cluster_path(@cluster), as: :cluster, html: { class: 'js-cluster-integration-form' } do |field| = form_for @cluster, url: clusterable.cluster_path(@cluster), as: :cluster, html: { class: 'js-cluster-integration-form' } do |field|
= form_errors(@cluster) = form_errors(@cluster)
#js-cluster-integration-form{ data: js_cluster_form_data(@cluster, can?(current_user, :update_cluster, @cluster)) } #js-cluster-integration-form{ data: js_cluster_form_data(@cluster, can?(current_user, :update_cluster, @cluster)) }
.form-group
%h5= s_('ClusterIntegration|Environment scope')
= field.text_field :environment_scope, class: 'col-md-6 form-control js-select-on-focus', placeholder: s_('ClusterIntegration|Environment scope')
- environment_scope_url = help_page_path('user/project/clusters/index', anchor: 'base-domain')
- environment_scope_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: environment_scope_url }
.form-text.text-muted= s_("ClusterIntegration|Choose which of your environments will use this cluster. %{environment_scope_start}More information%{environment_scope_end}").html_safe % { environment_scope_start: environment_scope_start, environment_scope_end: '</a>'.html_safe }
.form-group
%h5= s_('ClusterIntegration|Base domain')
= field.text_field :base_domain, class: 'col-md-6 form-control js-select-on-focus', data: { qa_selector: 'base_domain_field' }
.form-text.text-muted
- auto_devops_url = help_page_path('topics/autodevops/index')
- auto_devops_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: auto_devops_url }
= s_('ClusterIntegration|Specifying a domain will allow you to use Auto Review Apps and Auto Deploy stages for %{auto_devops_start}Auto DevOps%{auto_devops_end}. The domain should have a wildcard DNS configured matching the domain.').html_safe % { auto_devops_start: auto_devops_start, auto_devops_end: '</a>'.html_safe }
%span{ :class => ["js-ingress-domain-help-text", ("hide" unless @cluster.application_ingress_external_ip.present?)] }
= s_('ClusterIntegration|Alternatively')
%code{ :class => "js-ingress-domain-snippet" }
= s_('ClusterIntegration|%{external_ip}.nip.io').html_safe % { external_ip: @cluster.application_ingress_external_ip }
= s_('ClusterIntegration| can be used instead of a custom domain.')
- custom_domain_url = help_page_path('user/clusters/applications.md', anchor: 'pointing-your-dns-at-the-external-endpoint')
- custom_domain_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: custom_domain_url }
= s_('ClusterIntegration| %{custom_domain_start}More information%{custom_domain_end}.').html_safe % { custom_domain_start: custom_domain_start, custom_domain_end: '</a>'.html_safe }
- if can?(current_user, :update_cluster, @cluster)
.form-group.gl-display-flex.gl-justify-content-end
= field.submit _('Save changes'), class: 'btn btn-success', data: { qa_selector: 'save_changes_button'}
...@@ -5105,19 +5105,16 @@ msgstr "" ...@@ -5105,19 +5105,16 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter" msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr "" msgstr ""
msgid "ClusterIntegration| %{custom_domain_start}More information%{custom_domain_end}."
msgstr ""
msgid "ClusterIntegration| This will permanently delete the following resources: <ul> <li>All installed applications and related resources</li> <li>The <code>gitlab-managed-apps</code> namespace</li> <li>Any project namespaces</li> <li><code>clusterroles</code></li> <li><code>clusterrolebindings</code></li> </ul>" msgid "ClusterIntegration| This will permanently delete the following resources: <ul> <li>All installed applications and related resources</li> <li>The <code>gitlab-managed-apps</code> namespace</li> <li>Any project namespaces</li> <li><code>clusterroles</code></li> <li><code>clusterrolebindings</code></li> </ul>"
msgstr "" msgstr ""
msgid "ClusterIntegration| can be used instead of a custom domain." msgid "ClusterIntegration|%{appList} was successfully installed on your Kubernetes cluster"
msgstr "" msgstr ""
msgid "ClusterIntegration|%{appList} was successfully installed on your Kubernetes cluster" msgid "ClusterIntegration|%{externalIp}.nip.io"
msgstr "" msgstr ""
msgid "ClusterIntegration|%{external_ip}.nip.io" msgid "ClusterIntegration|%{linkStart}More information%{linkEnd}"
msgstr "" msgstr ""
msgid "ClusterIntegration|%{title} uninstalled successfully." msgid "ClusterIntegration|%{title} uninstalled successfully."
...@@ -5171,7 +5168,7 @@ msgstr "" ...@@ -5171,7 +5168,7 @@ msgstr ""
msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}" msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
msgstr "" msgstr ""
msgid "ClusterIntegration|Alternatively" msgid "ClusterIntegration|Alternatively, "
msgstr "" msgstr ""
msgid "ClusterIntegration|Amazon EKS" msgid "ClusterIntegration|Amazon EKS"
...@@ -5234,9 +5231,6 @@ msgstr "" ...@@ -5234,9 +5231,6 @@ msgstr ""
msgid "ClusterIntegration|Choose which of your environments will use this cluster." msgid "ClusterIntegration|Choose which of your environments will use this cluster."
msgstr "" msgstr ""
msgid "ClusterIntegration|Choose which of your environments will use this cluster. %{environment_scope_start}More information%{environment_scope_end}"
msgstr ""
msgid "ClusterIntegration|Clear cluster cache" msgid "ClusterIntegration|Clear cluster cache"
msgstr "" msgstr ""
...@@ -5858,7 +5852,7 @@ msgstr "" ...@@ -5858,7 +5852,7 @@ msgstr ""
msgid "ClusterIntegration|Something went wrong while updating Knative domain name." msgid "ClusterIntegration|Something went wrong while updating Knative domain name."
msgstr "" msgstr ""
msgid "ClusterIntegration|Specifying a domain will allow you to use Auto Review Apps and Auto Deploy stages for %{auto_devops_start}Auto DevOps%{auto_devops_end}. The domain should have a wildcard DNS configured matching the domain." msgid "ClusterIntegration|Specifying a domain will allow you to use Auto Review Apps and Auto Deploy stages for %{linkStart}Auto DevOps.%{linkEnd} The domain should have a wildcard DNS configured matching the domain. "
msgstr "" msgstr ""
msgid "ClusterIntegration|Subnets" msgid "ClusterIntegration|Subnets"
...@@ -5981,6 +5975,9 @@ msgstr "" ...@@ -5981,6 +5975,9 @@ msgstr ""
msgid "ClusterIntegration|access to Google Kubernetes Engine" msgid "ClusterIntegration|access to Google Kubernetes Engine"
msgstr "" msgstr ""
msgid "ClusterIntegration|can be used instead of a custom domain. "
msgstr ""
msgid "ClusterIntegration|documentation" msgid "ClusterIntegration|documentation"
msgstr "" msgstr ""
...@@ -25704,9 +25701,6 @@ msgstr "" ...@@ -25704,9 +25701,6 @@ msgstr ""
msgid "Today" msgid "Today"
msgstr "" msgstr ""
msgid "Toggle Kubernetes cluster"
msgstr ""
msgid "Toggle Markdown preview" msgid "Toggle Markdown preview"
msgstr "" msgstr ""
......
...@@ -12,9 +12,6 @@ module QA ...@@ -12,9 +12,6 @@ module QA
view 'app/assets/javascripts/clusters/forms/components/integration_form.vue' do view 'app/assets/javascripts/clusters/forms/components/integration_form.vue' do
element :integration_status_toggle, required: true element :integration_status_toggle, required: true
end
view 'app/views/clusters/clusters/_gitlab_integration_form.html.haml' do
element :base_domain_field, required: true element :base_domain_field, required: true
element :save_changes_button, required: true element :save_changes_button, required: true
end end
......
...@@ -20,7 +20,7 @@ RSpec.describe 'Clusterable > Show page' do ...@@ -20,7 +20,7 @@ RSpec.describe 'Clusterable > Show page' do
expect(page).to have_content(cluster_type_label) expect(page).to have_content(cluster_type_label)
end end
it 'allow the user to set domain' do it 'allow the user to set domain', :js do
visit cluster_path visit cluster_path
within '.js-cluster-integration-form' do within '.js-cluster-integration-form' do
...@@ -28,20 +28,19 @@ RSpec.describe 'Clusterable > Show page' do ...@@ -28,20 +28,19 @@ RSpec.describe 'Clusterable > Show page' do
click_on 'Save changes' click_on 'Save changes'
end end
expect(page.status_code).to eq(200)
expect(page).to have_content('Kubernetes cluster was successfully updated.') expect(page).to have_content('Kubernetes cluster was successfully updated.')
end end
context 'when there is a cluster with ingress and external ip' do context 'when there is a cluster with ingress and external ip', :js do
before do before do
cluster.create_application_ingress!(external_ip: '192.168.1.100') cluster.create_application_ingress!(external_ip: '192.168.1.100')
visit cluster_path visit cluster_path
end end
it 'shows help text with the domain as an alternative to custom domain' do it 'shows help text with the domain as an alternative to custom domain', :js do
within '.js-cluster-integration-form' do within '.js-cluster-integration-form' do
expect(find(cluster_ingress_help_text_selector)).not_to match_css(hide_modifier_selector) expect(find(cluster_ingress_help_text_selector).text).to include('192.168.1.100')
end end
end end
end end
...@@ -51,7 +50,7 @@ RSpec.describe 'Clusterable > Show page' do ...@@ -51,7 +50,7 @@ RSpec.describe 'Clusterable > Show page' do
visit cluster_path visit cluster_path
within '.js-cluster-integration-form' do within '.js-cluster-integration-form' do
expect(find(cluster_ingress_help_text_selector)).to match_css(hide_modifier_selector) expect(page).not_to have_selector(cluster_ingress_help_text_selector)
end end
end end
end end
......
...@@ -2,12 +2,7 @@ import MockAdapter from 'axios-mock-adapter'; ...@@ -2,12 +2,7 @@ import MockAdapter from 'axios-mock-adapter';
import { loadHTMLFixture } from 'helpers/fixtures'; import { loadHTMLFixture } from 'helpers/fixtures';
import { setTestTimeout } from 'helpers/timeout'; import { setTestTimeout } from 'helpers/timeout';
import Clusters from '~/clusters/clusters_bundle'; import Clusters from '~/clusters/clusters_bundle';
import { import { APPLICATION_STATUS, APPLICATIONS, RUNNER } from '~/clusters/constants';
APPLICATION_STATUS,
INGRESS_DOMAIN_SUFFIX,
APPLICATIONS,
RUNNER,
} from '~/clusters/constants';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import initProjectSelectDropdown from '~/project_select'; import initProjectSelectDropdown from '~/project_select';
...@@ -308,7 +303,6 @@ describe('Clusters', () => { ...@@ -308,7 +303,6 @@ describe('Clusters', () => {
return promise.then(() => { return promise.then(() => {
expect(cluster.store.state.applications.helm.status).toEqual(INSTALLED); expect(cluster.store.state.applications.helm.status).toEqual(INSTALLED);
expect(cluster.store.state.applications.helm.uninstallFailed).toBe(true); expect(cluster.store.state.applications.helm.uninstallFailed).toBe(true);
expect(cluster.store.state.applications.helm.requestReason).toBeDefined(); expect(cluster.store.state.applications.helm.requestReason).toBeDefined();
}); });
}); });
...@@ -334,10 +328,8 @@ describe('Clusters', () => { ...@@ -334,10 +328,8 @@ describe('Clusters', () => {
describe('handleClusterStatusSuccess', () => { describe('handleClusterStatusSuccess', () => {
beforeEach(() => { beforeEach(() => {
jest.spyOn(cluster.store, 'updateStateFromServer').mockReturnThis(); jest.spyOn(cluster.store, 'updateStateFromServer').mockReturnThis();
jest.spyOn(cluster, 'toggleIngressDomainHelpText').mockReturnThis();
jest.spyOn(cluster, 'checkForNewInstalls').mockReturnThis(); jest.spyOn(cluster, 'checkForNewInstalls').mockReturnThis();
jest.spyOn(cluster, 'updateContainer').mockReturnThis(); jest.spyOn(cluster, 'updateContainer').mockReturnThis();
cluster.handleClusterStatusSuccess({ data: {} }); cluster.handleClusterStatusSuccess({ data: {} });
}); });
...@@ -349,53 +341,11 @@ describe('Clusters', () => { ...@@ -349,53 +341,11 @@ describe('Clusters', () => {
expect(cluster.checkForNewInstalls).toHaveBeenCalled(); expect(cluster.checkForNewInstalls).toHaveBeenCalled();
}); });
it('toggles ingress domain help text', () => {
expect(cluster.toggleIngressDomainHelpText).toHaveBeenCalled();
});
it('updates message containers', () => { it('updates message containers', () => {
expect(cluster.updateContainer).toHaveBeenCalled(); expect(cluster.updateContainer).toHaveBeenCalled();
}); });
}); });
describe('toggleIngressDomainHelpText', () => {
let ingressPreviousState;
let ingressNewState;
beforeEach(() => {
ingressPreviousState = { externalIp: null };
ingressNewState = { externalIp: '127.0.0.1' };
});
describe(`when ingress have an external ip assigned`, () => {
beforeEach(() => {
cluster.toggleIngressDomainHelpText(ingressPreviousState, ingressNewState);
});
it('displays custom domain help text', () => {
expect(cluster.ingressDomainHelpText.classList.contains('hide')).toEqual(false);
});
it('updates ingress external ip address', () => {
expect(cluster.ingressDomainSnippet.textContent).toEqual(
`${ingressNewState.externalIp}${INGRESS_DOMAIN_SUFFIX}`,
);
});
});
describe(`when ingress does not have an external ip assigned`, () => {
it('hides custom domain help text', () => {
ingressPreviousState.externalIp = '127.0.0.1';
ingressNewState.externalIp = null;
cluster.ingressDomainHelpText.classList.remove('hide');
cluster.toggleIngressDomainHelpText(ingressPreviousState, ingressNewState);
expect(cluster.ingressDomainHelpText.classList.contains('hide')).toEqual(true);
});
});
});
describe('updateApplication', () => { describe('updateApplication', () => {
const params = { version: '1.0.0' }; const params = { version: '1.0.0' };
let storeUpdateApplication; let storeUpdateApplication;
......
import Vuex from 'vuex';
import IntegrationForm from '~/clusters/forms/components/integration_form.vue'; import IntegrationForm from '~/clusters/forms/components/integration_form.vue';
import { createStore } from '~/clusters/forms/stores/index'; import { createStore } from '~/clusters/forms/stores/index';
import { mount } from '@vue/test-utils'; import { shallowMount, createLocalVue } from '@vue/test-utils';
import { GlToggle } from '@gitlab/ui'; import { GlToggle, GlButton } from '@gitlab/ui';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('ClusterIntegrationForm', () => { describe('ClusterIntegrationForm', () => {
let wrapper; let wrapper;
let store;
const glToggle = () => wrapper.find(GlToggle); const defaultStoreValues = {
const toggleButton = () => glToggle().find('button'); enabled: true,
const toggleInput = () => wrapper.find('input'); editable: true,
environmentScope: '*',
baseDomain: 'testDomain',
applicationIngressExternalIp: null,
};
const createWrapper = () => { const createWrapper = (storeValues = defaultStoreValues) => {
store = createStore({ wrapper = shallowMount(IntegrationForm, {
enabled: 'true', localVue,
editable: 'true', store: createStore(storeValues),
provide: {
autoDevopsHelpPath: 'topics/autodevops/index',
externalEndpointHelpPath: 'user/clusters/applications.md',
},
}); });
wrapper = mount(IntegrationForm, { store });
return wrapper.vm.$nextTick();
}; };
const destroyWrapper = () => {
wrapper.destroy();
wrapper = null;
};
const findSubmitButton = () => wrapper.find(GlButton);
const findGlToggle = () => wrapper.find(GlToggle);
afterEach(() => {
destroyWrapper();
});
describe('rendering', () => {
beforeEach(() => createWrapper());
it('enables toggle if editable is true', () => {
expect(findGlToggle().props('disabled')).toBe(false);
});
it('sets the envScope to default', () => {
expect(wrapper.find('[id="cluster_environment_scope"]').attributes('value')).toBe('*');
});
it('sets the baseDomain to default', () => {
expect(wrapper.find('[id="cluster_base_domain"]').attributes('value')).toBe('testDomain');
});
describe('when editable is false', () => {
beforeEach(() => { beforeEach(() => {
return createWrapper(); createWrapper({ ...defaultStoreValues, editable: false });
}); });
afterEach(() => { it('disables toggle if editable is false', () => {
wrapper.destroy(); expect(findGlToggle().props('disabled')).toBe(true);
});
it('does not render the save button', () => {
expect(findSubmitButton().exists()).toBe(false);
});
});
it('does not render external IP block if applicationIngressExternalIp was not passed', () => {
createWrapper({ ...defaultStoreValues });
expect(wrapper.find('.js-ingress-domain-help-text').exists()).toBe(false);
}); });
it('creates the toggle and label', () => { it('renders external IP block if applicationIngressExternalIp was passed', () => {
expect(wrapper.text()).toContain('GitLab Integration'); createWrapper({ ...defaultStoreValues, applicationIngressExternalIp: '127.0.0.1' });
expect(wrapper.contains(GlToggle)).toBe(true);
expect(wrapper.find('.js-ingress-domain-help-text').exists()).toBe(true);
});
}); });
it('initializes toggle with store value', () => { describe('reactivity', () => {
expect(toggleButton().classes()).toContain('is-checked'); beforeEach(() => createWrapper());
expect(toggleInput().attributes('value')).toBe('true');
it('enables the submit button on changing toggle to different value', () => {
return wrapper.vm
.$nextTick()
.then(() => {
// setData is a bad approach because it changes the internal implementation which we should not touch
// but our GlFormInput lacks the ability to set a new value.
wrapper.setData({ toggleEnabled: !defaultStoreValues.enabled });
})
.then(() => {
expect(findSubmitButton().props('disabled')).toBe(false);
});
}); });
it('switches the toggle value on click', () => { it('enables the submit button on changing input values', () => {
toggleButton().trigger('click'); return wrapper.vm
wrapper.vm.$nextTick(() => { .$nextTick()
expect(toggleButton().classes()).not.toContain('is-checked'); .then(() => {
expect(toggleInput().attributes('value')).toBe('false'); wrapper.setData({ envScope: `${defaultStoreValues.environmentScope}1` });
})
.then(() => {
expect(findSubmitButton().props('disabled')).toBe(false);
});
}); });
}); });
}); });
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment