Commit 9643bcc6 authored by Justin Ho Tuan Duong's avatar Justin Ho Tuan Duong Committed by Phil Hughes

Add Vuex store for isSaving and isTesting

For separate Save and Test buttons
parent cb3da621
<script> <script>
import { mapState, mapActions, mapGetters } from 'vuex'; import { mapState, mapActions, mapGetters } from 'vuex';
import { GlButton } from '@gitlab/ui';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import eventHub from '../event_hub';
import OverrideDropdown from './override_dropdown.vue'; import OverrideDropdown from './override_dropdown.vue';
import ActiveCheckbox from './active_checkbox.vue'; import ActiveCheckbox from './active_checkbox.vue';
...@@ -18,11 +20,15 @@ export default { ...@@ -18,11 +20,15 @@ export default {
JiraIssuesFields, JiraIssuesFields,
TriggerFields, TriggerFields,
DynamicField, DynamicField,
GlButton,
}, },
mixins: [glFeatureFlagsMixin()], mixins: [glFeatureFlagsMixin()],
computed: { computed: {
...mapGetters(['currentKey', 'propsSource']), ...mapGetters(['currentKey', 'propsSource', 'isSavingOrTesting']),
...mapState(['adminState', 'override']), ...mapState(['adminState', 'override', 'isSaving', 'isTesting']),
isEditable() {
return this.propsSource.editable;
},
isJira() { isJira() {
return this.propsSource.type === 'jira'; return this.propsSource.type === 'jira';
}, },
...@@ -31,7 +37,15 @@ export default { ...@@ -31,7 +37,15 @@ export default {
}, },
}, },
methods: { methods: {
...mapActions(['setOverride']), ...mapActions(['setOverride', 'setIsSaving', 'setIsTesting']),
onSaveClick() {
this.setIsSaving(true);
eventHub.$emit('saveIntegration');
},
onTestClick() {
this.setIsTesting(true);
eventHub.$emit('testIntegration');
},
}, },
}; };
</script> </script>
...@@ -67,5 +81,29 @@ export default { ...@@ -67,5 +81,29 @@ export default {
:key="`${currentKey}-jira-issues-fields`" :key="`${currentKey}-jira-issues-fields`"
v-bind="propsSource.jiraIssuesProps" v-bind="propsSource.jiraIssuesProps"
/> />
<div v-if="isEditable" class="footer-block row-content-block">
<gl-button
category="primary"
variant="success"
type="submit"
:loading="isSaving"
:disabled="isSavingOrTesting"
data-qa-selector="save_changes_button"
@click.prevent="onSaveClick"
>
{{ __('Save changes') }}
</gl-button>
<gl-button
v-if="propsSource.canTest"
:loading="isTesting"
:disabled="isSavingOrTesting"
:href="propsSource.testPath"
@click.prevent="onTestClick"
>
{{ __('Test settings') }}
</gl-button>
<gl-button class="btn-cancel" :href="propsSource.cancelPath">{{ __('Cancel') }}</gl-button>
</div>
</div> </div>
</template> </template>
...@@ -24,11 +24,15 @@ function parseDatasetToProps(data) { ...@@ -24,11 +24,15 @@ function parseDatasetToProps(data) {
fields, fields,
inheritFromId, inheritFromId,
integrationLevel, integrationLevel,
cancelPath,
testPath,
...booleanAttributes ...booleanAttributes
} = data; } = data;
const { const {
showActive, showActive,
activated, activated,
editable,
canTest,
commitEvents, commitEvents,
mergeRequestEvents, mergeRequestEvents,
enableComments, enableComments,
...@@ -41,6 +45,10 @@ function parseDatasetToProps(data) { ...@@ -41,6 +45,10 @@ function parseDatasetToProps(data) {
initialActivated: activated, initialActivated: activated,
showActive, showActive,
type, type,
cancelPath,
editable,
canTest,
testPath,
triggerFieldsProps: { triggerFieldsProps: {
initialTriggerCommit: commitEvents, initialTriggerCommit: commitEvents,
initialTriggerMergeRequest: mergeRequestEvents, initialTriggerMergeRequest: mergeRequestEvents,
......
import * as types from './mutation_types'; import * as types from './mutation_types';
export const setOverride = ({ commit }, override) => commit(types.SET_OVERRIDE, override); export const setOverride = ({ commit }, override) => commit(types.SET_OVERRIDE, override);
export const setIsSaving = ({ commit }, isSaving) => commit(types.SET_IS_SAVING, isSaving);
export const setIsTesting = ({ commit }, isTesting) => commit(types.SET_IS_TESTING, isTesting);
export const isInheriting = state => (state.adminState === null ? false : !state.override); export const isInheriting = state => (state.adminState === null ? false : !state.override);
export const isSavingOrTesting = state => state.isSaving || state.isTesting;
export const propsSource = (state, getters) => export const propsSource = (state, getters) =>
getters.isInheriting ? state.adminState : state.customState; getters.isInheriting ? state.adminState : state.customState;
......
export const SET_OVERRIDE = 'SET_OVERRIDE'; export const SET_OVERRIDE = 'SET_OVERRIDE';
export const SET_IS_SAVING = 'SET_IS_SAVING';
export const SET_IS_TESTING = 'SET_IS_TESTING';
...@@ -4,4 +4,10 @@ export default { ...@@ -4,4 +4,10 @@ export default {
[types.SET_OVERRIDE](state, override) { [types.SET_OVERRIDE](state, override) {
state.override = override; state.override = override;
}, },
[types.SET_IS_SAVING](state, isSaving) {
state.isSaving = isSaving;
},
[types.SET_IS_TESTING](state, isTesting) {
state.isTesting = isTesting;
},
}; };
...@@ -5,5 +5,7 @@ export default ({ adminState = null, customState = {} } = {}) => { ...@@ -5,5 +5,7 @@ export default ({ adminState = null, customState = {} } = {}) => {
override, override,
adminState, adminState,
customState, customState,
isSaving: false,
isTesting: false,
}; };
}; };
import $ from 'jquery'; import $ from 'jquery';
import axios from '../lib/utils/axios_utils'; import axios from '../lib/utils/axios_utils';
import { deprecatedCreateFlash as flash } from '../flash'; import { __, s__ } from '~/locale';
import { __ } from '~/locale'; import toast from '~/vue_shared/plugins/global_toast';
import initForm from './edit'; import initForm from './edit';
import eventHub from './edit/event_hub'; import eventHub from './edit/event_hub';
...@@ -10,65 +10,63 @@ export default class IntegrationSettingsForm { ...@@ -10,65 +10,63 @@ export default class IntegrationSettingsForm {
this.$form = $(formSelector); this.$form = $(formSelector);
this.formActive = false; this.formActive = false;
this.vue = null;
// Form Metadata // Form Metadata
this.canTestService = this.$form.data('canTest');
this.testEndPoint = this.$form.data('testUrl'); this.testEndPoint = this.$form.data('testUrl');
// Form Child Elements
this.$submitBtn = this.$form.find('button[type="submit"]');
this.$submitBtnLoader = this.$submitBtn.find('.js-btn-spinner');
this.$submitBtnLabel = this.$submitBtn.find('.js-btn-label');
} }
init() { init() {
// Init Vue component // Init Vue component
initForm( this.vue = initForm(
document.querySelector('.js-vue-integration-settings'), document.querySelector('.js-vue-integration-settings'),
document.querySelector('.js-vue-admin-integration-settings'), document.querySelector('.js-vue-admin-integration-settings'),
); );
eventHub.$on('toggle', active => { eventHub.$on('toggle', active => {
this.formActive = active; this.formActive = active;
this.handleServiceToggle(); this.toggleServiceState();
});
eventHub.$on('testIntegration', () => {
this.testIntegration();
});
eventHub.$on('saveIntegration', () => {
this.saveIntegration();
}); });
// Bind Event Listeners
this.$submitBtn.on('click', e => this.handleSettingsSave(e));
} }
handleSettingsSave(e) { saveIntegration() {
// Check if Service is marked active, as if not marked active, // Service was marked active so now we check;
// We can skip testing it and directly go ahead to allow form to // 1) If form contents are valid
// be submitted // 2) If this service can be saved
if (!this.formActive) { // If both conditions are true, we override form submission
return; // and save the service using provided configuration.
if (this.$form.get(0).checkValidity()) {
this.$form.submit();
} else {
eventHub.$emit('validateForm');
this.vue.$store.dispatch('setIsSaving', false);
} }
}
testIntegration() {
// Service was marked active so now we check; // Service was marked active so now we check;
// 1) If form contents are valid // 1) If form contents are valid
// 2) If this service can be tested // 2) If this service can be tested
// If both conditions are true, we override form submission // If both conditions are true, we override form submission
// and test the service using provided configuration. // and test the service using provided configuration.
if (this.$form.get(0).checkValidity()) { if (this.$form.get(0).checkValidity()) {
if (this.canTestService) { // eslint-disable-next-line no-jquery/no-serialize
e.preventDefault(); this.testSettings(this.$form.serialize());
// eslint-disable-next-line no-jquery/no-serialize
this.testSettings(this.$form.serialize());
}
} else { } else {
e.preventDefault();
eventHub.$emit('validateForm'); eventHub.$emit('validateForm');
this.vue.$store.dispatch('setIsTesting', false);
} }
} }
handleServiceToggle() {
this.toggleServiceState();
}
/** /**
* Change Form's validation enforcement based on service status (active/inactive) * Change Form's validation enforcement based on service status (active/inactive)
*/ */
toggleServiceState() { toggleServiceState() {
this.toggleSubmitBtnLabel();
if (this.formActive) { if (this.formActive) {
this.$form.removeAttr('novalidate'); this.$form.removeAttr('novalidate');
} else if (!this.$form.attr('novalidate')) { } else if (!this.$form.attr('novalidate')) {
...@@ -76,68 +74,24 @@ export default class IntegrationSettingsForm { ...@@ -76,68 +74,24 @@ export default class IntegrationSettingsForm {
} }
} }
/**
* Toggle Submit button label based on Integration status and ability to test service
*/
toggleSubmitBtnLabel() {
let btnLabel = __('Save changes');
if (this.formActive && this.canTestService) {
btnLabel = __('Test settings and save changes');
}
this.$submitBtnLabel.text(btnLabel);
}
/**
* Toggle Submit button state based on provided boolean value of `saveTestActive`
* When enabled, it does two things, and reverts back when disabled
*
* 1. It shows load spinner on submit button
* 2. Makes submit button disabled
*/
toggleSubmitBtnState(saveTestActive) {
if (saveTestActive) {
this.$submitBtn.disable();
this.$submitBtnLoader.removeClass('hidden');
} else {
this.$submitBtn.enable();
this.$submitBtnLoader.addClass('hidden');
}
}
/** /**
* Test Integration config * Test Integration config
*/ */
testSettings(formData) { testSettings(formData) {
this.toggleSubmitBtnState(true);
return axios return axios
.put(this.testEndPoint, formData) .put(this.testEndPoint, formData)
.then(({ data }) => { .then(({ data }) => {
if (data.error) { if (data.error) {
let flashActions; toast(`${data.message} ${data.service_response}`);
if (data.test_failed) {
flashActions = {
title: __('Save anyway'),
clickHandler: e => {
e.preventDefault();
this.$form.submit();
},
};
}
flash(`${data.message} ${data.service_response}`, 'alert', document, flashActions);
} else { } else {
this.$form.submit(); toast(s__('Integrations|Connection successful.'));
} }
this.toggleSubmitBtnState(false);
}) })
.catch(() => { .catch(() => {
flash(__('Something went wrong on our end.')); toast(__('Something went wrong on our end.'));
this.toggleSubmitBtnState(false); })
.finally(() => {
this.vue.$store.dispatch('setIsTesting', false);
}); });
} }
} }
...@@ -56,9 +56,11 @@ module IntegrationsActions ...@@ -56,9 +56,11 @@ module IntegrationsActions
end end
def success_message def success_message
message = integration.active? ? _('activated') : _('settings saved, but not activated') if integration.active?
s_('Integrations|%{integration} settings saved and active.') % { integration: integration.title }
_('%{service_title} %{message}.') % { service_title: integration.title, message: message } else
s_('Integrations|%{integration} settings saved, but not active.') % { integration: integration.title }
end
end end
def serialize_as_json def serialize_as_json
......
...@@ -65,18 +65,20 @@ class Projects::ServicesController < Projects::ApplicationController ...@@ -65,18 +65,20 @@ class Projects::ServicesController < Projects::ApplicationController
result = ::Integrations::Test::ProjectService.new(@service, current_user, params[:event]).execute result = ::Integrations::Test::ProjectService.new(@service, current_user, params[:event]).execute
unless result[:success] unless result[:success]
return { error: true, message: _('Test failed.'), service_response: result[:message].to_s, test_failed: true } return { error: true, message: s_('Integrations|Connection failed. Please check your settings.'), service_response: result[:message].to_s, test_failed: true }
end end
{} {}
rescue Gitlab::HTTP::BlockedUrlError => e rescue Gitlab::HTTP::BlockedUrlError => e
{ error: true, message: _('Test failed.'), service_response: e.message, test_failed: true } { error: true, message: s_('Integrations|Connection failed. Please check your settings.'), service_response: e.message, test_failed: true }
end end
def success_message def success_message
message = @service.active? ? _('activated') : _('settings saved, but not activated') if @service.active?
s_('Integrations|%{integration} settings saved and active.') % { integration: @service.title }
_('%{service_title} %{message}.') % { service_title: @service.title, message: message } else
s_('Integrations|%{integration} settings saved, but not active.') % { integration: @service.title }
end
end end
def service def service
......
...@@ -96,7 +96,11 @@ module ServicesHelper ...@@ -96,7 +96,11 @@ module ServicesHelper
trigger_events: trigger_events_for_service(integration), trigger_events: trigger_events_for_service(integration),
fields: fields_for_service(integration), fields: fields_for_service(integration),
inherit_from_id: integration.inherit_from_id, inherit_from_id: integration.inherit_from_id,
integration_level: integration_level(integration) integration_level: integration_level(integration),
editable: integration.editable?.to_s,
cancel_path: scoped_integrations_path,
can_test: integration.can_test?.to_s,
test_path: scoped_test_integration_path(integration)
} }
end end
......
...@@ -5,6 +5,3 @@ ...@@ -5,6 +5,3 @@
= form_for :service, url: admin_application_settings_service_path, method: :put, html: { class: 'fieldset-form js-integration-settings-form' } do |form| = form_for :service, url: admin_application_settings_service_path, method: :put, html: { class: 'fieldset-form js-integration-settings-form' } do |form|
= render 'shared/service_settings', form: form, integration: @service = render 'shared/service_settings', form: form, integration: @service
.footer-block.row-content-block
= form.submit 'Save', class: 'btn btn-success'
...@@ -10,4 +10,4 @@ ...@@ -10,4 +10,4 @@
%span= value %span= value
- if %w(alert notice success).include?(key) - if %w(alert notice success).include?(key)
%div{ class: "close-icon-wrapper js-close-icon" } %div{ class: "close-icon-wrapper js-close-icon" }
= sprite_icon('close', css_class: 'close-icon') = sprite_icon('close', css_class: 'close-icon gl-vertical-align-baseline!')
...@@ -13,13 +13,9 @@ ...@@ -13,13 +13,9 @@
- if @service.respond_to?(:detailed_description) - if @service.respond_to?(:detailed_description)
%p= @service.detailed_description %p= @service.detailed_description
.col-lg-8 .col-lg-8
= form_for(@service, as: :service, url: scoped_integration_path(@service), method: :put, html: { class: 'gl-show-field-errors integration-settings-form js-integration-settings-form', data: { 'can-test' => @service.can_test?, 'test-url' => test_project_service_path(@project, @service) } }) do |form| = form_for(@service, as: :service, url: scoped_integration_path(@service), method: :put, html: { class: 'gl-show-field-errors integration-settings-form js-integration-settings-form', data: { 'test-url' => test_project_service_path(@project, @service) } }) do |form|
= render 'shared/service_settings', form: form, integration: @service = render 'shared/service_settings', form: form, integration: @service
.footer-block.row-content-block{ :class => "#{'gl-display-none' if @service.is_a?(AlertsService)}" } %input{ id: 'services_redirect_to', type: 'hidden', name: 'redirect_to', value: request.referrer }
%input{ id: 'services_redirect_to', type: 'hidden', name: 'redirect_to', value: request.referrer }
= service_save_button(disabled: @service.is_a?(AlertsService))
&nbsp;
= link_to _('Cancel'), project_settings_integrations_path(@project), class: 'btn btn-cancel'
- if lookup_context.template_exists?('show', "projects/services/#{@service.to_param}", true) - if lookup_context.template_exists?('show', "projects/services/#{@service.to_param}", true)
%hr %hr
......
...@@ -6,10 +6,5 @@ ...@@ -6,10 +6,5 @@
= integration.title = integration.title
.col-lg-8 .col-lg-8
= form_for integration, as: :service, url: scoped_integration_path(integration), method: :put, html: { class: 'gl-show-field-errors integration-settings-form js-integration-settings-form', data: { 'can-test' => integration.can_test?, 'test-url' => scoped_test_integration_path(integration) } } do |form| = form_for integration, as: :service, url: scoped_integration_path(integration), method: :put, html: { class: 'gl-show-field-errors integration-settings-form js-integration-settings-form', data: { 'test-url' => scoped_test_integration_path(integration) } } do |form|
= render 'shared/service_settings', form: form, integration: integration = render 'shared/service_settings', form: form, integration: integration
- if integration.editable?
.footer-block.row-content-block
= service_save_button
= link_to _('Cancel'), scoped_integrations_path, class: 'btn btn-cancel'
---
title: Split "Test settings" and "Save changes" to separate buttons
merge_request: 37413
author:
type: changed
...@@ -16,8 +16,8 @@ ...@@ -16,8 +16,8 @@
.footer-block.row-content-block .footer-block.row-content-block
%button.btn.btn-success{ type: 'submit' } %button.btn.btn-success{ type: 'submit' }
.spinner.spinner-light.js-btn-spinner .spinner.spinner-light
%span.js-btn-label %span
Save changes Save changes
&nbsp; &nbsp;
= link_to 'Cancel', edit_project_service_path(@project, @service), class: 'btn btn-cancel' = link_to 'Cancel', edit_project_service_path(@project, @service), class: 'btn btn-cancel'
...@@ -36,7 +36,7 @@ RSpec.describe 'User activates GitHub Service' do ...@@ -36,7 +36,7 @@ RSpec.describe 'User activates GitHub Service' do
it 'activates service' do it 'activates service' do
click_button('Save') click_button('Save')
expect(page).to have_content('GitHub activated.') expect(page).to have_content('GitHub settings saved and active.')
end end
it 'renders a token field of type `password` for masking input' do it 'renders a token field of type `password` for masking input' do
...@@ -53,9 +53,9 @@ RSpec.describe 'User activates GitHub Service' do ...@@ -53,9 +53,9 @@ RSpec.describe 'User activates GitHub Service' do
headers: { 'Content-Type' => 'application/json' } headers: { 'Content-Type' => 'application/json' }
) )
click_button 'Test settings and save changes' click_test_then_save_integration(expect_test_to_fail: false)
expect(page).to have_content('GitHub activated.') expect(page).to have_content('GitHub settings saved and active.')
end end
end end
end end
......
...@@ -7,17 +7,20 @@ RSpec.describe 'User activates Jira', :js do ...@@ -7,17 +7,20 @@ RSpec.describe 'User activates Jira', :js do
include_context 'project service Jira context' include_context 'project service Jira context'
describe 'user sets and activates Jira Service' do describe 'user sets and activates Jira Service' do
before do
server_info = { key: 'value' }.to_json
stub_request(:get, test_url).with(basic_auth: %w(username password)).to_return(body: server_info)
end
context 'when Jira connection test succeeds' do context 'when Jira connection test succeeds' do
before do before do
stub_licensed_features(jira_issues_integration: true) stub_licensed_features(jira_issues_integration: true)
allow_any_instance_of(JiraService).to receive(:issues_enabled) { true } allow_any_instance_of(JiraService).to receive(:issues_enabled) { true }
server_info = { key: 'value' }.to_json
stub_request(:get, test_url).with(basic_auth: %w(username password)).to_return(body: server_info)
visit_project_integration('Jira') visit_project_integration('Jira')
fill_form fill_form
fill_in 'service_project_key', with: 'AB' fill_in 'service_project_key', with: 'AB'
click_test_integration click_test_then_save_integration(expect_test_to_fail: false)
end end
it 'adds Jira links to sidebar menu' do it 'adds Jira links to sidebar menu' do
...@@ -28,19 +31,23 @@ RSpec.describe 'User activates Jira', :js do ...@@ -28,19 +31,23 @@ RSpec.describe 'User activates Jira', :js do
expect(page).not_to have_link('Jira', href: url) expect(page).not_to have_link('Jira', href: url)
end end
end end
end
context 'when jira_issues_integration feature is not available' do context 'when jira_issues_integration feature is not available' do
before do before do
stub_licensed_features(jira_issues_integration: false) stub_licensed_features(jira_issues_integration: false)
end
it 'does not show Jira links to sidebar menu' do visit_project_integration('Jira')
page.within('.nav-sidebar') do fill_form
expect(page).not_to have_link('Jira Issues', href: project_integrations_jira_issues_path(project)) click_save_integration
expect(page).not_to have_link('Issue List', href: project_integrations_jira_issues_path(project), visible: false) end
expect(page).not_to have_link('Open Jira', href: url, visible: false)
expect(page).to have_link('Jira', href: url) it 'does not show Jira links in sidebar menu' do
end page.within('.nav-sidebar') do
expect(page).not_to have_link('Jira Issues', href: project_integrations_jira_issues_path(project))
expect(page).not_to have_link('Issue List', href: project_integrations_jira_issues_path(project), visible: false)
expect(page).not_to have_link('Open Jira', href: url, visible: false)
expect(page).to have_link('Jira', href: url)
end end
end end
end end
......
...@@ -703,9 +703,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha ...@@ -703,9 +703,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
msgid "%{service_title} %{message}."
msgstr ""
msgid "%{size} GiB" msgid "%{size} GiB"
msgstr "" msgstr ""
...@@ -13569,6 +13566,12 @@ msgstr "" ...@@ -13569,6 +13566,12 @@ msgstr ""
msgid "Integrations" msgid "Integrations"
msgstr "" msgstr ""
msgid "Integrations|%{integration} settings saved and active."
msgstr ""
msgid "Integrations|%{integration} settings saved, but not active."
msgstr ""
msgid "Integrations|All details" msgid "Integrations|All details"
msgstr "" msgstr ""
...@@ -13578,6 +13581,12 @@ msgstr "" ...@@ -13578,6 +13581,12 @@ msgstr ""
msgid "Integrations|Comment settings:" msgid "Integrations|Comment settings:"
msgstr "" msgstr ""
msgid "Integrations|Connection failed. Please check your settings."
msgstr ""
msgid "Integrations|Connection successful."
msgstr ""
msgid "Integrations|Default settings are inherited from the group level." msgid "Integrations|Default settings are inherited from the group level."
msgstr "" msgstr ""
...@@ -24798,10 +24807,7 @@ msgid_plural "Test coverage: %d hits" ...@@ -24798,10 +24807,7 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
msgid "Test failed." msgid "Test settings"
msgstr ""
msgid "Test settings and save changes"
msgstr "" msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests." msgid "TestHooks|Ensure one of your projects has merge requests."
...@@ -29434,9 +29440,6 @@ msgstr[1] "" ...@@ -29434,9 +29440,6 @@ msgstr[1] ""
msgid "access:" msgid "access:"
msgstr "" msgstr ""
msgid "activated"
msgstr ""
msgid "added %{created_at_timeago}" msgid "added %{created_at_timeago}"
msgstr "" msgstr ""
...@@ -30649,9 +30652,6 @@ msgstr "" ...@@ -30649,9 +30652,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request" msgid "security Reports|There was an error creating the merge request"
msgstr "" msgstr ""
msgid "settings saved, but not activated"
msgstr ""
msgid "severity|Critical" msgid "severity|Critical"
msgstr "" msgstr ""
......
...@@ -14,7 +14,7 @@ module QA ...@@ -14,7 +14,7 @@ module QA
element :password_field, ':data-qa-selector="`${fieldId}_field`"' # rubocop:disable QA/ElementWithPattern element :password_field, ':data-qa-selector="`${fieldId}_field`"' # rubocop:disable QA/ElementWithPattern
end end
view 'app/helpers/services_helper.rb' do view 'app/assets/javascripts/integrations/edit/components/integration_form.vue' do
element :save_changes_button element :save_changes_button
end end
......
...@@ -13,7 +13,7 @@ module QA ...@@ -13,7 +13,7 @@ module QA
element :service_jira_issue_transition_id_field, ':data-qa-selector="`${fieldId}_field`"' # rubocop:disable QA/ElementWithPattern element :service_jira_issue_transition_id_field, ':data-qa-selector="`${fieldId}_field`"' # rubocop:disable QA/ElementWithPattern
end end
view 'app/helpers/services_helper.rb' do view 'app/assets/javascripts/integrations/edit/components/integration_form.vue' do
element :save_changes_button element :save_changes_button
end end
......
...@@ -58,7 +58,7 @@ module QA ...@@ -58,7 +58,7 @@ module QA
end end
expect(page).not_to have_text("Url is blocked") expect(page).not_to have_text("Url is blocked")
expect(page).to have_text("Jira activated") expect(page).to have_text("Jira settings saved and active.")
end end
end end
......
...@@ -123,7 +123,7 @@ RSpec.describe Projects::ServicesController do ...@@ -123,7 +123,7 @@ RSpec.describe Projects::ServicesController do
expect(response).to be_successful expect(response).to be_successful
expect(json_response).to eq( expect(json_response).to eq(
'error' => true, 'error' => true,
'message' => 'Test failed.', 'message' => 'Connection failed. Please check your settings.',
'service_response' => '', 'service_response' => '',
'test_failed' => true 'test_failed' => true
) )
...@@ -136,7 +136,7 @@ RSpec.describe Projects::ServicesController do ...@@ -136,7 +136,7 @@ RSpec.describe Projects::ServicesController do
let(:service_params) { { active: true } } let(:service_params) { { active: true } }
let(:params) { project_params(service: service_params) } let(:params) { project_params(service: service_params) }
let(:message) { 'Jira activated.' } let(:message) { 'Jira settings saved and active.' }
let(:redirect_url) { edit_project_service_path(project, service) } let(:redirect_url) { edit_project_service_path(project, service) }
before do before do
...@@ -175,7 +175,7 @@ RSpec.describe Projects::ServicesController do ...@@ -175,7 +175,7 @@ RSpec.describe Projects::ServicesController do
context 'when param `active` is set to false' do context 'when param `active` is set to false' do
let(:service_params) { { active: false } } let(:service_params) { { active: false } }
let(:message) { 'Jira settings saved, but not activated.' } let(:message) { 'Jira settings saved, but not active.' }
it_behaves_like 'service update' it_behaves_like 'service update'
end end
......
...@@ -232,7 +232,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n ...@@ -232,7 +232,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n
page.select 'All branches', from: 'Branches to be notified' page.select 'All branches', from: 'Branches to be notified'
check_all_events check_all_events
click_on 'Save' click_button 'Save changes'
expect(page).to have_content 'Application settings saved successfully' expect(page).to have_content 'Application settings saved successfully'
......
...@@ -16,7 +16,7 @@ RSpec.describe 'Admin activates Prometheus', :js do ...@@ -16,7 +16,7 @@ RSpec.describe 'Admin activates Prometheus', :js do
it 'activates service' do it 'activates service' do
check('Active') check('Active')
fill_in('API URL', with: 'http://prometheus.example.com') fill_in('API URL', with: 'http://prometheus.example.com')
click_button('Save') click_button('Save changes')
expect(page).to have_content('Application settings saved successfully') expect(page).to have_content('Application settings saved successfully')
end end
......
...@@ -12,6 +12,6 @@ RSpec.describe 'User activates Asana' do ...@@ -12,6 +12,6 @@ RSpec.describe 'User activates Asana' do
click_test_then_save_integration click_test_then_save_integration
expect(page).to have_content('Asana activated.') expect(page).to have_content('Asana settings saved and active.')
end end
end end
...@@ -13,8 +13,8 @@ RSpec.describe 'User activates Assembla' do ...@@ -13,8 +13,8 @@ RSpec.describe 'User activates Assembla' do
visit_project_integration('Assembla') visit_project_integration('Assembla')
fill_in('Token', with: 'verySecret') fill_in('Token', with: 'verySecret')
click_test_integration click_test_then_save_integration(expect_test_to_fail: false)
expect(page).to have_content('Assembla activated.') expect(page).to have_content('Assembla settings saved and active.')
end end
end end
...@@ -16,9 +16,9 @@ RSpec.describe 'User activates Atlassian Bamboo CI' do ...@@ -16,9 +16,9 @@ RSpec.describe 'User activates Atlassian Bamboo CI' do
fill_in('Username', with: 'user') fill_in('Username', with: 'user')
fill_in('Password', with: 'verySecret') fill_in('Password', with: 'verySecret')
click_test_integration click_test_then_save_integration(expect_test_to_fail: false)
expect(page).to have_content('Atlassian Bamboo CI activated.') expect(page).to have_content('Atlassian Bamboo CI settings saved and active.')
# Password field should not be filled in. # Password field should not be filled in.
click_link('Atlassian Bamboo CI') click_link('Atlassian Bamboo CI')
......
...@@ -9,8 +9,8 @@ RSpec.describe 'User activates Emails on push' do ...@@ -9,8 +9,8 @@ RSpec.describe 'User activates Emails on push' do
visit_project_integration('Emails on push') visit_project_integration('Emails on push')
fill_in('Recipients', with: 'qa@company.name') fill_in('Recipients', with: 'qa@company.name')
click_test_integration click_test_then_save_integration(expect_test_to_fail: false)
expect(page).to have_content('Emails on push activated.') expect(page).to have_content('Emails on push settings saved and active.')
end end
end end
...@@ -15,8 +15,8 @@ RSpec.describe 'User activates Flowdock' do ...@@ -15,8 +15,8 @@ RSpec.describe 'User activates Flowdock' do
visit_project_integration('Flowdock') visit_project_integration('Flowdock')
fill_in('Token', with: 'verySecret') fill_in('Token', with: 'verySecret')
click_test_integration click_test_then_save_integration(expect_test_to_fail: false)
expect(page).to have_content('Flowdock activated.') expect(page).to have_content('Flowdock settings saved and active.')
end end
end end
...@@ -5,7 +5,7 @@ require 'spec_helper' ...@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'User activates HipChat', :js do RSpec.describe 'User activates HipChat', :js do
include_context 'project service activation' include_context 'project service activation'
context 'with standart settings' do context 'with standard settings' do
before do before do
stub_request(:post, /.*api.hipchat.com.*/) stub_request(:post, /.*api.hipchat.com.*/)
end end
...@@ -15,9 +15,9 @@ RSpec.describe 'User activates HipChat', :js do ...@@ -15,9 +15,9 @@ RSpec.describe 'User activates HipChat', :js do
fill_in('Room', with: 'gitlab') fill_in('Room', with: 'gitlab')
fill_in('Token', with: 'verySecret') fill_in('Token', with: 'verySecret')
click_test_integration click_test_then_save_integration(expect_test_to_fail: false)
expect(page).to have_content('HipChat activated.') expect(page).to have_content('HipChat settings saved and active.')
end end
end end
...@@ -32,9 +32,9 @@ RSpec.describe 'User activates HipChat', :js do ...@@ -32,9 +32,9 @@ RSpec.describe 'User activates HipChat', :js do
fill_in('Token', with: 'secretCustom') fill_in('Token', with: 'secretCustom')
fill_in('Server', with: 'https://chat.example.com') fill_in('Server', with: 'https://chat.example.com')
click_test_integration click_test_then_save_integration(expect_test_to_fail: false)
expect(page).to have_content('HipChat activated.') expect(page).to have_content('HipChat settings saved and active.')
end end
end end
end end
...@@ -10,8 +10,8 @@ RSpec.describe 'User activates Irker (IRC gateway)' do ...@@ -10,8 +10,8 @@ RSpec.describe 'User activates Irker (IRC gateway)' do
check('Colorize messages') check('Colorize messages')
fill_in('Recipients', with: 'irc://chat.freenode.net/#commits') fill_in('Recipients', with: 'irc://chat.freenode.net/#commits')
click_test_integration click_test_then_save_integration(expect_test_to_fail: false)
expect(page).to have_content('Irker (IRC gateway) activated.') expect(page).to have_content('Irker (IRC gateway) settings saved and active.')
end end
end end
...@@ -26,14 +26,14 @@ RSpec.describe 'User activates issue tracker', :js do ...@@ -26,14 +26,14 @@ RSpec.describe 'User activates issue tracker', :js do
fill_form(skip_new_issue_url: skip_new_issue_url) fill_form(skip_new_issue_url: skip_new_issue_url)
if skip_test if skip_test
click_button('Save changes') click_save_integration
else else
click_test_integration click_test_then_save_integration(expect_test_to_fail: false)
end end
end end
it 'activates the service' do it 'activates the service' do
expect(page).to have_content("#{tracker} activated.") expect(page).to have_content("#{tracker} settings saved and active.")
expect(current_path).to eq(edit_project_service_path(project, tracker.parameterize(separator: '_'))) expect(current_path).to eq(edit_project_service_path(project, tracker.parameterize(separator: '_')))
end end
...@@ -57,7 +57,7 @@ RSpec.describe 'User activates issue tracker', :js do ...@@ -57,7 +57,7 @@ RSpec.describe 'User activates issue tracker', :js do
click_test_then_save_integration click_test_then_save_integration
end end
expect(page).to have_content("#{tracker} activated.") expect(page).to have_content("#{tracker} settings saved and active.")
expect(current_path).to eq(edit_project_service_path(project, tracker.parameterize(separator: '_'))) expect(current_path).to eq(edit_project_service_path(project, tracker.parameterize(separator: '_')))
end end
end end
...@@ -72,7 +72,7 @@ RSpec.describe 'User activates issue tracker', :js do ...@@ -72,7 +72,7 @@ RSpec.describe 'User activates issue tracker', :js do
end end
it 'saves but does not activate the service' do it 'saves but does not activate the service' do
expect(page).to have_content("#{tracker} settings saved, but not activated.") expect(page).to have_content("#{tracker} settings saved, but not active.")
expect(current_path).to eq(edit_project_service_path(project, tracker.parameterize(separator: '_'))) expect(current_path).to eq(edit_project_service_path(project, tracker.parameterize(separator: '_')))
end end
......
...@@ -18,8 +18,8 @@ RSpec.describe 'User activates JetBrains TeamCity CI' do ...@@ -18,8 +18,8 @@ RSpec.describe 'User activates JetBrains TeamCity CI' do
fill_in('Username', with: 'user') fill_in('Username', with: 'user')
fill_in('Password', with: 'verySecret') fill_in('Password', with: 'verySecret')
click_test_integration click_test_then_save_integration(expect_test_to_fail: false)
expect(page).to have_content('JetBrains TeamCity CI activated.') expect(page).to have_content('JetBrains TeamCity CI settings saved and active.')
end end
end end
...@@ -6,7 +6,7 @@ RSpec.describe 'User activates Jira', :js do ...@@ -6,7 +6,7 @@ RSpec.describe 'User activates Jira', :js do
include_context 'project service activation' include_context 'project service activation'
include_context 'project service Jira context' include_context 'project service Jira context'
describe 'user sets and activates Jira Service' do describe 'user tests Jira Service' do
context 'when Jira connection test succeeds' do context 'when Jira connection test succeeds' do
before do before do
server_info = { key: 'value' }.to_json server_info = { key: 'value' }.to_json
...@@ -14,11 +14,11 @@ RSpec.describe 'User activates Jira', :js do ...@@ -14,11 +14,11 @@ RSpec.describe 'User activates Jira', :js do
visit_project_integration('Jira') visit_project_integration('Jira')
fill_form fill_form
click_test_integration click_test_then_save_integration(expect_test_to_fail: false)
end end
it 'activates the Jira service' do it 'activates the Jira service' do
expect(page).to have_content('Jira activated.') expect(page).to have_content('Jira settings saved and active.')
expect(current_path).to eq(edit_project_service_path(project, :jira)) expect(current_path).to eq(edit_project_service_path(project, :jira))
end end
...@@ -54,7 +54,7 @@ RSpec.describe 'User activates Jira', :js do ...@@ -54,7 +54,7 @@ RSpec.describe 'User activates Jira', :js do
fill_form fill_form
click_test_then_save_integration click_test_then_save_integration
expect(page).to have_content('Jira activated.') expect(page).to have_content('Jira settings saved and active.')
expect(current_path).to eq(edit_project_service_path(project, :jira)) expect(current_path).to eq(edit_project_service_path(project, :jira))
end end
end end
...@@ -67,11 +67,11 @@ RSpec.describe 'User activates Jira', :js do ...@@ -67,11 +67,11 @@ RSpec.describe 'User activates Jira', :js do
stub_jira_service_test stub_jira_service_test
visit_project_integration('Jira') visit_project_integration('Jira')
fill_form(disable: true) fill_form(disable: true)
click_button('Save changes') click_save_integration
end end
it 'saves but does not activate the Jira service' do it 'saves but does not activate the Jira service' do
expect(page).to have_content('Jira settings saved, but not activated.') expect(page).to have_content('Jira settings saved, but not active.')
expect(current_path).to eq(edit_project_service_path(project, :jira)) expect(current_path).to eq(edit_project_service_path(project, :jira))
end end
......
...@@ -29,20 +29,20 @@ RSpec.describe 'Set up Mattermost slash commands', :js do ...@@ -29,20 +29,20 @@ RSpec.describe 'Set up Mattermost slash commands', :js do
fill_in 'service_token', with: token fill_in 'service_token', with: token
click_active_checkbox click_active_checkbox
click_on 'Save changes' click_save_integration
expect(current_path).to eq(edit_project_service_path(project, :mattermost_slash_commands)) expect(current_path).to eq(edit_project_service_path(project, :mattermost_slash_commands))
expect(page).to have_content('Mattermost slash commands settings saved, but not activated.') expect(page).to have_content('Mattermost slash commands settings saved, but not active.')
end end
it 'redirects to the integrations page after activating' do it 'redirects to the integrations page after activating' do
token = ('a'..'z').to_a.join token = ('a'..'z').to_a.join
fill_in 'service_token', with: token fill_in 'service_token', with: token
click_on 'Save changes' click_save_integration
expect(current_path).to eq(edit_project_service_path(project, :mattermost_slash_commands)) expect(current_path).to eq(edit_project_service_path(project, :mattermost_slash_commands))
expect(page).to have_content('Mattermost slash commands activated.') expect(page).to have_content('Mattermost slash commands settings saved and active.')
end end
it 'shows the add to mattermost button' do it 'shows the add to mattermost button' do
......
...@@ -16,6 +16,6 @@ RSpec.describe 'User activates Packagist' do ...@@ -16,6 +16,6 @@ RSpec.describe 'User activates Packagist' do
click_test_then_save_integration click_test_then_save_integration
expect(page).to have_content('Packagist activated.') expect(page).to have_content('Packagist settings saved and active.')
end end
end end
...@@ -13,8 +13,8 @@ RSpec.describe 'User activates PivotalTracker' do ...@@ -13,8 +13,8 @@ RSpec.describe 'User activates PivotalTracker' do
visit_project_integration('PivotalTracker') visit_project_integration('PivotalTracker')
fill_in('Token', with: 'verySecret') fill_in('Token', with: 'verySecret')
click_test_integration click_test_then_save_integration(expect_test_to_fail: false)
expect(page).to have_content('PivotalTracker activated.') expect(page).to have_content('PivotalTracker settings saved and active.')
end end
end end
...@@ -16,7 +16,7 @@ RSpec.describe 'User activates Prometheus' do ...@@ -16,7 +16,7 @@ RSpec.describe 'User activates Prometheus' do
click_button('Save changes') click_button('Save changes')
expect(page).not_to have_content('Prometheus activated.') expect(page).not_to have_content('Prometheus settings saved and active.')
expect(page).to have_content('Fields on this page has been deprecated.') expect(page).to have_content('Fields on this page has been deprecated.')
end end
end end
...@@ -17,8 +17,8 @@ RSpec.describe 'User activates Pushover' do ...@@ -17,8 +17,8 @@ RSpec.describe 'User activates Pushover' do
select('High Priority', from: 'Priority') select('High Priority', from: 'Priority')
select('Bike', from: 'Sound') select('Bike', from: 'Sound')
click_test_integration click_test_then_save_integration(expect_test_to_fail: false)
expect(page).to have_content('Pushover activated.') expect(page).to have_content('Pushover settings saved and active.')
end end
end end
...@@ -15,7 +15,7 @@ RSpec.describe 'User activates Slack notifications', :js do ...@@ -15,7 +15,7 @@ RSpec.describe 'User activates Slack notifications', :js do
click_test_then_save_integration click_test_then_save_integration
expect(page).to have_content('Slack notifications activated.') expect(page).to have_content('Slack notifications settings saved and active.')
end end
end end
......
...@@ -25,7 +25,7 @@ RSpec.describe 'Slack slash commands', :js do ...@@ -25,7 +25,7 @@ RSpec.describe 'Slack slash commands', :js do
click_on 'Save' click_on 'Save'
expect(current_path).to eq(edit_project_service_path(project, :slack_slash_commands)) expect(current_path).to eq(edit_project_service_path(project, :slack_slash_commands))
expect(page).to have_content('Slack slash commands settings saved, but not activated.') expect(page).to have_content('Slack slash commands settings saved, but not active.')
end end
it 'redirects to the integrations page after activating' do it 'redirects to the integrations page after activating' do
...@@ -33,7 +33,7 @@ RSpec.describe 'Slack slash commands', :js do ...@@ -33,7 +33,7 @@ RSpec.describe 'Slack slash commands', :js do
click_on 'Save' click_on 'Save'
expect(current_path).to eq(edit_project_service_path(project, :slack_slash_commands)) expect(current_path).to eq(edit_project_service_path(project, :slack_slash_commands))
expect(page).to have_content('Slack slash commands activated.') expect(page).to have_content('Slack slash commands settings saved and active.')
end end
it 'shows the correct trigger url' do it 'shows the correct trigger url' do
......
...@@ -5,6 +5,8 @@ describe('Integration form state factory', () => { ...@@ -5,6 +5,8 @@ describe('Integration form state factory', () => {
expect(createState()).toEqual({ expect(createState()).toEqual({
adminState: null, adminState: null,
customState: {}, customState: {},
isSaving: false,
isTesting: false,
override: false, override: false,
}); });
}); });
......
import $ from 'jquery';
import MockAdaptor from 'axios-mock-adapter'; import MockAdaptor from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import IntegrationSettingsForm from '~/integrations/integration_settings_form'; import IntegrationSettingsForm from '~/integrations/integration_settings_form';
import toast from '~/vue_shared/plugins/global_toast';
jest.mock('~/vue_shared/plugins/global_toast');
describe('IntegrationSettingsForm', () => { describe('IntegrationSettingsForm', () => {
const FIXTURE = 'services/edit_service.html'; const FIXTURE = 'services/edit_service.html';
...@@ -11,7 +13,7 @@ describe('IntegrationSettingsForm', () => { ...@@ -11,7 +13,7 @@ describe('IntegrationSettingsForm', () => {
loadFixtures(FIXTURE); loadFixtures(FIXTURE);
}); });
describe('contructor', () => { describe('constructor', () => {
let integrationSettingsForm; let integrationSettingsForm;
beforeEach(() => { beforeEach(() => {
...@@ -24,16 +26,10 @@ describe('IntegrationSettingsForm', () => { ...@@ -24,16 +26,10 @@ describe('IntegrationSettingsForm', () => {
expect(integrationSettingsForm.$form).toBeDefined(); expect(integrationSettingsForm.$form).toBeDefined();
expect(integrationSettingsForm.$form.prop('nodeName')).toEqual('FORM'); expect(integrationSettingsForm.$form.prop('nodeName')).toEqual('FORM');
expect(integrationSettingsForm.formActive).toBeDefined(); expect(integrationSettingsForm.formActive).toBeDefined();
// Form Child Elements
expect(integrationSettingsForm.$submitBtn).toBeDefined();
expect(integrationSettingsForm.$submitBtnLoader).toBeDefined();
expect(integrationSettingsForm.$submitBtnLabel).toBeDefined();
}); });
it('should initialize form metadata on class object', () => { it('should initialize form metadata on class object', () => {
expect(integrationSettingsForm.testEndPoint).toBeDefined(); expect(integrationSettingsForm.testEndPoint).toBeDefined();
expect(integrationSettingsForm.canTestService).toBeDefined();
}); });
}); });
...@@ -59,69 +55,6 @@ describe('IntegrationSettingsForm', () => { ...@@ -59,69 +55,6 @@ describe('IntegrationSettingsForm', () => {
}); });
}); });
describe('toggleSubmitBtnLabel', () => {
let integrationSettingsForm;
beforeEach(() => {
integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form');
});
it('should set Save button label to "Test settings and save changes" when serviceActive & canTestService are `true`', () => {
integrationSettingsForm.canTestService = true;
integrationSettingsForm.formActive = true;
integrationSettingsForm.toggleSubmitBtnLabel();
expect(integrationSettingsForm.$submitBtnLabel.text()).toEqual(
'Test settings and save changes',
);
});
it('should set Save button label to "Save changes" when either serviceActive or canTestService (or both) is `false`', () => {
integrationSettingsForm.canTestService = false;
integrationSettingsForm.formActive = false;
integrationSettingsForm.toggleSubmitBtnLabel();
expect(integrationSettingsForm.$submitBtnLabel.text()).toEqual('Save changes');
integrationSettingsForm.formActive = true;
integrationSettingsForm.toggleSubmitBtnLabel();
expect(integrationSettingsForm.$submitBtnLabel.text()).toEqual('Save changes');
integrationSettingsForm.canTestService = true;
integrationSettingsForm.formActive = false;
integrationSettingsForm.toggleSubmitBtnLabel();
expect(integrationSettingsForm.$submitBtnLabel.text()).toEqual('Save changes');
});
});
describe('toggleSubmitBtnState', () => {
let integrationSettingsForm;
beforeEach(() => {
integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form');
});
it('should disable Save button and show loader animation when called with `true`', () => {
integrationSettingsForm.toggleSubmitBtnState(true);
expect(integrationSettingsForm.$submitBtn.is(':disabled')).toBeTruthy();
expect(integrationSettingsForm.$submitBtnLoader.hasClass('hidden')).toBeFalsy();
});
it('should enable Save button and hide loader animation when called with `false`', () => {
integrationSettingsForm.toggleSubmitBtnState(false);
expect(integrationSettingsForm.$submitBtn.is(':disabled')).toBeFalsy();
expect(integrationSettingsForm.$submitBtnLoader.hasClass('hidden')).toBeTruthy();
});
});
describe('testSettings', () => { describe('testSettings', () => {
let integrationSettingsForm; let integrationSettingsForm;
let formData; let formData;
...@@ -133,6 +66,8 @@ describe('IntegrationSettingsForm', () => { ...@@ -133,6 +66,8 @@ describe('IntegrationSettingsForm', () => {
jest.spyOn(axios, 'put'); jest.spyOn(axios, 'put');
integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form'); integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form');
integrationSettingsForm.init();
// eslint-disable-next-line no-jquery/no-serialize // eslint-disable-next-line no-jquery/no-serialize
formData = integrationSettingsForm.$form.serialize(); formData = integrationSettingsForm.$form.serialize();
}); });
...@@ -141,128 +76,60 @@ describe('IntegrationSettingsForm', () => { ...@@ -141,128 +76,60 @@ describe('IntegrationSettingsForm', () => {
mock.restore(); mock.restore();
}); });
it('should make an ajax request with provided `formData`', () => { it('should make an ajax request with provided `formData`', async () => {
return integrationSettingsForm.testSettings(formData).then(() => { await integrationSettingsForm.testSettings(formData);
expect(axios.put).toHaveBeenCalledWith(integrationSettingsForm.testEndPoint, formData);
});
});
it('should show error Flash with `Save anyway` action if ajax request responds with error in test', () => {
const errorMessage = 'Test failed.';
mock.onPut(integrationSettingsForm.testEndPoint).reply(200, {
error: true,
message: errorMessage,
service_response: 'some error',
test_failed: true,
});
return integrationSettingsForm.testSettings(formData).then(() => { expect(axios.put).toHaveBeenCalledWith(integrationSettingsForm.testEndPoint, formData);
const $flashContainer = $('.flash-container');
expect(
$flashContainer
.find('.flash-text')
.text()
.trim(),
).toEqual('Test failed. some error');
expect($flashContainer.find('.flash-action')).toBeDefined();
expect(
$flashContainer
.find('.flash-action')
.text()
.trim(),
).toEqual('Save anyway');
});
}); });
it('should not show error Flash with `Save anyway` action if ajax request responds with error in validation', () => { it('should show success message if test is successful', async () => {
const errorMessage = 'Validations failed.';
mock.onPut(integrationSettingsForm.testEndPoint).reply(200, {
error: true,
message: errorMessage,
service_response: 'some error',
test_failed: false,
});
return integrationSettingsForm.testSettings(formData).then(() => {
const $flashContainer = $('.flash-container');
expect(
$flashContainer
.find('.flash-text')
.text()
.trim(),
).toEqual('Validations failed. some error');
expect($flashContainer.find('.flash-action')).toBeDefined();
expect(
$flashContainer
.find('.flash-action')
.text()
.trim(),
).toEqual('');
});
});
it('should submit form if ajax request responds without any error in test', () => {
jest.spyOn(integrationSettingsForm.$form, 'submit').mockImplementation(() => {}); jest.spyOn(integrationSettingsForm.$form, 'submit').mockImplementation(() => {});
mock.onPut(integrationSettingsForm.testEndPoint).reply(200, { mock.onPut(integrationSettingsForm.testEndPoint).reply(200, {
error: false, error: false,
}); });
return integrationSettingsForm.testSettings(formData).then(() => { await integrationSettingsForm.testSettings(formData);
expect(integrationSettingsForm.$form.submit).toHaveBeenCalled();
});
});
it('should submit form when clicked on `Save anyway` action of error Flash', () => { expect(toast).toHaveBeenCalledWith('Connection successful.');
jest.spyOn(integrationSettingsForm.$form, 'submit').mockImplementation(() => {}); });
it('should show error message if ajax request responds with test error', async () => {
const errorMessage = 'Test failed.'; const errorMessage = 'Test failed.';
const serviceResponse = 'some error';
mock.onPut(integrationSettingsForm.testEndPoint).reply(200, { mock.onPut(integrationSettingsForm.testEndPoint).reply(200, {
error: true, error: true,
message: errorMessage, message: errorMessage,
test_failed: true, service_response: serviceResponse,
test_failed: false,
}); });
return integrationSettingsForm await integrationSettingsForm.testSettings(formData);
.testSettings(formData)
.then(() => {
const $flashAction = $('.flash-container .flash-action');
expect($flashAction).toBeDefined(); expect(toast).toHaveBeenCalledWith(`${errorMessage} ${serviceResponse}`);
$flashAction.get(0).click();
})
.then(() => {
expect(integrationSettingsForm.$form.submit).toHaveBeenCalled();
});
}); });
it('should show error Flash if ajax request failed', () => { it('should show error message if ajax request failed', async () => {
const errorMessage = 'Something went wrong on our end.'; const errorMessage = 'Something went wrong on our end.';
mock.onPut(integrationSettingsForm.testEndPoint).networkError(); mock.onPut(integrationSettingsForm.testEndPoint).networkError();
return integrationSettingsForm.testSettings(formData).then(() => { await integrationSettingsForm.testSettings(formData);
expect(
$('.flash-container .flash-text') expect(toast).toHaveBeenCalledWith(errorMessage);
.text()
.trim(),
).toEqual(errorMessage);
});
}); });
it('should always call `toggleSubmitBtnState` with `false` once request is completed', () => { it('should always dispatch `setIsTesting` with `false` once request is completed', async () => {
const dispatchSpy = jest.fn();
mock.onPut(integrationSettingsForm.testEndPoint).networkError(); mock.onPut(integrationSettingsForm.testEndPoint).networkError();
jest.spyOn(integrationSettingsForm, 'toggleSubmitBtnState').mockImplementation(() => {}); integrationSettingsForm.vue.$store = { dispatch: dispatchSpy };
return integrationSettingsForm.testSettings(formData).then(() => { await integrationSettingsForm.testSettings(formData);
expect(integrationSettingsForm.toggleSubmitBtnState).toHaveBeenCalledWith(false);
}); expect(dispatchSpy).toHaveBeenCalledWith('setIsTesting', false);
}); });
}); });
}); });
...@@ -22,15 +22,23 @@ RSpec.shared_context 'project service activation' do ...@@ -22,15 +22,23 @@ RSpec.shared_context 'project service activation' do
find('input[name="service[active]"]').click find('input[name="service[active]"]').click
end end
def click_save_integration
click_button('Save changes')
end
def click_test_integration def click_test_integration
click_button('Test settings and save changes') click_link('Test settings')
end end
def click_test_then_save_integration def click_test_then_save_integration(expect_test_to_fail: true)
click_test_integration click_test_integration
expect(page).to have_content('Test failed.') if expect_test_to_fail
expect(page).to have_content('Connection failed.')
else
expect(page).to have_content('Connection successful.')
end
click_link('Save anyway') click_save_integration
end end
end end
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