UNPKG

execution-engine

Version:

A TypeScript library for tracing and visualizing code execution workflows.

172 lines (171 loc) 9.11 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const trace_1 = require("./trace"); describe('ExecutionTrace', () => { const executionTraceExpectation = { id: expect.any(String), inputs: expect.any(Array), startTime: expect.any(Date), endTime: expect.any(Date), duration: expect.any(Number), elapsedTime: expect.any(String) }; const successfullExecutionTraceExpectation = { ...executionTraceExpectation, outputs: expect.anything() }; const failedExecutionTraceExpectation = { ...executionTraceExpectation, errors: expect.anything() }; describe('Tracing synchronous functions', () => { it('should trace a synchronous function without parameters', () => { function helloWorld() { return 'Hello World response No Params!'; } const response = (0, trace_1.executionTrace)(helloWorld); expect(response).toMatchObject(successfullExecutionTraceExpectation); }); it('should trace a synchronous function with trace parameter', () => { function helloWorldWithTrace(trace) { trace.narratives = ['HELLO WORLD AS NARRATIVE!']; return 'Hello World response with Trace!'; } const response = (0, trace_1.executionTrace)(helloWorldWithTrace, undefined, undefined, { injectContextInArgs: true }); expect(response).toMatchObject(successfullExecutionTraceExpectation); }); }); describe('Tracing asynchronous functions', () => { it('should trace an async function without parameters', async () => { async function helloWorldAsync() { return 'Hello World async response!'; } const response = await (0, trace_1.executionTrace)(helloWorldAsync); expect(response).toMatchObject(successfullExecutionTraceExpectation); }); it('should trace an async function with trace parameter', async () => { async function helloWorldAsyncWithTrace(trace) { trace.narratives = ['HELLO WORLD AS NARRATIVE!']; return 'Hello World async response with Trace!'; } const response = await (0, trace_1.executionTrace)(helloWorldAsyncWithTrace, undefined, undefined, { injectContextInArgs: true }); expect(response).toMatchObject(successfullExecutionTraceExpectation); }); }); describe('Tracing error scenarios', () => { function throwErrorFunction(param) { throw new Error(`Sample Error: ${param}`); } async function asyncThrowErrorFunction(param) { throw new Error(`Sample Async Error: ${param}`); } it('should trace a synchronous function throwing an error', () => { const response = (0, trace_1.executionTrace)(throwErrorFunction, ['ErrorParam'], undefined, { errorStrategy: 'catch' }); expect(response).toMatchObject({ ...failedExecutionTraceExpectation, inputs: ['ErrorParam'], errors: [ { code: undefined, message: 'Sample Error: ErrorParam', name: 'Error' } ] }); }); it('should trace an async function throwing an error', async () => { const response = await (0, trace_1.executionTrace)(asyncThrowErrorFunction, ['ErrorParam'], undefined, { errorStrategy: 'catch' }); expect(response).toMatchObject({ ...failedExecutionTraceExpectation, inputs: ['ErrorParam'], errors: [ { code: undefined, message: 'Sample Async Error: ErrorParam', name: 'Error' } ] }); }); }); describe('Tracing function onTraceEventMock and traceContext', () => { const divisionFunction = (x, y, traceContext) => { if (y === 0) { traceContext['narratives'] = [`Throwing because division of ${x} by ${y}`]; throw new Error('Throwing because division by zero is not allowed.'); } traceContext['narratives'] = [`Calculating the division of ${x} by ${y}`]; return x / y; }; const fetchDataFunction = async (url, traceContext) => { traceContext['narratives'] = [`Fetching data from ${url}`]; if (!url.startsWith('http')) { traceContext['narratives'] = [`Throwing because the URL ${url} is invalid`]; throw new Error('Invalid URL provided.'); } return { data: 'Success' }; }; it('should sync trace successfully and pass correct onTraceEventMock and traceContext', () => { const onTraceEventMock = jest.fn(); const response = trace_1.executionTrace.bind({ __execution: { context: { metadata: { requestId: '12345' } } } })(divisionFunction, [1, 2], onTraceEventMock, { injectContextInArgs: true }); expect(onTraceEventMock).toHaveBeenCalledWith(expect.objectContaining({ metadata: expect.any(Object), ...successfullExecutionTraceExpectation, narratives: ['Calculating the division of 1 by 2'] })); expect(response).toMatchObject(successfullExecutionTraceExpectation); }); it('should sync trace errors and pass correct onTraceEventMock and traceContext', () => { const onTraceEventMock = jest.fn(); const traceContextMock = { context: { metadata: { requestId: '12345' } } }; const response = trace_1.executionTrace.bind({ __execution: traceContextMock })(divisionFunction, [1, 0], onTraceEventMock, { errorStrategy: 'catch', contextKey: '__execution', injectContextInArgs: true }); expect(onTraceEventMock).toHaveBeenCalledWith(expect.objectContaining({ ...failedExecutionTraceExpectation, ...traceContextMock, narratives: ['Throwing because division of 1 by 0'] })); expect(response).toMatchObject(failedExecutionTraceExpectation); }); it('should async trace successfully and pass correct onTraceEventMock and traceContext', async () => { const onTraceEventMock = jest.fn(); const traceContextMock = { context: { metadata: { requestId: '12345' } } }; const response = await trace_1.executionTrace.bind({ __execution: traceContextMock })(fetchDataFunction, ['https://api.example.com/data'], onTraceEventMock, { contextKey: '__execution', injectContextInArgs: true }); expect(onTraceEventMock).toHaveBeenCalledWith(expect.objectContaining({ ...successfullExecutionTraceExpectation, ...traceContextMock, narratives: ['Fetching data from https://api.example.com/data'] })); expect(response).toMatchObject(successfullExecutionTraceExpectation); }); it('should async trace errors and pass correct onTraceEventMock and traceContext', async () => { const onTraceEventMock = jest.fn(); const traceContextMock = { context: { metadata: { requestId: '12345' } } }; const response = await trace_1.executionTrace.bind({ __execution: traceContextMock })(fetchDataFunction, ['invalid-url'], onTraceEventMock, { errorStrategy: 'catch', contextKey: '__execution', injectContextInArgs: true }); expect(onTraceEventMock).toHaveBeenCalledWith(expect.objectContaining({ ...failedExecutionTraceExpectation, ...traceContextMock, narratives: ['Throwing because the URL invalid-url is invalid'] })); expect(response).toMatchObject(failedExecutionTraceExpectation); }); it('should throw an error and trace context when provided with an invalid URL', async () => { const onTraceEventMock = jest.fn(); const traceContextMock = { context: { metadata: { requestId: '12345' } } }; // Expect the trace function to throw an error for an invalid URL await expect(trace_1.executionTrace.bind({ __execution: traceContextMock })(fetchDataFunction, ['invalid-url'], onTraceEventMock, { contextKey: '__execution', injectContextInArgs: true })).rejects.toThrow('Invalid URL provided.'); // Check the error message expect(onTraceEventMock).toHaveBeenCalledWith(expect.objectContaining({ ...failedExecutionTraceExpectation, ...traceContextMock, narratives: ['Throwing because the URL invalid-url is invalid'] })); }); }); });