diff --git a/src/components/form/texteditor/TextEditorActions.test.tsx b/src/components/form/texteditor/TextEditorActions.test.tsx new file mode 100644 index 000000000..bbf89bf76 --- /dev/null +++ b/src/components/form/texteditor/TextEditorActions.test.tsx @@ -0,0 +1,79 @@ +import TextEditorActions, { + TextEditorActionProps, +} from 'components/form/texteditor/TextEditorActions'; +import * as React from 'react'; +import { render, fireEvent, fireCustomEvent } from 'test/utils'; + +const baseProps: TextEditorActionProps = { + entry: { value: '' }, + maxLength: 100, + onAddEmoji: vi.fn(), + onFormat: vi.fn(), +}; + +describe(TextEditorActions.name, () => { + it('renders', () => { + const { baseElement } = render(); + expect(baseElement).toMatchSnapshot(); + }); + + it('should toggle emoji picker', () => { + const { baseElement, getByTestId } = render( + , + ); + + const emojiButton = getByTestId('emoji-button'); + expect(baseElement).toMatchSnapshot(); + fireEvent.click(emojiButton); + expect(baseElement).toMatchSnapshot(); + }); + + it('should emit add emoji', () => { + const { getByTestId } = render(); + + const emojiButton = getByTestId('emoji-button'); + fireEvent.click(emojiButton); + + expect(baseProps.onAddEmoji).not.toHaveBeenCalled(); + const emojiPicker = getByTestId('emoji-picker'); + + fireCustomEvent(emojiPicker, 'emoji-selected', { emoji: '👍' }); + expect(baseProps.onAddEmoji).toHaveBeenCalled(); + }); + + it('should close emoji picker on click outside', () => { + const { baseElement, getByTestId } = render( + , + ); + + const emojiButton = getByTestId('emoji-button'); + fireEvent.click(emojiButton); + expect(baseElement).toMatchSnapshot(); + + const emojiPicker = getByTestId('emoji-picker'); + fireCustomEvent(emojiPicker, 'click-outside', true); + expect(baseElement).toMatchSnapshot(); + }); + + it('should emit formats', () => { + const { getByTestId } = render(); + + const boldButton = getByTestId('bold-button'); + const italicButton = getByTestId('italic-button'); + const codeButton = getByTestId('code-button'); + const strikeButton = getByTestId('strike-button'); + + expect(baseProps.onFormat).not.toHaveBeenCalled(); + fireEvent.click(boldButton); + expect(baseProps.onFormat).toHaveBeenCalledWith('*'); + + fireEvent.click(italicButton); + expect(baseProps.onFormat).toHaveBeenCalledWith('_'); + + fireEvent.click(codeButton); + expect(baseProps.onFormat).toHaveBeenCalledWith('```'); + + fireEvent.click(strikeButton); + expect(baseProps.onFormat).toHaveBeenCalledWith('~'); + }); +}); diff --git a/src/components/form/texteditor/TextEditorActions.tsx b/src/components/form/texteditor/TextEditorActions.tsx index 5f709125c..ad380577b 100644 --- a/src/components/form/texteditor/TextEditorActions.tsx +++ b/src/components/form/texteditor/TextEditorActions.tsx @@ -10,7 +10,7 @@ import styles from './TextEditorActions.module.scss'; const UnnnicButton = applyVueInReact(Unnnic.unnnicButton); const UnnnicEmojiPicker = applyVueInReact(Unnnic.unnnicEmojiPicker); -export interface TextEditorProps { +export interface TextEditorActionProps { entry: StringEntry; maxLength: number; onAddEmoji: (emoji: any) => void; @@ -22,10 +22,10 @@ export interface TextEditorState { } export default class TextEditorActions extends React.Component< - TextEditorProps, + TextEditorActionProps, TextEditorState > { - constructor(props: TextEditorProps) { + constructor(props: TextEditorActionProps) { super(props); this.state = { @@ -49,6 +49,7 @@ export default class TextEditorActions extends React.Component<
this.addEmoji(e)} onClickOutside={() => this.toggleEmojiPicker()} /> @@ -65,6 +67,7 @@ export default class TextEditorActions extends React.Component<
{ + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('renders', () => { + const { baseElement } = render(); + expect(baseElement).toMatchSnapshot(); + }); + + it('renders with initial value', () => { + const { baseElement } = render( + , + ); + expect(baseElement).toMatchSnapshot(); + }); + + it('renders with autocomplete', () => { + const { baseElement } = render( + , + ); + expect(baseElement).toMatchSnapshot(); + }); + + it('renders with label', () => { + const { baseElement } = render( + , + ); + expect(baseElement).toMatchSnapshot(); + }); + + it('renders with autocomplete and label', () => { + const { baseElement } = render( + , + ); + expect(baseElement).toMatchSnapshot(); + }); + + it('renders with error', () => { + const { baseElement } = render( + , + ); + expect(baseElement).toMatchSnapshot(); + }); + + it('should call onChange with correct value', () => { + const { getByTestId } = render( + , + ); + const input = getByTestId('Message'); + + fireUnnnicTextAreaChangeText(input, 'Hello'); + expect(baseProps.onChange).toHaveBeenCalledWith('Hello', 'Message'); + }); + + it('should not call onChange if undefined', () => { + const { getByTestId } = render( + , + ); + const input = getByTestId('Message'); + + fireUnnnicTextAreaChangeText(input, 'hello'); + expect(baseProps.onChange).not.toHaveBeenCalled(); + }); + + it('should call on change when emoji is added', () => { + const { getByTestId } = render( + , + ); + + const emojiButton = getByTestId('emoji-button'); + fireEvent.click(emojiButton); + + expect(baseProps.onChange).not.toHaveBeenCalled(); + const emojiPicker = getByTestId('emoji-picker'); + + fireCustomEvent(emojiPicker, 'emoji-selected', { emoji: '👍' }); + expect(baseProps.onChange).toHaveBeenCalledTimes(1); + }); + + it('should emit on change formatted value', () => { + const { getByTestId, rerender } = render( + , + ); + + const input = getByTestId('Message'); + fireUnnnicTextAreaChangeText(input, 'Hello'); + expect(baseProps.onChange).toHaveBeenCalledWith('Hello', 'Message'); + + rerender( + , + ); + + const boldButton = getByTestId('bold-button'); + fireEvent.click(boldButton); + expect(baseProps.onChange).toHaveBeenCalledWith('Hello**', 'Message'); + + const italicButton = getByTestId('italic-button'); + fireEvent.click(italicButton); + expect(baseProps.onChange).toHaveBeenCalledWith('Hello__', 'Message'); + + const codeButton = getByTestId('code-button'); + fireEvent.click(codeButton); + expect(baseProps.onChange).toHaveBeenCalledWith('Hello``````', 'Message'); + + const strikeButton = getByTestId('strike-button'); + fireEvent.click(strikeButton); + expect(baseProps.onChange).toHaveBeenCalledWith('Hello~~', 'Message'); + }); + + it('should not emit formats if disabled', () => { + const { getByTestId } = render( + , + ); + + const boldButton = getByTestId('bold-button'); + const italicButton = getByTestId('italic-button'); + const codeButton = getByTestId('code-button'); + const strikeButton = getByTestId('strike-button'); + + expect(baseProps.onChange).not.toHaveBeenCalled(); + fireEvent.click(boldButton); + fireEvent.click(italicButton); + fireEvent.click(codeButton); + fireEvent.click(strikeButton); + expect(baseProps.onChange).not.toHaveBeenCalled(); + }); +}); diff --git a/src/components/form/texteditor/__snapshots__/TextEditorActions.test.tsx.snap b/src/components/form/texteditor/__snapshots__/TextEditorActions.test.tsx.snap new file mode 100644 index 000000000..032b65b50 --- /dev/null +++ b/src/components/form/texteditor/__snapshots__/TextEditorActions.test.tsx.snap @@ -0,0 +1,895 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`TextEditorActions > renders 1`] = ` + +
+
+
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+ + 0 + / + 100 + +
+
+ +`; + +exports[`TextEditorActions > should close emoji picker on click outside 1`] = ` + +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+ + 0 + / + 100 + +
+
+ +`; + +exports[`TextEditorActions > should close emoji picker on click outside 2`] = ` + +
+
+
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+ + 0 + / + 100 + +
+
+ +`; + +exports[`TextEditorActions > should toggle emoji picker 1`] = ` + +
+
+
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+ + 0 + / + 100 + +
+
+ +`; + +exports[`TextEditorActions > should toggle emoji picker 2`] = ` + +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+ + 0 + / + 100 + +
+
+ +`; diff --git a/src/components/form/texteditor/__snapshots__/TextEditorElement.test.tsx.snap b/src/components/form/texteditor/__snapshots__/TextEditorElement.test.tsx.snap new file mode 100644 index 000000000..20978103f --- /dev/null +++ b/src/components/form/texteditor/__snapshots__/TextEditorElement.test.tsx.snap @@ -0,0 +1,1210 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`TextEditorElement > renders 1`] = ` + +
+
+
+
+ +