Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add decorateAll & getDefinition methods to DapiWrapper class #16

Merged
merged 1 commit into from
Feb 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,16 @@ The class also allows to decorate the Dapi functions with decorators and hooks.

#### Methods

##### `getDefinition`

`DapiDefinition` getter.

**Syntax**:

```Typescript
getDefinition(): DapiDefinition<DEPENDENCIES, DAPI>
```

##### `getDependencies`

Dependencies getter.
Expand Down Expand Up @@ -471,6 +481,27 @@ Removes a decorator from the `DapiWrapper` instance.
- `key` - The name of the decorated method. Must be a key of the [`DapiDefinition.fns`](#dapidefinition) fns dictionary.
- `decorator` - The decorator function to be removed from the method.

##### `decorateAll`

Decorates all the `DapiDefinition.fns` with the passed decorator.

**Syntax**:

```Typescript
decorateAll(decorator: DecoratorFn<DAPI[keyof DAPI], DapiWrapper>): () => void
```

**Parameters**:

- `decorator` - The decorator function to be added to the method. Each decorator must accept the following arguments
- `fn` - The function to be decorated.
- `deps` - The dependencies of the [`DapiDefinition.fns`](#dapidefinition).
- `args` - The arguments passed to the method.

**Returns**:

- Function to remove the all the added that accepts no arguments.

##### `addHook`

Adds a hook to a `DapiFn` of the `DapiWrapper` instance. Hooks are functions that are called before (`hookType` = `'pre'`) or after (`hookType` = `'post'`) the `DapiFn` is called.
Expand Down
28 changes: 28 additions & 0 deletions src/DapiMixin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,15 @@ export function DapiMixin<DEPENDENCIES, DAPI extends DapiFns<DEPENDENCIES>, T ex
this.__definition.dependencies = newDeps;
}

/**
* DapiDefinition getter.
*
* @returns DapiDefinition
*/
getDefinition() {
return this.__definition;
}

/**
* Returns a JSON representation of the `DapiWrapper` instance.
* @param replacer An array of strings and numbers that acts as an approved list for selecting the object properties that will be stringified.
Expand Down Expand Up @@ -241,6 +250,25 @@ export function DapiMixin<DEPENDENCIES, DAPI extends DapiFns<DEPENDENCIES>, T ex
};
}

/**
* Decorates all the Dapi functions of the `DapiWrapper`'s Dapi functions dictionary.
* @param decorator The decorator function. The decorator function receives the decorated function as its first argument and the rest of the arguments are the arguments of the decorated function.
* @returns A function to remove all the added decorators.
*/
decorateAll(decorator: DecoratorFn<DAPI[keyof DAPI], DapiWrapper>) {
const removeDecorators: (() => void)[] = [];

for (const key of Object.keys(this.__definition.fns)) {
removeDecorators.push(this.addDecorator(key as keyof DAPI, decorator));
}

return () => {
for (const removeDecorator of removeDecorators) {
removeDecorator();
}
};
}

/**
* Removes a decorator from the DapiWrapper instance.
* @param key The key of the function to remove the decorator from. Must be a key of the `DapiDefinition.fns` dictionary.
Expand Down
42 changes: 41 additions & 1 deletion src/__tests__/DapiMixin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,13 @@ describe('DapiMixin', () => {
assert.deepStrictEqual(testClass.getDependencies(), newDependencies);
});

it('should expose a definition getter', () => {
const TestClass = DapiMixin(definition, BaseTestClass);
const instance = new TestClass();

assert.deepStrictEqual(instance.getDefinition(), definition);
});

it('should throw if you try to set the dependencies to a falsy value', () => {
const TestClass = DapiMixin(definition, BaseTestClass);
const instance = new TestClass();
Expand Down Expand Up @@ -308,7 +315,7 @@ describe('DapiMixin', () => {
assert.throws(() => instance.command4());
});

it('should be possible to decorate the commands', () => {
it('should be possible to decorate the dapi fns', () => {
const TestClass = DapiMixin(definition, BaseTestClass);
const instance = new TestClass();
const decorator = mock.fn(function (method, ...args) {
Expand Down Expand Up @@ -685,5 +692,38 @@ describe('DapiMixin', () => {
assert.strictEqual(TestClass.testProperty, 'test');
assert.strictEqual(TestClass.baseStaticProperty, 'baseStaticProperty');
});

it('should be possible to decorate all dapi functions at once', async () => {
const TestClass = DapiMixin(definition, BaseTestClass);
const instance = new TestClass();
const decorator = mock.fn(function (method, ...args) {
return method(...args);
});

const removeAllDecorators = instance.decorateAll(decorator);

assert.deepStrictEqual(instance.command1('a1', 'a2'), ['a1', 'a2']);
assert.deepStrictEqual(command1.mock.calls[0].arguments, [deps, 'a1', 'a2']);
assert.deepStrictEqual(command1.mock.calls[0].this, instance);
assert.equal(decorator.mock.callCount(), 1);

assert.deepStrictEqual(instance.command2(), undefined);
assert.deepStrictEqual(command2.mock.calls[0].arguments, [deps]);
assert.deepStrictEqual(command2.mock.calls[0].this, instance);
assert.equal(decorator.mock.callCount(), 2);

assert.deepStrictEqual(await instance.command3('a1', 'a2'), ['a1', 'a2']);
assert.deepStrictEqual(command3.mock.calls[0].arguments, [deps, 'a1', 'a2']);
assert.deepStrictEqual(command3.mock.calls[0].this, instance);
assert.equal(decorator.mock.callCount(), 3);

removeAllDecorators();

assert.deepStrictEqual(instance.command1('a1', 'a2'), ['a1', 'a2']);
assert.deepStrictEqual(instance.command2(), undefined);
assert.deepStrictEqual(await instance.command3('a1', 'a2'), ['a1', 'a2']);

assert.equal(decorator.mock.callCount(), 3);
});
});
});