Skip to content

Commit

Permalink
feat: dice notation fake
Browse files Browse the repository at this point in the history
Signed-off-by: hxtree <[email protected]>
  • Loading branch information
hxtree committed Nov 1, 2023
1 parent f912496 commit d78e829
Show file tree
Hide file tree
Showing 18 changed files with 376 additions and 61 deletions.
222 changes: 208 additions & 14 deletions common/config/rush/pnpm-lock.yaml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion common/config/rush/repo-state.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush.
{
"pnpmShrinkwrapHash": "b494a61a3dd66fffe41bf91e5d3f0d656e935872",
"pnpmShrinkwrapHash": "374cc425860ef0a63a23f3ed83e8b649005cedfb",
"preferredVersionsHash": "8ae0ba5bd02ec9c5763773a15e27aee08a6567f6"
}
3 changes: 2 additions & 1 deletion libraries/faker-factory/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
"class-validator-jsonschema": "3.1.1",
"json-schema-faker": "~0.5.0-rcv.46",
"json-schema": "~0.4.0",
"openapi3-ts": "~3.1.2"
"openapi3-ts": "~3.1.2",
"@cats-cradle/validation-schemas": "workspace:*"
},
"devDependencies": {
"@types/jest": "29.5.5",
Expand Down
8 changes: 0 additions & 8 deletions libraries/faker-factory/src/__tests__/faker-factory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,6 @@ describe('FakerFactory', () => {
expect(typeof faker.uuid).toBe('string');
});

it('should create currency based on decorators', () => {
expect(typeof faker.currency).toBe('string');
});

it('should create email based on decorators', () => {
expect(typeof faker.email).toContain('string');
expect(faker.email).toContain('@');
Expand All @@ -56,10 +52,6 @@ describe('FakerFactory', () => {
expect(faker.site).toContain('.');
});

it('should create date on decorators', () => {
expect(typeof faker.date).toContain('string');
});

it('should create enum of defined type', () => {
const enumValues = Object.values(SampleEnum);
expect(enumValues.includes(faker.enum));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ describe('generateFakeData', () => {
expect(typeof result.number).toBe('number');
expect(typeof result.string).toBe('string');
expect(typeof result.uuid).toBe('string');
expect(typeof result.currency).toBe('string');
expect(typeof result.email).toBe('string');
expect(typeof result.site).toBe('string');
});
Expand Down
32 changes: 32 additions & 0 deletions libraries/faker-factory/src/__tests__/get-schemas.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { IsDiceNotation } from '@cats-cradle/validation-schemas';
import { getSchemas } from '../get-schemas';

describe('getSchemas', () => {
let testClass: TestClass;

class TestClass {
@IsDiceNotation()
public property: string;
}

beforeEach(async () => {
testClass = new TestClass();
});

it('should get accurate pattern for schemas', async () => {
const schemas = getSchemas();

expect(schemas).toMatchObject({
TestClass: {
properties: {
property: {
pattern: /(\d+)?d(\d+)([+-]\d+)?/,
type: 'string',
},
},
type: 'object',
required: ['property'],
},
});
});
});
12 changes: 2 additions & 10 deletions libraries/faker-factory/src/__tests__/sample-class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,12 @@ import {
Min,
IsEmail,
IsFQDN,
IsDate,
Length,
IsCurrency,
IsInstance,
ValidateNested,
IsOptional,
} from 'class-validator';
import { Type } from 'class-transformer';
Type,
} from '@cats-cradle/validation-schemas';

export enum SampleEnum {
RED = 'red',
Expand Down Expand Up @@ -49,18 +47,12 @@ export class SampleClass {
@IsUUID()
public uuid: string;

@IsCurrency()
public currency: string;

@IsEmail()
public email: string;

@IsFQDN()
public site: string;

@IsDate()
public date: Date;

@IsString()
@Length(1, 10)
public min: string;
Expand Down
3 changes: 3 additions & 0 deletions libraries/faker-factory/src/generate-fake-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ export async function generateFakeData(
JSONSchemaFaker.format('hostname', () => faker.internet.url());
JSONSchemaFaker.format('string', () => faker.internet.url());

JSONSchemaFaker.format('latitude', () => faker.address.latitude());
JSONSchemaFaker.format('longitude', () => faker.address.longitude());

if (settings.optionals === true || settings.probability === 1) {
JSONSchemaFaker.option('alwaysFakeOptionals', true);
}
Expand Down
6 changes: 6 additions & 0 deletions libraries/faker-factory/src/get-schemas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { validationMetadatasToSchemas } from 'class-validator-jsonschema';
import { SchemaObject } from 'openapi3-ts';

export function getSchemas(): Record<string, SchemaObject> {
return validationMetadatasToSchemas();
}
3 changes: 1 addition & 2 deletions libraries/validation-schemas/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
"@types/uuid": "~9.0.6",
"eslint": "8.44.0",
"@cats-cradle/eslint-config": "1.0.6",
"@types/json-schema": "~7.0.11",
"@cats-cradle/faker-factory": "workspace:*"
"@types/json-schema": "~7.0.11"
}
}
31 changes: 10 additions & 21 deletions libraries/validation-schemas/src/custom/is-dice-notation.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,18 @@
import { registerDecorator, ValidationOptions } from 'class-validator';
import { Matches, matches, ValidationOptions } from 'class-validator';

export function IsDiceNotationValidator(value: any): boolean {
return typeof value === 'string' && /(\d+)?d(\d+)([\+\-]\d+)?/.test(value);
export const DICE_NOTATION_REGEX = /(\d+)?d(\d+)([+-]\d+)?/;

export function IsDiceNotationValidator(value: string) {
return matches(value, DICE_NOTATION_REGEX);
}

/**
* Checks if is dice notation
*
* "d4", "2d6", "4d8+2", "3d5+20*3"
*
* @param property
* Checks if is dice notation, e.g. "d4", "2d6", "4d8+2", "3d5+20*3"
* @param validationOptions
* @returns
*/
export function IsDiceNotation(validationOptions?: ValidationOptions) {
return function (object: Object, propertyName: string) {
registerDecorator({
name: 'isDiceNotation',
target: object.constructor,
propertyName,
constraints: [],
options: validationOptions,
validator: {
validate: IsDiceNotationValidator,
},
});
};
export function IsDiceNotation(
validationOptions?: ValidationOptions,
): PropertyDecorator {
return Matches(DICE_NOTATION_REGEX, validationOptions);
}
4 changes: 2 additions & 2 deletions libraries/validation-schemas/src/custom/is-money.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { registerDecorator, ValidationOptions } from 'class-validator';
import currency from 'currency.js';

export function isMoneyValidator(value: any): boolean {
export function IsMoneyValidator(value: any): boolean {
const formatted = currency(value, {
symbol: '',
separator: '',
Expand Down Expand Up @@ -29,7 +29,7 @@ export function IsMoney(validationOptions?: ValidationOptions) {
constraints: [],
options: validationOptions,
validator: {
validate: isMoneyValidator,
validate: IsMoneyValidator,
},
});
};
Expand Down
5 changes: 4 additions & 1 deletion libraries/validation-schemas/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// supported custom
export {
DICE_NOTATION_REGEX,
IsDiceNotation,
IsDiceNotationValidator,
} from './custom/is-dice-notation';
export { IsMoney, isMoneyValidator } from './custom/is-money';
export { IsMoney, IsMoneyValidator } from './custom/is-money';
export { IsUuidV4, IsUuidV4Validator } from './custom/is-uuidv4';
export { IsFilename, IsFilenameValidator } from './custom/is-filename';

Expand Down Expand Up @@ -67,6 +68,8 @@ export {
ArrayMaxSize,
ArrayUnique,
IsInstance,
IsLatitude,
IsLongitude,
} from 'class-validator';

// work around for validating nested types
Expand Down
2 changes: 2 additions & 0 deletions services/weather-control/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ConfigModule } from '@nestjs/config';
import { ServeStaticModule } from '@nestjs/serve-static';
import { join } from 'path';
import { HealthModule } from './module/health/health.module';
import { WeatherModule } from './module/weather/weather.module';

@Module({
imports: [
Expand All @@ -11,6 +12,7 @@ import { HealthModule } from './module/health/health.module';
rootPath: join(__dirname, '../../', 'public'),
}),
HealthModule,
WeatherModule,
],
providers: [],
exports: [],
Expand Down
20 changes: 20 additions & 0 deletions services/weather-control/src/module/weather/query.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { IsLongitude, IsLatitude } from '@cats-cradle/validation-schemas';
import { ApiProperty } from '@nestjs/swagger';

export class QueryDto {
@IsLatitude()
@ApiProperty({
description: 'Latitude',
default: '38.2942',
type: String,
})
latitude: string;

@IsLongitude()
@ApiProperty({
description: 'Longitude',
default: '141.4164',
type: String,
})
longitude: string;
}
23 changes: 23 additions & 0 deletions services/weather-control/src/module/weather/weather.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {
Controller,
Post,
Body,
Res,
Get,
VERSION_NEUTRAL,
Query,
} from '@nestjs/common';
import { WeatherService } from './weather.service';

@Controller({ path: 'weather', version: ['1', VERSION_NEUTRAL] })
export class WeatherController {
constructor(private readonly weatherService: WeatherService) {}

@Post()
async fetch(
@Query('latitude') latitude: number,
@Query('longitude') longitude: number,
) {
return this.weatherService.get(latitude, longitude);
}
}
50 changes: 50 additions & 0 deletions services/weather-control/src/module/weather/weather.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import supertest from 'supertest';
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication, Injectable } from '@nestjs/common';
import { FakerFactory } from '@cats-cradle/faker-factory';
import { WeatherService } from './weather.service';
import { WeatherController } from './weather.controller';
import { ClimateType } from './climates.type';
import { QueryDto } from './query.dto';

describe('/weather', () => {
let app: INestApplication;
let weatherService: WeatherService;

beforeAll(async () => {
const moduleRef: TestingModule = await Test.createTestingModule({
imports: [],
controllers: [WeatherController],
providers: [WeatherService],
}).compile();

app = moduleRef.createNestApplication();

weatherService = moduleRef.get<WeatherService>(WeatherService);

await app.init();
});

afterAll(async () => {
app.close();
});

describe('POST /weather', () => {
it('should determine climate', async () => {
const body = await FakerFactory.create<QueryDto>(QueryDto, {
// longitude: '0',
});
console.log(body);
console.log(body);

const response = await supertest(app.getHttpServer())
.post('/weather')
.send(body)
.expect(201);

expect(response.body).toMatchObject({
climate: ClimateType.POLAR,
});
});
});
});
10 changes: 10 additions & 0 deletions services/weather-control/src/module/weather/weather.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';
import { WeatherController } from './weather.controller';
import { WeatherService } from './weather.service';

@Module({
imports: [],
controllers: [WeatherController],
providers: [WeatherService],
})
export class WeatherModule {}

0 comments on commit d78e829

Please sign in to comment.