Skip to content

Commit

Permalink
feat: Add shorthands for decorating to make addition of e.g. jest.spy…
Browse files Browse the repository at this point in the history
… easier
  • Loading branch information
jansav committed Jun 14, 2022
1 parent 96dd665 commit 350a957
Show file tree
Hide file tree
Showing 3 changed files with 229 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import reject from 'lodash/fp/reject';
import { pipeline } from '@ogre-tools/fp';
import nth from 'lodash/fp/nth';
import overSome from 'lodash/fp/overSome';
import getInjectable from '../getInjectable/getInjectable';

export default () => {
let injectables = [];
Expand Down Expand Up @@ -175,15 +176,43 @@ export default () => {
});
};

const register = withRegistrationDecorators(nonDecoratedRegister);

const decorate = (alias, decorator) => {
const decoratorInjectable = getInjectable({
id: `${alias.id}-decorator-${Math.random()}`,
injectionToken: injectionDecoratorToken,
decorable: false,

instantiate: () => ({
decorate: decorator,
target: alias,
}),
});

register(decoratorInjectable);
};

const privateDi = {
inject: decoratedPrivateInject,

injectMany: decoratedPrivateInjectMany,

register: withRegistrationDecorators(nonDecoratedRegister),
register,

deregister: withDeregistrationDecorators(nonDecoratedDeregister),

decorate,

decorateFunction: (alias, decorator) => {
decorate(
alias,
toBeDecorated =>
(...instantiation) =>
decorator(toBeDecorated(...instantiation)),
);
},

override: (alias, instantiateStub) => {
const originalInjectable = injectables.find(isRelatedTo(alias));

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import getInjectable from '../getInjectable/getInjectable';
import createContainer from './createContainer';

describe('createContainer.targeted-decoration-for-function-via-shorthand', () => {
it('given decorating function, when called, returns the decorated value', () => {
const someInjectable = getInjectable({
id: 'some-some-injectable',

instantiate: (di, instantiationParameter) => parameter =>
`some(${instantiationParameter}(${parameter}))`,
});

const di = createContainer();

di.register(someInjectable);

const decorator =
toBeDecorated =>
(...args) =>
`decorator(${toBeDecorated(...args)})`;

di.decorateFunction(someInjectable, decorator);

const getActual = di.inject(someInjectable, 'some-instantiation-parameter');

const actual = getActual('some-parameter');

expect(actual).toBe(
'decorator(some(some-instantiation-parameter(some-parameter)))',
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import getInjectable from '../getInjectable/getInjectable';
import createContainer, { injectionDecoratorToken } from './createContainer';
import getInjectionToken from '../getInjectionToken/getInjectionToken';

describe('createContainer.targeted-decoration-via-shorthand', () => {
it('given decorator targeting child, when parent is injected, decorates instance and instantiation parameter of only child', () => {
const decorator =
toBeDecorated =>
(alias, instantiationParameter, ...args) => {
const decoratedInstantiationParameter = `decorated-parameter(${instantiationParameter})`;

return `decorated-instance(${toBeDecorated(
alias,
decoratedInstantiationParameter,
...args,
)})`;
};

const childInjectable = getInjectable({
id: 'some-child-injectable',

instantiate: (di, instantiationParameter) =>
`child(${instantiationParameter})`,
});

const parentInjectable = getInjectable({
id: 'some-parent-injectable',

instantiate: (di, instantiationParameter) => {
const childInstance = di.inject(childInjectable, 'child-parameter');

return `parent(${instantiationParameter}) -> ${childInstance}`;
},
});

const di = createContainer();

di.register(parentInjectable, childInjectable);

di.decorate(childInjectable, decorator);

const actual = di.inject(parentInjectable, 'parent-parameter');

expect(actual).toBe(
'parent(parent-parameter) -> decorated-instance(child(decorated-parameter(child-parameter)))',
);
});

it('given decorator targeting an injection token and child implementing the token, when parent is injected, decorates instance and instantiation parameter of only the child', () => {
const someInjectionTokenForTargetedDecoration = getInjectionToken({
id: 'some-injection-token-for-targeted-decoration',
});

let decorator = injectToBeDecorated => (alias, instantiationParameter) => {
const decoratedParameter = `decorated-parameter(${instantiationParameter})`;

return `decorated-instance(${injectToBeDecorated(
alias,
decoratedParameter,
)})`;
};

const childInjectable = getInjectable({
id: 'some-child-injectable',

instantiate: (di, instantiationParameter) =>
`child(${instantiationParameter})`,

injectionToken: someInjectionTokenForTargetedDecoration,
});

const parentInjectable = getInjectable({
id: 'some-parent-injectable',

instantiate: (di, instantiationParameter) => {
const childInstance = di.inject(childInjectable, 'child-parameter');

return `parent(${instantiationParameter}) -> ${childInstance}`;
},
});

const di = createContainer();

di.register(parentInjectable, childInjectable);

di.decorate(someInjectionTokenForTargetedDecoration, decorator);

const actual = di.inject(parentInjectable, 'parent-parameter');

expect(actual).toBe(
'parent(parent-parameter) -> decorated-instance(child(decorated-parameter(child-parameter)))',
);
});

it('given decorating multiple times, when injected, decorates instance and instantiation parameter on order', () => {
const someDecorator =
toBeDecorated =>
(alias, instantiationParameter, ...args) => {
const decoratedInstantiationParameter = `some-decorated-parameter(${instantiationParameter})`;

return `some-decorated-instance(${toBeDecorated(
alias,
decoratedInstantiationParameter,
...args,
)})`;
};

const someOtherDecorator =
toBeDecorated =>
(alias, instantiationParameter, ...args) => {
const decoratedInstantiationParameter = `some-other-decorated-parameter(${instantiationParameter})`;

return `some-other-decorated-instance(${toBeDecorated(
alias,
decoratedInstantiationParameter,
...args,
)})`;
};

const someInjectable = getInjectable({
id: 'some-some-injectable',

instantiate: (di, instantiationParameter) =>
`some(${instantiationParameter})`,
});

const di = createContainer();

di.register(someInjectable);

di.decorate(someInjectable, someDecorator);
di.decorate(someInjectable, someOtherDecorator);

const actual = di.inject(someInjectable, 'some-parameter');

expect(actual).toBe(
'some-other-decorated-instance(some-decorated-instance(some(some-decorated-parameter(some-other-decorated-parameter(some-parameter)))))',
);
});

fit('asd', () => {
const someInjectable = getInjectable({
id: 'some-some-injectable',

instantiate: (di, instantiationParameter) => () =>
`some(${instantiationParameter})`,
});

const di = createContainer();

di.register(someInjectable);

di.decorate(
someInjectable,
toBeDecorated =>
(...instantiation) =>
jest.fn(toBeDecorated(...instantiation)),
);

const getActual = di.inject(someInjectable, 'some-parameter');

console.log(getActual);
const actual = getActual('asd');

expect(getActual).toHaveBeenCalledWith('asd');
});
});

0 comments on commit 350a957

Please sign in to comment.