@@ -2,8 +2,9 @@ import { expect } from 'chai';
22import { PlainClientAPI } from 'contentful-management' ;
33import sinon from 'sinon' ;
44import * as clientWrapper from './client' ;
5- import { CreateAppActionPayload } from './types' ;
6- import { doUpsert } from './upsert-actions' ;
5+ import { AppActionManifest , CreateAppActionPayload } from './types' ;
6+ import { doUpsert , processActionManifests , syncUpsertToManifest } from './upsert-actions' ;
7+ import fs from 'node:fs' ;
78
89describe ( 'doUpsert' , ( ) => {
910 let createStub : sinon . SinonStub ;
@@ -97,3 +98,124 @@ describe('doUpsert', () => {
9798 expect ( updateStub . called ) . to . be . false ;
9899 } ) ;
99100} ) ;
101+
102+ describe ( 'syncUpsertToManifest' , ( ) => {
103+ let writeFileSyncStub : sinon . SinonStub ;
104+ let consoleLogStub : sinon . SinonStub ;
105+
106+ beforeEach ( ( ) => {
107+ writeFileSyncStub = sinon . stub ( fs , 'writeFileSync' ) ;
108+ consoleLogStub = sinon . stub ( console , 'log' ) ;
109+ } ) ;
110+
111+ afterEach ( ( ) => {
112+ writeFileSyncStub . restore ( ) ;
113+ consoleLogStub . restore ( ) ;
114+ } ) ;
115+
116+ it ( 'should sync actions and write updated manifest to file in order' , ( ) => {
117+ const manifestActions = [
118+ { id : '1' , name : 'action1' , type : 'endpoint' , url : 'https://example.com/1' } ,
119+ { id : '2' , name : 'action2' , type : 'endpoint' , url : 'https://example.com/2' } ,
120+ { id : '3' , name : 'action3' , type : 'endpoint' , url : 'https://example.com/3' }
121+ ] ;
122+
123+ const actionsToSync = {
124+ 1 : { id : '2' , name : 'updated-action2' , type : 'endpoint' , url : 'https://example.com/1' }
125+ } ;
126+
127+ const manifest = {
128+ functions : [ { id : '1' , name : 'function1' } ] ,
129+ actions : manifestActions
130+ } ;
131+
132+ const manifestFile = 'manifest.json' ;
133+
134+ syncUpsertToManifest ( manifestActions as any as AppActionManifest [ ] , actionsToSync as any as { [ i : number ] : AppActionManifest } , manifest , manifestFile ) ;
135+
136+ expect ( writeFileSyncStub . calledOnce ) . to . be . true ;
137+ expect ( writeFileSyncStub . firstCall . args [ 0 ] ) . to . equal ( manifestFile ) ;
138+ expect ( JSON . parse ( writeFileSyncStub . firstCall . args [ 1 ] ) ) . to . deep . equal ( {
139+ // preserve other properties of the manifest
140+ functions : [ { id : '1' , name : 'function1' } ] ,
141+ actions : [
142+ { id : '1' , name : 'action1' , type : 'endpoint' , url : 'https://example.com/1' } ,
143+ { id : '2' , name : 'updated-action2' , type : 'endpoint' , url : 'https://example.com/1' } ,
144+ { id : '3' , name : 'action3' , type : 'endpoint' , url : 'https://example.com/3' }
145+ ]
146+ } ) ;
147+ } ) ;
148+ } ) ;
149+
150+ describe ( 'processActionManifests' , ( ) => {
151+ it ( 'should process actions and return synced actions when successful' , async ( ) => {
152+ const actions = [
153+ { name : 'action1' , type : 'endpoint' } ,
154+ { name : 'action2' , type : 'endpoint' }
155+ ] ;
156+
157+ const doUpsertStub = ( ) => Promise . resolve ( {
158+ sys : {
159+ id : 'test-id'
160+ } ,
161+ name : 'action1' ,
162+ type : 'endpoint'
163+ } ) ;
164+
165+ const { actionsToSync, errors } = await processActionManifests ( actions as AppActionManifest [ ] , doUpsertStub as any ) ;
166+
167+ expect ( Object . keys ( actionsToSync ) . length ) . to . equal ( 2 ) ;
168+ expect ( actionsToSync [ 0 ] ) . to . deep . include ( {
169+ name : 'action1' ,
170+ type : 'endpoint' ,
171+ id : 'test-id'
172+ } ) ;
173+ expect ( errors ) . to . be . empty ;
174+ } ) ;
175+
176+ it ( 'should collect errors when action processing fails' , async ( ) => {
177+ const actions = [
178+ { name : 'action1' , type : 'endpoint' } ,
179+ { name : 'action2' , type : 'endpoint' }
180+ ] ;
181+
182+ const error = new Error ( 'Processing failed' )
183+ const doUpsertStub = ( ) => Promise . reject ( error ) ;
184+
185+ const { actionsToSync, errors } = await processActionManifests ( actions as AppActionManifest [ ] , doUpsertStub ) ;
186+
187+ expect ( Object . keys ( actionsToSync ) ) . to . be . empty ;
188+ expect ( errors ) . to . have . length ( 2 ) ;
189+ expect ( errors [ 0 ] . details ) . to . equal ( error ) ;
190+ expect ( errors [ 0 ] . path ) . to . deep . equal ( [ 'actions' , '0' ] ) ;
191+ expect ( errors [ 1 ] . details ) . to . equal ( error ) ;
192+ expect ( errors [ 1 ] . path ) . to . deep . equal ( [ 'actions' , '1' ] ) ;
193+ } ) ;
194+
195+ it ( 'should handle mixed success and failure cases' , async ( ) => {
196+ const actions = [
197+ { name : 'action1' , type : 'endpoint' } ,
198+ { name : 'action2' , type : 'endpoint' }
199+ ] ;
200+
201+ const successResponse = { sys : { id : 'success-id' } } ;
202+ const error = new Error ( 'Processing failed' ) ;
203+
204+ const doUpsertStubMixed = sinon . stub ( ) ;
205+ doUpsertStubMixed . onFirstCall ( ) . resolves ( successResponse ) ;
206+ doUpsertStubMixed . onSecondCall ( ) . rejects ( error ) ;
207+
208+ const { actionsToSync, errors } = await processActionManifests ( actions as AppActionManifest [ ] , doUpsertStubMixed ) ;
209+
210+ expect ( Object . keys ( actionsToSync ) ) . to . have . length ( 1 ) ;
211+ expect ( actionsToSync [ 0 ] ) . to . deep . include ( {
212+ name : 'action1' ,
213+ type : 'endpoint' ,
214+ id : 'success-id'
215+ } ) ;
216+ expect ( errors ) . to . have . length ( 1 ) ;
217+ expect ( errors [ 0 ] . details ) . to . equal ( error ) ;
218+ expect ( errors [ 0 ] . path ) . to . deep . equal ( [ 'actions' , '1' ] ) ;
219+ } ) ;
220+ } ) ;
221+
0 commit comments