Skip to content

Commit

Permalink
Merge pull request #3 from fga-eps-mds/feature/#129-CRUD_usuario
Browse files Browse the repository at this point in the history
Feature/#129 crud usuario
  • Loading branch information
pedro-cella authored Oct 20, 2023
2 parents 9e243e4 + 03da984 commit 8da7a29
Show file tree
Hide file tree
Showing 20 changed files with 704 additions and 20 deletions.
8 changes: 4 additions & 4 deletions e2e/app.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { INestApplication, ValidationPipe } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import request from 'supertest';
import { AppModule } from './../src/app.module';
import { AllExceptionsFilter } from './../src/shared/filters/all-exceptions.filter';
import { ModelNotFoundExceptionFilter } from './../src/shared/filters/model-not-found.exception-filter';
import { DataTransformInterceptor } from './../src/shared/interceptors/data-transform.interceptor';
import { AppModule } from '../src/app.module';
import { AllExceptionsFilter } from '../src/shared/filters/all-exceptions.filter';
import { ModelNotFoundExceptionFilter } from '../src/shared/filters/model-not-found.exception-filter';
import { DataTransformInterceptor } from '../src/shared/interceptors/data-transform.interceptor';

describe('App (e2e)', () => {
let app: INestApplication;
Expand Down
182 changes: 182 additions & 0 deletions e2e/usuario.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import { INestApplication, ValidationPipe } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import request from 'supertest';
import { Repository } from 'typeorm';
import { AppModule } from '../src/app.module';
import { AllExceptionsFilter } from '../src/shared/filters/all-exceptions.filter';
import { ModelNotFoundExceptionFilter } from '../src/shared/filters/model-not-found.exception-filter';
import { DataTransformInterceptor } from '../src/shared/interceptors/data-transform.interceptor';
import { Usuario } from '../src/usuario/entities/usuario.entity';

describe('E2E - Usuario', () => {
let app: INestApplication;
let repository: Repository<Usuario>;

const user: Partial<Usuario> = {
id: undefined,
nome: 'Henrique',
email: '[email protected]',
senha: '123',
admin: false,
};

beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();

app = moduleFixture.createNestApplication();

app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
transform: true,
}),
);
app.useGlobalInterceptors(new DataTransformInterceptor());
app.useGlobalFilters(
new AllExceptionsFilter(),
new ModelNotFoundExceptionFilter(),
);

await app.startAllMicroservices();
await app.init();

repository = app.get<Repository<Usuario>>(getRepositoryToken(Usuario));
});

describe('POST - /api/usuario', () => {
it('should successfully add a new "usuario"', async () => {
const res = await request(app.getHttpServer())
.post('')
.set('Content-Type', 'application/json')
.send(user);

expect(res.statusCode).toEqual(201);
expect(res.body.message).toEqual('Salvo com sucesso!');
expect(res.body.data).toMatchObject({ ...user, id: res.body.data.id });

Object.assign(user, res.body.data);
delete user.senha;
});

it('should not add a new "usuario" when validations are incorrect', async () => {
const res = await request(app.getHttpServer())
.post('')
.set('Content-Type', 'application/json')
.send({});

expect(res.statusCode).toEqual(400);
expect(res.body.message).toBeInstanceOf(Array);
expect(res.body.message).toEqual([
'nome must be longer than or equal to 5 characters',
'nome must be shorter than or equal to 60 characters',
'nome should not be empty',
'nome must be a string',
'email must be shorter than or equal to 100 characters',
'email must be an email',
'email should not be empty',
'email must be a string',
'senha must be shorter than or equal to 100 characters',
'senha should not be empty',
'senha must be a string',
]);
expect(res.body.data).toBeNull();
});
});

