debian-mirror-gitlab/spec/frontend/feature_flags/components/feature_flags_spec.js

321 lines
9.7 KiB
JavaScript
Raw Normal View History

2021-09-04 01:27:46 +05:30
import { GlAlert, GlEmptyState, GlLoadingIcon } from '@gitlab/ui';
import { mount, createLocalVue } from '@vue/test-utils';
2021-01-03 14:25:43 +05:30
import MockAdapter from 'axios-mock-adapter';
2021-03-11 19:13:27 +05:30
import Vuex from 'vuex';
2021-09-04 01:27:46 +05:30
import waitForPromises from 'helpers/wait_for_promises';
2021-01-03 14:25:43 +05:30
import { TEST_HOST } from 'spec/test_constants';
2021-03-11 19:13:27 +05:30
import ConfigureFeatureFlagsModal from '~/feature_flags/components/configure_feature_flags_modal.vue';
2021-09-04 01:27:46 +05:30
import EmptyState from '~/feature_flags/components/empty_state.vue';
2021-01-03 14:25:43 +05:30
import FeatureFlagsComponent from '~/feature_flags/components/feature_flags.vue';
import FeatureFlagsTable from '~/feature_flags/components/feature_flags_table.vue';
2021-03-11 19:13:27 +05:30
import createStore from '~/feature_flags/store/index';
2021-01-03 14:25:43 +05:30
import axios from '~/lib/utils/axios_utils';
2021-03-11 19:13:27 +05:30
import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue';
2021-09-04 01:27:46 +05:30
import { getRequestData } from '../mock_data';
2021-01-03 14:25:43 +05:30
const localVue = createLocalVue();
localVue.use(Vuex);
describe('Feature flags', () => {
const mockData = {
canUserConfigure: true,
csrfToken: 'testToken',
featureFlagsClientExampleHelpPagePath: '/help/feature-flags#client-example',
featureFlagsClientLibrariesHelpPagePath: '/help/feature-flags#unleash-clients',
featureFlagsHelpPagePath: '/help/feature-flags',
featureFlagsLimit: '200',
featureFlagsLimitExceeded: false,
newFeatureFlagPath: 'feature-flags/new',
2021-09-04 01:27:46 +05:30
userListPath: '/user-list',
2021-01-03 14:25:43 +05:30
unleashApiUrl: `${TEST_HOST}/api/unleash`,
projectName: 'fakeProjectName',
errorStateSvgPath: '/assets/illustrations/feature_flag.svg',
};
const mockState = {
endpoint: `${TEST_HOST}/endpoint.json`,
projectId: '8',
unleashApiInstanceId: 'oP6sCNRqtRHmpy1gw2-F',
};
let wrapper;
let mock;
let store;
2021-09-04 01:27:46 +05:30
const factory = (provide = mockData, fn = mount) => {
2021-01-03 14:25:43 +05:30
store = createStore(mockState);
wrapper = fn(FeatureFlagsComponent, {
localVue,
store,
provide,
stubs: {
2021-09-04 01:27:46 +05:30
EmptyState,
2021-01-03 14:25:43 +05:30
},
});
};
const configureButton = () => wrapper.find('[data-testid="ff-configure-button"]');
const newButton = () => wrapper.find('[data-testid="ff-new-button"]');
2021-09-04 01:27:46 +05:30
const userListButton = () => wrapper.find('[data-testid="ff-user-list-button"]');
const limitAlert = () => wrapper.findComponent(GlAlert);
2021-01-03 14:25:43 +05:30
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
wrapper.destroy();
wrapper = null;
});
describe('when limit exceeded', () => {
const provideData = { ...mockData, featureFlagsLimitExceeded: true };
2021-03-08 18:12:59 +05:30
beforeEach((done) => {
2021-01-03 14:25:43 +05:30
mock
2021-09-04 01:27:46 +05:30
.onGet(`${TEST_HOST}/endpoint.json`, { params: { page: '1' } })
2021-01-03 14:25:43 +05:30
.reply(200, getRequestData, {});
factory(provideData);
setImmediate(done);
});
it('makes the new feature flag button do nothing if clicked', () => {
expect(newButton().exists()).toBe(true);
expect(newButton().props('disabled')).toBe(false);
expect(newButton().props('href')).toBe(undefined);
});
it('shows a feature flags limit reached alert', () => {
expect(limitAlert().exists()).toBe(true);
2021-09-04 01:27:46 +05:30
expect(limitAlert().text()).toContain('Feature flags limit reached');
2021-01-03 14:25:43 +05:30
});
describe('when the alert is dismissed', () => {
beforeEach(async () => {
await limitAlert().vm.$emit('dismiss');
});
it('hides the alert', async () => {
expect(limitAlert().exists()).toBe(false);
});
it('re-shows the alert if the new feature flag button is clicked', async () => {
await newButton().vm.$emit('click');
expect(limitAlert().exists()).toBe(true);
});
});
});
describe('without permissions', () => {
const provideData = {
...mockData,
canUserConfigure: false,
canUserRotateToken: false,
newFeatureFlagPath: null,
2021-09-04 01:27:46 +05:30
userListPath: null,
2021-01-03 14:25:43 +05:30
};
2021-03-08 18:12:59 +05:30
beforeEach((done) => {
2021-01-03 14:25:43 +05:30
mock
2021-09-04 01:27:46 +05:30
.onGet(`${TEST_HOST}/endpoint.json`, { params: { page: '1' } })
2021-01-03 14:25:43 +05:30
.reply(200, getRequestData, {});
factory(provideData);
setImmediate(done);
});
it('does not render configure button', () => {
expect(configureButton().exists()).toBe(false);
});
it('does not render new feature flag button', () => {
expect(newButton().exists()).toBe(false);
});
2021-09-04 01:27:46 +05:30
it('does not render view user list button', () => {
expect(userListButton().exists()).toBe(false);
2021-01-03 14:25:43 +05:30
});
});
describe('loading state', () => {
it('renders a loading icon', () => {
mock
2021-09-04 01:27:46 +05:30
.onGet(`${TEST_HOST}/endpoint.json`, { params: { page: '1' } })
2021-01-03 14:25:43 +05:30
.replyOnce(200, getRequestData, {});
factory();
2021-09-04 01:27:46 +05:30
const loadingElement = wrapper.findComponent(GlLoadingIcon);
2021-01-03 14:25:43 +05:30
expect(loadingElement.exists()).toBe(true);
expect(loadingElement.props('label')).toEqual('Loading feature flags');
});
});
describe('successful request', () => {
describe('without feature flags', () => {
let emptyState;
beforeEach(async () => {
2021-09-04 01:27:46 +05:30
mock.onGet(mockState.endpoint, { params: { page: '1' } }).reply(
2021-01-03 14:25:43 +05:30
200,
{
feature_flags: [],
count: {
all: 0,
enabled: 0,
disabled: 0,
},
},
{},
);
factory();
2021-09-04 01:27:46 +05:30
await waitForPromises();
2021-01-03 14:25:43 +05:30
await wrapper.vm.$nextTick();
2021-09-04 01:27:46 +05:30
emptyState = wrapper.findComponent(GlEmptyState);
2021-01-03 14:25:43 +05:30
});
it('should render the empty state', async () => {
expect(emptyState.exists()).toBe(true);
});
it('renders configure button', () => {
expect(configureButton().exists()).toBe(true);
});
it('renders new feature flag button', () => {
expect(newButton().exists()).toBe(true);
});
2021-09-04 01:27:46 +05:30
it('renders view user list button', () => {
expect(userListButton().exists()).toBe(true);
expect(userListButton().attributes('href')).toBe(mockData.userListPath);
2021-01-03 14:25:43 +05:30
});
describe('in feature flags tab', () => {
it('renders generic title', () => {
expect(emptyState.props('title')).toEqual('Get started with feature flags');
});
});
});
describe('with paginated feature flags', () => {
2021-03-08 18:12:59 +05:30
beforeEach((done) => {
2021-09-04 01:27:46 +05:30
mock.onGet(mockState.endpoint, { params: { page: '1' } }).replyOnce(200, getRequestData, {
'x-next-page': '2',
'x-page': '1',
'X-Per-Page': '2',
'X-Prev-Page': '',
'X-TOTAL': '37',
'X-Total-Pages': '5',
});
2021-01-03 14:25:43 +05:30
factory();
jest.spyOn(store, 'dispatch');
setImmediate(done);
});
it('should render a table with feature flags', () => {
2021-09-04 01:27:46 +05:30
const table = wrapper.findComponent(FeatureFlagsTable);
2021-01-03 14:25:43 +05:30
expect(table.exists()).toBe(true);
2021-09-04 01:27:46 +05:30
expect(table.props('featureFlags')).toEqual(
2021-01-03 14:25:43 +05:30
expect.arrayContaining([
expect.objectContaining({
name: getRequestData.feature_flags[0].name,
description: getRequestData.feature_flags[0].description,
}),
]),
);
});
it('should toggle a flag when receiving the toggle-flag event', () => {
2021-09-04 01:27:46 +05:30
const table = wrapper.findComponent(FeatureFlagsTable);
2021-01-03 14:25:43 +05:30
2021-09-04 01:27:46 +05:30
const [flag] = table.props('featureFlags');
2021-01-03 14:25:43 +05:30
table.vm.$emit('toggle-flag', flag);
expect(store.dispatch).toHaveBeenCalledWith('toggleFeatureFlag', flag);
});
it('renders configure button', () => {
expect(configureButton().exists()).toBe(true);
});
it('renders new feature flag button', () => {
expect(newButton().exists()).toBe(true);
});
2021-09-04 01:27:46 +05:30
it('renders view user list button', () => {
expect(userListButton().exists()).toBe(true);
expect(userListButton().attributes('href')).toBe(mockData.userListPath);
2021-01-03 14:25:43 +05:30
});
describe('pagination', () => {
it('should render pagination', () => {
2021-09-04 01:27:46 +05:30
expect(wrapper.findComponent(TablePagination).exists()).toBe(true);
2021-01-03 14:25:43 +05:30
});
it('should make an API request when page is clicked', () => {
jest.spyOn(wrapper.vm, 'updateFeatureFlagOptions');
2021-09-04 01:27:46 +05:30
wrapper.findComponent(TablePagination).vm.change(4);
2021-01-03 14:25:43 +05:30
expect(wrapper.vm.updateFeatureFlagOptions).toHaveBeenCalledWith({
page: '4',
});
});
});
});
});
describe('unsuccessful request', () => {
2021-03-08 18:12:59 +05:30
beforeEach((done) => {
2021-09-04 01:27:46 +05:30
mock.onGet(mockState.endpoint, { params: { page: '1' } }).replyOnce(500, {});
2021-01-03 14:25:43 +05:30
factory();
setImmediate(done);
});
it('should render error state', () => {
2021-09-04 01:27:46 +05:30
const emptyState = wrapper.findComponent(GlEmptyState);
2021-01-03 14:25:43 +05:30
expect(emptyState.props('title')).toEqual('There was an error fetching the feature flags.');
expect(emptyState.props('description')).toEqual(
'Try again in a few moments or contact your support team.',
);
});
it('renders configure button', () => {
expect(configureButton().exists()).toBe(true);
});
it('renders new feature flag button', () => {
expect(newButton().exists()).toBe(true);
});
2021-09-04 01:27:46 +05:30
it('renders view user list button', () => {
expect(userListButton().exists()).toBe(true);
expect(userListButton().attributes('href')).toBe(mockData.userListPath);
2021-01-03 14:25:43 +05:30
});
});
describe('rotate instance id', () => {
2021-03-08 18:12:59 +05:30
beforeEach((done) => {
2021-01-03 14:25:43 +05:30
mock
2021-09-04 01:27:46 +05:30
.onGet(`${TEST_HOST}/endpoint.json`, { params: { page: '1' } })
2021-01-03 14:25:43 +05:30
.reply(200, getRequestData, {});
factory();
setImmediate(done);
});
it('should fire the rotate action when a `token` event is received', () => {
const actionSpy = jest.spyOn(wrapper.vm, 'rotateInstanceId');
2021-09-04 01:27:46 +05:30
const modal = wrapper.findComponent(ConfigureFeatureFlagsModal);
2021-01-03 14:25:43 +05:30
modal.vm.$emit('token');
expect(actionSpy).toHaveBeenCalled();
});
});
});