Skip to content

Commit

Permalink
Merge pull request #219 from s-xix98/217-チャンネル機能を作る
Browse files Browse the repository at this point in the history
最小のチャンネル機能を作った
  • Loading branch information
s-xix98 authored May 30, 2023
2 parents 8cd1926 + de8329c commit 8b90c9d
Show file tree
Hide file tree
Showing 20 changed files with 434 additions and 7 deletions.
38 changes: 38 additions & 0 deletions backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"jest": "29.5.0",
"prettier": "^2.3.2",
"prisma": "^4.12.0",
"socket.io-client": "^4.6.1",
"source-map-support": "^0.5.20",
"supertest": "^6.1.3",
"ts-jest": "29.0.5",
Expand Down
8 changes: 2 additions & 6 deletions backend/prisma/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,8 @@ async function main() {
hashedPassword: 'piyopiyo',
},
});
const room = await prisma.chatRoom.upsert({
where: {
roomName: 'hogeRoom',
},
update: {},
create: {
const room = await prisma.chatRoom.create({
data: {
roomName: 'hogeRoom',
},
});
Expand Down
9 changes: 8 additions & 1 deletion backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,16 @@ import { EventsGateway } from './events/events.gateway';
import { PostMessageModule } from './post-message/post-message.module';
import { PrismaModule } from './prisma/prisma.module';
import { UserModule } from './user/user.module';
import { ChatModule } from './chat/chat.module';

@Module({
imports: [PrismaModule, PostMessageModule, ConfigModule, UserModule],
imports: [
PrismaModule,
PostMessageModule,
ConfigModule,
UserModule,
ChatModule,
],
controllers: [AppController],
providers: [AppService, EventsGateway],
})
Expand Down
19 changes: 19 additions & 0 deletions backend/src/chat/chat.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Test, TestingModule } from '@nestjs/testing';

import { ChatController } from './chat.controller';

describe('ChatController', () => {
let controller: ChatController;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [ChatController],
}).compile();

controller = module.get<ChatController>(ChatController);
});

test('should be defined', () => {
expect(controller).toBeDefined();
});
});
4 changes: 4 additions & 0 deletions backend/src/chat/chat.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { Controller } from '@nestjs/common';

@Controller('chat')
export class ChatController {}
234 changes: 234 additions & 0 deletions backend/src/chat/chat.gateway.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
import { Test, TestingModule } from '@nestjs/testing';
import { io, Socket } from 'socket.io-client';
import { ChatRoom, User } from '@prisma/client';
import { IoAdapter } from '@nestjs/platform-socket.io';
import { INestApplication } from '@nestjs/common';

import { TestModule } from '../test/test.module';
import { PrismaService } from '../prisma/prisma.service';

import { CreateChannelDto, JoinChannelDto } from './dto/Channel.dto';
import { ChatGateway } from './chat.gateway';
import { MessageDto } from './dto/message.dto';

type testUser = {
user: User;
socket: Socket;
};

const modelNames = ['chatRoom', 'user'];
const USERNUM = 10;

const createTestUsers = async (prismaService: PrismaService) => {
const testUsers: testUser[] = [];
for (let i = 0; i < USERNUM; i++) {
const sock: Socket = io('http://localhost:8001');

const user: User = await prismaService.user.upsert({
where: {
email: `chatTestUser${i}@test.com`,
},
update: {},
create: {
email: `chatTestUser${i}@test.com`,
username: `chatTestUser${i}`,
hashedPassword: `chatTestUser${i}`,
},
});

testUsers.push({ user, socket: sock });
}
return testUsers;
};

const cleanupDatabase = async (
modelNames: string[],
prisma: PrismaService,
): Promise<void> => {
console.log(modelNames);
// prisma.user prisma.chatroom 的なのになる
for (const name of modelNames) {
await (prisma as any)[name].deleteMany({});
}
};

