@@ -13,6 +13,11 @@ const {
1313 mockSnapshotFromJson,
1414 mockCreateResumeAttemptTimeoutController,
1515 mockIsTimedOut,
16+ mockWithCascadeLock,
17+ mockGetRowById,
18+ mockGetTableById,
19+ mockCreateWorkflowCellProgressWriter,
20+ mockWriteWorkflowGroupState,
1621} = vi . hoisted ( ( ) => ( {
1722 mockTask : vi . fn ( ( config ) => config ) ,
1823 mockGetPausedExecutionById : vi . fn ( ) ,
@@ -21,6 +26,11 @@ const {
2126 mockSnapshotFromJson : vi . fn ( ) ,
2227 mockCreateResumeAttemptTimeoutController : vi . fn ( ) ,
2328 mockIsTimedOut : vi . fn ( ( ) => false ) ,
29+ mockWithCascadeLock : vi . fn ( ) ,
30+ mockGetRowById : vi . fn ( ) ,
31+ mockGetTableById : vi . fn ( ) ,
32+ mockCreateWorkflowCellProgressWriter : vi . fn ( ) ,
33+ mockWriteWorkflowGroupState : vi . fn ( ) ,
2434} ) )
2535
2636vi . mock ( '@trigger.dev/sdk' , ( ) => ( { task : mockTask , timeout : { None : 'none' } } ) )
@@ -29,9 +39,17 @@ vi.mock('@/lib/billing/core/billing-attribution', () => ({
2939 assertBillingAttributionSnapshot : vi . fn ( ( value ) => value ) ,
3040} ) )
3141
32- vi . mock ( '@/lib/table/cascade-lock' , ( ) => ( { withCascadeLock : vi . fn ( ) } ) )
42+ vi . mock ( '@/lib/table/cascade-lock' , ( ) => ( { withCascadeLock : mockWithCascadeLock } ) )
3343vi . mock ( '@/lib/table/deps' , ( ) => ( { isExecCancelled : vi . fn ( ( ) => false ) } ) )
3444
45+ vi . mock ( '@/lib/table/rows/service' , ( ) => ( { getRowById : mockGetRowById } ) )
46+ vi . mock ( '@/lib/table/service' , ( ) => ( { getTableById : mockGetTableById } ) )
47+ vi . mock ( '@/lib/table/cell-write' , ( ) => ( {
48+ buildCancelledExecution : vi . fn ( ) ,
49+ createWorkflowCellProgressWriter : mockCreateWorkflowCellProgressWriter ,
50+ writeWorkflowGroupState : mockWriteWorkflowGroupState ,
51+ } ) )
52+
3553vi . mock ( '@/lib/table/workflow-columns' , ( ) => ( {
3654 findCellContextByExecutionId : mockFindCellContextByExecutionId ,
3755} ) )
@@ -70,7 +88,7 @@ const payload: ResumeExecutionPayload = {
7088 parentExecutionId : 'parent-execution-1' ,
7189}
7290
73- describe ( 'executeResumeJob terminal errors ' , ( ) => {
91+ describe ( 'executeResumeJob' , ( ) => {
7492 beforeEach ( ( ) => {
7593 vi . clearAllMocks ( )
7694 mockGetPausedExecutionById . mockResolvedValue ( {
@@ -93,6 +111,21 @@ describe('executeResumeJob terminal errors', () => {
93111 } )
94112 mockFindCellContextByExecutionId . mockResolvedValue ( null )
95113 mockIsTimedOut . mockReturnValue ( false )
114+ mockWithCascadeLock . mockImplementation (
115+ async ( _tableId : string , _rowId : string , _ownerId : string , run : ( ) => Promise < unknown > ) => ( {
116+ status : 'acquired' ,
117+ result : await run ( ) ,
118+ } )
119+ )
120+ mockCreateWorkflowCellProgressWriter . mockReturnValue ( {
121+ onBlockComplete : vi . fn ( ) ,
122+ finish : vi . fn ( ) ,
123+ getBlockErrors : vi . fn ( ( ) => ( { } ) ) ,
124+ getPendingDataPatch : vi . fn ( ( ) => undefined ) ,
125+ getEventOutputs : vi . fn ( ( ) => ( { } ) ) ,
126+ getPendingSecretProvenance : vi . fn ( ( ) => undefined ) ,
127+ } )
128+ mockWriteWorkflowGroupState . mockResolvedValue ( 'wrote' )
96129 } )
97130
98131 it ( 'rethrows the original core-finalized resume error' , async ( ) => {
@@ -155,4 +188,47 @@ describe('executeResumeJob terminal errors', () => {
155188 message : 'Execution timed out after 5 seconds' ,
156189 } )
157190 } )
191+
192+ it ( 'preserves manual-run provenance across a paused cell resume' , async ( ) => {
193+ mockFindCellContextByExecutionId . mockResolvedValue ( {
194+ tableId : 'table-1' ,
195+ tableName : 'Table' ,
196+ rowId : 'row-1' ,
197+ groupId : 'group-1' ,
198+ workspaceId : 'workspace-1' ,
199+ workflowId : 'workflow-1' ,
200+ } )
201+ mockGetRowById . mockResolvedValue ( {
202+ executions : {
203+ 'group-1' : {
204+ status : 'pending' ,
205+ executionId : payload . parentExecutionId ,
206+ jobId : `paused-${ payload . parentExecutionId } ` ,
207+ workflowId : 'workflow-1' ,
208+ isManualRun : true ,
209+ error : null ,
210+ } ,
211+ } ,
212+ } )
213+ mockGetTableById . mockResolvedValue ( {
214+ schema : {
215+ columns : [ ] ,
216+ workflowGroups : [ { id : 'group-1' , workflowId : 'workflow-1' , outputs : [ ] } ] ,
217+ } ,
218+ } )
219+ mockStartResumeExecution . mockResolvedValue ( {
220+ success : true ,
221+ status : 'paused' ,
222+ output : undefined ,
223+ } )
224+
225+ await executeResumeJob ( payload )
226+
227+ expect ( mockWriteWorkflowGroupState ) . toHaveBeenCalledWith (
228+ expect . objectContaining ( { isManualRun : true } ) ,
229+ expect . objectContaining ( {
230+ executionState : expect . objectContaining ( { status : 'pending' } ) ,
231+ } )
232+ )
233+ } )
158234} )
0 commit comments