Commit ba854e13 authored by Shinya Maeda's avatar Shinya Maeda

Merge branch 'afontaine/remove-legacy-flags-frontend-index' into 'master'

Remove Legacy Flags from Feature Flag Table

See merge request gitlab-org/gitlab!64007
parents e8dfbc64 f7097cf1
<script> <script>
import { GlBadge, GlButton, GlTooltipDirective, GlModal, GlToggle, GlIcon } from '@gitlab/ui'; import { GlBadge, GlButton, GlTooltipDirective, GlModal, GlToggle } from '@gitlab/ui';
import { __, s__, sprintf } from '~/locale'; import { __, s__, sprintf } from '~/locale';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { ROLLOUT_STRATEGY_PERCENT_ROLLOUT, NEW_VERSION_FLAG, LEGACY_FLAG } from '../constants';
import { labelForStrategy } from '../utils'; import { labelForStrategy } from '../utils';
export default { export default {
...@@ -14,7 +13,6 @@ export default { ...@@ -14,7 +13,6 @@ export default {
components: { components: {
GlBadge, GlBadge,
GlButton, GlButton,
GlIcon,
GlModal, GlModal,
GlToggle, GlToggle,
}, },
...@@ -35,13 +33,7 @@ export default { ...@@ -35,13 +33,7 @@ export default {
deleteFeatureFlagName: null, deleteFeatureFlagName: null,
}; };
}, },
translations: {
legacyFlagReadOnlyAlert: s__('FeatureFlags|Flag is read-only'),
},
computed: { computed: {
permissions() {
return this.glFeatures.featureFlagPermissions;
},
modalTitle() { modalTitle() {
return sprintf(s__('FeatureFlags|Delete %{name}?'), { return sprintf(s__('FeatureFlags|Delete %{name}?'), {
name: this.deleteFeatureFlagName, name: this.deleteFeatureFlagName,
...@@ -57,12 +49,6 @@ export default { ...@@ -57,12 +49,6 @@ export default {
}, },
}, },
methods: { methods: {
isLegacyFlag(flag) {
return flag.version !== NEW_VERSION_FLAG;
},
statusToggleDisabled(flag) {
return flag.version === LEGACY_FLAG;
},
scopeTooltipText(scope) { scopeTooltipText(scope) {
return !scope.active return !scope.active
? sprintf(s__('FeatureFlags|Inactive flag for %{scope}'), { ? sprintf(s__('FeatureFlags|Inactive flag for %{scope}'), {
...@@ -70,22 +56,6 @@ export default { ...@@ -70,22 +56,6 @@ export default {
}) })
: ''; : '';
}, },
badgeText(scope) {
const displayName =
scope.environmentScope === '*'
? s__('FeatureFlags|* (All environments)')
: scope.environmentScope;
const displayPercentage =
scope.rolloutStrategy === ROLLOUT_STRATEGY_PERCENT_ROLLOUT
? `: ${scope.rolloutPercentage}%`
: '';
return `${displayName}${displayPercentage}`;
},
badgeVariant(scope) {
return scope.active ? 'info' : 'muted';
},
strategyBadgeText(strategy) { strategyBadgeText(strategy) {
return labelForStrategy(strategy); return labelForStrategy(strategy);
}, },
...@@ -142,7 +112,6 @@ export default { ...@@ -142,7 +112,6 @@ export default {
<gl-toggle <gl-toggle
v-if="featureFlag.update_path" v-if="featureFlag.update_path"
:value="featureFlag.active" :value="featureFlag.active"
:disabled="statusToggleDisabled(featureFlag)"
:label="$options.i18n.toggleLabel" :label="$options.i18n.toggleLabel"
label-position="hidden" label-position="hidden"
data-testid="feature-flag-status-toggle" data-testid="feature-flag-status-toggle"
...@@ -169,12 +138,6 @@ export default { ...@@ -169,12 +138,6 @@ export default {
<div class="feature-flag-name text-monospace text-truncate"> <div class="feature-flag-name text-monospace text-truncate">
{{ featureFlag.name }} {{ featureFlag.name }}
</div> </div>
<gl-icon
v-if="isLegacyFlag(featureFlag)"
v-gl-tooltip.hover="$options.translations.legacyFlagReadOnlyAlert"
class="gl-ml-3"
name="information-o"
/>
</div> </div>
<div class="feature-flag-description text-secondary text-truncate"> <div class="feature-flag-description text-secondary text-truncate">
{{ featureFlag.description }} {{ featureFlag.description }}
...@@ -189,18 +152,6 @@ export default { ...@@ -189,18 +152,6 @@ export default {
<div <div
class="table-mobile-content d-flex flex-wrap justify-content-end justify-content-md-start js-feature-flag-environments" class="table-mobile-content d-flex flex-wrap justify-content-end justify-content-md-start js-feature-flag-environments"
> >
<template v-if="isLegacyFlag(featureFlag)">
<gl-badge
v-for="scope in featureFlag.scopes"
:key="scope.id"
v-gl-tooltip.hover="scopeTooltipText(scope)"
:variant="badgeVariant(scope)"
:data-qa-selector="`feature-flag-scope-${badgeVariant(scope)}-badge`"
class="gl-mr-3 gl-mt-2"
>{{ badgeText(scope) }}</gl-badge
>
</template>
<template v-else>
<gl-badge <gl-badge
v-for="strategy in featureFlag.strategies" v-for="strategy in featureFlag.strategies"
:key="strategy.id" :key="strategy.id"
...@@ -209,7 +160,6 @@ export default { ...@@ -209,7 +160,6 @@ export default {
class="gl-mr-3 gl-mt-2 gl-white-space-normal gl-text-left gl-px-5" class="gl-mr-3 gl-mt-2 gl-white-space-normal gl-text-left gl-px-5"
>{{ strategyBadgeText(strategy) }}</gl-badge >{{ strategyBadgeText(strategy) }}</gl-badge
> >
</template>
</div> </div>
</div> </div>
......
import Vue from 'vue'; import Vue from 'vue';
import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils'; import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
import { mapToScopesViewModel } from '../helpers';
import * as types from './mutation_types'; import * as types from './mutation_types';
const mapFlag = (flag) => ({ ...flag, scopes: mapToScopesViewModel(flag.scopes || []) });
const updateFlag = (state, flag) => { const updateFlag = (state, flag) => {
const index = state.featureFlags.findIndex(({ id }) => id === flag.id); const index = state.featureFlags.findIndex(({ id }) => id === flag.id);
Vue.set(state.featureFlags, index, flag); Vue.set(state.featureFlags, index, flag);
...@@ -31,7 +28,7 @@ export default { ...@@ -31,7 +28,7 @@ export default {
[types.RECEIVE_FEATURE_FLAGS_SUCCESS](state, response) { [types.RECEIVE_FEATURE_FLAGS_SUCCESS](state, response) {
state.isLoading = false; state.isLoading = false;
state.hasError = false; state.hasError = false;
state.featureFlags = (response.data.feature_flags || []).map(mapFlag); state.featureFlags = response.data.feature_flags || [];
const paginationInfo = createPaginationInfo(response.headers); const paginationInfo = createPaginationInfo(response.headers);
state.count = paginationInfo?.total ?? state.featureFlags.length; state.count = paginationInfo?.total ?? state.featureFlags.length;
...@@ -58,7 +55,7 @@ export default { ...@@ -58,7 +55,7 @@ export default {
updateFlag(state, flag); updateFlag(state, flag);
}, },
[types.RECEIVE_UPDATE_FEATURE_FLAG_SUCCESS](state, data) { [types.RECEIVE_UPDATE_FEATURE_FLAG_SUCCESS](state, data) {
updateFlag(state, mapFlag(data)); updateFlag(state, data);
}, },
[types.RECEIVE_UPDATE_FEATURE_FLAG_ERROR](state, i) { [types.RECEIVE_UPDATE_FEATURE_FLAG_ERROR](state, i) {
const flag = state.featureFlags.find(({ id }) => i === id); const flag = state.featureFlags.find(({ id }) => i === id);
......
...@@ -13568,9 +13568,6 @@ msgstr "" ...@@ -13568,9 +13568,6 @@ msgstr ""
msgid "FeatureFlags|* (All Environments)" msgid "FeatureFlags|* (All Environments)"
msgstr "" msgstr ""
msgid "FeatureFlags|* (All environments)"
msgstr ""
msgid "FeatureFlags|API URL" msgid "FeatureFlags|API URL"
msgstr "" msgstr ""
...@@ -13652,9 +13649,6 @@ msgstr "" ...@@ -13652,9 +13649,6 @@ msgstr ""
msgid "FeatureFlags|Feature flags limit reached (%{featureFlagsLimit}). Delete one or more feature flags before adding new ones." msgid "FeatureFlags|Feature flags limit reached (%{featureFlagsLimit}). Delete one or more feature flags before adding new ones."
msgstr "" msgstr ""
msgid "FeatureFlags|Flag is read-only"
msgstr ""
msgid "FeatureFlags|Get started with feature flags" msgid "FeatureFlags|Get started with feature flags"
msgstr "" msgstr ""
......
...@@ -16,33 +16,63 @@ RSpec.describe 'User sees feature flag list', :js do ...@@ -16,33 +16,63 @@ RSpec.describe 'User sees feature flag list', :js do
sign_in(user) sign_in(user)
end end
context 'with legacy feature flags' do context 'with feature flags' do
before do before do
create_flag(project, 'ci_live_trace', false, version: :legacy_flag).tap do |feature_flag| create_flag(project, 'ci_live_trace', false).tap do |feature_flag|
create_scope(feature_flag, 'review/*', true) create_strategy(feature_flag).tap do |strat|
create(:operations_scope, strategy: strat, environment_scope: '*')
create(:operations_scope, strategy: strat, environment_scope: 'review/*')
end end
create_flag(project, 'drop_legacy_artifacts', false, version: :legacy_flag)
create_flag(project, 'mr_train', true, version: :legacy_flag).tap do |feature_flag|
create_scope(feature_flag, 'production', false)
end end
create_flag(project, 'drop_legacy_artifacts', false)
create_flag(project, 'mr_train', true).tap do |feature_flag|
create_strategy(feature_flag).tap do |strat|
create(:operations_scope, strategy: strat, environment_scope: 'production')
end
end
create(:operations_feature_flag, :new_version_flag, project: project,
name: 'my_flag', active: false)
end end
it 'shows empty page' do it 'shows the user the first flag' do
visit(project_feature_flags_path(project)) visit(project_feature_flags_path(project))
expect(page).to have_text 'Get started with feature flags' within_feature_flag_row(1) do
expect(page).to have_selector('.btn-confirm', text: 'New feature flag') expect(page.find('.js-feature-flag-id')).to have_content('^1')
expect(page).to have_selector('[data-qa-selector="configure_feature_flags_button"]', text: 'Configure') expect(page.find('.feature-flag-name')).to have_content('ci_live_trace')
expect_status_toggle_button_not_to_be_checked
within_feature_flag_scopes do
expect(page.find('[data-testid="strategy-badge"]')).to have_content('All Users: All Environments, review/*')
end
end end
end end
context 'with new version flags' do it 'shows the user the second flag' do
before do visit(project_feature_flags_path(project))
create(:operations_feature_flag, :new_version_flag, project: project,
name: 'my_flag', active: false) within_feature_flag_row(2) do
expect(page.find('.js-feature-flag-id')).to have_content('^2')
expect(page.find('.feature-flag-name')).to have_content('drop_legacy_artifacts')
expect_status_toggle_button_not_to_be_checked
end
end
it 'shows the user the third flag' do
visit(project_feature_flags_path(project))
within_feature_flag_row(3) do
expect(page.find('.js-feature-flag-id')).to have_content('^3')
expect(page.find('.feature-flag-name')).to have_content('mr_train')
expect_status_toggle_button_to_be_checked
within_feature_flag_scopes do
expect(page.find('[data-testid="strategy-badge"]')).to have_content('All Users: production')
end
end
end end
it 'user updates the status toggle' do it 'allows the user to update the status toggle' do
visit(project_feature_flags_path(project)) visit(project_feature_flags_path(project))
within_feature_flag_row(1) do within_feature_flag_row(1) do
...@@ -58,7 +88,7 @@ RSpec.describe 'User sees feature flag list', :js do ...@@ -58,7 +88,7 @@ RSpec.describe 'User sees feature flag list', :js do
visit(project_feature_flags_path(project)) visit(project_feature_flags_path(project))
end end
it 'shows empty page' do it 'shows the empty page' do
expect(page).to have_text 'Get started with feature flags' expect(page).to have_text 'Get started with feature flags'
expect(page).to have_selector('.btn-confirm', text: 'New feature flag') expect(page).to have_selector('.btn-confirm', text: 'New feature flag')
expect(page).to have_selector('[data-qa-selector="configure_feature_flags_button"]', text: 'Configure') expect(page).to have_selector('[data-qa-selector="configure_feature_flags_button"]', text: 'Configure')
......
...@@ -8,9 +8,6 @@ import { ...@@ -8,9 +8,6 @@ import {
ROLLOUT_STRATEGY_PERCENT_ROLLOUT, ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
ROLLOUT_STRATEGY_USER_ID, ROLLOUT_STRATEGY_USER_ID,
ROLLOUT_STRATEGY_GITLAB_USER_LIST, ROLLOUT_STRATEGY_GITLAB_USER_LIST,
NEW_VERSION_FLAG,
LEGACY_FLAG,
DEFAULT_PERCENT_ROLLOUT,
} from '~/feature_flags/constants'; } from '~/feature_flags/constants';
const getDefaultProps = () => ({ const getDefaultProps = () => ({
...@@ -23,17 +20,28 @@ const getDefaultProps = () => ({ ...@@ -23,17 +20,28 @@ const getDefaultProps = () => ({
description: 'flag description', description: 'flag description',
destroy_path: 'destroy/path', destroy_path: 'destroy/path',
edit_path: 'edit/path', edit_path: 'edit/path',
version: LEGACY_FLAG, scopes: [],
scopes: [ strategies: [
{ {
id: 1, name: ROLLOUT_STRATEGY_ALL_USERS,
active: true, parameters: {},
environmentScope: 'scope', scopes: [{ environment_scope: '*' }],
canUpdate: true, },
protected: false, {
rolloutStrategy: ROLLOUT_STRATEGY_ALL_USERS, name: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
rolloutPercentage: DEFAULT_PERCENT_ROLLOUT, parameters: { percentage: '50' },
shouldBeDestroyed: false, scopes: [{ environment_scope: 'production' }, { environment_scope: 'staging' }],
},
{
name: ROLLOUT_STRATEGY_USER_ID,
parameters: { userIds: '1,2,3,4' },
scopes: [{ environment_scope: 'review/*' }],
},
{
name: ROLLOUT_STRATEGY_GITLAB_USER_LIST,
parameters: {},
user_list: { name: 'test list' },
scopes: [{ environment_scope: '*' }],
}, },
], ],
}, },
...@@ -43,6 +51,7 @@ const getDefaultProps = () => ({ ...@@ -43,6 +51,7 @@ const getDefaultProps = () => ({
describe('Feature flag table', () => { describe('Feature flag table', () => {
let wrapper; let wrapper;
let props; let props;
let badges;
const createWrapper = (propsData, opts = {}) => { const createWrapper = (propsData, opts = {}) => {
wrapper = shallowMount(FeatureFlagsTable, { wrapper = shallowMount(FeatureFlagsTable, {
...@@ -54,6 +63,15 @@ describe('Feature flag table', () => { ...@@ -54,6 +63,15 @@ describe('Feature flag table', () => {
}); });
}; };
beforeEach(() => {
props = getDefaultProps();
createWrapper(props, {
provide: { csrfToken: 'fakeToken' },
});
badges = wrapper.findAll('[data-testid="strategy-badge"]');
});
beforeEach(() => { beforeEach(() => {
props = getDefaultProps(); props = getDefaultProps();
}); });
...@@ -97,17 +115,10 @@ describe('Feature flag table', () => { ...@@ -97,17 +115,10 @@ describe('Feature flag table', () => {
); );
}); });
it('should render an environments specs column', () => {
const envColumn = wrapper.find('.js-feature-flag-environments');
expect(envColumn).toBeDefined();
expect(trimText(envColumn.text())).toBe('scope');
});
it('should render an environments specs badge with active class', () => { it('should render an environments specs badge with active class', () => {
const envColumn = wrapper.find('.js-feature-flag-environments'); const envColumn = wrapper.find('.js-feature-flag-environments');
expect(trimText(envColumn.find(GlBadge).text())).toBe('scope'); expect(trimText(envColumn.find(GlBadge).text())).toBe('All Users: All Environments');
}); });
it('should render an actions column', () => { it('should render an actions column', () => {
...@@ -120,11 +131,13 @@ describe('Feature flag table', () => { ...@@ -120,11 +131,13 @@ describe('Feature flag table', () => {
describe('when active and with an update toggle', () => { describe('when active and with an update toggle', () => {
let toggle; let toggle;
let spy;
beforeEach(() => { beforeEach(() => {
props.featureFlags[0].update_path = props.featureFlags[0].destroy_path; props.featureFlags[0].update_path = props.featureFlags[0].destroy_path;
createWrapper(props); createWrapper(props);
toggle = wrapper.find(GlToggle); toggle = wrapper.find(GlToggle);
spy = mockTracking('_category_', toggle.element, jest.spyOn);
}); });
it('should have a toggle', () => { it('should have a toggle', () => {
...@@ -143,88 +156,14 @@ describe('Feature flag table', () => { ...@@ -143,88 +156,14 @@ describe('Feature flag table', () => {
expect(wrapper.emitted('toggle-flag')).toEqual([[flag]]); expect(wrapper.emitted('toggle-flag')).toEqual([[flag]]);
}); });
}); });
});
describe('with an active scope and a percentage rollout strategy', () => {
beforeEach(() => {
props.featureFlags[0].scopes[0].rolloutStrategy = ROLLOUT_STRATEGY_PERCENT_ROLLOUT;
props.featureFlags[0].scopes[0].rolloutPercentage = '54';
createWrapper(props);
});
it('should render an environments specs badge with percentage', () => {
const envColumn = wrapper.find('.js-feature-flag-environments');
expect(trimText(envColumn.find(GlBadge).text())).toBe('scope: 54%');
});
});
describe('with an inactive scope', () => {
beforeEach(() => {
props.featureFlags[0].scopes[0].active = false;
createWrapper(props);
});
it('should render an environments specs badge with inactive class', () => { it('tracks a click', () => {
const envColumn = wrapper.find('.js-feature-flag-environments'); toggle.trigger('click');
expect(trimText(envColumn.find(GlBadge).text())).toBe('scope'); expect(spy).toHaveBeenCalledWith('_category_', 'click_button', {
}); label: 'feature_flag_toggle',
}); });
describe('with a new version flag', () => {
let toggle;
let spy;
let badges;
beforeEach(() => {
const newVersionProps = {
...props,
featureFlags: [
{
id: 1,
iid: 1,
active: true,
name: 'flag name',
description: 'flag description',
destroy_path: 'destroy/path',
edit_path: 'edit/path',
update_path: 'update/path',
version: NEW_VERSION_FLAG,
scopes: [],
strategies: [
{
name: ROLLOUT_STRATEGY_ALL_USERS,
parameters: {},
scopes: [{ environment_scope: '*' }],
},
{
name: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
parameters: { percentage: '50' },
scopes: [{ environment_scope: 'production' }, { environment_scope: 'staging' }],
},
{
name: ROLLOUT_STRATEGY_USER_ID,
parameters: { userIds: '1,2,3,4' },
scopes: [{ environment_scope: 'review/*' }],
},
{
name: ROLLOUT_STRATEGY_GITLAB_USER_LIST,
parameters: {},
user_list: { name: 'test list' },
scopes: [{ environment_scope: '*' }],
},
],
},
],
};
createWrapper(newVersionProps, {
provide: { csrfToken: 'fakeToken', glFeatures: { featureFlagsNewVersion: true } },
}); });
toggle = wrapper.find(GlToggle);
spy = mockTracking('_category_', toggle.element, jest.spyOn);
badges = wrapper.findAll('[data-testid="strategy-badge"]');
}); });
it('shows All Environments if the environment scope is *', () => { it('shows All Environments if the environment scope is *', () => {
...@@ -253,15 +192,6 @@ describe('Feature flag table', () => { ...@@ -253,15 +192,6 @@ describe('Feature flag table', () => {
expect(badges.at(3).text()).toContain('User List - test list'); expect(badges.at(3).text()).toContain('User List - test list');
}); });
it('tracks a click', () => {
toggle.trigger('click');
expect(spy).toHaveBeenCalledWith('_category_', 'click_button', {
label: 'feature_flag_toggle',
});
});
});
it('renders a feature flag without an iid', () => { it('renders a feature flag without an iid', () => {
delete props.featureFlags[0].iid; delete props.featureFlags[0].iid;
createWrapper(props); createWrapper(props);
......
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper'; import testAction from 'helpers/vuex_action_helper';
import { TEST_HOST } from 'spec/test_constants'; import { TEST_HOST } from 'spec/test_constants';
import { mapToScopesViewModel } from '~/feature_flags/store/helpers';
import { import {
requestFeatureFlags, requestFeatureFlags,
receiveFeatureFlagsSuccess, receiveFeatureFlagsSuccess,
...@@ -255,7 +254,6 @@ describe('Feature flags actions', () => { ...@@ -255,7 +254,6 @@ describe('Feature flags actions', () => {
beforeEach(() => { beforeEach(() => {
mockedState.featureFlags = getRequestData.feature_flags.map((flag) => ({ mockedState.featureFlags = getRequestData.feature_flags.map((flag) => ({
...flag, ...flag,
scopes: mapToScopesViewModel(flag.scopes || []),
})); }));
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
}); });
...@@ -314,7 +312,6 @@ describe('Feature flags actions', () => { ...@@ -314,7 +312,6 @@ describe('Feature flags actions', () => {
beforeEach(() => { beforeEach(() => {
mockedState.featureFlags = getRequestData.feature_flags.map((f) => ({ mockedState.featureFlags = getRequestData.feature_flags.map((f) => ({
...f, ...f,
scopes: mapToScopesViewModel(f.scopes || []),
})); }));
}); });
...@@ -338,7 +335,6 @@ describe('Feature flags actions', () => { ...@@ -338,7 +335,6 @@ describe('Feature flags actions', () => {
beforeEach(() => { beforeEach(() => {
mockedState.featureFlags = getRequestData.feature_flags.map((f) => ({ mockedState.featureFlags = getRequestData.feature_flags.map((f) => ({
...f, ...f,
scopes: mapToScopesViewModel(f.scopes || []),
})); }));
}); });
...@@ -362,7 +358,6 @@ describe('Feature flags actions', () => { ...@@ -362,7 +358,6 @@ describe('Feature flags actions', () => {
beforeEach(() => { beforeEach(() => {
mockedState.featureFlags = getRequestData.feature_flags.map((f) => ({ mockedState.featureFlags = getRequestData.feature_flags.map((f) => ({
...f, ...f,
scopes: mapToScopesViewModel(f.scopes || []),
})); }));
}); });
......
import { mapToScopesViewModel } from '~/feature_flags/store/helpers';
import * as types from '~/feature_flags/store/index/mutation_types'; import * as types from '~/feature_flags/store/index/mutation_types';
import mutations from '~/feature_flags/store/index/mutations'; import mutations from '~/feature_flags/store/index/mutations';
import state from '~/feature_flags/store/index/state'; import state from '~/feature_flags/store/index/state';
...@@ -49,15 +48,6 @@ describe('Feature flags store Mutations', () => { ...@@ -49,15 +48,6 @@ describe('Feature flags store Mutations', () => {
expect(stateCopy.hasError).toEqual(false); expect(stateCopy.hasError).toEqual(false);
}); });
it('should set featureFlags with the transformed data', () => {
const expected = getRequestData.feature_flags.map((flag) => ({
...flag,
scopes: mapToScopesViewModel(flag.scopes || []),
}));
expect(stateCopy.featureFlags).toEqual(expected);
});
it('should set count with the given data', () => { it('should set count with the given data', () => {
expect(stateCopy.count).toEqual(37); expect(stateCopy.count).toEqual(37);
}); });
...@@ -131,13 +121,11 @@ describe('Feature flags store Mutations', () => { ...@@ -131,13 +121,11 @@ describe('Feature flags store Mutations', () => {
beforeEach(() => { beforeEach(() => {
stateCopy.featureFlags = getRequestData.feature_flags.map((flag) => ({ stateCopy.featureFlags = getRequestData.feature_flags.map((flag) => ({
...flag, ...flag,
scopes: mapToScopesViewModel(flag.scopes || []),
})); }));
stateCopy.count = { featureFlags: 1, userLists: 0 }; stateCopy.count = { featureFlags: 1, userLists: 0 };
mutations[types.UPDATE_FEATURE_FLAG](stateCopy, { mutations[types.UPDATE_FEATURE_FLAG](stateCopy, {
...featureFlag, ...featureFlag,
scopes: mapToScopesViewModel(featureFlag.scopes || []),
active: false, active: false,
}); });
}); });
...@@ -146,7 +134,6 @@ describe('Feature flags store Mutations', () => { ...@@ -146,7 +134,6 @@ describe('Feature flags store Mutations', () => {
expect(stateCopy.featureFlags).toEqual([ expect(stateCopy.featureFlags).toEqual([
{ {
...featureFlag, ...featureFlag,
scopes: mapToScopesViewModel(featureFlag.scopes || []),
active: false, active: false,
}, },
]); ]);
...@@ -158,7 +145,6 @@ describe('Feature flags store Mutations', () => { ...@@ -158,7 +145,6 @@ describe('Feature flags store Mutations', () => {
stateCopy.featureFlags = getRequestData.feature_flags.map((flag) => ({ stateCopy.featureFlags = getRequestData.feature_flags.map((flag) => ({
...flag, ...flag,
...flagState, ...flagState,
scopes: mapToScopesViewModel(flag.scopes || []),
})); }));
stateCopy.count = stateCount; stateCopy.count = stateCount;
...@@ -174,7 +160,6 @@ describe('Feature flags store Mutations', () => { ...@@ -174,7 +160,6 @@ describe('Feature flags store Mutations', () => {
expect(stateCopy.featureFlags).toEqual([ expect(stateCopy.featureFlags).toEqual([
{ {
...featureFlag, ...featureFlag,
scopes: mapToScopesViewModel(featureFlag.scopes || []),
active: false, active: false,
}, },
]); ]);
...@@ -185,7 +170,6 @@ describe('Feature flags store Mutations', () => { ...@@ -185,7 +170,6 @@ describe('Feature flags store Mutations', () => {
beforeEach(() => { beforeEach(() => {
stateCopy.featureFlags = getRequestData.feature_flags.map((flag) => ({ stateCopy.featureFlags = getRequestData.feature_flags.map((flag) => ({
...flag, ...flag,
scopes: mapToScopesViewModel(flag.scopes || []),
})); }));
mutations[types.RECEIVE_UPDATE_FEATURE_FLAG_ERROR](stateCopy, featureFlag.id); mutations[types.RECEIVE_UPDATE_FEATURE_FLAG_ERROR](stateCopy, featureFlag.id);
}); });
...@@ -194,7 +178,6 @@ describe('Feature flags store Mutations', () => { ...@@ -194,7 +178,6 @@ describe('Feature flags store Mutations', () => {
expect(stateCopy.featureFlags).toEqual([ expect(stateCopy.featureFlags).toEqual([
{ {
...featureFlag, ...featureFlag,
scopes: mapToScopesViewModel(featureFlag.scopes || []),
active: false, active: false,
}, },
]); ]);
......
...@@ -14,6 +14,12 @@ module FeatureFlagHelpers ...@@ -14,6 +14,12 @@ module FeatureFlagHelpers
strategies: strategies) strategies: strategies)
end end
def create_strategy(feature_flag, name = 'default', parameters = {})
create(:operations_strategy,
feature_flag: feature_flag,
name: name)
end
def within_feature_flag_row(index) def within_feature_flag_row(index)
within ".gl-responsive-table-row:nth-child(#{index + 1})" do within ".gl-responsive-table-row:nth-child(#{index + 1})" do
yield yield
......
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