const emitAndWaitForEvent = async <T>(
eventName: string,
socket: Socket,
dto: T,
) => {
return new Promise((resolve) => {
socket.on(eventName, async () => resolve(null));
socket.emit(eventName, dto);
});
};

describe('ChatGateway', () => {
let gateway: ChatGateway;
let prismaService: PrismaService;
let testUsers: testUser[];
let room: ChatRoom | null;
let app: INestApplication;

beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [TestModule],
providers: [ChatGateway, PrismaService],
}).compile();

gateway = module.get<ChatGateway>(ChatGateway);
prismaService = module.get<PrismaService>(PrismaService);

app = module.createNestApplication();
app.useWebSocketAdapter(new IoAdapter(app));
await app.listen(8001);

testUsers = [];
testUsers = await createTestUsers(prismaService);

testUsers.map((testUser) => {
testUser.socket.on('connect', () => {
console.log(`connected ${testUser.user.username}`);
});
});
});
afterAll(async () => {
testUsers.map((testUser) => {
testUser.socket.off('connect', () => {
console.log(`dissconnected ${testUser.user.username}`);
});
});

testUsers.map((testUser) => {
testUser.socket.disconnect();
});

await app.close();
await cleanupDatabase(modelNames, prismaService);
});

test('should be defined', () => {
expect(gateway).toBeDefined();
});

describe('create Channel', () => {
test('users[0]が部屋を作成', async () => {
const user: testUser = testUsers[0];
const createChannelDto: CreateChannelDto = {
roomName: 'testroom',
userId: user.user.id,
};
await emitAndWaitForEvent<CreateChannelDto>(
'createChannel',
user.socket,
createChannelDto,
);

room = await prismaService.chatRoom.findFirst({
where: {
roomName: 'testroom',
},
});

expect(room?.roomName).toEqual(createChannelDto.roomName);
});
});

describe('join Channel', () => {
let roomId: string;
beforeEach(() => {
if (!room) {
throw Error('room is not created');
}
roomId = room.id;
});

test('users[1]~users[9]が部屋に参加', async () => {
const promises: Promise<unknown>[] = [];

testUsers.slice(1).map((testUser) => {
const joinChannel: JoinChannelDto = {
userId: testUser.user.id,
chatRoomId: roomId,
};
const joinPromise = emitAndWaitForEvent<JoinChannelDto>(
'joinChannel',
testUser.socket,
joinChannel,
);
promises.push(joinPromise);
});

await Promise.all(promises).then(async () => {
const MemberList = await prismaService.roomMember.findMany({
where: {
chatRoomId: roomId,
},
});
expect(MemberList.length).toEqual(USERNUM);
});
});
});

describe('sendMessage', () => {
let roomId: string;
beforeEach(() => {
if (!room) {
throw Error('room is not created');
}
roomId = room.id;
});

test('users[0]が送信したメッセージがDBに保存されるか', async () => {
const user: testUser = testUsers[0];
const messageDto: MessageDto = {
content: 'test message',
userId: user.user.id,
chatRoomId: roomId,
};

await emitAndWaitForEvent<MessageDto>(
'sendMessage',
user.socket,
messageDto,
);
const dbMsg = await prismaService.message.findFirst({
where: {
chatRoomId: roomId,
},
});

expect(dbMsg?.content).toEqual(messageDto.content);
});

test('users[0]が送信したメッセージが全員に送信されるか', async () => {
const user = testUsers[0];
const messageDto: MessageDto = {
content: 'test message',
userId: user.user.id,
chatRoomId: roomId,
};
const promises: Promise<unknown>[] = [];

let receivedCount = 0;

testUsers.map((user) => {
const joinPromise = new Promise((resolve) => {
user.socket.on('sendMessage', async () => {
receivedCount++;
console.log(receivedCount);
resolve(null);
});
});

promises.push(joinPromise);
});

user.socket.emit('sendMessage', messageDto);

Promise.all(promises).then(() => {
expect(receivedCount).toEqual(USERNUM);
});
});
});
});
Loading

0 comments on commit 8b90c9d

Please sign in to comment.