Skip to content

Commit

Permalink
add test suite to decorator
Browse files Browse the repository at this point in the history
  • Loading branch information
ezzabuzaid committed Oct 5, 2019
1 parent ca04281 commit 3b770f2
Show file tree
Hide file tree
Showing 18 changed files with 373 additions and 184 deletions.
8 changes: 8 additions & 0 deletions src/app/api/users/users.model.ts
Expand Up @@ -2,6 +2,7 @@ import { HashService, Constants } from '@core/helpers';
import { BaseModel, Entity, Field } from '@lib/mongoose';
import { ValidationPatterns } from '@shared/common';
import { parsePhoneNumberFromString } from 'libphonenumber-js';
import { Query } from 'mongoose';

@Entity(Constants.Schemas.USERS)
export class UsersSchema {
Expand Down Expand Up @@ -37,3 +38,10 @@ export class UsersSchema {
}

export const UsersModel = BaseModel<UsersSchema>(UsersSchema);
UsersModel.schema.pre('find', () => {
(this as unknown as Query<any>).select({ password: 0 });
});

UsersModel.schema.pre('findOne', (query) => {
(this as unknown as Query<any>).select({ password: 0 });
});
20 changes: 11 additions & 9 deletions src/app/api/users/users.routes.ts
@@ -1,18 +1,20 @@
import { CrudRouter } from '@shared/crud';
import usersService from './users.service';
import { Constants } from '@core/helpers';
import { Logger } from '@core/utils';
import { Router } from '@lib/methods';
import { Constants, SuccessResponse, NetworkStatus } from '@core/helpers';
import { Router, Post } from '@lib/methods';
import { UsersSchema } from './users.model';
import { Request, Response } from 'express';
import { translate } from '@lib/translation';

const log = new Logger('UsersRouter');
@Router(Constants.Endpoints.USERS, {
crud: {
create: []
}
})
@Router(Constants.Endpoints.USERS)
export class UsersRouter extends CrudRouter<UsersSchema> {
constructor() {
super(usersService);
}

@Post('')
public async create(req: Request, res: Response) {
return super.create(req, res);
}

}
2 changes: 1 addition & 1 deletion src/app/api/users/users.service.ts
Expand Up @@ -20,7 +20,7 @@ class UserService extends CrudService<UsersSchema> {
async post(entity) {
await accountsService.deleteAccount(entity.id);
}
},
}
});
}
}
Expand Down
147 changes: 83 additions & 64 deletions src/app/api/users/users.spec.ts
@@ -1,8 +1,9 @@
import '@test/index';
import { Types } from 'mongoose';
import { superAgent } from '@test/supertest';
import { createUser, deleteUser, UserFixture } from '@test/fixture';
import { Constants, NetworkStatus } from '@core/helpers';
import { Body } from '@lib/mongoose';
import { UsersSchema } from './users.model';

const ENDPOINT = `/api/${Constants.Endpoints.USERS}`;
let user: UserFixture = null;
Expand All @@ -15,80 +16,98 @@ afterAll(async () => {
});

