Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/clusters_list')
-rw-r--r--spec/frontend/clusters_list/components/agent_empty_state_spec.js16
-rw-r--r--spec/frontend/clusters_list/components/agent_table_spec.js9
-rw-r--r--spec/frontend/clusters_list/components/agents_spec.js40
-rw-r--r--spec/frontend/clusters_list/components/clusters_actions_spec.js55
-rw-r--r--spec/frontend/clusters_list/components/clusters_empty_state_spec.js104
-rw-r--r--spec/frontend/clusters_list/components/clusters_main_view_spec.js82
-rw-r--r--spec/frontend/clusters_list/components/clusters_spec.js60
-rw-r--r--spec/frontend/clusters_list/components/clusters_view_all_spec.js243
-rw-r--r--spec/frontend/clusters_list/components/install_agent_modal_spec.js38
-rw-r--r--spec/frontend/clusters_list/mocks/apollo.js47
-rw-r--r--spec/frontend/clusters_list/store/mutations_spec.js10
11 files changed, 643 insertions, 61 deletions
diff --git a/spec/frontend/clusters_list/components/agent_empty_state_spec.js b/spec/frontend/clusters_list/components/agent_empty_state_spec.js
index a548721588e..38f0e0ba2c4 100644
--- a/spec/frontend/clusters_list/components/agent_empty_state_spec.js
+++ b/spec/frontend/clusters_list/components/agent_empty_state_spec.js
@@ -1,13 +1,12 @@
import { GlAlert, GlEmptyState, GlSprintf } from '@gitlab/ui';
import AgentEmptyState from '~/clusters_list/components/agent_empty_state.vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { helpPagePath } from '~/helpers/help_page_helper';
const emptyStateImage = '/path/to/image';
const projectPath = 'path/to/project';
-const agentDocsUrl = 'path/to/agentDocs';
-const installDocsUrl = 'path/to/installDocs';
-const getStartedDocsUrl = 'path/to/getStartedDocs';
-const integrationDocsUrl = 'path/to/integrationDocs';
+const multipleClustersDocsUrl = helpPagePath('user/project/clusters/multiple_kubernetes_clusters');
+const installDocsUrl = helpPagePath('administration/clusters/kas');
describe('AgentEmptyStateComponent', () => {
let wrapper;
@@ -18,14 +17,10 @@ describe('AgentEmptyStateComponent', () => {
const provideData = {
emptyStateImage,
projectPath,
- agentDocsUrl,
- installDocsUrl,
- getStartedDocsUrl,
- integrationDocsUrl,
};
const findConfigurationsAlert = () => wrapper.findComponent(GlAlert);
- const findAgentDocsLink = () => wrapper.findByTestId('agent-docs-link');
+ const findMultipleClustersDocsLink = () => wrapper.findByTestId('multiple-clusters-docs-link');
const findInstallDocsLink = () => wrapper.findByTestId('install-docs-link');
const findIntegrationButton = () => wrapper.findByTestId('integration-primary-button');
const findEmptyState = () => wrapper.findComponent(GlEmptyState);
@@ -41,12 +36,11 @@ describe('AgentEmptyStateComponent', () => {
afterEach(() => {
if (wrapper) {
wrapper.destroy();
- wrapper = null;
}
});
it('renders correct href attributes for the links', () => {
- expect(findAgentDocsLink().attributes('href')).toBe(agentDocsUrl);
+ expect(findMultipleClustersDocsLink().attributes('href')).toBe(multipleClustersDocsUrl);
expect(findInstallDocsLink().attributes('href')).toBe(installDocsUrl);
});
diff --git a/spec/frontend/clusters_list/components/agent_table_spec.js b/spec/frontend/clusters_list/components/agent_table_spec.js
index e3b90584f29..a6d76b069cf 100644
--- a/spec/frontend/clusters_list/components/agent_table_spec.js
+++ b/spec/frontend/clusters_list/components/agent_table_spec.js
@@ -1,4 +1,4 @@
-import { GlButton, GlLink, GlIcon } from '@gitlab/ui';
+import { GlLink, GlIcon } from '@gitlab/ui';
import AgentTable from '~/clusters_list/components/agent_table.vue';
import { ACTIVE_CONNECTION_TIME } from '~/clusters_list/constants';
import { mountExtended } from 'helpers/vue_test_utils_helper';
@@ -47,7 +47,6 @@ const propsData = {
},
],
};
-const provideData = { integrationDocsUrl: 'path/to/integrationDocs' };
describe('AgentTable', () => {
let wrapper;
@@ -60,7 +59,7 @@ describe('AgentTable', () => {
wrapper.findAllByTestId('cluster-agent-configuration-link').at(at);
beforeEach(() => {
- wrapper = mountExtended(AgentTable, { propsData, provide: provideData });
+ wrapper = mountExtended(AgentTable, { propsData });
});
afterEach(() => {
@@ -70,10 +69,6 @@ describe('AgentTable', () => {
}
});
- it('displays header button', () => {
- expect(wrapper.find(GlButton).text()).toBe('Install a new GitLab Agent');
- });
-
describe('agent table', () => {
it.each`
agentName | link | lineNumber
diff --git a/spec/frontend/clusters_list/components/agents_spec.js b/spec/frontend/clusters_list/components/agents_spec.js
index 54d5ae94172..2dec7cdc973 100644
--- a/spec/frontend/clusters_list/components/agents_spec.js
+++ b/spec/frontend/clusters_list/components/agents_spec.js
@@ -14,7 +14,7 @@ localVue.use(VueApollo);
describe('Agents', () => {
let wrapper;
- const propsData = {
+ const defaultProps = {
defaultBranchName: 'default',
};
const provideData = {
@@ -22,12 +22,12 @@ describe('Agents', () => {
kasAddress: 'kas.example.com',
};
- const createWrapper = ({ agents = [], pageInfo = null, trees = [] }) => {
+ const createWrapper = ({ props = {}, agents = [], pageInfo = null, trees = [], count = 0 }) => {
const provide = provideData;
const apolloQueryResponse = {
data: {
project: {
- clusterAgents: { nodes: agents, pageInfo, tokens: { nodes: [] } },
+ clusterAgents: { nodes: agents, pageInfo, tokens: { nodes: [] }, count },
repository: { tree: { trees: { nodes: trees, pageInfo } } },
},
},
@@ -40,7 +40,10 @@ describe('Agents', () => {
wrapper = shallowMount(Agents, {
localVue,
apolloProvider,
- propsData,
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
provide: provideData,
});
@@ -54,7 +57,6 @@ describe('Agents', () => {
afterEach(() => {
if (wrapper) {
wrapper.destroy();
- wrapper = null;
}
});
@@ -81,6 +83,8 @@ describe('Agents', () => {
},
];
+ const count = 2;
+
const trees = [
{
name: 'agent-2',
@@ -121,7 +125,7 @@ describe('Agents', () => {
];
beforeEach(() => {
- return createWrapper({ agents, trees });
+ return createWrapper({ agents, count, trees });
});
it('should render agent table', () => {
@@ -133,6 +137,10 @@ describe('Agents', () => {
expect(findAgentTable().props('agents')).toMatchObject(expectedAgentsList);
});
+ it('should emit agents count to the parent component', () => {
+ expect(wrapper.emitted().onAgentsLoad).toEqual([[count]]);
+ });
+
describe('when the agent has recently connected tokens', () => {
it('should set agent status to active', () => {
expect(findAgentTable().props('agents')).toMatchObject(expectedAgentsList);
@@ -180,6 +188,20 @@ describe('Agents', () => {
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);
+ });
+ });
});
});
@@ -234,7 +256,11 @@ describe('Agents', () => {
};
beforeEach(() => {
- wrapper = shallowMount(Agents, { mocks, propsData, provide: provideData });
+ wrapper = shallowMount(Agents, {
+ mocks,
+ propsData: defaultProps,
+ provide: provideData,
+ });
return wrapper.vm.$nextTick();
});
diff --git a/spec/frontend/clusters_list/components/clusters_actions_spec.js b/spec/frontend/clusters_list/components/clusters_actions_spec.js
new file mode 100644
index 00000000000..cb8303ca4b2
--- /dev/null
+++ b/spec/frontend/clusters_list/components/clusters_actions_spec.js
@@ -0,0 +1,55 @@
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import ClustersActions from '~/clusters_list/components/clusters_actions.vue';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import { INSTALL_AGENT_MODAL_ID, CLUSTERS_ACTIONS } from '~/clusters_list/constants';
+
+describe('ClustersActionsComponent', () => {
+ let wrapper;
+
+ const newClusterPath = 'path/to/create/cluster';
+ const addClusterPath = 'path/to/connect/existing/cluster';
+
+ const provideData = {
+ newClusterPath,
+ addClusterPath,
+ };
+
+ const findDropdown = () => wrapper.findComponent(GlDropdown);
+ const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
+ const findNewClusterLink = () => wrapper.findByTestId('new-cluster-link');
+ const findConnectClusterLink = () => wrapper.findByTestId('connect-cluster-link');
+ const findConnectNewAgentLink = () => wrapper.findByTestId('connect-new-agent-link');
+
+ beforeEach(() => {
+ wrapper = shallowMountExtended(ClustersActions, {
+ provide: provideData,
+ directives: {
+ GlModalDirective: createMockDirective(),
+ },
+ });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders actions menu', () => {
+ expect(findDropdown().props('text')).toBe(CLUSTERS_ACTIONS.actionsButton);
+ });
+
+ it('renders a dropdown with 3 actions items', () => {
+ expect(findDropdownItems()).toHaveLength(3);
+ });
+
+ it('renders correct href attributes for the links', () => {
+ expect(findNewClusterLink().attributes('href')).toBe(newClusterPath);
+ expect(findConnectClusterLink().attributes('href')).toBe(addClusterPath);
+ });
+
+ it('renders correct modal id for the agent link', () => {
+ const binding = getBinding(findConnectNewAgentLink().element, 'gl-modal-directive');
+
+ expect(binding.value).toBe(INSTALL_AGENT_MODAL_ID);
+ });
+});
diff --git a/spec/frontend/clusters_list/components/clusters_empty_state_spec.js b/spec/frontend/clusters_list/components/clusters_empty_state_spec.js
new file mode 100644
index 00000000000..f7e1791d0f7
--- /dev/null
+++ b/spec/frontend/clusters_list/components/clusters_empty_state_spec.js
@@ -0,0 +1,104 @@
+import { GlEmptyState, GlButton } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import ClustersEmptyState from '~/clusters_list/components/clusters_empty_state.vue';
+import ClusterStore from '~/clusters_list/store';
+
+const clustersEmptyStateImage = 'path/to/svg';
+const newClusterPath = '/path/to/connect/cluster';
+const emptyStateHelpText = 'empty state text';
+const canAddCluster = true;
+
+describe('ClustersEmptyStateComponent', () => {
+ let wrapper;
+
+ const propsData = {
+ isChildComponent: false,
+ };
+
+ const provideData = {
+ clustersEmptyStateImage,
+ emptyStateHelpText: null,
+ newClusterPath,
+ };
+
+ const entryData = {
+ canAddCluster,
+ };
+
+ const findButton = () => wrapper.findComponent(GlButton);
+ const findEmptyStateText = () => wrapper.findByTestId('clusters-empty-state-text');
+
+ beforeEach(() => {
+ wrapper = shallowMountExtended(ClustersEmptyState, {
+ store: ClusterStore(entryData),
+ propsData,
+ provide: provideData,
+ stubs: { GlEmptyState },
+ });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('when the component is loaded independently', () => {
+ it('should render the action button', () => {
+ expect(findButton().exists()).toBe(true);
+ });
+ });
+
+ describe('when the help text is not provided', () => {
+ it('should not render the empty state text', () => {
+ expect(findEmptyStateText().exists()).toBe(false);
+ });
+ });
+
+ describe('when the component is loaded as a child component', () => {
+ beforeEach(() => {
+ propsData.isChildComponent = true;
+ wrapper = shallowMountExtended(ClustersEmptyState, {
+ store: ClusterStore(entryData),
+ propsData,
+ provide: provideData,
+ });
+ });
+
+ afterEach(() => {
+ propsData.isChildComponent = false;
+ });
+
+ it('should not render the action button', () => {
+ expect(findButton().exists()).toBe(false);
+ });
+ });
+
+ describe('when the help text is provided', () => {
+ beforeEach(() => {
+ provideData.emptyStateHelpText = emptyStateHelpText;
+ wrapper = shallowMountExtended(ClustersEmptyState, {
+ store: ClusterStore(entryData),
+ propsData,
+ provide: provideData,
+ });
+ });
+
+ it('should show the empty state text', () => {
+ expect(findEmptyStateText().text()).toBe(emptyStateHelpText);
+ });
+ });
+
+ describe('when the user cannot add clusters', () => {
+ entryData.canAddCluster = false;
+ beforeEach(() => {
+ wrapper = shallowMountExtended(ClustersEmptyState, {
+ store: ClusterStore(entryData),
+ propsData,
+ provide: provideData,
+ stubs: { GlEmptyState },
+ });
+ });
+ it('should disable the button', () => {
+ expect(findButton().props('disabled')).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/clusters_list/components/clusters_main_view_spec.js b/spec/frontend/clusters_list/components/clusters_main_view_spec.js
new file mode 100644
index 00000000000..c2233e5d39c
--- /dev/null
+++ b/spec/frontend/clusters_list/components/clusters_main_view_spec.js
@@ -0,0 +1,82 @@
+import { GlTabs, GlTab } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import ClustersMainView from '~/clusters_list/components/clusters_main_view.vue';
+import InstallAgentModal from '~/clusters_list/components/install_agent_modal.vue';
+import {
+ AGENT,
+ CERTIFICATE_BASED,
+ CLUSTERS_TABS,
+ MAX_CLUSTERS_LIST,
+ MAX_LIST_COUNT,
+} from '~/clusters_list/constants';
+
+const defaultBranchName = 'default-branch';
+
+describe('ClustersMainViewComponent', () => {
+ let wrapper;
+
+ const propsData = {
+ defaultBranchName,
+ };
+
+ beforeEach(() => {
+ wrapper = shallowMountExtended(ClustersMainView, {
+ propsData,
+ });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ const findTabs = () => wrapper.findComponent(GlTabs);
+ const findAllTabs = () => wrapper.findAllComponents(GlTab);
+ const findGlTabAtIndex = (index) => findAllTabs().at(index);
+ const findComponent = () => wrapper.findByTestId('clusters-tab-component');
+ const findModal = () => wrapper.findComponent(InstallAgentModal);
+
+ it('renders `GlTabs` with `syncActiveTabWithQueryParams` and `queryParamName` props set', () => {
+ expect(findTabs().exists()).toBe(true);
+ expect(findTabs().props('syncActiveTabWithQueryParams')).toBe(true);
+ });
+
+ it('renders correct number of tabs', () => {
+ expect(findAllTabs()).toHaveLength(CLUSTERS_TABS.length);
+ });
+
+ it('passes child-component param to the component', () => {
+ expect(findComponent().props('defaultBranchName')).toBe(defaultBranchName);
+ });
+
+ it('passes correct max-agents param to the modal', () => {
+ expect(findModal().props('maxAgents')).toBe(MAX_CLUSTERS_LIST);
+ });
+
+ describe('tabs', () => {
+ it.each`
+ tabTitle | queryParamValue | lineNumber
+ ${'All'} | ${'all'} | ${0}
+ ${'Agent'} | ${AGENT} | ${1}
+ ${'Certificate based'} | ${CERTIFICATE_BASED} | ${2}
+ `(
+ 'renders correct tab title and query param value',
+ ({ tabTitle, queryParamValue, lineNumber }) => {
+ expect(findGlTabAtIndex(lineNumber).attributes('title')).toBe(tabTitle);
+ expect(findGlTabAtIndex(lineNumber).props('queryParamValue')).toBe(queryParamValue);
+ },
+ );
+ });
+
+ describe('when the child component emits the tab change event', () => {
+ beforeEach(() => {
+ findComponent().vm.$emit('changeTab', AGENT);
+ });
+ it('changes the tab', () => {
+ expect(findTabs().attributes('value')).toBe('1');
+ });
+
+ it('passes correct max-agents param to the modal', () => {
+ expect(findModal().props('maxAgents')).toBe(MAX_LIST_COUNT);
+ });
+ });
+});
diff --git a/spec/frontend/clusters_list/components/clusters_spec.js b/spec/frontend/clusters_list/components/clusters_spec.js
index 941a3adb625..a34202c789d 100644
--- a/spec/frontend/clusters_list/components/clusters_spec.js
+++ b/spec/frontend/clusters_list/components/clusters_spec.js
@@ -8,6 +8,7 @@ import * as Sentry from '@sentry/browser';
import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import Clusters from '~/clusters_list/components/clusters.vue';
+import ClustersEmptyState from '~/clusters_list/components/clusters_empty_state.vue';
import ClusterStore from '~/clusters_list/store';
import axios from '~/lib/utils/axios_utils';
import { apiData } from '../mock_data';
@@ -18,26 +19,38 @@ describe('Clusters', () => {
let wrapper;
const endpoint = 'some/endpoint';
+ const totalClustersNumber = 6;
+ const clustersEmptyStateImage = 'path/to/svg';
+ const emptyStateHelpText = null;
+ const newClusterPath = '/path/to/new/cluster';
const entryData = {
endpoint,
imgTagsAwsText: 'AWS Icon',
imgTagsDefaultText: 'Default Icon',
imgTagsGcpText: 'GCP Icon',
+ totalClusters: totalClustersNumber,
};
- const findLoader = () => wrapper.find(GlLoadingIcon);
- const findPaginatedButtons = () => wrapper.find(GlPagination);
- const findTable = () => wrapper.find(GlTable);
+ const provideData = {
+ clustersEmptyStateImage,
+ emptyStateHelpText,
+ newClusterPath,
+ };
+
+ const findLoader = () => wrapper.findComponent(GlLoadingIcon);
+ const findPaginatedButtons = () => wrapper.findComponent(GlPagination);
+ const findTable = () => wrapper.findComponent(GlTable);
const findStatuses = () => findTable().findAll('.js-status');
+ const findEmptyState = () => wrapper.findComponent(ClustersEmptyState);
const mockPollingApi = (response, body, header) => {
mock.onGet(`${endpoint}?page=${header['x-page']}`).reply(response, body, header);
};
- const mountWrapper = () => {
+ const createWrapper = ({ propsData = {} }) => {
store = ClusterStore(entryData);
- wrapper = mount(Clusters, { store });
+ wrapper = mount(Clusters, { propsData, provide: provideData, store, stubs: { GlTable } });
return axios.waitForAll();
};
@@ -57,7 +70,7 @@ describe('Clusters', () => {
mock = new MockAdapter(axios);
mockPollingApi(200, apiData, paginationHeader());
- return mountWrapper();
+ return createWrapper({});
});
afterEach(() => {
@@ -70,7 +83,6 @@ describe('Clusters', () => {
describe('when data is loading', () => {
beforeEach(() => {
wrapper.vm.$store.state.loadingClusters = true;
- return wrapper.vm.$nextTick();
});
it('displays a loader instead of the table while loading', () => {
@@ -79,23 +91,29 @@ describe('Clusters', () => {
});
});
- it('displays a table component', () => {
- expect(findTable().exists()).toBe(true);
+ describe('when clusters are present', () => {
+ it('displays a table component', () => {
+ expect(findTable().exists()).toBe(true);
+ });
});
- it('renders the correct table headers', () => {
- const tableHeaders = wrapper.vm.fields;
- const headers = findTable().findAll('th');
-
- expect(headers.length).toBe(tableHeaders.length);
-
- tableHeaders.forEach((headerText, i) =>
- expect(headers.at(i).text()).toEqual(headerText.label),
- );
+ describe('when there are no clusters', () => {
+ beforeEach(() => {
+ wrapper.vm.$store.state.totalClusters = 0;
+ });
+ it('should render empty state', () => {
+ expect(findEmptyState().exists()).toBe(true);
+ });
});
- it('should stack on smaller devices', () => {
- expect(findTable().classes()).toContain('b-table-stacked-md');
+ describe('when is loaded as a child component', () => {
+ beforeEach(() => {
+ createWrapper({ limit: 6 });
+ });
+
+ it("shouldn't render pagination buttons", () => {
+ expect(findPaginatedButtons().exists()).toBe(false);
+ });
});
});
@@ -240,7 +258,7 @@ describe('Clusters', () => {
beforeEach(() => {
mockPollingApi(200, apiData, paginationHeader(totalFirstPage, perPage, 1));
- return mountWrapper();
+ return createWrapper({});
});
it('should load to page 1 with header values', () => {
diff --git a/spec/frontend/clusters_list/components/clusters_view_all_spec.js b/spec/frontend/clusters_list/components/clusters_view_all_spec.js
new file mode 100644
index 00000000000..6ef56beddee
--- /dev/null
+++ b/spec/frontend/clusters_list/components/clusters_view_all_spec.js
@@ -0,0 +1,243 @@
+import { GlCard, GlLoadingIcon, GlButton, GlSprintf, GlBadge } from '@gitlab/ui';
+import { createLocalVue } from '@vue/test-utils';
+import Vuex from 'vuex';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import ClustersViewAll from '~/clusters_list/components/clusters_view_all.vue';
+import Agents from '~/clusters_list/components/agents.vue';
+import Clusters from '~/clusters_list/components/clusters.vue';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import {
+ AGENT,
+ CERTIFICATE_BASED,
+ AGENT_CARD_INFO,
+ CERTIFICATE_BASED_CARD_INFO,
+ MAX_CLUSTERS_LIST,
+ INSTALL_AGENT_MODAL_ID,
+} from '~/clusters_list/constants';
+import { sprintf } from '~/locale';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+const addClusterPath = '/path/to/add/cluster';
+const defaultBranchName = 'default-branch';
+
+describe('ClustersViewAllComponent', () => {
+ let wrapper;
+
+ const event = {
+ preventDefault: jest.fn(),
+ };
+
+ const propsData = {
+ defaultBranchName,
+ };
+
+ const provideData = {
+ addClusterPath,
+ };
+
+ const entryData = {
+ loadingClusters: false,
+ totalClusters: 0,
+ };
+
+ const findCards = () => wrapper.findAllComponents(GlCard);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findAgentsComponent = () => wrapper.findComponent(Agents);
+ const findClustersComponent = () => wrapper.findComponent(Clusters);
+ const findCardsContainer = () => wrapper.findByTestId('clusters-cards-container');
+ const findAgentCardTitle = () => wrapper.findByTestId('agent-card-title');
+ const findRecommendedBadge = () => wrapper.findComponent(GlBadge);
+ const findClustersCardTitle = () => wrapper.findByTestId('clusters-card-title');
+ const findFooterButton = (line) => findCards().at(line).findComponent(GlButton);
+
+ const createStore = (initialState) =>
+ new Vuex.Store({
+ state: initialState,
+ });
+
+ const createWrapper = ({ initialState }) => {
+ wrapper = shallowMountExtended(ClustersViewAll, {
+ localVue,
+ store: createStore(initialState),
+ propsData,
+ provide: provideData,
+ directives: {
+ GlModalDirective: createMockDirective(),
+ },
+ stubs: { GlCard, GlSprintf },
+ });
+ };
+
+ beforeEach(() => {
+ createWrapper({ initialState: entryData });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('when agents and clusters are not loaded', () => {
+ const initialState = {
+ loadingClusters: true,
+ totalClusters: 0,
+ };
+ beforeEach(() => {
+ createWrapper({ initialState });
+ });
+
+ it('should show the loading icon', () => {
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
+ });
+
+ describe('when both agents and clusters are loaded', () => {
+ beforeEach(() => {
+ findAgentsComponent().vm.$emit('onAgentsLoad', 6);
+ });
+
+ it("shouldn't show the loading icon", () => {
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+
+ it('should make content visible', () => {
+ expect(findCardsContainer().isVisible()).toBe(true);
+ });
+
+ it('should render 2 cards', () => {
+ expect(findCards().length).toBe(2);
+ });
+ });
+
+ describe('agents card', () => {
+ it('should show recommended badge', () => {
+ expect(findRecommendedBadge().exists()).toBe(true);
+ });
+
+ it('should render Agents component', () => {
+ expect(findAgentsComponent().exists()).toBe(true);
+ });
+
+ it('should pass the limit prop', () => {
+ expect(findAgentsComponent().props('limit')).toBe(MAX_CLUSTERS_LIST);
+ });
+
+ it('should pass the default-branch-name prop', () => {
+ expect(findAgentsComponent().props('defaultBranchName')).toBe(defaultBranchName);
+ });
+
+ describe('when there are no agents', () => {
+ it('should show the empty title', () => {
+ expect(findAgentCardTitle().text()).toBe(AGENT_CARD_INFO.emptyTitle);
+ });
+
+ it('should show install new Agent button in the footer', () => {
+ expect(findFooterButton(0).exists()).toBe(true);
+ });
+
+ it('should render correct modal id for the agent link', () => {
+ const binding = getBinding(findFooterButton(0).element, 'gl-modal-directive');
+
+ expect(binding.value).toBe(INSTALL_AGENT_MODAL_ID);
+ });
+ });
+
+ describe('when the agents are present', () => {
+ const findFooterLink = () => wrapper.findByTestId('agents-tab-footer-link');
+ const agentsNumber = 7;
+
+ beforeEach(() => {
+ findAgentsComponent().vm.$emit('onAgentsLoad', agentsNumber);
+ });
+
+ it('should show the correct title', () => {
+ expect(findAgentCardTitle().text()).toBe(
+ sprintf(AGENT_CARD_INFO.title, { number: MAX_CLUSTERS_LIST, total: agentsNumber }),
+ );
+ });
+
+ it('should show the link to the Agents tab in the footer', () => {
+ expect(findFooterLink().exists()).toBe(true);
+ expect(findFooterLink().text()).toBe(
+ sprintf(AGENT_CARD_INFO.footerText, { number: agentsNumber }),
+ );
+ expect(findFooterLink().attributes('href')).toBe(`?tab=${AGENT}`);
+ });
+
+ describe('when clicking on the footer link', () => {
+ beforeEach(() => {
+ findFooterLink().vm.$emit('click', event);
+ });
+
+ it('should trigger tab change', () => {
+ expect(wrapper.emitted('changeTab')).toEqual([[AGENT]]);
+ });
+ });
+ });
+ });
+
+ describe('clusters tab', () => {
+ it('should pass the limit prop', () => {
+ expect(findClustersComponent().props('limit')).toBe(MAX_CLUSTERS_LIST);
+ });
+
+ it('should pass the is-child-component prop', () => {
+ expect(findClustersComponent().props('isChildComponent')).toBe(true);
+ });
+
+ describe('when there are no clusters', () => {
+ it('should show the empty title', () => {
+ expect(findClustersCardTitle().text()).toBe(CERTIFICATE_BASED_CARD_INFO.emptyTitle);
+ });
+
+ it('should show install new Agent button in the footer', () => {
+ expect(findFooterButton(1).exists()).toBe(true);
+ });
+
+ it('should render correct href for the button in the footer', () => {
+ expect(findFooterButton(1).attributes('href')).toBe(addClusterPath);
+ });
+ });
+
+ describe('when the clusters are present', () => {
+ const findFooterLink = () => wrapper.findByTestId('clusters-tab-footer-link');
+
+ const clustersNumber = 7;
+ const initialState = {
+ loadingClusters: false,
+ totalClusters: clustersNumber,
+ };
+
+ beforeEach(() => {
+ createWrapper({ initialState });
+ });
+
+ it('should show the correct title', () => {
+ expect(findClustersCardTitle().text()).toBe(
+ sprintf(CERTIFICATE_BASED_CARD_INFO.title, {
+ number: MAX_CLUSTERS_LIST,
+ total: clustersNumber,
+ }),
+ );
+ });
+
+ it('should show the link to the Clusters tab in the footer', () => {
+ expect(findFooterLink().exists()).toBe(true);
+ expect(findFooterLink().text()).toBe(
+ sprintf(CERTIFICATE_BASED_CARD_INFO.footerText, { number: clustersNumber }),
+ );
+ });
+
+ describe('when clicking on the footer link', () => {
+ beforeEach(() => {
+ findFooterLink().vm.$emit('click', event);
+ });
+
+ it('should trigger tab change', () => {
+ expect(wrapper.emitted('changeTab')).toEqual([[CERTIFICATE_BASED]]);
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/clusters_list/components/install_agent_modal_spec.js b/spec/frontend/clusters_list/components/install_agent_modal_spec.js
index 98ca5e05b3f..6c2ea45b99b 100644
--- a/spec/frontend/clusters_list/components/install_agent_modal_spec.js
+++ b/spec/frontend/clusters_list/components/install_agent_modal_spec.js
@@ -3,7 +3,8 @@ import { createLocalVue, shallowMount } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import AvailableAgentsDropdown from '~/clusters_list/components/available_agents_dropdown.vue';
import InstallAgentModal from '~/clusters_list/components/install_agent_modal.vue';
-import { I18N_INSTALL_AGENT_MODAL } from '~/clusters_list/constants';
+import { I18N_INSTALL_AGENT_MODAL, MAX_LIST_COUNT } from '~/clusters_list/constants';
+import getAgentsQuery from '~/clusters_list/graphql/queries/get_agents.query.graphql';
import createAgentMutation from '~/clusters_list/graphql/mutations/create_agent.mutation.graphql';
import createAgentTokenMutation from '~/clusters_list/graphql/mutations/create_agent_token.mutation.graphql';
import createMockApollo from 'helpers/mock_apollo_helper';
@@ -14,12 +15,17 @@ import {
createAgentErrorResponse,
createAgentTokenResponse,
createAgentTokenErrorResponse,
+ getAgentResponse,
} from '../mocks/apollo';
import ModalStub from '../stubs';
const localVue = createLocalVue();
localVue.use(VueApollo);
+const projectPath = 'path/to/project';
+const defaultBranchName = 'default';
+const maxAgents = MAX_LIST_COUNT;
+
describe('InstallAgentModal', () => {
let wrapper;
let apolloProvider;
@@ -45,10 +51,15 @@ describe('InstallAgentModal', () => {
const createWrapper = () => {
const provide = {
- projectPath: 'path/to/project',
+ projectPath,
kasAddress: 'kas.example.com',
};
+ const propsData = {
+ defaultBranchName,
+ maxAgents,
+ };
+
wrapper = shallowMount(InstallAgentModal, {
attachTo: document.body,
stubs: {
@@ -57,11 +68,26 @@ describe('InstallAgentModal', () => {
localVue,
apolloProvider,
provide,
+ propsData,
+ });
+ };
+
+ const writeQuery = () => {
+ apolloProvider.clients.defaultClient.cache.writeQuery({
+ query: getAgentsQuery,
+ variables: {
+ projectPath,
+ defaultBranchName,
+ first: MAX_LIST_COUNT,
+ last: null,
+ },
+ data: getAgentResponse.data,
});
};
const mockSelectedAgentResponse = () => {
createWrapper();
+ writeQuery();
wrapper.vm.setAgentName('agent-name');
findActionButton().vm.$emit('click');
@@ -95,7 +121,7 @@ describe('InstallAgentModal', () => {
it('renders a disabled next button', () => {
expect(findActionButton().isVisible()).toBe(true);
- expect(findActionButton().text()).toBe(i18n.next);
+ expect(findActionButton().text()).toBe(i18n.registerAgentButton);
expectDisabledAttribute(findActionButton(), true);
});
});
@@ -126,7 +152,7 @@ describe('InstallAgentModal', () => {
it('creates an agent and token', () => {
expect(createAgentHandler).toHaveBeenCalledWith({
- input: { name: 'agent-name', projectPath: 'path/to/project' },
+ input: { name: 'agent-name', projectPath },
});
expect(createAgentTokenHandler).toHaveBeenCalledWith({
@@ -134,9 +160,9 @@ describe('InstallAgentModal', () => {
});
});
- it('renders a done button', () => {
+ it('renders a close button', () => {
expect(findActionButton().isVisible()).toBe(true);
- expect(findActionButton().text()).toBe(i18n.done);
+ expect(findActionButton().text()).toBe(i18n.close);
expectDisabledAttribute(findActionButton(), false);
});
diff --git a/spec/frontend/clusters_list/mocks/apollo.js b/spec/frontend/clusters_list/mocks/apollo.js
index 27b71a0d4b5..1a7ef84a6d9 100644
--- a/spec/frontend/clusters_list/mocks/apollo.js
+++ b/spec/frontend/clusters_list/mocks/apollo.js
@@ -1,8 +1,29 @@
+const agent = {
+ id: 'agent-id',
+ name: 'agent-name',
+ webPath: 'agent-webPath',
+};
+const token = {
+ id: 'token-id',
+ lastUsedAt: null,
+};
+const tokens = {
+ nodes: [token],
+};
+const pageInfo = {
+ endCursor: '',
+ hasNextPage: false,
+ hasPreviousPage: false,
+ startCursor: '',
+};
+const count = 1;
+
export const createAgentResponse = {
data: {
createClusterAgent: {
clusterAgent: {
- id: 'agent-id',
+ ...agent,
+ tokens,
},
errors: [],
},
@@ -13,7 +34,8 @@ export const createAgentErrorResponse = {
data: {
createClusterAgent: {
clusterAgent: {
- id: 'agent-id',
+ ...agent,
+ tokens,
},
errors: ['could not create agent'],
},
@@ -23,9 +45,7 @@ export const createAgentErrorResponse = {
export const createAgentTokenResponse = {
data: {
clusterAgentTokenCreate: {
- token: {
- id: 'token-id',
- },
+ token,
secret: 'mock-agent-token',
errors: [],
},
@@ -35,11 +55,22 @@ export const createAgentTokenResponse = {
export const createAgentTokenErrorResponse = {
data: {
clusterAgentTokenCreate: {
- token: {
- id: 'token-id',
- },
+ token,
secret: 'mock-agent-token',
errors: ['could not create agent token'],
},
},
};
+
+export const getAgentResponse = {
+ data: {
+ project: {
+ clusterAgents: { nodes: [{ ...agent, tokens }], pageInfo, count },
+ repository: {
+ tree: {
+ trees: { nodes: [{ ...agent, path: null }], pageInfo },
+ },
+ },
+ },
+ },
+};
diff --git a/spec/frontend/clusters_list/store/mutations_spec.js b/spec/frontend/clusters_list/store/mutations_spec.js
index c0fe634a703..ae264eee449 100644
--- a/spec/frontend/clusters_list/store/mutations_spec.js
+++ b/spec/frontend/clusters_list/store/mutations_spec.js
@@ -26,7 +26,7 @@ describe('Admin statistics panel mutations', () => {
expect(state.clusters).toBe(apiData.clusters);
expect(state.clustersPerPage).toBe(paginationInformation.perPage);
expect(state.hasAncestorClusters).toBe(apiData.has_ancestor_clusters);
- expect(state.totalCulsters).toBe(paginationInformation.total);
+ expect(state.totalClusters).toBe(paginationInformation.total);
});
});
@@ -57,4 +57,12 @@ describe('Admin statistics panel mutations', () => {
expect(state.page).toBe(123);
});
});
+
+ describe(`${types.SET_CLUSTERS_PER_PAGE}`, () => {
+ it('changes clustersPerPage value', () => {
+ mutations[types.SET_CLUSTERS_PER_PAGE](state, 123);
+
+ expect(state.clustersPerPage).toBe(123);
+ });
+ });
});