gitlab-org--gitlab-foss/spec/frontend/runner/admin_runner_show/admin_runner_show_app_spec.js

260 lines
7.9 KiB
JavaScript

import Vue from 'vue';
import { GlTab, GlTabs } from '@gitlab/ui';
import VueApollo from 'vue-apollo';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { createAlert, VARIANT_SUCCESS } from '~/flash';
import { redirectTo } from '~/lib/utils/url_utility';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import RunnerHeader from '~/runner/components/runner_header.vue';
import RunnerDetails from '~/runner/components/runner_details.vue';
import RunnerPauseButton from '~/runner/components/runner_pause_button.vue';
import RunnerDeleteButton from '~/runner/components/runner_delete_button.vue';
import RunnerEditButton from '~/runner/components/runner_edit_button.vue';
import RunnersJobs from '~/runner/components/runner_jobs.vue';
import runnerQuery from '~/runner/graphql/show/runner.query.graphql';
import AdminRunnerShowApp from '~/runner/admin_runner_show/admin_runner_show_app.vue';
import { captureException } from '~/runner/sentry_utils';
import { saveAlertToLocalStorage } from '~/runner/local_storage_alert/save_alert_to_local_storage';
import { runnerData } from '../mock_data';
jest.mock('~/runner/local_storage_alert/save_alert_to_local_storage');
jest.mock('~/flash');
jest.mock('~/runner/sentry_utils');
jest.mock('~/lib/utils/url_utility');
const mockRunner = runnerData.data.runner;
const mockRunnerGraphqlId = mockRunner.id;
const mockRunnerId = `${getIdFromGraphQLId(mockRunnerGraphqlId)}`;
const mockRunnersPath = '/admin/runners';
Vue.use(VueApollo);
describe('AdminRunnerShowApp', () => {
let wrapper;
let mockRunnerQuery;
const findRunnerHeader = () => wrapper.findComponent(RunnerHeader);
const findRunnerDetails = () => wrapper.findComponent(RunnerDetails);
const findRunnerDeleteButton = () => wrapper.findComponent(RunnerDeleteButton);
const findRunnerEditButton = () => wrapper.findComponent(RunnerEditButton);
const findRunnerPauseButton = () => wrapper.findComponent(RunnerPauseButton);
const findRunnersJobs = () => wrapper.findComponent(RunnersJobs);
const findJobCountBadge = () => wrapper.findByTestId('job-count-badge');
const mockRunnerQueryResult = (runner = {}) => {
mockRunnerQuery = jest.fn().mockResolvedValue({
data: {
runner: { ...mockRunner, ...runner },
},
});
};
const createComponent = ({ props = {}, mountFn = shallowMountExtended, ...options } = {}) => {
wrapper = mountFn(AdminRunnerShowApp, {
apolloProvider: createMockApollo([[runnerQuery, mockRunnerQuery]]),
propsData: {
runnerId: mockRunnerId,
runnersPath: mockRunnersPath,
...props,
},
...options,
});
return waitForPromises();
};
afterEach(() => {
mockRunnerQuery.mockReset();
wrapper.destroy();
});
describe('When showing runner details', () => {
beforeEach(async () => {
mockRunnerQueryResult();
await createComponent({ mountFn: mountExtended });
});
it('expect GraphQL ID to be requested', async () => {
expect(mockRunnerQuery).toHaveBeenCalledWith({ id: mockRunnerGraphqlId });
});
it('displays the runner header', async () => {
expect(findRunnerHeader().text()).toContain(`Runner #${mockRunnerId}`);
});
it('displays the runner edit and pause buttons', async () => {
expect(findRunnerEditButton().exists()).toBe(true);
expect(findRunnerPauseButton().exists()).toBe(true);
expect(findRunnerDeleteButton().exists()).toBe(true);
});
it('shows basic runner details', async () => {
const expected = `Description Instance runner
Last contact Never contacted
Version 1.0.0
IP Address 127.0.0.1
Executor None
Architecture None
Platform darwin
Configuration Runs untagged jobs
Maximum job timeout None
Tags None`.replace(/\s+/g, ' ');
expect(wrapper.text().replace(/\s+/g, ' ')).toContain(expected);
});
describe('when runner cannot be updated', () => {
beforeEach(async () => {
mockRunnerQueryResult({
userPermissions: {
updateRunner: false,
},
});
await createComponent({
mountFn: mountExtended,
});
});
it('does not display the runner edit and pause buttons', () => {
expect(findRunnerEditButton().exists()).toBe(false);
expect(findRunnerPauseButton().exists()).toBe(false);
});
});
describe('when runner cannot be deleted', () => {
beforeEach(async () => {
mockRunnerQueryResult({
userPermissions: {
deleteRunner: false,
},
});
await createComponent({
mountFn: mountExtended,
});
});
it('does not display the runner edit and pause buttons', () => {
expect(findRunnerDeleteButton().exists()).toBe(false);
});
});
describe('when runner is deleted', () => {
beforeEach(async () => {
await createComponent({
mountFn: mountExtended,
});
});
it('redirects to the runner list page', () => {
findRunnerDeleteButton().vm.$emit('deleted', { message: 'Runner deleted' });
expect(saveAlertToLocalStorage).toHaveBeenCalledWith({
message: 'Runner deleted',
variant: VARIANT_SUCCESS,
});
expect(redirectTo).toHaveBeenCalledWith(mockRunnersPath);
});
});
describe('when runner does not have an edit url ', () => {
beforeEach(async () => {
mockRunnerQueryResult({
editAdminUrl: null,
});
await createComponent({
mountFn: mountExtended,
});
});
it('does not display the runner edit button', () => {
expect(findRunnerEditButton().exists()).toBe(false);
expect(findRunnerPauseButton().exists()).toBe(true);
});
});
});
describe('When loading', () => {
beforeEach(() => {
mockRunnerQueryResult();
createComponent();
});
it('does not show runner details', () => {
expect(findRunnerDetails().exists()).toBe(false);
});
it('does not show runner jobs', () => {
expect(findRunnersJobs().exists()).toBe(false);
});
});
describe('When there is an error', () => {
beforeEach(async () => {
mockRunnerQuery = jest.fn().mockRejectedValueOnce(new Error('Error!'));
await createComponent();
});
it('does not show runner details', () => {
expect(findRunnerDetails().exists()).toBe(false);
});
it('error is reported to sentry', () => {
expect(captureException).toHaveBeenCalledWith({
error: new Error('Error!'),
component: 'AdminRunnerShowApp',
});
});
it('error is shown to the user', () => {
expect(createAlert).toHaveBeenCalled();
});
});
describe('Jobs tab', () => {
const stubs = {
GlTab,
GlTabs,
};
it('without a runner, shows no jobs', () => {
mockRunnerQuery = jest.fn().mockResolvedValue({
data: {
runner: null,
},
});
createComponent({ stubs });
expect(findJobCountBadge().exists()).toBe(false);
expect(findRunnersJobs().exists()).toBe(false);
});
it('without a job count, shows no jobs count', async () => {
mockRunnerQueryResult({ jobCount: null });
await createComponent({ stubs });
expect(findJobCountBadge().exists()).toBe(false);
});
it('with a job count, shows jobs count', async () => {
const runner = { jobCount: 3 };
mockRunnerQueryResult(runner);
await createComponent({ stubs });
expect(findJobCountBadge().text()).toBe('3');
expect(findRunnersJobs().props('runner')).toEqual({ ...mockRunner, ...runner });
});
});
});