diff options
Diffstat (limited to 'spec/frontend/projects')
13 files changed, 232 insertions, 303 deletions
diff --git a/spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap b/spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap index 736d149f06d..974650a2c7c 100644 --- a/spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap +++ b/spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap @@ -19,6 +19,7 @@ exports[`Project remove modal initialized matches the snapshot 1`] = ` <gl-button-stub buttontextclasses="" category="primary" + data-qa-selector="delete_button" icon="" role="button" size="medium" @@ -102,6 +103,7 @@ exports[`Project remove modal initialized matches the snapshot 1`] = ` </p> <gl-form-input-stub + data-qa-selector="confirm_name_field" id="confirm_name_input" name="confirm_name_input" type="text" diff --git a/spec/frontend/projects/components/shared/__snapshots__/delete_button_spec.js.snap b/spec/frontend/projects/components/shared/__snapshots__/delete_button_spec.js.snap index 26495fbcf83..ac020fe6915 100644 --- a/spec/frontend/projects/components/shared/__snapshots__/delete_button_spec.js.snap +++ b/spec/frontend/projects/components/shared/__snapshots__/delete_button_spec.js.snap @@ -20,6 +20,7 @@ exports[`Project remove modal intialized matches the snapshot 1`] = ` <gl-button-stub buttontextclasses="" category="primary" + data-qa-selector="delete_button" icon="" role="button" size="medium" @@ -103,6 +104,7 @@ exports[`Project remove modal intialized matches the snapshot 1`] = ` </p> <gl-form-input-stub + data-qa-selector="confirm_name_field" id="confirm_name_input" name="confirm_name_input" type="text" diff --git a/spec/frontend/projects/new/components/new_project_push_tip_popover_spec.js b/spec/frontend/projects/new/components/new_project_push_tip_popover_spec.js index f50dd393174..16b4493c622 100644 --- a/spec/frontend/projects/new/components/new_project_push_tip_popover_spec.js +++ b/spec/frontend/projects/new/components/new_project_push_tip_popover_spec.js @@ -71,7 +71,7 @@ describe('New project push tip popover', () => { it('displays a link to open the push command help page reference', () => { expect(findHelpLink().attributes().href).toBe( - `${workingWithProjectsHelpPath}#push-to-create-a-new-project`, + `${workingWithProjectsHelpPath}#create-a-new-project-with-git-push`, ); }); }); diff --git a/spec/frontend/projects/pipelines/charts/components/app_spec.js b/spec/frontend/projects/pipelines/charts/components/app_spec.js index e3aaf760d1e..d8876349c5e 100644 --- a/spec/frontend/projects/pipelines/charts/components/app_spec.js +++ b/spec/frontend/projects/pipelines/charts/components/app_spec.js @@ -8,6 +8,12 @@ import { mergeUrlParams, updateHistory, getParameterValues } from '~/lib/utils/u import Component from '~/projects/pipelines/charts/components/app.vue'; import PipelineCharts from '~/projects/pipelines/charts/components/pipeline_charts.vue'; import API from '~/api'; +import { mockTracking } from 'helpers/tracking_helper'; +import { + SNOWPLOW_DATA_SOURCE, + SNOWPLOW_LABEL, + SNOWPLOW_SCHEMA, +} from '~/projects/pipelines/charts/constants'; jest.mock('~/lib/utils/url_utility'); @@ -125,21 +131,59 @@ describe('ProjectsPipelinesChartsApp', () => { }); describe('event tracking', () => { - it.each` - testId | event - ${'pipelines-tab'} | ${'p_analytics_ci_cd_pipelines'} - ${'deployment-frequency-tab'} | ${'p_analytics_ci_cd_deployment_frequency'} - ${'lead-time-tab'} | ${'p_analytics_ci_cd_lead_time'} - ${'time-to-restore-service-tab'} | ${'p_analytics_ci_cd_time_to_restore_service'} - ${'change-failure-rate-tab'} | ${'p_analytics_ci_cd_change_failure_rate'} - `('tracks the $event event when clicked', ({ testId, event }) => { - jest.spyOn(API, 'trackRedisHllUserEvent'); + describe('RedisHLL events', () => { + it.each` + testId | event + ${'pipelines-tab'} | ${'p_analytics_ci_cd_pipelines'} + ${'deployment-frequency-tab'} | ${'p_analytics_ci_cd_deployment_frequency'} + ${'lead-time-tab'} | ${'p_analytics_ci_cd_lead_time'} + ${'time-to-restore-service-tab'} | ${'p_analytics_ci_cd_time_to_restore_service'} + ${'change-failure-rate-tab'} | ${'p_analytics_ci_cd_change_failure_rate'} + `('tracks the $event event when clicked', ({ testId, event }) => { + const trackApiSpy = jest.spyOn(API, 'trackRedisHllUserEvent'); + + expect(trackApiSpy).not.toHaveBeenCalled(); + + wrapper.findByTestId(testId).vm.$emit('click'); + + expect(trackApiSpy).toHaveBeenCalledWith(event); + }); + }); - expect(API.trackRedisHllUserEvent).not.toHaveBeenCalled(); + describe('Snowplow events', () => { + it.each` + testId | event + ${'pipelines-tab'} | ${'p_analytics_ci_cd_pipelines'} + ${'deployment-frequency-tab'} | ${'p_analytics_ci_cd_deployment_frequency'} + ${'lead-time-tab'} | ${'p_analytics_ci_cd_lead_time'} + `('tracks the $event event when clicked', ({ testId, event }) => { + const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn); + + wrapper.findByTestId(testId).vm.$emit('click'); + + expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_tab', { + label: SNOWPLOW_LABEL, + context: { + schema: SNOWPLOW_SCHEMA, + data: { + event_name: event, + data_source: SNOWPLOW_DATA_SOURCE, + }, + }, + }); + }); - wrapper.findByTestId(testId).vm.$emit('click'); + it.each` + tab + ${'time-to-restore-service-tab'} + ${'change-failure-rate-tab'} + `('does not track when tab $tab is clicked', ({ tab }) => { + const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn); - expect(API.trackRedisHllUserEvent).toHaveBeenCalledWith(event); + wrapper.findByTestId(tab).vm.$emit('click'); + + expect(trackingSpy).not.toHaveBeenCalled(); + }); }); }); }); diff --git a/spec/frontend/projects/settings/branch_rules/components/view/index_spec.js b/spec/frontend/projects/settings/branch_rules/components/view/index_spec.js index bf4026b65db..27065a704e2 100644 --- a/spec/frontend/projects/settings/branch_rules/components/view/index_spec.js +++ b/spec/frontend/projects/settings/branch_rules/components/view/index_spec.js @@ -12,7 +12,11 @@ import { import Protection from '~/projects/settings/branch_rules/components/view/protection.vue'; import branchRulesQuery from '~/projects/settings/branch_rules/queries/branch_rules_details.query.graphql'; import { sprintf } from '~/locale'; -import { branchProtectionsMockResponse } from './mock_data'; +import { + branchProtectionsMockResponse, + approvalRulesMock, + statusChecksRulesMock, +} from './mock_data'; jest.mock('~/lib/utils/url_utility', () => ({ getParameterByName: jest.fn().mockReturnValue('main'), @@ -34,6 +38,7 @@ describe('View branch rules', () => { const projectPath = 'test/testing'; const protectedBranchesPath = 'protected/branches'; const approvalRulesPath = 'approval/rules'; + const statusChecksPath = 'status/checks'; const branchProtectionsMockRequestHandler = jest .fn() .mockResolvedValue(branchProtectionsMockResponse); @@ -43,7 +48,7 @@ describe('View branch rules', () => { wrapper = shallowMountExtended(RuleView, { apolloProvider: fakeApollo, - provide: { projectPath, protectedBranchesPath, approvalRulesPath }, + provide: { projectPath, protectedBranchesPath, approvalRulesPath, statusChecksPath }, }); await waitForPromises(); @@ -59,6 +64,7 @@ describe('View branch rules', () => { const findBranchProtections = () => wrapper.findAllComponents(Protection); const findForcePushTitle = () => wrapper.findByText(I18N.allowForcePushDescription); const findApprovalsTitle = () => wrapper.findByText(I18N.approvalsTitle); + const findStatusChecksTitle = () => wrapper.findByText(I18N.statusChecksTitle); it('gets the branch param from url and renders it in the view', () => { expect(util.getParameterByName).toHaveBeenCalledWith('branch'); @@ -105,9 +111,21 @@ describe('View branch rules', () => { expect(findApprovalsTitle().exists()).toBe(true); expect(findBranchProtections().at(2).props()).toMatchObject({ - header: sprintf(I18N.approvalsHeader, { total: 0 }), + header: sprintf(I18N.approvalsHeader, { total: 3 }), headerLinkHref: approvalRulesPath, headerLinkTitle: I18N.manageApprovalsLinkTitle, + approvals: approvalRulesMock, + }); + }); + + it('renders a branch protection component for status checks', () => { + expect(findStatusChecksTitle().exists()).toBe(true); + + expect(findBranchProtections().at(3).props()).toMatchObject({ + header: sprintf(I18N.statusChecksHeader, { total: 2 }), + headerLinkHref: statusChecksPath, + headerLinkTitle: I18N.statusChecksLinkTitle, + statusChecks: statusChecksRulesMock, }); }); }); diff --git a/spec/frontend/projects/settings/branch_rules/components/view/mock_data.js b/spec/frontend/projects/settings/branch_rules/components/view/mock_data.js index c3f573061da..c07d4673344 100644 --- a/spec/frontend/projects/settings/branch_rules/components/view/mock_data.js +++ b/spec/frontend/projects/settings/branch_rules/components/view/mock_data.js @@ -1,29 +1,34 @@ const usersMock = [ { + id: '123', username: 'usr1', webUrl: 'http://test.test/usr1', name: 'User 1', avatarUrl: 'http://test.test/avt1.png', }, { + id: '456', username: 'usr2', webUrl: 'http://test.test/usr2', name: 'User 2', avatarUrl: 'http://test.test/avt2.png', }, { + id: '789', username: 'usr3', webUrl: 'http://test.test/usr3', name: 'User 3', avatarUrl: 'http://test.test/avt3.png', }, { + id: '987', username: 'usr4', webUrl: 'http://test.test/usr4', name: 'User 4', avatarUrl: 'http://test.test/avt4.png', }, { + id: '654', username: 'usr5', webUrl: 'http://test.test/usr5', name: 'User 5', @@ -40,6 +45,22 @@ const approvalsRequired = 3; const groupsMock = [{ name: 'test_group_1' }, { name: 'test_group_2' }]; +export const approvalRulesMock = [ + { + __typename: 'ApprovalProjectRule', + id: '123', + name: 'test', + type: 'REGULAR', + eligibleApprovers: { nodes: usersMock }, + approvalsRequired, + }, +]; + +export const statusChecksRulesMock = [ + { __typename: 'StatusCheckRule', id: '123', name: 'test', externalUrl: 'https://test.test' }, + { __typename: 'StatusCheckRule', id: '456', name: 'test 2', externalUrl: 'https://test2.test2' }, +]; + export const protectionPropsMock = { header: 'Test protection', headerLinkTitle: 'Test link title', @@ -47,13 +68,8 @@ export const protectionPropsMock = { roles: accessLevelsMock, users: usersMock, groups: groupsMock, - approvals: [ - { - name: 'test', - eligibleApprovers: { nodes: usersMock }, - approvalsRequired, - }, - ], + approvals: approvalRulesMock, + statusChecks: statusChecksRulesMock, }; export const protectionRowPropsMock = { @@ -61,6 +77,7 @@ export const protectionRowPropsMock = { users: usersMock, accessLevels: accessLevelsMock, approvalsRequired, + statusCheckUrl: statusChecksRulesMock[0].externalUrl, }; export const accessLevelsMockResponse = [ @@ -116,6 +133,14 @@ export const branchProtectionsMockResponse = { edges: accessLevelsMockResponse, }, }, + approvalRules: { + __typename: 'ApprovalProjectRuleConnection', + nodes: approvalRulesMock, + }, + externalStatusChecks: { + __typename: 'ExternalStatusCheckConnection', + nodes: statusChecksRulesMock, + }, }, { __typename: 'BranchRule', @@ -133,6 +158,14 @@ export const branchProtectionsMockResponse = { edges: [], }, }, + approvalRules: { + __typename: 'ApprovalProjectRuleConnection', + nodes: [], + }, + externalStatusChecks: { + __typename: 'ExternalStatusCheckConnection', + nodes: [], + }, }, ], }, diff --git a/spec/frontend/projects/settings/branch_rules/components/view/protection_row_spec.js b/spec/frontend/projects/settings/branch_rules/components/view/protection_row_spec.js index b0a69bedd3e..a98b156f94e 100644 --- a/spec/frontend/projects/settings/branch_rules/components/view/protection_row_spec.js +++ b/spec/frontend/projects/settings/branch_rules/components/view/protection_row_spec.js @@ -27,6 +27,7 @@ describe('Branch rule protection row', () => { const findAccessLevels = () => wrapper.findAllByTestId('access-level'); const findApprovalsRequired = () => wrapper.findByText(`${protectionRowPropsMock.approvalsRequired} approvals required`); + const findStatusChecksUrl = () => wrapper.findByText(protectionRowPropsMock.statusCheckUrl); it('renders a title', () => { expect(findTitle().exists()).toBe(true); @@ -68,4 +69,8 @@ describe('Branch rule protection row', () => { it('renders the number of approvals required', () => { expect(findApprovalsRequired().exists()).toBe(true); }); + + it('renders status checks URL', () => { + expect(findStatusChecksUrl().exists()).toBe(true); + }); }); diff --git a/spec/frontend/projects/settings/branch_rules/components/view/protection_spec.js b/spec/frontend/projects/settings/branch_rules/components/view/protection_spec.js index e2fbb4f5bbb..caf967b4257 100644 --- a/spec/frontend/projects/settings/branch_rules/components/view/protection_spec.js +++ b/spec/frontend/projects/settings/branch_rules/components/view/protection_spec.js @@ -65,4 +65,15 @@ describe('Branch rule protection', () => { approvalsRequired: approval.approvalsRequired, }); }); + + it('renders a protection row for status checks', () => { + const statusCheck = protectionPropsMock.statusChecks[0]; + expect(findProtectionRows().at(4).props()).toMatchObject({ + title: statusCheck.name, + showDivider: false, + statusCheckUrl: statusCheck.externalUrl, + }); + + expect(findProtectionRows().at(5).props('showDivider')).toBe(true); + }); }); diff --git a/spec/frontend/projects/settings/components/transfer_project_form_spec.js b/spec/frontend/projects/settings/components/transfer_project_form_spec.js index 6e639f895a8..e091f3e25c3 100644 --- a/spec/frontend/projects/settings/components/transfer_project_form_spec.js +++ b/spec/frontend/projects/settings/components/transfer_project_form_spec.js @@ -1,18 +1,9 @@ -import Vue, { nextTick } from 'vue'; -import { GlAlert } from '@gitlab/ui'; -import VueApollo from 'vue-apollo'; -import currentUserNamespaceQueryResponse from 'test_fixtures/graphql/projects/settings/current_user_namespace.query.graphql.json'; import transferLocationsResponsePage1 from 'test_fixtures/api/projects/transfer_locations_page_1.json'; -import transferLocationsResponsePage2 from 'test_fixtures/api/projects/transfer_locations_page_2.json'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import createMockApollo from 'helpers/mock_apollo_helper'; -import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import TransferProjectForm from '~/projects/settings/components/transfer_project_form.vue'; -import NamespaceSelect from '~/vue_shared/components/namespace_select/namespace_select_deprecated.vue'; +import TransferLocations from '~/groups_projects/components/transfer_locations.vue'; import ConfirmDanger from '~/vue_shared/components/confirm_danger/confirm_danger.vue'; -import currentUserNamespaceQuery from '~/projects/settings/graphql/queries/current_user_namespace.query.graphql'; import { getTransferLocations } from '~/api/projects_api'; -import waitForPromises from 'helpers/wait_for_promises'; jest.mock('~/api/projects_api', () => ({ getTransferLocations: jest.fn(), @@ -21,68 +12,36 @@ jest.mock('~/api/projects_api', () => ({ describe('Transfer project form', () => { let wrapper; - const projectId = '1'; + const resourceId = '1'; const confirmButtonText = 'Confirm'; const confirmationPhrase = 'You must construct additional pylons!'; - Vue.use(VueApollo); - - const defaultQueryHandler = jest.fn().mockResolvedValue(currentUserNamespaceQueryResponse); - const mockResolvedGetTransferLocations = ({ - data = transferLocationsResponsePage1, - page = '1', - nextPage = '2', - prevPage = null, - } = {}) => { - getTransferLocations.mockResolvedValueOnce({ - data, - headers: { - 'x-per-page': '2', - 'x-page': page, - 'x-total': '4', - 'x-total-pages': '2', - 'x-next-page': nextPage, - 'x-prev-page': prevPage, - }, - }); - }; - const mockRejectedGetTransferLocations = () => { - const error = new Error(); - - getTransferLocations.mockRejectedValueOnce(error); - }; - - const createComponent = ({ - requestHandlers = [[currentUserNamespaceQuery, defaultQueryHandler]], - } = {}) => { + const createComponent = () => { wrapper = shallowMountExtended(TransferProjectForm, { provide: { - projectId, + resourceId, }, propsData: { confirmButtonText, confirmationPhrase, }, - apolloProvider: createMockApollo(requestHandlers), }); }; - const findNamespaceSelect = () => wrapper.findComponent(NamespaceSelect); - const showNamespaceSelect = async () => { - findNamespaceSelect().vm.$emit('show'); - await waitForPromises(); - }; + const findTransferLocations = () => wrapper.findComponent(TransferLocations); const findConfirmDanger = () => wrapper.findComponent(ConfirmDanger); - const findAlert = () => wrapper.findComponent(GlAlert); afterEach(() => { wrapper.destroy(); }); - it('renders the namespace selector', () => { + it('renders the namespace selector and passes `groupTransferLocationsApiMethod` prop', () => { createComponent(); - expect(findNamespaceSelect().exists()).toBe(true); + expect(findTransferLocations().exists()).toBe(true); + + findTransferLocations().props('groupTransferLocationsApiMethod')(); + expect(getTransferLocations).toHaveBeenCalled(); }); it('renders the confirm button', () => { @@ -100,220 +59,29 @@ describe('Transfer project form', () => { describe('with a selected namespace', () => { const [selectedItem] = transferLocationsResponsePage1; - const arrange = async () => { - mockResolvedGetTransferLocations(); + beforeEach(() => { createComponent(); - await showNamespaceSelect(); - findNamespaceSelect().vm.$emit('select', selectedItem); - }; + findTransferLocations().vm.$emit('input', selectedItem); + }); - it('emits the `selectNamespace` event when a namespace is selected', async () => { - await arrange(); + it('sets `value` prop on `TransferLocations` component', () => { + expect(findTransferLocations().props('value')).toEqual(selectedItem); + }); + it('emits the `selectTransferLocation` event when a namespace is selected', async () => { const args = [selectedItem.id]; - expect(wrapper.emitted('selectNamespace')).toEqual([args]); + expect(wrapper.emitted('selectTransferLocation')).toEqual([args]); }); it('enables the confirm button', async () => { - await arrange(); - expect(findConfirmDanger().attributes('disabled')).toBeUndefined(); }); it('clicking the confirm button emits the `confirm` event', async () => { - await arrange(); - findConfirmDanger().vm.$emit('confirm'); expect(wrapper.emitted('confirm')).toBeDefined(); }); }); - - describe('when `NamespaceSelect` is opened', () => { - it('fetches user and group namespaces and passes correct props to `NamespaceSelect` component', async () => { - mockResolvedGetTransferLocations(); - createComponent(); - await showNamespaceSelect(); - - const { namespace } = currentUserNamespaceQueryResponse.data.currentUser; - - expect(findNamespaceSelect().props()).toMatchObject({ - userNamespaces: [ - { - id: getIdFromGraphQLId(namespace.id), - humanName: namespace.fullName, - }, - ], - groupNamespaces: transferLocationsResponsePage1.map(({ id, full_name: humanName }) => ({ - id, - humanName, - })), - hasNextPageOfGroups: true, - isLoading: false, - isSearchLoading: false, - shouldFilterNamespaces: false, - }); - }); - - describe('when namespaces have already been fetched', () => { - beforeEach(async () => { - mockResolvedGetTransferLocations(); - createComponent(); - await showNamespaceSelect(); - }); - - it('does not fetch namespaces', async () => { - getTransferLocations.mockClear(); - defaultQueryHandler.mockClear(); - - await showNamespaceSelect(); - - expect(getTransferLocations).not.toHaveBeenCalled(); - expect(defaultQueryHandler).not.toHaveBeenCalled(); - }); - }); - - describe('when `getTransferLocations` API call fails', () => { - it('displays error alert', async () => { - mockRejectedGetTransferLocations(); - createComponent(); - await showNamespaceSelect(); - - expect(findAlert().exists()).toBe(true); - }); - }); - - describe('when `currentUser` GraphQL query fails', () => { - it('displays error alert', async () => { - mockResolvedGetTransferLocations(); - const error = new Error(); - createComponent({ - requestHandlers: [[currentUserNamespaceQuery, jest.fn().mockRejectedValueOnce(error)]], - }); - await showNamespaceSelect(); - - expect(findAlert().exists()).toBe(true); - }); - }); - }); - - describe('when `search` event is fired', () => { - const arrange = async () => { - mockResolvedGetTransferLocations(); - createComponent(); - await showNamespaceSelect(); - mockResolvedGetTransferLocations(); - findNamespaceSelect().vm.$emit('search', 'foo'); - await nextTick(); - }; - - it('sets `isSearchLoading` prop to `true`', async () => { - await arrange(); - - expect(findNamespaceSelect().props('isSearchLoading')).toBe(true); - }); - - it('passes `search` param to API call', async () => { - await arrange(); - - await waitForPromises(); - - expect(getTransferLocations).toHaveBeenCalledWith( - projectId, - expect.objectContaining({ search: 'foo' }), - ); - }); - - describe('when `getTransferLocations` API call fails', () => { - it('displays dismissible error alert', async () => { - mockResolvedGetTransferLocations(); - createComponent(); - await showNamespaceSelect(); - mockRejectedGetTransferLocations(); - findNamespaceSelect().vm.$emit('search', 'foo'); - await waitForPromises(); - - const alert = findAlert(); - - expect(alert.exists()).toBe(true); - - alert.vm.$emit('dismiss'); - await nextTick(); - - expect(alert.exists()).toBe(false); - }); - }); - }); - - describe('when `load-more-groups` event is fired', () => { - const arrange = async () => { - mockResolvedGetTransferLocations(); - createComponent(); - await showNamespaceSelect(); - - mockResolvedGetTransferLocations({ - data: transferLocationsResponsePage2, - page: '2', - nextPage: null, - prevPage: '1', - }); - - findNamespaceSelect().vm.$emit('load-more-groups'); - await nextTick(); - }; - - it('sets `isLoading` prop to `true`', async () => { - await arrange(); - - expect(findNamespaceSelect().props('isLoading')).toBe(true); - }); - - it('passes `page` param to API call', async () => { - await arrange(); - - await waitForPromises(); - - expect(getTransferLocations).toHaveBeenCalledWith( - projectId, - expect.objectContaining({ page: 2 }), - ); - }); - - it('updates `groupNamespaces` prop with new groups', async () => { - await arrange(); - - await waitForPromises(); - - expect(findNamespaceSelect().props('groupNamespaces')).toMatchObject( - [...transferLocationsResponsePage1, ...transferLocationsResponsePage2].map( - ({ id, full_name: humanName }) => ({ - id, - humanName, - }), - ), - ); - }); - - it('updates `hasNextPageOfGroups` prop', async () => { - await arrange(); - - await waitForPromises(); - - expect(findNamespaceSelect().props('hasNextPageOfGroups')).toBe(false); - }); - - describe('when `getTransferLocations` API call fails', () => { - it('displays error alert', async () => { - mockResolvedGetTransferLocations(); - createComponent(); - await showNamespaceSelect(); - mockRejectedGetTransferLocations(); - findNamespaceSelect().vm.$emit('load-more-groups'); - await waitForPromises(); - - expect(findAlert().exists()).toBe(true); - }); - }); - }); }); diff --git a/spec/frontend/projects/settings/repository/branch_rules/app_spec.js b/spec/frontend/projects/settings/repository/branch_rules/app_spec.js index 4603436c40a..6369f04781f 100644 --- a/spec/frontend/projects/settings/repository/branch_rules/app_spec.js +++ b/spec/frontend/projects/settings/repository/branch_rules/app_spec.js @@ -52,6 +52,10 @@ describe('Branch rules app', () => { expect(findAllBranchRules().at(0).props('name')).toBe(nodes[0].name); + expect(findAllBranchRules().at(0).props('branchProtection')).toEqual(nodes[0].branchProtection); + expect(findAllBranchRules().at(1).props('name')).toBe(nodes[1].name); + + expect(findAllBranchRules().at(1).props('branchProtection')).toEqual(nodes[1].branchProtection); }); }); diff --git a/spec/frontend/projects/settings/repository/branch_rules/components/branch_rule_spec.js b/spec/frontend/projects/settings/repository/branch_rules/components/branch_rule_spec.js index 2bc705f538b..2aa93fd0e28 100644 --- a/spec/frontend/projects/settings/repository/branch_rules/components/branch_rule_spec.js +++ b/spec/frontend/projects/settings/repository/branch_rules/components/branch_rule_spec.js @@ -2,7 +2,12 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import BranchRule, { i18n, } from '~/projects/settings/repository/branch_rules/components/branch_rule.vue'; -import { branchRuleProvideMock, branchRulePropsMock } from '../mock_data'; +import { sprintf, n__ } from '~/locale'; +import { + branchRuleProvideMock, + branchRulePropsMock, + branchRuleWithoutDetailsPropsMock, +} from '../mock_data'; describe('Branch rule', () => { let wrapper; @@ -15,7 +20,6 @@ describe('Branch rule', () => { }; const findDefaultBadge = () => wrapper.findByText(i18n.defaultLabel); - const findProtectedBadge = () => wrapper.findByText(i18n.protectedLabel); const findBranchName = () => wrapper.findByText(branchRulePropsMock.name); const findProtectionDetailsList = () => wrapper.findByRole('list'); const findProtectionDetailsListItems = () => wrapper.findAllByRole('listitem'); @@ -28,33 +32,36 @@ describe('Branch rule', () => { }); describe('badges', () => { - it('renders both default and protected badges', () => { + it('renders default badge', () => { expect(findDefaultBadge().exists()).toBe(true); - expect(findProtectedBadge().exists()).toBe(true); }); it('does not render default badge if isDefault is set to false', () => { createComponent({ isDefault: false }); expect(findDefaultBadge().exists()).toBe(false); }); - - it('does not render protected badge if isProtected is set to false', () => { - createComponent({ isProtected: false }); - expect(findProtectedBadge().exists()).toBe(false); - }); }); - it('does not render the protection details list of no details are present', () => { - createComponent({ approvalDetails: null }); + it('does not render the protection details list if no details are present', () => { + createComponent(branchRuleWithoutDetailsPropsMock); expect(findProtectionDetailsList().exists()).toBe(false); }); it('renders the protection details list items', () => { - expect(findProtectionDetailsListItems().at(0).text()).toBe( - branchRulePropsMock.approvalDetails[0], + expect(findProtectionDetailsListItems()).toHaveLength(wrapper.vm.approvalDetails.length); + expect(findProtectionDetailsListItems().at(0).text()).toBe(i18n.allowForcePush); + expect(findProtectionDetailsListItems().at(1).text()).toBe(i18n.codeOwnerApprovalRequired); + expect(findProtectionDetailsListItems().at(2).text()).toMatchInterpolatedText( + sprintf(i18n.statusChecks, { + total: branchRulePropsMock.statusChecksTotal, + subject: n__('check', 'checks', branchRulePropsMock.statusChecksTotal), + }), ); - expect(findProtectionDetailsListItems().at(1).text()).toBe( - branchRulePropsMock.approvalDetails[1], + expect(findProtectionDetailsListItems().at(3).text()).toMatchInterpolatedText( + sprintf(i18n.approvalRules, { + total: branchRulePropsMock.approvalRulesTotal, + subject: n__('rule', 'rules', branchRulePropsMock.approvalRulesTotal), + }), ); }); diff --git a/spec/frontend/projects/settings/repository/branch_rules/mock_data.js b/spec/frontend/projects/settings/repository/branch_rules/mock_data.js index bac82992c4d..8aa03a12996 100644 --- a/spec/frontend/projects/settings/repository/branch_rules/mock_data.js +++ b/spec/frontend/projects/settings/repository/branch_rules/mock_data.js @@ -8,10 +8,36 @@ export const branchRulesMockResponse = { nodes: [ { name: 'main', + isDefault: true, + branchProtection: { + allowForcePush: true, + codeOwnerApprovalRequired: true, + }, + approvalRules: { + nodes: [{ id: 1 }], + __typename: 'ApprovalProjectRuleConnection', + }, + externalStatusChecks: { + nodes: [{ id: 1 }, { id: 2 }], + __typename: 'BranchRule', + }, __typename: 'BranchRule', }, { name: 'test-*', + isDefault: false, + branchProtection: { + allowForcePush: false, + codeOwnerApprovalRequired: false, + }, + approvalRules: { + nodes: [], + __typename: 'ApprovalProjectRuleConnection', + }, + externalStatusChecks: { + nodes: [], + __typename: 'BranchRule', + }, __typename: 'BranchRule', }, ], @@ -31,6 +57,21 @@ export const branchRuleProvideMock = { export const branchRulePropsMock = { name: 'main', isDefault: true, - isProtected: true, - approvalDetails: ['requires approval from TEST', '2 status checks'], + branchProtection: { + allowForcePush: true, + codeOwnerApprovalRequired: true, + }, + approvalRulesTotal: 1, + statusChecksTotal: 2, +}; + +export const branchRuleWithoutDetailsPropsMock = { + name: 'main', + isDefault: false, + branchProtection: { + allowForcePush: false, + codeOwnerApprovalRequired: false, + }, + approvalRulesTotal: 0, + statusChecksTotal: 0, }; diff --git a/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js b/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js index 7c3f4e76ae5..f9762491507 100644 --- a/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js +++ b/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js @@ -64,20 +64,14 @@ describe('ServiceDeskSetting', () => { }); }); - describe('when customEmailEnabled', () => { - beforeEach(() => { - wrapper = createComponent({ - props: { customEmailEnabled: true }, - }); - }); + describe('service desk email "from" name', () => { + it('service desk e-mail "from" name input appears', () => { + wrapper = createComponent(); - it('should not display help text', () => { - expect(findSuffixFormGroup().text()).not.toContain( - 'To add a custom suffix, set up a Service Desk email address', - ); - expect(findSuffixFormGroup().text()).toContain( - 'Add a suffix to Service Desk email address', - ); + const input = wrapper.findByTestId('email-from-name'); + + expect(input.exists()).toBe(true); + expect(input.attributes('disabled')).toBeUndefined(); }); }); |