Skip to content

Commit

Permalink
Add backend e2e test
Browse files Browse the repository at this point in the history
  • Loading branch information
version-1 committed Feb 26, 2024
1 parent ed141f9 commit 249b192
Show file tree
Hide file tree
Showing 26 changed files with 1,648 additions and 156 deletions.
7 changes: 7 additions & 0 deletions .github/workflows/github-actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,11 @@ jobs:
run: npm run build
- name: Test
run: npm run test
- name: E2E Test
env:
DATABASE_PASSWORD: root
run:
sudo systemctl start mysql.service && \
mysql -u root -proot -c 'create database todo_test;'
npm run test:e2e

10 changes: 7 additions & 3 deletions api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,23 @@
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"tsc": "tsc --project tsconfig.json",
"test": "jest --passWithNoTests",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json",
"test:e2e": "NODE_ENV=test jest --config ./test/jest-e2e.json",
"typeorm": "typeorm-ts-node-commonjs",
"migration:create": "typeorm-ts-node-commonjs migration:create",
"migration:run": "typeorm-ts-node-commonjs migration:run -d src/db/config.ts",
"migration:revert": "typeorm-ts-node-commonjs migration:revert -d src/db/config.ts",
"db:migrate": "ts-node src/db/cli/index.ts migrate",
"db:seed": "ts-node src/db/cli/index.ts seed",
"db:reset": "ts-node src/db/cli/index.ts reset",
"db:setup": "npm run db:reset && npm run db:migrate && npm run db:seed"
"db:setup": "npm run db:reset && npm run db:seed",
"db:test:migrate": "NODE_ENV=test ts-node src/db/cli/index.ts migrate",
"db:test:seed": "NODE_ENV=test ts-node src/db/cli/index.ts seed",
"db:test:reset": "NODE_ENV=test ts-node src/db/cli/index.ts reset",
"db:test:setup": "npm run db:test:reset && npm run db:test:seed"
},
"dependencies": {
"@nestjs/common": "^10.0.0",
Expand Down
1 change: 0 additions & 1 deletion api/src/app.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export class AppController {
@Get()
index(): { version: string } {
const res = this.appService.index();
console.log(res);
return res;
}
}
4 changes: 3 additions & 1 deletion api/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ import { LoggerModule } from './lib/modules/logger/logger.module';

const config = appConfig();

const envFilePath = [`.env.${process.env.NODE_ENV || 'development'}`];

@Module({
imports: [
ConfigModule.forRoot({
load: [appConfig],
envFilePath: ['.env.development.local', '.env.development'],
envFilePath,
validationSchema: Joi.object({
NODE_ENV: Joi.string()
.valid('development', 'production', 'test', 'provision')
Expand Down
113 changes: 95 additions & 18 deletions api/src/db/cli/seeds/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ import { EntityManager, DeepPartial } from 'typeorm';
import dayjs from 'dayjs';
import { UsersService } from '../../../domains/users/users.service';
import { User } from '../../../domains/users/user.entity';
import { Project } from '../../../domains/projects/project.entity';
import { Project, StatusType } from '../../../domains/projects/project.entity';
import { Task } from '../../../domains/tasks/task.entity';
import { Tag } from '../../../domains/tags/tag.entity';

export const seed = async ({ app, dataSource, logger }) => {
const usersService = app.get(UsersService);
const now = dayjs();
console.log('connection is establised');
logger.info('connection is establised');

console.log('users ========');
logger.info('users ========');
const users = [];
await dataSource.transaction(async (manager: EntityManager) => {
for (let i = 1; i <= 10; i++) {
Expand All @@ -31,7 +31,7 @@ export const seed = async ({ app, dataSource, logger }) => {
users.push(user);
}

console.log('tags ========');
logger.info('tags ========');
const user = users[0];
const tags = [];
await Promise.all(
Expand Down Expand Up @@ -63,13 +63,14 @@ export const seed = async ({ app, dataSource, logger }) => {
}),
);

console.log('projects ========');
logger.info('projects ========');
const projects = [];
await Promise.all(
[
{
userId: user.id,
name: 'プログラミング',
uuid: '9a1b53d8-4afc-4630-a26e-3634a10bf619',
slug: 'programming',
goal: '期限日までにフロントエンドエンジニアとして就職する。',
shouldbe: 'エンジニアとしての学習習慣を身につけて生活する。',
Expand All @@ -78,6 +79,7 @@ export const seed = async ({ app, dataSource, logger }) => {
{
userId: user.id,
name: '英語',
uuid: 'ee9f5f2e-fc8c-4830-985a-a44e96e96ffe',
slug: 'english',
goal: 'IELTS Over All 7.0',
shouldbe: '英語に浸る',
Expand All @@ -86,6 +88,7 @@ export const seed = async ({ app, dataSource, logger }) => {
{
userId: user.id,
name: 'プライベート',
uuid: '75cda72f-9883-4570-b3b5-66d389d5b1a9',
slug: 'private',
goal: '長期休みに海外旅行する',
status: 'active' as const,
Expand All @@ -104,12 +107,17 @@ export const seed = async ({ app, dataSource, logger }) => {
);
Promise.all(
new Array(20 - projects.length).fill('').map(async (_, index) => {
let status: StatusType = 'active' as const;
if (index >= 14) {
status = 'archived' as const;
}

const it: DeepPartial<Project> = {
userId: user.id,
name: `ダミープロジェクト ${index + 1}`,
slug: `dummy-projec-${index + 1}`,
goal: `ダミープロジェクト ${index + 1}`,
status: 'active' as const,
status,
};

it.deadline = dayjs()
Expand All @@ -127,22 +135,78 @@ export const seed = async ({ app, dataSource, logger }) => {
projects.push(project);
}),
);
console.log('tasks ========');
logger.info('tasks ========');
const args = [
{
project: projects[0],
premadeTasks: [
{
userId: user.id,
projectId: projects[0].id,
uuid: '067176b2-baaf-4936-b7d4-6d202ab72639',
kind: 'task',
status: 'scheduled',
},
],
premadeMilestones: [
{
userId: user.id,
uuid: '67331996-7671-4cce-87a4-18b46adbd230',
projectId: projects[0].id,
title: `milestone 0`,
kind: 'milestone' as const,
status: 'scheduled' as const,
},
],
tasks: [],
count: 100,
baseDate: dayjs().add(1, 'year'),
},
{
project: projects[1],
premadeTasks: [
{
userId: user.id,
projectId: projects[1].id,
uuid: 'c185e0c2-842e-46f0-a1e8-41d598569431',
kind: 'task',
status: 'scheduled',
},
],
premadeMilestones: [
{
userId: user.id,
uuid: 'be36a559-ec88-4817-b98e-c084a0d51616',
projectId: projects[1].id,
title: `milestone 0`,
kind: 'milestone' as const,
status: 'scheduled' as const,
},
],
tasks: [],
count: 30,
baseDate: dayjs().add(1, 'year'),
},
{
project: projects[2],
premadeTasks: [
{
userId: user.id,
uuid: '1afdd678-1690-4567-9b9f-053cbbec286d',
projectId: projects[2].id,
kind: 'task',
status: 'scheduled',
},
],
premadeMilestones: [
{
userId: user.id,
projectId: projects[2].id,
title: `milestone 0`,
kind: 'milestone' as const,
status: 'scheduled' as const,
},
],
tasks: [],
count: 10,
baseDate: dayjs().add(1, 'year'),
Expand All @@ -151,14 +215,24 @@ export const seed = async ({ app, dataSource, logger }) => {

await Promise.all(
args.map(async (arg, index) => {
console.log('tasks ========', index);
const { project, tasks, count, baseDate } = arg;
for (let i = 0; i < count; i++) {
logger.info('tasks ========', index);
const { project, premadeTasks, tasks, count, baseDate } = arg;
premadeTasks.forEach((it) => tasks.push(it));

const _count = count - premadeTasks.length;
for (let i = 0; i < _count; i++) {
let status = 'scheduled';
if (i >= arg.count - 3) {
status = 'archived';
} else if (i >= arg.count - 6) {
status = 'completed';
}

tasks.push({
userId: user.id,
projectId: project.id,
kind: 'task' as const,
status: 'scheduled' as const,
status,
});
}

Expand All @@ -178,13 +252,16 @@ export const seed = async ({ app, dataSource, logger }) => {

let head = 0;
for (let i = 0; i < 5; i++) {
const milestone = {
userId: user.id,
projectId: project.id,
title: `milestone ${i}`,
kind: 'milestone' as const,
status: 'scheduled' as const,
};
const milestone =
i === 0
? arg.premadeMilestones[0]
: {
userId: user.id,
projectId: project.id,
title: `milestone ${i}`,
kind: 'milestone' as const,
status: 'scheduled' as const,
};

const m = manager.create(Task, milestone);
const tail = head + Math.ceil((tasks.length - 1 - head) / 2);
Expand Down
8 changes: 6 additions & 2 deletions api/src/db/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,21 @@ import { Tag } from '../domains/tags/tag.entity';
import { DataSource, DataSourceOptions } from 'typeorm';
import migrations from '../db/migrations';

const database =
process.env['DATABASE_NAME'] ||
`todo_${process.env.NODE_ENV || 'development'}`;

export const dataSourceOptions = {
type: 'mysql',
host: process.env['DATABASE_HOST'] || 'localhost',
port: 3306,
username: process.env['DATABASE_USERNAME'] || 'root',
password: process.env['DATABASE_PASSWORD'],
database: process.env['DATABASE_NAME'] || 'todo_development',
database,
entities: [User, Project, Task, TagTask, Tag],
migrations,
synchronize: false,
logging: true,
logging: process.env.NODE_ENV !== 'test',
autoLoadEntities: true,
};

Expand Down
15 changes: 9 additions & 6 deletions api/src/domains/bulk/tasks.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,31 @@ export class TasksController {
@DUser() user: User,
@Body('ids') ids: string[],
): Promise<Record<string, any>> {
const result = await this.tasksService.archive(user.id, ids);
await this.tasksService.archive(user.id, ids);
const data = await this.tasksService.findAll({ userId: user.id, ids });

return { data: result };
return { data };
}

@Put('complete')
async complete(
@DUser() user: User,
@Body('ids') ids: string[],
): Promise<Record<string, any>> {
const result = await this.tasksService.complete(user.id, ids);
await this.tasksService.complete(user.id, ids);
const data = await this.tasksService.findAll({ userId: user.id, ids });

return { data: result };
return { data };
}

@Put('reopen')
async reopen(
@DUser() user: User,
@Body('ids') ids: string[],
): Promise<Record<string, any>> {
const result = await this.tasksService.reopen(user.id, ids);
await this.tasksService.reopen(user.id, ids);
const data = await this.tasksService.findAll({ userId: user.id, ids });

return { data: result };
return { data };
}
}
3 changes: 1 addition & 2 deletions api/src/domains/projects/projects.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import { TasksModule } from '../tasks/tasks.module';
import { Task } from '../tasks/task.entity';
import { Project } from './project.entity';
import { ProjectsService } from './projects.service';
import { TasksController } from './tasks.controller';
import { MilestonesController } from './milestones.controller';

@Module({
imports: [TypeOrmModule.forFeature([Project, Task]), TasksModule],
providers: [ProjectsService],
exports: [ProjectsService],
controllers: [TasksController, MilestonesController],
controllers: [MilestonesController],
})
export class ProjectsModule {}
7 changes: 5 additions & 2 deletions api/src/domains/projects/projects.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,17 @@ export class ProjectsService {
});

const projectIds = projects.map((it) => it.id);
const stats = await this.tasksService.statics(projectIds);
let stats = {};
if (projectIds.length > 0) {
stats = await this.tasksService.statics(projectIds);
}
projects.forEach((p: Project) => {
p.stats = stats[p.id] || initialStat();
});

const result = new Pagination({
data: projects,
limit,
limit: take,
page: page || 1,
totalCount,
...sortOptions,
Expand Down

0 comments on commit 249b192

Please sign in to comment.