import { CompassComponentType, CompassLinkType, CreateLinkInput, } from '@atlassian/forge-graphql-types'; import { MAX_NAME_LENGTH } from '../../helpers/constants'; // eslint-disable-next-line max-len import { AdditionalLinksValidator } from '../../requests/config-as-code-requests/helpers/append-links/additional-links-validator'; describe('AdditionalLinksValidator', () => { let additionalLinksValidator: AdditionalLinksValidator; beforeEach(() => { additionalLinksValidator = new AdditionalLinksValidator(); }); describe('Keys validation', () => { test('Adds error if mandatory property is missing', () => { const mockLinkWithoutUrl = { type: CompassLinkType.Repository, }; additionalLinksValidator.validateLinkKeys( mockLinkWithoutUrl as CreateLinkInput, CompassComponentType.Service, 1, ); const expectedError = '"url" must be included in the additional link'; expect(additionalLinksValidator.errors).toContain(expectedError); }); test('Adds error if link has invalid property', () => { const mockLinkWithInvalidProperty = { type: CompassLinkType.Repository, url: 'https://test', invalidKey: 'invalidKey', }; additionalLinksValidator.validateLinkKeys( mockLinkWithInvalidProperty, CompassComponentType.Service, 1, ); const expectedError = '"invalidKey" of additional link must be one of the following keys: url, type, name'; expect(additionalLinksValidator.errors).toContain(expectedError); }); test('Adds error if link URL is invalid', () => { const mockLinkWithInvalidUrl = { type: CompassLinkType.Repository, url: 'invalid URL', }; additionalLinksValidator.validateLinkKeys( mockLinkWithInvalidUrl, CompassComponentType.Service, 1, ); const expectedError = 'URL of additional link is not valid'; expect(additionalLinksValidator.errors).toContain(expectedError); }); test('Adds error if link URL scheme is invalid', () => { const mockLinkWithoutUrl = { type: CompassLinkType.Repository, // eslint-disable-next-line no-script-url url: 'javascript://test', }; additionalLinksValidator.validateLinkKeys( mockLinkWithoutUrl, CompassComponentType.Service, 1, ); const expectedError = 'URL scheme "javascript:" is not allowed in additional link'; expect(additionalLinksValidator.errors).toContain(expectedError); }); test('Adds error if type value is not string', () => { const invalidType = 1; const mockLinkWithInvalidType = { type: invalidType, url: 'https://test', }; additionalLinksValidator.validateLinkKeys( mockLinkWithInvalidType as unknown as CreateLinkInput, CompassComponentType.Service, 1, ); const expectedError = `"${invalidType}" is not a valid additional link type. ` + 'The accepted values are: DOCUMENT, CHAT_CHANNEL, REPOSITORY, PROJECT, DASHBOARD, OTHER_LINK, ON_CALL'; expect(additionalLinksValidator.errors).toContain(expectedError); }); test('Adds error if type value is not valid CompassComponentType', () => { const mockLinkWithInvalidType = { type: 'Not a compass type', url: 'https://test', }; additionalLinksValidator.validateLinkKeys( mockLinkWithInvalidType as unknown as CreateLinkInput, CompassComponentType.Service, 1, ); const expectedError = '"Not a compass type" is not a valid additional link type. ' + 'The accepted values are: DOCUMENT, CHAT_CHANNEL, REPOSITORY, PROJECT, DASHBOARD, OTHER_LINK, ON_CALL'; expect(additionalLinksValidator.errors).toContain(expectedError); }); test('Does not add error if component has a valid link type', () => { const mockLink = { type: CompassLinkType.OnCall, url: 'https://test', }; additionalLinksValidator.validateLinkKeys( mockLink, 'WEBSITE', MAX_NAME_LENGTH, ); expect(additionalLinksValidator.errors).toEqual([]); }); test('Adds error if name property has not a string value', () => { const mockLinkWithInvalidName = { type: CompassLinkType.Repository, url: 'https://test', name: 1, }; additionalLinksValidator.validateLinkKeys( mockLinkWithInvalidName as unknown as CreateLinkInput, CompassComponentType.Service, 1, ); const expectedError = 'Invalid additional link "name" field value'; expect(additionalLinksValidator.errors).toContain(expectedError); }); test('Adds error if name property has value exceeded limit', () => { const mockLinkWithInvalidName = { type: CompassLinkType.Repository, url: 'https://test', name: 'more than limit', }; additionalLinksValidator.validateLinkKeys( mockLinkWithInvalidName, CompassComponentType.Service, 1, ); const expectedError = '"name" field of additional link is too long. Try again with a value no longer than 1 characters.'; expect(additionalLinksValidator.errors).toContain(expectedError); }); }); test('Adds error if links count of type exceeded limit', () => { const mockValidLink = { type: CompassLinkType.Repository, url: 'https://test', }; const maxLinksOfTypeLimit = 1; additionalLinksValidator.validateMaxLinksByType( [mockValidLink, mockValidLink], maxLinksOfTypeLimit, ); const expectedError = `Exceeded allowed total links count of ${maxLinksOfTypeLimit} for the type REPOSITORY`; expect(additionalLinksValidator.errors).toContain(expectedError); }); test('Does not add errors if links are valid', () => { const mockValidLink = { type: CompassLinkType.Repository, url: 'https://test', }; additionalLinksValidator.validateLinkKeys( mockValidLink, CompassComponentType.Service, 1, ); additionalLinksValidator.validateMaxLinksByType([mockValidLink], 1); expect(additionalLinksValidator.errors).toEqual([]); }); test('Does not add errors if links are valid', () => { const mockValidLink = { type: CompassLinkType.Repository, url: 'https://test', }; additionalLinksValidator.validateLinkKeys( mockValidLink, CompassComponentType.Service, 1, ); additionalLinksValidator.validateMaxLinksByType([mockValidLink], 1); expect(additionalLinksValidator.errors).toEqual([]); }); });