// NOTE test the fail, don't test the success
describe('GET ALL', () => {
test('Reject request without token', async () => {
(await superAgent).get(ENDPOINT);
const res = (await (await superAgent).get(`${ENDPOINT}`));
expect(res.status).toBe(NetworkStatus.UNAUTHORIZED);
});
describe('CREATE USER', () => {
test('Fail if the user exist before', async () => {
const body = {
email: 'test@create1.com',
mobile: '0792807794',
password: '123456789',
username: 'testCreate1'
} as Body<UsersSchema>;
const req1 = (await superAgent).post(ENDPOINT);
const res1 = await req1.send(body);

const req2 = (await superAgent).post(ENDPOINT);
const res2 = await req2.send(body);

test('Should return list', async () => {
const req = (await superAgent).get(`${ENDPOINT}`);
const res = await req.set('Authorization', user.token);
expect(res.status).toBe(NetworkStatus.OK);
expect(res.body.data).toBeInstanceOf(Array);
const deleteReq = await (await superAgent).delete(`${ENDPOINT}/${res1.body.id}`);
expect(res2.status).toBe(NetworkStatus.BAD_REQUEST);
});
});

describe('GET BY ${id}/', () => {
test('Reject request without token', async () => {
const res = await (await superAgent).get(`${ENDPOINT}/${user.id}`);
expect(res.status).toBe(NetworkStatus.UNAUTHORIZED);
});
// describe('GET ALL', () => {
// test('Reject request without token', async () => {
// const res = (await (await superAgent).get(`${ENDPOINT}`));
// expect(res.status).toBe(NetworkStatus.UNAUTHORIZED);
// });

test('should fail if requested with id not of type ObjectId', async () => {
// this will rise cast error
const req = (await superAgent).get(`${ENDPOINT}/${undefined}`);
const res = await req.set('Authorization', user.token);
expect(res.status).toBe(NetworkStatus.BAD_REQUEST);
});
// test('Should return list', async () => {
// const req = (await superAgent).get(`${ENDPOINT}`);
// const res = await req.set('Authorization', user.token);
// expect(res.status).toBe(NetworkStatus.OK);
// expect(res.body.data).toBeInstanceOf(Array);
// });
// });

test('should fail if requested to non exist entity', async () => {
const req = (await superAgent).get(`${ENDPOINT}/${new Types.ObjectId()}`);
const res = await req.set('Authorization', user.token);
expect(res.status).toBe(NetworkStatus.NOT_ACCEPTABLE);
});
// describe('GET BY ${id}/', () => {
// test('Reject request without token', async () => {
// const res = await (await superAgent).get(`${ENDPOINT}/${user.id}`);
// expect(res.status).toBe(NetworkStatus.UNAUTHORIZED);
// });

test('resposne body should equal to', async () => {
const req = (await superAgent).get(`${ENDPOINT}/${user.id}`);
const res = await req.set('Authorization', user.token);
const { data } = res.body;
expect(data).toHaveProperty('username');
expect(data).toHaveProperty('email');
expect(data).toHaveProperty('mobile');
expect(data).toHaveProperty('createdAt');
expect(data).toHaveProperty('updatedAt');
expect(data).toHaveProperty('_id');
// password return, even it returned without being hashing
expect(data).not.toHaveProperty('password');
});
});
// test('should fail if requested with id not of type ObjectId', async () => {
// // this will rise cast error
// const req = (await superAgent).get(`${ENDPOINT}/${undefined}`);
// const res = await req.set('Authorization', user.token);
// expect(res.status).toBe(NetworkStatus.BAD_REQUEST);
// });

describe('DELETE BY ${id}/', () => {
test('Reject request without token', async () => {
const res = await (await superAgent).delete(`${ENDPOINT}/${user.id}`);
expect(res.status).toBe(NetworkStatus.UNAUTHORIZED);
});
// test('should fail if requested to non exist entity', async () => {
// const req = (await superAgent).get(`${ENDPOINT}/${new Types.ObjectId()}`);
// const res = await req.set('Authorization', user.token);
// expect(res.status).toBe(NetworkStatus.NOT_ACCEPTABLE);
// });

test('should fail if requested with id not of type ObjectId', async () => {
const req = (await superAgent).delete(`${ENDPOINT}/${undefined}`);
const res = await req.set('Authorization', user.token);
expect(res.status).toBe(NetworkStatus.BAD_REQUEST);
});
// test('resposne body should equal to', async () => {
// const req = (await superAgent).get(`${ENDPOINT}/${user.id}`);
// const res = await req.set('Authorization', user.token);
// const { data } = res.body;
// expect(data).toHaveProperty('username');
// expect(data).toHaveProperty('email');
// expect(data).toHaveProperty('mobile');
// expect(data).toHaveProperty('createdAt');
// expect(data).toHaveProperty('updatedAt');
// expect(data).toHaveProperty('_id');
// // password return, even it returned without being hashing
// expect(data).not.toHaveProperty('password');
// });
// });

test('should fail if requested to non exist entity', async () => {
const req = (await superAgent).delete(`${ENDPOINT}/${new Types.ObjectId()}`);
const res = await req.set('Authorization', user.token);
expect(res.status).toBe(NetworkStatus.NOT_ACCEPTABLE);
});
// describe('DELETE BY ${id}/', () => {
// test('Reject request without token', async () => {
// const res = await (await superAgent).delete(`${ENDPOINT}/${user.id}`);
// expect(res.status).toBe(NetworkStatus.UNAUTHORIZED);
// });

test('resposne body should equal to', async () => {
const req = (await superAgent).delete(`${ENDPOINT}/${user.id}`);
const res = await req.set('Authorization', user.token);
const { data } = res.body;
expect(data).toBeNull();
});
});
// test('should fail if requested with id not of type ObjectId', async () => {
// const req = (await superAgent).delete(`${ENDPOINT}/${undefined}`);
// const res = await req.set('Authorization', user.token);
// expect(res.status).toBe(NetworkStatus.BAD_REQUEST);
// });

// test('should fail if requested to non exist entity', async () => {
// const req = (await superAgent).delete(`${ENDPOINT}/${new Types.ObjectId()}`);
// const res = await req.set('Authorization', user.token);
// expect(res.status).toBe(NetworkStatus.NOT_ACCEPTABLE);
// });

// test('resposne body should equal to', async () => {
// const req = (await superAgent).delete(`${ENDPOINT}/${user.id}`);
// const res = await req.set('Authorization', user.token);
// const { data } = res.body;
// expect(data).toBeNull();
// });
// });

// tslint:disable-next-line: max-line-length
// REVIEW in create and update you should check and verify if the data was update or created successfully other that the failur test
Expand Down
7 changes: 6 additions & 1 deletion src/app/core/utils/utils.service.ts
Expand Up @@ -58,7 +58,7 @@ export class AppUtils {
return Object.keys(object).filter((el) => typeof object[el].value === 'function');
}

public static removeKey(key, obj) {
public static removeKey<T>(key: keyof T, obj: T) {
const { [key]: foo, ...rest } = obj;
return rest;
}
Expand All @@ -74,6 +74,11 @@ export class AppUtils {
public static isNullOrUndefined(value) {
return value === undefined || value === null;
}

public static hasItemWithin(list: any[]) {
return list.length > 0;
}

}

// NOTE Utility class to be extended, so when you call build it will construct an instance from that class
Expand Down
18 changes: 9 additions & 9 deletions src/app/playground/deploy.ts
Expand Up @@ -5,8 +5,8 @@ import del from 'del';
import path from 'path';

const git_clone = path.join(process.cwd(), 'git_clone');
const clone = git(createDir(git_clone));
deploy(null, null);
// const clone = git(createDir(git_clone));
// deploy(null, null);

function createDir(_path) {
del.sync(_path, { force: true });
Expand All @@ -20,12 +20,12 @@ export function deploy(req, res) {
// const sender = req.body.sender;
// const branch = req.body.ref;
const REPO = 'https://github.com/ezzabuzaid/angular-buildozer.git';
clone.silent(true)
.clone(REPO)
.then(() => {
execSync('cd ' + git_clone + '/angular-buildozer' + ' && chmod +x ./deploy.sh');
console.log('Finished => ', 'cd ' + git_clone + '/angular-buildozer' + ' && chmod +x ./deploy.sh');
})
.catch((err) => console.error('failed: ', err));
// clone.silent(true)
// .clone(REPO)
// .then(() => {
// execSync('cd ' + git_clone + '/angular-buildozer' + ' && chmod +x ./deploy.sh');
// console.log('Finished => ', 'cd ' + git_clone + '/angular-buildozer' + ' && chmod +x ./deploy.sh');
// })
// .catch((err) => console.error('failed: ', err));
// res.send({ success: true });
}
24 changes: 13 additions & 11 deletions src/app/shared/crud/crud.options.ts
@@ -1,20 +1,22 @@
import { Body, Document } from '@lib/mongoose';
import { PickAttr } from '@core/utils';

export interface ICrudHooks<T> {
pre?: (doc: Document<T>) => any;
post?: (doc: Document<T>) => any;
}

export interface ICrudOperation<T = any> {
create?: {
pre?: (doc: Document<T>) => any;
post?: (doc: Document<T>) => any;
};
update?: {
pre?: (doc: Document<T>) => any;
post?: (doc: Document<T>) => any;
};
delete?: {
pre?: (doc: Document<T>) => any;
post?: (doc: Document<T>) => any;
create?: ICrudHooks<T>;
update?: ICrudHooks<T>;
delete?: ICrudHooks<T>;
one?: ICrudHooks<T>;
all?: {
post: (docs: Array<Document<T>>) => any
};
}
export interface ICrudOptions<T> extends ICrudOperation<T> {
// TODO: Move it to each crud operation without the [attr] key
unique: Array<{
attr: keyof Body<T>,
}>;
Expand Down

0 comments on commit 3b770f2

Please sign in to comment.