Skip to content

Commit

Permalink
feat(random): enable random feature for primitives types
Browse files Browse the repository at this point in the history
* feat(random): add failing test for random string

* feat(random): add new feature configuration option

* feat(random): enable feature for test features

* feat(random): generate random string

* feat(random): generate random string at runtime to avoid duplicatiopn

* feat(random): generate random number

* feat(random): extract length and number max value

* feat(random): generate random boolean

* feat(random): improve string random test

* feat(random): add documentation

* feat(random): add random module so it will be easier to read the code

* feat(random): add random module so it will be easier to read the code

* feat(random): add random module so it will be easier to read the code

* revert playground changes

* remove unnecessary length parameter

* add min and max constant to improve readability

* use existing propertyName string getter

* ensure number math.random doesnt returns value outside the default range 0,1
  • Loading branch information
uittorio committed May 24, 2020
1 parent b62f3d8 commit 9666efc
Show file tree
Hide file tree
Showing 24 changed files with 243 additions and 13 deletions.
7 changes: 7 additions & 0 deletions config/karma/karma.config.features.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const karmaBaseConfig = require('./karma.config.base');

module.exports = function(config) {
const karmaConfig = karmaBaseConfig(config, '../../test/features/context.ts');

config.set(karmaConfig);
};
3 changes: 2 additions & 1 deletion config/modules/webpack.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ module.exports = merge(base({
index: './src/index.ts',
'extension/index': './src/extension/index.ts',
'merge/index': './src/merge/index.ts',
'repository/index': './src/repository/index.ts'
'repository/index': './src/repository/index.ts',
'random/index': './src/random/index.ts'
},
output: {
path: path.resolve(__dirname, "../../dist")
Expand Down
4 changes: 3 additions & 1 deletion config/test/webpack.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const transformer = require('../../dist/transformer');
const path = require('path');
const DetermineCacheBetweenTestsFromDebugEnvironment = require('./../utils/cache');
const DetermineFeaturesFromEnvironment = require('./../utils/features');

module.exports = function () {
return {
Expand All @@ -27,7 +28,8 @@ module.exports = function () {
getCustomTransformers: (program) => ({
before: [transformer.default(program, {
debug: false,
cacheBetweenTests: DetermineCacheBetweenTestsFromDebugEnvironment()
cacheBetweenTests: DetermineCacheBetweenTestsFromDebugEnvironment(),
features: DetermineFeaturesFromEnvironment(),
})]
})
}
Expand Down
15 changes: 15 additions & 0 deletions config/utils/features.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const ProcessService = require('../../utils/process/process');

function DetermineFeaturesFromEnvironment() {
const processService = ProcessService(process);
const features = processService.getEnvironmentValue('FEATURES');

if (features) {
return [
'random'
];
}

return [];
}
module.exports = DetermineFeaturesFromEnvironment;
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@
"build:modules:debug": "cross-env DEBUG=true webpack --config config/modules/webpack.js",
"build:transformer:definitelyTyped": "webpack --config config/modules/definitelyTypedTransformer/webpack.functions.js && webpack --config config/modules/definitelyTypedTransformer/webpack.js",
"build:playground": "ttsc --project tsconfig.playground.json",
"test": "npm run test:transformer && npm run test:framework:context && npm run test:framework && npm run test:frameworkDeprecated && npm run test:registerMock && npm run test:unit",
"test": "npm run test:transformer && npm run test:framework:context && npm run test:framework && npm run test:frameworkDeprecated && npm run test:registerMock && npm run test:features && npm run test:unit",
"test:unit": "karma start config/karma/karma.config.unit.js",
"test:transformer": "cross-env CACHE=true karma start config/karma/karma.config.transformer.js",
"test:registerMock": "cross-env CACHE=true karma start config/karma/karma.config.registerMock.js",
"test:framework:context": "cross-env CACHE=true karma start config/karma/karma.config.framework.context.js",
"test:frameworkDeprecated": "cross-env CACHE=true karma start config/karma/karma.config.framework.deprecated.js",
"test:framework": "cross-env CACHE=false karma start config/karma/karma.config.framework.js",
"test:features": "cross-env CACHE=true FEATURES=true karma start config/karma/karma.config.features.js",
"test:playground": "karma start config/karma/karma.config.transformer.playground.js",
"test:playground:build": "karma start config/karma/karma.config.transformer.playground.build.js",
"version": "conventional-changelog -p angular -i CHANGELOG.md -s && git add CHANGELOG.md",
Expand Down
1 change: 1 addition & 0 deletions src/options/default.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { TsAutoMockOptions } from './options';

export const defaultOptions: TsAutoMockOptions = {
features: [],
debug: false,
cacheBetweenTests: true,
};
1 change: 1 addition & 0 deletions src/options/features.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type TsAutoMockFeaturesOption = 'random';
2 changes: 2 additions & 0 deletions src/options/options.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { TsAutoMockCacheOptions } from './cache';
import { TsAutoMockDebugOptions } from './debug';
import { defaultOptions } from './default';
import { TsAutoMockFeaturesOption } from './features';

export interface TsAutoMockOptions {
debug: TsAutoMockDebugOptions;
cacheBetweenTests: TsAutoMockCacheOptions;
features: TsAutoMockFeaturesOption[];
}

let tsAutoMockOptions: TsAutoMockOptions = defaultOptions;
Expand Down
5 changes: 5 additions & 0 deletions src/options/random.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { GetOptionByKey } from './options';

export function IsTsAutoMockRandomEnabled(): boolean {
return GetOptionByKey('features').includes('random');
}
1 change: 1 addition & 0 deletions src/random/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Random as ɵRandom } from './random';
16 changes: 16 additions & 0 deletions src/random/random.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const MIN_NUMBER: number = -10000;
const MAX_NUMBER: number = 10000;

export class Random {
public static number(): number {
return Math.random() * (MAX_NUMBER - MIN_NUMBER) + MIN_NUMBER;
}

public static string(prefix: string): string {
return prefix + Math.random().toString(20).substr(2, 6);
}

public static boolean(): boolean {
return !Math.round(Math.random());
}
}
5 changes: 5 additions & 0 deletions src/transformer/descriptor/boolean/boolean.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import * as ts from 'typescript';
import { IsTsAutoMockRandomEnabled } from '../../../options/random';
import { RandomPropertyAccessor } from '../random/random';
import { GetBooleanFalseDescriptor } from './booleanFalse';

export function GetBooleanDescriptor(): ts.Expression {
if (IsTsAutoMockRandomEnabled()) {
return ts.createCall(RandomPropertyAccessor('boolean'), [], []);
}
return GetBooleanFalseDescriptor();
}
5 changes: 5 additions & 0 deletions src/transformer/descriptor/number/number.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import * as ts from 'typescript';
import { IsTsAutoMockRandomEnabled } from '../../../options/random';
import { RandomPropertyAccessor } from '../random/random';

export function GetNumberDescriptor(): ts.Expression {
if (IsTsAutoMockRandomEnabled()) {
return ts.createCall(RandomPropertyAccessor('number'), [], []);
}
return ts.createLiteral(0);
}
14 changes: 14 additions & 0 deletions src/transformer/descriptor/random/random.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as ts from 'typescript';
import { MockDefiner } from '../../mockDefiner/mockDefiner';
import { ModuleName } from '../../mockDefiner/modules/moduleName';
import { PrivateIdentifier } from '../../privateIdentifier/privateIdentifier';

export function RandomPropertyAccessor(methodName: string): ts.PropertyAccessExpression {
return ts.createPropertyAccess(
ts.createPropertyAccess(
MockDefiner.instance.getCurrentModuleIdentifier(ModuleName.Random),
PrivateIdentifier('Random')
),
ts.createIdentifier(methodName),
);
}
9 changes: 9 additions & 0 deletions src/transformer/descriptor/string/string.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import * as ts from 'typescript';
import { IsTsAutoMockRandomEnabled } from '../../../options/random';
import { PropertySignatureCache } from '../property/cache';
import { RandomPropertyAccessor } from '../random/random';
import { TypescriptHelper } from '../helper/helper';

export function GetStringDescriptor(): ts.Expression {
if (IsTsAutoMockRandomEnabled()) {
const propertyName: string = TypescriptHelper.GetStringPropertyName(PropertySignatureCache.instance.get());
const prefix: ts.StringLiteral = ts.createLiteral(propertyName);
return ts.createCall(RandomPropertyAccessor('string'), [], [prefix]);
}
return ts.createLiteral('');
}
1 change: 1 addition & 0 deletions src/transformer/mockDefiner/mockDefiner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export class MockDefiner {
[ModuleName.Extension]: PrivateIdentifier(ModuleName.Extension),
[ModuleName.Merge]: PrivateIdentifier(ModuleName.Merge),
[ModuleName.Repository]: PrivateIdentifier(ModuleName.Repository),
[ModuleName.Random]: PrivateIdentifier(ModuleName.Random),
};

this._neededImportIdentifierPerFile[this._fileName] = this._neededImportIdentifierPerFile[this._fileName] || [];
Expand Down
1 change: 1 addition & 0 deletions src/transformer/mockDefiner/modules/moduleName.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export enum ModuleName {
Repository = 'Repository',
Extension = 'Extension',
Merge = 'Merge',
Random = 'Random',
}
2 changes: 2 additions & 0 deletions src/transformer/mockDefiner/modules/modulesImportUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { ModuleName } from './moduleName';
export enum ModuleImportUrl {
Repository = 'ts-auto-mock/repository',
Extension = 'ts-auto-mock/extension',
Random = 'ts-auto-mock/random',
Merge = 'ts-auto-mock/merge',
}

export const ModulesImportUrl: {[key in ModuleName]: ModuleImportUrl } = {
Repository: ModuleImportUrl.Repository,
Extension: ModuleImportUrl.Extension,
Merge: ModuleImportUrl.Merge,
Random: ModuleImportUrl.Random,
};
4 changes: 4 additions & 0 deletions test/features/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/typedef
const frameworkContext = require.context('./', true, /\.test\.ts$/);
frameworkContext.keys().map(frameworkContext);
25 changes: 25 additions & 0 deletions test/features/random/bool.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { createMock } from 'ts-auto-mock';

describe('Random boolean', () => {
it('should be generated by math random', () => {
type WithBoolean = {
propertyName: boolean;
};

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

spy.and.returnValue(0);

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

// because we are mocking the return value of Math.random with 0 the result should be always !0 = true
expect(mock.propertyName).toBe(true);

spy.calls.reset();
spy.and.returnValue(1);

const mock2: WithBoolean = createMock<WithBoolean>();
// because we are mocking the return value of Math.random with 1 the result should be always !1 = false
expect(mock2.propertyName).toBe(false);
});
});
26 changes: 26 additions & 0 deletions test/features/random/number.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { createMock } from 'ts-auto-mock';

describe('Random number', () => {
it('should be generated by math random', () => {
type WithNumber = {
propertyName: number;
};

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

spy.and.returnValue(1);

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

// because we are mocking the return value of Math.random with 1 the result should be = 1 * (10000 - -10000) + -10000
expect(mock.propertyName).toBe(10000);

spy.calls.reset();
spy.and.returnValue(0);

const mock2: WithNumber = createMock<WithNumber>();

// because we are mocking the return value of Math.random with 10 the result should be = 10 * (10000 - -10000) + -10000
expect(mock2.propertyName).toBe(-10000);
});
});
33 changes: 33 additions & 0 deletions test/features/random/string.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { createMock } from 'ts-auto-mock';

describe('Random string', () => {
it('should return a random string value with the property name and 6 character', () => {
interface WithString {
prop: string;
}

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

expect(mock.prop).toMatch(/prop.{6}/);
});

it('should include the property name at the beginning of the value', () => {
interface WithString {
propertyName: string;
}

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

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

it('should include the function name when the string is the result of the function', () => {
type WithString = {
fnReturnsString: () => string;
};

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

expect(mock.fnReturnsString()).toMatch(/fnReturnsString.*/);
});
});
3 changes: 2 additions & 1 deletion tsconfig.playground.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"plugins": [
{
"transform": "./dist/transformer",
"debug": "console"
"debug": "console",
"features": []
}
]
},
Expand Down
70 changes: 61 additions & 9 deletions ui/src/views/config.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,33 @@ tsAutoMockTransformer(program: ts.Program, options: TsAutoMockOptions)
interface TsAutoMockOptions {
debug: boolean | 'file' | 'console';
cacheBetweenTests: boolean;
features: TsAutoMockFeaturesOption[];
}

export type TsAutoMockFeaturesOption = 'random';

```
options:

| Name | Value | Description | Default
| -------------------- | -------- | -------------------------------------------- | --------
| `debug` | `false` | it will NOT log to the console | false
| | `true` | it will log to the console |
| | `true` | it will log to a file (tsAutoMock.log) |
| `cacheBetweenTests` | `true` | it will reuse mocks between different tests | true
| | `false` | it create new mocks for each different tests |
| Name | Value | Description | Default
| -------------------- | -------- | -------------------------------------------- | --------
| `debug` | `false` | it will NOT log to the console | false
| | `true` | it will log to the console |
| | `file` | it will log to a file (tsAutoMock.log) |
| `cacheBetweenTests` | `true` | it will reuse mocks between different tests | true
| | `false` | it create new mocks for each different tests |
| `features` | `feature[]` | it will enable a specific feature | []

---

## debug
## Debug
We currently support
- Logs for [not supported types](./types-not-supported)
It will log any not supported type automatically converted to null.
This is useful to report an issue or to investigate a potential bug
---

## cacheBetweenTests
## CacheBetweenTests
One of the main functionality of ts auto mock is to generate mocks and cache them.

Mocks are currently created in the test file making tests to depend to each other
Expand All @@ -44,3 +52,47 @@ If test2 run in a different context than test1 it will not be able to access to
Set this property to false when your test run in different context.

We are working on an [issue](https://github.com/Typescript-TDD/ts-auto-mock/issues/101) to make sure tests do not depend to each other but they will still take advance of a cache system

---
## Features
We currently support the following features
### Random ('random')

When adding random to the feature list any string, boolean and number will be transformed to a random values

#### String
Example
```ts
interface WithString {
prop: string;
}

createMock<WithString>() // { prop: 'propQsdeos'}
```

The name of the property will be prepended following 6 random character

### Number
Example
```ts
interface WithNumber {
prop: number;
}

createMock<WithNumber>() // { prop: 5000.213123}
```

A random number will be generated between -10000 and 10000


### Boolean
Example
```ts
interface WithBoolean {
prop: boolean;
}

createMock<WithBoolean>() // { prop: true|false}
```

true|false will be random

0 comments on commit 9666efc

Please sign in to comment.