Skip to content

Commit

Permalink
feat(getAccessor): correctly mock get accessors for mocked classes
Browse files Browse the repository at this point in the history
  • Loading branch information
Pmyl committed May 19, 2021
1 parent 3a33c01 commit 3530039
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 1 deletion.
6 changes: 6 additions & 0 deletions src/transformer/descriptor/descriptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { GetClassDeclarationDescriptor } from './class/classDeclaration';
import { GetConstructorTypeDescriptor } from './constructor/constructorType';
import { GetEnumDeclarationDescriptor } from './enum/enumDeclaration';
import { GetExpressionWithTypeArgumentsDescriptor } from './expression/expressionWithTypeArguments';
import { GetGetAccessorDeclarationDescriptor } from './getAccessor/getAccessor';
import { GetIdentifierDescriptor } from './identifier/identifier';
import { GetImportDescriptor } from './import/import';
import { GetImportEqualsDescriptor } from './import/importEquals';
Expand Down Expand Up @@ -89,6 +90,11 @@ export function GetDescriptor(node: ts.Node, scope: Scope): ts.Expression {
return GetImportDescriptor(node as ts.ImportClause, scope);
case ts.SyntaxKind.MethodSignature:
return GetMethodSignatureDescriptor(node as ts.MethodSignature, scope);
case ts.SyntaxKind.GetAccessor:
return GetGetAccessorDeclarationDescriptor(
node as ts.GetAccessorDeclaration,
scope
);
case ts.SyntaxKind.FunctionDeclaration:
return GetMethodDeclarationDescriptor(
node as ts.FunctionDeclaration,
Expand Down
15 changes: 15 additions & 0 deletions src/transformer/descriptor/getAccessor/getAccessor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import * as ts from 'typescript';
import { Scope } from '../../scope/scope';
import { GetDescriptor } from '../descriptor';
import { GetFunctionReturnType } from '../method/functionReturnType';
import { PropertySignatureCache } from '../property/cache';

export function GetGetAccessorDeclarationDescriptor(
node: ts.GetAccessorDeclaration,
scope: Scope
): ts.Expression {
PropertySignatureCache.instance.set(node.name);
const returnTypeNode: ts.Node = GetFunctionReturnType(node);

return GetDescriptor(returnTypeNode, scope);
}
8 changes: 7 additions & 1 deletion src/transformer/descriptor/mock/mockProperties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ export function GetMockPropertiesFromSymbol(
): ts.Expression {
const properties: PropertyLike[] = propertiesSymbol
.filter((prop: ts.Symbol) => !!prop.declarations) // Dynamically generated properties (mapped types) do not have declarations
.map((prop: ts.Symbol) => prop.declarations[0]) as PropertyLike[];
.map(
(prop: ts.Symbol) =>
prop.declarations.filter(
(declaration: ts.Declaration) => !ts.isSetAccessor(declaration)
)[0]
)
.filter(Boolean) as PropertyLike[];

const signaturesDeclarations: SignatureLike[] = signatures.map(
(signature: ts.Signature) => signature.declaration
Expand Down
12 changes: 12 additions & 0 deletions test/features/random/string.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,16 @@ describe('Random string', () => {

expect(mock.fnReturnsString()).toMatch(/fnReturnsString.*/);
});

it('should include the getter name when the string is the result of the get', () => {
class WithGetterString {
public get getterString(): string {
return 'string';
}
}

const mock: WithGetterString = createMock<WithGetterString>();

expect(mock.getterString).toMatch(/getterString.*/);
});
});
63 changes: 63 additions & 0 deletions test/transformer/descriptor/getAccessor/getAccessor.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { createMock } from 'ts-auto-mock';

describe('getAccessor', () => {
class AClass {
public get prop1(): number {
return 4;
}

public get prop2(): string {
return '42';
}

public get prop3(): AClass {
return new AClass();
}

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
public get prop4() {
return 123;
}
}

it('should mock the correct explicit type', () => {
const mock: AClass = createMock<AClass>();
expect(mock.prop1).toBe(0);
expect(mock.prop2).toBe('');
expect(mock.prop3.prop3.prop3.prop1).toBe(0);
});

it('should mock the correct type inferred from the body', () => {
const mock: AClass = createMock<AClass>();
expect(mock.prop4).toBe(123);
});

describe('when setter is defined', () => {
it('should ignore it', () => {
class AClassWithSetter {
private aValue: string;

public set a(value: string) {
this.aValue = value;
}

public get a(): string {
return '';
}

public get b(): string {
return '';
}

public set b(value: string) {
this.aValue = value;
}
}

const mock: AClassWithSetter = createMock<AClassWithSetter>();

expect(mock.a).toBe('');
expect(mock.b).toBe('');
});
});
});
16 changes: 16 additions & 0 deletions test/transformer/descriptor/setAccessor/setAccessor.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { createMock } from 'ts-auto-mock';

describe('setAccessor', () => {
class AClass {
public _prop1: number;

public set prop1(value: number) {
this._prop1 = value;
}
}

it('should always be undefined for only setter', () => {
const mock: AClass = createMock<AClass>();
expect(mock.prop1).toBeUndefined();
});
});

0 comments on commit 3530039

Please sign in to comment.