import { CompassComponentType, CompassLinkType, Component, CreateLinkInput, } from '@atlassian/forge-graphql-types'; import { AdditionalLinksValidator } from '../../requests/config-as-code-requests/helpers/append-links/additional-links-validator'; import { ConfigLinksTransformer } from '../../requests/config-as-code-requests/helpers/append-links/config-links-transformer'; import { AdditionalLinksValidationError } from '../../requests/config-as-code-requests/helpers/append-links/models/errors'; import { YamlLink } from '../../types'; const mockComponent = { type: CompassComponentType.Service, }; class StubAdditionalLinksValidator extends AdditionalLinksValidator { validateLinkKeys = jest.fn(); validateMaxLinksByType = jest.fn(); } describe('ConfigLinksTransformer', () => { let stubAdditionalLinksValidator: StubAdditionalLinksValidator; beforeEach(() => { stubAdditionalLinksValidator = new StubAdditionalLinksValidator(); }); test('Throws error if component does not exist', () => { const configLinksTransformer = new ConfigLinksTransformer( [], [], stubAdditionalLinksValidator, ); const expectedError = new AdditionalLinksValidationError([ 'Component not found', ]); expect( configLinksTransformer.getLinks.bind(configLinksTransformer), ).toThrow(expectedError); }); test('Returns mapped to CreateLinkInput config links if no additional links provided', () => { const mockConfigLinks: YamlLink[] = [ { type: CompassLinkType.Repository, url: 'https://test', id: 'id', name: null, }, { type: CompassLinkType.ChatChannel, url: 'https://test1', id: 'id1', name: 'name', }, ]; const configLinksTransformer = new ConfigLinksTransformer( [], mockConfigLinks, stubAdditionalLinksValidator, mockComponent as Component, ); const expectedLinks: CreateLinkInput[] = [ { type: CompassLinkType.Repository, url: 'https://test', }, { type: CompassLinkType.ChatChannel, url: 'https://test1', name: 'name', }, ]; expect(configLinksTransformer.getLinks()).toEqual(expectedLinks); }); test('Returns combined and deduplicated config files and additional links', () => { const mockConfigLinks: YamlLink[] = [ { type: CompassLinkType.Repository, url: 'https://test', id: 'id', name: null, }, { type: CompassLinkType.ChatChannel, url: 'https://test1', id: 'id1', name: 'should be deduplicated', }, ]; const mockAdditionalLinks: CreateLinkInput[] = [ { type: CompassLinkType.OnCall, url: 'https://test', }, { type: CompassLinkType.ChatChannel, url: 'https://test1', name: 'should be deduplicated', }, ]; const configLinksTransformer = new ConfigLinksTransformer( mockAdditionalLinks, mockConfigLinks, stubAdditionalLinksValidator, mockComponent as Component, ); const expectedLinks: CreateLinkInput[] = [ { type: CompassLinkType.Repository, url: 'https://test', }, { type: CompassLinkType.ChatChannel, url: 'https://test1', name: 'should be deduplicated', }, { type: CompassLinkType.OnCall, url: 'https://test', }, ]; expect(configLinksTransformer.getLinks()).toEqual(expectedLinks); }); test('Ignores name when looking for duplicate compnents in the additional links section', () => { const mockConfigLinks: YamlLink[] = [ { type: CompassLinkType.Repository, url: 'https://test', id: 'id', name: null, }, { type: CompassLinkType.ChatChannel, url: 'https://test1', id: 'id1', name: 'should be deduplicated', }, ]; const mockAdditionalLinks: CreateLinkInput[] = [ { type: CompassLinkType.OnCall, url: 'https://test', }, { type: CompassLinkType.ChatChannel, url: 'https://test1', }, ]; const configLinksTransformer = new ConfigLinksTransformer( mockAdditionalLinks, mockConfigLinks, stubAdditionalLinksValidator, mockComponent as Component, ); const expectedLinks: CreateLinkInput[] = [ { type: CompassLinkType.Repository, url: 'https://test', }, { type: CompassLinkType.ChatChannel, url: 'https://test1', name: 'should be deduplicated', }, { type: CompassLinkType.OnCall, url: 'https://test', }, ]; expect(configLinksTransformer.getLinks()).toEqual(expectedLinks); }); test('Ignores subdirectories in the additional links section to avoid duplicates', () => { const mockConfigLinks: YamlLink[] = [ { type: CompassLinkType.Repository, url: 'https://bitbucket.org/organization-name/repo-name', }, ]; const mockAdditionalLinks: CreateLinkInput[] = [ { type: CompassLinkType.Repository, url: 'https://bitbucket.org/organization-name/repo-name/src', }, ]; const configLinksTransformer = new ConfigLinksTransformer( mockAdditionalLinks, mockConfigLinks, stubAdditionalLinksValidator, mockComponent as Component, ); const expectedLinks: CreateLinkInput[] = [ { type: CompassLinkType.Repository, url: 'https://bitbucket.org/organization-name/repo-name', }, ]; expect(configLinksTransformer.getLinks()).toEqual(expectedLinks); }); test('Ignores trailing slash in the additional links section to avoid duplicates', () => { const mockConfigLinks: YamlLink[] = [ { type: CompassLinkType.Repository, url: 'https://bitbucket.org/organization-name/repo-name/', }, ]; const mockAdditionalLinks: CreateLinkInput[] = [ { type: CompassLinkType.Repository, url: 'https://bitbucket.org/organization-name/repo-name', }, ]; const configLinksTransformer = new ConfigLinksTransformer( mockAdditionalLinks, mockConfigLinks, stubAdditionalLinksValidator, mockComponent as Component, ); const expectedLinks: CreateLinkInput[] = [ { type: CompassLinkType.Repository, url: 'https://bitbucket.org/organization-name/repo-name/', }, ]; expect(configLinksTransformer.getLinks()).toEqual(expectedLinks); }); test('Throws error if validation failed', () => { const validationErrors = ['error1', 'error2']; stubAdditionalLinksValidator.errors = validationErrors; const mockConfigLinks: YamlLink[] = [ { type: CompassLinkType.Repository, url: 'https://test', id: 'id', name: null, }, ]; const mockAdditionalLinks: CreateLinkInput[] = [ { type: CompassLinkType.OnCall, url: 'https://test', }, ]; const configLinksTransformer = new ConfigLinksTransformer( mockAdditionalLinks, mockConfigLinks, stubAdditionalLinksValidator, mockComponent as Component, ); const expectedError = new AdditionalLinksValidationError(validationErrors); expect( configLinksTransformer.getLinks.bind(configLinksTransformer), ).toThrow(expectedError); }); });