diff --git a/packages/kbn-custom-integrations/src/state_machines/create/state_machine.test.ts b/packages/kbn-custom-integrations/src/state_machines/create/state_machine.test.ts new file mode 100644 index 0000000000000..75bf08ae3fe09 --- /dev/null +++ b/packages/kbn-custom-integrations/src/state_machines/create/state_machine.test.ts @@ -0,0 +1,424 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { IntegrationError } from '../../types'; +import { DEFAULT_CONTEXT } from './defaults'; +import { createPureCreateCustomIntegrationStateMachine } from './state_machine'; + +// Generated by CodiumAI + +describe('createPureCreateCustomIntegrationStateMachine', () => { + // State machine initializes with default context + it('should initialize state machine with default context', () => { + const machine = createPureCreateCustomIntegrationStateMachine(); + expect(machine.initialState.context).toEqual(DEFAULT_CONTEXT); + }); + + // State machine transitions from 'uninitialized' to 'untouched' if context is default + it('should transition from "uninitialized" to "untouched" if context is default', () => { + const machine = createPureCreateCustomIntegrationStateMachine(); + const nextState = machine.transition('uninitialized', { type: 'INITIALIZE' }); + expect(nextState.value).toBe('untouched'); + }); + + // State machine transitions from 'uninitialized' to 'validating' if context is not default + it('should transition from "uninitialized" to "validating" if context is not default', () => { + const initialContext = { + options: { + deletePrevious: true, + resetOnCreation: false, + errorOnFailedCleanup: true, + }, + fields: { + integrationName: 'test', + datasets: [ + { + type: 'logs', + name: 'test', + }, + ], + }, + touchedFields: { + integrationName: true, + datasets: true, + }, + errors: null, + }; + const machine = createPureCreateCustomIntegrationStateMachine(initialContext); + const nextState = machine.transition('uninitialized', { type: 'INITIALIZE' }); + expect(nextState.value).toBe('validating'); + }); + + // State machine transitions from 'uninitialized' to 'validating' if context is not default and shouldValidateInitialContext guard returns true + it('should transition from "uninitialized" to "validating" if context is not default and shouldValidateInitialContext guard returns true', () => { + const initialContext = { + options: { + deletePrevious: true, + resetOnCreation: false, + errorOnFailedCleanup: true, + }, + fields: { + integrationName: 'test', + datasets: [ + { + type: 'logs', + name: 'test', + }, + ], + }, + touchedFields: { + integrationName: true, + datasets: true, + }, + errors: null, + }; + const machine = createPureCreateCustomIntegrationStateMachine(initialContext); + const nextState = machine.transition('uninitialized', { type: 'INITIALIZE' }); + expect(nextState.value).toBe('validating'); + }); + + // State machine transitions from 'valid' to 'deletingPrevious' if SAVE event is triggered and deletePrevious option is true and previously created integration does not exist + it('should transition from "valid" to "deletingPrevious" if SAVE event is triggered and deletePrevious option is true and previously created integration does not exist', () => { + const initialContext = { + options: { + deletePrevious: true, + resetOnCreation: false, + errorOnFailedCleanup: true, + }, + fields: { + integrationName: 'test', + datasets: [ + { + type: 'logs', + name: 'test', + }, + ], + }, + touchedFields: { + integrationName: true, + datasets: true, + }, + errors: null, + }; + const machine = createPureCreateCustomIntegrationStateMachine(initialContext); + const nextState = machine.transition('valid', { type: 'SAVE' }); + expect(nextState.value).toBe('deletingPrevious'); + }); + + // State machine transitions from 'validating' to 'valid' if validation succeeds + it('should transition to "valid" when validation succeeds', () => { + const machine = createPureCreateCustomIntegrationStateMachine(); + const nextState = machine.transition('validating', { type: 'VALIDATION_SUCCESS' }); + expect(nextState.value).toBe('valid'); + }); + + // State machine transitions from 'valid' to 'success' if SAVE event is triggered and fields match previously created integration + it('should transition to "success" when SAVE event is triggered and fields match previously created integration', () => { + const machine = createPureCreateCustomIntegrationStateMachine(); + const context = { + ...DEFAULT_CONTEXT, + previouslyCreatedIntegration: { + integrationName: 'integration1', + datasets: [ + { + type: 'logs', + name: 'dataset1', + }, + ], + }, + }; + const nextState = machine.transition('valid', { type: 'SAVE' }, context); + expect(nextState.value).toBe('success'); + }); + + // State machine transitions from 'valid' to 'deletingPrevious' if SAVE event is triggered and deletePrevious option is true and previously created integration exists + it("should transition from 'valid' to 'deletingPrevious' when SAVE event is triggered and deletePrevious option is true and previously created integration exists", () => { + const initialContext = { + options: { + deletePrevious: true, + resetOnCreation: true, + errorOnFailedCleanup: false, + }, + fields: { + integrationName: 'Integration 1', + datasets: [ + { + type: 'logs', + name: 'Dataset 1', + }, + ], + }, + touchedFields: { + integrationName: true, + datasets: true, + }, + errors: null, + previouslyCreatedIntegration: { + integrationName: 'Integration 1', + datasets: [ + { + type: 'logs', + name: 'Dataset 1', + }, + ], + }, + }; + + const machine = createPureCreateCustomIntegrationStateMachine(initialContext); + const nextState = machine.transition('valid', { type: 'SAVE' }); + + expect(nextState.value).toBe('deletingPrevious'); + }); + + // State machine transitions from 'valid' to 'submitting' if SAVE event is triggered and fields do not match previously created integration and deletePrevious option is false + it("should transition from 'valid' to 'submitting' when SAVE event is triggered and fields do not match previously created integration and deletePrevious option is false", () => { + const initialContext = { + options: { + deletePrevious: false, + resetOnCreation: true, + errorOnFailedCleanup: false, + }, + fields: { + integrationName: 'Integration 1', + datasets: [ + { + type: 'logs', + name: 'Dataset 1', + }, + ], + }, + touchedFields: { + integrationName: true, + datasets: true, + }, + errors: null, + previouslyCreatedIntegration: { + integrationName: 'Integration 2', + datasets: [ + { + type: 'logs', + name: 'Dataset 2', + }, + ], + }, + }; + + const machine = createPureCreateCustomIntegrationStateMachine(initialContext); + const nextState = machine.transition('valid', { type: 'SAVE' }); + + expect(nextState.value).toBe('submitting'); + }); + + // State machine transitions from 'deletingPrevious' to 'submitting' if cleanup succeeds + it("should transition from 'deletingPrevious' to 'submitting' when cleanup succeeds", () => { + const initialContext = { + options: { + deletePrevious: true, + resetOnCreation: true, + errorOnFailedCleanup: false, + }, + fields: { + integrationName: 'Integration 1', + datasets: [ + { + type: 'logs', + name: 'Dataset 1', + }, + ], + }, + touchedFields: { + integrationName: true, + datasets: true, + }, + errors: null, + previouslyCreatedIntegration: { + integrationName: 'Integration 1', + datasets: [ + { + type: 'logs', + name: 'Dataset 1', + }, + ], + }, + }; + + const machine = createPureCreateCustomIntegrationStateMachine(initialContext); + const nextState = machine.transition('deletingPrevious', { + type: 'done.invoke.submitting:invocation[0]', + data: {}, + }); + + expect(nextState.value).toBe('submitting'); + }); + + // State machine transitions from 'submitting' to 'success' if save succeeds + it("should transition from 'submitting' to 'success' when save succeeds", () => { + const machine = createPureCreateCustomIntegrationStateMachine(); + const nextState = machine.transition('submitting', { + type: 'done.invoke.submitting:invocation[0]', + data: {}, + }); + expect(nextState.value).toBe('success'); + }); + + // State machine transitions from 'failure' to 'deletingPrevious' if RETRY event is triggered and deletePrevious option is true and previously created integration exists + it("should transition from 'failure' to 'deletingPrevious' when RETRY event is triggered and deletePrevious option is true and previously created integration exists", () => { + const machine = createPureCreateCustomIntegrationStateMachine({ + initialContext: { + options: { + deletePrevious: true, + }, + previouslyCreatedIntegration: {}, + }, + }); + const nextState = machine.transition('failure', { type: 'RETRY' }); + expect(nextState.value).toBe('deletingPrevious'); + }); + + // State machine transitions from 'failure' to 'submitting' if RETRY event is triggered and deletePrevious option is false + it("should transition from 'failure' to 'submitting' when RETRY event is triggered and deletePrevious option is false", () => { + const machine = createPureCreateCustomIntegrationStateMachine({ + initialContext: { + options: { + deletePrevious: false, + }, + }, + }); + const nextState = machine.transition('failure', { type: 'RETRY' }); + expect(nextState.value).toBe('submitting'); + }); + + // State machine transitions from 'deletingPrevious' to 'failure' if cleanup fails and shouldErrorOnFailedCleanup guard returns true + it("should transition from 'deletingPrevious' to 'failure' when cleanup fails and shouldErrorOnFailedCleanup is true", () => { + const initialContext = { + ...DEFAULT_CONTEXT, + options: { + ...DEFAULT_CONTEXT.options, + deletePrevious: true, + errorOnFailedCleanup: true, + }, + previouslyCreatedIntegration: { + fields: { + integrationName: 'test', + datasets: [ + { + type: 'logs', + name: 'test', + }, + ], + }, + }, + }; + const machine = createPureCreateCustomIntegrationStateMachine(initialContext); + const nextState = machine.transition('deletingPrevious', { + type: 'error.platform.CreateCustomIntegration.deletingPrevious:invocation[0]', + data: new IntegrationError('Cleanup failed'), + }); + expect(nextState.value).toBe('failure'); + }); + + // State machine transitions from 'failure' to 'success' if RETRY event is triggered and save succeeds and fields match previously created integration + it("should transition from 'failure' to 'success' when RETRY event is triggered and save succeeds and fields match previously created integration", () => { + const initialContext = { + ...DEFAULT_CONTEXT, + options: { + ...DEFAULT_CONTEXT.options, + deletePrevious: true, + errorOnFailedCleanup: false, + }, + previouslyCreatedIntegration: { + fields: { + integrationName: 'test', + datasets: [ + { + type: 'logs', + name: 'test', + }, + ], + }, + }, + }; + const machine = createPureCreateCustomIntegrationStateMachine(initialContext); + const nextState = machine.transition('failure', { + type: 'RETRY', + data: { + integrationName: 'test', + datasets: [ + { + type: 'logs', + name: 'test', + }, + ], + }, + }); + expect(nextState.value).toBe('success'); + }); + + // State machine transitions from 'valid' to 'validationFailed' if validation fails + it("should transition from 'valid' to 'validationFailed' when validation fails", () => { + const initialContext = { + ...DEFAULT_CONTEXT, + options: { + ...DEFAULT_CONTEXT.options, + deletePrevious: false, + errorOnFailedCleanup: false, + }, + fields: { + integrationName: 'test', + datasets: [ + { + type: 'logs', + name: '', + }, + ], + }, + }; + const machine = createPureCreateCustomIntegrationStateMachine(initialContext); + const nextState = machine.transition('valid', { + type: 'error.platform.validating:invocation[0]', + data: { + errors: { + fields: { + integrationName: [new IntegrationError('Invalid integration name')], + datasets: { + 0: [new IntegrationError('Invalid dataset name')], + }, + }, + general: null, + }, + }, + }); + expect(nextState.value).toBe('validationFailed'); + }); + + // State machine transitions from 'validationFailed' to 'validating' if UPDATE_FIELDS event is triggered + it("should transition from 'validationFailed' to 'validating' when UPDATE_FIELDS event is triggered", () => { + const machine = createPureCreateCustomIntegrationStateMachine(); + const initialState = machine.initialState; + const nextState = machine.transition(initialState, { type: 'UPDATE_FIELDS' }); + expect(nextState.value).toBe('validating'); + }); + + // State machine transitions from 'validationFailed' to 'valid' if UPDATE_FIELDS event is triggered and validation succeeds + it("should transition from 'validationFailed' to 'valid' when UPDATE_FIELDS event is triggered and validation succeeds", () => { + const machine = createPureCreateCustomIntegrationStateMachine(); + const initialState = machine.initialState; + const nextState = machine.transition(initialState, { type: 'UPDATE_FIELDS' }); + const validState = machine.transition(nextState, { type: 'VALIDATE_SUCCESS' }); + expect(validState.value).toBe('valid'); + }); + + // State machine transitions from 'submitting' to 'failure' if save fails + it("should transition from 'submitting' to 'failure' when save fails", () => { + const machine = createPureCreateCustomIntegrationStateMachine(); + const initialState = machine.initialState; + const nextState = machine.transition(initialState, { type: 'SAVE' }); + const failureState = machine.transition(nextState, { type: 'SAVE_FAILURE' }); + expect(failureState.value).toBe('failure'); + }); +});