bsalex/typed-path

View on GitHub
index.spec.ts

Summary

Maintainability
B
4 hrs
Test Coverage
import {typedPath, TypedPathKey} from './index';

export const sym = Symbol('SomeSymbol');

export type TestType = {
    a: {
        testFunc: () => {result: string};
        b: {
            arrayOfArrays: string[][];
            c: number;
            f: {test: string; blah: {path?: string}; arr: string[]}[];
        };
        [sym]: {
            g: string;
        };
    };
};

interface OptionalThing {
    foo: string;
    bar?: string;
}

const testAdditionalHandlers = {
    $abs: (path: TypedPathKey[]) =>
        typedPath<TestType, typeof testAdditionalHandlers>(testAdditionalHandlers, ['', ...path]),
    $url: (path: TypedPathKey[]) => path.join('/')
};

const testCases = {
    'regular field path': {
        path: typedPath<TestType>().a.b.c,
        expectedResults: {
            $path: 'a.b.c',
            $raw: ['a', 'b', 'c'],
            $rawPath: ['a', 'b', 'c']
        }
    },
    'path with index': {
        path: typedPath<TestType>().a.b.f[3],
        expectedResults: {
            $path: 'a.b.f[3]',
            $raw: ['a', 'b', 'f', '3'],
            $rawPath: ['a', 'b', 'f', 3]
        }
    },
    'path with index of index for array of array': {
        path: typedPath<TestType>().a.b.arrayOfArrays[3][3],
        expectedResults: {
            $path: 'a.b.arrayOfArrays[3][3]',
            $raw: ['a', 'b', 'arrayOfArrays', '3', '3'],
            $rawPath: ['a', 'b', 'arrayOfArrays', 3, 3]
        }
    },
    'path with function': {
        path: typedPath<TestType>().a.testFunc,
        expectedResults: {
            $path: 'a.testFunc',
            $raw: ['a', 'testFunc'],
            $rawPath: ['a', 'testFunc']
        }
    },
    'path with function return type': {
        path: typedPath<TestType>().a.testFunc.result,
        expectedResults: {
            $path: 'a.testFunc.result',
            $raw: ['a', 'testFunc', 'result'],
            $rawPath: ['a', 'testFunc', 'result']
        }
    },
    'path with optional field': {
        path: typedPath<OptionalThing>().bar,
        expectedResults: {
            $path: 'bar',
            $raw: ['bar'],
            $rawPath: ['bar']
        }
    },
    'path with symbol': {
        path: typedPath<TestType>().a[sym].g,
        expectedResults: {
            $path: 'a.Symbol(SomeSymbol).g',
            $raw: ['a', 'Symbol(SomeSymbol)', 'g'],
            $rawPath: ['a', sym, 'g']
        }
    }
};

describe('Typed path', () => {
    for (const [testCaseName, {path, expectedResults}] of Object.entries(testCases)) {
        describe(`for ${testCaseName}`, () => {
            if ('$path' in expectedResults) {
                it(`should have correct $path special field value`, () => {
                    expect(path.$path).toEqual(expectedResults.$path);
                });

                it(`should have correct .toString() special field value`, () => {
                    expect(path.toString()).toEqual(expectedResults.$path);
                });

                it(`should have correct .valueOf() special field value`, () => {
                    expect(path.valueOf()).toEqual(expectedResults.$path);
                });
            }

            if ('$raw' in expectedResults) {
                it(`should have correct $raw special field value`, () => {
                    expect(path.$raw).toEqual(expectedResults.$raw);
                });
            }

            if ('$rawPath' in expectedResults) {
                it(`should have correct $rawPath special field value`, () => {
                    expect(path.$rawPath).toEqual(expectedResults.$rawPath);
                });
            }
        });
    }

    it('should get path with a string tag', () => {
        expect(Object.prototype.toString.call(typedPath<TestType>().a.b.f[3].blah.path)).toEqual(
            '[object a.b.f[3].blah.path]'
        );
    });

    it('should work with extended handlers', () => {
        expect(typedPath<TestType, typeof testAdditionalHandlers>(testAdditionalHandlers).a.b.c.$url).toEqual('a/b/c');
    });

    it('should work with chained extended handlers', () => {
        expect(typedPath<TestType, typeof testAdditionalHandlers>(testAdditionalHandlers).a.b.c.$abs.$url).toEqual(
            '/a/b/c'
        );
    });
});