diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-05-02 21:18:39 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-05-02 21:18:39 +0300 |
commit | b9ce0fe1e6311105b7a748126621f9bfbe37fb2e (patch) | |
tree | c73b711a72de036cf3f48be9365038fea171c8c6 /spec/frontend | |
parent | 6f991190fe4dbb93070b090a9a31d71b25e8101d (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
9 files changed, 200 insertions, 104 deletions
diff --git a/spec/frontend/admin/abuse_reports/components/abuse_report_details_spec.js b/spec/frontend/admin/abuse_reports/components/abuse_report_details_spec.js deleted file mode 100644 index b89bbac0196..00000000000 --- a/spec/frontend/admin/abuse_reports/components/abuse_report_details_spec.js +++ /dev/null @@ -1,53 +0,0 @@ -import { GlButton, GlCollapse } from '@gitlab/ui'; -import { nextTick } from 'vue'; -import { shallowMount } from '@vue/test-utils'; -import AbuseReportDetails from '~/admin/abuse_reports/components/abuse_report_details.vue'; -import { getTimeago } from '~/lib/utils/datetime_utility'; -import { mockAbuseReports } from '../mock_data'; - -describe('AbuseReportDetails', () => { - let wrapper; - const report = mockAbuseReports[0]; - - const findToggleButton = () => wrapper.findComponent(GlButton); - const findCollapsible = () => wrapper.findComponent(GlCollapse); - - const createComponent = () => { - wrapper = shallowMount(AbuseReportDetails, { - propsData: { - report, - }, - }); - }; - - describe('default', () => { - beforeEach(() => { - createComponent(); - }); - - it('renders toggle button with the correct text', () => { - expect(findToggleButton().text()).toEqual('Show details'); - }); - - it('renders collapsed GlCollapse containing the report details', () => { - const collapsible = findCollapsible(); - expect(collapsible.attributes('visible')).toBeUndefined(); - - const userJoinedText = `User joined ${getTimeago().format(report.reportedUser.createdAt)}`; - expect(collapsible.text()).toMatch(userJoinedText); - expect(collapsible.text()).toMatch(report.message); - }); - }); - - describe('when toggled', () => { - it('expands GlCollapse and updates toggle text', async () => { - createComponent(); - - findToggleButton().vm.$emit('click'); - await nextTick(); - - expect(findToggleButton().text()).toEqual('Hide details'); - expect(findCollapsible().attributes('visible')).toBe('true'); - }); - }); -}); diff --git a/spec/frontend/admin/abuse_reports/components/abuse_report_row_spec.js b/spec/frontend/admin/abuse_reports/components/abuse_report_row_spec.js index 9876ee70e5e..f3cced81478 100644 --- a/spec/frontend/admin/abuse_reports/components/abuse_report_row_spec.js +++ b/spec/frontend/admin/abuse_reports/components/abuse_report_row_spec.js @@ -1,9 +1,6 @@ -import { GlSprintf, GlLink } from '@gitlab/ui'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import setWindowLocation from 'helpers/set_window_location_helper'; -import AbuseReportDetails from '~/admin/abuse_reports/components/abuse_report_details.vue'; import AbuseReportRow from '~/admin/abuse_reports/components/abuse_report_row.vue'; -import AbuseReportActions from '~/admin/abuse_reports/components/abuse_report_actions.vue'; import ListItem from '~/vue_shared/components/registry/list_item.vue'; import { getTimeago } from '~/lib/utils/datetime_utility'; import { SORT_UPDATED_AT } from '~/admin/abuse_reports/constants'; @@ -13,19 +10,16 @@ describe('AbuseReportRow', () => { let wrapper; const mockAbuseReport = mockAbuseReports[0]; - const findLinks = () => wrapper.findAllComponents(GlLink); - const findAbuseReportActions = () => wrapper.findComponent(AbuseReportActions); const findListItem = () => wrapper.findComponent(ListItem); const findTitle = () => wrapper.findByTestId('title'); const findDisplayedDate = () => wrapper.findByTestId('abuse-report-date'); - const findAbuseReportDetails = () => wrapper.findComponent(AbuseReportDetails); - const createComponent = () => { + const createComponent = (props = {}) => { wrapper = shallowMountExtended(AbuseReportRow, { propsData: { report: mockAbuseReport, + ...props, }, - stubs: { GlSprintf }, }); }; @@ -37,19 +31,42 @@ describe('AbuseReportRow', () => { expect(findListItem().exists()).toBe(true); }); - it('displays correctly formatted title', () => { - const { reporter, reportedUser, category, reportedUserPath, reporterPath } = mockAbuseReport; - expect(findTitle().text()).toMatchInterpolatedText( - `${reportedUser.name} reported for ${category} by ${reporter.name}`, - ); + describe('title', () => { + const { reporter, reportedUser, category, reportPath } = mockAbuseReport; - const userLink = findLinks().at(0); - expect(userLink.text()).toEqual(reportedUser.name); - expect(userLink.attributes('href')).toEqual(reportedUserPath); + it('displays correctly formatted title', () => { + expect(findTitle().text()).toMatchInterpolatedText( + `${reportedUser.name} reported for ${category} by ${reporter.name}`, + ); + }); + + it('links to the details page', () => { + expect(findTitle().attributes('href')).toEqual(reportPath); + }); + + describe('when the reportedUser is missing', () => { + beforeEach(() => { + createComponent({ report: { ...mockAbuseReport, reportedUser: null } }); + }); + + it('displays correctly formatted title', () => { + expect(findTitle().text()).toMatchInterpolatedText( + `Deleted user reported for ${category} by ${reporter.name}`, + ); + }); + }); - const reporterLink = findLinks().at(1); - expect(reporterLink.text()).toEqual(reporter.name); - expect(reporterLink.attributes('href')).toEqual(reporterPath); + describe('when the reporter is missing', () => { + beforeEach(() => { + createComponent({ report: { ...mockAbuseReport, reporter: null } }); + }); + + it('displays correctly formatted title', () => { + expect(findTitle().text()).toMatchInterpolatedText( + `${reportedUser.name} reported for ${category} by Deleted user`, + ); + }); + }); }); describe('displayed date', () => { @@ -71,16 +88,4 @@ describe('AbuseReportRow', () => { }); }); }); - - it('renders AbuseReportDetails', () => { - expect(findAbuseReportDetails().exists()).toBe(true); - expect(findAbuseReportDetails().props('report')).toEqual(mockAbuseReport); - }); - - it('renders AbuseReportRowActions with the correct props', () => { - const actions = findAbuseReportActions(); - - expect(actions.exists()).toBe(true); - expect(actions.props('report')).toMatchObject(mockAbuseReport); - }); }); diff --git a/spec/frontend/admin/abuse_reports/mock_data.js b/spec/frontend/admin/abuse_reports/mock_data.js index ee9e56d043b..1ea6ea7d131 100644 --- a/spec/frontend/admin/abuse_reports/mock_data.js +++ b/spec/frontend/admin/abuse_reports/mock_data.js @@ -4,14 +4,7 @@ export const mockAbuseReports = [ createdAt: '2018-10-03T05:46:38.977Z', updatedAt: '2022-12-07T06:45:39.977Z', reporter: { name: 'Ms. Admin' }, - reportedUser: { name: 'Mr. Abuser', createdAt: '2017-09-01T05:46:38.977Z' }, - reportedUserPath: '/mr_abuser', - reporterPath: '/admin', - userBlocked: false, - blockUserPath: '/block/user/mr_abuser/path', - removeUserAndReportPath: '/remove/user/mr_abuser/and/report/path', - removeReportPath: '/remove/report/path', - message: 'message 1', + reportedUser: { name: 'Mr. Abuser' }, reportPath: '/admin/abuse_reports/1', }, { @@ -19,14 +12,7 @@ export const mockAbuseReports = [ createdAt: '2018-10-03T05:46:38.977Z', updatedAt: '2022-12-07T06:45:39.977Z', reporter: { name: 'Ms. Reporter' }, - reportedUser: { name: 'Mr. Phisher', createdAt: '2016-09-01T05:46:38.977Z' }, - reportedUserPath: '/mr_phisher', - reporterPath: '/admin', - userBlocked: false, - blockUserPath: '/block/user/mr_phisher/path', - removeUserAndReportPath: '/remove/user/mr_phisher/and/report/path', - removeReportPath: '/remove/report/path', - message: 'message 2', + reportedUser: { name: 'Mr. Phisher' }, reportPath: '/admin/abuse_reports/2', }, ]; diff --git a/spec/frontend/ci/pipeline_editor/components/commit/commit_section_spec.js b/spec/frontend/ci/pipeline_editor/components/commit/commit_section_spec.js index f8be035d33c..8834231aaef 100644 --- a/spec/frontend/ci/pipeline_editor/components/commit/commit_section_spec.js +++ b/spec/frontend/ci/pipeline_editor/components/commit/commit_section_spec.js @@ -4,6 +4,7 @@ import { mount } from '@vue/test-utils'; import Vue from 'vue'; import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; +import { mockTracking } from 'helpers/tracking_helper'; import CommitForm from '~/ci/pipeline_editor/components/commit/commit_form.vue'; import CommitSection from '~/ci/pipeline_editor/components/commit/commit_section.vue'; import { @@ -11,12 +12,12 @@ import { COMMIT_ACTION_UPDATE, COMMIT_SUCCESS, COMMIT_SUCCESS_WITH_REDIRECT, + pipelineEditorTrackingOptions, } from '~/ci/pipeline_editor/constants'; import { resolvers } from '~/ci/pipeline_editor/graphql/resolvers'; import commitCreate from '~/ci/pipeline_editor/graphql/mutations/commit_ci_file.mutation.graphql'; import getCurrentBranch from '~/ci/pipeline_editor/graphql/queries/client/current_branch.query.graphql'; import updatePipelineEtag from '~/ci/pipeline_editor/graphql/mutations/client/update_pipeline_etag.mutation.graphql'; - import { mockCiConfigPath, mockCiYml, @@ -280,4 +281,43 @@ describe('Pipeline Editor | Commit section', () => { createComponent({ props: { 'scroll-to-commit-form': true } }); expect(findCommitForm().props('scrollToCommitForm')).toBe(true); }); + + describe('tracking', () => { + let trackingSpy; + const { actions, label } = pipelineEditorTrackingOptions; + + beforeEach(() => { + trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn); + }); + + describe('when user commit a new file', () => { + beforeEach(async () => { + mockMutateCommitData.mockResolvedValue(mockCommitCreateResponse); + createComponentWithApollo({ props: { isNewCiConfigFile: true } }); + await submitCommit(); + }); + + it('calls tracking event with the CREATE property', () => { + expect(trackingSpy).toHaveBeenCalledWith(undefined, actions.commitCiConfig, { + label, + property: COMMIT_ACTION_CREATE, + }); + }); + }); + + describe('when user commit an update to the CI file', () => { + beforeEach(async () => { + mockMutateCommitData.mockResolvedValue(mockCommitCreateResponse); + createComponentWithApollo({ props: { isNewCiConfigFile: false } }); + await submitCommit(); + }); + + it('calls the tracking event with the UPDATE property', () => { + expect(trackingSpy).toHaveBeenCalledWith(undefined, actions.commitCiConfig, { + label, + property: COMMIT_ACTION_UPDATE, + }); + }); + }); + }); }); diff --git a/spec/frontend/jobs/components/table/job_table_app_spec.js b/spec/frontend/jobs/components/table/job_table_app_spec.js index 1ca28fefd28..30f674f5ba7 100644 --- a/spec/frontend/jobs/components/table/job_table_app_spec.js +++ b/spec/frontend/jobs/components/table/job_table_app_spec.js @@ -117,6 +117,16 @@ describe('Job table app', () => { expect(wrapper.vm.$apollo.queries.jobs.refetch).toHaveBeenCalledTimes(1); }); + it('avoids refetch jobs query when scope has not changed', async () => { + jest.spyOn(wrapper.vm.$apollo.queries.jobs, 'refetch').mockImplementation(jest.fn()); + + expect(wrapper.vm.$apollo.queries.jobs.refetch).toHaveBeenCalledTimes(0); + + await findTabs().vm.$emit('fetchJobsByStatus', null); + + expect(wrapper.vm.$apollo.queries.jobs.refetch).toHaveBeenCalledTimes(0); + }); + describe('when infinite scrolling is triggered', () => { it('does not display a skeleton loader', () => { triggerInfiniteScroll(); diff --git a/spec/frontend/merge_request_tabs_spec.js b/spec/frontend/merge_request_tabs_spec.js index 8f92ab46714..3b8c9dd3bf3 100644 --- a/spec/frontend/merge_request_tabs_spec.js +++ b/spec/frontend/merge_request_tabs_spec.js @@ -384,12 +384,12 @@ describe('MergeRequestTabs', () => { }); }); - it('scrolls to 0, if no position is stored', () => { + it('does not scroll if no position is stored', () => { testContext.class.tabShown('unknownTab'); jest.advanceTimersByTime(250); - expect(window.scrollTo.mock.calls[0][0]).toEqual({ top: 0, left: 0, behavior: 'auto' }); + expect(window.scrollTo).not.toHaveBeenCalled(); }); }); }); diff --git a/spec/frontend/pages/admin/jobs/components/table/admin_job_table_app_spec.js b/spec/frontend/pages/admin/jobs/components/table/admin_job_table_app_spec.js index 44a5878e6f2..cc6f1c27142 100644 --- a/spec/frontend/pages/admin/jobs/components/table/admin_job_table_app_spec.js +++ b/spec/frontend/pages/admin/jobs/components/table/admin_job_table_app_spec.js @@ -129,6 +129,16 @@ describe('Job table app', () => { expect(wrapper.vm.$apollo.queries.jobs.refetch).toHaveBeenCalledTimes(1); }); + it('avoids refetch jobs query when scope has not changed', async () => { + jest.spyOn(wrapper.vm.$apollo.queries.jobs, 'refetch').mockImplementation(jest.fn()); + + expect(wrapper.vm.$apollo.queries.jobs.refetch).toHaveBeenCalledTimes(0); + + await findTabs().vm.$emit('fetchJobsByStatus', null); + + expect(wrapper.vm.$apollo.queries.jobs.refetch).toHaveBeenCalledTimes(0); + }); + describe('when infinite scrolling is triggered', () => { it('does not display a skeleton loader', () => { triggerInfiniteScroll(); diff --git a/spec/frontend/pages/admin/jobs/components/table/cells/project_cell_spec.js b/spec/frontend/pages/admin/jobs/components/table/cells/project_cell_spec.js new file mode 100644 index 00000000000..3366d60d9f3 --- /dev/null +++ b/spec/frontend/pages/admin/jobs/components/table/cells/project_cell_spec.js @@ -0,0 +1,32 @@ +import { GlLink } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import ProjectCell from '~/pages/admin/jobs/components/table/cell/project_cell.vue'; +import { mockAllJobsNodes } from '../../../../../../jobs/mock_data'; + +const mockJob = mockAllJobsNodes[0]; + +describe('Project cell', () => { + let wrapper; + + const findProjectLink = () => wrapper.findComponent(GlLink); + + const createComponent = (props = {}) => { + wrapper = shallowMount(ProjectCell, { + propsData: { + ...props, + }, + }); + }; + + describe('Project Link', () => { + beforeEach(() => { + createComponent({ job: mockJob }); + }); + + it('shows and links to the project', () => { + expect(findProjectLink().exists()).toBe(true); + expect(findProjectLink().text()).toBe(mockJob.pipeline.project.fullPath); + expect(findProjectLink().attributes('href')).toBe(mockJob.pipeline.project.webUrl); + }); + }); +}); diff --git a/spec/frontend/token_access/outbound_token_access_spec.js b/spec/frontend/token_access/outbound_token_access_spec.js index 347ea1178bc..7f321495d72 100644 --- a/spec/frontend/token_access/outbound_token_access_spec.js +++ b/spec/frontend/token_access/outbound_token_access_spec.js @@ -44,15 +44,26 @@ describe('TokenAccess component', () => { const findAddProjectBtn = () => wrapper.findByRole('button', { name: 'Add project' }); const findRemoveProjectBtn = () => wrapper.findByRole('button', { name: 'Remove access' }); const findTokenDisabledAlert = () => wrapper.findByTestId('token-disabled-alert'); + const findDeprecationAlert = () => wrapper.findByTestId('deprecation-alert'); + const findProjectPathInput = () => wrapper.findByTestId('project-path-input'); const createMockApolloProvider = (requestHandlers) => { return createMockApollo(requestHandlers); }; - const createComponent = (requestHandlers, mountFn = shallowMountExtended) => { + const createComponent = ( + requestHandlers, + mountFn = shallowMountExtended, + frozenOutboundJobTokenScopes = false, + frozenOutboundJobTokenScopesOverride = false, + ) => { wrapper = mountFn(OutboundTokenAccess, { provide: { fullPath: projectPath, + glFeatures: { + frozenOutboundJobTokenScopes, + frozenOutboundJobTokenScopesOverride, + }, }, apolloProvider: createMockApolloProvider(requestHandlers), data() { @@ -272,4 +283,59 @@ describe('TokenAccess component', () => { expect(createAlert).toHaveBeenCalledWith({ message }); }); }); + + describe('with the frozenOutboundJobTokenScopes feature flag enabled', () => { + describe('toggle', () => { + it('the toggle is off and the deprecation alert is visible', async () => { + createComponent( + [ + [getCIJobTokenScopeQuery, disabledJobTokenScopeHandler], + [getProjectsWithCIJobTokenScopeQuery, getProjectsWithScopeHandler], + ], + shallowMountExtended, + true, + ); + + await waitForPromises(); + + expect(findToggle().props('value')).toBe(false); + expect(findToggle().props('disabled')).toBe(true); + expect(findDeprecationAlert().exists()).toBe(true); + expect(findTokenDisabledAlert().exists()).toBe(false); + }); + + it('contains a warning message about disabling the current configuration', async () => { + createComponent( + [ + [getCIJobTokenScopeQuery, disabledJobTokenScopeHandler], + [getProjectsWithCIJobTokenScopeQuery, getProjectsWithScopeHandler], + ], + mountExtended, + true, + ); + + await waitForPromises(); + + expect(findToggle().text()).toContain('Disabling this feature is a permanent change.'); + }); + }); + + describe('adding a new project', () => { + it('disables the input to add new projects', async () => { + createComponent( + [ + [getCIJobTokenScopeQuery, disabledJobTokenScopeHandler], + [getProjectsWithCIJobTokenScopeQuery, getProjectsWithScopeHandler], + ], + mountExtended, + true, + false, + ); + + await waitForPromises(); + + expect(findProjectPathInput().attributes('disabled')).toBe('disabled'); + }); + }); + }); }); |