/* eslint-disable import/first, import/order */ import { SDK_SCHEMA_ERROR } from '../../helpers'; // eslint-disable-next-line max-len import { EXTERNAL_ALIAS_SOURCE_COMPONENT_PATH_TO_FILE } from '../../requests/config-as-code-requests/helpers/createOrUpdateComponent/constants'; // eslint-disable-next-line max-len import { generateExternalIdWithPrefix } from '../../requests/config-as-code-requests/helpers/createOrUpdateComponent/helpers'; import { mockAggCompassRequests, mockDetachDataManager, mockGetComponent, mockGetComponentByExternalAlias, } from './helpers/mockCompassRequests'; mockAggCompassRequests(); // eslint-disable-next-line max-len import { deleteAliasesByCreateFromYaml } from '../../requests/config-as-code-requests/helpers/unlinkComponent/externalAliasManager'; import { MOCK_ADDITIONAL_EXTERNAL_ALIASES, MOCK_CLOUD_ID, MOCK_COMPONENT, MOCK_COMPONENT_CAPITALIZED_OLD_PATH, MOCK_COMPONENT_ID, MOCK_COMPONENT_NAME, MOCK_COMPONENT_OLD_PATH, MOCK_DEDUPLICATION_ID, MOCK_EXTERNAL_ALIAS, getManagedComponentAliases, getMockedComponent, } from '../fixtures/mocks'; import api from '../../index'; import { ApiPayload, ComponentPayload, GetComponentByExternalAliasInput, UnLinkComponentInput, } from '@atlassian/forge-graphql-types'; const configReq = api.compass.configAsCode.asApp(); const compassApp = api.compass.asApp(); const ERROR_MESSAGE = 'test'; const ERROR = new Error(ERROR_MESSAGE); const COMPONENT_WITH_MANAGED_ALIASES = getMockedComponent({ externalAliases: getManagedComponentAliases({ path: MOCK_COMPONENT_OLD_PATH, }), }); const getMockedUnlinkComponentInput = ( overrideMockedUnlinkInput: Partial = {}, ) => ({ cloudId: MOCK_CLOUD_ID, componentId: MOCK_COMPONENT_ID, filePath: MOCK_COMPONENT_OLD_PATH, deduplicationId: MOCK_DEDUPLICATION_ID, additionalExternalAliasesToRemove: MOCK_ADDITIONAL_EXTERNAL_ALIASES, ...overrideMockedUnlinkInput, }); jest.mock( '../../requests/config-as-code-requests/helpers/unlinkComponent/externalAliasManager', () => ({ deleteAliasesByCreateFromYaml: jest.fn(), }), ); describe('unlinkComponent', () => { beforeEach(() => { jest.resetAllMocks(); mockAggCompassRequests(); }); function validateUnlinkComponentState( unlinkState: ApiPayload, isSuccessful = true, ) { if (isSuccessful) { expect(unlinkState.success).toEqual(true); expect(unlinkState.errors.length).toEqual(0); expect(unlinkState.data.component).not.toBeNull(); expect(unlinkState.data.component.id).toEqual(MOCK_COMPONENT_ID); expect(unlinkState.data.component.name).toEqual(MOCK_COMPONENT_NAME); } else { expect(unlinkState.success).toEqual(false); expect(unlinkState.errors.length).toEqual(1); } } describe('Component Id passed as input to unlink component', () => { function verifyCalledWithParametersWithComponentId( validateDetachDataManager = true, ) { expect(mockGetComponent).toBeCalledWith({ componentId: MOCK_COMPONENT_ID, }); if (validateDetachDataManager) { expect(mockDetachDataManager).toBeCalledWith({ componentId: MOCK_COMPONENT_ID, }); } } it('successfully unlink the component', async () => { // Mock setups mockGetComponent.mockResolvedValue({ success: true, data: { component: COMPONENT_WITH_MANAGED_ALIASES }, errors: [], }); mockGetComponentByExternalAlias.mockRejectedValue(ERROR); mockDetachDataManager.mockResolvedValue({ success: true, errors: [], }); const mockDeleteAliasesByCreateFromYaml = ( deleteAliasesByCreateFromYaml as jest.Mock ).mockResolvedValueOnce({ errors: [], success: true, unDeletedAliasCount: 0, totalAliasCount: 0, }); // Method Under test const unlinkInput = getMockedUnlinkComponentInput(); const unlinkState = await configReq.unlinkComponent(unlinkInput); // validations expect(mockGetComponentByExternalAlias).not.toBeCalled(); // Because component id is passed as a parameter verifyCalledWithParametersWithComponentId(); validateUnlinkComponentState(unlinkState); expect(mockDeleteAliasesByCreateFromYaml).toBeCalledWith( compassApp, COMPONENT_WITH_MANAGED_ALIASES, unlinkInput.additionalExternalAliasesToRemove, ); }); it('Failed to fetch component', async () => { // Mock setups mockGetComponent.mockResolvedValue({ success: false, data: { component: null }, errors: [SDK_SCHEMA_ERROR], }); mockGetComponentByExternalAlias.mockResolvedValue({ success: false, data: { component: null }, errors: [SDK_SCHEMA_ERROR], }); // Method Under test const unlinkState = await configReq.unlinkComponent( getMockedUnlinkComponentInput(), ); // validations verifyCalledWithParametersWithComponentId(false); validateUnlinkComponentState(unlinkState, false); expect(unlinkState.data).toBeNull(); }); // eslint-disable-next-line max-len it('successfully unlink the component when component was not fetched through getComponent but fetched through path Alias', async () => { // Mock setups mockGetComponent.mockResolvedValueOnce({ success: false, data: { component: null }, errors: [], }); mockGetComponentByExternalAlias.mockResolvedValueOnce({ success: true, data: { component: COMPONENT_WITH_MANAGED_ALIASES }, errors: [], }); mockDetachDataManager.mockResolvedValue({ success: true, errors: [], }); const mockDeleteAliasesByCreateFromYaml = ( deleteAliasesByCreateFromYaml as jest.Mock ).mockResolvedValueOnce({ errors: [], success: true, unDeletedAliasCount: 0, totalAliasCount: 0, }); // Method Under test const unlinkState = await configReq.unlinkComponent( getMockedUnlinkComponentInput(), ); // validations expect(mockGetComponentByExternalAlias).toBeCalled(); verifyCalledWithParametersWithComponentId(); validateUnlinkComponentState(unlinkState); expect(mockDeleteAliasesByCreateFromYaml).toBeCalledWith( compassApp, COMPONENT_WITH_MANAGED_ALIASES, [MOCK_EXTERNAL_ALIAS], ); }); it('unlink component - failed detach data manager', async () => { // Mock setups mockGetComponent.mockResolvedValue({ success: true, data: { component: COMPONENT_WITH_MANAGED_ALIASES }, errors: [], }); mockGetComponentByExternalAlias.mockRejectedValue(ERROR); mockDetachDataManager.mockRejectedValueOnce({ success: false, errors: [SDK_SCHEMA_ERROR], }); // Method Under test const unlinkState = await configReq.unlinkComponent( getMockedUnlinkComponentInput(), ); // validations expect(mockGetComponentByExternalAlias).not.toBeCalled(); // Because component id is passed as a parameter expect(mockDetachDataManager).toBeCalledWith({ componentId: MOCK_COMPONENT_ID, }); validateUnlinkComponentState(unlinkState, false); expect(unlinkState.data).not.toBeNull(); // Detach failed but fetch should work. expect(unlinkState.data.component.id).toEqual(MOCK_COMPONENT_ID); }); it('unlink component - successful detach data manager but failed deleting aliases', async () => { // Mock setups mockGetComponent.mockResolvedValue({ success: true, data: { component: COMPONENT_WITH_MANAGED_ALIASES }, errors: [], }); mockGetComponentByExternalAlias.mockRejectedValue(ERROR); mockDetachDataManager.mockResolvedValue({ success: true, errors: [], }); const mockDeleteAliasesByCreateFromYaml = ( deleteAliasesByCreateFromYaml as jest.Mock ).mockRejectedValueOnce({ errors: [SDK_SCHEMA_ERROR], success: false, unDeletedAliasCount: 0, totalAliasCount: 0, }); // Method Under test const unlinkInput = getMockedUnlinkComponentInput(); const unlinkState = await configReq.unlinkComponent(unlinkInput); // validations verifyCalledWithParametersWithComponentId(); expect(mockGetComponentByExternalAlias).not.toBeCalled(); // Because component id is passed as a parameter validateUnlinkComponentState(unlinkState, false); expect(unlinkState.data).not.toBeNull(); expect(unlinkState.data.component.id).toEqual(MOCK_COMPONENT_ID); expect(mockDeleteAliasesByCreateFromYaml).toBeCalledWith( compassApp, COMPONENT_WITH_MANAGED_ALIASES, unlinkInput.additionalExternalAliasesToRemove, ); }); }); describe('Component Id is NOT passed as input to unlink component, Component fetched through the Name Alias', () => { function verifyCalledWithParametersWithoutComponentId() { expect(mockGetComponent).not.toBeCalled(); expect(mockDetachDataManager).toBeCalledWith({ componentId: MOCK_COMPONENT_ID, }); expect(mockGetComponentByExternalAlias).toBeCalledWith({ cloudId: MOCK_CLOUD_ID, externalId: generateExternalIdWithPrefix( MOCK_DEDUPLICATION_ID, MOCK_COMPONENT_OLD_PATH, ), externalSource: EXTERNAL_ALIAS_SOURCE_COMPONENT_PATH_TO_FILE, } as GetComponentByExternalAliasInput); } it('successfully unlink the component', async () => { // Mock setups mockGetComponentByExternalAlias.mockResolvedValueOnce({ success: true, data: { component: COMPONENT_WITH_MANAGED_ALIASES }, errors: [], }); mockDetachDataManager.mockResolvedValue({ success: true, errors: [], }); const mockDeleteAliasesByCreateFromYaml = ( deleteAliasesByCreateFromYaml as jest.Mock ).mockResolvedValueOnce({ errors: [], success: true, unDeletedAliasCount: 0, totalAliasCount: 0, }); // Method Under test const unlinkInput = getMockedUnlinkComponentInput({ componentId: null, additionalExternalAliasesToRemove: [], }); const unlinkState = await configReq.unlinkComponent(unlinkInput); // validations verifyCalledWithParametersWithoutComponentId(); expect(unlinkState.success).toEqual(true); expect(unlinkState.errors.length).toEqual(0); expect(unlinkState.data).not.toBeNull(); expect(unlinkState.data.component.id).toEqual(MOCK_COMPONENT_ID); expect(mockDeleteAliasesByCreateFromYaml).toBeCalledWith( compassApp, COMPONENT_WITH_MANAGED_ALIASES, unlinkInput.additionalExternalAliasesToRemove, ); }); it('successfully unlink the component with capitalized path alias', async () => { // Mock setups mockGetComponentByExternalAlias.mockResolvedValueOnce({ success: true, data: { component: COMPONENT_WITH_MANAGED_ALIASES }, errors: [], }); mockDetachDataManager.mockResolvedValue({ success: true, errors: [], }); const mockDeleteAliasesByCreateFromYaml = ( deleteAliasesByCreateFromYaml as jest.Mock ).mockResolvedValueOnce({ errors: [], success: true, unDeletedAliasCount: 0, totalAliasCount: 0, }); // Method Under test const unlinkInput = getMockedUnlinkComponentInput({ filePath: MOCK_COMPONENT_CAPITALIZED_OLD_PATH, componentId: null, additionalExternalAliasesToRemove: [], }); const unlinkState = await configReq.unlinkComponent(unlinkInput); // validations verifyCalledWithParametersWithoutComponentId(); expect(unlinkState.success).toEqual(true); expect(unlinkState.errors.length).toEqual(0); expect(unlinkState.data).not.toBeNull(); expect(unlinkState.data.component.id).toEqual(MOCK_COMPONENT_ID); expect(mockDeleteAliasesByCreateFromYaml).toBeCalledWith( compassApp, COMPONENT_WITH_MANAGED_ALIASES, unlinkInput.additionalExternalAliasesToRemove, ); }); it('unlink component - failed detach data manager', async () => { // Mock setups mockGetComponentByExternalAlias.mockResolvedValueOnce({ success: true, data: { component: { ...MOCK_COMPONENT, id: MOCK_COMPONENT_ID } }, errors: [], }); mockDetachDataManager.mockRejectedValueOnce({ success: false, errors: [SDK_SCHEMA_ERROR], }); // Method Under test const unlinkState = await configReq.unlinkComponent( getMockedUnlinkComponentInput({ componentId: null, }), ); // validations verifyCalledWithParametersWithoutComponentId(); expect(unlinkState.success).toEqual(false); expect(unlinkState.errors.length).toEqual(1); expect(unlinkState.data).not.toBeNull(); expect(unlinkState.data.component.id).toEqual(MOCK_COMPONENT_ID); }); it('unlink component - successful detach data manager but failed deleting aliases', async () => { // Mock setups mockGetComponentByExternalAlias.mockResolvedValueOnce({ success: true, data: { component: COMPONENT_WITH_MANAGED_ALIASES }, errors: [], }); mockDetachDataManager.mockResolvedValue({ success: true, errors: [], }); const mockDeleteAliasesByCreateFromYaml = ( deleteAliasesByCreateFromYaml as jest.Mock ).mockRejectedValueOnce({ errors: [SDK_SCHEMA_ERROR], success: false, unDeletedAliasCount: 0, totalAliasCount: 0, }); // Method Under test const unlinkInput = getMockedUnlinkComponentInput({ componentId: null, }); const unlinkState = await configReq.unlinkComponent(unlinkInput); // validations verifyCalledWithParametersWithoutComponentId(); expect(unlinkState.success).toEqual(false); expect(unlinkState.errors.length).toEqual(1); expect(unlinkState.data).not.toBeNull(); expect(unlinkState.data.component.id).toEqual(MOCK_COMPONENT_ID); expect(mockDeleteAliasesByCreateFromYaml).toBeCalledWith( compassApp, COMPONENT_WITH_MANAGED_ALIASES, unlinkInput.additionalExternalAliasesToRemove, ); }); }); });