diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-12-20 13:37:47 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-12-20 13:37:47 +0000 |
commit | aee0a117a889461ce8ced6fcf73207fe017f1d99 (patch) | |
tree | 891d9ef189227a8445d83f35c1b0fc99573f4380 /spec/frontend/clusters | |
parent | 8d46af3258650d305f53b819eabf7ab18d22f59e (diff) | |
download | gitlab-ce-aee0a117a889461ce8ced6fcf73207fe017f1d99.tar.gz |
Add latest changes from gitlab-org/gitlab@14-6-stable-eev14.6.0-rc42
Diffstat (limited to 'spec/frontend/clusters')
4 files changed, 332 insertions, 1 deletions
diff --git a/spec/frontend/clusters/agents/components/activity_events_list_spec.js b/spec/frontend/clusters/agents/components/activity_events_list_spec.js new file mode 100644 index 00000000000..4abbd77dfb7 --- /dev/null +++ b/spec/frontend/clusters/agents/components/activity_events_list_spec.js @@ -0,0 +1,102 @@ +import { GlLoadingIcon, GlAlert, GlEmptyState } from '@gitlab/ui'; +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import { useFakeDate } from 'helpers/fake_date'; +import createMockApollo from 'helpers/mock_apollo_helper'; +import waitForPromises from 'helpers/wait_for_promises'; +import ActivityEvents from '~/clusters/agents/components/activity_events_list.vue'; +import ActivityHistoryItem from '~/clusters/agents/components/activity_history_item.vue'; +import getAgentActivityEventsQuery from '~/clusters/agents/graphql/queries/get_agent_activity_events.query.graphql'; +import { mockResponse, mockEmptyResponse } from '../../mock_data'; + +const activityEmptyStateImage = '/path/to/image'; +const projectPath = 'path/to/project'; +const agentName = 'cluster-agent'; + +Vue.use(VueApollo); + +describe('ActivityEvents', () => { + let wrapper; + useFakeDate([2021, 12, 3]); + + const provideData = { + agentName, + projectPath, + activityEmptyStateImage, + }; + + const createWrapper = ({ queryResponse = null } = {}) => { + const agentEventsQueryResponse = queryResponse || jest.fn().mockResolvedValue(mockResponse); + const apolloProvider = createMockApollo([ + [getAgentActivityEventsQuery, agentEventsQueryResponse], + ]); + + wrapper = shallowMountExtended(ActivityEvents, { + apolloProvider, + provide: provideData, + }); + }; + + const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); + const findAlert = () => wrapper.findComponent(GlAlert); + const findEmptyState = () => wrapper.findComponent(GlEmptyState); + const findAllActivityHistoryItems = () => wrapper.findAllComponents(ActivityHistoryItem); + const findSectionTitle = (at) => wrapper.findAllByTestId('activity-section-title').at(at); + + afterEach(() => { + wrapper.destroy(); + }); + + describe('while the agentEvents query is loading', () => { + it('displays a loading icon', async () => { + createWrapper(); + + expect(findLoadingIcon().exists()).toBe(true); + await waitForPromises(); + expect(findLoadingIcon().exists()).toBe(false); + }); + }); + + describe('when the agentEvents query has errored', () => { + beforeEach(() => { + createWrapper({ queryResponse: jest.fn().mockRejectedValue() }); + return waitForPromises(); + }); + + it('displays an alert message', () => { + expect(findAlert().exists()).toBe(true); + }); + }); + + describe('when there are no agentEvents', () => { + beforeEach(() => { + createWrapper({ queryResponse: jest.fn().mockResolvedValue(mockEmptyResponse) }); + }); + + it('displays an empty state with the correct illustration', () => { + expect(findEmptyState().exists()).toBe(true); + expect(findEmptyState().props('svgPath')).toBe(activityEmptyStateImage); + }); + }); + + describe('when the agentEvents are present', () => { + const length = mockResponse.data?.project?.clusterAgent?.activityEvents?.nodes?.length; + + beforeEach(() => { + createWrapper(); + }); + it('renders an activity-history-item components for every event', () => { + expect(findAllActivityHistoryItems()).toHaveLength(length); + }); + + it.each` + recordedAt | date | lineNumber + ${'2021-12-03T01:06:56Z'} | ${'Today'} | ${0} + ${'2021-12-02T19:26:56Z'} | ${'Yesterday'} | ${1} + ${'2021-11-22T19:26:56Z'} | ${'2021-11-22'} | ${2} + `('renders correct titles for different days', ({ date, lineNumber }) => { + expect(findSectionTitle(lineNumber).text()).toBe(date); + }); + }); +}); diff --git a/spec/frontend/clusters/agents/components/activity_history_item_spec.js b/spec/frontend/clusters/agents/components/activity_history_item_spec.js new file mode 100644 index 00000000000..100a280d0cc --- /dev/null +++ b/spec/frontend/clusters/agents/components/activity_history_item_spec.js @@ -0,0 +1,56 @@ +import { GlSprintf } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import { sprintf } from '~/locale'; +import HistoryItem from '~/vue_shared/components/registry/history_item.vue'; +import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; +import ActivityHistoryItem from '~/clusters/agents/components/activity_history_item.vue'; +import { EVENT_DETAILS, DEFAULT_ICON } from '~/clusters/agents/constants'; +import { mockAgentHistoryActivityItems } from '../../mock_data'; + +const agentName = 'cluster-agent'; + +describe('ActivityHistoryItem', () => { + let wrapper; + + const createWrapper = ({ event = {} }) => { + wrapper = shallowMount(ActivityHistoryItem, { + propsData: { event }, + stubs: { + HistoryItem, + GlSprintf, + }, + }); + }; + + const findHistoryItem = () => wrapper.findComponent(HistoryItem); + const findTimeAgo = () => wrapper.find(TimeAgoTooltip); + + afterEach(() => { + wrapper.destroy(); + }); + + describe.each` + kind | icon | title | lineNumber + ${'token_created'} | ${EVENT_DETAILS.token_created.eventTypeIcon} | ${sprintf(EVENT_DETAILS.token_created.title, { tokenName: agentName })} | ${0} + ${'token_revoked'} | ${EVENT_DETAILS.token_revoked.eventTypeIcon} | ${sprintf(EVENT_DETAILS.token_revoked.title, { tokenName: agentName })} | ${1} + ${'agent_connected'} | ${EVENT_DETAILS.agent_connected.eventTypeIcon} | ${sprintf(EVENT_DETAILS.agent_connected.title, { titleIcon: '' })} | ${2} + ${'agent_disconnected'} | ${EVENT_DETAILS.agent_disconnected.eventTypeIcon} | ${sprintf(EVENT_DETAILS.agent_disconnected.title, { titleIcon: '' })} | ${3} + ${'agent_connected'} | ${EVENT_DETAILS.agent_connected.eventTypeIcon} | ${sprintf(EVENT_DETAILS.agent_connected.title, { titleIcon: '' })} | ${4} + ${'unknown_agent'} | ${DEFAULT_ICON} | ${'unknown_agent Event occurred'} | ${5} + `('when the event type is $kind event', ({ icon, title, lineNumber }) => { + beforeEach(() => { + const event = mockAgentHistoryActivityItems[lineNumber]; + createWrapper({ event }); + }); + it('renders the correct icon', () => { + expect(findHistoryItem().props('icon')).toBe(icon); + }); + it('renders the correct title', () => { + expect(findHistoryItem().text()).toContain(title); + }); + it('renders the correct time-ago tooltip', () => { + const activityEvents = mockAgentHistoryActivityItems; + expect(findTimeAgo().props('time')).toBe(activityEvents[lineNumber].recordedAt); + }); + }); +}); diff --git a/spec/frontend/clusters/agents/components/show_spec.js b/spec/frontend/clusters/agents/components/show_spec.js index c502e7d813e..d5a8117f48c 100644 --- a/spec/frontend/clusters/agents/components/show_spec.js +++ b/spec/frontend/clusters/agents/components/show_spec.js @@ -5,6 +5,7 @@ import VueApollo from 'vue-apollo'; import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import ClusterAgentShow from '~/clusters/agents/components/show.vue'; import TokenTable from '~/clusters/agents/components/token_table.vue'; +import ActivityEvents from '~/clusters/agents/components/activity_events_list.vue'; import getAgentQuery from '~/clusters/agents/graphql/queries/get_cluster_agent.query.graphql'; import { useFakeDate } from 'helpers/fake_date'; import createMockApollo from 'helpers/mock_apollo_helper'; @@ -27,6 +28,7 @@ describe('ClusterAgentShow', () => { id: '1', createdAt: '2021-02-13T00:00:00Z', createdByUser: { + id: 'user-1', name: 'user-1', }, name: 'token-1', @@ -39,7 +41,8 @@ describe('ClusterAgentShow', () => { const createWrapper = ({ clusterAgent, queryResponse = null }) => { const agentQueryResponse = - queryResponse || jest.fn().mockResolvedValue({ data: { project: { clusterAgent } } }); + queryResponse || + jest.fn().mockResolvedValue({ data: { project: { id: 'project-1', clusterAgent } } }); const apolloProvider = createMockApollo([[getAgentQuery, agentQueryResponse]]); wrapper = extendedWrapper( @@ -70,6 +73,7 @@ describe('ClusterAgentShow', () => { const findPaginationButtons = () => wrapper.findComponent(GlKeysetPagination); const findTokenCount = () => wrapper.findByTestId('cluster-agent-token-count').text(); const findEESecurityTabSlot = () => wrapper.findByTestId('ee-security-tab'); + const findActivity = () => wrapper.findComponent(ActivityEvents); afterEach(() => { wrapper.destroy(); @@ -101,6 +105,10 @@ describe('ClusterAgentShow', () => { it('should not render pagination buttons when there are no additional pages', () => { expect(findPaginationButtons().exists()).toBe(false); }); + + it('renders activity events list', () => { + expect(findActivity().exists()).toBe(true); + }); }); describe('when create user is unknown', () => { diff --git a/spec/frontend/clusters/mock_data.js b/spec/frontend/clusters/mock_data.js new file mode 100644 index 00000000000..75306ca0295 --- /dev/null +++ b/spec/frontend/clusters/mock_data.js @@ -0,0 +1,165 @@ +const user = { + id: 1, + name: 'Administrator', + username: 'root', + webUrl: 'http://172.31.0.1:3000/root', +}; + +const agentToken = { + id: 1, + name: 'cluster-agent', +}; + +export const defaultActivityEvent = { + kind: 'unknown_agent', + level: 'info', + recordedAt: '2021-11-22T19:26:56Z', + agentToken, + user, +}; + +export const mockAgentActivityEvents = [ + { + kind: 'token_created', + level: 'info', + recordedAt: '2021-12-03T01:06:56Z', + agentToken, + user, + }, + + { + kind: 'token_revoked', + level: 'info', + recordedAt: '2021-12-03T00:26:56Z', + agentToken, + user, + }, + + { + kind: 'agent_connected', + level: 'info', + recordedAt: '2021-12-02T19:26:56Z', + agentToken, + user, + }, + + { + kind: 'agent_disconnected', + level: 'info', + recordedAt: '2021-12-02T19:26:56Z', + agentToken, + user, + }, + + { + kind: 'agent_connected', + level: 'info', + recordedAt: '2021-11-22T19:26:56Z', + agentToken, + user, + }, + + { + kind: 'unknown_agent', + level: 'info', + recordedAt: '2021-11-22T19:26:56Z', + agentToken, + user, + }, +]; + +export const mockResponse = { + data: { + project: { + id: 'project-1', + clusterAgent: { + id: 'cluster-agent', + activityEvents: { + nodes: mockAgentActivityEvents, + }, + }, + }, + }, +}; + +export const mockEmptyResponse = { + data: { + project: { + id: 'project-1', + clusterAgent: { + id: 'cluster-agent', + activityEvents: { + nodes: [], + }, + }, + }, + }, +}; + +export const mockAgentHistoryActivityItems = [ + { + kind: 'token_created', + level: 'info', + recordedAt: '2021-12-03T01:06:56Z', + agentToken, + user, + eventTypeIcon: 'token', + title: 'cluster-agent created', + body: 'Token created by Administrator', + }, + + { + kind: 'token_revoked', + level: 'info', + recordedAt: '2021-12-03T00:26:56Z', + agentToken, + user, + eventTypeIcon: 'token', + title: 'cluster-agent revoked', + body: 'Token revoked by Administrator', + }, + + { + kind: 'agent_connected', + level: 'info', + recordedAt: '2021-12-02T19:26:56Z', + agentToken, + user, + eventTypeIcon: 'connected', + title: 'Connected', + body: 'Agent Connected', + }, + + { + kind: 'agent_disconnected', + level: 'info', + recordedAt: '2021-12-02T19:26:56Z', + agentToken, + user, + eventTypeIcon: 'connected', + title: 'Not connected', + body: 'Agent Not connected', + }, + + { + kind: 'agent_connected', + level: 'info', + recordedAt: '2021-11-22T19:26:56Z', + agentToken, + user, + eventTypeIcon: 'connected', + title: 'Connected', + body: 'Agent Connected', + }, + + { + kind: 'unknown_agent', + level: 'info', + recordedAt: '2021-11-22T19:26:56Z', + agentToken, + user, + eventTypeIcon: 'token', + title: 'unknown_agent', + body: 'Event occurred', + }, +]; |