Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions jest-setup.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import './__mocks__/intersectionObserverMock';
import '@testing-library/jest-dom';

const { JSDOM } = require('jsdom');

Expand Down
31 changes: 31 additions & 0 deletions src/lib/Sendbird/__tests__/SendbirdContext.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React, { useContext } from 'react';
import { render } from '@testing-library/react';
import { SendbirdContext, createSendbirdContextStore } from '../context/SendbirdContext';

describe('SendbirdContext', () => {
it('should initialize with null by default', () => {
const TestComponent = () => {
const context = useContext(SendbirdContext);
return <div>{context ? 'Not Null' : 'Null'}</div>;
};

const { getByText } = render(<TestComponent />);
expect(getByText('Null')).toBeInTheDocument();
});

it('should provide a valid context to child components', () => {
const mockStore = createSendbirdContextStore();
const TestComponent = () => {
const context = useContext(SendbirdContext);
return <div>{context ? 'Not Null' : 'Null'}</div>;
};

const { getByText } = render(
<SendbirdContext.Provider value={mockStore}>
<TestComponent />
</SendbirdContext.Provider>,
);

expect(getByText('Not Null')).toBeInTheDocument();
});
});
73 changes: 73 additions & 0 deletions src/lib/Sendbird/__tests__/SendbirdProvider.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React from 'react';
import { render } from '@testing-library/react';
import { SendbirdContextProvider } from '../context/SendbirdProvider';
import useSendbird from '../context/hooks/useSendbird';

const mockState = {
stores: { sdkStore: { initialized: false } },
config: { logger: console, groupChannel: { enableVoiceMessage: false } },
};
const mockActions = { connect: jest.fn(), disconnect: jest.fn() };

jest.mock('../context/hooks/useSendbird', () => ({
__esModule: true,
default: jest.fn(() => ({ state: mockState, actions: mockActions })),
useSendbird: jest.fn(() => ({ state: mockState, actions: mockActions })),
}));

describe('SendbirdProvider', () => {
beforeEach(() => {
// Reset mock functions before each test
jest.clearAllMocks();

// Mock MediaRecorder.isTypeSupported
global.MediaRecorder = {
isTypeSupported: jest.fn((type) => {
const supportedMimeTypes = ['audio/webm', 'audio/wav'];
return supportedMimeTypes.includes(type);
}),
};

// Mock useSendbird return value
useSendbird.mockReturnValue({
state: mockState,
actions: mockActions,
});
});

it('should render child components', () => {
const { getByTestId } = render(
<SendbirdContextProvider appId="mockAppId" userId="mockUserId">
<div data-testid="child">Child Component</div>
</SendbirdContextProvider>,
);

expect(getByTestId('child')).toBeInTheDocument();
});

it('should call connect when mounted', () => {
render(
<SendbirdContextProvider appId="mockAppId" userId="mockUserId">
<div data-testid="child">Child Component</div>
</SendbirdContextProvider>,
);

expect(mockActions.connect).toHaveBeenCalledWith(
expect.objectContaining({
appId: 'mockAppId',
userId: 'mockUserId',
}),
);
});

it('should call disconnect on unmount', () => {
const { unmount } = render(
<SendbirdContextProvider appId="mockAppId" userId="mockUserId">
<div data-testid="child">Child Component</div>
</SendbirdContextProvider>,
);

unmount();
expect(mockActions.disconnect).toHaveBeenCalled();
});
});
90 changes: 90 additions & 0 deletions src/lib/Sendbird/__tests__/index.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import React from 'react';
import { render, screen } from '@testing-library/react';

import { SendbirdProvider, withSendBird } from '../index';

jest.mock('@sendbird/uikit-tools', () => ({
UIKitConfigProvider: jest.fn(({ children }) => <div data-testid="UIKitConfigProvider">{children}</div>),
}));
jest.mock('../context/SendbirdProvider', () => ({
SendbirdContextProvider: jest.fn(({ children }) => <div data-testid="SendbirdContextProvider">{children}</div>),
}));
jest.mock('../context/hooks/useSendbird', () => jest.fn(() => ({
state: { someState: 'testState' },
actions: { someAction: jest.fn() },
})));
jest.mock('../../utils/uikitConfigMapper', () => ({
uikitConfigMapper: jest.fn(() => ({
common: {},
groupChannel: {},
openChannel: {},
})),
}));
jest.mock('../../utils/uikitConfigStorage', () => ({}));

