Files
gitlab-foss/spec/frontend/token_access/namespace_form_spec.js
2024-12-21 00:34:19 +00:00

298 lines
9.7 KiB
JavaScript

import { GlFormGroup, GlFormInput } from '@gitlab/ui';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import NamespaceForm from '~/token_access/components/namespace_form.vue';
import addNamespaceMutation from '~/token_access/graphql/mutations/inbound_add_group_or_project_ci_job_token_scope.mutation.graphql';
import editNamespaceMutation from '~/token_access/graphql/mutations/edit_namespace_job_token_scope.mutation.graphql';
import { stubComponent } from 'helpers/stub_component';
import waitForPromises from 'helpers/wait_for_promises';
import PoliciesSelector from '~/token_access/components/policies_selector.vue';
import { getSaveNamespaceHandler } from './mock_data';
Vue.use(VueApollo);
describe('Namespace form component', () => {
let wrapper;
const defaultAddMutationHandler = getSaveNamespaceHandler();
const defaultEditMutationHandler = getSaveNamespaceHandler();
const createWrapper = ({
namespace,
addMutationHandler = defaultAddMutationHandler,
editMutationHandler = defaultEditMutationHandler,
addPoliciesToCiJobToken = true,
} = {}) => {
wrapper = shallowMountExtended(NamespaceForm, {
apolloProvider: createMockApollo([
[addNamespaceMutation, addMutationHandler],
[editNamespaceMutation, editMutationHandler],
]),
propsData: { namespace },
provide: { fullPath: 'full/path', glFeatures: { addPoliciesToCiJobToken } },
stubs: {
GlFormInput: stubComponent(GlFormInput, {
props: ['autofocus', 'disabled', 'state', 'placeholder'],
}),
},
});
};
const findFormGroup = () => wrapper.findComponent(GlFormGroup);
const findFormInput = () => wrapper.findComponent(GlFormInput);
const findSubmitButton = () => wrapper.findByTestId('submit-button');
const findCancelButton = () => wrapper.findByTestId('cancel-button');
const findPoliciesSelector = () => wrapper.findComponent(PoliciesSelector);
describe('on page load', () => {
beforeEach(() => createWrapper());
describe('namespace text input', () => {
it('shows form group', () => {
expect(findFormGroup().attributes('label')).toBe('Group or project');
});
it('shows textbox', () => {
expect(findFormInput().props()).toMatchObject({
autofocus: '',
placeholder: 'full/path',
});
});
it('shows description', () => {
expect(findFormGroup().props('labelDescription')).toBe(
'Paste a group or project path to authorize access into this project.',
);
});
});
describe('policies selector', () => {
it('shows policies selector', () => {
expect(findPoliciesSelector().props()).toMatchObject({
isDefaultPermissionsSelected: true,
jobTokenPolicies: [],
disabled: false,
});
});
it('updates defaultPermissions when policies selector emits an update', async () => {
findPoliciesSelector().vm.$emit('update:isDefaultPermissionsSelected', false);
await nextTick();
expect(findPoliciesSelector().props('isDefaultPermissionsSelected')).toBe(false);
});
it('updates jobTokenPolicies when policies selector emits an update', async () => {
findPoliciesSelector().vm.$emit('update:jobTokenPolicies', ['ADMIN_JOB']);
await nextTick();
expect(findPoliciesSelector().props('jobTokenPolicies')).toEqual(['ADMIN_JOB']);
});
});
describe('Submit button', () => {
it('shows button', () => {
expect(findSubmitButton().text()).toBe('Add');
expect(findSubmitButton().props()).toMatchObject({
variant: 'confirm',
disabled: true,
loading: false,
});
});
});
describe('Cancel button', () => {
it('shows button', () => {
expect(findCancelButton().text()).toBe('Cancel');
expect(findCancelButton().props('disabled')).toBe(false);
});
it('emits close event when clicked', () => {
findCancelButton().vm.$emit('click');
expect(wrapper.emitted('close')).toHaveLength(1);
});
});
describe('when the namespace input has a value', () => {
beforeEach(() => {
findFormInput().vm.$emit('input', 'gitlab');
});
it('enables Save button', () => {
expect(findSubmitButton().props('disabled')).toBe(false);
});
describe('when the save button is clicked', () => {
beforeEach(() => {
findSubmitButton().vm.$emit('click');
});
it('runs save mutation', () => {
expect(defaultAddMutationHandler).toHaveBeenCalledTimes(1);
expect(defaultAddMutationHandler).toHaveBeenCalledWith({
projectPath: 'full/path',
targetPath: 'gitlab',
defaultPermissions: true,
jobTokenPolicies: [],
});
});
it('disables form input', () => {
expect(findFormInput().props('disabled')).toBe(true);
});
it('disables policies selector', () => {
expect(findPoliciesSelector().props('disabled')).toBe(true);
});
it('disables submit button', () => {
expect(findSubmitButton().props('loading')).toBe(true);
});
it('disables Cancel button', () => {
expect(findCancelButton().props('disabled')).toBe(true);
});
describe('when save is done', () => {
beforeEach(() => waitForPromises());
it('emits saved and close event', () => {
expect(wrapper.emitted('saved')).toHaveLength(1);
expect(wrapper.emitted('close')).toHaveLength(1);
});
it('enables form input', () => {
expect(findFormInput().props('disabled')).toBe(false);
});
it('enables policies selector', () => {
expect(findPoliciesSelector().props('disabled')).toBe(false);
});
it('enables submit button', () => {
expect(findSubmitButton().props('loading')).toBe(false);
});
it('enables Cancel button', () => {
expect(findCancelButton().props('disabled')).toBe(false);
});
});
});
});
});
describe.each`
phrase | addMutationHandler
${'when the mutation response contains an error'} | ${getSaveNamespaceHandler('some error')}
${'when the mutation throws an error'} | ${jest.fn().mockRejectedValue(new Error('some error'))}
`('$phrase', ({ addMutationHandler }) => {
beforeEach(() => {
createWrapper({ addMutationHandler });
findSubmitButton().vm.$emit('click');
return waitForPromises();
});
it('shows error message', () => {
expect(findFormGroup().attributes('invalid-feedback')).toBe('some error');
});
it('show form input error state', () => {
expect(findFormInput().props('state')).toBe(false);
});
it('enables form input', () => {
expect(findFormInput().props('disabled')).toBe(false);
});
it('enables submit button', () => {
expect(findSubmitButton().props('loading')).toBe(false);
});
it('enables Cancel button', () => {
expect(findCancelButton().props('disabled')).toBe(false);
});
describe.each`
phrase | actionFn
${'when the namespace input is changed'} | ${() => findFormInput().vm.$emit('input', 'gitlab2')}
${'when the submit button is clicked'} | ${() => findSubmitButton().vm.$emit('click')}
`('$phrase', ({ actionFn }) => {
beforeEach(() => {
actionFn();
return nextTick();
});
it('clears error message', () => {
expect(findFormGroup().attributes('invalid-feedback')).toBe('');
});
it('clears form input error state', () => {
expect(findFormInput().props('state')).toBe(true);
});
});
});
describe('when the addPoliciesToCiJobToken feature flag is disabled', () => {
beforeEach(() => createWrapper({ addPoliciesToCiJobToken: false }));
it('does not show permissions selector', () => {
expect(findPoliciesSelector().exists()).toBe(false);
});
describe('when namespace is saved', () => {
it('calls mutation without defaultPermissions or jobTokenPolicies', () => {
findFormInput().vm.$emit('input', 'gitlab');
findSubmitButton().vm.$emit('click');
expect(defaultAddMutationHandler).toHaveBeenCalledWith({
projectPath: 'full/path',
targetPath: 'gitlab',
});
});
});
});
describe('editing a namespace', () => {
beforeEach(() =>
createWrapper({
namespace: {
fullPath: 'namespace/path',
defaultPermissions: false,
jobTokenPolicies: ['READ_JOBS'],
},
}),
);
describe('path input', () => {
it('disables the input', () => {
expect(findFormInput().props('disabled')).toBe(true);
});
it('shows the namespace full path', () => {
expect(findFormInput().attributes('value')).toBe('namespace/path');
});
});
it('passes expected values to the policies selector', () => {
expect(findPoliciesSelector().props()).toMatchObject({
isDefaultPermissionsSelected: false,
jobTokenPolicies: ['READ_JOBS'],
});
});
it('shows "Save" for the submit button text', () => {
expect(findSubmitButton().text()).toBe('Save');
});
it('calls the edit mutation when the submit button is clicked', () => {
findSubmitButton().vm.$emit('click');
expect(defaultEditMutationHandler).toHaveBeenCalledTimes(1);
});
});
});