Skip to content

Commit

Permalink
Merge pull request #70 from automock/next
Browse files Browse the repository at this point in the history
  • Loading branch information
omermorad authored Jul 17, 2023
2 parents 5d5fdeb + 1b04b17 commit 88cbfab
Show file tree
Hide file tree
Showing 18 changed files with 132 additions and 71 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}

- name: Yarn
run: yarn --frozen-lockfile && lerna bootstrap --ci
run: yarn --frozen-lockfile

- name: Build
run: yarn build
Expand All @@ -49,7 +49,7 @@ jobs:
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}

- name: Yarn
run: yarn --frozen-lockfile && lerna bootstrap --ci
run: yarn --frozen-lockfile

- name: Lint
run: yarn lint
Expand All @@ -75,7 +75,7 @@ jobs:
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}

- name: Yarn
run: yarn --frozen-lockfile && lerna bootstrap --ci
run: yarn --frozen-lockfile

- name: Test
run: yarn jest --selectProjects ${{ matrix.project }} --coverage --verbose --passWithNoTests
Expand Down
6 changes: 6 additions & 0 deletions packages/adapters/nestjs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

# 1.2.1 (2023-07-01)

### Code Refactoring

* **adapters.nestjs**: tuples instead of map when collecting dependencies ([8c5c6cbe](https://github.com/omermorad/automock/commit/8c5c6cbee97790add30570b79684481780d25bea))

# 1.2.0 (2023-06-10)

### Features
Expand Down
3 changes: 3 additions & 0 deletions packages/adapters/nestjs/__test__/integration.assets.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { forwardRef, Inject } from '@nestjs/common';

type DummyType = string;

export class DependencyOne {
print(): string {
return 'dependencyOne';
Expand Down Expand Up @@ -30,6 +32,7 @@ export class MainClass {
private readonly dependencyTwo: DependencyTwo,
@Inject(forwardRef(() => DependencyThree)) private readonly dependencyThree: DependencyThree,
@Inject('CUSTOM_TOKEN') private readonly dependencyFour: DependencyFourToken,
@Inject('CUSTOM_TOKEN') private readonly dummy: DummyType,
@Inject('LITERAL_VALUE_ARR') private readonly literalValueArray: string[],
@Inject('LITERAL_VALUE_STR') private readonly literalValueString: string
) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,23 @@ import {
DependencyTwo,
MainClass,
} from './integration.assets';
import { Type } from '@automock/types';
import { ClassDependencies, PrimitiveValue } from '@automock/common';
import { ClassDependenciesMap } from '@automock/common';

describe('NestJS Automock Adapter Integration Test', () => {
describe('reflecting a class', () => {
const reflectorFactory = ReflectorFactory(Reflect, TokensReflector);
const classDependencies = reflectorFactory.reflectDependencies(MainClass);

it('should return a map of the class dependencies', () => {
expect(classDependencies).toStrictEqual<ClassDependencies>(
new Map<Type | string, PrimitiveValue | Type>([
['CUSTOM_TOKEN', DependencyFourToken],
[DependencyOne, DependencyOne],
[DependencyTwo, DependencyTwo],
[DependencyThree, DependencyThree],
['LITERAL_VALUE_ARR', Array],
['LITERAL_VALUE_STR', String],
])
);
expect(classDependencies.constructor).toStrictEqual<ClassDependenciesMap['constructor']>([
[DependencyOne, DependencyOne],
[DependencyTwo, DependencyTwo],
[DependencyThree, DependencyThree],
['CUSTOM_TOKEN', DependencyFourToken],
['CUSTOM_TOKEN', String],
['LITERAL_VALUE_ARR', Array],
['LITERAL_VALUE_STR', String],
]);
});
});
});
4 changes: 2 additions & 2 deletions packages/adapters/nestjs/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@automock/adapters.nestjs",
"private": false,
"version": "1.2.0",
"version": "1.2.1",
"license": "MIT",
"main": "dist/index.js",
"repository": {
Expand Down Expand Up @@ -29,7 +29,7 @@
"index.js"
],
"dependencies": {
"@automock/common": "^1.2.0"
"@automock/common": "^2.0.0"
},
"peerDependencies": {
"@nestjs/common": ">= 8.x"
Expand Down
18 changes: 6 additions & 12 deletions packages/adapters/nestjs/src/reflector.service.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { Type } from '@automock/types';
import {
ClassDependencies,
DependenciesReflector as AutomockDependenciesReflector,
PrimitiveValue,
} from '@automock/common';
import { ClassDependencies, ClassDependenciesMap } from '@automock/common';
import { DependenciesReflector as AutomockDependenciesReflector } from '@automock/common';
import { CustomToken, TokensReflector } from './token-reflector.service';

const INJECTED_TOKENS_METADATA = 'self:paramtypes';
Expand All @@ -13,10 +10,10 @@ export function ReflectorFactory(
reflector: typeof Reflect,
tokensReflector: TokensReflector
): AutomockDependenciesReflector {
function reflectDependencies(targetClass: Type): ClassDependencies {
function reflectDependencies(targetClass: Type): ClassDependenciesMap {
const types = reflectParamTypes(targetClass);
const tokens = reflectParamTokens(targetClass);
const classDependencies: ClassDependencies = new Map<Type | string, PrimitiveValue | Type>();
const classDependencies: ClassDependencies = [];

const callback = tokensReflector.attachTokenToDependency(tokens);

Expand All @@ -30,12 +27,9 @@ export function ReflectorFactory(
);
}
})
.forEach((tuple) => {
const [typeOrToken, type] = tuple;
classDependencies.set(typeOrToken, type);
});
.forEach((tuple) => classDependencies.push(tuple));

return classDependencies;
return { constructor: classDependencies };
}

function reflectParamTokens(targetClass: Type): CustomToken[] {
Expand Down
10 changes: 10 additions & 0 deletions packages/common/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

# 2.0.0 (2023-07-01)

### Code Refactoring

* **common:** change dependencies reflector signature ([96d33a2](https://github.com/omermorad/automock/commit/96d33a28c97ad93c8bd27d50b4bdf8ab43d11308))

### BREAKING CHANGES

* **common:** The `reflectDependencies` method of `DependenciesReflector` now returns a different interface to accommodate the support for both constructor parameters and properties.

# 1.2.0 (2023-06-10)

### Features
Expand Down
2 changes: 1 addition & 1 deletion packages/common/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@automock/common",
"private": false,
"version": "1.2.0",
"version": "2.0.0",
"license": "MIT",
"types": "dist/index.d.ts",
"keywords": [
Expand Down
8 changes: 6 additions & 2 deletions packages/common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ import { Type } from '@automock/types';

export type PrimitiveValue = string | number | boolean | symbol | null;

export type ClassDependencies = Map<Type | string, Type | PrimitiveValue>;
export type ClassDependencies = [Type | string, PrimitiveValue | Type][];

export interface ClassDependenciesMap {
constructor: ClassDependencies;
}

export interface DependenciesReflector {
reflectDependencies(targetClass: Type): ClassDependencies;
reflectDependencies(targetClass: Type): ClassDependenciesMap;
}
6 changes: 6 additions & 0 deletions packages/core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

# 1.2.2 (2023-07-01)

### Code Refactoring

* **core:** dependencies mocker to return new interface ([0881c0e4](https://github.com/omermorad/automock/commit/0881c0e468951166be3afe14454bb45d319859bd))

# 1.2.0 (2023-06-10)

### Features
Expand Down
27 changes: 17 additions & 10 deletions packages/core/__test__/testbed-builder.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
DependencyTwo,
DependencyFive,
} from './integration.assets';
import { PrimitiveValue } from '@automock/common';
import { DependenciesReflector } from '@automock/common';

describe('Builder Factory Integration Test', () => {
let underTest: TestBedBuilder<MainClass>;
Expand All @@ -18,16 +18,22 @@ describe('Builder Factory Integration Test', () => {
const mockFunctionMockOfBuilder = jest.fn(() => '__MOCKED_FROM_BUILDER__');
const mockFunctionMockOfMocker = jest.fn(() => '__MOCKED_FROM_MOCKER__');

const reflectorMock = {
const reflectorMock: DependenciesReflector = {
reflectDependencies: () => {
return new Map<Type | string, Type | PrimitiveValue>([
[DependencyOne, DependencyOne],
[DependencyTwo, DependencyTwo],
[DependencyThree, DependencyThree],
['DEPENDENCY_FOUR_TOKEN', DependencyFourToken],
[DependencyFive, DependencyFive],
['STRING_TOKEN', 'ANY STRING'],
]);
return {
constructor: [
[DependencyOne, DependencyOne],
// Repeat on the same dependency twice, as it can be returned from the reflector (@since 1.2.2)
[DependencyTwo, DependencyTwo],
[DependencyTwo, DependencyTwo],
[DependencyThree, DependencyThree],
// Repeat on the same dependency twice, as it can be returned from the reflector (@since 1.2.2)
['DEPENDENCY_FOUR_TOKEN', DependencyFourToken],
['DEPENDENCY_FOUR_TOKEN', DependencyFourToken],
[DependencyFive, DependencyFive],
['STRING_TOKEN', 'ANY STRING'],
],
};
},
};

Expand Down Expand Up @@ -76,6 +82,7 @@ describe('Builder Factory Integration Test', () => {
it.each([
[DependencyOne.name, '__MOCKED_FROM_BUILDER__', DependencyOne],
[DependencyTwo.name, '__MOCKED_FROM_BUILDER__', DependencyTwo],
[DependencyTwo.name, '__MOCKED_FROM_BUILDER__', DependencyTwo],
[DependencyThree.name, '__MOCKED_FROM_MOCKER__', DependencyThree],
['custom token with function', '__MOCKED_FROM_BUILDER__', 'DEPENDENCY_FOUR_TOKEN'],
[DependencyFive.name, '__MOCKED_FROM_MOCKER__', DependencyFive],
Expand Down
4 changes: 2 additions & 2 deletions packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@automock/core",
"private": false,
"version": "1.2.0",
"version": "1.2.1",
"license": "MIT",
"main": "dist/index.js",
"keywords": [
Expand Down Expand Up @@ -35,7 +35,7 @@
"README.md"
],
"devDependencies": {
"@automock/common": "^1.2.0",
"@automock/common": "^2.0.0",
"@automock/types": "^1.2.0"
}
}
45 changes: 33 additions & 12 deletions packages/core/src/services/dependencies-mocker.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { DependenciesMocker } from './dependencies-mocker';
import { Type } from '@automock/types';
import { DependenciesReflector } from '@automock/common';
import { DependenciesMocker, MockedDependencies } from './dependencies-mocker';

import MockedFn = jest.MockedFn;
import { StubbedInstance, Type } from '@automock/types';

class SomeClassOne {}

Expand All @@ -11,40 +14,58 @@ const MOCKED = '__MOCKED__';
describe('Dependencies Mocker Unit Spec', () => {
let underTest: DependenciesMocker;
const mockFunctionStub = () => MOCKED;
const reflectorMock = { reflectDependencies: jest.fn() };
const reflectorMock = {
reflectDependencies: jest.fn() as MockedFn<DependenciesReflector['reflectDependencies']>,
};

beforeAll(() => {
underTest = new DependenciesMocker(reflectorMock, mockFunctionStub);
});

describe('mocking all class dependencies', () => {
beforeAll(() => {
reflectorMock.reflectDependencies.mockReturnValue(
new Map<Type | string, Type>([
reflectorMock.reflectDependencies.mockReturnValue({
constructor: [
[SomeClassOne, SomeClassOne],
[SomeClassTwo, SomeClassTwo],
[SomeClassTwo, SomeClassTwo],
['TOKEN', ClassFromToken],
])
);
],
});
});

describe('assuming there is only one mocked class in the given dependencies', () => {
class DoesntMatterClass {}
let result: MockedDependencies;

class ArbitraryClass {}
const alreadyMockedDependencies = new Map<Type | string, Type>([
[SomeClassTwo, SomeClassTwoMockedLike],
]);

it('should return a map of class dependencies and mock anything not mocked', () => {
const result = underTest.mockAllDependencies(DoesntMatterClass)(alreadyMockedDependencies);
beforeAll(() => {
result = underTest.mockAllDependencies(ArbitraryClass)(alreadyMockedDependencies);
});

expect(result).toEqual(
new Map<Type | string, Type | string>([
it('should return a map of the mocks of the class dependencies', () => {
expect(result.mocks).toEqual<MockedDependencies['mocks']>(
new Map<Type | string, StubbedInstance<unknown>>([
[SomeClassOne, MOCKED],
[SomeClassTwo, SomeClassTwoMockedLike],
['TOKEN', MOCKED],
])
);
});

it('should also return the original reflected dependencies', () => {
expect(result.origin).toEqual<MockedDependencies['origin']>({
constructor: [
[SomeClassOne, SomeClassOne],
[SomeClassTwo, SomeClassTwo],
[SomeClassTwo, SomeClassTwo],
['TOKEN', ClassFromToken],
],
});
});
});
});
});
19 changes: 15 additions & 4 deletions packages/core/src/services/dependencies-mocker.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { Type, MockFunction, StubbedInstance } from '@automock/types';
import { DependenciesReflector, PrimitiveValue } from '@automock/common';
import { ClassDependenciesMap } from '@automock/common/src';

export interface MockedDependencies {
mocks: Map<Type | string, StubbedInstance<unknown>>;
origin: ClassDependenciesMap;
}

export class DependenciesMocker {
public constructor(
Expand All @@ -17,12 +23,14 @@ export class DependenciesMocker {
targetClass: Type<TClass>
): (
alreadyMockedDependencies: Map<Type | string, StubbedInstance<unknown> | PrimitiveValue>
) => Map<Type | string, StubbedInstance<unknown>> {
return (alreadyMockedDependencies: Map<Type | string, StubbedInstance<unknown>>) => {
) => MockedDependencies {
return (
alreadyMockedDependencies: Map<Type | string, StubbedInstance<unknown>>
): MockedDependencies => {
const classDependencies = this.reflector.reflectDependencies(targetClass);
const classMockedDependencies = new Map<Type | string, StubbedInstance<unknown>>();

for (const [dependency] of classDependencies.entries()) {
for (const [dependency] of classDependencies.constructor) {
const alreadyMocked = alreadyMockedDependencies.get(dependency);

const mockedDependency = alreadyMocked
Expand All @@ -32,7 +40,10 @@ export class DependenciesMocker {
classMockedDependencies.set(dependency, mockedDependency);
}

return classMockedDependencies;
return {
mocks: classMockedDependencies,
origin: classDependencies,
};
};
}
}
Loading

0 comments on commit 88cbfab

Please sign in to comment.