2022-06-21 17:19:12 +05:30
|
|
|
import Vue from 'vue';
|
2022-08-27 11:52:29 +05:30
|
|
|
import { GlModal, GlSprintf } from '@gitlab/ui';
|
2022-06-21 17:19:12 +05:30
|
|
|
import VueApollo from 'vue-apollo';
|
2022-08-27 11:52:29 +05:30
|
|
|
import { createAlert } from '~/flash';
|
|
|
|
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
|
2022-06-21 17:19:12 +05:30
|
|
|
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
2022-08-27 11:52:29 +05:30
|
|
|
import { s__ } from '~/locale';
|
2022-06-21 17:19:12 +05:30
|
|
|
import RunnerBulkDelete from '~/runner/components/runner_bulk_delete.vue';
|
|
|
|
import createMockApollo from 'helpers/mock_apollo_helper';
|
2022-08-27 11:52:29 +05:30
|
|
|
import BulkRunnerDeleteMutation from '~/runner/graphql/list/bulk_runner_delete.mutation.graphql';
|
2022-06-21 17:19:12 +05:30
|
|
|
import { createLocalState } from '~/runner/graphql/list/local_state';
|
|
|
|
import waitForPromises from 'helpers/wait_for_promises';
|
2022-08-27 11:52:29 +05:30
|
|
|
import { allRunnersData } from '../mock_data';
|
2022-06-21 17:19:12 +05:30
|
|
|
|
|
|
|
Vue.use(VueApollo);
|
|
|
|
|
2022-08-27 11:52:29 +05:30
|
|
|
jest.mock('~/flash');
|
2022-06-21 17:19:12 +05:30
|
|
|
|
|
|
|
describe('RunnerBulkDelete', () => {
|
|
|
|
let wrapper;
|
2022-08-27 11:52:29 +05:30
|
|
|
let apolloCache;
|
2022-06-21 17:19:12 +05:30
|
|
|
let mockState;
|
|
|
|
let mockCheckedRunnerIds;
|
|
|
|
|
2022-08-27 11:52:29 +05:30
|
|
|
const findClearBtn = () => wrapper.findByText(s__('Runners|Clear selection'));
|
|
|
|
const findDeleteBtn = () => wrapper.findByText(s__('Runners|Delete selected'));
|
|
|
|
const findModal = () => wrapper.findComponent(GlModal);
|
|
|
|
|
|
|
|
const mockRunners = allRunnersData.data.runners.nodes;
|
|
|
|
const mockId1 = allRunnersData.data.runners.nodes[0].id;
|
|
|
|
const mockId2 = allRunnersData.data.runners.nodes[1].id;
|
|
|
|
|
|
|
|
const bulkRunnerDeleteHandler = jest.fn();
|
2022-06-21 17:19:12 +05:30
|
|
|
|
|
|
|
const createComponent = () => {
|
|
|
|
const { cacheConfig, localMutations } = mockState;
|
2022-08-27 11:52:29 +05:30
|
|
|
const apolloProvider = createMockApollo(
|
|
|
|
[[BulkRunnerDeleteMutation, bulkRunnerDeleteHandler]],
|
|
|
|
undefined,
|
|
|
|
cacheConfig,
|
|
|
|
);
|
2022-06-21 17:19:12 +05:30
|
|
|
|
|
|
|
wrapper = shallowMountExtended(RunnerBulkDelete, {
|
2022-08-27 11:52:29 +05:30
|
|
|
apolloProvider,
|
2022-06-21 17:19:12 +05:30
|
|
|
provide: {
|
|
|
|
localMutations,
|
|
|
|
},
|
2022-08-27 11:52:29 +05:30
|
|
|
propsData: {
|
|
|
|
runners: mockRunners,
|
|
|
|
},
|
|
|
|
directives: {
|
|
|
|
GlTooltip: createMockDirective(),
|
|
|
|
},
|
2022-06-21 17:19:12 +05:30
|
|
|
stubs: {
|
|
|
|
GlSprintf,
|
2022-08-27 11:52:29 +05:30
|
|
|
GlModal,
|
2022-06-21 17:19:12 +05:30
|
|
|
},
|
|
|
|
});
|
2022-08-27 11:52:29 +05:30
|
|
|
|
|
|
|
apolloCache = apolloProvider.defaultClient.cache;
|
|
|
|
jest.spyOn(apolloCache, 'evict');
|
|
|
|
jest.spyOn(apolloCache, 'gc');
|
2022-06-21 17:19:12 +05:30
|
|
|
};
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
mockState = createLocalState();
|
|
|
|
|
|
|
|
jest
|
|
|
|
.spyOn(mockState.cacheConfig.typePolicies.Query.fields, 'checkedRunnerIds')
|
|
|
|
.mockImplementation(() => mockCheckedRunnerIds);
|
|
|
|
});
|
|
|
|
|
|
|
|
afterEach(() => {
|
2022-08-27 11:52:29 +05:30
|
|
|
bulkRunnerDeleteHandler.mockReset();
|
2022-06-21 17:19:12 +05:30
|
|
|
wrapper.destroy();
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('When no runners are checked', () => {
|
|
|
|
beforeEach(async () => {
|
|
|
|
mockCheckedRunnerIds = [];
|
|
|
|
|
|
|
|
createComponent();
|
|
|
|
|
|
|
|
await waitForPromises();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('shows no contents', () => {
|
|
|
|
expect(wrapper.html()).toBe('');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe.each`
|
2022-08-27 11:52:29 +05:30
|
|
|
count | ids | text
|
|
|
|
${1} | ${[mockId1]} | ${'1 runner'}
|
|
|
|
${2} | ${[mockId1, mockId2]} | ${'2 runners'}
|
|
|
|
`('When $count runner(s) are checked', ({ ids, text }) => {
|
2022-06-21 17:19:12 +05:30
|
|
|
beforeEach(() => {
|
|
|
|
mockCheckedRunnerIds = ids;
|
|
|
|
|
|
|
|
createComponent();
|
|
|
|
|
|
|
|
jest.spyOn(mockState.localMutations, 'clearChecked').mockImplementation(() => {});
|
|
|
|
});
|
|
|
|
|
|
|
|
it(`shows "${text}"`, () => {
|
|
|
|
expect(wrapper.text()).toContain(text);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('clears selection', () => {
|
|
|
|
expect(mockState.localMutations.clearChecked).toHaveBeenCalledTimes(0);
|
|
|
|
|
|
|
|
findClearBtn().vm.$emit('click');
|
|
|
|
|
|
|
|
expect(mockState.localMutations.clearChecked).toHaveBeenCalledTimes(1);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('shows confirmation modal', () => {
|
2022-08-27 11:52:29 +05:30
|
|
|
const modalId = getBinding(findDeleteBtn().element, 'gl-modal');
|
|
|
|
|
|
|
|
expect(findModal().props('modal-id')).toBe(modalId);
|
|
|
|
expect(findModal().text()).toContain(text);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('when runners are deleted', () => {
|
|
|
|
let evt;
|
|
|
|
let mockHideModal;
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
mockCheckedRunnerIds = [mockId1, mockId2];
|
|
|
|
|
|
|
|
createComponent();
|
|
|
|
|
|
|
|
jest.spyOn(mockState.localMutations, 'clearChecked').mockImplementation(() => {});
|
|
|
|
mockHideModal = jest.spyOn(findModal().vm, 'hide');
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('when deletion is successful', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
bulkRunnerDeleteHandler.mockResolvedValue({
|
|
|
|
data: {
|
|
|
|
bulkRunnerDelete: { deletedIds: mockCheckedRunnerIds, errors: [] },
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
evt = {
|
|
|
|
preventDefault: jest.fn(),
|
|
|
|
};
|
|
|
|
findModal().vm.$emit('primary', evt);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('has loading state', async () => {
|
|
|
|
expect(findModal().props('actionPrimary').attributes.loading).toBe(true);
|
|
|
|
expect(findModal().props('actionCancel').attributes.loading).toBe(true);
|
|
|
|
|
|
|
|
await waitForPromises();
|
|
|
|
|
|
|
|
expect(findModal().props('actionPrimary').attributes.loading).toBe(false);
|
|
|
|
expect(findModal().props('actionCancel').attributes.loading).toBe(false);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('modal is not prevented from closing', () => {
|
|
|
|
expect(evt.preventDefault).toHaveBeenCalledTimes(1);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('mutation is called', async () => {
|
|
|
|
expect(bulkRunnerDeleteHandler).toHaveBeenCalledWith({
|
|
|
|
input: { ids: mockCheckedRunnerIds },
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('user interface is updated', async () => {
|
|
|
|
const { evict, gc } = apolloCache;
|
|
|
|
|
|
|
|
expect(evict).toHaveBeenCalledTimes(mockCheckedRunnerIds.length);
|
|
|
|
expect(evict).toHaveBeenCalledWith({
|
|
|
|
id: expect.stringContaining(mockCheckedRunnerIds[0]),
|
|
|
|
});
|
|
|
|
expect(evict).toHaveBeenCalledWith({
|
|
|
|
id: expect.stringContaining(mockCheckedRunnerIds[1]),
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(gc).toHaveBeenCalledTimes(1);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('modal is hidden', () => {
|
|
|
|
expect(mockHideModal).toHaveBeenCalledTimes(1);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('when deletion fails', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
bulkRunnerDeleteHandler.mockRejectedValue(new Error('error!'));
|
|
|
|
|
|
|
|
evt = {
|
|
|
|
preventDefault: jest.fn(),
|
|
|
|
};
|
|
|
|
findModal().vm.$emit('primary', evt);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('has loading state', async () => {
|
|
|
|
expect(findModal().props('actionPrimary').attributes.loading).toBe(true);
|
|
|
|
expect(findModal().props('actionCancel').attributes.loading).toBe(true);
|
|
|
|
|
|
|
|
await waitForPromises();
|
|
|
|
|
|
|
|
expect(findModal().props('actionPrimary').attributes.loading).toBe(false);
|
|
|
|
expect(findModal().props('actionCancel').attributes.loading).toBe(false);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('modal is not prevented from closing', () => {
|
|
|
|
expect(evt.preventDefault).toHaveBeenCalledTimes(1);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('mutation is called', () => {
|
|
|
|
expect(bulkRunnerDeleteHandler).toHaveBeenCalledWith({
|
|
|
|
input: { ids: mockCheckedRunnerIds },
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('user interface is not updated', async () => {
|
|
|
|
await waitForPromises();
|
2022-06-21 17:19:12 +05:30
|
|
|
|
2022-08-27 11:52:29 +05:30
|
|
|
const { evict, gc } = apolloCache;
|
2022-06-21 17:19:12 +05:30
|
|
|
|
2022-08-27 11:52:29 +05:30
|
|
|
expect(evict).not.toHaveBeenCalled();
|
|
|
|
expect(gc).not.toHaveBeenCalled();
|
|
|
|
expect(mockState.localMutations.clearChecked).not.toHaveBeenCalled();
|
|
|
|
});
|
2022-06-21 17:19:12 +05:30
|
|
|
|
2022-08-27 11:52:29 +05:30
|
|
|
it('alert is called', async () => {
|
|
|
|
await waitForPromises();
|
2022-06-21 17:19:12 +05:30
|
|
|
|
2022-08-27 11:52:29 +05:30
|
|
|
expect(createAlert).toHaveBeenCalled();
|
|
|
|
expect(createAlert).toHaveBeenCalledWith({
|
|
|
|
message: expect.any(String),
|
|
|
|
captureError: true,
|
|
|
|
error: expect.any(Error),
|
|
|
|
});
|
|
|
|
});
|
2022-06-21 17:19:12 +05:30
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|