Skip to content

Commit

Permalink
refactor(core): add injectFromBase
Browse files Browse the repository at this point in the history
  • Loading branch information
notaphplover committed Dec 20, 2024
1 parent 55cb4e4 commit 074b22e
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { afterAll, beforeAll, describe, expect, it, jest } from '@jest/globals';

jest.mock('@inversifyjs/prototype-utils');

import { Newable } from '@inversifyjs/common';
import { getBaseType } from '@inversifyjs/prototype-utils';

jest.mock('./injectFrom');

import { InversifyCoreError } from '../../error/models/InversifyCoreError';
import { InversifyCoreErrorKind } from '../../error/models/InversifyCoreErrorKind';
import { InjectFromBaseOptions } from '../models/InjectFromBaseOptions';
import { InjectFromOptions } from '../models/InjectFromOptions';
import { injectFrom } from './injectFrom';
import { injectFromBase } from './injectFromBase';

describe(injectFromBase.name, () => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
let targetFixture: Function;

beforeAll(() => {
targetFixture = class {};
});

describe('when called, and getBaseType returns Newable', () => {
let injectFromBaseOptionsFixture: InjectFromBaseOptions;

let baseTypefixture: Newable;
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
let injectFromResultMock: jest.Mock<(target: Function) => void>;

let result: unknown;

beforeAll(() => {
injectFromBaseOptionsFixture = {
extendConstructorArguments: true,
extendProperties: true,
};
baseTypefixture = class Base {};
injectFromResultMock = jest.fn().mockReturnValueOnce(undefined);

(getBaseType as jest.Mock<typeof getBaseType>).mockReturnValueOnce(
baseTypefixture,
);

(injectFrom as jest.Mock<typeof injectFrom>).mockReturnValueOnce(
injectFromResultMock,
);

result = injectFromBase(injectFromBaseOptionsFixture)(targetFixture);
});

afterAll(() => {
jest.clearAllMocks();
});

it('should call getBaseType()', () => {
expect(getBaseType).toHaveBeenCalledTimes(1);
expect(getBaseType).toHaveBeenCalledWith(targetFixture);
});

it('should call injectFrom()', () => {
const expected: InjectFromOptions = {
...injectFromBaseOptionsFixture,
type: baseTypefixture,
};

expect(injectFrom).toHaveBeenCalledTimes(1);
expect(injectFrom).toHaveBeenCalledWith(expected);

expect(injectFromResultMock).toHaveBeenCalledTimes(1);
expect(injectFromResultMock).toHaveBeenCalledWith(targetFixture);
});

it('should return undefined', () => {
expect(result).toBeUndefined();
});
});

describe('when called, and getBaseType returns undefined', () => {
let injectFromBaseOptionsFixture: InjectFromBaseOptions;

let result: unknown;

beforeAll(() => {
injectFromBaseOptionsFixture = {
extendConstructorArguments: true,
extendProperties: true,
};

(getBaseType as jest.Mock<typeof getBaseType>).mockReturnValueOnce(
undefined,
);

try {
injectFromBase(injectFromBaseOptionsFixture)(targetFixture);
} catch (error: unknown) {
result = error;
}
});

afterAll(() => {
jest.clearAllMocks();
});

it('should call getBaseType()', () => {
expect(getBaseType).toHaveBeenCalledTimes(1);
expect(getBaseType).toHaveBeenCalledWith(targetFixture);
});

it('should return undefined', () => {
const expectedErrorProperties: Partial<InversifyCoreError> = {
kind: InversifyCoreErrorKind.injectionDecoratorConflict,
message: `Expected base type for type "${targetFixture.name}", none found.`,
};

expect(result).toBeInstanceOf(InversifyCoreError);
expect(result).toStrictEqual(
expect.objectContaining(expectedErrorProperties),
);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Newable } from '@inversifyjs/common';
import { getBaseType } from '@inversifyjs/prototype-utils';

import { InversifyCoreError } from '../../error/models/InversifyCoreError';
import { InversifyCoreErrorKind } from '../../error/models/InversifyCoreErrorKind';
import { InjectFromBaseOptions } from '../models/InjectFromBaseOptions';
import { injectFrom } from './injectFrom';

export function injectFromBase(options: InjectFromBaseOptions): ClassDecorator {
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
return (target: Function): void => {
const baseType: Newable | undefined = getBaseType(target as Newable);

if (baseType === undefined) {
throw new InversifyCoreError(
InversifyCoreErrorKind.injectionDecoratorConflict,
`Expected base type for type "${target.name}", none found.`,
);
}

injectFrom({
...options,
type: baseType,
})(target);
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface InjectFromBaseOptions {
extendConstructorArguments?: boolean | undefined;
extendProperties?: boolean | undefined;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Newable } from '@inversifyjs/common';

export interface InjectFromOptions {
extendConstructorArguments?: boolean;
extendProperties?: boolean;
extendConstructorArguments?: boolean | undefined;
extendProperties?: boolean | undefined;
type: Newable;
}

0 comments on commit 074b22e

Please sign in to comment.