Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions src/auth/guards/api.guard.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
import {
ExecutionContext,
Injectable,
CanActivate,
UnauthorizedException,
} from '@nestjs/common';
import { ExecutionContext, Injectable, CanActivate, UnauthorizedException } from '@nestjs/common';
import { Request } from 'express';
import { PrismaService } from '../../prisma/prisma.service';

@Injectable()
export class ApiGuard implements CanActivate {
constructor(private readonly prismaService: PrismaService) { }
constructor(private readonly prismaService: PrismaService) {}

async canActivate(context: ExecutionContext): Promise<boolean> {
const request: Request = context.switchToHttp().getRequest();
try {
const user = await this.prismaService.user.findOne({
where: { apiKey: request.header('apiKey') }
where: { apiKey: request.header('apiKey') },
});
return !!user;
} catch {
Expand Down
4 changes: 4 additions & 0 deletions src/users/users.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ export class UsersService {
return this.prismaService.user.findOne({ where: { id } });
}

async delete(id: string): Promise<User> {
return this.prismaService.user.delete({ where: { id } });
}

async get(id: string): Promise<UserDto> {
const user = await this.findOne(id);
return new UserDto(user);
Expand Down
102 changes: 102 additions & 0 deletions test/builds.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import { AppModule } from '../src/app.module';
import { UsersService } from '../src/users/users.service';
import { haveUserLogged, requestWithApiKey, requestWithAuth } from './preconditions';
import { BuildsService } from '../src/builds/builds.service';
import { CreateBuildDto } from '../src/builds/dto/build-create.dto';
import { UserLoginResponseDto } from '../src/users/dto/user-login-response.dto';
import { Project } from '@prisma/client';
import { ProjectsService } from '../src/projects/projects.service';

describe('Builds (e2e)', () => {
let app: INestApplication;
let buildsService: BuildsService;
let projecstService: ProjectsService;
let usersService: UsersService;
let user: UserLoginResponseDto;
let project: Project;

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

app = moduleFixture.createNestApplication();
buildsService = moduleFixture.get<BuildsService>(BuildsService);
usersService = moduleFixture.get<UsersService>(UsersService);
projecstService = moduleFixture.get<ProjectsService>(ProjectsService);

await app.init();
});

beforeEach(async () => {
user = await haveUserLogged(usersService);
project = await projecstService.create({ name: 'E2E test' });
});

afterEach(async () => {
await projecstService.remove(project.id);
await usersService.delete(user.id);
});

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

describe('POST /', () => {
it('201', () => {
const createBuildDto: CreateBuildDto = {
branchName: 'branchName',
projectId: project.id,
};
return requestWithApiKey(app, 'post', '/builds', createBuildDto, user.apiKey)
.expect(201)
.expect(res => {
expect(res.body.projectId).toBe(project.id);
expect(res.body.branchName).toBe(createBuildDto.branchName);
expect(res.body.failedCount).toBe(0);
expect(res.body.passedCount).toBe(0);
expect(res.body.unresolvedCount).toBe(0);
});
});

it('403', () => {
const createBuildDto: CreateBuildDto = {
branchName: 'branchName',
projectId: project.id,
};
return requestWithApiKey(app, 'post', '/builds', createBuildDto, '').expect(403);
});
});

describe('GET /', () => {
it('200', async () => {
const build = await buildsService.create({ projectId: project.id, branchName: 'develop' });

return requestWithAuth(app, 'get', `/builds?projectId=${project.id}`, {}, user.token)
.expect(200)
.expect(res => {
expect(JSON.stringify(res.body)).toEqual(JSON.stringify([build]));
});
});

it('401', async () => {
return requestWithAuth(app, 'get', `/builds?projectId=${project.id}`, {}, '').expect(401);
});
});

describe('DELETE /', () => {
it('200', async () => {
const build = await buildsService.create({ projectId: project.id, branchName: 'develop' });

return requestWithAuth(app, 'delete', `/builds/${build.id}`, {}, user.token).expect(200);
});

it('401', async () => {
const build = await buildsService.create({ projectId: project.id, branchName: 'develop' });

return requestWithAuth(app, 'delete', `/builds/${build.id}`, {}, '').expect(401);
});
});
});
58 changes: 38 additions & 20 deletions test/preconditions.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,47 @@
import { INestApplication } from '@nestjs/common';
import { UsersService } from 'src/users/users.service';
import { UserLoginRequestDto } from 'src/users/dto/user-login-request.dto';
import uuidAPIKey from 'uuid-apikey';
import request, { Test, CallbackHandler, Request } from 'supertest';
import { CreateUserDto } from 'src/users/dto/user-create.dto';
import request, { Test } from 'supertest';

export const generateUser = (password: string): { email: string, password: string, firstName: string, lastName: string } => ({
email: `${uuidAPIKey.create().uuid}@example.com'`,
password,
firstName: 'fName',
lastName: 'lName',
})
export const generateUser = (
password: string
): { email: string; password: string; firstName: string; lastName: string } => ({
email: `${uuidAPIKey.create().uuid}@example.com'`,
password,
firstName: 'fName',
lastName: 'lName',
});

export const requestWithAuth = (
app: INestApplication,
method: 'post' | 'get' | 'put' | 'delete',
url: string,
body = {},
token: string
): Test =>
request(app.getHttpServer())
[method](url)
.set('Authorization', 'Bearer ' + token)
.send(body);

export const requestWithAuth = (app: INestApplication, method: 'post' | 'get' | 'put' | 'delete', url: string, body = {}, token: string): Test =>
request(app.getHttpServer())
export const requestWithApiKey = (
app: INestApplication,
method: 'post' | 'get' | 'put' | 'delete',
url: string,
body = {},
apiKey: string
): Test =>
request(app.getHttpServer())
[method](url)
.set('Authorization', 'Bearer ' + token)
.send(body)
.set('apiKey', apiKey)
.send(body);

export const haveUserLogged = async (usersService: UsersService) => {
const password = '123456'
const user = await usersService.create(generateUser(password))
const password = '123456';
const user = await usersService.create(generateUser(password));

return usersService.login({
email: user.email,
password
})
}
return usersService.login({
email: user.email,
password,
});
};
57 changes: 29 additions & 28 deletions test/projects.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import { UsersService } from '../src/users/users.service';
import { requestWithAuth, haveUserLogged } from './preconditions';
import { ProjectsService } from '../src/projects/projects.service';
import uuidAPIKey from 'uuid-apikey';
import { UserLoginResponseDto } from 'src/users/dto/user-login-response.dto';

const project = {
id: uuidAPIKey.create().uuid,
name: 'Test project'
}
name: 'Test project',
};

