HanselGretelBreadCrumbTrailSpec

Overview

The HanselGretelBreadCrumbTrailSpec file contains unit tests for the HanselGretelBreadCrumbTrail class. These tests ensure the correctness and reliability of breadcrumb tracing functionality, including basic tracing, deeper tracing, self-logging callbacks, and console logging.

File Definition

import { BreadCrumbTraceLevel } from '../enumerations/breadCrumbTraceLevel';
import { IBreadCrumbContext } from '../interfaces/breadCrumbContext';
import { IBreadCrumbTrace } from '../interfaces/breadCrumbTrace';
import { HanselGretelBreadCrumbTrail } from './HanselGretelBreadCrumbTrail';

const emitConsoleOnAdd = false;

/**
 * Tests for the HanselGretelBreadCrumbTrail class.
 */
describe('HanselGretelBreadCrumbTrail', () => {
  let context: IBreadCrumbContext;
  let traceLog: Array<IBreadCrumbTrace>;

  beforeEach(() => {
    context = { category: 'test' };
    traceLog = [];
  });

  /**
   * Tests basic tracing functionality.
   */
  it('should trace', () => {
    const traceLog: Array<IBreadCrumbTrace> = [];
    const firstCrumb = HanselGretelBreadCrumbTrail.addCrumb(
      context,
      emitConsoleOnAdd,
      traceLog,
      'HanselGretelBreadCrumbTrail.spec.ts',
      BreadCrumbTraceLevel.Debug,
      1000,
    );
    expect(firstCrumb.date).toBeDefined();
    expect(firstCrumb.IBreadCrumbTrace).toEqual(
      HanselGretelBreadCrumbTrail.IBreadCrumbTrace({
        date: firstCrumb.date,
        functionName: 'HanselGretelBreadCrumbTrail.spec.ts',
        functionArgs: [],
      }),
    );
    const secondCrumb = firstCrumb.addCrumb('trace 1');
    expect(secondCrumb.IBreadCrumbTrace).toEqual(
      HanselGretelBreadCrumbTrail.IBreadCrumbTrace({
        date: secondCrumb.date,
        functionName: 'HanselGretelBreadCrumbTrail.spec.ts',
        functionArgs: ['trace 1'],
      }),
    );
    expect(secondCrumb.date.getUTCMilliseconds()).toBeGreaterThanOrEqual(
      firstCrumb.date.getUTCMilliseconds(),
    );
  });

  /**
   * Tests deeper tracing functionality.
   */
  it('should trace deeper', () => {
    const traceLog: Array<IBreadCrumbTrace> = [];
    const firstCrumb = HanselGretelBreadCrumbTrail.addCrumb(
      context,
      emitConsoleOnAdd,
      traceLog,
      'HanselGretelBreadCrumbTrail.spec.ts',
      BreadCrumbTraceLevel.Debug,
      1000,
    );
    expect(firstCrumb.date).toBeDefined();
    expect(firstCrumb.IBreadCrumbTrace).toEqual(
      HanselGretelBreadCrumbTrail.IBreadCrumbTrace({
        date: firstCrumb.date,
        functionName: 'HanselGretelBreadCrumbTrail.spec.ts',
        functionArgs: [],
      }),
    );
    const forkedCrumb = firstCrumb.forkAndAddCrumb('trace 1', 'trace 2');
    expect(forkedCrumb.IBreadCrumbTrace).toEqual(
      HanselGretelBreadCrumbTrail.IBreadCrumbTrace({
        date: forkedCrumb.date,
        functionName: 'HanselGretelBreadCrumbTrail.spec.ts>trace 1',
        functionArgs: ['trace 2'],
      }),
    );
    expect(forkedCrumb.date.getUTCMilliseconds()).toBeGreaterThanOrEqual(
      firstCrumb.date.getUTCMilliseconds(),
    );
  });

  /**
   * Tests tracing with a self-logging callback.
   */
  it('should trace with self logging callback', () => {
    const traceLog: Array<IBreadCrumbTrace> = [];
    const firstCrumb = HanselGretelBreadCrumbTrail.addCrumb(
      context,
      emitConsoleOnAdd,
      traceLog,
      'HanselGretelBreadCrumbTrail.spec.ts',
      BreadCrumbTraceLevel.Debug,
      1000,
    );
    expect(firstCrumb.date).toBeDefined();
    expect(firstCrumb.IBreadCrumbTrace).toEqual(
      HanselGretelBreadCrumbTrail.IBreadCrumbTrace({
        date: firstCrumb.date,
        functionName: 'HanselGretelBreadCrumbTrail.spec.ts',
        functionArgs: [],
      }),
    );
    const newTrace = 'trace 1';
    const newTraceCompleted = `${newTrace} callback completed`;
    const secondCrumb = firstCrumb.addCrumbWithCallback((crumbResult) => {
      expect(crumbResult.IBreadCrumbTrace).toEqual(
        HanselGretelBreadCrumbTrail.IBreadCrumbTrace({
          date: crumbResult.date,
          functionName: 'HanselGretelBreadCrumbTrail.spec.ts',
          functionArgs: [newTrace],
        }),
      );
      return crumbResult.addCrumb(newTraceCompleted);
    }, newTrace);
    expect(secondCrumb.IBreadCrumbTrace).toEqual(
      HanselGretelBreadCrumbTrail.IBreadCrumbTrace({
        date: secondCrumb.date,
        functionName: 'HanselGretelBreadCrumbTrail.spec.ts',
        functionArgs: [newTraceCompleted],
      }),
    );
  });

  /**
   * Tests forking and tracing with a self-logging callback.
   */
  it('should fork and trace with self logging callback', () => {
    const traceLog: Array<IBreadCrumbTrace> = [];
    const firstCrumb = HanselGretelBreadCrumbTrail.addCrumb(
      context,
      emitConsoleOnAdd,
      traceLog,
      'HanselGretelBreadCrumbTrail.spec.ts',
      BreadCrumbTraceLevel.Debug,
      1000,
    );
    expect(firstCrumb.date).toBeDefined();
    expect(firstCrumb.IBreadCrumbTrace).toEqual(
      HanselGretelBreadCrumbTrail.IBreadCrumbTrace({
        date: firstCrumb.date,
        functionName: 'HanselGretelBreadCrumbTrail.spec.ts',
        functionArgs: [],
      }),
    );
    const newSection = 'section 1';
    const newTrace = 'trace 1';
    const newTraceCompleted = `${newTrace} callback completed`;
    const secondCrumb = firstCrumb.forkAndAddCrumbWithCallback(
      newSection,
      (crumbResult) => {
        expect(crumbResult.IBreadCrumbTrace).toEqual(
          HanselGretelBreadCrumbTrail.IBreadCrumbTrace({
            date: crumbResult.date,
            functionName: 'HanselGretelBreadCrumbTrail.spec.ts>section 1',
            functionArgs: [newTrace],
          }),
        );
        return crumbResult.addCrumb(newTraceCompleted);
      },
      newTrace,
    );
    expect(secondCrumb.IBreadCrumbTrace).toEqual(
      HanselGretelBreadCrumbTrail.IBreadCrumbTrace({
        date: secondCrumb.date,
        functionName: 'HanselGretelBreadCrumbTrail.spec.ts>section 1',
        functionArgs: [newTraceCompleted],
      }),
    );
  });

  /**
   * Tests console logging functionality.
   */
  it('should console log if enabled', () => {
    const traceLog: Array<IBreadCrumbTrace> = [];
    const originalConsoleLog = console.log;
    const logFunc = jest.fn();
    console.log = logFunc;
    let emit = false;
    HanselGretelBreadCrumbTrail.addCrumb(
      context,
      emit,
      traceLog,
      'HanselGretelBreadCrumbTrail.spec.ts',
      BreadCrumbTraceLevel.Debug,
      1000,
    );
    //expect console.log not to have been called
    expect(logFunc).not.toHaveBeenCalled();
    emit = true;
    HanselGretelBreadCrumbTrail.addCrumb(
      context,
      emit,
      traceLog,
      'HanselGretelBreadCrumbTrail.spec.ts',
      BreadCrumbTraceLevel.Debug,
      1000,
    );
    // expect console.log to have been called
    expect(logFunc).toHaveBeenCalledTimes(1);
    console.log = originalConsoleLog;
  });

  /**
   * Tests handling of async operations.
   */
  it('should handle async operations', async () => {
    const asyncOperation = new Promise((resolve) =>
      setTimeout(() => resolve('done'), 100),
    );
    const breadcrumbTrail = new HanselGretelBreadCrumbTrail(
      context,
      false,
      traceLog,
      'asyncTest',
      BreadCrumbTraceLevel.Debug,
      10,
    );
    const resultTrail = await breadcrumbTrail.addCrumbAsync(asyncOperation);

    expect(resultTrail.traceLog.length).toBe(3);
    expect(resultTrail.traceLog[0].functionArgs).toEqual([]);
    expect(resultTrail.traceLog[1].functionArgs).toContain('start');
    expect(resultTrail.traceLog[2].functionArgs).toContain('complete');
  });

  /**
   * Tests memory management functionality.
   */
  it('should properly manage memory limits', () => {
    const maxEntries = 5;
    const breadcrumbTrail = new HanselGretelBreadCrumbTrail(
      context,
      false,
      traceLog,
      'memoryTest',
      BreadCrumbTraceLevel.Debug,
      maxEntries,
    );

    for (let i = 0; i < maxEntries + 2; i++) {
      breadcrumbTrail.addCrumb(`trace ${i}`);
    }

    expect(breadcrumbTrail.traceLog.length).toBe(maxEntries);
    expect(breadcrumbTrail.traceLog[0].functionArgs).toContain('trace 2');
  });

  /**
   * Tests trace filtering functionality.
   */
  it('should correctly filter traces', () => {
    const breadcrumbTrail = new HanselGretelBreadCrumbTrail(
      context,
      false,
      traceLog,
      'filterTest',
      BreadCrumbTraceLevel.Debug,
      10,
    );
    breadcrumbTrail.addCrumb('trace 1');
    breadcrumbTrail.addCrumb('trace 2');
    breadcrumbTrail.addCrumb('trace 3');

    const filteredCrumbs = breadcrumbTrail.findTraces({
      functionArgs: ['trace 2'],
    });
    expect(filteredCrumbs.length).toBe(1);
    expect(filteredCrumbs[0].functionArgs).toContain('trace 2');
  });
});

