Skip to content

Commit

Permalink
Text only mode tests for Composites (#4848)
Browse files Browse the repository at this point in the history
  • Loading branch information
vhuseinova-msft authored Jul 12, 2024
1 parent 8aa3956 commit 825fe8d
Show file tree
Hide file tree
Showing 2 changed files with 177 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,58 +12,62 @@ import '@testing-library/jest-dom';
/* @conditional-compile-remove(rich-text-editor-composite-support) */
import { COMPOSITE_LOCALE_ZH_TW } from '../localization/locales/zh-TW/CompositeLocale';
/* @conditional-compile-remove(rich-text-editor-composite-support) */
import { ChatComposite } from './ChatComposite';
import { ChatComposite, ChatCompositeProps } from './ChatComposite';
/* @conditional-compile-remove(rich-text-editor-composite-support) */
import React from 'react';

/* @conditional-compile-remove(rich-text-editor-composite-support) */
function createMockChatAdapter(): ChatAdapter {
const chatAdapter = {} as ChatAdapter;
chatAdapter.onStateChange = jest.fn();
chatAdapter.offStateChange = jest.fn();
chatAdapter.fetchInitialData = jest.fn();
chatAdapter.loadPreviousChatMessages = jest.fn();
chatAdapter.getState = jest.fn(
(): ChatAdapterState => ({
userId: { kind: 'communicationUser', communicationUserId: 'test' },
displayName: 'test',
thread: {
chatMessages: {},
participants: {},
threadId: 'test',
readReceipts: [],
typingIndicators: [],
latestReadTime: new Date()
},
latestErrors: {},
error: undefined
})
);
return chatAdapter;
}
import { RichTextSendBoxProps } from '@internal/react-components';
/* @conditional-compile-remove(rich-text-editor-composite-support) */
import { RichTextSendBoxWrapper } from '../common/RichTextSendBoxWrapper';
/* @conditional-compile-remove(rich-text-editor-composite-support) */
import { removeImageTags } from './ImageUpload/ImageUploadUtils';

// Mock the richTextSendBoxWrapper component as it's lazy loaded in ChatComposite
/* @conditional-compile-remove(rich-text-editor-composite-support) */
function MockedRichTextSendBoxWrapper(): JSX.Element {
return <div id="richTextSendBoxWrapper">Mocked RichTextSendboxWrapper</div>;
function MockedRichTextSendBoxWrapperComponent(): JSX.Element {
return <div data-testid="rich-text-editor-test">Mocked RichTextSendboxWrapper</div>;
}

/* @conditional-compile-remove(rich-text-editor-composite-support) */
jest.mock('../common/RichTextSendBoxWrapper', () => {
return {
RichTextSendBoxWrapper: MockedRichTextSendBoxWrapper
};
});
jest.mock('../common/RichTextSendBoxWrapper');
/* @conditional-compile-remove(rich-text-editor-composite-support) */
const mockedRichTextSendBoxWrapper = jest.mocked(RichTextSendBoxWrapper);

/* @conditional-compile-remove(rich-text-editor-composite-support) */
describe('ChatComposite', () => {
const createMockChatAdapter = (): ChatAdapter => {
const chatAdapter = {} as ChatAdapter;
chatAdapter.onStateChange = jest.fn();
chatAdapter.offStateChange = jest.fn();
chatAdapter.fetchInitialData = jest.fn();
chatAdapter.loadPreviousChatMessages = jest.fn();
chatAdapter.getState = jest.fn(
(): ChatAdapterState => ({
userId: { kind: 'communicationUser', communicationUserId: 'test' },
displayName: 'test',
thread: {
chatMessages: {},
participants: {},
threadId: 'test',
readReceipts: [],
typingIndicators: [],
latestReadTime: new Date()
},
latestErrors: {}
})
);
return chatAdapter;
};

beforeEach(() => {
jest.restoreAllMocks();
// Register icons used in ChatComposite to avoid warnings
registerIcons({
icons: {
chevrondown: <></>
}
});

mockedRichTextSendBoxWrapper.mockImplementation(MockedRichTextSendBoxWrapperComponent);
});

test('Chat Composite should show RichTextSendBoxWrapper if it is enabled', async () => {
Expand All @@ -81,7 +85,8 @@ describe('ChatComposite', () => {
const mockChatAdapter = createMockChatAdapter();

render(<ChatComposite adapter={mockChatAdapter} {...mockBaseCompositeProps} />);
expect(await screen.findByText(/Mocked RichTextSendboxWrapper/)).toBeVisible();
const mockSendBox = await screen.findByTestId('rich-text-editor-test');
expect(mockSendBox).toBeVisible();
});

test('Chat Composite should not show RichTextSendBoxWrapper if it is not enabled', async () => {
Expand All @@ -99,7 +104,129 @@ describe('ChatComposite', () => {
const mockChatAdapter = createMockChatAdapter();

render(<ChatComposite adapter={mockChatAdapter} {...mockBaseCompositeProps} />);
expect(screen.findByText(/Mocked RichTextSendboxWrapper/)).rejects.toThrow();
expect(screen.queryByTestId('rich-text-editor-test')).toBeNull();
});
});

/* @conditional-compile-remove(rich-text-editor-composite-support) */
describe('ChatComposite - text only mode', () => {
const createMockChatAdapter = (textOnlyChat: boolean): ChatAdapter => {
const chatAdapter = {} as ChatAdapter;
chatAdapter.onStateChange = jest.fn();
chatAdapter.offStateChange = jest.fn();
chatAdapter.fetchInitialData = jest.fn();
chatAdapter.loadPreviousChatMessages = jest.fn();
chatAdapter.getState = jest.fn(
(): ChatAdapterState => ({
//Text only mode is available for Teams meetings only
userId: { kind: 'microsoftTeamsUser', microsoftTeamsUserId: 'test' },
displayName: 'test',
thread: {
chatMessages: {},
participants: {},
threadId: 'test',
readReceipts: [],
typingIndicators: [],
latestReadTime: new Date(),
properties: {
messagingPolicy: { textOnlyChat: textOnlyChat },
createdBy: { kind: 'microsoftTeamsUser', microsoftTeamsUserId: 'test' }
}
},
latestErrors: {}
})
);
return chatAdapter;
};

const mockBaseCompositeProps = (adapter: ChatAdapter, richTextEditor: boolean): ChatCompositeProps => {
return {
adapter: adapter,
fluentTheme: {},
icons: {},
locale: COMPOSITE_LOCALE_ZH_TW,
rtl: true,
onFetchAvatarPersonaData: jest.fn(),
options: {
richTextEditor: richTextEditor,
attachmentOptions: {
uploadOptions: {
handleAttachmentSelection: () => {}
}
}
}
};
};

beforeEach(() => {
jest.restoreAllMocks();
// Register icons used in ChatComposite to avoid warnings
registerIcons({
icons: {
chevrondown: <></>
}
});
mockedRichTextSendBoxWrapper.mockImplementation(MockedRichTextSendBoxWrapperComponent);
});

test('Chat Composite should set onPaste callback when text only mode is on', async () => {
let onPaste: ((event: { content: DocumentFragment }) => void) | undefined = undefined;
expect.assertions(2);
function Wrapper(props: RichTextSendBoxProps): JSX.Element {
onPaste = props.onPaste;
return <MockedRichTextSendBoxWrapperComponent />;
}
mockedRichTextSendBoxWrapper.mockImplementation(Wrapper);
const mockChatAdapter = createMockChatAdapter(true);
render(<ChatComposite {...mockBaseCompositeProps(mockChatAdapter, true)} />);
await screen.findByTestId('rich-text-editor-test');
expect(onPaste).toBeDefined();
if (onPaste !== undefined) {
const onPasteFunction = onPaste as (event: { content: DocumentFragment }) => void;
expect(onPasteFunction).toBe(removeImageTags);
} else {
fail('onPaste is undefined');
}
});

test('Chat Composite with rich text send box should not show attachments button when text only mode is on', async () => {
const mockChatAdapter = createMockChatAdapter(true);
render(<ChatComposite {...mockBaseCompositeProps(mockChatAdapter, true)} />);
expect(screen.queryByTestId('attachment-upload-button')).toBeNull();
});

test('Chat Composite with plain text send box should not show attachments button when text only mode is on', async () => {
const mockChatAdapter = createMockChatAdapter(true);
render(<ChatComposite {...mockBaseCompositeProps(mockChatAdapter, false)} />);
expect(screen.queryByTestId('attachment-upload-button')).toBeNull();
});

test('Chat Composite should set onPaste callback to undefined when text only mode is off', async () => {
let onPaste: ((event: { content: DocumentFragment }) => void) | undefined = undefined;
expect.assertions(1);
function Wrapper(props: RichTextSendBoxProps): JSX.Element {
onPaste = props.onPaste;
return <MockedRichTextSendBoxWrapperComponent />;
}
mockedRichTextSendBoxWrapper.mockImplementation(Wrapper);
const mockChatAdapter = createMockChatAdapter(false);
render(<ChatComposite {...mockBaseCompositeProps(mockChatAdapter, true)} />);
await screen.findByTestId('rich-text-editor-test');
expect(onPaste).toBeUndefined();
});

test('Chat Composite with rich text send box should show attachments button when text only mode is off', async () => {
const mockChatAdapter = createMockChatAdapter(false);
render(<ChatComposite {...mockBaseCompositeProps(mockChatAdapter, true)} />);
const attachmentsButton = await screen.findByTestId('attachment-upload-button');
expect(attachmentsButton).toBeDefined();
});

test('Chat Composite with plain text send box should show attachments button when text only mode is off', async () => {
const mockChatAdapter = createMockChatAdapter(false);
render(<ChatComposite {...mockBaseCompositeProps(mockChatAdapter, false)} />);
const attachmentsButton = await screen.findByTestId('attachment-upload-button');
expect(attachmentsButton).toBeDefined();
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ import { useImageUpload } from './ImageUpload/useImageUpload';
import { removeImageTags } from './ImageUpload/ImageUploadUtils';
/* @conditional-compile-remove(rich-text-editor-image-upload) */
import type { ChatAdapterState } from './adapter/ChatAdapter';
/* @conditional-compile-remove(rich-text-editor-image-upload) */
import { isMicrosoftTeamsUserIdentifier } from '@azure/communication-common';

/**
* @private
Expand Down Expand Up @@ -134,13 +136,20 @@ export const ChatScreen = (props: ChatScreenProps): JSX.Element => {
useImageUpload();
/* @conditional-compile-remove(rich-text-editor-image-upload) */
const [textOnlyChat, setTextOnlyChat] = useState(false);
/* @conditional-compile-remove(rich-text-editor-image-upload) */
const [isACSChat, setIsACSChat] = useState(false);

/* @conditional-compile-remove(rich-text-editor-image-upload) */
useEffect(() => {
const updateChatState = (newState: ChatAdapterState): void => {
setTextOnlyChat(newState.thread.properties?.messagingPolicy?.textOnlyChat === true);
if (newState.thread.properties?.createdBy) {
setIsACSChat(!isMicrosoftTeamsUserIdentifier(newState.thread.properties?.createdBy));
}
};
// set initial state for textOnlyChat and isACSChat
updateChatState(adapter.getState());

adapter.onStateChange(updateChatState);
return () => {
adapter.offStateChange(updateChatState);
Expand Down Expand Up @@ -515,17 +524,6 @@ export const ChatScreen = (props: ChatScreenProps): JSX.Element => {
[/* @conditional-compile-remove(rich-text-editor-image-upload) */ handleInlineImageUploadAction, messageThreadProps]
);

/* @conditional-compile-remove(rich-text-editor-image-upload) */
const onPasteHandler = useCallback(
(event: { content: DocumentFragment }) => {
const threadCreatedBy = adapter.getState().thread?.properties?.createdBy;
if (threadCreatedBy?.kind !== 'microsoftTeamsUser' || textOnlyChat) {
removeImageTags(event);
}
},
[adapter, textOnlyChat]
);

/* @conditional-compile-remove(rich-text-editor-image-upload) */
const onCancelEditMessageHandler = useCallback(() => {
handleInlineImageUploadAction({ type: AttachmentUploadActionType.Clear });
Expand All @@ -542,9 +540,10 @@ export const ChatScreen = (props: ChatScreenProps): JSX.Element => {

/* @conditional-compile-remove(rich-text-editor-composite-support) */
const richTextEditorOptions = useMemo(() => {
const onPasteCallback = isACSChat || textOnlyChat ? removeImageTags : undefined;
return options?.richTextEditor
? {
/* @conditional-compile-remove(rich-text-editor-image-upload) */ onPaste: onPasteHandler,
/* @conditional-compile-remove(rich-text-editor-image-upload) */ onPaste: onPasteCallback,
/* @conditional-compile-remove(rich-text-editor-image-upload) */
onUploadInlineImage: onUploadInlineImage,
/* @conditional-compile-remove(rich-text-editor-image-upload) */
Expand All @@ -561,7 +560,9 @@ export const ChatScreen = (props: ChatScreenProps): JSX.Element => {
/* @conditional-compile-remove(rich-text-editor-image-upload) */
onUploadInlineImage,
/* @conditional-compile-remove(rich-text-editor-image-upload) */
onPasteHandler,
isACSChat,
/* @conditional-compile-remove(rich-text-editor-image-upload) */
textOnlyChat,
options?.richTextEditor
]);

Expand Down

0 comments on commit 825fe8d

Please sign in to comment.