diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-04-28 12:18:08 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-04-28 12:18:08 +0300 |
commit | 70c1d0352e39c3c04caaa3082c3ffb4ad5c29b32 (patch) | |
tree | d3ea704848d6a4bb44de46116ee7aec78019e90c /spec/frontend/ci/artifacts/components | |
parent | 64a5bf8e84f5f4e3348b1586f3a3904cedceb207 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/ci/artifacts/components')
5 files changed, 154 insertions, 27 deletions
diff --git a/spec/frontend/ci/artifacts/components/artifact_row_spec.js b/spec/frontend/ci/artifacts/components/artifact_row_spec.js index f64d32410ed..ee5d62c2d48 100644 --- a/spec/frontend/ci/artifacts/components/artifact_row_spec.js +++ b/spec/frontend/ci/artifacts/components/artifact_row_spec.js @@ -4,7 +4,7 @@ import { numberToHumanSize } from '~/lib/utils/number_utils'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import waitForPromises from 'helpers/wait_for_promises'; import ArtifactRow from '~/ci/artifacts/components/artifact_row.vue'; -import { BULK_DELETE_FEATURE_FLAG } from '~/ci/artifacts/constants'; +import { BULK_DELETE_FEATURE_FLAG, I18N_BULK_DELETE_MAX_SELECTED } from '~/ci/artifacts/constants'; describe('ArtifactRow component', () => { let wrapper; @@ -18,13 +18,15 @@ describe('ArtifactRow component', () => { const findDeleteButton = () => wrapper.findByTestId('job-artifact-row-delete-button'); const findCheckbox = () => wrapper.findComponent(GlFormCheckbox); - const createComponent = ({ canDestroyArtifacts = true, glFeatures = {} } = {}) => { + const createComponent = ({ canDestroyArtifacts = true, glFeatures = {}, props = {} } = {}) => { wrapper = shallowMountExtended(ArtifactRow, { propsData: { artifact, isSelected: false, isLoading: false, isLastRow: false, + isSelectedArtifactsLimitReached: false, + ...props, }, provide: { canDestroyArtifacts, glFeatures }, stubs: { GlBadge, GlFriendlyWrap }, @@ -79,15 +81,35 @@ describe('ArtifactRow component', () => { describe('bulk delete checkbox', () => { describe('with permission and feature flag enabled', () => { - beforeEach(() => { + it('emits selectArtifact when toggled', () => { createComponent({ glFeatures: { [BULK_DELETE_FEATURE_FLAG]: true } }); - }); - it('emits selectArtifact when toggled', () => { findCheckbox().vm.$emit('input', true); expect(wrapper.emitted('selectArtifact')).toStrictEqual([[artifact, true]]); }); + + describe('when the selected artifacts limit is reached', () => { + it('remains enabled if the artifact was selected', () => { + createComponent({ + glFeatures: { [BULK_DELETE_FEATURE_FLAG]: true }, + props: { isSelected: true, isSelectedArtifactsLimitReached: true }, + }); + + expect(findCheckbox().attributes('disabled')).toBeUndefined(); + expect(findCheckbox().attributes('title')).toBe(''); + }); + + it('is disabled if the artifact was not selected', () => { + createComponent({ + glFeatures: { [BULK_DELETE_FEATURE_FLAG]: true }, + props: { isSelected: false, isSelectedArtifactsLimitReached: true }, + }); + + expect(findCheckbox().attributes('disabled')).toBe('true'); + expect(findCheckbox().attributes('title')).toBe(I18N_BULK_DELETE_MAX_SELECTED); + }); + }); }); it('is not shown without permission', () => { diff --git a/spec/frontend/ci/artifacts/components/artifacts_bulk_delete_spec.js b/spec/frontend/ci/artifacts/components/artifacts_bulk_delete_spec.js index 9e4fa6b9c6f..549f6e1e375 100644 --- a/spec/frontend/ci/artifacts/components/artifacts_bulk_delete_spec.js +++ b/spec/frontend/ci/artifacts/components/artifacts_bulk_delete_spec.js @@ -1,7 +1,8 @@ -import { GlSprintf } from '@gitlab/ui'; +import { GlSprintf, GlAlert } from '@gitlab/ui'; import mockGetJobArtifactsResponse from 'test_fixtures/graphql/ci/artifacts/graphql/queries/get_job_artifacts.query.graphql.json'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import ArtifactsBulkDelete from '~/ci/artifacts/components/artifacts_bulk_delete.vue'; +import { I18N_BULK_DELETE_MAX_SELECTED } from '~/ci/artifacts/constants'; describe('ArtifactsBulkDelete component', () => { let wrapper; @@ -14,11 +15,14 @@ describe('ArtifactsBulkDelete component', () => { const findText = () => wrapper.findComponent(GlSprintf).text(); const findDeleteButton = () => wrapper.findByTestId('bulk-delete-delete-button'); const findClearButton = () => wrapper.findByTestId('bulk-delete-clear-button'); + const findAlertText = () => wrapper.findComponent(GlAlert).text(); - const createComponent = () => { + const createComponent = (props) => { wrapper = shallowMountExtended(ArtifactsBulkDelete, { propsData: { selectedArtifacts, + isSelectedArtifactsLimitReached: false, + ...props, }, stubs: { GlSprintf }, }); @@ -45,4 +49,10 @@ describe('ArtifactsBulkDelete component', () => { expect(wrapper.emitted('clearSelectedArtifacts')).toBeDefined(); }); }); + + it('shows an alert when the selected artifacts limit is reached', () => { + createComponent({ isSelectedArtifactsLimitReached: true }); + + expect(findAlertText()).toBe(I18N_BULK_DELETE_MAX_SELECTED); + }); }); diff --git a/spec/frontend/ci/artifacts/components/artifacts_table_row_details_spec.js b/spec/frontend/ci/artifacts/components/artifacts_table_row_details_spec.js index ebdb7e25c45..479ecf6b183 100644 --- a/spec/frontend/ci/artifacts/components/artifacts_table_row_details_spec.js +++ b/spec/frontend/ci/artifacts/components/artifacts_table_row_details_spec.js @@ -41,6 +41,7 @@ describe('ArtifactsTableRowDetails component', () => { selectedArtifacts, refetchArtifacts, queryVariables: {}, + isSelectedArtifactsLimitReached: false, }, provide: { canDestroyArtifacts: true }, data() { diff --git a/spec/frontend/ci/artifacts/components/job_artifacts_table_spec.js b/spec/frontend/ci/artifacts/components/job_artifacts_table_spec.js index 74d0d683662..fe58f302a1d 100644 --- a/spec/frontend/ci/artifacts/components/job_artifacts_table_spec.js +++ b/spec/frontend/ci/artifacts/components/job_artifacts_table_spec.js @@ -7,7 +7,7 @@ import { GlModal, GlFormCheckbox, } from '@gitlab/ui'; -import Vue from 'vue'; +import Vue, { nextTick } from 'vue'; import VueApollo from 'vue-apollo'; import getJobArtifactsResponse from 'test_fixtures/graphql/ci/artifacts/graphql/queries/get_job_artifacts.query.graphql.json'; import CiIcon from '~/vue_shared/components/ci_icon.vue'; @@ -18,6 +18,7 @@ import ArtifactsTableRowDetails from '~/ci/artifacts/components/artifacts_table_ import ArtifactDeleteModal from '~/ci/artifacts/components/artifact_delete_modal.vue'; import ArtifactsBulkDelete from '~/ci/artifacts/components/artifacts_bulk_delete.vue'; import BulkDeleteModal from '~/ci/artifacts/components/bulk_delete_modal.vue'; +import JobCheckbox from '~/ci/artifacts/components/job_checkbox.vue'; import createMockApollo from 'helpers/mock_apollo_helper'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import getJobArtifactsQuery from '~/ci/artifacts/graphql/queries/get_job_artifacts.query.graphql'; @@ -31,6 +32,7 @@ import { INITIAL_CURRENT_PAGE, BULK_DELETE_FEATURE_FLAG, I18N_BULK_DELETE_ERROR, + SELECTED_ARTIFACTS_MAX_COUNT, } from '~/ci/artifacts/constants'; import { totalArtifactsSizeForJob } from '~/ci/artifacts/utils'; import { createAlert } from '~/alert'; @@ -123,6 +125,8 @@ describe('JobArtifactsTable component', () => { }, }); + const maxSelectedArtifacts = new Array(SELECTED_ARTIFACTS_MAX_COUNT).fill({}); + const createComponent = ({ handlers = { getJobArtifactsQuery: jest.fn().mockResolvedValue(getJobArtifactsResponse), @@ -236,12 +240,12 @@ describe('JobArtifactsTable component', () => { expect(findDetailsRows().length).toBe(0); findCount().trigger('click'); - await waitForPromises(); + await nextTick(); expect(findDetailsRows().length).toBe(1); findCount().trigger('click'); - await waitForPromises(); + await nextTick(); expect(findDetailsRows().length).toBe(0); }); @@ -252,7 +256,7 @@ describe('JobArtifactsTable component', () => { expect(findDetailsInRow(1).exists()).toBe(false); findCountAt(0).trigger('click'); - await waitForPromises(); + await nextTick(); // first job is expanded, second row has its details expect(findDetailsInRow(0).exists()).toBe(false); @@ -260,7 +264,7 @@ describe('JobArtifactsTable component', () => { expect(findDetailsInRow(2).exists()).toBe(false); findCountAt(1).trigger('click'); - await waitForPromises(); + await nextTick(); // both jobs are expanded, each has details below it expect(findDetailsInRow(0).exists()).toBe(false); @@ -269,7 +273,7 @@ describe('JobArtifactsTable component', () => { expect(findDetailsInRow(3).exists()).toBe(true); findCountAt(0).trigger('click'); - await waitForPromises(); + await nextTick(); // first job collapsed, second job expanded expect(findDetailsInRow(0).exists()).toBe(false); @@ -285,7 +289,7 @@ describe('JobArtifactsTable component', () => { expect(findDetailsInRow(1).exists()).toBe(true); findArtifactDeleteButton().vm.$emit('click'); - await waitForPromises(); + await nextTick(); expect(findDeleteModal().findComponent(GlModal).props('visible')).toBe(true); @@ -510,7 +514,7 @@ describe('JobArtifactsTable component', () => { findJobCheckbox().vm.$emit('input', true); findBulkDelete().vm.$emit('showBulkDeleteModal'); - await waitForPromises(); + await nextTick(); expect(findBulkDeleteModal().props('visible')).toBe(true); }); @@ -543,6 +547,35 @@ describe('JobArtifactsTable component', () => { }); }); + describe('when the selected artifacts limit is reached', () => { + beforeEach(async () => { + createComponent({ + canDestroyArtifacts: true, + glFeatures: { [BULK_DELETE_FEATURE_FLAG]: true }, + data: { selectedArtifacts: maxSelectedArtifacts }, + }); + + await nextTick(); + }); + + it('passes isSelectedArtifactsLimitReached to bulk delete', () => { + expect(findBulkDelete().props('isSelectedArtifactsLimitReached')).toBe(true); + }); + + it('passes isSelectedArtifactsLimitReached to job checkbox', () => { + expect(wrapper.findComponent(JobCheckbox).props('isSelectedArtifactsLimitReached')).toBe( + true, + ); + }); + + it('passes isSelectedArtifactsLimitReached to table row details', async () => { + findCount().trigger('click'); + await nextTick(); + + expect(findDetailsInRow(1).props('isSelectedArtifactsLimitReached')).toBe(true); + }); + }); + it('shows an alert and does not clear selected artifacts on error', async () => { createComponent({ canDestroyArtifacts: true, @@ -604,7 +637,7 @@ describe('JobArtifactsTable component', () => { data: { pageInfo }, }); - await waitForPromises(); + await nextTick(); }); it('renders pagination and passes page props', () => { diff --git a/spec/frontend/ci/artifacts/components/job_checkbox_spec.js b/spec/frontend/ci/artifacts/components/job_checkbox_spec.js index ae70bb4b17b..56f1d8cc47b 100644 --- a/spec/frontend/ci/artifacts/components/job_checkbox_spec.js +++ b/spec/frontend/ci/artifacts/components/job_checkbox_spec.js @@ -2,6 +2,7 @@ import { GlFormCheckbox } from '@gitlab/ui'; import mockGetJobArtifactsResponse from 'test_fixtures/graphql/ci/artifacts/graphql/queries/get_job_artifacts.query.graphql.json'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import JobCheckbox from '~/ci/artifacts/components/job_checkbox.vue'; +import { I18N_BULK_DELETE_MAX_SELECTED } from '~/ci/artifacts/constants'; describe('JobCheckbox component', () => { let wrapper; @@ -16,12 +17,14 @@ describe('JobCheckbox component', () => { hasArtifacts = true, selectedArtifacts = mockSelectedArtifacts, unselectedArtifacts = mockUnselectedArtifacts, + isSelectedArtifactsLimitReached = false, } = {}) => { wrapper = shallowMountExtended(JobCheckbox, { propsData: { hasArtifacts, selectedArtifacts, unselectedArtifacts, + isSelectedArtifactsLimitReached, }, mocks: { GlFormCheckbox }, }); @@ -33,24 +36,44 @@ describe('JobCheckbox component', () => { expect(findCheckbox().attributes('disabled')).toBe('true'); }); - describe('when some artifacts are selected', () => { - beforeEach(() => { - createComponent(); - }); + describe('when some artifacts from this job are selected', () => { + describe('when the selected artifacts limit has not been reached', () => { + beforeEach(() => { + createComponent(); + }); + + it('is indeterminate', () => { + expect(findCheckbox().attributes('indeterminate')).toBe('true'); + expect(findCheckbox().attributes('checked')).toBeUndefined(); + }); + + it('selects the unselected artifacts on click', () => { + findCheckbox().vm.$emit('input', true); - it('is indeterminate', () => { - expect(findCheckbox().attributes('indeterminate')).toBe('true'); - expect(findCheckbox().attributes('checked')).toBeUndefined(); + expect(wrapper.emitted('selectArtifact')).toMatchObject([ + [mockUnselectedArtifacts[0], true], + ]); + }); }); - it('selects the unselected artifacts on click', () => { - findCheckbox().vm.$emit('input', true); + describe('when the selected artifacts limit has been reached', () => { + beforeEach(() => { + // limit has been reached by selecting artifacts from this job + createComponent({ + selectedArtifacts: mockSelectedArtifacts, + isSelectedArtifactsLimitReached: true, + }); + }); - expect(wrapper.emitted('selectArtifact')).toMatchObject([[mockUnselectedArtifacts[0], true]]); + it('remains enabled', () => { + // job checkbox remains enabled to allow de-selection + expect(findCheckbox().attributes('disabled')).toBeUndefined(); + expect(findCheckbox().attributes('title')).not.toBe(I18N_BULK_DELETE_MAX_SELECTED); + }); }); }); - describe('when all artifacts are selected', () => { + describe('when all artifacts from this job are selected', () => { beforeEach(() => { createComponent({ unselectedArtifacts: [] }); }); @@ -68,4 +91,42 @@ describe('JobCheckbox component', () => { ]); }); }); + + describe('when no artifacts from this job are selected', () => { + describe('when the selected artifacts limit has not been reached', () => { + beforeEach(() => { + createComponent({ selectedArtifacts: [] }); + }); + + it('is enabled and not checked', () => { + expect(findCheckbox().attributes('checked')).toBeUndefined(); + expect(findCheckbox().attributes('disabled')).toBeUndefined(); + expect(findCheckbox().attributes('title')).toBe(''); + }); + + it('selects the artifacts on click', () => { + findCheckbox().vm.$emit('input', true); + + expect(wrapper.emitted('selectArtifact')).toMatchObject([ + [mockUnselectedArtifacts[0], true], + ]); + }); + }); + + describe('when the selected artifacts limit has been reached', () => { + beforeEach(() => { + // limit has been reached by selecting artifacts from other jobs + createComponent({ + selectedArtifacts: [], + isSelectedArtifactsLimitReached: true, + }); + }); + + it('is disabled when the selected artifacts limit has been reached', () => { + // job checkbox is disabled to block further selection + expect(findCheckbox().attributes('disabled')).toBe('true'); + expect(findCheckbox().attributes('title')).toBe(I18N_BULK_DELETE_MAX_SELECTED); + }); + }); + }); }); |