Tests

should trace

  • Purpose: Tests basic tracing functionality.
  • Example:
    const traceLog: Array<IBreadCrumbTrace> = [];
    const firstCrumb = HanselGretelBreadCrumbTrail.addCrumb(
      context,
      emitConsoleOnAdd,
      traceLog,
      'HanselGretelBreadCrumbTrail.spec.ts',
      BreadCrumbTraceLevel.Debug,
      1000,
    );
    expect(firstCrumb.date).toBeDefined();
    expect(firstCrumb.IBreadCrumbTrace).toEqual(
      HanselGretelBreadCrumbTrail.IBreadCrumbTrace({
        date: firstCrumb.date,
        functionName: 'HanselGretelBreadCrumbTrail.spec.ts',
        functionArgs: [],
      }),
    );
    const secondCrumb = firstCrumb.addCrumb('trace 1');
    expect(secondCrumb.IBreadCrumbTrace).toEqual(
      HanselGretelBreadCrumbTrail.IBreadCrumbTrace({
        date: secondCrumb.date,
        functionName: 'HanselGretelBreadCrumbTrail.spec.ts',
        functionArgs: ['trace 1'],
      }),
    );
    expect(secondCrumb.date.getUTCMilliseconds()).toBeGreaterThanOrEqual(
      firstCrumb.date.getUTCMilliseconds(),
    );
    