describe('GET - /api/usuario/:id', () => {
it('should successfully get "usuario" by id', async () => {
const res = await request(app.getHttpServer())
.get(`/${user.id}`)
.set('Content-Type', 'application/json')
.send();

expect(res.statusCode).toEqual(200);
expect(res.body.message).toBeNull();
expect(res.body.data).toMatchObject(user);
});

it('should return status 400 when id is invalid', async () => {
const wrongId = 'NaN';
const res = await request(app.getHttpServer())
.get(`/${wrongId}`)
.set('Content-Type', 'application/json')
.send();

expect(res.statusCode).toEqual(400);
expect(res.body.message).toBeInstanceOf(Array);
expect(res.body.message).toEqual(['ID inválido']);
expect(res.body.data).toBeNull();
});

it('should return status 404 when no "usuario" is found', async () => {
const res = await request(app.getHttpServer())
.get('/9999')
.set('Content-Type', 'application/json')
.send();

expect(res.statusCode).toEqual(404);
expect(res.body.message).toEqual('Registro(s) não encontrado(s)!');
expect(res.body.data).toBeNull();
});
});

describe('GET - /api/usuario/', () => {
it('should successfully findAll "usuario"', async () => {
const filter = JSON.stringify({
nome: user.nome,
id: user.id,
email: user.email,
});

const res = await request(app.getHttpServer())
.get('?filter=' + JSON.stringify(filter))
.set('Content-Type', 'application/json')
.send();

expect(res.statusCode).toEqual(200);
expect(res.body.message).toBeNull();
expect(res.body.data).toEqual([user]);
});
});

describe('PATCH - /api/usuario/:id', () => {
it('should successfully update "usuario" by id', async () => {
const update = { nome: 'Jose da Silva' };

const res = await request(app.getHttpServer())
.patch(`/${user.id}`)
.set('Content-Type', 'application/json')
.send(update);

user.nome = update.nome;

expect(res.statusCode).toEqual(200);
expect(res.body.message).toBe('Atualizado com sucesso!');
expect(res.body.data).toMatchObject(user);
});
});

describe('DELETE - /api/usuario/:id', () => {
it('should successfully delete "usuario" by id', async () => {
const res = await request(app.getHttpServer())
.delete(`/${user.id}`)
.set('Content-Type', 'application/json')
.send();

delete user.id;

expect(res.statusCode).toEqual(200);
expect(res.body.message).toBe('Excluído com sucesso!');
expect(res.body.data).toMatchObject(user);
});
});

afterAll(async () => {
await repository.query('TRUNCATE usuario CASCADE');
await repository.delete({});
await app.close();
});
});
4 changes: 2 additions & 2 deletions src/app.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AppController } from './app.controler';
import { AppController } from './app.controller';
import { AppService } from './app.service';

