341 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			341 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
| import { GlAlert, GlKeysetPagination, GlLoadingIcon, GlBanner } from '@gitlab/ui';
 | |
| import { createLocalVue, shallowMount } from '@vue/test-utils';
 | |
| import VueApollo from 'vue-apollo';
 | |
| import { nextTick } from 'vue';
 | |
| import AgentEmptyState from '~/clusters_list/components/agent_empty_state.vue';
 | |
| import AgentTable from '~/clusters_list/components/agent_table.vue';
 | |
| import Agents from '~/clusters_list/components/agents.vue';
 | |
| import {
 | |
|   ACTIVE_CONNECTION_TIME,
 | |
|   AGENT_FEEDBACK_KEY,
 | |
|   AGENT_FEEDBACK_ISSUE,
 | |
| } from '~/clusters_list/constants';
 | |
| import getAgentsQuery from '~/clusters_list/graphql/queries/get_agents.query.graphql';
 | |
| import createMockApollo from 'helpers/mock_apollo_helper';
 | |
| import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
 | |
| 
 | |
| const localVue = createLocalVue();
 | |
| localVue.use(VueApollo);
 | |
| 
 | |
| describe('Agents', () => {
 | |
|   let wrapper;
 | |
| 
 | |
|   const defaultProps = {
 | |
|     defaultBranchName: 'default',
 | |
|   };
 | |
|   const provideData = {
 | |
|     projectPath: 'path/to/project',
 | |
|   };
 | |
| 
 | |
|   const createWrapper = async ({
 | |
|     props = {},
 | |
|     glFeatures = {},
 | |
|     agents = [],
 | |
|     pageInfo = null,
 | |
|     trees = [],
 | |
|     count = 0,
 | |
|   }) => {
 | |
|     const provide = provideData;
 | |
|     const apolloQueryResponse = {
 | |
|       data: {
 | |
|         project: {
 | |
|           id: '1',
 | |
|           clusterAgents: {
 | |
|             nodes: agents,
 | |
|             pageInfo,
 | |
|             connections: { nodes: [] },
 | |
|             tokens: { nodes: [] },
 | |
|             count,
 | |
|           },
 | |
|           repository: { tree: { trees: { nodes: trees, pageInfo } } },
 | |
|         },
 | |
|       },
 | |
|     };
 | |
| 
 | |
|     const apolloProvider = createMockApollo([
 | |
|       [getAgentsQuery, jest.fn().mockResolvedValue(apolloQueryResponse, provide)],
 | |
|     ]);
 | |
| 
 | |
|     wrapper = shallowMount(Agents, {
 | |
|       localVue,
 | |
|       apolloProvider,
 | |
|       propsData: {
 | |
|         ...defaultProps,
 | |
|         ...props,
 | |
|       },
 | |
|       provide: {
 | |
|         ...provideData,
 | |
|         glFeatures,
 | |
|       },
 | |
|       stubs: {
 | |
|         GlBanner,
 | |
|         LocalStorageSync,
 | |
|       },
 | |
|     });
 | |
| 
 | |
|     await nextTick();
 | |
|   };
 | |
| 
 | |
|   const findAgentTable = () => wrapper.findComponent(AgentTable);
 | |
|   const findEmptyState = () => wrapper.findComponent(AgentEmptyState);
 | |
|   const findPaginationButtons = () => wrapper.findComponent(GlKeysetPagination);
 | |
|   const findAlert = () => wrapper.findComponent(GlAlert);
 | |
|   const findBanner = () => wrapper.findComponent(GlBanner);
 | |
| 
 | |
|   afterEach(() => {
 | |
|     wrapper.destroy();
 | |
| 
 | |
|     localStorage.removeItem(AGENT_FEEDBACK_KEY);
 | |
|   });
 | |
| 
 | |
|   describe('when there is a list of agents', () => {
 | |
|     let testDate = new Date();
 | |
|     const agents = [
 | |
|       {
 | |
|         __typename: 'ClusterAgent',
 | |
|         id: '1',
 | |
|         name: 'agent-1',
 | |
|         webPath: '/agent-1',
 | |
|         connections: null,
 | |
|         tokens: null,
 | |
|       },
 | |
|       {
 | |
|         __typename: 'ClusterAgent',
 | |
|         id: '2',
 | |
|         name: 'agent-2',
 | |
|         webPath: '/agent-2',
 | |
|         connections: null,
 | |
|         tokens: {
 | |
|           nodes: [
 | |
|             {
 | |
|               id: 'token-1',
 | |
|               lastUsedAt: testDate,
 | |
|             },
 | |
|           ],
 | |
|         },
 | |
|       },
 | |
|     ];
 | |
| 
 | |
|     const count = 2;
 | |
| 
 | |
|     const trees = [
 | |
|       {
 | |
|         id: 'tree-1',
 | |
|         name: 'agent-2',
 | |
|         path: '.gitlab/agents/agent-2',
 | |
|         webPath: '/project/path/.gitlab/agents/agent-2',
 | |
|       },
 | |
|     ];
 | |
| 
 | |
|     const expectedAgentsList = [
 | |
|       {
 | |
|         id: '1',
 | |
|         name: 'agent-1',
 | |
|         webPath: '/agent-1',
 | |
|         configFolder: undefined,
 | |
|         status: 'unused',
 | |
|         lastContact: null,
 | |
|         connections: null,
 | |
|         tokens: null,
 | |
|       },
 | |
|       {
 | |
|         id: '2',
 | |
|         name: 'agent-2',
 | |
|         configFolder: {
 | |
|           name: 'agent-2',
 | |
|           path: '.gitlab/agents/agent-2',
 | |
|           webPath: '/project/path/.gitlab/agents/agent-2',
 | |
|         },
 | |
|         webPath: '/agent-2',
 | |
|         status: 'active',
 | |
|         lastContact: new Date(testDate).getTime(),
 | |
|         connections: null,
 | |
|         tokens: {
 | |
|           nodes: [
 | |
|             {
 | |
|               lastUsedAt: testDate,
 | |
|             },
 | |
|           ],
 | |
|         },
 | |
|       },
 | |
|     ];
 | |
| 
 | |
|     beforeEach(() => {
 | |
|       return createWrapper({ agents, count, trees });
 | |
|     });
 | |
| 
 | |
|     it('should render agent table', () => {
 | |
|       expect(findAgentTable().exists()).toBe(true);
 | |
|       expect(findEmptyState().exists()).toBe(false);
 | |
|     });
 | |
| 
 | |
|     it('should pass agent and folder info to table component', () => {
 | |
|       expect(findAgentTable().props('agents')).toMatchObject(expectedAgentsList);
 | |
|     });
 | |
| 
 | |
|     it('should emit agents count to the parent component', () => {
 | |
|       expect(wrapper.emitted().onAgentsLoad).toEqual([[count]]);
 | |
|     });
 | |
| 
 | |
|     describe.each`
 | |
|       featureFlagEnabled | localStorageItemExists | bannerShown
 | |
|       ${true}            | ${false}               | ${true}
 | |
|       ${true}            | ${true}                | ${false}
 | |
|       ${false}           | ${true}                | ${false}
 | |
|       ${false}           | ${false}               | ${false}
 | |
|     `(
 | |
|       'when the feature flag enabled is $featureFlagEnabled and dismissed localStorage item exists is $localStorageItemExists',
 | |
|       ({ featureFlagEnabled, localStorageItemExists, bannerShown }) => {
 | |
|         const glFeatures = {
 | |
|           showGitlabAgentFeedback: featureFlagEnabled,
 | |
|         };
 | |
|         beforeEach(() => {
 | |
|           if (localStorageItemExists) {
 | |
|             localStorage.setItem(AGENT_FEEDBACK_KEY, true);
 | |
|           }
 | |
| 
 | |
|           return createWrapper({ glFeatures, agents, count, trees });
 | |
|         });
 | |
| 
 | |
|         it(`should ${bannerShown ? 'show' : 'hide'} the feedback banner`, () => {
 | |
|           expect(findBanner().exists()).toBe(bannerShown);
 | |
|         });
 | |
|       },
 | |
|     );
 | |
| 
 | |
|     describe('when the agent feedback banner is present', () => {
 | |
|       const glFeatures = {
 | |
|         showGitlabAgentFeedback: true,
 | |
|       };
 | |
|       beforeEach(() => {
 | |
|         return createWrapper({ glFeatures, agents, count, trees });
 | |
|       });
 | |
| 
 | |
|       it('should render the correct title', () => {
 | |
|         expect(findBanner().props('title')).toBe('Tell us what you think');
 | |
|       });
 | |
| 
 | |
|       it('should render the correct issue link', () => {
 | |
|         expect(findBanner().props('buttonLink')).toBe(AGENT_FEEDBACK_ISSUE);
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     describe('when the agent has recently connected tokens', () => {
 | |
|       it('should set agent status to active', () => {
 | |
|         expect(findAgentTable().props('agents')).toMatchObject(expectedAgentsList);
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     describe('when the agent has tokens connected more then 8 minutes ago', () => {
 | |
|       const now = new Date();
 | |
|       testDate = new Date(now.getTime() - ACTIVE_CONNECTION_TIME);
 | |
|       it('should set agent status to inactive', () => {
 | |
|         expect(findAgentTable().props('agents')).toMatchObject(expectedAgentsList);
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     describe('when the agent has no connected tokens', () => {
 | |
|       testDate = null;
 | |
|       it('should set agent status to unused', () => {
 | |
|         expect(findAgentTable().props('agents')).toMatchObject(expectedAgentsList);
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     it('should not render pagination buttons when there are no additional pages', () => {
 | |
|       expect(findPaginationButtons().exists()).toBe(false);
 | |
|     });
 | |
| 
 | |
|     describe('when the list has additional pages', () => {
 | |
|       const pageInfo = {
 | |
|         hasNextPage: true,
 | |
|         hasPreviousPage: false,
 | |
|         startCursor: 'prev',
 | |
|         endCursor: 'next',
 | |
|       };
 | |
| 
 | |
|       beforeEach(() => {
 | |
|         return createWrapper({
 | |
|           agents,
 | |
|           pageInfo: {
 | |
|             ...pageInfo,
 | |
|             __typename: 'PageInfo',
 | |
|           },
 | |
|         });
 | |
|       });
 | |
| 
 | |
|       it('should render pagination buttons', () => {
 | |
|         expect(findPaginationButtons().exists()).toBe(true);
 | |
|       });
 | |
| 
 | |
|       it('should pass pageInfo to the pagination component', () => {
 | |
|         expect(findPaginationButtons().props()).toMatchObject(pageInfo);
 | |
|       });
 | |
| 
 | |
|       describe('when limit is passed from the parent component', () => {
 | |
|         beforeEach(() => {
 | |
|           return createWrapper({
 | |
|             props: { limit: 6 },
 | |
|             agents,
 | |
|             pageInfo,
 | |
|           });
 | |
|         });
 | |
| 
 | |
|         it('should not render pagination buttons', () => {
 | |
|           expect(findPaginationButtons().exists()).toBe(false);
 | |
|         });
 | |
|       });
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('when the agent list is empty', () => {
 | |
|     beforeEach(() => {
 | |
|       return createWrapper({ agents: [] });
 | |
|     });
 | |
| 
 | |
|     it('should render empty state', () => {
 | |
|       expect(findAgentTable().exists()).toBe(false);
 | |
|       expect(findEmptyState().exists()).toBe(true);
 | |
|     });
 | |
| 
 | |
|     it('should not show agent feedback alert', () => {
 | |
|       expect(findAlert().exists()).toBe(false);
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('when agents query has errored', () => {
 | |
|     beforeEach(() => {
 | |
|       return createWrapper({ agents: null });
 | |
|     });
 | |
| 
 | |
|     it('displays an alert message', () => {
 | |
|       expect(findAlert().text()).toBe('An error occurred while loading your agents');
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('when agents query is loading', () => {
 | |
|     const mocks = {
 | |
|       $apollo: {
 | |
|         queries: {
 | |
|           agents: {
 | |
|             loading: true,
 | |
|           },
 | |
|         },
 | |
|       },
 | |
|     };
 | |
| 
 | |
|     beforeEach(async () => {
 | |
|       wrapper = shallowMount(Agents, {
 | |
|         mocks,
 | |
|         propsData: defaultProps,
 | |
|         provide: provideData,
 | |
|       });
 | |
| 
 | |
|       await nextTick();
 | |
|     });
 | |
| 
 | |
|     it('displays a loading icon', () => {
 | |
|       expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
 | |
|     });
 | |
|   });
 | |
| });
 |