690417:1538 Refactor Work flow ADR-021

This commit is contained in:
2026-04-17 15:38:20 +07:00
parent 6d45bdaeb5
commit 3a5fc8d4af
23 changed files with 892 additions and 135 deletions
@@ -1,7 +1,7 @@
import { Test, TestingModule } from '@nestjs/testing';
import { WorkflowEngineService } from './workflow-engine.service';
import { getRepositoryToken } from '@nestjs/typeorm';
import { DataSource, Repository } from 'typeorm';
import { DataSource, In, Repository } from 'typeorm';
import { WorkflowDefinition } from './entities/workflow-definition.entity';
import {
WorkflowInstance,
@@ -11,6 +11,7 @@ import { WorkflowHistory } from './entities/workflow-history.entity';
import { Attachment } from '../../common/file-storage/entities/attachment.entity';
import { WorkflowDslService } from './workflow-dsl.service';
import { WorkflowEventService } from './workflow-event.service';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { NotFoundException } from '../../common/exceptions';
import { CreateWorkflowDefinitionDto } from './dto/create-workflow-definition.dto';
@@ -96,6 +97,14 @@ describe('WorkflowEngineService', () => {
{ provide: WorkflowDslService, useValue: mockDslService },
{ provide: WorkflowEventService, useValue: mockEventService },
{ provide: DataSource, useValue: mockDataSource },
{
provide: CACHE_MANAGER,
useValue: {
get: jest.fn().mockResolvedValue(null),
set: jest.fn().mockResolvedValue(undefined),
del: jest.fn().mockResolvedValue(undefined),
},
},
],
}).compile();
@@ -210,5 +219,103 @@ describe('WorkflowEngineService', () => {
expect(mockQueryRunner.rollbackTransaction).toHaveBeenCalled();
expect(mockQueryRunner.release).toHaveBeenCalled();
});
// ADR-021 T031: Tests for step-specific attachments
describe('ADR-021 Step-specific Attachments', () => {
it('should link attachments to workflow history record', async () => {
const instanceId = 'inst-1';
const attachmentPublicIds = ['att-123', 'att-456'];
const mockInstance = {
id: instanceId,
currentState: 'PENDING',
status: WorkflowStatus.ACTIVE,
definition: { compiled: mockCompiledWorkflow },
context: { some: 'data' },
};
// Mock the history object with an ID
const mockHistory = { id: 'history-123' };
mockQueryRunner.manager.findOne.mockResolvedValue(mockInstance);
// Mock save to return the history object when called with any entity
mockQueryRunner.manager.save.mockResolvedValue(mockHistory);
mockDslService.evaluate.mockReturnValue({
nextState: 'APPROVED',
events: [],
});
await service.processTransition(
instanceId,
'APPROVE',
1,
'Test comment',
{},
attachmentPublicIds
);
expect(mockQueryRunner.manager.update).toHaveBeenCalledWith(
Attachment,
{ publicId: In(attachmentPublicIds) },
{ workflowHistoryId: 'history-123' }
);
});
it('should skip attachment linking when no attachmentPublicIds provided', async () => {
const instanceId = 'inst-1';
const mockInstance = {
id: instanceId,
currentState: 'PENDING',
status: WorkflowStatus.ACTIVE,
definition: { compiled: mockCompiledWorkflow },
context: { some: 'data' },
};
mockQueryRunner.manager.findOne.mockResolvedValue(mockInstance);
mockDslService.evaluate.mockReturnValue({
nextState: 'APPROVED',
events: [],
});
await service.processTransition(instanceId, 'APPROVE', 1);
expect(mockQueryRunner.manager.update).not.toHaveBeenCalledWith(
expect.any(Object),
expect.any(Object),
expect.objectContaining({ workflowHistoryId: expect.any(String) })
);
});
it('should handle empty attachmentPublicIds array', async () => {
const instanceId = 'inst-1';
const mockInstance = {
id: instanceId,
currentState: 'PENDING',
status: WorkflowStatus.ACTIVE,
definition: { compiled: mockCompiledWorkflow },
context: { some: 'data' },
};
mockQueryRunner.manager.findOne.mockResolvedValue(mockInstance);
mockDslService.evaluate.mockReturnValue({
nextState: 'APPROVED',
events: [],
});
await service.processTransition(
instanceId,
'APPROVE',
1,
'Test comment',
{},
[] // Empty array
);
expect(mockQueryRunner.manager.update).not.toHaveBeenCalledWith(
expect.any(Object),
expect.any(Object),
expect.objectContaining({ workflowHistoryId: expect.any(String) })
);
});
});
});
});