From a5f4bba440d7f9ea47046a0a561d49adf0a1e6d4 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 16 Jun 2021 18:25:58 +0000 Subject: Add latest changes from gitlab-org/gitlab@14-0-stable-ee --- .../feature_flags/components/empty_state_spec.js | 136 +++++++++++++++++ .../feature_flags/components/feature_flags_spec.js | 145 ++++++------------ .../components/feature_flags_tab_spec.js | 167 --------------------- .../components/user_lists_table_spec.js | 98 ------------ .../feature_flags/store/index/actions_spec.js | 165 +------------------- .../feature_flags/store/index/mutations_spec.js | 94 +----------- 6 files changed, 189 insertions(+), 616 deletions(-) create mode 100644 spec/frontend/feature_flags/components/empty_state_spec.js delete mode 100644 spec/frontend/feature_flags/components/feature_flags_tab_spec.js delete mode 100644 spec/frontend/feature_flags/components/user_lists_table_spec.js (limited to 'spec/frontend/feature_flags') diff --git a/spec/frontend/feature_flags/components/empty_state_spec.js b/spec/frontend/feature_flags/components/empty_state_spec.js new file mode 100644 index 00000000000..86d0c1a05fd --- /dev/null +++ b/spec/frontend/feature_flags/components/empty_state_spec.js @@ -0,0 +1,136 @@ +import { GlAlert, GlEmptyState, GlLink, GlLoadingIcon } from '@gitlab/ui'; +import { mount } from '@vue/test-utils'; +import EmptyState from '~/feature_flags/components/empty_state.vue'; + +const DEFAULT_PROPS = { + alerts: ['an alert', 'another alert'], + isLoading: false, + loadingLabel: 'test loading', + errorState: false, + errorTitle: 'test title', + emptyState: false, + emptyTitle: 'test empty', + emptyDescription: 'empty description', +}; + +const DEFAULT_PROVIDE = { + errorStateSvgPath: '/error.svg', + featureFlagsHelpPagePath: '/help/page/path', +}; + +describe('feature_flags/components/feature_flags_tab.vue', () => { + let wrapper; + + const factory = (props = {}) => + mount( + { + components: { + EmptyState, + }, + render(h) { + return h(EmptyState, { props: this.$attrs, on: this.$listeners }, this.$slots.default); + }, + }, + { + propsData: { + ...DEFAULT_PROPS, + ...props, + }, + provide: DEFAULT_PROVIDE, + slots: { + default: '

testing

', + }, + }, + ); + + afterEach(() => { + if (wrapper?.destroy) { + wrapper.destroy(); + } + + wrapper = null; + }); + + describe('alerts', () => { + let alerts; + + beforeEach(() => { + wrapper = factory(); + alerts = wrapper.findAll(GlAlert); + }); + + it('should show any alerts', () => { + expect(alerts).toHaveLength(DEFAULT_PROPS.alerts.length); + alerts.wrappers.forEach((alert, i) => expect(alert.text()).toBe(DEFAULT_PROPS.alerts[i])); + }); + + it('should emit a dismiss event for a dismissed alert', () => { + alerts.at(0).vm.$emit('dismiss'); + + expect(wrapper.find(EmptyState).emitted('dismissAlert')).toEqual([[0]]); + }); + }); + + describe('loading', () => { + beforeEach(() => { + wrapper = factory({ isLoading: true }); + }); + + it('should show a loading icon and nothing else', () => { + expect(wrapper.find(GlLoadingIcon).exists()).toBe(true); + expect(wrapper.findAll(GlEmptyState)).toHaveLength(0); + }); + }); + + describe('error', () => { + let emptyState; + + beforeEach(() => { + wrapper = factory({ errorState: true }); + emptyState = wrapper.find(GlEmptyState); + }); + + it('should show an error state if there has been an error', () => { + expect(emptyState.text()).toContain(DEFAULT_PROPS.errorTitle); + expect(emptyState.text()).toContain( + 'Try again in a few moments or contact your support team.', + ); + expect(emptyState.props('svgPath')).toBe(DEFAULT_PROVIDE.errorStateSvgPath); + }); + }); + + describe('empty', () => { + let emptyState; + let emptyStateLink; + + beforeEach(() => { + wrapper = factory({ emptyState: true }); + emptyState = wrapper.find(GlEmptyState); + emptyStateLink = emptyState.find(GlLink); + }); + + it('should show an empty state if it is empty', () => { + expect(emptyState.text()).toContain(DEFAULT_PROPS.emptyTitle); + expect(emptyState.text()).toContain(DEFAULT_PROPS.emptyDescription); + expect(emptyState.props('svgPath')).toBe(DEFAULT_PROVIDE.errorStateSvgPath); + expect(emptyStateLink.attributes('href')).toBe(DEFAULT_PROVIDE.featureFlagsHelpPagePath); + expect(emptyStateLink.text()).toBe('More information'); + }); + }); + + describe('slot', () => { + let slot; + + beforeEach(async () => { + wrapper = factory(); + await wrapper.vm.$nextTick(); + + slot = wrapper.find('[data-testid="test-slot"]'); + }); + + it('should display the passed slot', () => { + expect(slot.exists()).toBe(true); + expect(slot.text()).toBe('testing'); + }); + }); +}); diff --git a/spec/frontend/feature_flags/components/feature_flags_spec.js b/spec/frontend/feature_flags/components/feature_flags_spec.js index b519aab0dc4..db4bdc736de 100644 --- a/spec/frontend/feature_flags/components/feature_flags_spec.js +++ b/spec/frontend/feature_flags/components/feature_flags_spec.js @@ -1,19 +1,17 @@ -import { GlAlert, GlEmptyState, GlLoadingIcon, GlSprintf } from '@gitlab/ui'; -import { shallowMount, createLocalVue } from '@vue/test-utils'; +import { GlAlert, GlEmptyState, GlLoadingIcon } from '@gitlab/ui'; +import { mount, createLocalVue } from '@vue/test-utils'; import MockAdapter from 'axios-mock-adapter'; import Vuex from 'vuex'; +import waitForPromises from 'helpers/wait_for_promises'; import { TEST_HOST } from 'spec/test_constants'; -import Api from '~/api'; import ConfigureFeatureFlagsModal from '~/feature_flags/components/configure_feature_flags_modal.vue'; +import EmptyState from '~/feature_flags/components/empty_state.vue'; import FeatureFlagsComponent from '~/feature_flags/components/feature_flags.vue'; -import FeatureFlagsTab from '~/feature_flags/components/feature_flags_tab.vue'; import FeatureFlagsTable from '~/feature_flags/components/feature_flags_table.vue'; -import UserListsTable from '~/feature_flags/components/user_lists_table.vue'; -import { FEATURE_FLAG_SCOPE, USER_LIST_SCOPE } from '~/feature_flags/constants'; import createStore from '~/feature_flags/store/index'; import axios from '~/lib/utils/axios_utils'; import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue'; -import { getRequestData, userList } from '../mock_data'; +import { getRequestData } from '../mock_data'; const localVue = createLocalVue(); localVue.use(Vuex); @@ -28,7 +26,7 @@ describe('Feature flags', () => { featureFlagsLimit: '200', featureFlagsLimitExceeded: false, newFeatureFlagPath: 'feature-flags/new', - newUserListPath: '/user-list/new', + userListPath: '/user-list', unleashApiUrl: `${TEST_HOST}/api/unleash`, projectName: 'fakeProjectName', errorStateSvgPath: '/assets/illustrations/feature_flag.svg', @@ -44,36 +42,25 @@ describe('Feature flags', () => { let mock; let store; - const factory = (provide = mockData, fn = shallowMount) => { + const factory = (provide = mockData, fn = mount) => { store = createStore(mockState); wrapper = fn(FeatureFlagsComponent, { localVue, store, provide, stubs: { - FeatureFlagsTab, + EmptyState, }, }); }; const configureButton = () => wrapper.find('[data-testid="ff-configure-button"]'); const newButton = () => wrapper.find('[data-testid="ff-new-button"]'); - const newUserListButton = () => wrapper.find('[data-testid="ff-new-list-button"]'); - const limitAlert = () => wrapper.find(GlAlert); + const userListButton = () => wrapper.find('[data-testid="ff-user-list-button"]'); + const limitAlert = () => wrapper.findComponent(GlAlert); beforeEach(() => { mock = new MockAdapter(axios); - jest.spyOn(Api, 'fetchFeatureFlagUserLists').mockResolvedValue({ - data: [userList], - headers: { - 'x-next-page': '2', - 'x-page': '1', - 'X-Per-Page': '8', - 'X-Prev-Page': '', - 'X-TOTAL': '40', - 'X-Total-Pages': '5', - }, - }); }); afterEach(() => { @@ -87,7 +74,7 @@ describe('Feature flags', () => { beforeEach((done) => { mock - .onGet(`${TEST_HOST}/endpoint.json`, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } }) + .onGet(`${TEST_HOST}/endpoint.json`, { params: { page: '1' } }) .reply(200, getRequestData, {}); factory(provideData); setImmediate(done); @@ -101,9 +88,7 @@ describe('Feature flags', () => { it('shows a feature flags limit reached alert', () => { expect(limitAlert().exists()).toBe(true); - expect(limitAlert().find(GlSprintf).attributes('message')).toContain( - 'Feature flags limit reached', - ); + expect(limitAlert().text()).toContain('Feature flags limit reached'); }); describe('when the alert is dismissed', () => { @@ -129,12 +114,12 @@ describe('Feature flags', () => { canUserConfigure: false, canUserRotateToken: false, newFeatureFlagPath: null, - newUserListPath: null, + userListPath: null, }; beforeEach((done) => { mock - .onGet(`${TEST_HOST}/endpoint.json`, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } }) + .onGet(`${TEST_HOST}/endpoint.json`, { params: { page: '1' } }) .reply(200, getRequestData, {}); factory(provideData); setImmediate(done); @@ -148,20 +133,20 @@ describe('Feature flags', () => { expect(newButton().exists()).toBe(false); }); - it('does not render new user list button', () => { - expect(newUserListButton().exists()).toBe(false); + it('does not render view user list button', () => { + expect(userListButton().exists()).toBe(false); }); }); describe('loading state', () => { it('renders a loading icon', () => { mock - .onGet(`${TEST_HOST}/endpoint.json`, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } }) + .onGet(`${TEST_HOST}/endpoint.json`, { params: { page: '1' } }) .replyOnce(200, getRequestData, {}); factory(); - const loadingElement = wrapper.find(GlLoadingIcon); + const loadingElement = wrapper.findComponent(GlLoadingIcon); expect(loadingElement.exists()).toBe(true); expect(loadingElement.props('label')).toEqual('Loading feature flags'); @@ -173,7 +158,7 @@ describe('Feature flags', () => { let emptyState; beforeEach(async () => { - mock.onGet(mockState.endpoint, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } }).reply( + mock.onGet(mockState.endpoint, { params: { page: '1' } }).reply( 200, { feature_flags: [], @@ -187,9 +172,10 @@ describe('Feature flags', () => { ); factory(); + await waitForPromises(); await wrapper.vm.$nextTick(); - emptyState = wrapper.find(GlEmptyState); + emptyState = wrapper.findComponent(GlEmptyState); }); it('should render the empty state', async () => { @@ -204,9 +190,9 @@ describe('Feature flags', () => { expect(newButton().exists()).toBe(true); }); - it('renders new user list button', () => { - expect(newUserListButton().exists()).toBe(true); - expect(newUserListButton().attributes('href')).toBe('/user-list/new'); + it('renders view user list button', () => { + expect(userListButton().exists()).toBe(true); + expect(userListButton().attributes('href')).toBe(mockData.userListPath); }); describe('in feature flags tab', () => { @@ -218,16 +204,14 @@ describe('Feature flags', () => { describe('with paginated feature flags', () => { beforeEach((done) => { - mock - .onGet(mockState.endpoint, { params: { scope: FEATURE_FLAG_SCOPE, 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', - }); + 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', + }); factory(); jest.spyOn(store, 'dispatch'); @@ -235,9 +219,9 @@ describe('Feature flags', () => { }); it('should render a table with feature flags', () => { - const table = wrapper.find(FeatureFlagsTable); + const table = wrapper.findComponent(FeatureFlagsTable); expect(table.exists()).toBe(true); - expect(table.props(FEATURE_FLAG_SCOPE)).toEqual( + expect(table.props('featureFlags')).toEqual( expect.arrayContaining([ expect.objectContaining({ name: getRequestData.feature_flags[0].name, @@ -248,9 +232,9 @@ describe('Feature flags', () => { }); it('should toggle a flag when receiving the toggle-flag event', () => { - const table = wrapper.find(FeatureFlagsTable); + const table = wrapper.findComponent(FeatureFlagsTable); - const [flag] = table.props(FEATURE_FLAG_SCOPE); + const [flag] = table.props('featureFlags'); table.vm.$emit('toggle-flag', flag); expect(store.dispatch).toHaveBeenCalledWith('toggleFeatureFlag', flag); @@ -264,71 +248,38 @@ describe('Feature flags', () => { expect(newButton().exists()).toBe(true); }); - it('renders new user list button', () => { - expect(newUserListButton().exists()).toBe(true); - expect(newUserListButton().attributes('href')).toBe('/user-list/new'); + it('renders view user list button', () => { + expect(userListButton().exists()).toBe(true); + expect(userListButton().attributes('href')).toBe(mockData.userListPath); }); describe('pagination', () => { it('should render pagination', () => { - expect(wrapper.find(TablePagination).exists()).toBe(true); + expect(wrapper.findComponent(TablePagination).exists()).toBe(true); }); it('should make an API request when page is clicked', () => { jest.spyOn(wrapper.vm, 'updateFeatureFlagOptions'); - wrapper.find(TablePagination).vm.change(4); + wrapper.findComponent(TablePagination).vm.change(4); expect(wrapper.vm.updateFeatureFlagOptions).toHaveBeenCalledWith({ - scope: FEATURE_FLAG_SCOPE, page: '4', }); }); - - it('should make an API request when using tabs', () => { - jest.spyOn(wrapper.vm, 'updateFeatureFlagOptions'); - wrapper.find('[data-testid="user-lists-tab"]').vm.$emit('changeTab'); - - expect(wrapper.vm.updateFeatureFlagOptions).toHaveBeenCalledWith({ - scope: USER_LIST_SCOPE, - page: '1', - }); - }); - }); - }); - - describe('in user lists tab', () => { - beforeEach((done) => { - factory(); - setImmediate(done); - }); - beforeEach(() => { - wrapper.find('[data-testid="user-lists-tab"]').vm.$emit('changeTab'); - return wrapper.vm.$nextTick(); - }); - - it('should display the user list table', () => { - expect(wrapper.find(UserListsTable).exists()).toBe(true); - }); - - it('should set the user lists to display', () => { - expect(wrapper.find(UserListsTable).props('userLists')).toEqual([userList]); }); }); }); describe('unsuccessful request', () => { beforeEach((done) => { - mock - .onGet(mockState.endpoint, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } }) - .replyOnce(500, {}); - Api.fetchFeatureFlagUserLists.mockRejectedValueOnce(); + mock.onGet(mockState.endpoint, { params: { page: '1' } }).replyOnce(500, {}); factory(); setImmediate(done); }); it('should render error state', () => { - const emptyState = wrapper.find(GlEmptyState); + const emptyState = wrapper.findComponent(GlEmptyState); 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.', @@ -343,16 +294,16 @@ describe('Feature flags', () => { expect(newButton().exists()).toBe(true); }); - it('renders new user list button', () => { - expect(newUserListButton().exists()).toBe(true); - expect(newUserListButton().attributes('href')).toBe('/user-list/new'); + it('renders view user list button', () => { + expect(userListButton().exists()).toBe(true); + expect(userListButton().attributes('href')).toBe(mockData.userListPath); }); }); describe('rotate instance id', () => { beforeEach((done) => { mock - .onGet(`${TEST_HOST}/endpoint.json`, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } }) + .onGet(`${TEST_HOST}/endpoint.json`, { params: { page: '1' } }) .reply(200, getRequestData, {}); factory(); setImmediate(done); @@ -360,7 +311,7 @@ describe('Feature flags', () => { it('should fire the rotate action when a `token` event is received', () => { const actionSpy = jest.spyOn(wrapper.vm, 'rotateInstanceId'); - const modal = wrapper.find(ConfigureFeatureFlagsModal); + const modal = wrapper.findComponent(ConfigureFeatureFlagsModal); modal.vm.$emit('token'); expect(actionSpy).toHaveBeenCalled(); diff --git a/spec/frontend/feature_flags/components/feature_flags_tab_spec.js b/spec/frontend/feature_flags/components/feature_flags_tab_spec.js deleted file mode 100644 index c2170e8a768..00000000000 --- a/spec/frontend/feature_flags/components/feature_flags_tab_spec.js +++ /dev/null @@ -1,167 +0,0 @@ -import { GlAlert, GlBadge, GlEmptyState, GlLink, GlLoadingIcon, GlTabs } from '@gitlab/ui'; -import { mount } from '@vue/test-utils'; -import FeatureFlagsTab from '~/feature_flags/components/feature_flags_tab.vue'; - -const DEFAULT_PROPS = { - title: 'test', - count: 5, - alerts: ['an alert', 'another alert'], - isLoading: false, - loadingLabel: 'test loading', - errorState: false, - errorTitle: 'test title', - emptyState: true, - emptyTitle: 'test empty', - emptyDescription: 'empty description', -}; - -const DEFAULT_PROVIDE = { - errorStateSvgPath: '/error.svg', - featureFlagsHelpPagePath: '/help/page/path', -}; - -describe('feature_flags/components/feature_flags_tab.vue', () => { - let wrapper; - - const factory = (props = {}) => - mount( - { - components: { - GlTabs, - FeatureFlagsTab, - }, - render(h) { - return h(GlTabs, [ - h(FeatureFlagsTab, { props: this.$attrs, on: this.$listeners }, this.$slots.default), - ]); - }, - }, - { - propsData: { - ...DEFAULT_PROPS, - ...props, - }, - provide: DEFAULT_PROVIDE, - slots: { - default: '

testing

', - }, - }, - ); - - afterEach(() => { - if (wrapper?.destroy) { - wrapper.destroy(); - } - - wrapper = null; - }); - - describe('alerts', () => { - let alerts; - - beforeEach(() => { - wrapper = factory(); - alerts = wrapper.findAll(GlAlert); - }); - - it('should show any alerts', () => { - expect(alerts).toHaveLength(DEFAULT_PROPS.alerts.length); - alerts.wrappers.forEach((alert, i) => expect(alert.text()).toBe(DEFAULT_PROPS.alerts[i])); - }); - - it('should emit a dismiss event for a dismissed alert', () => { - alerts.at(0).vm.$emit('dismiss'); - - expect(wrapper.find(FeatureFlagsTab).emitted('dismissAlert')).toEqual([[0]]); - }); - }); - - describe('loading', () => { - beforeEach(() => { - wrapper = factory({ isLoading: true }); - }); - - it('should show a loading icon and nothing else', () => { - expect(wrapper.find(GlLoadingIcon).exists()).toBe(true); - expect(wrapper.findAll(GlEmptyState)).toHaveLength(0); - }); - }); - - describe('error', () => { - let emptyState; - - beforeEach(() => { - wrapper = factory({ errorState: true }); - emptyState = wrapper.find(GlEmptyState); - }); - - it('should show an error state if there has been an error', () => { - expect(emptyState.text()).toContain(DEFAULT_PROPS.errorTitle); - expect(emptyState.text()).toContain( - 'Try again in a few moments or contact your support team.', - ); - expect(emptyState.props('svgPath')).toBe(DEFAULT_PROVIDE.errorStateSvgPath); - }); - }); - - describe('empty', () => { - let emptyState; - let emptyStateLink; - - beforeEach(() => { - wrapper = factory({ emptyState: true }); - emptyState = wrapper.find(GlEmptyState); - emptyStateLink = emptyState.find(GlLink); - }); - - it('should show an empty state if it is empty', () => { - expect(emptyState.text()).toContain(DEFAULT_PROPS.emptyTitle); - expect(emptyState.text()).toContain(DEFAULT_PROPS.emptyDescription); - expect(emptyState.props('svgPath')).toBe(DEFAULT_PROVIDE.errorStateSvgPath); - expect(emptyStateLink.attributes('href')).toBe(DEFAULT_PROVIDE.featureFlagsHelpPagePath); - expect(emptyStateLink.text()).toBe('More information'); - }); - }); - - describe('slot', () => { - let slot; - - beforeEach(async () => { - wrapper = factory(); - await wrapper.vm.$nextTick(); - - slot = wrapper.find('[data-testid="test-slot"]'); - }); - - it('should display the passed slot', () => { - expect(slot.exists()).toBe(true); - expect(slot.text()).toBe('testing'); - }); - }); - - describe('count', () => { - it('should display a count if there is one', async () => { - wrapper = factory(); - await wrapper.vm.$nextTick(); - - expect(wrapper.find(GlBadge).text()).toBe(DEFAULT_PROPS.count.toString()); - }); - it('should display 0 if there is no count', async () => { - wrapper = factory({ count: undefined }); - await wrapper.vm.$nextTick(); - - expect(wrapper.find(GlBadge).text()).toBe('0'); - }); - }); - - describe('title', () => { - it('should show the title', async () => { - wrapper = factory(); - await wrapper.vm.$nextTick(); - - expect(wrapper.find('[data-testid="feature-flags-tab-title"]').text()).toBe( - DEFAULT_PROPS.title, - ); - }); - }); -}); diff --git a/spec/frontend/feature_flags/components/user_lists_table_spec.js b/spec/frontend/feature_flags/components/user_lists_table_spec.js deleted file mode 100644 index 1b04ecee146..00000000000 --- a/spec/frontend/feature_flags/components/user_lists_table_spec.js +++ /dev/null @@ -1,98 +0,0 @@ -import { GlModal } from '@gitlab/ui'; -import { mount } from '@vue/test-utils'; -import * as timeago from 'timeago.js'; -import UserListsTable from '~/feature_flags/components/user_lists_table.vue'; -import { userList } from '../mock_data'; - -jest.mock('timeago.js', () => ({ - format: jest.fn().mockReturnValue('2 weeks ago'), - register: jest.fn(), -})); - -describe('User Lists Table', () => { - let wrapper; - let userLists; - - beforeEach(() => { - userLists = new Array(5).fill(userList).map((x, i) => ({ ...x, id: i })); - wrapper = mount(UserListsTable, { - propsData: { userLists }, - }); - }); - - afterEach(() => { - wrapper.destroy(); - }); - - it('should display the details of a user list', () => { - expect(wrapper.find('[data-testid="ffUserListName"]').text()).toBe(userList.name); - expect(wrapper.find('[data-testid="ffUserListIds"]').text()).toBe( - userList.user_xids.replace(/,/g, ', '), - ); - expect(wrapper.find('[data-testid="ffUserListTimestamp"]').text()).toBe('created 2 weeks ago'); - expect(timeago.format).toHaveBeenCalledWith(userList.created_at); - }); - - it('should set the title for a tooltip on the created stamp', () => { - expect(wrapper.find('[data-testid="ffUserListTimestamp"]').attributes('title')).toBe( - 'Feb 4, 2020 8:13am GMT+0000', - ); - }); - - it('should display a user list entry per user list', () => { - const lists = wrapper.findAll('[data-testid="ffUserList"]'); - expect(lists).toHaveLength(5); - lists.wrappers.forEach((list) => { - expect(list.find('[data-testid="ffUserListName"]').exists()).toBe(true); - expect(list.find('[data-testid="ffUserListIds"]').exists()).toBe(true); - expect(list.find('[data-testid="ffUserListTimestamp"]').exists()).toBe(true); - }); - }); - - describe('edit button', () => { - it('should link to the path for the user list', () => { - expect(wrapper.find('[data-testid="edit-user-list"]').attributes('href')).toBe(userList.path); - }); - }); - - describe('delete button', () => { - it('should display the confirmation modal', () => { - const modal = wrapper.find(GlModal); - - wrapper.find('[data-testid="delete-user-list"]').trigger('click'); - - return wrapper.vm.$nextTick().then(() => { - expect(modal.text()).toContain(`Delete ${userList.name}?`); - expect(modal.text()).toContain(`User list ${userList.name} will be removed.`); - }); - }); - }); - - describe('confirmation modal', () => { - let modal; - - beforeEach(() => { - modal = wrapper.find(GlModal); - - wrapper.find('button').trigger('click'); - - return wrapper.vm.$nextTick(); - }); - - it('should emit delete with list on confirmation', () => { - modal.find('[data-testid="modal-confirm"]').trigger('click'); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.emitted('delete')).toEqual([[userLists[0]]]); - }); - }); - - it('should not emit delete with list when not confirmed', () => { - modal.find('button').trigger('click'); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.emitted('delete')).toBeUndefined(); - }); - }); - }); -}); diff --git a/spec/frontend/feature_flags/store/index/actions_spec.js b/spec/frontend/feature_flags/store/index/actions_spec.js index a7ab2e92cb2..ec311ef92a3 100644 --- a/spec/frontend/feature_flags/store/index/actions_spec.js +++ b/spec/frontend/feature_flags/store/index/actions_spec.js @@ -1,7 +1,6 @@ import MockAdapter from 'axios-mock-adapter'; import testAction from 'helpers/vuex_action_helper'; import { TEST_HOST } from 'spec/test_constants'; -import Api from '~/api'; import { mapToScopesViewModel } from '~/feature_flags/store/helpers'; import { requestFeatureFlags, @@ -17,18 +16,12 @@ import { updateFeatureFlag, receiveUpdateFeatureFlagSuccess, receiveUpdateFeatureFlagError, - requestUserLists, - receiveUserListsSuccess, - receiveUserListsError, - fetchUserLists, - deleteUserList, - receiveDeleteUserListError, clearAlert, } from '~/feature_flags/store/index/actions'; import * as types from '~/feature_flags/store/index/mutation_types'; import state from '~/feature_flags/store/index/state'; import axios from '~/lib/utils/axios_utils'; -import { getRequestData, rotateData, featureFlag, userList } from '../../mock_data'; +import { getRequestData, rotateData, featureFlag } from '../../mock_data'; jest.mock('~/api.js'); @@ -154,99 +147,6 @@ describe('Feature flags actions', () => { }); }); - describe('fetchUserLists', () => { - beforeEach(() => { - Api.fetchFeatureFlagUserLists.mockResolvedValue({ data: [userList], headers: {} }); - }); - - describe('success', () => { - it('dispatches requestUserLists and receiveUserListsSuccess ', (done) => { - testAction( - fetchUserLists, - null, - mockedState, - [], - [ - { - type: 'requestUserLists', - }, - { - payload: { data: [userList], headers: {} }, - type: 'receiveUserListsSuccess', - }, - ], - done, - ); - }); - }); - - describe('error', () => { - it('dispatches requestUserLists and receiveUserListsError ', (done) => { - Api.fetchFeatureFlagUserLists.mockRejectedValue(); - - testAction( - fetchUserLists, - null, - mockedState, - [], - [ - { - type: 'requestUserLists', - }, - { - type: 'receiveUserListsError', - }, - ], - done, - ); - }); - }); - }); - - describe('requestUserLists', () => { - it('should commit RECEIVE_USER_LISTS_SUCCESS mutation', (done) => { - testAction( - requestUserLists, - null, - mockedState, - [{ type: types.REQUEST_USER_LISTS }], - [], - done, - ); - }); - }); - - describe('receiveUserListsSuccess', () => { - it('should commit RECEIVE_USER_LISTS_SUCCESS mutation', (done) => { - testAction( - receiveUserListsSuccess, - { data: [userList], headers: {} }, - mockedState, - [ - { - type: types.RECEIVE_USER_LISTS_SUCCESS, - payload: { data: [userList], headers: {} }, - }, - ], - [], - done, - ); - }); - }); - - describe('receiveUserListsError', () => { - it('should commit RECEIVE_USER_LISTS_ERROR mutation', (done) => { - testAction( - receiveUserListsError, - null, - mockedState, - [{ type: types.RECEIVE_USER_LISTS_ERROR }], - [], - done, - ); - }); - }); - describe('rotateInstanceId', () => { let mock; @@ -482,69 +382,6 @@ describe('Feature flags actions', () => { ); }); }); - describe('deleteUserList', () => { - beforeEach(() => { - mockedState.userLists = [userList]; - }); - - describe('success', () => { - beforeEach(() => { - Api.deleteFeatureFlagUserList.mockResolvedValue(); - }); - - it('should refresh the user lists', (done) => { - testAction( - deleteUserList, - userList, - mockedState, - [], - [{ type: 'requestDeleteUserList', payload: userList }, { type: 'fetchUserLists' }], - done, - ); - }); - }); - - describe('error', () => { - beforeEach(() => { - Api.deleteFeatureFlagUserList.mockRejectedValue({ response: { data: 'some error' } }); - }); - - it('should dispatch receiveDeleteUserListError', (done) => { - testAction( - deleteUserList, - userList, - mockedState, - [], - [ - { type: 'requestDeleteUserList', payload: userList }, - { - type: 'receiveDeleteUserListError', - payload: { list: userList, error: 'some error' }, - }, - ], - done, - ); - }); - }); - }); - - describe('receiveDeleteUserListError', () => { - it('should commit RECEIVE_DELETE_USER_LIST_ERROR with the given list', (done) => { - testAction( - receiveDeleteUserListError, - { list: userList, error: 'mock error' }, - mockedState, - [ - { - type: 'RECEIVE_DELETE_USER_LIST_ERROR', - payload: { list: userList, error: 'mock error' }, - }, - ], - [], - done, - ); - }); - }); describe('clearAlert', () => { it('should commit RECEIVE_CLEAR_ALERT', (done) => { diff --git a/spec/frontend/feature_flags/store/index/mutations_spec.js b/spec/frontend/feature_flags/store/index/mutations_spec.js index 08b5868d1b4..b9354196c68 100644 --- a/spec/frontend/feature_flags/store/index/mutations_spec.js +++ b/spec/frontend/feature_flags/store/index/mutations_spec.js @@ -3,7 +3,7 @@ import * as types from '~/feature_flags/store/index/mutation_types'; import mutations from '~/feature_flags/store/index/mutations'; import state from '~/feature_flags/store/index/state'; import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils'; -import { getRequestData, rotateData, featureFlag, userList } from '../../mock_data'; +import { getRequestData, rotateData, featureFlag } from '../../mock_data'; describe('Feature flags store Mutations', () => { let stateCopy; @@ -59,13 +59,11 @@ describe('Feature flags store Mutations', () => { }); it('should set count with the given data', () => { - expect(stateCopy.count.featureFlags).toEqual(37); + expect(stateCopy.count).toEqual(37); }); it('should set pagination', () => { - expect(stateCopy.pageInfo.featureFlags).toEqual( - parseIntPagination(normalizeHeaders(headers)), - ); + expect(stateCopy.pageInfo).toEqual(parseIntPagination(normalizeHeaders(headers))); }); }); @@ -83,58 +81,6 @@ describe('Feature flags store Mutations', () => { }); }); - describe('REQUEST_USER_LISTS', () => { - it('sets isLoading to true', () => { - mutations[types.REQUEST_USER_LISTS](stateCopy); - expect(stateCopy.isLoading).toBe(true); - }); - }); - - describe('RECEIVE_USER_LISTS_SUCCESS', () => { - const headers = { - 'x-next-page': '2', - 'x-page': '1', - 'X-Per-Page': '2', - 'X-Prev-Page': '', - 'X-TOTAL': '37', - 'X-Total-Pages': '5', - }; - - beforeEach(() => { - mutations[types.RECEIVE_USER_LISTS_SUCCESS](stateCopy, { data: [userList], headers }); - }); - - it('sets isLoading to false', () => { - expect(stateCopy.isLoading).toBe(false); - }); - - it('sets userLists to the received userLists', () => { - expect(stateCopy.userLists).toEqual([userList]); - }); - - it('sets pagination info for user lits', () => { - expect(stateCopy.pageInfo.userLists).toEqual(parseIntPagination(normalizeHeaders(headers))); - }); - - it('sets the count for user lists', () => { - expect(stateCopy.count.userLists).toBe(parseInt(headers['X-TOTAL'], 10)); - }); - }); - - describe('RECEIVE_USER_LISTS_ERROR', () => { - beforeEach(() => { - mutations[types.RECEIVE_USER_LISTS_ERROR](stateCopy); - }); - - it('should set isLoading to false', () => { - expect(stateCopy.isLoading).toEqual(false); - }); - - it('should set hasError to true', () => { - expect(stateCopy.hasError).toEqual(true); - }); - }); - describe('REQUEST_ROTATE_INSTANCE_ID', () => { beforeEach(() => { mutations[types.REQUEST_ROTATE_INSTANCE_ID](stateCopy); @@ -214,7 +160,7 @@ describe('Feature flags store Mutations', () => { ...flagState, scopes: mapToScopesViewModel(flag.scopes || []), })); - stateCopy.count.featureFlags = stateCount; + stateCopy.count = stateCount; mutations[types.RECEIVE_UPDATE_FEATURE_FLAG_SUCCESS](stateCopy, { ...featureFlag, @@ -241,8 +187,6 @@ describe('Feature flags store Mutations', () => { ...flag, scopes: mapToScopesViewModel(flag.scopes || []), })); - stateCopy.count = { enabled: 1, disabled: 0 }; - mutations[types.RECEIVE_UPDATE_FEATURE_FLAG_ERROR](stateCopy, featureFlag.id); }); @@ -257,36 +201,6 @@ describe('Feature flags store Mutations', () => { }); }); - describe('REQUEST_DELETE_USER_LIST', () => { - beforeEach(() => { - stateCopy.userLists = [userList]; - mutations[types.REQUEST_DELETE_USER_LIST](stateCopy, userList); - }); - - it('should remove the deleted list', () => { - expect(stateCopy.userLists).not.toContain(userList); - }); - }); - - describe('RECEIVE_DELETE_USER_LIST_ERROR', () => { - beforeEach(() => { - stateCopy.userLists = []; - mutations[types.RECEIVE_DELETE_USER_LIST_ERROR](stateCopy, { - list: userList, - error: 'some error', - }); - }); - - it('should set isLoading to false and hasError to false', () => { - expect(stateCopy.isLoading).toBe(false); - expect(stateCopy.hasError).toBe(false); - }); - - it('should add the user list back to the list of user lists', () => { - expect(stateCopy.userLists).toContain(userList); - }); - }); - describe('RECEIVE_CLEAR_ALERT', () => { it('clears the alert', () => { stateCopy.alerts = ['a server error']; -- cgit v1.2.3