should trace deeper

  • Purpose: Tests deeper tracing functionality.
  • Example:
    const traceLog: Array<IBreadCrumbTrace> = [];
    const firstCrumb = HanselGretelBreadCrumbTrail.addCrumb(
      context,
      emitConsoleOnAdd,
      traceLog,
      'HanselGretelBreadCrumbTrail.spec.ts',
      BreadCrumbTraceLevel.Debug,
      1000,
    );
    expect(firstCrumb.date).toBeDefined();
    expect(firstCrumb.IBreadCrumbTrace).toEqual(
      HanselGretelBreadCrumbTrail.IBreadCrumbTrace({
        date: firstCrumb.date,
        functionName: 'HanselGretelBreadCrumbTrail.spec.ts',
        functionArgs: [],
      }),
    );
    const forkedCrumb = firstCrumb.forkAndAddCrumb('trace 1', 'trace 2');
    expect(forkedCrumb.IBreadCrumbTrace).toEqual(
      HanselGretelBreadCrumbTrail.IBreadCrumbTrace({
        date: forkedCrumb.date,
        functionName: 'HanselGretelBreadCrumbTrail.spec.ts>trace 1',
        functionArgs: ['trace 2'],
      }),
    );
    expect(forkedCrumb.date.getUTCMilliseconds()).toBeGreaterThanOrEqual(
      firstCrumb.date.getUTCMilliseconds(),
    );
    

