Skip to content

Commit

Permalink
feat(random): add enum random support
Browse files Browse the repository at this point in the history
* add-random-enums

* add-random-enums

* added test for enums without value assigned
added fix for enum's with computed values

* add-random-enums

Now, if we can't access to one of enum values, instead of "0" we're set it's position
Added tests for case, when enum imported from d.ts files, and we can't access to it values

* add-random-enums

Co-authored-by: Artem Kornev <artem.kornev@y-tree.com>
Co-authored-by: Vittorio Guerriero <vittorio.gue@gmail.com>
  • Loading branch information
3 people committed May 26, 2020
1 parent 89a1a73 commit eeceea2
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 3 deletions.
4 changes: 4 additions & 0 deletions src/random/random.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ export class Random {
return Math.random() * (MAX_NUMBER - MIN_NUMBER) + MIN_NUMBER;
}

public static enumValue(...args: Array<string | number>): string | number {
return args[Math.floor(Math.random() * args.length)] ?? 0;
}

public static string(prefix: string): string {
return prefix + Math.random().toString(20).substr(2, 6);
}
Expand Down
20 changes: 17 additions & 3 deletions src/transformer/descriptor/enum/enumDeclaration.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
import * as ts from 'typescript';
import { TypeChecker } from '../../typeChecker/typeChecker';
import { RandomPropertyAccessor } from '../random/random';
import { IsTsAutoMockRandomEnabled } from '../../../options/random';

export function GetEnumDeclarationDescriptor(node: ts.EnumDeclaration): ts.Expression {
const typeChecker: ts.TypeChecker = TypeChecker();
const type: ts.LiteralType = typeChecker.getTypeAtLocation(node.members[0]) as ts.LiteralType;
const typesList: ts.LiteralType[] = node.members.map((it: ts.EnumMember) => typeChecker.getTypeAtLocation(it)) as ts.LiteralType[];

if (type.hasOwnProperty('value')) {
return ts.createLiteral(type.value);
if (IsTsAutoMockRandomEnabled()) {
const nodesList: ts.Expression[] = typesList.map((type: ts.LiteralType, index: number) => {
if (type.hasOwnProperty('value')) {
return ts.createLiteral(type.value);
}

return ts.createLiteral(index);
});

return ts.createCall(RandomPropertyAccessor('enumValue'), [], [...nodesList]);
}

if (typesList[0].hasOwnProperty('value')) {
return ts.createLiteral(typesList[0].value);
}

return ts.createLiteral(0);
Expand Down
126 changes: 126 additions & 0 deletions test/features/random/enum.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { createMock } from 'ts-auto-mock';

describe('Random enum', () => {
it('should have random enum values', () => {
enum EnumType {
firstValue = 'firstValue',
secondValue = 'secondValue',
thirdValue = 2,
}

type WithEnum = {
propertyName: EnumType;
};

const spy: jasmine.Spy = spyOn(Math, 'floor');

spy.and.returnValue(0);
const firstMock: WithEnum = createMock<WithEnum>();

expect(firstMock.propertyName).toBe(EnumType.firstValue);

spy.and.returnValue(1);
const secondMock: WithEnum = createMock<WithEnum>();

expect(secondMock.propertyName).toBe(EnumType.secondValue);

spy.and.returnValue(2);
const thirdMock: WithEnum = createMock<WithEnum>();

expect(thirdMock.propertyName).toBe(EnumType.thirdValue);

// Should have 0, when does't have value in array
spy.and.returnValue(100);
const fourthMock: WithEnum = createMock<WithEnum>();

expect(fourthMock.propertyName).toBe(0);
});

it('should have 0 value, when enum empty', () => {
enum EmptyEnum {}

type WithEmptyEnum = {
propertyName: EmptyEnum;
};

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

expect(mock.propertyName).toBe(0);
});

describe('for enum from a module', () => {
it('should assign correct random value', () => {
// We cannot check against the real ENUM because is a d.ts, it cannot be used as a value
const spy: jasmine.Spy = spyOn(Math, 'floor');
spy.and.returnValue(0);

const mock1: NameSpace.WithEnum = createMock<NameSpace.WithEnum>();

expect(mock1.propertyWithoutDefaultValue).toBe(0);
expect(mock1.propertyWithDefaultValue).toBe('1');

spy.and.returnValue(1);
const mock2: NameSpace.WithEnum = createMock<NameSpace.WithEnum>();

expect(mock2.propertyWithoutDefaultValue).toBe(1);
expect(mock2.propertyWithDefaultValue).toBe('2');
});
});

it('const enum declaration should work correctly with random', () => {
const enum Direction {
Up,
Down,
None = 'Nothing'
}

interface Movement {
direction: Direction;
}

const spy: jasmine.Spy = spyOn(Math, 'floor');

spy.and.returnValue(0);
const firstMock: Movement = createMock<Movement>();

expect(firstMock.direction).toBe(Direction.Up);

spy.and.returnValue(1);
const secondMock: Movement = createMock<Movement>();

expect(secondMock.direction).toBe(Direction.Down);

spy.and.returnValue(2);
const thirdMock: Movement = createMock<Movement>();

expect(thirdMock.direction).toBe(Direction.None);
});

it('should have position of "computed" property, because transformer don\'t support computed Enum values', () => {
// Issue https://github.com/Typescript-TDD/ts-auto-mock/issues/339
function getComputed(): number {
return 12;
}

enum WithComputed {
Computed = getComputed(),
Computed2 = 1 + 4,
}

interface IWithComputed {
computed: WithComputed;
}

const spy: jasmine.Spy = spyOn(Math, 'floor');

spy.and.returnValue(0);
const mock1: IWithComputed = createMock<IWithComputed>();

expect(mock1.computed).toBe(0);

spy.and.returnValue(1);
const mock2: IWithComputed = createMock<IWithComputed>();

expect(mock2.computed).toBe(1);
});
});

0 comments on commit eeceea2

Please sign in to comment.