312 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			312 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
| import { GlAlert, GlFormInput, GlToggle, GlLoadingIcon } from '@gitlab/ui';
 | |
| import Vue from 'vue';
 | |
| import VueApollo from 'vue-apollo';
 | |
| import createMockApollo from 'helpers/mock_apollo_helper';
 | |
| import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
 | |
| import waitForPromises from 'helpers/wait_for_promises';
 | |
| import { createAlert } from '~/flash';
 | |
| import InboundTokenAccess from '~/token_access/components/inbound_token_access.vue';
 | |
| import inboundAddProjectCIJobTokenScopeMutation from '~/token_access/graphql/mutations/inbound_add_project_ci_job_token_scope.mutation.graphql';
 | |
| import inboundRemoveProjectCIJobTokenScopeMutation from '~/token_access/graphql/mutations/inbound_remove_project_ci_job_token_scope.mutation.graphql';
 | |
| import inboundUpdateCIJobTokenScopeMutation from '~/token_access/graphql/mutations/inbound_update_ci_job_token_scope.mutation.graphql';
 | |
| import inboundGetCIJobTokenScopeQuery from '~/token_access/graphql/queries/inbound_get_ci_job_token_scope.query.graphql';
 | |
| import inboundGetProjectsWithCIJobTokenScopeQuery from '~/token_access/graphql/queries/inbound_get_projects_with_ci_job_token_scope.query.graphql';
 | |
| import {
 | |
|   inboundJobTokenScopeEnabledResponse,
 | |
|   inboundJobTokenScopeDisabledResponse,
 | |
|   inboundProjectsWithScopeResponse,
 | |
|   inboundAddProjectSuccessResponse,
 | |
|   inboundRemoveProjectSuccess,
 | |
|   inboundUpdateScopeSuccessResponse,
 | |
| } from './mock_data';
 | |
| 
 | |
| const projectPath = 'root/my-repo';
 | |
| const message = 'An error occurred';
 | |
| const error = new Error(message);
 | |
| 
 | |
| Vue.use(VueApollo);
 | |
| 
 | |
| jest.mock('~/flash');
 | |
| 
 | |