should trace with self logging callback

  • Purpose: Tests tracing with a self-logging callback.
  • Example:
    const traceLog: Array<IBreadCrumbTrace> = [];
    const firstCrumb = HanselGretelBreadCrumbTrail.addCrumb(
      context,
      emitConsoleOnAdd,
      traceLog,
      'HanselGretelBreadCrumbTrail.spec.ts',
      BreadCrumbTraceLevel.Debug,
      1000,
    );
    expect(firstCrumb.date).toBeDefined();
    expect(firstCrumb.IBreadCrumbTrace).toEqual(
      HanselGretelBreadCrumbTrail.IBreadCrumbTrace({
        date: firstCrumb.date,
        functionName: 'HanselGretelBreadCrumbTrail.spec.ts',
        functionArgs: [],
      }),
    );
    const newTrace = 'trace 1';
    const newTraceCompleted = `${newTrace} callback completed`;
    const secondCrumb = firstCrumb.addCrumbWithCallback((crumbResult) => {
      expect(crumbResult.IBreadCrumbTrace).toEqual(
        HanselGretelBreadCrumbTrail.IBreadCrumbTrace({
          date: crumbResult.date,
          functionName: 'HanselGretelBreadCrumbTrail.spec.ts',
          functionArgs: [newTrace],
        }),
      );
      return crumbResult.addCrumb(newTraceCompleted);
    }, newTrace);
    expect(secondCrumb.IBreadCrumbTrace).toEqual(
      HanselGretelBreadCrumbTrail.IBreadCrumbTrace({
        date: secondCrumb.date,
        functionName: 'HanselGretelBreadCrumbTrail.spec.ts',
        functionArgs: [newTraceCompleted],
      }),
    );
    

should fork and trace with self logging callback

  • Purpose: Tests forking and tracing with a self-logging callback.
  • Example:
    const traceLog: Array<IBreadCrumbTrace> = [];
    const firstCrumb = HanselGretelBreadCrumbTrail.addCrumb(
      context,
      emitConsoleOnAdd,
      traceLog,
      'HanselGretelBreadCrumbTrail.spec.ts',
      BreadCrumbTraceLevel.Debug,
      1000,
    );
    expect(firstCrumb.date).toBeDefined();
    expect(firstCrumb.IBreadCrumbTrace).toEqual(
      HanselGretelBreadCrumbTrail.IBreadCrumbTrace({
        date: firstCrumb.date,
        functionName: 'HanselGretelBreadCrumbTrail.spec.ts',
        functionArgs: [],
      }),
    );
    const newSection = 'section 1';
    const newTrace = 'trace 1';
    const newTraceCompleted = `${newTrace} callback completed`;
    const secondCrumb = firstCrumb.forkAndAddCrumbWithCallback(
      newSection,
      (crumbResult) => {
        expect(crumbResult.IBreadCrumbTrace).toEqual(
          HanselGretelBreadCrumbTrail.IBreadCrumbTrace({
            date: crumbResult.date,
            functionName: 'HanselGretelBreadCrumbTrail.spec.ts>section 1',
            functionArgs: [newTrace],
          }),
        );
        return crumbResult.addCrumb(newTraceCompleted);
      },
      newTrace,
    );
    expect(secondCrumb.IBreadCrumbTrace).toEqual(
      HanselGretelBreadCrumbTrail.IBreadCrumbTrace({
        date: secondCrumb.date,
        functionName: 'HanselGretelBreadCrumbTrail.spec.ts>section 1',
        functionArgs: [newTraceCompleted],
      }),
    );
    

