Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import React from 'react';
import * as useCreateChannelModule from '../../../context/useCreateChannel';
import { CHANNEL_TYPE } from '../../../types';
import { act, render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { LocalizationContext } from '../../../../../lib/LocalizationContext';
import CreateChannelUI from '../index';

jest.mock('../../../../../hooks/useSendbirdStateContext', () => ({
__esModule: true,
default: jest.fn(() => ({
stores: {
userStore: {
user: {
userId: ' test-user-id',
},
},
sdkStore: {
sdk: {
currentUser: {
userId: 'test-user-id',
},
createApplicationUserListQuery: () => ({
next: () => Promise.resolve([{ userId: 'test-user-id' }]),
isLoading: false,
}),
},
initialized: true,
},
},
config: {
logger: console,
userId: 'test-user-id',
groupChannel: {
enableMention: true,
},
isOnline: true,
},
})),
}));
jest.mock('../../../context/useCreateChannel');

const mockStringSet = {
MODAL__CREATE_CHANNEL__TITLE: 'CREATE_CHANNEL',
MODAL__INVITE_MEMBER__SELECTED: 'USERS_SELECTED',
};

const mockLocalizationContext = {
stringSet: mockStringSet,
};

const defaultMockState = {
sdk: undefined,
createChannel: undefined,
userListQuery: undefined,
onCreateChannelClick: undefined,
onChannelCreated: undefined,
onBeforeCreateChannel: undefined,
step: 0,
type: CHANNEL_TYPE.GROUP,
onCreateChannel: undefined,
overrideInviteUser: undefined,
};

const defaultMockActions = {
setStep: jest.fn(),
setType: jest.fn(),
};

describe('CreateChannelUI Integration Tests', () => {
const mockUseCreateChannel = useCreateChannelModule.default as jest.Mock;

const renderComponent = (mockState = {}, mockActions = {}) => {
mockUseCreateChannel.mockReturnValue({
state: { ...defaultMockState, ...mockState },
actions: { ...defaultMockActions, ...mockActions },
});

return render(
<LocalizationContext.Provider value={mockLocalizationContext as any}>
<CreateChannelUI />
</LocalizationContext.Provider>,
);
};

beforeEach(() => {
jest.clearAllMocks();
document.body.innerHTML = `
<div id='sendbird-modal-root' />
`;
});

it('display initial state correctly', () => {
renderComponent();

expect(screen.getByText('CREATE_CHANNEL')).toBeInTheDocument();
});

it('display SelectChannelType when step is 0', () => {
renderComponent({ step: 0 });

expect(screen.getByText('CREATE_CHANNEL')).toBeInTheDocument();
});

it('display InviteUsers when step is 1', async () => {
await act(async () => {
renderComponent({ step: 1 });
});

expect(screen.getByText('0 USERS_SELECTED')).toBeInTheDocument();
});

});
14 changes: 9 additions & 5 deletions src/modules/CreateChannel/components/CreateChannelUI/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import './create-channel-ui.scss';

import React from 'react';

import { useCreateChannelContext } from '../../context/CreateChannelProvider';
import InviteUsers from '../InviteUsers';

import SelectChannelType from '../SelectChannelType';
import useCreateChannel from '../../context/useCreateChannel';

export interface CreateChannelUIProps {
onCancel?(): void;
Expand All @@ -16,10 +16,14 @@ const CreateChannel: React.FC<CreateChannelUIProps> = (props: CreateChannelUIPro
const { onCancel, renderStepOne } = props;

const {
step,
setStep,
userListQuery,
} = useCreateChannelContext();
state: {
step,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

단순 궁금증인데 step 이게 어떤걸 의미하는건가요? 코드를 보니 값이 매직넘버인것같아서 의미가 조금 명확해지도록 개선하면 좋을것 같습니다.

Copy link
Contributor

@HoonBaek HoonBaek Nov 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image
image

채널 생성화면에서의 스텝을 말하는 것 같습니다.
(1) 생성할 채널 타입 선택
(2) 초대할 유저 선택

저도 동의합니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

step -> pageStep으로 변경하였습니다.

userListQuery,
},
actions: {
setStep,
},
} = useCreateChannel();

return (
<>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,90 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import '@testing-library/jest-dom/matchers';
import InviteUsers from '../index';
import { ApplicationUserListQuery } from '@sendbird/chat';
import { SendbirdSdkContext } from '../../../../../lib/SendbirdSdkContext';
import { SendBirdState } from '../../../../../lib/types';

jest.mock('../../../context/CreateChannelProvider', () => ({
useCreateChannelContext: jest.fn(() => ({
onBeforeCreateChannel: jest.fn(),
onCreateChannel: jest.fn(),
overrideInviteUser: jest.fn(),
createChannel: jest.fn().mockResolvedValue({}),
type: 'group',
import { CHANNEL_TYPE } from '../../../types';
import * as useCreateChannelModule from '../../../context/useCreateChannel';
import { LocalizationContext } from '../../../../../lib/LocalizationContext';

jest.mock('../../../../../hooks/useSendbirdStateContext', () => ({
__esModule: true,
default: jest.fn(() => ({
stores: {
sdkStore: {
sdk: {
currentUser: {
userId: 'test-user-id',
},
},
initialized: true,
},
},
config: { logger: console },
})),
}));
jest.mock('../../../context/useCreateChannel');

// Mock createPortal function to render content directly without portal
jest.mock('react-dom', () => ({
...jest.requireActual('react-dom'),
createPortal: (node) => node,
}));

const mockStringSet = {
MODAL__CREATE_CHANNEL__TITLE: 'CREATE_CHANNEL',
MODAL__INVITE_MEMBER__SELECTED: 'USERS_SELECTED',
BUTTON__CREATE: 'CREATE',
};

const mockLocalizationContext = {
stringSet: mockStringSet,
};

const defaultMockState = {
sdk: undefined,
createChannel: undefined,
userListQuery: undefined,
onCreateChannelClick: undefined,
onChannelCreated: undefined,
onBeforeCreateChannel: undefined,
step: 0,
type: CHANNEL_TYPE.GROUP,
onCreateChannel: undefined,
overrideInviteUser: undefined,
};

const defaultMockActions = {
setStep: jest.fn(),
setType: jest.fn(),
};

const defaultMockInvitUserState = {
user: { userId: 'test-user-id' },
};

describe('InviteUsers', () => {
const mockUseCreateChannel = useCreateChannelModule.default as jest.Mock;

const renderComponent = (mockState = {}, mockActions = {}, mockInviteUsersState = {}) => {
mockUseCreateChannel.mockReturnValue({
state: { ...defaultMockState, ...mockState },
actions: { ...defaultMockActions, ...mockActions },
});

const inviteUserProps = { ...defaultMockInvitUserState, ...mockInviteUsersState };

return render(
<LocalizationContext.Provider value={mockLocalizationContext as any}>
<InviteUsers {...inviteUserProps}/>
</LocalizationContext.Provider>,
);
};

beforeEach(() => {
jest.clearAllMocks();
});

it('should enable the modal submit button when there is only the logged-in user is in the user list', async () => {
const userListQuery = jest.fn(
() => ({
Expand All @@ -32,13 +93,9 @@ describe('InviteUsers', () => {
} as unknown as ApplicationUserListQuery),
);

render(
<SendbirdSdkContext.Provider value={{} as SendBirdState}>
<InviteUsers userListQuery={userListQuery} />
</SendbirdSdkContext.Provider>,
);
renderComponent({}, {}, { userListQuery });

expect(await screen.findByText('Create')).toBeEnabled();
expect(await screen.findByText('CREATE')).toBeEnabled();
});

// TODO: add this case too
Expand Down
20 changes: 11 additions & 9 deletions src/modules/CreateChannel/components/InviteUsers/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import type { GroupChannelCreateParams } from '@sendbird/chat/groupChannel';

import './invite-users.scss';
import { LocalizationContext } from '../../../../lib/LocalizationContext';
import { useCreateChannelContext } from '../../context/CreateChannelProvider';
import useSendbirdStateContext from '../../../../hooks/useSendbirdStateContext';
import { useMediaQueryContext } from '../../../../lib/MediaQueryContext';
import Modal from '../../../../ui/Modal';
Expand All @@ -15,6 +14,7 @@ import UserListItem from '../../../../ui/UserListItem';
import { createDefaultUserListQuery, filterUser, setChannelType } from './utils';
import { noop } from '../../../../utils/utils';
import { UserListQuery } from '../../../../types';
import useCreateChannel from '../../context/useCreateChannel';

export interface InviteUsersProps {
onCancel?: () => void;
Expand All @@ -28,14 +28,16 @@ const InviteUsers: React.FC<InviteUsersProps> = ({
userListQuery,
}: InviteUsersProps) => {
const {
onCreateChannelClick,
onBeforeCreateChannel,
onChannelCreated,
createChannel,
onCreateChannel,
overrideInviteUser,
type,
} = useCreateChannelContext();
state: {
onCreateChannelClick,
onBeforeCreateChannel,
onChannelCreated,
createChannel,
onCreateChannel,
overrideInviteUser,
type,
},
} = useCreateChannel();

const globalStore = useSendbirdStateContext();
const userId = globalStore?.config?.userId;
Expand Down
12 changes: 6 additions & 6 deletions src/modules/CreateChannel/components/SelectChannelType.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import React, { useContext } from 'react';
import * as sendbirdSelectors from '../../../lib/selectors';
import useSendbirdStateContext from '../../../hooks/useSendbirdStateContext';

import { useCreateChannelContext } from '../context/CreateChannelProvider';

import { LocalizationContext } from '../../../lib/LocalizationContext';
import Label, { LabelColors, LabelTypography } from '../../../ui/Label';
import Icon, { IconTypes, IconColors } from '../../../ui/Icon';
Expand All @@ -16,6 +14,7 @@ import {
isSuperGroupChannelEnabled,
} from '../utils';
import { CHANNEL_TYPE } from '../types';
import useCreateChannel from '../context/useCreateChannel';

export interface SelectChannelTypeProps {
onCancel?(): void;
Expand All @@ -27,11 +26,12 @@ const SelectChannelType: React.FC<SelectChannelTypeProps> = (props: SelectChanne

const sdk = sendbirdSelectors.getSdk(store);

const createChannelProps = useCreateChannelContext();
const {
setStep,
setType,
} = createChannelProps;
actions: {
setStep,
setType,
},
} = useCreateChannel();

const { stringSet } = useContext(LocalizationContext);

Expand Down
Loading