| describe('TokenAccess component', () => {
 | |
|   let wrapper;
 | |
| 
 | |
|   const inboundJobTokenScopeEnabledResponseHandler = jest
 | |
|     .fn()
 | |
|     .mockResolvedValue(inboundJobTokenScopeEnabledResponse);
 | |
|   const inboundJobTokenScopeDisabledResponseHandler = jest
 | |
|     .fn()
 | |
|     .mockResolvedValue(inboundJobTokenScopeDisabledResponse);
 | |
|   const inboundProjectsWithScopeResponseHandler = jest
 | |
|     .fn()
 | |
|     .mockResolvedValue(inboundProjectsWithScopeResponse);
 | |
|   const inboundAddProjectSuccessResponseHandler = jest
 | |
|     .fn()
 | |
|     .mockResolvedValue(inboundAddProjectSuccessResponse);
 | |
|   const inboundRemoveProjectSuccessHandler = jest
 | |
|     .fn()
 | |
|     .mockResolvedValue(inboundRemoveProjectSuccess);
 | |
|   const inboundUpdateScopeSuccessResponseHandler = jest
 | |
|     .fn()
 | |
|     .mockResolvedValue(inboundUpdateScopeSuccessResponse);
 | |
|   const failureHandler = jest.fn().mockRejectedValue(error);
 | |
| 
 | |
|   const findToggle = () => wrapper.findComponent(GlToggle);
 | |
|   const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
 | |
|   const findAddProjectBtn = () => wrapper.findByRole('button', { name: 'Add project' });
 | |
|   const findCancelBtn = () => wrapper.findByRole('button', { name: 'Cancel' });
 | |
|   const findProjectInput = () => wrapper.findComponent(GlFormInput);
 | |
|   const findRemoveProjectBtn = () => wrapper.findByRole('button', { name: 'Remove access' });
 | |
|   const findTokenDisabledAlert = () => wrapper.findComponent(GlAlert);
 | |
| 
 | |
|   const createMockApolloProvider = (requestHandlers) => {
 | |
|     return createMockApollo(requestHandlers);
 | |
|   };
 | |
| 
 | |
|   const createComponent = (requestHandlers, mountFn = shallowMountExtended) => {
 | |
|     wrapper = mountFn(InboundTokenAccess, {
 | |
|       provide: {
 | |
|         fullPath: projectPath,
 | |
|       },
 | |
|       apolloProvider: createMockApolloProvider(requestHandlers),
 | |
|       data() {
 | |
|         return {
 | |
|           targetProjectPath: 'root/test',
 | |
|         };
 | |
|       },
 | |
|     });
 | |
|   };
 | |
| 
 | |
|   describe('loading state', () => {
 | |
|     it('shows loading state while waiting on query to resolve', async () => {
 | |
|       createComponent([
 | |
|         [inboundGetCIJobTokenScopeQuery, inboundJobTokenScopeEnabledResponseHandler],
 | |
|         [inboundGetProjectsWithCIJobTokenScopeQuery, inboundProjectsWithScopeResponseHandler],
 | |
|       ]);
 | |
| 
 | |
|       expect(findLoadingIcon().exists()).toBe(true);
 | |
| 
 | |
|       await waitForPromises();
 | |
| 
 | |
|       expect(findLoadingIcon().exists()).toBe(false);
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('fetching projects and scope', () => {
 | |
|     it('fetches projects and scope correctly', () => {
 | |
|       const expectedVariables = {
 | |
|         fullPath: 'root/my-repo',
 | |
|       };
 | |
| 
 | |
|       createComponent([
 | |
|         [inboundGetCIJobTokenScopeQuery, inboundJobTokenScopeEnabledResponseHandler],
 | |
|         [inboundGetProjectsWithCIJobTokenScopeQuery, inboundProjectsWithScopeResponseHandler],
 | |
|       ]);
 | |
| 
 | |
|       expect(inboundJobTokenScopeEnabledResponseHandler).toHaveBeenCalledWith(expectedVariables);
 | |
|       expect(inboundProjectsWithScopeResponseHandler).toHaveBeenCalledWith(expectedVariables);
 | |
|     });
 | |
| 
 | |
|     it('handles fetch projects error correctly', async () => {
 | |
|       createComponent([
 | |
|         [inboundGetCIJobTokenScopeQuery, inboundJobTokenScopeEnabledResponseHandler],
 | |
|         [inboundGetProjectsWithCIJobTokenScopeQuery, failureHandler],
 | |
|       ]);
 | |
| 
 | |
|       await waitForPromises();
 | |
| 
 | |
|       expect(createAlert).toHaveBeenCalledWith({
 | |
|         message: 'There was a problem fetching the projects',
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     it('handles fetch scope error correctly', async () => {
 | |
|       createComponent([
 | |
|         [inboundGetCIJobTokenScopeQuery, failureHandler],
 | |
|         [inboundGetProjectsWithCIJobTokenScopeQuery, inboundProjectsWithScopeResponseHandler],
 | |
|       ]);
 | |
| 
 | |
|       await waitForPromises();
 | |
| 
 | |
|       expect(createAlert).toHaveBeenCalledWith({
 | |
|         message: 'There was a problem fetching the job token scope value',
 | |
|       });
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('toggle', () => {
 | |
|     it('the toggle is on and the alert is hidden', async () => {
 | |
|       createComponent([
 | |
|         [inboundGetCIJobTokenScopeQuery, inboundJobTokenScopeEnabledResponseHandler],
 | |
|         [inboundGetProjectsWithCIJobTokenScopeQuery, inboundProjectsWithScopeResponseHandler],
 | |
|       ]);
 | |
| 
 | |
|       await waitForPromises();
 | |
| 
 | |
|       expect(findToggle().props('value')).toBe(true);
 | |
|       expect(findTokenDisabledAlert().exists()).toBe(false);
 | |
|     });
 | |
| 
 | |
|     it('the toggle is off and the alert is visible', async () => {
 | |
|       createComponent([
 | |
|         [inboundGetCIJobTokenScopeQuery, inboundJobTokenScopeDisabledResponseHandler],
 | |
|         [inboundGetProjectsWithCIJobTokenScopeQuery, inboundProjectsWithScopeResponseHandler],
 | |
|       ]);
 | |
| 
 | |
|       await waitForPromises();
 | |
| 
 | |
|       expect(findToggle().props('value')).toBe(false);
 | |
|       expect(findTokenDisabledAlert().exists()).toBe(true);
 | |
|     });
 | |
| 
 | |
|     describe('update ci job token scope', () => {
 | |
|       it('calls inboundUpdateCIJobTokenScopeMutation mutation', async () => {
 | |
|         createComponent(
 | |
|           [
 | |
|             [inboundGetCIJobTokenScopeQuery, inboundJobTokenScopeEnabledResponseHandler],
 | |
|             [inboundUpdateCIJobTokenScopeMutation, inboundUpdateScopeSuccessResponseHandler],
 | |
|           ],
 | |
|           mountExtended,
 | |
|         );
 | |
| 
 | |
|         await waitForPromises();
 | |
| 
 | |
|         expect(findToggle().props('value')).toBe(true);
 | |
| 
 | |
|         findToggle().vm.$emit('change', false);
 | |
| 
 | |
|         await waitForPromises();
 | |
| 
 | |
|         expect(findToggle().props('value')).toBe(false);
 | |
|         expect(inboundUpdateScopeSuccessResponseHandler).toHaveBeenCalledWith({
 | |
|           input: {
 | |
|             fullPath: 'root/my-repo',
 | |
|             inboundJobTokenScopeEnabled: false,
 | |
|           },
 | |
|         });
 | |
|       });
 | |
| 
 | |
|       it('handles update scope error correctly', async () => {
 | |
|         createComponent(
 | |
|           [
 | |
|             [inboundGetCIJobTokenScopeQuery, inboundJobTokenScopeDisabledResponseHandler],
 | |
|             [inboundUpdateCIJobTokenScopeMutation, failureHandler],
 | |
|           ],
 | |
|           mountExtended,
 | |
|         );
 | |
| 
 | |
|         await waitForPromises();
 | |
| 
 | |
|         expect(findToggle().props('value')).toBe(false);
 | |
| 
 | |
|         findToggle().vm.$emit('change', true);
 | |
| 
 | |
|         await waitForPromises();
 | |
| 
 | |
|         expect(findToggle().props('value')).toBe(false);
 | |
|         expect(createAlert).toHaveBeenCalledWith({ message });
 | |
|       });
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('add project', () => {
 | |
|     it('calls add project mutation', async () => {
 | |
|       createComponent(
 | |
|         [
 | |
|           [inboundGetCIJobTokenScopeQuery, inboundJobTokenScopeEnabledResponseHandler],
 | |
|           [inboundGetProjectsWithCIJobTokenScopeQuery, inboundProjectsWithScopeResponseHandler],
 | |
|           [inboundAddProjectCIJobTokenScopeMutation, inboundAddProjectSuccessResponseHandler],
 | |
|         ],
 | |
|         mountExtended,
 | |
|       );
 | |
| 
 | |
|       await waitForPromises();
 | |
| 
 | |
|       findAddProjectBtn().trigger('click');
 | |
| 
 | |
|       expect(inboundAddProjectSuccessResponseHandler).toHaveBeenCalledWith({
 | |
|         projectPath,
 | |
|         targetProjectPath: 'root/test',
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     it('add project handles error correctly', async () => {
 | |
|       createComponent(
 | |
|         [
 | |
|           [inboundGetCIJobTokenScopeQuery, inboundJobTokenScopeEnabledResponseHandler],
 | |
|           [inboundGetProjectsWithCIJobTokenScopeQuery, inboundProjectsWithScopeResponseHandler],
 | |
|           [inboundAddProjectCIJobTokenScopeMutation, failureHandler],
 | |
|         ],
 | |
|         mountExtended,
 | |
|       );
 | |
| 
 | |
|       await waitForPromises();
 | |
| 
 | |
|       findAddProjectBtn().trigger('click');
 | |
| 
 | |
|       await waitForPromises();
 | |
| 
 | |
|       expect(createAlert).toHaveBeenCalledWith({ message });
 | |
|     });
 | |
| 
 | |
|     it('clicking cancel clears target path', async () => {
 | |
|       createComponent(
 | |
|         [
 | |
|           [inboundGetCIJobTokenScopeQuery, inboundJobTokenScopeEnabledResponseHandler],
 | |
|           [inboundGetProjectsWithCIJobTokenScopeQuery, inboundProjectsWithScopeResponseHandler],
 | |
|         ],
 | |
|         mountExtended,
 | |
|       );
 | |
| 
 | |
|       await waitForPromises();
 | |
| 
 | |
|       expect(findProjectInput().element.value).toBe('root/test');
 | |
| 
 | |
|       await findCancelBtn().trigger('click');
 | |
| 
 | |
|       expect(findProjectInput().element.value).toBe('');
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('remove project', () => {
 | |
|     it('calls remove project mutation', async () => {
 | |
|       createComponent(
 | |
|         [
 | |
|           [inboundGetCIJobTokenScopeQuery, inboundJobTokenScopeEnabledResponseHandler],
 | |
|           [inboundGetProjectsWithCIJobTokenScopeQuery, inboundProjectsWithScopeResponseHandler],
 | |
|           [inboundRemoveProjectCIJobTokenScopeMutation, inboundRemoveProjectSuccessHandler],
 | |
|         ],
 | |
|         mountExtended,
 | |
|       );
 | |
| 
 | |
|       await waitForPromises();
 | |
| 
 | |
|       findRemoveProjectBtn().trigger('click');
 | |
| 
 | |
|       expect(inboundRemoveProjectSuccessHandler).toHaveBeenCalledWith({
 | |
|         projectPath,
 | |
|         targetProjectPath: 'root/ci-project',
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     it('remove project handles error correctly', async () => {
 | |
|       createComponent(
 | |
|         [
 | |
|           [inboundGetCIJobTokenScopeQuery, inboundJobTokenScopeEnabledResponseHandler],
 | |
|           [inboundGetProjectsWithCIJobTokenScopeQuery, inboundProjectsWithScopeResponseHandler],
 | |
|           [inboundRemoveProjectCIJobTokenScopeMutation, failureHandler],
 | |
|         ],
 | |
|         mountExtended,
 | |
|       );
 | |
| 
 | |
|       await waitForPromises();
 | |
| 
 | |
|       findRemoveProjectBtn().trigger('click');
 | |
| 
 | |
|       await waitForPromises();
 | |
| 
 | |
|       expect(createAlert).toHaveBeenCalledWith({ message });
 | |
|     });
 | |
|   });
 | |
| });
 |