gitlab-org--gitlab-foss/spec/frontend/clusters_list/components/delete_agent_button_spec.js

251 lines
7.7 KiB
JavaScript

import { GlButton, GlModal, GlFormInput } from '@gitlab/ui';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { ENTER_KEY } from '~/lib/utils/keys';
import getAgentsQuery from '~/clusters_list/graphql/queries/get_agents.query.graphql';
import deleteAgentMutation from '~/clusters_list/graphql/mutations/delete_agent.mutation.graphql';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import DeleteAgentButton from '~/clusters_list/components/delete_agent_button.vue';
import { MAX_LIST_COUNT, DELETE_AGENT_BUTTON } from '~/clusters_list/constants';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { getAgentResponse, mockDeleteResponse, mockErrorDeleteResponse } from '../mocks/apollo';
Vue.use(VueApollo);
const projectPath = 'path/to/project';
const defaultBranchName = 'default';
const maxAgents = MAX_LIST_COUNT;
const agent = {
id: 'agent-id',
name: 'agent-name',
webPath: 'agent-webPath',
};
describe('DeleteAgentButton', () => {
let wrapper;
let toast;
let apolloProvider;
let deleteResponse;
const findModal = () => wrapper.findComponent(GlModal);
const findDeleteBtn = () => wrapper.findComponent(GlButton);
const findInput = () => wrapper.findComponent(GlFormInput);
const findPrimaryAction = () => findModal().props('actionPrimary');
const findPrimaryActionAttributes = (attr) => findPrimaryAction().attributes[0][attr];
const findDeleteAgentButtonTooltip = () => wrapper.findByTestId('delete-agent-button-tooltip');
const getTooltipText = (el) => {
const binding = getBinding(el, 'gl-tooltip');
return binding.value;
};
const createMockApolloProvider = ({ mutationResponse }) => {
deleteResponse = jest.fn().mockResolvedValue(mutationResponse);
return createMockApollo([[deleteAgentMutation, deleteResponse]]);
};
const writeQuery = () => {
apolloProvider.clients.defaultClient.cache.writeQuery({
query: getAgentsQuery,
variables: {
projectPath,
defaultBranchName,
first: maxAgents,
last: null,
},
data: getAgentResponse.data,
});
};
const createWrapper = async ({
mutationResponse = mockDeleteResponse,
provideData = {},
} = {}) => {
apolloProvider = createMockApolloProvider({ mutationResponse });
const defaultProvide = {
projectPath,
canAdminCluster: true,
};
const propsData = {
defaultBranchName,
maxAgents,
agent,
};
toast = jest.fn();
wrapper = shallowMountExtended(DeleteAgentButton, {
apolloProvider,
provide: {
...defaultProvide,
...provideData,
},
directives: {
GlTooltip: createMockDirective(),
},
propsData,
mocks: { $toast: { show: toast } },
stubs: { GlModal },
});
wrapper.vm.$refs.modal.hide = jest.fn();
writeQuery();
await nextTick();
};
const submitAgentToDelete = async () => {
findDeleteBtn().vm.$emit('click');
findInput().vm.$emit('input', agent.name);
await findModal().vm.$emit('primary');
await waitForPromises();
};
beforeEach(() => {
return createWrapper({});
});
afterEach(() => {
wrapper.destroy();
apolloProvider = null;
deleteResponse = null;
toast = null;
});
describe('delete agent action', () => {
it('displays a delete button', () => {
expect(findDeleteBtn().attributes('aria-label')).toBe(DELETE_AGENT_BUTTON.deleteButton);
});
it('shows a tooltip for the button', () => {
expect(getTooltipText(findDeleteAgentButtonTooltip().element)).toBe(
DELETE_AGENT_BUTTON.deleteButton,
);
});
describe('when clicking the delete button', () => {
beforeEach(() => {
findDeleteBtn().vm.$emit('click');
});
it('displays a delete confirmation modal', () => {
expect(findModal().isVisible()).toBe(true);
});
});
describe('when user cannot delete clusters', () => {
beforeEach(() => {
createWrapper({ provideData: { canAdminCluster: false } });
});
it('disables the button', () => {
expect(findDeleteBtn().attributes('disabled')).toBe('true');
});
it('shows a disabled tooltip', () => {
expect(getTooltipText(findDeleteAgentButtonTooltip().element)).toBe(
DELETE_AGENT_BUTTON.disabledHint,
);
});
});
describe.each`
condition | agentName | isDisabled | mutationCalled
${'the input with agent name is missing'} | ${''} | ${true} | ${false}
${'the input with agent name is incorrect'} | ${'wrong-name'} | ${true} | ${false}
${'the input with agent name is correct'} | ${agent.name} | ${false} | ${true}
`('when $condition', ({ agentName, isDisabled, mutationCalled }) => {
beforeEach(() => {
findDeleteBtn().vm.$emit('click');
findInput().vm.$emit('input', agentName);
});
it(`${isDisabled ? 'disables' : 'enables'} the modal primary button`, () => {
expect(findPrimaryActionAttributes('disabled')).toBe(isDisabled);
});
describe('when user clicks the modal primary button', () => {
beforeEach(async () => {
await findModal().vm.$emit('primary');
});
if (mutationCalled) {
it('calls the delete mutation', () => {
expect(deleteResponse).toHaveBeenCalledWith({ input: { id: agent.id } });
});
} else {
it("doesn't call the delete mutation", () => {
expect(deleteResponse).not.toHaveBeenCalled();
});
}
});
describe('when user presses the enter button', () => {
beforeEach(async () => {
await findInput().vm.$emit('keydown', new KeyboardEvent({ key: ENTER_KEY }));
});
if (mutationCalled) {
it('calls the delete mutation', () => {
expect(deleteResponse).toHaveBeenCalledWith({ input: { id: agent.id } });
});
} else {
it("doesn't call the delete mutation", () => {
expect(deleteResponse).not.toHaveBeenCalled();
});
}
});
});
describe('when agent was deleted successfully', () => {
beforeEach(async () => {
await submitAgentToDelete();
});
it('calls the toast action', () => {
expect(toast).toHaveBeenCalledWith(`${agent.name} successfully deleted`);
});
});
});
describe('when getting an error deleting agent', () => {
beforeEach(async () => {
await createWrapper({ mutationResponse: mockErrorDeleteResponse });
await submitAgentToDelete();
});
it('displays the error message', () => {
expect(toast).toHaveBeenCalledWith('could not delete agent');
});
});
describe('when the delete modal was closed', () => {
beforeEach(async () => {
const loadingResponse = new Promise(() => {});
await createWrapper({ mutationResponse: loadingResponse });
await submitAgentToDelete();
});
it('reenables the button', async () => {
expect(findPrimaryActionAttributes('loading')).toBe(true);
expect(findDeleteBtn().attributes('disabled')).toBe('true');
await findModal().vm.$emit('hide');
expect(findPrimaryActionAttributes('loading')).toBe(false);
expect(findDeleteBtn().attributes('disabled')).toBeUndefined();
});
it('clears the agent name input', async () => {
expect(findInput().attributes('value')).toBe(agent.name);
await findModal().vm.$emit('hide');
expect(findInput().attributes('value')).toBeUndefined();
});
});
});