diff options
Diffstat (limited to 'spec/frontend/admin')
8 files changed, 149 insertions, 56 deletions
diff --git a/spec/frontend/admin/analytics/devops_score/components/devops_score_callout_spec.js b/spec/frontend/admin/analytics/devops_score/components/devops_score_callout_spec.js new file mode 100644 index 00000000000..ee14e002f1b --- /dev/null +++ b/spec/frontend/admin/analytics/devops_score/components/devops_score_callout_spec.js @@ -0,0 +1,67 @@ +import { GlBanner } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import DevopsScoreCallout from '~/analytics/devops_report/components/devops_score_callout.vue'; +import { INTRO_COOKIE_KEY } from '~/analytics/devops_report/constants'; +import * as utils from '~/lib/utils/common_utils'; +import { devopsReportDocsPath, devopsScoreIntroImagePath } from '../mock_data'; + +describe('DevopsScoreCallout', () => { + let wrapper; + + const createComponent = () => { + wrapper = shallowMount(DevopsScoreCallout, { + provide: { + devopsReportDocsPath, + devopsScoreIntroImagePath, + }, + }); + }; + + const findBanner = () => wrapper.findComponent(GlBanner); + + afterEach(() => { + wrapper.destroy(); + }); + + describe('with no cookie set', () => { + beforeEach(() => { + utils.setCookie = jest.fn(); + + createComponent(); + }); + + it('displays the banner', () => { + expect(findBanner().exists()).toBe(true); + }); + + it('does not call setCookie', () => { + expect(utils.setCookie).not.toHaveBeenCalled(); + }); + + describe('when the close button is clicked', () => { + beforeEach(() => { + findBanner().vm.$emit('close'); + }); + + it('sets the dismissed cookie', () => { + expect(utils.setCookie).toHaveBeenCalledWith(INTRO_COOKIE_KEY, 'true'); + }); + + it('hides the banner', () => { + expect(findBanner().exists()).toBe(false); + }); + }); + }); + + describe('with the dismissed cookie set', () => { + beforeEach(() => { + jest.spyOn(utils, 'getCookie').mockReturnValue('true'); + + createComponent(); + }); + + it('hides the banner', () => { + expect(findBanner().exists()).toBe(false); + }); + }); +}); diff --git a/spec/frontend/admin/analytics/devops_score/components/devops_score_spec.js b/spec/frontend/admin/analytics/devops_score/components/devops_score_spec.js index 7c20bbe21c8..8f8dac977de 100644 --- a/spec/frontend/admin/analytics/devops_score/components/devops_score_spec.js +++ b/spec/frontend/admin/analytics/devops_score/components/devops_score_spec.js @@ -1,14 +1,10 @@ -import { GlTable, GlBadge, GlEmptyState, GlLink } from '@gitlab/ui'; +import { GlTable, GlBadge, GlEmptyState } from '@gitlab/ui'; import { GlSingleStat } from '@gitlab/ui/dist/charts'; import { mount } from '@vue/test-utils'; import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import DevopsScore from '~/analytics/devops_report/components/devops_score.vue'; -import { - devopsScoreMetricsData, - devopsReportDocsPath, - noDataImagePath, - devopsScoreTableHeaders, -} from '../mock_data'; +import DevopsScoreCallout from '~/analytics/devops_report/components/devops_score_callout.vue'; +import { devopsScoreMetricsData, noDataImagePath, devopsScoreTableHeaders } from '../mock_data'; describe('DevopsScore', () => { let wrapper; @@ -18,7 +14,6 @@ describe('DevopsScore', () => { mount(DevopsScore, { provide: { devopsScoreMetrics, - devopsReportDocsPath, noDataImagePath, }, }), @@ -30,12 +25,19 @@ describe('DevopsScore', () => { const findCol = (testId) => findTable().find(`[data-testid="${testId}"]`); const findUsageCol = () => findCol('usageCol'); const findDevopsScoreApp = () => wrapper.findByTestId('devops-score-app'); + const bannerExists = () => wrapper.findComponent(DevopsScoreCallout).exists(); + const findDocsLink = () => + wrapper.findByRole('link', { name: 'See example DevOps Score page in our documentation.' }); describe('with no data', () => { beforeEach(() => { createComponent({ devopsScoreMetrics: {} }); }); + it('includes the DevopsScoreCallout component ', () => { + expect(bannerExists()).toBe(true); + }); + describe('empty state', () => { it('displays the empty state', () => { expect(findEmptyState().exists()).toBe(true); @@ -48,7 +50,10 @@ describe('DevopsScore', () => { }); it('contains a link to the feature documentation', () => { - expect(wrapper.findComponent(GlLink).exists()).toBe(true); + expect(findDocsLink().exists()).toBe(true); + expect(findDocsLink().attributes('href')).toBe( + '/help/user/admin_area/analytics/dev_ops_report', + ); }); }); @@ -62,6 +67,10 @@ describe('DevopsScore', () => { createComponent(); }); + it('includes the DevopsScoreCallout component ', () => { + expect(bannerExists()).toBe(true); + }); + it('does not display the empty state', () => { expect(findEmptyState().exists()).toBe(false); }); diff --git a/spec/frontend/admin/analytics/devops_score/mock_data.js b/spec/frontend/admin/analytics/devops_score/mock_data.js index ae0c01a2661..e8f8b778ffa 100644 --- a/spec/frontend/admin/analytics/devops_score/mock_data.js +++ b/spec/frontend/admin/analytics/devops_score/mock_data.js @@ -44,3 +44,5 @@ export const devopsScoreMetricsData = { export const devopsReportDocsPath = 'docs-path'; export const noDataImagePath = 'image-path'; + +export const devopsScoreIntroImagePath = 'image-path'; diff --git a/spec/frontend/admin/signup_restrictions/components/signup_form_spec.js b/spec/frontend/admin/signup_restrictions/components/signup_form_spec.js index 18339164d5a..4bb22feb913 100644 --- a/spec/frontend/admin/signup_restrictions/components/signup_form_spec.js +++ b/spec/frontend/admin/signup_restrictions/components/signup_form_spec.js @@ -192,22 +192,27 @@ describe('Signup Form', () => { describe('form submit button confirmation modal for side-effect of adding possibly unwanted new users', () => { it.each` - requireAdminApprovalAction | userCapAction | buttonEffect - ${'unchanged from true'} | ${'unchanged'} | ${'submits form'} - ${'unchanged from false'} | ${'unchanged'} | ${'submits form'} - ${'toggled off'} | ${'unchanged'} | ${'shows confirmation modal'} - ${'toggled on'} | ${'unchanged'} | ${'submits form'} - ${'unchanged from false'} | ${'increased'} | ${'shows confirmation modal'} - ${'unchanged from true'} | ${'increased'} | ${'shows confirmation modal'} - ${'toggled off'} | ${'increased'} | ${'shows confirmation modal'} - ${'toggled on'} | ${'increased'} | ${'shows confirmation modal'} - ${'toggled on'} | ${'decreased'} | ${'submits form'} - ${'unchanged from false'} | ${'changed from limited to unlimited'} | ${'shows confirmation modal'} - ${'unchanged from false'} | ${'changed from unlimited to limited'} | ${'submits form'} - ${'unchanged from false'} | ${'unchanged from unlimited'} | ${'submits form'} + requireAdminApprovalAction | userCapAction | pendingUserCount | buttonEffect + ${'unchanged from true'} | ${'unchanged'} | ${0} | ${'submits form'} + ${'unchanged from false'} | ${'unchanged'} | ${0} | ${'submits form'} + ${'toggled off'} | ${'unchanged'} | ${1} | ${'shows confirmation modal'} + ${'toggled off'} | ${'unchanged'} | ${0} | ${'submits form'} + ${'toggled on'} | ${'unchanged'} | ${0} | ${'submits form'} + ${'unchanged from false'} | ${'increased'} | ${1} | ${'shows confirmation modal'} + ${'unchanged from true'} | ${'increased'} | ${0} | ${'submits form'} + ${'toggled off'} | ${'increased'} | ${1} | ${'shows confirmation modal'} + ${'toggled off'} | ${'increased'} | ${0} | ${'submits form'} + ${'toggled on'} | ${'increased'} | ${1} | ${'shows confirmation modal'} + ${'toggled on'} | ${'increased'} | ${0} | ${'submits form'} + ${'toggled on'} | ${'decreased'} | ${0} | ${'submits form'} + ${'toggled on'} | ${'decreased'} | ${1} | ${'submits form'} + ${'unchanged from false'} | ${'changed from limited to unlimited'} | ${1} | ${'shows confirmation modal'} + ${'unchanged from false'} | ${'changed from limited to unlimited'} | ${0} | ${'submits form'} + ${'unchanged from false'} | ${'changed from unlimited to limited'} | ${0} | ${'submits form'} + ${'unchanged from false'} | ${'unchanged from unlimited'} | ${0} | ${'submits form'} `( - '$buttonEffect if require admin approval for new sign-ups is $requireAdminApprovalAction and the user cap is $userCapAction', - async ({ requireAdminApprovalAction, userCapAction, buttonEffect }) => { + '$buttonEffect if require admin approval for new sign-ups is $requireAdminApprovalAction and the user cap is $userCapAction and pending user count is $pendingUserCount', + async ({ requireAdminApprovalAction, userCapAction, pendingUserCount, buttonEffect }) => { let isModalDisplayed; switch (buttonEffect) { @@ -224,7 +229,9 @@ describe('Signup Form', () => { const isFormSubmittedWhenClickingFormSubmitButton = !isModalDisplayed; - const injectedProps = {}; + const injectedProps = { + pendingUserCount, + }; const USER_CAP_DEFAULT = 5; @@ -310,6 +317,7 @@ describe('Signup Form', () => { await mountComponent({ injectedProps: { newUserSignupsCap: INITIAL_USER_CAP, + pendingUserCount: 5, }, stubs: { GlButton, GlModal: stubComponent(GlModal) }, }); diff --git a/spec/frontend/admin/signup_restrictions/mock_data.js b/spec/frontend/admin/signup_restrictions/mock_data.js index 624a5614c9c..135fc8caae0 100644 --- a/spec/frontend/admin/signup_restrictions/mock_data.js +++ b/spec/frontend/admin/signup_restrictions/mock_data.js @@ -17,6 +17,7 @@ export const rawMockData = { supportedSyntaxLinkUrl: '/supported/syntax/link', emailRestrictions: 'user1@domain.com, user2@domain.com', afterSignUpText: 'Congratulations on your successful sign-up!', + pendingUserCount: '0', }; export const mockData = { @@ -38,4 +39,5 @@ export const mockData = { supportedSyntaxLinkUrl: '/supported/syntax/link', emailRestrictions: 'user1@domain.com, user2@domain.com', afterSignUpText: 'Congratulations on your successful sign-up!', + pendingUserCount: '0', }; diff --git a/spec/frontend/admin/users/components/actions/actions_spec.js b/spec/frontend/admin/users/components/actions/actions_spec.js index 67d9bac8580..fd05b08a3fb 100644 --- a/spec/frontend/admin/users/components/actions/actions_spec.js +++ b/spec/frontend/admin/users/components/actions/actions_spec.js @@ -5,8 +5,8 @@ import { nextTick } from 'vue'; import Actions from '~/admin/users/components/actions'; import SharedDeleteAction from '~/admin/users/components/actions/shared/shared_delete_action.vue'; import { capitalizeFirstCharacter } from '~/lib/utils/text_utility'; - import { CONFIRMATION_ACTIONS, DELETE_ACTIONS } from '../../constants'; +import { paths } from '../../mock_data'; describe('Action components', () => { let wrapper; @@ -47,32 +47,33 @@ describe('Action components', () => { describe('DELETE_ACTION_COMPONENTS', () => { const oncallSchedules = [{ name: 'schedule1' }, { name: 'schedule2' }]; - it.each(DELETE_ACTIONS)('renders a dropdown item for "%s"', async (action) => { - initComponent({ - component: Actions[capitalizeFirstCharacter(action)], - props: { - username: 'John Doe', - paths: { - delete: '/delete', - block: '/block', + + it.each(DELETE_ACTIONS.map((action) => [action, paths[action]]))( + 'renders a dropdown item for "%s"', + async (action, expectedPath) => { + initComponent({ + component: Actions[capitalizeFirstCharacter(action)], + props: { + username: 'John Doe', + paths, + oncallSchedules, }, - oncallSchedules, - }, - stubs: { SharedDeleteAction }, - }); + stubs: { SharedDeleteAction }, + }); - await nextTick(); + await nextTick(); - const sharedAction = wrapper.find(SharedDeleteAction); + const sharedAction = wrapper.find(SharedDeleteAction); - expect(sharedAction.attributes('data-block-user-url')).toBe('/block'); - expect(sharedAction.attributes('data-delete-user-url')).toBe('/delete'); - expect(sharedAction.attributes('data-gl-modal-action')).toBe(kebabCase(action)); - expect(sharedAction.attributes('data-username')).toBe('John Doe'); - expect(sharedAction.attributes('data-oncall-schedules')).toBe( - JSON.stringify(oncallSchedules), - ); - expect(findDropdownItem().exists()).toBe(true); - }); + expect(sharedAction.attributes('data-block-user-url')).toBe(paths.block); + expect(sharedAction.attributes('data-delete-user-url')).toBe(expectedPath); + expect(sharedAction.attributes('data-gl-modal-action')).toBe(kebabCase(action)); + expect(sharedAction.attributes('data-username')).toBe('John Doe'); + expect(sharedAction.attributes('data-oncall-schedules')).toBe( + JSON.stringify(oncallSchedules), + ); + expect(findDropdownItem().exists()).toBe(true); + }, + ); }); }); diff --git a/spec/frontend/admin/users/components/user_date_spec.js b/spec/frontend/admin/users/components/user_date_spec.js index 1a2f2938db5..af262c6d3f0 100644 --- a/spec/frontend/admin/users/components/user_date_spec.js +++ b/spec/frontend/admin/users/components/user_date_spec.js @@ -1,6 +1,7 @@ import { shallowMount } from '@vue/test-utils'; import UserDate from '~/vue_shared/components/user_date.vue'; +import { ISO_SHORT_FORMAT } from '~/vue_shared/constants'; import { users } from '../mock_data'; const mockDate = users[0].createdAt; @@ -22,12 +23,15 @@ describe('FormatDate component', () => { }); it.each` - date | output - ${mockDate} | ${'13 Nov, 2020'} - ${null} | ${'Never'} - ${undefined} | ${'Never'} - `('renders $date as $output', ({ date, output }) => { - initComponent({ date }); + date | dateFormat | output + ${mockDate} | ${undefined} | ${'13 Nov, 2020'} + ${null} | ${undefined} | ${'Never'} + ${undefined} | ${undefined} | ${'Never'} + ${mockDate} | ${ISO_SHORT_FORMAT} | ${'2020-11-13'} + ${null} | ${ISO_SHORT_FORMAT} | ${'Never'} + ${undefined} | ${ISO_SHORT_FORMAT} | ${'Never'} + `('renders $date as $output', ({ date, dateFormat, output }) => { + initComponent({ date, dateFormat }); expect(wrapper.text()).toBe(output); }); diff --git a/spec/frontend/admin/users/mock_data.js b/spec/frontend/admin/users/mock_data.js index ded3e6f7edf..73fa73c0b47 100644 --- a/spec/frontend/admin/users/mock_data.js +++ b/spec/frontend/admin/users/mock_data.js @@ -30,7 +30,7 @@ export const paths = { activate: '/admin/users/id/activate', unlock: '/admin/users/id/unlock', delete: '/admin/users/id', - deleteWithContributions: '/admin/users/id', + deleteWithContributions: '/admin/users/id?hard_delete=true', adminUser: '/admin/users/id', ban: '/admin/users/id/ban', unban: '/admin/users/id/unban', |