diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-12-13 12:12:51 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-12-13 12:12:51 +0300 |
commit | c283bdb7bc86aee27a7ed065fc9fb17e4c4ffee6 (patch) | |
tree | c5a33d4145f949ca6be24f09330c32c2a65e2d12 /spec/frontend | |
parent | e7b6c527c40962adc6623521ff190771e4ac50e4 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
6 files changed, 273 insertions, 21 deletions
diff --git a/spec/frontend/import_entities/import_projects/components/import_projects_table_spec.js b/spec/frontend/import_entities/import_projects/components/import_projects_table_spec.js index 92d064846bd..056155a560f 100644 --- a/spec/frontend/import_entities/import_projects/components/import_projects_table_spec.js +++ b/spec/frontend/import_entities/import_projects/components/import_projects_table_spec.js @@ -36,6 +36,7 @@ describe('ImportProjectsTable', () => { .filter((w) => w.props().variant === 'confirm') .at(0); const findImportAllModal = () => wrapper.findComponent({ ref: 'importAllModal' }); + const findIntersectionObserver = () => wrapper.findComponent(GlIntersectionObserver); const importAllFn = jest.fn(); const importAllModalShowFn = jest.fn(); @@ -203,13 +204,13 @@ describe('ImportProjectsTable', () => { describe('when paginatable is set to true', () => { const initState = { namespaces: [{ fullPath: 'path' }], - pageInfo: { page: 1, hasNextPage: true }, + pageInfo: { page: 1, hasNextPage: false }, repositories: [ { importSource: { id: 1 }, importedProject: null, importStatus: STATUSES.NONE }, ], }; - describe('with hasNextPage true', () => { + describe('with hasNextPage false', () => { beforeEach(() => { createComponent({ state: initState, @@ -217,26 +218,14 @@ describe('ImportProjectsTable', () => { }); }); - it('does not call fetchRepos on mount', () => { - expect(fetchReposFn).not.toHaveBeenCalled(); - }); - - it('renders intersection observer component', () => { - expect(wrapper.findComponent(GlIntersectionObserver).exists()).toBe(true); - }); - - it('calls fetchRepos when intersection observer appears', async () => { - wrapper.findComponent(GlIntersectionObserver).vm.$emit('appear'); - - await nextTick(); - - expect(fetchReposFn).toHaveBeenCalled(); + it('does not render intersection observer component', () => { + expect(findIntersectionObserver().exists()).toBe(false); }); }); - describe('with hasNextPage false', () => { + describe('with hasNextPage true', () => { beforeEach(() => { - initState.pageInfo.hasNextPage = false; + initState.pageInfo.hasNextPage = true; createComponent({ state: initState, @@ -244,8 +233,16 @@ describe('ImportProjectsTable', () => { }); }); - it('does not render intersection observer component', () => { - expect(wrapper.findComponent(GlIntersectionObserver).exists()).toBe(false); + it('renders intersection observer component', () => { + expect(findIntersectionObserver().exists()).toBe(true); + }); + + it('calls fetchRepos again when intersection observer appears', async () => { + findIntersectionObserver().vm.$emit('appear'); + + await nextTick(); + + expect(fetchReposFn).toHaveBeenCalledTimes(2); }); }); }); diff --git a/spec/frontend/import_entities/import_projects/store/actions_spec.js b/spec/frontend/import_entities/import_projects/store/actions_spec.js index 3b94db37801..918821dfa59 100644 --- a/spec/frontend/import_entities/import_projects/store/actions_spec.js +++ b/spec/frontend/import_entities/import_projects/store/actions_spec.js @@ -17,6 +17,7 @@ import { SET_PAGE, SET_FILTER, SET_PAGE_CURSORS, + SET_HAS_NEXT_PAGE, } from '~/import_entities/import_projects/store/mutation_types'; import state from '~/import_entities/import_projects/store/state'; import axios from '~/lib/utils/axios_utils'; @@ -143,6 +144,44 @@ describe('import_projects store actions', () => { ); }); }); + + describe('when provider is BITBUCKET_SERVER', () => { + beforeEach(() => { + localState.provider = PROVIDERS.BITBUCKET_SERVER; + }); + + describe.each` + reposLength | expectedHasNextPage + ${0} | ${false} + ${12} | ${false} + ${20} | ${false} + ${25} | ${true} + `('when reposLength is $reposLength', ({ reposLength, expectedHasNextPage }) => { + beforeEach(() => { + payload.provider_repos = Array(reposLength).fill({}); + + mock.onGet(MOCK_ENDPOINT).reply(HTTP_STATUS_OK, payload); + }); + + it('commits SET_HAS_NEXT_PAGE', () => { + return testAction( + fetchRepos, + null, + localState, + [ + { type: REQUEST_REPOS }, + { type: SET_PAGE, payload: 1 }, + { type: SET_HAS_NEXT_PAGE, payload: expectedHasNextPage }, + { + type: RECEIVE_REPOS_SUCCESS, + payload: convertObjectPropsToCamelCase(payload, { deep: true }), + }, + ], + [], + ); + }); + }); + }); }); it('commits REQUEST_REPOS, RECEIVE_REPOS_ERROR mutations on an unsuccessful request', () => { diff --git a/spec/frontend/import_entities/import_projects/store/mutations_spec.js b/spec/frontend/import_entities/import_projects/store/mutations_spec.js index 07d247630cc..90053f79bdf 100644 --- a/spec/frontend/import_entities/import_projects/store/mutations_spec.js +++ b/spec/frontend/import_entities/import_projects/store/mutations_spec.js @@ -332,6 +332,16 @@ describe('import_projects store mutations', () => { }); }); + describe(`${types.SET_HAS_NEXT_PAGE}`, () => { + it('sets hasNextPage in pageInfo', () => { + const NEW_HAS_NEXT_PAGE = true; + state = { pageInfo: { hasNextPage: false } }; + + mutations[types.SET_HAS_NEXT_PAGE](state, NEW_HAS_NEXT_PAGE); + expect(state.pageInfo.hasNextPage).toBe(NEW_HAS_NEXT_PAGE); + }); + }); + describe(`${types.CANCEL_IMPORT_SUCCESS}`, () => { const payload = { repoId: 1 }; diff --git a/spec/frontend/kubernetes_dashboard/graphql/mock_data.js b/spec/frontend/kubernetes_dashboard/graphql/mock_data.js index 030e801c06d..fe26bf5c600 100644 --- a/spec/frontend/kubernetes_dashboard/graphql/mock_data.js +++ b/spec/frontend/kubernetes_dashboard/graphql/mock_data.js @@ -289,3 +289,9 @@ export const mockStatefulSetsTableItems = [ kind: 'StatefulSet', }, ]; + +export const k8sReplicaSetsMock = [readyStatefulSet, readyStatefulSet, failedStatefulSet]; + +export const mockReplicaSetsTableItems = mockStatefulSetsTableItems.map((item) => { + return { ...item, kind: 'ReplicaSet' }; +}); diff --git a/spec/frontend/kubernetes_dashboard/graphql/resolvers/kubernetes_spec.js b/spec/frontend/kubernetes_dashboard/graphql/resolvers/kubernetes_spec.js index 5841c73ea71..feee63546dd 100644 --- a/spec/frontend/kubernetes_dashboard/graphql/resolvers/kubernetes_spec.js +++ b/spec/frontend/kubernetes_dashboard/graphql/resolvers/kubernetes_spec.js @@ -3,7 +3,13 @@ import { resolvers } from '~/kubernetes_dashboard/graphql/resolvers'; import k8sDashboardPodsQuery from '~/kubernetes_dashboard/graphql/queries/k8s_dashboard_pods.query.graphql'; import k8sDashboardDeploymentsQuery from '~/kubernetes_dashboard/graphql/queries/k8s_dashboard_deployments.query.graphql'; import k8sDashboardStatefulSetsQuery from '~/kubernetes_dashboard/graphql/queries/k8s_dashboard_stateful_sets.query.graphql'; -import { k8sPodsMock, k8sDeploymentsMock, k8sStatefulSetsMock } from '../mock_data'; +import k8sDashboardReplicaSetsQuery from '~/kubernetes_dashboard/graphql/queries/k8s_dashboard_replica_sets.query.graphql'; +import { + k8sPodsMock, + k8sDeploymentsMock, + k8sStatefulSetsMock, + k8sReplicaSetsMock, +} from '../mock_data'; describe('~/frontend/environments/graphql/resolvers', () => { let mockResolvers; @@ -276,4 +282,92 @@ describe('~/frontend/environments/graphql/resolvers', () => { ).rejects.toThrow('API error'); }); }); + + describe('k8sReplicaSets', () => { + const client = { writeQuery: jest.fn() }; + + const mockWatcher = WatchApi.prototype; + const mockReplicaSetsListWatcherFn = jest.fn().mockImplementation(() => { + return Promise.resolve(mockWatcher); + }); + + const mockOnDataFn = jest.fn().mockImplementation((eventName, callback) => { + if (eventName === 'data') { + callback([]); + } + }); + + const mockReplicaSetsListFn = jest.fn().mockImplementation(() => { + return Promise.resolve({ + items: k8sReplicaSetsMock, + }); + }); + + const mockAllReplicaSetsListFn = jest.fn().mockImplementation(mockReplicaSetsListFn); + + describe('when the ReplicaSets data is present', () => { + beforeEach(() => { + jest + .spyOn(AppsV1Api.prototype, 'listAppsV1ReplicaSetForAllNamespaces') + .mockImplementation(mockAllReplicaSetsListFn); + jest + .spyOn(mockWatcher, 'subscribeToStream') + .mockImplementation(mockReplicaSetsListWatcherFn); + jest.spyOn(mockWatcher, 'on').mockImplementation(mockOnDataFn); + }); + + it('should request all ReplicaSets from the cluster_client library and watch the events', async () => { + const ReplicaSets = await mockResolvers.Query.k8sReplicaSets( + null, + { + configuration, + }, + { client }, + ); + + expect(mockAllReplicaSetsListFn).toHaveBeenCalled(); + expect(mockReplicaSetsListWatcherFn).toHaveBeenCalled(); + + expect(ReplicaSets).toEqual(k8sReplicaSetsMock); + }); + + it('should update cache with the new data when received from the library', async () => { + await mockResolvers.Query.k8sReplicaSets( + null, + { configuration, namespace: '' }, + { client }, + ); + + expect(client.writeQuery).toHaveBeenCalledWith({ + query: k8sDashboardReplicaSetsQuery, + variables: { configuration, namespace: '' }, + data: { k8sReplicaSets: [] }, + }); + }); + }); + + it('should not watch ReplicaSets from the cluster_client library when the ReplicaSets data is not present', async () => { + jest.spyOn(AppsV1Api.prototype, 'listAppsV1ReplicaSetForAllNamespaces').mockImplementation( + jest.fn().mockImplementation(() => { + return Promise.resolve({ + items: [], + }); + }), + ); + + await mockResolvers.Query.k8sReplicaSets(null, { configuration }, { client }); + + expect(mockReplicaSetsListWatcherFn).not.toHaveBeenCalled(); + }); + + it('should throw an error if the API call fails', async () => { + jest + .spyOn(AppsV1Api.prototype, 'listAppsV1ReplicaSetForAllNamespaces') + .mockRejectedValue(new Error('API error')); + + await expect( + mockResolvers.Query.k8sReplicaSets(null, { configuration }, { client }), + ).rejects.toThrow('API error'); + }); + }); }); diff --git a/spec/frontend/kubernetes_dashboard/pages/replica_sets_page_spec.js b/spec/frontend/kubernetes_dashboard/pages/replica_sets_page_spec.js new file mode 100644 index 00000000000..0e442ec8328 --- /dev/null +++ b/spec/frontend/kubernetes_dashboard/pages/replica_sets_page_spec.js @@ -0,0 +1,106 @@ +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import { shallowMount } from '@vue/test-utils'; +import waitForPromises from 'helpers/wait_for_promises'; +import createMockApollo from 'helpers/mock_apollo_helper'; +import ReplicaSetsPage from '~/kubernetes_dashboard/pages/replica_sets_page.vue'; +import WorkloadLayout from '~/kubernetes_dashboard/components/workload_layout.vue'; +import { useFakeDate } from 'helpers/fake_date'; +import { + k8sReplicaSetsMock, + mockStatefulSetsStats, + mockReplicaSetsTableItems, +} from '../graphql/mock_data'; + +Vue.use(VueApollo); + +describe('Kubernetes dashboard replicaSets page', () => { + let wrapper; + + const configuration = { + basePath: 'kas/tunnel/url', + baseOptions: { + headers: { 'GitLab-Agent-Id': '1' }, + }, + }; + + const findWorkloadLayout = () => wrapper.findComponent(WorkloadLayout); + + const createApolloProvider = () => { + const mockResolvers = { + Query: { + k8sReplicaSets: jest.fn().mockReturnValue(k8sReplicaSetsMock), + }, + }; + + return createMockApollo([], mockResolvers); + }; + + const createWrapper = (apolloProvider = createApolloProvider()) => { + wrapper = shallowMount(ReplicaSetsPage, { + provide: { configuration }, + apolloProvider, + }); + }; + + describe('mounted', () => { + it('renders WorkloadLayout component', () => { + createWrapper(); + + expect(findWorkloadLayout().exists()).toBe(true); + }); + + it('sets loading prop for the WorkloadLayout', () => { + createWrapper(); + + expect(findWorkloadLayout().props('loading')).toBe(true); + }); + + it('removes loading prop from the WorkloadLayout when the list of pods loaded', async () => { + createWrapper(); + await waitForPromises(); + + expect(findWorkloadLayout().props('loading')).toBe(false); + }); + }); + + describe('when gets pods data', () => { + useFakeDate(2023, 10, 23, 10, 10); + + it('sets correct stats object for the WorkloadLayout', async () => { + createWrapper(); + await waitForPromises(); + + expect(findWorkloadLayout().props('stats')).toEqual(mockStatefulSetsStats); + }); + + it('sets correct table items object for the WorkloadLayout', async () => { + createWrapper(); + await waitForPromises(); + + expect(findWorkloadLayout().props('items')).toMatchObject(mockReplicaSetsTableItems); + }); + }); + + describe('when gets an error from the cluster_client API', () => { + const error = new Error('Error from the cluster_client API'); + const createErroredApolloProvider = () => { + const mockResolvers = { + Query: { + k8sReplicaSets: jest.fn().mockRejectedValueOnce(error), + }, + }; + + return createMockApollo([], mockResolvers); + }; + + beforeEach(async () => { + createWrapper(createErroredApolloProvider()); + await waitForPromises(); + }); + + it('sets errorMessage prop for the WorkloadLayout', () => { + expect(findWorkloadLayout().props('errorMessage')).toBe(error.message); + }); + }); +}); |