import { GlAlert, GlKeysetPagination, GlLoadingIcon } from '@gitlab/ui'; import { createLocalVue, shallowMount } from '@vue/test-utils'; import VueApollo from 'vue-apollo'; 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 } from '~/clusters_list/constants'; import getAgentsQuery from '~/clusters_list/graphql/queries/get_agents.query.graphql'; import createMockApollo from 'helpers/mock_apollo_helper'; const localVue = createLocalVue(); localVue.use(VueApollo); describe('Agents', () => { let wrapper; const propsData = { defaultBranchName: 'default', }; const provideData = { projectPath: 'path/to/project', kasAddress: 'kas.example.com', }; const createWrapper = ({ agents = [], pageInfo = null, trees = [] }) => { const provide = provideData; const apolloQueryResponse = { data: { project: { clusterAgents: { nodes: agents, pageInfo, tokens: { nodes: [] } }, repository: { tree: { trees: { nodes: trees, pageInfo } } }, }, }, }; const apolloProvider = createMockApollo([ [getAgentsQuery, jest.fn().mockResolvedValue(apolloQueryResponse, provide)], ]); wrapper = shallowMount(Agents, { localVue, apolloProvider, propsData, provide: provideData, }); return wrapper.vm.$nextTick(); }; const findAgentTable = () => wrapper.find(AgentTable); const findEmptyState = () => wrapper.find(AgentEmptyState); const findPaginationButtons = () => wrapper.find(GlKeysetPagination); afterEach(() => { if (wrapper) { wrapper.destroy(); wrapper = null; } }); describe('when there is a list of agents', () => { let testDate = new Date(); const agents = [ { id: '1', name: 'agent-1', webPath: '/agent-1', tokens: null, }, { id: '2', name: 'agent-2', webPath: '/agent-2', tokens: { nodes: [ { lastUsedAt: testDate, }, ], }, }, ]; const trees = [ { 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, 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(), tokens: { nodes: [ { lastUsedAt: testDate, }, ], }, }, ]; beforeEach(() => { return createWrapper({ agents, 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); }); 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, }); }); 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 the agent list is empty', () => { beforeEach(() => { return createWrapper({ agents: [] }); }); it('should render empty state', () => { expect(findAgentTable().exists()).toBe(false); expect(findEmptyState().exists()).toBe(true); }); }); describe('when the agent configurations are present', () => { const trees = [ { name: 'agent-1', path: '.gitlab/agents/agent-1', webPath: '/project/path/.gitlab/agents/agent-1', }, ]; beforeEach(() => { return createWrapper({ agents: [], trees }); }); it('should pass the correct hasConfigurations boolean value to empty state component', () => { expect(findEmptyState().props('hasConfigurations')).toEqual(true); }); }); describe('when agents query has errored', () => { beforeEach(() => { return createWrapper({ agents: null }); }); it('displays an alert message', () => { expect(wrapper.find(GlAlert).exists()).toBe(true); }); }); describe('when agents query is loading', () => { const mocks = { $apollo: { queries: { agents: { loading: true, }, }, }, }; beforeEach(() => { wrapper = shallowMount(Agents, { mocks, propsData, provide: provideData }); return wrapper.vm.$nextTick(); }); it('displays a loading icon', () => { expect(wrapper.find(GlLoadingIcon).exists()).toBe(true); }); }); });