describe('AppController', () => {
Expand All @@ -19,7 +19,7 @@ describe('AppController', () => {
});

it('should make health check', () => {
expect(controller.heathCheck()).toEqual({
expect(controller.healthCheck()).toEqual({
message: 'GEROcuidadoApiUsuario health check Ok!',
data: {},
});
Expand Down
4 changes: 2 additions & 2 deletions src/app.controler.ts → src/app.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export class AppController {
constructor(private readonly service: AppService) {}

@Get('health-check')
heathCheck() {
return this.service.heathCheck();
healthCheck() {
return this.service.healthCheck();
}
}
4 changes: 3 additions & 1 deletion src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controler';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { DbModule } from './config/db/db.module';
import { DbService } from './config/db/db.service';
import { UsuarioModule } from './usuario/usuario.module';

const ENV = process.env.NODE_ENV;

Expand All @@ -19,6 +20,7 @@ const ENV = process.env.NODE_ENV;
useClass: DbService,
}),
DbModule,
UsuarioModule,
],
controllers: [AppController],
providers: [AppService],
Expand Down
2 changes: 1 addition & 1 deletion src/app.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('AppService', () => {
});

it('should make health check', () => {
expect(service.heathCheck()).toEqual({
expect(service.healthCheck()).toEqual({
message: 'GEROcuidadoApiUsuario health check Ok!',
data: {},
});
Expand Down
2 changes: 1 addition & 1 deletion src/app.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
heathCheck() {
healthCheck() {
return {
message: 'GEROcuidadoApiUsuario health check Ok!',
data: {},
Expand Down
15 changes: 15 additions & 0 deletions src/migration/1697762741479-CreateTableUsuario.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class CreateTableUsuario1697762741479 implements MigrationInterface {
name = 'CreateTableUsuario1697762741479';

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE "usuario" ("id" SERIAL NOT NULL, "nome" character varying(60) NOT NULL, "foto" bytea, "email" character varying(100) NOT NULL, "senha" character varying(100) NOT NULL, "admin" boolean NOT NULL DEFAULT false, CONSTRAINT "UQ_2863682842e688ca198eb25c124" UNIQUE ("email"), CONSTRAINT "PK_a56c58e5cabaa04fb2c98d2d7e2" PRIMARY KEY ("id"))`,
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE "usuario"`);
}
}
10 changes: 5 additions & 5 deletions src/shared/classes/http-response.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ describe('HttpResponse', () => {

it('should create message with payload text', () => {
const response = new HttpResponse({});
const created = response.onSuccess('MENSAGENS.SALVO-SUCESSO');
const created = response.onSuccess('Salvo com sucesso!');

const expected = {
message: 'MENSAGENS.SALVO-SUCESSO',
message: 'Salvo com sucesso!',
data: {},
};

Expand All @@ -22,7 +22,7 @@ describe('HttpResponse', () => {
const created = response.onCreated();

const expected = {
message: 'MENSAGENS.SALVO-SUCESSO',
message: 'Salvo com sucesso!',
data: {},
};

Expand All @@ -34,7 +34,7 @@ describe('HttpResponse', () => {
const updated = response.onUpdated();

const expected = {
message: 'MENSAGENS.ATUALIZADO-SUCESSO',
message: 'Atualizado com sucesso!',
data: {},
};

Expand All @@ -46,7 +46,7 @@ describe('HttpResponse', () => {
const updated = response.onDeleted();

const expected = {
message: 'MENSAGENS.EXCLUIDO-SUCESSO',
message: 'Excluído com sucesso!',
data: {},
};

Expand Down
6 changes: 3 additions & 3 deletions src/shared/classes/http-response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ export class HttpResponse<T> implements Response<T> {
}

onCreated(): Response<T> {
this.message = 'MENSAGENS.SALVO-SUCESSO';
this.message = 'Salvo com sucesso!';
return this;
}

onUpdated(): Response<T> {
this.message = 'MENSAGENS.ATUALIZADO-SUCESSO';
this.message = 'Atualizado com sucesso!';
return this;
}

onDeleted(): Response<T> {
this.message = 'MENSAGENS.EXCLUIDO-SUCESSO';
this.message = 'Excluído com sucesso!';
return this;
}
}
1 change: 0 additions & 1 deletion src/shared/helpers/commons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ export const isUndefined = (obj: any): obj is undefined =>
export const isJsonObject = (str: string) => {
try {
const parse = JSON.parse(str);

return parse && typeof parse === 'object';
} catch (e) {
return false;
Expand Down
38 changes: 38 additions & 0 deletions src/usuario/dto/create-usuario.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {
IsBoolean,
IsEmail,
IsNotEmpty,
IsOptional,
IsString,
MaxLength,
MinLength,
} from 'class-validator';

export class CreateUsuarioDto {
// TODO colocar mensagens customizadas "user friendly" em todos os validators

@IsString()
@IsNotEmpty()
@MaxLength(60)
@MinLength(5)
nome!: string;

@IsOptional()
@IsString()
foto?: string;

@IsString()
@IsNotEmpty()
@IsEmail()
@MaxLength(100)
email!: string;

@IsString()
@IsNotEmpty()
@MaxLength(100)
senha!: string;

@IsOptional()
@IsBoolean()
admin?: boolean;
}
4 changes: 4 additions & 0 deletions src/usuario/dto/update-usuario.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { PartialType } from '@nestjs/mapped-types';
import { CreateUsuarioDto } from './create-usuario.dto';

export class UpdateUsuarioDto extends PartialType(CreateUsuarioDto) {}
Loading

0 comments on commit 8da7a29

Please sign in to comment.