should console log if enabled

  • Purpose: Tests console logging functionality.
  • Example:
    const traceLog: Array<IBreadCrumbTrace> = [];
    const originalConsoleLog = console.log;
    const logFunc = jest.fn();
    console.log = logFunc;
    let emit = false;
    HanselGretelBreadCrumbTrail.addCrumb(
      context,
      emit,
      traceLog,
      'HanselGretelBreadCrumbTrail.spec.ts',
      BreadCrumbTraceLevel.Debug,
      1000,
    );
    //expect console.log not to have been called
    expect(logFunc).not.toHaveBeenCalled();
    emit = true;
    HanselGretelBreadCrumbTrail.addCrumb(
      context,
      emit,
      traceLog,
      'HanselGretelBreadCrumbTrail.spec.ts',
      BreadCrumbTraceLevel.Debug,
      1000,
    );
    // expect console.log to have been called
    expect(logFunc).toHaveBeenCalledTimes(1);
    console.log = originalConsoleLog;
    

should handle async operations

  • Purpose: Tests handling of async operations.
  • Example:

    const asyncOperation = new Promise((resolve) =>
      setTimeout(() => resolve('done'), 100),
    );
    const breadcrumbTrail = new HanselGretelBreadCrumbTrail(
      context,
      false,
      traceLog,
      'asyncTest',
      BreadCrumbTraceLevel.Debug,
      10,
    );
    const resultTrail = await breadcrumbTrail.addCrumbAsync(asyncOperation);
    
    expect(resultTrail.traceLog.length).toBe(3);
    expect(resultTrail.traceLog[0].functionArgs).toEqual([]);
    expect(resultTrail.traceLog[1].functionArgs).toContain('start');
    expect(resultTrail.traceLog[2].functionArgs).toContain('complete');
    

should properly manage memory limits

  • Purpose: Tests memory management functionality.
  • Example:

    const maxEntries = 5;
    const breadcrumbTrail = new HanselGretelBreadCrumbTrail(
      context,
      false,
      traceLog,
      'memoryTest',
      BreadCrumbTraceLevel.Debug,
      maxEntries,
    );
    
    for (let i = 0; i < maxEntries + 2; i++) {
      breadcrumbTrail.addCrumb(`trace ${i}`);
    }
    
    expect(breadcrumbTrail.traceLog.length).toBe(maxEntries);
    expect(breadcrumbTrail.traceLog[0].functionArgs).toContain('trace 2');
    

should correctly filter traces

  • Purpose: Tests trace filtering functionality.
  • Example:

    const breadcrumbTrail = new HanselGretelBreadCrumbTrail(
      context,
      false,
      traceLog,
      'filterTest',
      BreadCrumbTraceLevel.Debug,
      10,
    );
    breadcrumbTrail.addCrumb('trace 1');
    breadcrumbTrail.addCrumb('trace 2');
    breadcrumbTrail.addCrumb('trace 3');
    
    const filteredCrumbs = breadcrumbTrail.findTraces({
      functionArgs: ['trace 2'],
    });
    expect(filteredCrumbs.length).toBe(1);
    expect(filteredCrumbs[0].functionArgs).toContain('trace 2');
    

Conclusion

The HanselGretelBreadCrumbTrailSpec file provides comprehensive unit tests for the HanselGretelBreadCrumbTrail class, ensuring the correctness and reliability of breadcrumb tracing functionality.