Commit 53829fb2 authored by Paul Slaughter's avatar Paul Slaughter

Merge branch 'implement-feature-flags-plugin' into 'master'

Implement feature flags plugin

See merge request gitlab-org/gitlab!17385
parents 06ba7ac6 ec49429e
import Vue from 'vue';
import GlFeatureFlagsPlugin from '~/vue_shared/gl_feature_flags_plugin';
if (process.env.NODE_ENV !== 'production') {
Vue.config.productionTip = false;
}
Vue.use(GlFeatureFlagsPlugin);
export default Vue => {
Vue.mixin({
provide: {
glFeatures: { ...((window.gon && window.gon.features) || {}) },
},
});
};
export default () => ({
inject: {
glFeatures: {
from: 'glFeatures',
default: () => ({}),
},
},
});
......@@ -104,6 +104,51 @@ document.addEventListener('DOMContentLoaded', () => new Vue({
}));
```
#### Accessing feature flags
Use Vue's [provide/inject](https://vuejs.org/v2/api/#provide-inject) mechanism
to make feature flags available to any descendant components in a Vue
application. The `glFeatures` object is already provided in `commons/vue.js`, so
only the mixin is required to utilize the flags:
```javascript
// An arbitrary descendant component
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
export default {
// ...
mixins: [glFeatureFlagsMixin()],
// ...
created() {
if (this.glFeatures.myFlag) {
// ...
}
},
}
```
This approach has a few benefits:
- Arbitrarily deeply nested components can opt-in and access the flag without
intermediate components being aware of it (c.f. passing the flag down via
props).
- Good testability, since the flag can be provided to `mount`/`shallowMount`
from `vue-test-utils` as easily as a prop.
```javascript
import { shallowMount } from '@vue/test-utils';
shallowMount(component, {
provide: {
glFeatures: { myFlag: true },
},
});
```
- No need to access a global variable, except in the application's
[entry point](#accessing-the-gl-object).
### A folder for Components
This folder holds all components that are specific of this new feature.
......
......@@ -109,6 +109,9 @@ if ( gon.features.vimBindings ) {
The name of the feature flag in JavaScript will always be camelCased, meaning
that checking for `gon.features.vim_bindings` would not work.
See the [Vue guide](../fe_guide/vue.md#accessing-feature-flags) for details about
how to access feature flags in a Vue component.
### Specs
In the test environment `Feature.enabled?` is stubbed to always respond to `true`,
......
import { createLocalVue, shallowMount } from '@vue/test-utils';
import GlFeatureFlags from '~/vue_shared/gl_feature_flags_plugin';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
const localVue = createLocalVue();
describe('GitLab Feature Flags Plugin', () => {
beforeEach(() => {
window.gon = {
features: {
aFeature: true,
bFeature: false,
},
};
localVue.use(GlFeatureFlags);
});
it('should provide glFeatures to components', () => {
const component = {
template: `<span></span>`,
inject: ['glFeatures'],
};
const wrapper = shallowMount(component, { localVue });
expect(wrapper.vm.glFeatures).toEqual({
aFeature: true,
bFeature: false,
});
});
it('should integrate with the glFeatureMixin', () => {
const component = {
template: `<span></span>`,
mixins: [glFeatureFlagsMixin()],
};
const wrapper = shallowMount(component, { localVue });
expect(wrapper.vm.glFeatures).toEqual({
aFeature: true,
bFeature: false,
});
});
});
import { createLocalVue, shallowMount } from '@vue/test-utils';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
const localVue = createLocalVue();
describe('GitLab Feature Flags Mixin', () => {
let wrapper;
beforeEach(() => {
const gon = {
features: {
aFeature: true,
bFeature: false,
},
};
const component = {
template: `<span></span>`,
mixins: [glFeatureFlagsMixin()],
};
wrapper = shallowMount(component, {
localVue,
provide: {
glFeatures: { ...(gon.features || {}) },
},
});
});
it('should provide glFeatures to components', () => {
expect(wrapper.vm.glFeatures).toEqual({
aFeature: true,
bFeature: false,
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment