mirror of
https://github.com/n8n-io/n8n.git
synced 2026-05-24 21:35:24 +02:00
96 lines
3.2 KiB
TypeScript
96 lines
3.2 KiB
TypeScript
import type { IExecuteData, IExecuteFunctions, ITaskMetadata } from '../src/interfaces';
|
|
import { accumulateTokenUsage, parseErrorMetadata } from '../src/metadata-utils';
|
|
|
|
function createMockContext(metadata?: ITaskMetadata): IExecuteFunctions {
|
|
const executeData: IExecuteData = {
|
|
data: {},
|
|
node: {} as IExecuteData['node'],
|
|
source: null,
|
|
metadata,
|
|
};
|
|
return {
|
|
getExecuteData: () => executeData,
|
|
setMetadata(newMetadata: ITaskMetadata) {
|
|
executeData.metadata = { ...executeData.metadata, ...newMetadata };
|
|
},
|
|
} as unknown as IExecuteFunctions;
|
|
}
|
|
|
|
describe('MetadataUtils', () => {
|
|
describe('accumulateTokenUsage', () => {
|
|
it('should set token usage when no previous metadata exists', () => {
|
|
const context = createMockContext();
|
|
accumulateTokenUsage(context, 100, 50);
|
|
expect(context.getExecuteData().metadata?.tokenUsage).toEqual({
|
|
inputTokens: 100,
|
|
outputTokens: 50,
|
|
});
|
|
});
|
|
|
|
it('should accumulate tokens across multiple calls', () => {
|
|
const context = createMockContext();
|
|
accumulateTokenUsage(context, 100, 50);
|
|
accumulateTokenUsage(context, 200, 80);
|
|
accumulateTokenUsage(context, 50, 20);
|
|
expect(context.getExecuteData().metadata?.tokenUsage).toEqual({
|
|
inputTokens: 350,
|
|
outputTokens: 150,
|
|
});
|
|
});
|
|
|
|
it('should preserve existing metadata fields', () => {
|
|
const context = createMockContext({ subExecutionsCount: 3 });
|
|
accumulateTokenUsage(context, 100, 50);
|
|
const metadata = context.getExecuteData().metadata;
|
|
expect(metadata?.subExecutionsCount).toBe(3);
|
|
expect(metadata?.tokenUsage).toEqual({ inputTokens: 100, outputTokens: 50 });
|
|
});
|
|
});
|
|
|
|
describe('parseMetadataFromError', () => {
|
|
const expectedMetadata = {
|
|
subExecution: {
|
|
executionId: '123',
|
|
workflowId: '456',
|
|
},
|
|
subExecutionsCount: 1,
|
|
};
|
|
|
|
it('should return undefined if error does not have response or both keys on the object', () => {
|
|
const error = { message: 'An error occurred' };
|
|
const result = parseErrorMetadata(error);
|
|
expect(result).toBeUndefined();
|
|
});
|
|
|
|
it('should return undefined if errorResponse only has workflowId key', () => {
|
|
const error = { errorResponse: { executionId: '123' } };
|
|
const result = parseErrorMetadata(error);
|
|
expect(result).toBeUndefined();
|
|
});
|
|
|
|
it('should return undefined if error only has executionId key', () => {
|
|
const error = { executionId: '123' };
|
|
const result = parseErrorMetadata(error);
|
|
expect(result).toBeUndefined();
|
|
});
|
|
|
|
it('should support executionId and workflowId key directly on the error object', () => {
|
|
const error = { executionId: '123', workflowId: '456' };
|
|
const result = parseErrorMetadata(error);
|
|
expect(result).toEqual(expectedMetadata);
|
|
});
|
|
|
|
it('should return undefined if error response does not have subworkflow data', () => {
|
|
const error = { errorResponse: { someKey: 'someValue' } };
|
|
const result = parseErrorMetadata(error);
|
|
expect(result).toBeUndefined();
|
|
});
|
|
|
|
it('should return metadata if error response has subworkflow data', () => {
|
|
const error = { errorResponse: { executionId: '123', workflowId: '456' } };
|
|
const result = parseErrorMetadata(error);
|
|
expect(result).toEqual(expectedMetadata);
|
|
});
|
|
});
|
|
});
|