From b14bd5c3e19e62f30f609f297925c5eb5fda30f4 Mon Sep 17 00:00:00 2001 From: Marc Date: Wed, 10 Jun 2020 08:53:17 +0200 Subject: [PATCH] fix(registerMock): allow to use mocks defined in variables (#330) * fix(registerMock): allow to use mocks defined in variables * test(registerMock): fix wrong test description Co-authored-by: Vittorio Guerriero --- src/transformer/mock/mock.ts | 5 +- src/transformer/mockDefiner/mockDefiner.ts | 46 ++++++------------- .../mockFromScope/mockFromScope.ts | 43 +++++++++++++++++ 3 files changed, 58 insertions(+), 36 deletions(-) create mode 100644 test/registerMock/mockFromScope/mockFromScope.ts diff --git a/src/transformer/mock/mock.ts b/src/transformer/mock/mock.ts index 3b73ea443..c446282f9 100644 --- a/src/transformer/mock/mock.ts +++ b/src/transformer/mock/mock.ts @@ -66,10 +66,9 @@ export function getMockForList(nodeToMock: ts.TypeNode, node: ts.CallExpression) export function storeRegisterMock(typeToMock: ts.TypeNode, node: ts.CallExpression): ts.Node { if (ts.isTypeReferenceNode(typeToMock)) { const factory: ts.FunctionExpression = node.arguments[0] as ts.FunctionExpression; - MockDefiner.instance.storeRegisterMockFor(TypescriptHelper.GetDeclarationFromNode(typeToMock.typeName), factory); + return MockDefiner.instance.registerMockFor(TypescriptHelper.GetDeclarationFromNode(typeToMock.typeName), factory); } else { Logger('RegisterMock').error('registerMock can be used only to mock type references.'); + return ts.createEmptyStatement(); } - - return ts.createEmptyStatement(); } diff --git a/src/transformer/mockDefiner/mockDefiner.ts b/src/transformer/mockDefiner/mockDefiner.ts index 6dbe8c2e4..f2f85bf78 100644 --- a/src/transformer/mockDefiner/mockDefiner.ts +++ b/src/transformer/mockDefiner/mockDefiner.ts @@ -33,7 +33,6 @@ export class MockDefiner { private _neededImportIdentifierPerFile: { [key: string]: Array } = {}; private _internalModuleImportIdentifierPerFile: { [key: string]: { [key in ModuleName]: ts.Identifier } } = {}; private _factoryRegistrationsPerFile: FactoryRegistrationPerFile = {}; - private _registerMockFactoryRegistrationsPerFile: FactoryRegistrationPerFile = {}; private _factoryIntersectionsRegistrationsPerFile: FactoryIntersectionRegistrationPerFile = {}; private _factoryCache: DeclarationCache; private _registerMockFactoryCache: DeclarationCache; @@ -93,7 +92,6 @@ export class MockDefiner { ...this._getImportsToAddInFile(sourceFile), ...this._getExportsToAddInFile(sourceFile), ...this._getExportsIntersectionToAddInFile(sourceFile), - ...this._getRegisterMockInFile(sourceFile), ]; } @@ -105,7 +103,6 @@ export class MockDefiner { } this._factoryRegistrationsPerFile[sourceFile.fileName] = []; this._factoryIntersectionsRegistrationsPerFile[sourceFile.fileName] = []; - this._registerMockFactoryRegistrationsPerFile[sourceFile.fileName] = []; } public createMockFactory(declaration: ts.Declaration): void { @@ -157,16 +154,12 @@ export class MockDefiner { return this._declarationCache.get(declaration) as string; } - public storeRegisterMockFor(declaration: ts.Declaration, factory: ts.FunctionExpression): void { + public registerMockFor(declaration: ts.Declaration, factory: ts.FunctionExpression): ts.Node { const key: string = this.getDeclarationKeyMap(declaration); this._registerMockFactoryCache.set(declaration, key); - this._registerMockFactoryRegistrationsPerFile[this._fileName] = this._registerMockFactoryRegistrationsPerFile[this._fileName] || []; - this._registerMockFactoryRegistrationsPerFile[this._fileName].push({ - key: declaration, - factory, - }); + return this._getCallRegisterMock(this._fileName, key, factory); } public hasMockForDeclaration(declaration: ts.Declaration): boolean { @@ -283,33 +276,20 @@ export class MockDefiner { return []; } - private _getRegisterMockInFile(sourceFile: ts.SourceFile): ts.Statement[] { - if (this._registerMockFactoryRegistrationsPerFile[sourceFile.fileName]) { - return this._registerMockFactoryRegistrationsPerFile[sourceFile.fileName] - .map((reg: { key: ts.Declaration; factory: ts.Expression }) => { - // NOTE: this._registerMockFactoryCache and - // this._registerMockFactoryCache are populated in the same routine - // and if the former is defined the latter will be too! - // eslint-disable-next-line - const key: string = this._registerMockFactoryCache.get(reg.key)!; - - return this._createRegistration(sourceFile.fileName, key, reg.factory); - }); - } - - return []; - } - private _createRegistration(fileName: string, key: string, factory: ts.Expression): ts.Statement { return ts.createExpressionStatement( - ts.createCall( - ts.createPropertyAccess( - this._mockRepositoryAccess(fileName), - ts.createIdentifier('registerFactory'), - ), - [], - [ts.createStringLiteral(key), factory], + this._getCallRegisterMock(fileName, key, factory) + ); + } + + private _getCallRegisterMock(fileName: string, key: string, factory: ts.Expression): ts.CallExpression { + return ts.createCall( + ts.createPropertyAccess( + this._mockRepositoryAccess(fileName), + ts.createIdentifier('registerFactory'), ), + [], + [ts.createStringLiteral(key), factory], ); } diff --git a/test/registerMock/mockFromScope/mockFromScope.ts b/test/registerMock/mockFromScope/mockFromScope.ts new file mode 100644 index 000000000..c84fd791f --- /dev/null +++ b/test/registerMock/mockFromScope/mockFromScope.ts @@ -0,0 +1,43 @@ +import { createMock, registerMock } from 'ts-auto-mock'; + +describe('registerMock using vars from the scope', () => { + it('should override standard behaviour of mock creation using values from the scope', () => { + interface APropInterface { + internalProp: string; + call: () => APropInterface; + } + + interface AParentInterface { + prop: APropInterface; + } + + const propInstance: APropInterface = { internalProp: 'whaaat', call: () => propInstance }; + + registerMock(() => propInstance); + + const mock: AParentInterface = createMock(); + + expect(mock.prop).toBe(propInstance); + expect(mock.prop.call()).toBe(propInstance); + }); + + it('should override standard behaviour of mock creation using values from createMock', () => { + interface APropInterface { + internalProp: string; + call: () => APropInterface; + } + + interface AParentInterface { + prop: APropInterface; + } + + const propInstance: APropInterface = createMock(); + + registerMock(() => propInstance); + + const mock: AParentInterface = createMock(); + + expect(mock.prop).toBe(propInstance); + expect(mock.prop.call()).toBe(propInstance); + }); +});