const projectServiceMock = {
findAll: () => ['test'],
Expand All @@ -20,7 +21,7 @@ const projectServiceMock = {
describe('Projects (e2e)', () => {
let app: INestApplication;
let usersService: UsersService;
let loggedUser
let loggedUser: UserLoginResponseDto;

beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
Expand All @@ -31,10 +32,18 @@ describe('Projects (e2e)', () => {
.compile();

app = moduleFixture.createNestApplication();
usersService = moduleFixture.get<UsersService>(UsersService)
usersService = moduleFixture.get<UsersService>(UsersService);
usersService = moduleFixture.get<UsersService>(UsersService);

await app.init();
loggedUser = await haveUserLogged(usersService)
});

beforeEach(async () => {
loggedUser = await haveUserLogged(usersService);
});

afterEach(async () => {
await usersService.delete(loggedUser.id);
});

afterAll(async () => {
Expand All @@ -47,47 +56,39 @@ describe('Projects (e2e)', () => {
.expect(201)
.expect(res => {
expect(res.body.name).toBe(project.name);
})
});
});

it('401', () => {
return requestWithAuth(app, 'post', '/projects', project, '')
.expect(401)
return requestWithAuth(app, 'post', '/projects', project, '').expect(401);
});
})
});

describe('GET /', () => {
it('200', async () => {
const res = await requestWithAuth(app, 'get', '/projects', {}, loggedUser.token)
.expect(200)
const res = await requestWithAuth(app, 'get', '/projects', {}, loggedUser.token).expect(200);

expect(res.body).toEqual(expect.arrayContaining(projectServiceMock.findAll()))
expect(res.body).toEqual(expect.arrayContaining(projectServiceMock.findAll()));
});

it('401', async () => {
await requestWithAuth(app, 'get', '/projects', {}, '')
.expect(401)
await requestWithAuth(app, 'get', '/projects', {}, '').expect(401);
});
})

});

describe('DELETE /', () => {

it('can delete', async () => {
const res = await requestWithAuth(app, 'delete', `/projects/${project.id}`, {}, loggedUser.token)
.expect(200)
const res = await requestWithAuth(app, 'delete', `/projects/${project.id}`, {}, loggedUser.token).expect(200);

expect(res.body).toStrictEqual(projectServiceMock.remove())
})
expect(res.body).toStrictEqual(projectServiceMock.remove());
});

it('not valid UUID', async () => {
await requestWithAuth(app, 'delete', `/projects/123`, {}, loggedUser.token)
.expect(400)
})
await requestWithAuth(app, 'delete', `/projects/123`, {}, loggedUser.token).expect(400);
});

it('not valid token', async () => {
await requestWithAuth(app, 'delete', `/projects/${project.id}`, {}, 'asd')
.expect(401)
})
})
await requestWithAuth(app, 'delete', `/projects/${project.id}`, {}, 'asd').expect(401);
});
});
});