Commit 835d4a5a authored by Lukas Eipert's avatar Lukas Eipert

Implementation of Override Form in Integrations

This properly exposes the admin settings to the frontend components if
they exist and allows the user to switch between them and custom
settings.

If the user chooses to use the admin settings, all form fields are
populated as disabled or readonly.
Co-authored-by: default avatarJustin Ho Tuan Duong <hduong@gitlab.com>
parent 9793e093
...@@ -23,7 +23,7 @@ export default { ...@@ -23,7 +23,7 @@ export default {
}; };
}, },
computed: { computed: {
...mapGetters(['disableForm']), ...mapGetters(['isInheriting']),
}, },
mounted() { mounted() {
// Initialize view // Initialize view
...@@ -46,7 +46,7 @@ export default { ...@@ -46,7 +46,7 @@ export default {
v-model="activated" v-model="activated"
name="service[active]" name="service[active]"
class="gl-display-block gl-line-height-0" class="gl-display-block gl-line-height-0"
:disabled="disableForm" :disabled="isInheriting"
@change="onToggle" @change="onToggle"
/> />
</gl-form-group> </gl-form-group>
...@@ -55,7 +55,12 @@ export default { ...@@ -55,7 +55,12 @@ export default {
<div class="form-group row" role="group"> <div class="form-group row" role="group">
<label for="service[active]" class="col-form-label col-sm-2">{{ __('Active') }}</label> <label for="service[active]" class="col-form-label col-sm-2">{{ __('Active') }}</label>
<div class="col-sm-10 pt-1"> <div class="col-sm-10 pt-1">
<gl-toggle v-model="activated" name="service[active]" @change="onToggle" /> <gl-toggle
v-model="activated"
name="service[active]"
:disabled="isInheriting"
@change="onToggle"
/>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -60,7 +60,7 @@ export default { ...@@ -60,7 +60,7 @@ export default {
}; };
}, },
computed: { computed: {
...mapGetters(['disableForm']), ...mapGetters(['isInheriting']),
isCheckbox() { isCheckbox() {
return this.type === 'checkbox'; return this.type === 'checkbox';
}, },
...@@ -109,7 +109,7 @@ export default { ...@@ -109,7 +109,7 @@ export default {
id: this.fieldId, id: this.fieldId,
name: this.fieldName, name: this.fieldName,
state: this.valid, state: this.valid,
disabled: this.disableForm, readonly: this.isInheriting,
}; };
}, },
valid() { valid() {
...@@ -145,12 +145,15 @@ export default { ...@@ -145,12 +145,15 @@ export default {
</template> </template>
<template v-if="isCheckbox"> <template v-if="isCheckbox">
<input :name="fieldName" type="hidden" value="false" /> <input :name="fieldName" type="hidden" :value="model || false" />
<gl-form-checkbox v-model="model" v-bind="sharedProps"> <gl-form-checkbox :id="fieldId" v-model="model" :disabled="isInheriting">
{{ humanizedTitle }} {{ humanizedTitle }}
</gl-form-checkbox> </gl-form-checkbox>
</template> </template>
<gl-form-select v-else-if="isSelect" v-model="model" v-bind="sharedProps" :options="options" /> <template v-else-if="isSelect">
<input type="hidden" :name="fieldName" :value="model" />
<gl-form-select :id="fieldId" v-model="model" :options="options" :disabled="isInheriting" />
</template>
<gl-form-textarea <gl-form-textarea
v-else-if="isTextarea" v-else-if="isTextarea"
v-model="model" v-model="model"
......
<script> <script>
import { mapState } from 'vuex'; import { mapState, mapActions, mapGetters } from 'vuex';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import OverrideDropdown from './override_dropdown.vue'; import OverrideDropdown from './override_dropdown.vue';
...@@ -20,57 +20,55 @@ export default { ...@@ -20,57 +20,55 @@ export default {
DynamicField, DynamicField,
}, },
mixins: [glFeatureFlagsMixin()], mixins: [glFeatureFlagsMixin()],
props: {
activeToggleProps: {
type: Object,
required: true,
},
showActive: {
type: Boolean,
required: true,
},
triggerFieldsProps: {
type: Object,
required: true,
},
jiraIssuesProps: {
type: Object,
required: true,
},
triggerEvents: {
type: Array,
required: false,
default: () => [],
},
fields: {
type: Array,
required: false,
default: () => [],
},
type: {
type: String,
required: true,
},
},
computed: { computed: {
...mapState(['overrideAvailable']), ...mapGetters(['currentKey', 'propsSource']),
...mapState(['adminState', 'override']),
isJira() { isJira() {
return this.type === 'jira'; return this.propsSource.type === 'jira';
}, },
showJiraIssuesFields() { showJiraIssuesFields() {
return this.isJira && this.glFeatures.jiraIssuesIntegration; return this.isJira && this.glFeatures.jiraIssuesIntegration;
}, },
}, },
methods: {
...mapActions(['setOverride']),
},
}; };
</script> </script>
<template> <template>
<div> <div>
<override-dropdown v-if="overrideAvailable" /> <override-dropdown
<active-toggle v-if="showActive" v-bind="activeToggleProps" /> v-if="adminState !== null"
<jira-trigger-fields v-if="isJira" v-bind="triggerFieldsProps" /> :inherit-from-id="adminState.id"
<trigger-fields v-else-if="triggerEvents.length" :events="triggerEvents" :type="type" /> :override="override"
<dynamic-field v-for="field in fields" :key="field.name" v-bind="field" /> @change="setOverride"
<jira-issues-fields v-if="showJiraIssuesFields" v-bind="jiraIssuesProps" /> />
<active-toggle
v-if="propsSource.showActive"
:key="`${currentKey}-active-toggle`"
v-bind="propsSource.activeToggleProps"
/>
<jira-trigger-fields
v-if="isJira"
:key="`${currentKey}-jira-trigger-fields`"
v-bind="propsSource.triggerFieldsProps"
/>
<trigger-fields
v-else-if="propsSource.triggerEvents.length"
:key="`${currentKey}-trigger-fields`"
:events="propsSource.triggerEvents"
:type="propsSource.type"
/>
<dynamic-field
v-for="field in propsSource.fields"
:key="`${currentKey}-${field.name}`"
v-bind="field"
/>
<jira-issues-fields
v-if="showJiraIssuesFields"
:key="`${currentKey}-jira-issues-fields`"
v-bind="propsSource.jiraIssuesProps"
/>
</div> </div>
</template> </template>
...@@ -89,8 +89,8 @@ export default { ...@@ -89,8 +89,8 @@ export default {
}} }}
</p> </p>
<template v-if="showJiraIssuesIntegration"> <template v-if="showJiraIssuesIntegration">
<input name="service[issues_enabled]" type="hidden" value="false" /> <input name="service[issues_enabled]" type="hidden" :value="enableJiraIssues || false" />
<gl-form-checkbox v-model="enableJiraIssues" name="service[issues_enabled]"> <gl-form-checkbox v-model="enableJiraIssues">
{{ s__('JiraService|Enable Jira issues') }} {{ s__('JiraService|Enable Jira issues') }}
<template #help> <template #help>
{{ {{
......
...@@ -56,7 +56,7 @@ export default { ...@@ -56,7 +56,7 @@ export default {
}; };
}, },
computed: { computed: {
...mapGetters(['disableForm']), ...mapGetters(['isInheriting']),
showEnableComments() { showEnableComments() {
return this.triggerCommit || this.triggerMergeRequest; return this.triggerCommit || this.triggerMergeRequest;
}, },
...@@ -75,21 +75,17 @@ export default { ...@@ -75,21 +75,17 @@ export default {
) )
" "
> >
<input name="service[commit_events]" type="hidden" value="false" /> <input name="service[commit_events]" type="hidden" :value="triggerCommit || false" />
<gl-form-checkbox <gl-form-checkbox v-model="triggerCommit" :disabled="isInheriting">
v-model="triggerCommit"
name="service[commit_events]"
:disabled="disableForm"
>
{{ __('Commit') }} {{ __('Commit') }}
</gl-form-checkbox> </gl-form-checkbox>
<input name="service[merge_requests_events]" type="hidden" value="false" /> <input
<gl-form-checkbox
v-model="triggerMergeRequest"
name="service[merge_requests_events]" name="service[merge_requests_events]"
:disabled="disableForm" type="hidden"
> :value="triggerMergeRequest || false"
/>
<gl-form-checkbox v-model="triggerMergeRequest" :disabled="isInheriting">
{{ __('Merge request') }} {{ __('Merge request') }}
</gl-form-checkbox> </gl-form-checkbox>
</gl-form-group> </gl-form-group>
...@@ -99,12 +95,12 @@ export default { ...@@ -99,12 +95,12 @@ export default {
:label="s__('Integrations|Comment settings:')" :label="s__('Integrations|Comment settings:')"
data-testid="comment-settings" data-testid="comment-settings"
> >
<input name="service[comment_on_event_enabled]" type="hidden" value="false" /> <input
<gl-form-checkbox
v-model="enableComments"
name="service[comment_on_event_enabled]" name="service[comment_on_event_enabled]"
:disabled="disableForm" type="hidden"
> :value="enableComments || false"
/>
<gl-form-checkbox v-model="enableComments" :disabled="isInheriting">
{{ s__('Integrations|Enable comments') }} {{ s__('Integrations|Enable comments') }}
</gl-form-checkbox> </gl-form-checkbox>
</gl-form-group> </gl-form-group>
...@@ -114,13 +110,18 @@ export default { ...@@ -114,13 +110,18 @@ export default {
:label="s__('Integrations|Comment detail:')" :label="s__('Integrations|Comment detail:')"
data-testid="comment-detail" data-testid="comment-detail"
> >
<input
v-if="isInheriting"
name="service[comment_detail]"
type="hidden"
:value="commentDetail"
/>
<gl-form-radio <gl-form-radio
v-for="commentDetailOption in commentDetailOptions" v-for="commentDetailOption in commentDetailOptions"
:key="commentDetailOption.value" :key="commentDetailOption.value"
v-model="commentDetail" v-model="commentDetail"
:value="commentDetailOption.value" :value="commentDetailOption.value"
name="service[comment_detail]" :disabled="isInheriting"
:disabled="disableForm"
> >
{{ commentDetailOption.label }} {{ commentDetailOption.label }}
<template #help> <template #help>
...@@ -141,13 +142,17 @@ export default { ...@@ -141,13 +142,17 @@ export default {
}} }}
</label> </label>
<input name="service[commit_events]" type="hidden" value="false" /> <input name="service[commit_events]" type="hidden" :value="triggerCommit || false" />
<gl-form-checkbox v-model="triggerCommit" name="service[commit_events]"> <gl-form-checkbox v-model="triggerCommit" :disabled="isInheriting">
{{ __('Commit') }} {{ __('Commit') }}
</gl-form-checkbox> </gl-form-checkbox>
<input name="service[merge_requests_events]" type="hidden" value="false" /> <input
<gl-form-checkbox v-model="triggerMergeRequest" name="service[merge_requests_events]"> name="service[merge_requests_events]"
type="hidden"
:value="triggerMergeRequest || false"
/>
<gl-form-checkbox v-model="triggerMergeRequest" :disabled="isInheriting">
{{ __('Merge request') }} {{ __('Merge request') }}
</gl-form-checkbox> </gl-form-checkbox>
...@@ -159,8 +164,12 @@ export default { ...@@ -159,8 +164,12 @@ export default {
<label> <label>
{{ s__('Integrations|Comment settings:') }} {{ s__('Integrations|Comment settings:') }}
</label> </label>
<input name="service[comment_on_event_enabled]" type="hidden" value="false" /> <input
<gl-form-checkbox v-model="enableComments" name="service[comment_on_event_enabled]"> name="service[comment_on_event_enabled]"
type="hidden"
:value="enableComments || false"
/>
<gl-form-checkbox v-model="enableComments" :disabled="isInheriting">
{{ s__('Integrations|Enable comments') }} {{ s__('Integrations|Enable comments') }}
</gl-form-checkbox> </gl-form-checkbox>
...@@ -168,12 +177,18 @@ export default { ...@@ -168,12 +177,18 @@ export default {
<label> <label>
{{ s__('Integrations|Comment detail:') }} {{ s__('Integrations|Comment detail:') }}
</label> </label>
<input
v-if="isInheriting"
name="service[comment_detail]"
type="hidden"
:value="commentDetail"
/>
<gl-form-radio <gl-form-radio
v-for="commentDetailOption in commentDetailOptions" v-for="commentDetailOption in commentDetailOptions"
:key="commentDetailOption.value" :key="commentDetailOption.value"
v-model="commentDetail" v-model="commentDetail"
:value="commentDetailOption.value" :value="commentDetailOption.value"
name="service[comment_detail]" :disabled="isInheriting"
> >
{{ commentDetailOption.label }} {{ commentDetailOption.label }}
<template #help> <template #help>
......
<script> <script>
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import { mapState } from 'vuex';
import { GlNewDropdown, GlNewDropdownItem } from '@gitlab/ui'; import { GlNewDropdown, GlNewDropdownItem } from '@gitlab/ui';
const options = [ const dropdownOptions = [
{ {
value: 'instance', value: false,
text: s__('Integrations|Use instance level settings'), text: s__('Integrations|Use instance level settings'),
}, },
{ {
value: 'project', value: true,
text: s__('Integrations|Use custom settings'), text: s__('Integrations|Use custom settings'),
}, },
]; ];
const defaultOption = options[0];
const customOption = options[1];
export default { export default {
dropdownOptions,
name: 'OverrideDropdown', name: 'OverrideDropdown',
components: { components: {
GlNewDropdown, GlNewDropdown,
GlNewDropdownItem, GlNewDropdownItem,
}, },
props: {}, props: {
inheritFromId: {
type: Number,
required: true,
},
override: {
type: Boolean,
required: true,
},
},
data() { data() {
return { return {
options, selected: dropdownOptions.find(x => x.value === this.override),
selected: defaultOption,
}; };
}, },
computed: {
...mapState(['override']),
},
methods: { methods: {
onClick(option) { onClick(option) {
this.selected = option; this.selected = option;
this.$store.dispatch('setOverride', option === customOption); this.$emit('change', option.value);
}, },
}, },
}; };
...@@ -47,8 +49,13 @@ export default { ...@@ -47,8 +49,13 @@ export default {
class="gl-display-flex gl-justify-content-space-between gl-align-items-baseline gl-py-4 gl-mt-5 gl-mb-6 gl-border-t-1 gl-border-t-solid gl-border-b-1 gl-border-b-solid gl-border-gray-100" class="gl-display-flex gl-justify-content-space-between gl-align-items-baseline gl-py-4 gl-mt-5 gl-mb-6 gl-border-t-1 gl-border-t-solid gl-border-b-1 gl-border-b-solid gl-border-gray-100"
> >
<span>{{ s__('Integrations|This integration has multiple settings available.') }}</span> <span>{{ s__('Integrations|This integration has multiple settings available.') }}</span>
<input name="service[inherit_from_id]" :value="override ? '' : inheritFromId" type="hidden" />
<gl-new-dropdown :text="selected.text"> <gl-new-dropdown :text="selected.text">
<gl-new-dropdown-item v-for="option in options" :key="option.value" @click="onClick(option)"> <gl-new-dropdown-item
v-for="option in $options.dropdownOptions"
:key="option.value"
@click="onClick(option)"
>
{{ option.text }} {{ option.text }}
</gl-new-dropdown-item> </gl-new-dropdown-item>
</gl-new-dropdown> </gl-new-dropdown>
......
...@@ -33,7 +33,7 @@ export default { ...@@ -33,7 +33,7 @@ export default {
}, },
}, },
computed: { computed: {
...mapGetters(['disableForm']), ...mapGetters(['isInheriting']),
placeholder() { placeholder() {
return placeholderForType[this.type]; return placeholderForType[this.type];
}, },
...@@ -59,12 +59,8 @@ export default { ...@@ -59,12 +59,8 @@ export default {
> >
<div id="trigger-fields" class="gl-pt-3"> <div id="trigger-fields" class="gl-pt-3">
<gl-form-group v-for="event in events" :key="event.title" :description="event.description"> <gl-form-group v-for="event in events" :key="event.title" :description="event.description">
<input :name="checkboxName(event.name)" type="hidden" value="false" /> <input :name="checkboxName(event.name)" type="hidden" :value="event.value || false" />
<gl-form-checkbox <gl-form-checkbox v-model="event.value" :disabled="isInheriting">
v-model="event.value"
:name="checkboxName(event.name)"
:disabled="disableForm"
>
{{ startCase(event.title) }} {{ startCase(event.title) }}
</gl-form-checkbox> </gl-form-checkbox>
<gl-form-input <gl-form-input
...@@ -72,7 +68,7 @@ export default { ...@@ -72,7 +68,7 @@ export default {
v-model="event.field.value" v-model="event.field.value"
:name="fieldName(event.field.name)" :name="fieldName(event.field.name)"
:placeholder="placeholder" :placeholder="placeholder"
:disabled="disableForm" :readonly="isInheriting"
/> />
</gl-form-group> </gl-form-group>
</div> </div>
......
import Vue from 'vue'; import Vue from 'vue';
import { isEmpty } from 'lodash';
import { createStore } from './store'; import { createStore } from './store';
import { parseBoolean } from '~/lib/utils/common_utils'; import { parseBoolean } from '~/lib/utils/common_utils';
import IntegrationForm from './components/integration_form.vue'; import IntegrationForm from './components/integration_form.vue';
export default el => { function parseBooleanInData(data) {
if (!el) { const result = {};
return null; Object.entries(data).forEach(([key, value]) => {
} result[key] = parseBoolean(value);
});
function parseBooleanInData(data) { return result;
const result = {}; }
Object.entries(data).forEach(([key, value]) => {
result[key] = parseBoolean(value);
});
return result;
}
function parseDatasetToProps(data) {
const { const {
id,
type, type,
commentDetail, commentDetail,
projectKey, projectKey,
...@@ -27,7 +23,7 @@ export default el => { ...@@ -27,7 +23,7 @@ export default el => {
fields, fields,
inheritFromId, inheritFromId,
...booleanAttributes ...booleanAttributes
} = el.dataset; } = data;
const { const {
showActive, showActive,
activated, activated,
...@@ -38,38 +34,53 @@ export default el => { ...@@ -38,38 +34,53 @@ export default el => {
enableJiraIssues, enableJiraIssues,
} = parseBooleanInData(booleanAttributes); } = parseBooleanInData(booleanAttributes);
return {
activeToggleProps: {
initialActivated: activated,
},
showActive,
type,
triggerFieldsProps: {
initialTriggerCommit: commitEvents,
initialTriggerMergeRequest: mergeRequestEvents,
initialEnableComments: enableComments,
initialCommentDetail: commentDetail,
},
jiraIssuesProps: {
showJiraIssuesIntegration,
initialEnableJiraIssues: enableJiraIssues,
initialProjectKey: projectKey,
upgradePlanPath,
editProjectPath,
},
triggerEvents: JSON.parse(triggerEvents),
fields: JSON.parse(fields),
inheritFromId: parseInt(inheritFromId, 10),
id: parseInt(id, 10),
};
}
export default (el, adminEl) => {
if (!el) {
return null;
}
const props = parseDatasetToProps(el.dataset);
const initialState = { const initialState = {
overrideAvailable: !isEmpty(inheritFromId), adminState: null,
customState: props,
}; };
if (adminEl) {
initialState.adminState = Object.freeze(parseDatasetToProps(adminEl.dataset));
}
return new Vue({ return new Vue({
el, el,
store: createStore(initialState), store: createStore(initialState),
render(createElement) { render(createElement) {
return createElement(IntegrationForm, { return createElement(IntegrationForm);
props: {
activeToggleProps: {
initialActivated: activated,
},
showActive,
type,
triggerFieldsProps: {
initialTriggerCommit: commitEvents,
initialTriggerMergeRequest: mergeRequestEvents,
initialEnableComments: enableComments,
initialCommentDetail: commentDetail,
},
jiraIssuesProps: {
showJiraIssuesIntegration,
initialEnableJiraIssues: enableJiraIssues,
initialProjectKey: projectKey,
upgradePlanPath,
editProjectPath,
},
triggerEvents: JSON.parse(triggerEvents),
fields: JSON.parse(fields),
},
});
}, },
}); });
}; };
import * as types from './mutation_types'; import * as types from './mutation_types';
// eslint-disable-next-line import/prefer-default-export
export const setOverride = ({ commit }, override) => commit(types.SET_OVERRIDE, override); export const setOverride = ({ commit }, override) => commit(types.SET_OVERRIDE, override);
export const setOverrideAvailable = ({ commit }, overrideAvailable) =>
commit(types.SET_OVERRIDE_AVAILABLE, overrideAvailable);
// eslint-disable-next-line import/prefer-default-export export const isInheriting = state => (state.adminState === null ? false : !state.override);
export const disableForm = state => state.overrideAvailable && !state.override;
export const propsSource = (state, getters) =>
getters.isInheriting ? state.adminState : state.customState;
export const currentKey = (state, getters) => (getters.isInheriting ? 'admin' : 'custom');
...@@ -7,6 +7,7 @@ import createState from './state'; ...@@ -7,6 +7,7 @@ import createState from './state';
Vue.use(Vuex); Vue.use(Vuex);
// eslint-disable-next-line import/prefer-default-export
export const createStore = (initialState = {}) => export const createStore = (initialState = {}) =>
new Vuex.Store({ new Vuex.Store({
actions, actions,
...@@ -14,5 +15,3 @@ export const createStore = (initialState = {}) => ...@@ -14,5 +15,3 @@ export const createStore = (initialState = {}) =>
mutations, mutations,
state: createState(initialState), state: createState(initialState),
}); });
export default createStore();
// eslint-disable-next-line import/prefer-default-export
export const SET_OVERRIDE = 'SET_OVERRIDE'; export const SET_OVERRIDE = 'SET_OVERRIDE';
export const SET_OVERRIDE_AVAILABLE = 'SET_OVERRIDE_AVAILABLE';
...@@ -4,8 +4,4 @@ export default { ...@@ -4,8 +4,4 @@ export default {
[types.SET_OVERRIDE](state, override) { [types.SET_OVERRIDE](state, override) {
state.override = override; state.override = override;
}, },
[types.SET_OVERRIDE_AVAILABLE](state, overrideAvailable) {
state.overrideAvailable = overrideAvailable;
},
}; };
export default ({ overrideAvailable = false }) => ({ export default ({ adminState = null, customState = {} } = {}) => {
override: false, const override = adminState !== null ? adminState.id !== customState.inheritFromId : false;
overrideAvailable,
}); return {
override,
adminState,
customState,
};
};
...@@ -22,7 +22,10 @@ export default class IntegrationSettingsForm { ...@@ -22,7 +22,10 @@ export default class IntegrationSettingsForm {
init() { init() {
// Init Vue component // Init Vue component
initForm(document.querySelector('.js-vue-integration-settings')); initForm(
document.querySelector('.js-vue-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.handleServiceToggle();
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
= markdown integration.help = markdown integration.help
.service-settings .service-settings
- if @admin_integration
.js-vue-admin-integration-settings{ data: integration_form_data(@admin_integration) }
.js-vue-integration-settings{ data: integration_form_data(integration) } .js-vue-integration-settings{ data: integration_form_data(integration) }
- if show_service_trigger_events?(integration) - if show_service_trigger_events?(integration)
......
...@@ -5,7 +5,7 @@ require 'spec_helper' ...@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Disable individual triggers', :js do RSpec.describe 'Disable individual triggers', :js do
include_context 'project service activation' include_context 'project service activation'
let(:checkbox_selector) { 'input[type=checkbox][name$="_events]"]' } let(:checkbox_selector) { 'input[name$="_events]"]' }
before do before do
visit_project_integration(service_name) visit_project_integration(service_name)
...@@ -18,7 +18,7 @@ RSpec.describe 'Disable individual triggers', :js do ...@@ -18,7 +18,7 @@ RSpec.describe 'Disable individual triggers', :js do
event_count = HipchatService.supported_events.count event_count = HipchatService.supported_events.count
expect(page).to have_content "Trigger" expect(page).to have_content "Trigger"
expect(page).to have_css(checkbox_selector, count: event_count) expect(page).to have_css(checkbox_selector, visible: :all, count: event_count)
end end
end end
...@@ -27,7 +27,7 @@ RSpec.describe 'Disable individual triggers', :js do ...@@ -27,7 +27,7 @@ RSpec.describe 'Disable individual triggers', :js do
it "doesn't show unnecessary Trigger checkboxes" do it "doesn't show unnecessary Trigger checkboxes" do
expect(page).not_to have_content "Trigger" expect(page).not_to have_content "Trigger"
expect(page).not_to have_css(checkbox_selector) expect(page).not_to have_css(checkbox_selector, visible: :all)
end end
end end
end end
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import ActiveToggle from '~/integrations/edit/components/active_toggle.vue';
import { GlToggle } from '@gitlab/ui'; import { GlToggle } from '@gitlab/ui';
import ActiveToggle from '~/integrations/edit/components/active_toggle.vue';
const GL_TOGGLE_ACTIVE_CLASS = 'is-checked'; const GL_TOGGLE_ACTIVE_CLASS = 'is-checked';
const GL_TOGGLE_DISABLED_CLASS = 'is-disabled';
describe('ActiveToggle', () => { describe('ActiveToggle', () => {
let wrapper; let wrapper;
...@@ -11,9 +13,12 @@ describe('ActiveToggle', () => { ...@@ -11,9 +13,12 @@ describe('ActiveToggle', () => {
initialActivated: true, initialActivated: true,
}; };
const createComponent = props => { const createComponent = (props = {}, isInheriting = false) => {
wrapper = mount(ActiveToggle, { wrapper = mount(ActiveToggle, {
propsData: { ...defaultProps, ...props }, propsData: { ...defaultProps, ...props },
computed: {
isInheriting: () => isInheriting,
},
}); });
}; };
...@@ -29,6 +34,15 @@ describe('ActiveToggle', () => { ...@@ -29,6 +34,15 @@ describe('ActiveToggle', () => {
const findInputInToggle = () => findGlToggle().find('input'); const findInputInToggle = () => findGlToggle().find('input');
describe('template', () => { describe('template', () => {
describe('is inheriting adminSettings', () => {
it('renders GlToggle as disabled', () => {
createComponent({}, true);
expect(findGlToggle().exists()).toBe(true);
expect(findButtonInToggle().classes()).toContain(GL_TOGGLE_DISABLED_CLASS);
});
});
describe('initialActivated is false', () => { describe('initialActivated is false', () => {
it('renders GlToggle as inactive', () => { it('renders GlToggle as inactive', () => {
createComponent({ createComponent({
......
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import { createStore } from '~/integrations/edit/store';
import DynamicField from '~/integrations/edit/components/dynamic_field.vue'; import DynamicField from '~/integrations/edit/components/dynamic_field.vue';
import { GlFormGroup, GlFormCheckbox, GlFormInput, GlFormSelect, GlFormTextarea } from '@gitlab/ui'; import { GlFormGroup, GlFormCheckbox, GlFormInput, GlFormSelect, GlFormTextarea } from '@gitlab/ui';
...@@ -15,10 +14,12 @@ describe('DynamicField', () => { ...@@ -15,10 +14,12 @@ describe('DynamicField', () => {
value: '1', value: '1',
}; };
const createComponent = props => { const createComponent = (props, isInheriting = false) => {
wrapper = mount(DynamicField, { wrapper = mount(DynamicField, {
propsData: { ...defaultProps, ...props }, propsData: { ...defaultProps, ...props },
store: createStore(), computed: {
isInheriting: () => isInheriting,
},
}); });
}; };
...@@ -36,108 +37,143 @@ describe('DynamicField', () => { ...@@ -36,108 +37,143 @@ describe('DynamicField', () => {
const findGlFormTextarea = () => wrapper.find(GlFormTextarea); const findGlFormTextarea = () => wrapper.find(GlFormTextarea);
describe('template', () => { describe('template', () => {
describe('dynamic field', () => { describe.each([[true, 'disabled', 'readonly'], [false, undefined, undefined]])(
describe('type is checkbox', () => { 'dynamic field, when isInheriting = `%p`',
beforeEach(() => { (isInheriting, disabled, readonly) => {
createComponent({ describe('type is checkbox', () => {
type: 'checkbox', beforeEach(() => {
createComponent(
{
type: 'checkbox',
},
isInheriting,
);
}); });
});
it('renders GlFormCheckbox', () => { it(`renders GlFormCheckbox, which ${isInheriting ? 'is' : 'is not'} disabled`, () => {
expect(findGlFormCheckbox().exists()).toBe(true); expect(findGlFormCheckbox().exists()).toBe(true);
}); expect(
findGlFormCheckbox()
.find('[type=checkbox]')
.attributes('disabled'),
).toBe(disabled);
});
it('does not render other types of input', () => { it('does not render other types of input', () => {
expect(findGlFormSelect().exists()).toBe(false); expect(findGlFormSelect().exists()).toBe(false);
expect(findGlFormTextarea().exists()).toBe(false); expect(findGlFormTextarea().exists()).toBe(false);
expect(findGlFormInput().exists()).toBe(false); expect(findGlFormInput().exists()).toBe(false);
});
}); });
});
describe('type is select', () => { describe('type is select', () => {
beforeEach(() => { beforeEach(() => {
createComponent({ createComponent(
type: 'select', {
choices: [['all', 'All details'], ['standard', 'Standard']], type: 'select',
choices: [['all', 'All details'], ['standard', 'Standard']],
},
isInheriting,
);
}); });
});
it('renders findGlFormSelect', () => { it(`renders GlFormSelect, which ${isInheriting ? 'is' : 'is not'} disabled`, () => {
expect(findGlFormSelect().exists()).toBe(true); expect(findGlFormSelect().exists()).toBe(true);
expect(findGlFormSelect().findAll('option')).toHaveLength(2); expect(findGlFormSelect().findAll('option')).toHaveLength(2);
}); expect(
findGlFormSelect()
.find('select')
.attributes('disabled'),
).toBe(disabled);
});
it('does not render other types of input', () => { it('does not render other types of input', () => {
expect(findGlFormCheckbox().exists()).toBe(false); expect(findGlFormCheckbox().exists()).toBe(false);
expect(findGlFormTextarea().exists()).toBe(false); expect(findGlFormTextarea().exists()).toBe(false);
expect(findGlFormInput().exists()).toBe(false); expect(findGlFormInput().exists()).toBe(false);
});
}); });
});
describe('type is textarea', () => { describe('type is textarea', () => {
beforeEach(() => { beforeEach(() => {
createComponent({ createComponent(
type: 'textarea', {
type: 'textarea',
},
isInheriting,
);
}); });
});
it('renders findGlFormTextarea', () => { it(`renders GlFormTextarea, which ${isInheriting ? 'is' : 'is not'} readonly`, () => {
expect(findGlFormTextarea().exists()).toBe(true); expect(findGlFormTextarea().exists()).toBe(true);
}); expect(
findGlFormTextarea()
.find('textarea')
.attributes('readonly'),
).toBe(readonly);
});
it('does not render other types of input', () => { it('does not render other types of input', () => {
expect(findGlFormCheckbox().exists()).toBe(false); expect(findGlFormCheckbox().exists()).toBe(false);
expect(findGlFormSelect().exists()).toBe(false); expect(findGlFormSelect().exists()).toBe(false);
expect(findGlFormInput().exists()).toBe(false); expect(findGlFormInput().exists()).toBe(false);
});
}); });
});
describe('type is password', () => { describe('type is password', () => {
beforeEach(() => { beforeEach(() => {
createComponent({ createComponent(
type: 'password', {
type: 'password',
},
isInheriting,
);
}); });
});
it('renders GlFormInput', () => { it(`renders GlFormInput, which ${isInheriting ? 'is' : 'is not'} readonly`, () => {
expect(findGlFormInput().exists()).toBe(true); expect(findGlFormInput().exists()).toBe(true);
expect(findGlFormInput().attributes('type')).toBe('password'); expect(findGlFormInput().attributes('type')).toBe('password');
}); expect(findGlFormInput().attributes('readonly')).toBe(readonly);
});
it('does not render other types of input', () => { it('does not render other types of input', () => {
expect(findGlFormCheckbox().exists()).toBe(false); expect(findGlFormCheckbox().exists()).toBe(false);
expect(findGlFormSelect().exists()).toBe(false); expect(findGlFormSelect().exists()).toBe(false);
expect(findGlFormTextarea().exists()).toBe(false); expect(findGlFormTextarea().exists()).toBe(false);
});
}); });
});
describe('type is text', () => { describe('type is text', () => {
beforeEach(() => { beforeEach(() => {
createComponent({ createComponent(
type: 'text', {
required: true, type: 'text',
required: true,
},
isInheriting,
);
}); });
});
it('renders GlFormInput', () => { it(`renders GlFormInput, which ${isInheriting ? 'is' : 'is not'} readonly`, () => {
expect(findGlFormInput().exists()).toBe(true); expect(findGlFormInput().exists()).toBe(true);
expect(findGlFormInput().attributes()).toMatchObject({ expect(findGlFormInput().attributes()).toMatchObject({
type: 'text', type: 'text',
id: 'service_project_url', id: 'service_project_url',
name: 'service[project_url]', name: 'service[project_url]',
placeholder: defaultProps.placeholder, placeholder: defaultProps.placeholder,
required: 'required', required: 'required',
});
expect(findGlFormInput().attributes('readonly')).toBe(readonly);
}); });
});
it('does not render other types of input', () => { it('does not render other types of input', () => {
expect(findGlFormCheckbox().exists()).toBe(false); expect(findGlFormCheckbox().exists()).toBe(false);
expect(findGlFormSelect().exists()).toBe(false); expect(findGlFormSelect().exists()).toBe(false);
expect(findGlFormTextarea().exists()).toBe(false); expect(findGlFormTextarea().exists()).toBe(false);
});
}); });
}); },
}); );
describe('help text', () => { describe('help text', () => {
it('renders description with help text', () => { it('renders description with help text', () => {
......
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { createStore } from '~/integrations/edit/store'; import { createStore } from '~/integrations/edit/store';
import IntegrationForm from '~/integrations/edit/components/integration_form.vue'; import IntegrationForm from '~/integrations/edit/components/integration_form.vue';
import OverrideDropdown from '~/integrations/edit/components/override_dropdown.vue';
import ActiveToggle from '~/integrations/edit/components/active_toggle.vue'; import ActiveToggle from '~/integrations/edit/components/active_toggle.vue';
import JiraTriggerFields from '~/integrations/edit/components/jira_trigger_fields.vue'; import JiraTriggerFields from '~/integrations/edit/components/jira_trigger_fields.vue';
import JiraIssuesFields from '~/integrations/edit/components/jira_issues_fields.vue'; import JiraIssuesFields from '~/integrations/edit/components/jira_issues_fields.vue';
import TriggerFields from '~/integrations/edit/components/trigger_fields.vue'; import TriggerFields from '~/integrations/edit/components/trigger_fields.vue';
import DynamicField from '~/integrations/edit/components/dynamic_field.vue'; import DynamicField from '~/integrations/edit/components/dynamic_field.vue';
import { mockIntegrationProps } from 'jest/integrations/edit/mock_data';
describe('IntegrationForm', () => { describe('IntegrationForm', () => {
let wrapper; let wrapper;
const defaultProps = { const createComponent = (customStateProps = {}, featureFlags = {}, initialState = {}) => {
activeToggleProps: {
initialActivated: true,
},
showActive: true,
triggerFieldsProps: {
initialTriggerCommit: false,
initialTriggerMergeRequest: false,
initialEnableComments: false,
},
jiraIssuesProps: {},
type: '',
};
const createComponent = (props, featureFlags = {}) => {
wrapper = shallowMount(IntegrationForm, { wrapper = shallowMount(IntegrationForm, {
propsData: { ...defaultProps, ...props }, propsData: {},
store: createStore(), store: createStore({
customState: { ...mockIntegrationProps, ...customStateProps },
...initialState,
}),
stubs: { stubs: {
OverrideDropdown,
ActiveToggle, ActiveToggle,
JiraTriggerFields, JiraTriggerFields,
TriggerFields,
}, },
provide: { provide: {
glFeatures: featureFlags, glFeatures: featureFlags,
...@@ -45,6 +38,7 @@ describe('IntegrationForm', () => { ...@@ -45,6 +38,7 @@ describe('IntegrationForm', () => {
} }
}); });
const findOverrideDropdown = () => wrapper.find(OverrideDropdown);
const findActiveToggle = () => wrapper.find(ActiveToggle); const findActiveToggle = () => wrapper.find(ActiveToggle);
const findJiraTriggerFields = () => wrapper.find(JiraTriggerFields); const findJiraTriggerFields = () => wrapper.find(JiraTriggerFields);
const findJiraIssuesFields = () => wrapper.find(JiraIssuesFields); const findJiraIssuesFields = () => wrapper.find(JiraIssuesFields);
...@@ -142,5 +136,35 @@ describe('IntegrationForm', () => { ...@@ -142,5 +136,35 @@ describe('IntegrationForm', () => {
}); });
}); });
}); });
describe('adminState state is null', () => {
it('does not render OverrideDropdown', () => {
createComponent(
{},
{},
{
adminState: null,
},
);
expect(findOverrideDropdown().exists()).toBe(false);
});
});
describe('adminState state is an object', () => {
it('renders OverrideDropdown', () => {
createComponent(
{},
{},
{
adminState: {
...mockIntegrationProps,
},
},
);
expect(findOverrideDropdown().exists()).toBe(true);
});
});
}); });
}); });
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import JiraIssuesFields from '~/integrations/edit/components/jira_issues_fields.vue';
import { GlFormCheckbox, GlFormInput } from '@gitlab/ui'; import { GlFormCheckbox, GlFormInput } from '@gitlab/ui';
import JiraIssuesFields from '~/integrations/edit/components/jira_issues_fields.vue';
describe('JiraIssuesFields', () => { describe('JiraIssuesFields', () => {
let wrapper; let wrapper;
......
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import JiraTriggerFields from '~/integrations/edit/components/jira_trigger_fields.vue';
import { GlFormCheckbox } from '@gitlab/ui'; import { GlFormCheckbox } from '@gitlab/ui';
import JiraTriggerFields from '~/integrations/edit/components/jira_trigger_fields.vue';
describe('JiraTriggerFields', () => { describe('JiraTriggerFields', () => {
let wrapper; let wrapper;
...@@ -11,9 +11,12 @@ describe('JiraTriggerFields', () => { ...@@ -11,9 +11,12 @@ describe('JiraTriggerFields', () => {
initialEnableComments: false, initialEnableComments: false,
}; };
const createComponent = props => { const createComponent = (props, isInheriting = false) => {
wrapper = mount(JiraTriggerFields, { wrapper = mount(JiraTriggerFields, {
propsData: { ...defaultProps, ...props }, propsData: { ...defaultProps, ...props },
computed: {
isInheriting: () => isInheriting,
},
}); });
}; };
...@@ -93,5 +96,23 @@ describe('JiraTriggerFields', () => { ...@@ -93,5 +96,23 @@ describe('JiraTriggerFields', () => {
expect(findCommentDetail().isVisible()).toBe(true); expect(findCommentDetail().isVisible()).toBe(true);
}); });
}); });
it('disables checkboxes and radios if inheriting', () => {
createComponent(
{
initialTriggerCommit: true,
initialEnableComments: true,
},
true,
);
wrapper.findAll('[type=checkbox]').wrappers.forEach(checkbox => {
expect(checkbox.attributes('disabled')).toBe('disabled');
});
wrapper.findAll('[type=radio]').wrappers.forEach(radio => {
expect(radio.attributes('disabled')).toBe('disabled');
});
});
}); });
}); });
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import { createStore } from '~/integrations/edit/store';
import TriggerFields from '~/integrations/edit/components/trigger_fields.vue'; import TriggerFields from '~/integrations/edit/components/trigger_fields.vue';
import { GlFormGroup, GlFormCheckbox, GlFormInput } from '@gitlab/ui'; import { GlFormGroup, GlFormCheckbox, GlFormInput } from '@gitlab/ui';
...@@ -10,10 +9,12 @@ describe('TriggerFields', () => { ...@@ -10,10 +9,12 @@ describe('TriggerFields', () => {
type: 'slack', type: 'slack',
}; };
const createComponent = props => { const createComponent = (props, isInheriting = false) => {
wrapper = mount(TriggerFields, { wrapper = mount(TriggerFields, {
propsData: { ...defaultProps, ...props }, propsData: { ...defaultProps, ...props },
store: createStore(), computed: {
isInheriting: () => isInheriting,
},
}); });
}; };
...@@ -24,10 +25,11 @@ describe('TriggerFields', () => { ...@@ -24,10 +25,11 @@ describe('TriggerFields', () => {
} }
}); });
const findAllGlFormGroups = () => wrapper.find('#trigger-fields').findAll(GlFormGroup);
const findAllGlFormCheckboxes = () => wrapper.findAll(GlFormCheckbox); const findAllGlFormCheckboxes = () => wrapper.findAll(GlFormCheckbox);
const findAllGlFormInputs = () => wrapper.findAll(GlFormInput); const findAllGlFormInputs = () => wrapper.findAll(GlFormInput);
describe('template', () => { describe.each([true, false])('template, isInheriting = `%p`', isInheriting => {
it('renders a label with text "Trigger"', () => { it('renders a label with text "Trigger"', () => {
createComponent(); createComponent();
...@@ -53,9 +55,12 @@ describe('TriggerFields', () => { ...@@ -53,9 +55,12 @@ describe('TriggerFields', () => {
]; ];
beforeEach(() => { beforeEach(() => {
createComponent({ createComponent(
events, {
}); events,
},
isInheriting,
);
}); });
it('does not render GlFormInput for each event', () => { it('does not render GlFormInput for each event', () => {
...@@ -71,8 +76,10 @@ describe('TriggerFields', () => { ...@@ -71,8 +76,10 @@ describe('TriggerFields', () => {
}); });
}); });
it('renders GlFormCheckbox for each event', () => { it(`renders GlFormCheckbox and corresponding hidden input for each event, which ${
const checkboxes = findAllGlFormCheckboxes(); isInheriting ? 'is' : 'is not'
} disabled`, () => {
const checkboxes = findAllGlFormGroups();
const expectedResults = [ const expectedResults = [
{ labelText: 'Push', inputName: 'service[push_event]' }, { labelText: 'Push', inputName: 'service[push_event]' },
{ labelText: 'Merge Request', inputName: 'service[merge_requests_event]' }, { labelText: 'Merge Request', inputName: 'service[merge_requests_event]' },
...@@ -80,14 +87,22 @@ describe('TriggerFields', () => { ...@@ -80,14 +87,22 @@ describe('TriggerFields', () => {
expect(checkboxes).toHaveLength(2); expect(checkboxes).toHaveLength(2);
checkboxes.wrappers.forEach((checkbox, index) => { checkboxes.wrappers.forEach((checkbox, index) => {
const checkBox = checkbox.find(GlFormCheckbox);
expect(checkbox.find('label').text()).toBe(expectedResults[index].labelText); expect(checkbox.find('label').text()).toBe(expectedResults[index].labelText);
expect(checkbox.find('input').attributes('name')).toBe(expectedResults[index].inputName); expect(checkbox.find('[type=hidden]').attributes('name')).toBe(
expect(checkbox.vm.$attrs.checked).toBe(events[index].value); expectedResults[index].inputName,
);
expect(checkbox.find('[type=hidden]').attributes('value')).toBe(
events[index].value.toString(),
);
expect(checkBox.vm.$attrs.disabled).toBe(isInheriting);
expect(checkBox.vm.$attrs.checked).toBe(events[index].value);
}); });
}); });
}); });
describe('events with field property', () => { describe('events with field property, isInheriting = `%p`', () => {
const events = [ const events = [
{ {
field: { field: {
...@@ -104,16 +119,21 @@ describe('TriggerFields', () => { ...@@ -104,16 +119,21 @@ describe('TriggerFields', () => {
]; ];
beforeEach(() => { beforeEach(() => {
createComponent({ createComponent(
events, {
}); events,
},
isInheriting,
);
}); });
it('renders GlFormCheckbox for each event', () => { it('renders GlFormCheckbox for each event', () => {
expect(findAllGlFormCheckboxes()).toHaveLength(2); expect(findAllGlFormCheckboxes()).toHaveLength(2);
}); });
it('renders GlFormInput for each event', () => { it(`renders GlFormInput for each event, which ${
isInheriting ? 'is' : 'is not'
} readonly`, () => {
const fields = findAllGlFormInputs(); const fields = findAllGlFormInputs();
const expectedResults = [ const expectedResults = [
{ {
...@@ -130,6 +150,7 @@ describe('TriggerFields', () => { ...@@ -130,6 +150,7 @@ describe('TriggerFields', () => {
fields.wrappers.forEach((field, index) => { fields.wrappers.forEach((field, index) => {
expect(field.attributes()).toMatchObject(expectedResults[index]); expect(field.attributes()).toMatchObject(expectedResults[index]);
expect(field.vm.$attrs.readonly).toBe(isInheriting);
expect(field.vm.$attrs.value).toBe(events[index].field.value); expect(field.vm.$attrs.value).toBe(events[index].field.value);
}); });
}); });
......
// eslint-disable-next-line import/prefer-default-export
export const mockIntegrationProps = {
id: 25,
activeToggleProps: {
initialActivated: true,
},
showActive: true,
triggerFieldsProps: {
initialTriggerCommit: false,
initialTriggerMergeRequest: false,
initialEnableComments: false,
},
jiraIssuesProps: {},
triggerEvents: [],
fields: [],
type: '',
inheritFromId: 25,
};
import createState from '~/integrations/edit/store/state';
import { setOverride } from '~/integrations/edit/store/actions';
import * as types from '~/integrations/edit/store/mutation_types';
import testAction from 'helpers/vuex_action_helper';
describe('Integration form store actions', () => {
let state;
beforeEach(() => {
state = createState();
});
describe('setOverride', () => {
it('should commit override mutation', () => {
return testAction(setOverride, true, state, [{ type: types.SET_OVERRIDE, payload: true }]);
});
});
});
import { currentKey, isInheriting, propsSource } from '~/integrations/edit/store/getters';
import createState from '~/integrations/edit/store/state';
import { mockIntegrationProps } from '../mock_data';
describe('Integration form store getters', () => {
let state;
const customState = { ...mockIntegrationProps, type: 'CustomState' };
const adminState = { ...mockIntegrationProps, type: 'AdminState' };
beforeEach(() => {
state = createState({ customState });
});
describe('isInheriting', () => {
describe('when adminState is null', () => {
it('returns false', () => {
expect(isInheriting(state)).toBe(false);
});
});
describe('when adminState is an object', () => {
beforeEach(() => {
state.adminState = adminState;
});
describe('when override is false', () => {
beforeEach(() => {
state.override = false;
});
it('returns false', () => {
expect(isInheriting(state)).toBe(true);
});
});
describe('when override is true', () => {
beforeEach(() => {
state.override = true;
});
it('returns true', () => {
expect(isInheriting(state)).toBe(false);
});
});
});
});
describe('propsSource', () => {
beforeEach(() => {
state.adminState = adminState;
});
it('equals adminState if inheriting', () => {
expect(propsSource(state, { isInheriting: true })).toEqual(adminState);
});
it('equals customState if not inheriting', () => {
expect(propsSource(state, { isInheriting: false })).toEqual(customState);
});
});
describe('currentKey', () => {
it('equals `admin` if inheriting', () => {
expect(currentKey(state, { isInheriting: true })).toEqual('admin');
});
it('equals `custom` if not inheriting', () => {
expect(currentKey(state, { isInheriting: false })).toEqual('custom');
});
});
});
import mutations from '~/integrations/edit/store/mutations';
import createState from '~/integrations/edit/store/state';
import * as types from '~/integrations/edit/store/mutation_types';
describe('Integration form store mutations', () => {
let state;
beforeEach(() => {
state = createState();
});
describe(`${types.SET_OVERRIDE}`, () => {
it('sets override', () => {
mutations[types.SET_OVERRIDE](state, true);
expect(state.override).toBe(true);
});
});
});
import createState from '~/integrations/edit/store/state';
describe('Integration form state factory', () => {
it('states default to null', () => {
expect(createState()).toEqual({
adminState: null,
customState: {},
override: false,
});
});
describe('override is initialized correctly', () => {
it.each([
[{ id: 25 }, { inheritFromId: null }, true],
[{ id: 25 }, { inheritFromId: 27 }, true],
[{ id: 25 }, { inheritFromId: 25 }, false],
[null, { inheritFromId: null }, false],
[null, { inheritFromId: 25 }, false],
])(
'for adminState: %p, customState: %p: override = `%p`',
(adminState, customState, expected) => {
expect(createState({ adminState, customState }).override).toEqual(expected);
},
);
});
});
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