Skip to content

Commit

Permalink
Merge pull request #508 from boostcampwm2023/FE/bugfix/#428-게스트가-들어오기…
Browse files Browse the repository at this point in the history
…전에-프로필을-설정하면-상대방에게-적용-안됨

Fe/bugfix/#428 게스트가 들어오기전에 프로필을 설정하면 상대방에게 적용 안됨
  • Loading branch information
Doosies authored Jan 31, 2024
2 parents 0742016 + e6ff7a9 commit 714cf96
Show file tree
Hide file tree
Showing 12 changed files with 357 additions and 246 deletions.
8 changes: 4 additions & 4 deletions frontend/src/business/hooks/usePopup/usePasswordPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { randomString } from '@utils/ramdom';

type openPasswordPopupParams = {
host?: boolean;
onSubmit?: ({ password, closeOverlay }: { password: string } & CloseOverlayFunc) => void;
onSubmit?: ({ password, closePopup }: { password: string } & ClosePopupFunc) => void;
onCancel?: () => void;
};

Expand All @@ -16,12 +16,12 @@ export function usePasswordPopup() {
const openPasswordPopup = ({ host, onSubmit, onCancel }: openPasswordPopupParams) => {
const defaultValue = host ? randomString() : '';

openOverlay(({ closeOverlay }) => (
openOverlay(({ closeOverlay: closePopup }) => (
<PasswordPopup
closePopup={closeOverlay}
closePopup={closePopup}
onCancel={onCancel}
onSubmit={password => {
onSubmit?.({ password, closeOverlay });
onSubmit?.({ password, closePopup });
}}
defaultValue={defaultValue}
/>
Expand Down

This file was deleted.

148 changes: 21 additions & 127 deletions frontend/src/business/hooks/useWebRTC/useDataChannel.spec.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,19 @@
import { useDataChannel } from '.';
import { RenderHookResult, renderHook } from '@testing-library/react';
import { renderHook } from '@testing-library/react';

import WebRTC from '@business/services/WebRTC';

import {
sendMyNickname,
sendMyProfileImage,
sendNowMediaStates,
setMediaStates,
setRemoteNicknameState,
setRemoteProfileImageState,
} from './useDataChannel.eventListeners';

vi.mock('@business/services/WebRTC');

type RenderHookResultType = {
initDataChannels: () => void;
dataChannels: Map<any, RTCDataChannel>;
};

describe('useDataChannel 테스트', () => {
let mockWebRTCModule = WebRTC.getInstance();
let renderUtil: RenderHookResult<RenderHookResultType, unknown>;
let currentRenderResult: RenderHookResultType;

function rerenderHook() {
renderUtil = renderHook(() => useDataChannel());
currentRenderResult = renderUtil.result.current;
const {
rerender,
result: {
current: { dataChannels, initDataChannels },
},
} = renderHook(() => useDataChannel());
return { rerender, dataChannels, initDataChannels };
}

const addEventListener = vi.fn();
Expand All @@ -36,151 +23,58 @@ describe('useDataChannel 테스트', () => {
vi.spyOn(mockWebRTCModule, 'addDataChannel').mockReturnValue(mediaInfoChannelStub);
});

beforeEach(() => {
rerenderHook();
});

afterEach(() => {
vi.clearAllMocks();
});

afterAll(() => {
vi.resetAllMocks();
vi.resetModules();
});

describe('initDataChannels 함수 테스트: 아래 A ~ B의 함수가 실행됨', () => {
describe('initDataChannels 함수 테스트: 아래 A ~ D의 함수가 실행됨', () => {
describe('A. initMediaInfoChannel 함수 테스트', () => {
it('mediaInfoChannel 데이터 채널 추가 + message와 open 이벤트가 등록됨.', () => {
currentRenderResult.initDataChannels();
const { initDataChannels } = rerenderHook();
initDataChannels();

expect(mockWebRTCModule.addDataChannel).toBeCalledWith('mediaInfoChannel');
expect(addEventListener).toBeCalledWith('message', expect.any(Function));
expect(addEventListener).toBeCalledWith('open', expect.any(Function));
});

it(`message 이벤트: setMediaStates 호출
\t 1. type === video라면 onOrOff와 함께 setRemoteVideoOn 호출, 상대 비디오 상태 설정
\t 2. type === audio라면 onOrOff와 함께 setMicOn 호출, 상대 마이크 상태 설정`, () => {
const testDatas = [
{ data: JSON.stringify([{ type: 'video', onOrOff: true }]) },
{ data: JSON.stringify([{ type: 'audio', onOrOff: true }]) },
{ data: JSON.stringify([{ type: 'video', onOrOff: false }]) },
{ data: JSON.stringify([{ type: 'audio', onOrOff: false }]) },
];

testDatas.forEach(async (ev: any) => {
const setRemoteMicOn = vi.fn();
const setRemoteVideoOn = vi.fn();
const { type, onOrOff } = JSON.parse(ev.data);

setMediaStates({ ev, setRemoteMicOn, setRemoteVideoOn });

if (type === 'audio') {
expect(setRemoteMicOn).toBeCalledWith(onOrOff);
expect(setRemoteVideoOn).not.toBeCalled();
}

if (type === 'video') {
expect(setRemoteMicOn).not.toBeCalled();
expect(setRemoteVideoOn).toBeCalledWith(onOrOff);
}
});
});

it('open 이벤트: sendNowMediaStates 호출, 현재 미디어 상태를 전송', () => {
const testDatas = [
{ audioTrack: { enabled: true }, videoTrack: { enabled: true } },
{ audioTrack: { enabled: false }, videoTrack: { enabled: false } },
{ audioTrack: { enabled: true }, videoTrack: { enabled: false } },
{ audioTrack: { enabled: false }, videoTrack: { enabled: true } },
];

testDatas.forEach(({ audioTrack, videoTrack }) => {
vi.spyOn(mockWebRTCModule, 'getFirstAudioTrack').mockReturnValueOnce(audioTrack as any);
vi.spyOn(mockWebRTCModule, 'getFirstVideoTrack').mockReturnValueOnce(videoTrack as any);
const RTCDataChannelSendFn = vi.fn();

sendNowMediaStates.call({ send: RTCDataChannelSendFn } as any);

expect(RTCDataChannelSendFn).toBeCalledWith(
JSON.stringify([
{ type: 'audio', onOrOff: audioTrack?.enabled },
{ type: 'video', onOrOff: videoTrack?.enabled },
]),
);
});
});
});

describe('B. initChatChannel 함수 테스트', () => {
it('chatChannel 데이터 채널 추가', () => {
currentRenderResult.initDataChannels();
const { initDataChannels } = rerenderHook();
initDataChannels();

expect(mockWebRTCModule.addDataChannel).toBeCalledWith('chatChannel');
});
});

describe('C. initProfileChannel 함수 테스트', () => {
it('profileChannel 데이터 채널 추가 + message와 open 이벤트가 등록됨.', () => {
currentRenderResult.initDataChannels();
const { initDataChannels } = rerenderHook();
initDataChannels();

expect(mockWebRTCModule.addDataChannel).toBeCalledWith('profileChannel');
expect(addEventListener).toBeCalledWith('message', expect.any(Function));
expect(addEventListener).toBeCalledWith('open', expect.any(Function));
});

it(`message 이벤트: setRemoteProfileImageState(ev) 호출, 상대의 프로필사진을 설정함`, () => {
const setRemoteProfileImage = vi.fn();
const arrayBuffer = new ArrayBuffer(8);
const type = 'image/png';
const ev = { data: JSON.stringify({ type, arrayBuffer: new Uint8Array(arrayBuffer) }) } as any as MessageEvent;

setRemoteProfileImageState({ ev, setRemoteProfileImage } as any);

expect(setRemoteProfileImage).toBeCalledWith({ arrayBuffer, type });
});

it(`on 이벤트: sendMyProfileImage(myProfile) 호출, 내 프로필 사진을 전송함`, () => {
const myProfile = { arrayBuffer: new ArrayBuffer(8), type: 'image/png' };
const RTCDataChannelSendFn = vi.fn();

sendMyProfileImage.call({ send: RTCDataChannelSendFn } as any, { myProfile });

expect(RTCDataChannelSendFn).toBeCalledWith(JSON.stringify({ myProfile }));
});
});

describe('D. initNicknameChannel 함수 테스트', () => {
it('nicknameChannel 데이터 채널 추가 + message와 open 이벤트가 등록됨.', () => {
currentRenderResult.initDataChannels();
const { initDataChannels } = rerenderHook();
initDataChannels();

expect(mockWebRTCModule.addDataChannel).toBeCalledWith('nicknameChannel');
expect(addEventListener).toBeCalledWith('message', expect.any(Function));
expect(addEventListener).toBeCalledWith('open', expect.any(Function));
});

it(`message 이벤트: setRemoteNicknameState(ev) 호출, 상대의 닉네임을 설정함`, () => {
const setRemoteNickname = vi.fn();
const ev = { data: 'testNickName' } as any as MessageEvent;

setRemoteNicknameState({ ev, setRemoteNickname } as any);

expect(setRemoteNickname).toBeCalledWith('testNickName');
});

it(`on 이벤트: sendMyNickname(myNickname) 호출, 내 닉네임을 전송함`, () => {
const myNickname = 'testNickName';
const RTCDataChannelSendFn = vi.fn();

sendMyNickname.call({ send: RTCDataChannelSendFn } as any, { myNickname });

expect(RTCDataChannelSendFn).toBeCalledWith(myNickname);
});
});
});

it('dataChannels: webRTC.getDataChannels를 호출 후 그 결과를 반환함', () => {
expect(currentRenderResult.dataChannels).toBe(mockWebRTCModule.getDataChannels());
const { dataChannels, initDataChannels } = rerenderHook();
initDataChannels();

expect(dataChannels).toBe(mockWebRTCModule.getDataChannels());
});
});
40 changes: 14 additions & 26 deletions frontend/src/business/hooks/useWebRTC/useDataChannel.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,22 @@
import WebRTC from '@business/services/WebRTC';

import { useMediaInfo } from '@stores/zustandStores/useMediaInfo';
import { useProfileInfo } from '@stores/zustandStores/useProfileInfo';

import {
sendMyNickname,
sendMyProfileImage,
sendNowMediaStates,
setMediaStates,
setRemoteNicknameState,
setRemoteProfileImageState,
} from './useDataChannel.eventListeners';
import { useDataChannelEventListener } from './useDataChannelEventListener';

export function useDataChannel() {
const { setRemoteMicOn, setRemoteVideoOn } = useMediaInfo(state => ({
setRemoteMicOn: state.setRemoteMicOn,
setRemoteVideoOn: state.setRemoteVideoOn,
}));
const { myNickname, myProfile, setRemoteNickname, setRemoteProfileImage } = useProfileInfo(state => ({
setRemoteNickname: state.setRemoteNickname,
setRemoteProfileImage: state.setRemoteProfile,
myNickname: state.myNickname,
myProfile: state.myProfile,
}));
const webRTC = WebRTC.getInstance();
const {
sendMyNickname,
sendMyProfileImage,
sendNowMediaStates,
setMediaStates,
setRemoteNicknameState,
setRemoteProfileImageState,
} = useDataChannelEventListener();

const initMediaInfoChannel = () => {
const mediaInfoChannel = webRTC.addDataChannel('mediaInfoChannel');

mediaInfoChannel?.addEventListener('message', ev => setMediaStates({ ev, setRemoteMicOn, setRemoteVideoOn }));
mediaInfoChannel?.addEventListener('message', ev => setMediaStates({ ev }));

mediaInfoChannel?.addEventListener('open', sendNowMediaStates);
};
Expand All @@ -40,17 +28,17 @@ export function useDataChannel() {
const initProfileChannel = () => {
const profileChannel = webRTC.addDataChannel('profileChannel');

profileChannel?.addEventListener('message', ev => setRemoteProfileImageState({ ev, setRemoteProfileImage }));
profileChannel?.addEventListener('message', ev => setRemoteProfileImageState({ ev }));

profileChannel?.addEventListener('open', sendMyProfileImage.bind(profileChannel, { myProfile }));
profileChannel?.addEventListener('open', sendMyProfileImage.bind(profileChannel));
};

const initNicknameChannel = () => {
const nicknameChannel = webRTC.addDataChannel('nicknameChannel');

nicknameChannel?.addEventListener('message', ev => setRemoteNicknameState({ ev, setRemoteNickname }));
nicknameChannel?.addEventListener('message', ev => setRemoteNicknameState({ ev }));

nicknameChannel?.addEventListener('open', sendMyNickname.bind(nicknameChannel, { myNickname }));
nicknameChannel?.addEventListener('open', sendMyNickname.bind(nicknameChannel));
};

const initDataChannels = () => {
Expand Down
Loading

0 comments on commit 714cf96

Please sign in to comment.