describe('SendbirdProvider/index', () => {
it('renders UIKitConfigProvider with correct localConfigs', () => {
const props = {
replyType: 'threaded',
isMentionEnabled: true,
isReactionEnabled: true,
disableUserProfile: false,
isVoiceMessageEnabled: true,
isTypingIndicatorEnabledOnChannelList: false,
isMessageReceiptStatusEnabledOnChannelList: false,
showSearchIcon: true,
uikitOptions: {},
};

render(<SendbirdProvider {...props} />);

expect(screen.getByTestId('UIKitConfigProvider')).toBeInTheDocument();
expect(screen.getByTestId('SendbirdContextProvider')).toBeInTheDocument();
});
});

describe('withSendbirdContext', () => {
let consoleWarnSpy: jest.SpyInstance;

beforeEach(() => {
consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
});

afterEach(() => {
consoleWarnSpy.mockRestore();
});

it('logs a warning if mapStoreToProps is not a function', () => {
const MockComponent = jest.fn(() => <div data-testid="MockComponent" />);
const invalidMapStoreToProps = 'invalidValue';

const WrappedComponent = withSendBird(MockComponent, invalidMapStoreToProps);

render(<WrappedComponent />);

expect(consoleWarnSpy).toHaveBeenCalledWith(
'Second parameter to withSendbirdContext must be a pure function',
);
});

it('renders OriginalComponent with merged props', () => {
const MockComponent = jest.fn((props) => <div data-testid="MockComponent">{props.testProp}</div>);
const mapStoreToProps = (context: any) => ({
mappedProp: context.someState,
});

const WrappedComponent = withSendBird(MockComponent, mapStoreToProps);

render(<WrappedComponent testProp="additionalValue" />);

expect(screen.getByTestId('MockComponent')).toHaveTextContent('additionalValue');

expect(MockComponent).toHaveBeenCalledWith(
expect.objectContaining({
mappedProp: 'testState',
testProp: 'additionalValue',
}),
{},
);
});
});
47 changes: 47 additions & 0 deletions src/lib/Sendbird/__tests__/initialState.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { initialState } from '../context/initialState';

describe('initialState', () => {
it('should match the expected structure', () => {
expect(initialState).toMatchObject({
config: expect.any(Object),
stores: expect.any(Object),
utils: expect.any(Object),
eventHandlers: expect.any(Object),
});
});

it('should have default values', () => {
expect(initialState.stores.sdkStore).toEqual({
sdk: {},
initialized: false,
loading: false,
error: undefined,
});
expect(initialState.stores.userStore).toEqual({
user: {},
initialized: false,
loading: false,
});
expect(initialState.stores.appInfoStore).toEqual({
messageTemplatesInfo: undefined,
waitingTemplateKeysMap: {},
});
});

it('should have correct config values', () => {
expect(initialState.config.theme).toBe('light');
expect(initialState.config.replyType).toBe('NONE');
expect(initialState.config.uikitUploadSizeLimit).toBeDefined();
expect(initialState.config.uikitMultipleFilesMessageLimit).toBeDefined();
});

it('should have all eventHandlers initialized', () => {
expect(initialState.eventHandlers.reaction.onPressUserProfile).toBeInstanceOf(Function);
expect(initialState.eventHandlers.connection.onConnected).toBeInstanceOf(Function);
expect(initialState.eventHandlers.connection.onFailed).toBeInstanceOf(Function);
expect(initialState.eventHandlers.modal.onMounted).toBeInstanceOf(Function);
expect(initialState.eventHandlers.message.onSendMessageFailed).toBeInstanceOf(Function);
expect(initialState.eventHandlers.message.onUpdateMessageFailed).toBeInstanceOf(Function);
expect(initialState.eventHandlers.message.onFileUploadFailed).toBeInstanceOf(Function);
});
});
Loading