1- import { Capability , StackSummary , StackStatus , StackResourceSummary } from '@aws-sdk/client-cloudformation' ;
1+ import {
2+ Capability ,
3+ StackSummary ,
4+ StackStatus ,
5+ StackResourceSummary ,
6+ ChangeSetStatus ,
7+ } from '@aws-sdk/client-cloudformation' ;
28import { StubbedInstance } from 'ts-sinon' ;
39import { describe , it , expect , vi , beforeEach } from 'vitest' ;
410import { CancellationToken , ResponseError , ErrorCodes } from 'vscode-languageserver' ;
@@ -23,8 +29,10 @@ import {
2329 describeChangeSetDeletionStatusHandler ,
2430 getChangeSetDeletionStatusHandler ,
2531 getStackOutputsHandler ,
32+ describeChangeSetHandler ,
2633} from '../../../src/handlers/StackHandler' ;
2734import { analyzeCapabilities } from '../../../src/stacks/actions/CapabilityAnalyzer' ;
35+ import { mapChangesToStackChanges } from '../../../src/stacks/actions/StackActionOperations' ;
2836import {
2937 TemplateUri ,
3038 GetCapabilitiesResult ,
@@ -38,6 +46,8 @@ import {
3846 ListStacksResult ,
3947 ListStackResourcesResult ,
4048 GetStackOutputsResult ,
49+ DescribeChangeSetParams ,
50+ DescribeChangeSetResult ,
4151} from '../../../src/stacks/StackRequestType' ;
4252import {
4353 createMockComponents ,
@@ -73,6 +83,10 @@ vi.mock('../../../src/stacks/actions/CapabilityAnalyzer', () => ({
7383 analyzeCapabilities : vi . fn ( ) ,
7484} ) ) ;
7585
86+ vi . mock ( '../../../src/stacks/actions/StackActionOperations' , ( ) => ( {
87+ mapChangesToStackChanges : vi . fn ( ) ,
88+ } ) ) ;
89+
7690describe ( 'StackActionHandler' , ( ) => {
7791 let mockComponents : MockedServerComponents ;
7892 let syntaxTreeManager : StubbedInstance < SyntaxTreeManager > ;
@@ -763,4 +777,107 @@ describe('StackActionHandler', () => {
763777 await expect ( handler ( params , { } as any ) ) . rejects . toThrow ( ResponseError ) ;
764778 } ) ;
765779 } ) ;
780+
781+ describe ( 'describeChangeSetHandler' , ( ) => {
782+ it ( 'should return changeset details on success' , async ( ) => {
783+ const mockChangeSetResponse = {
784+ Status : ChangeSetStatus . CREATE_COMPLETE ,
785+ CreationTime : new Date ( '2023-01-01T00:00:00Z' ) ,
786+ Description : 'Test changeset' ,
787+ Changes : [
788+ {
789+ Action : 'Add' ,
790+ ResourceChange : {
791+ LogicalResourceId : 'MyBucket' ,
792+ ResourceType : 'AWS::S3::Bucket' ,
793+ } ,
794+ } ,
795+ ] ,
796+ $metadata : { } ,
797+ } ;
798+
799+ const mockMappedChanges = [
800+ {
801+ type : 'Resource' ,
802+ resourceChange : {
803+ action : 'Add' ,
804+ logicalResourceId : 'MyBucket' ,
805+ resourceType : 'AWS::S3::Bucket' ,
806+ } ,
807+ } ,
808+ ] ;
809+
810+ mockComponents . cfnService . describeChangeSet . resolves ( mockChangeSetResponse ) ;
811+ vi . mocked ( mapChangesToStackChanges ) . mockReturnValue ( mockMappedChanges ) ;
812+
813+ const handler = describeChangeSetHandler ( mockComponents ) ;
814+ const params : DescribeChangeSetParams = {
815+ changeSetName : 'test-changeset' ,
816+ stackName : 'test-stack' ,
817+ } ;
818+
819+ const result = ( await handler ( params , { } as any ) ) as DescribeChangeSetResult ;
820+
821+ expect ( result ) . toEqual ( {
822+ changeSetName : 'test-changeset' ,
823+ stackName : 'test-stack' ,
824+ status : ChangeSetStatus . CREATE_COMPLETE ,
825+ creationTime : '2023-01-01T00:00:00.000Z' ,
826+ description : 'Test changeset' ,
827+ changes : mockMappedChanges ,
828+ } ) ;
829+
830+ expect (
831+ mockComponents . cfnService . describeChangeSet . calledWith ( {
832+ ChangeSetName : 'test-changeset' ,
833+ IncludePropertyValues : true ,
834+ StackName : 'test-stack' ,
835+ } ) ,
836+ ) . toBe ( true ) ;
837+ expect ( mapChangesToStackChanges ) . toHaveBeenCalledWith ( mockChangeSetResponse . Changes ) ;
838+ } ) ;
839+
840+ it ( 'should handle undefined optional fields' , async ( ) => {
841+ const mockChangeSetResponse = {
842+ Status : undefined ,
843+ CreationTime : undefined ,
844+ Description : undefined ,
845+ Changes : undefined ,
846+ $metadata : { } ,
847+ } ;
848+
849+ mockComponents . cfnService . describeChangeSet . resolves ( mockChangeSetResponse ) ;
850+ vi . mocked ( mapChangesToStackChanges ) . mockReturnValue ( [ ] ) ;
851+
852+ const handler = describeChangeSetHandler ( mockComponents ) ;
853+ const params : DescribeChangeSetParams = {
854+ changeSetName : 'test-changeset' ,
855+ stackName : 'test-stack' ,
856+ } ;
857+
858+ const result = ( await handler ( params , { } as any ) ) as DescribeChangeSetResult ;
859+
860+ expect ( result ) . toEqual ( {
861+ changeSetName : 'test-changeset' ,
862+ stackName : 'test-stack' ,
863+ status : '' ,
864+ creationTime : undefined ,
865+ description : undefined ,
866+ changes : [ ] ,
867+ } ) ;
868+ } ) ;
869+
870+ it ( 'should propagate errors from cfnService' , async ( ) => {
871+ const error = new Error ( 'ChangeSet not found' ) ;
872+ mockComponents . cfnService . describeChangeSet . rejects ( error ) ;
873+
874+ const handler = describeChangeSetHandler ( mockComponents ) ;
875+ const params : DescribeChangeSetParams = {
876+ changeSetName : 'non-existent-changeset' ,
877+ stackName : 'test-stack' ,
878+ } ;
879+
880+ await expect ( handler ( params , { } as any ) ) . rejects . toThrow ( 'ChangeSet not found' ) ;
881+ } ) ;
882+ } ) ;
766883} ) ;
0 commit comments