@@ -17,90 +17,118 @@ limitations under the License.
1717import React from "react" ;
1818import { render , screen } from "@testing-library/react" ;
1919import userEvent from "@testing-library/user-event" ;
20- import { AllActionStates , FormattingFunctions } from "@matrix-org/matrix-wysiwyg" ;
20+ import { ActionState , ActionTypes , AllActionStates , FormattingFunctions } from "@matrix-org/matrix-wysiwyg" ;
2121
2222import { FormattingButtons } from "../../../../../../src/components/views/rooms/wysiwyg_composer/components/FormattingButtons" ;
2323import * as LinkModal from "../../../../../../src/components/views/rooms/wysiwyg_composer/components/LinkModal" ;
2424
25- describe ( "FormattingButtons" , ( ) => {
26- const wysiwyg = {
27- bold : jest . fn ( ) ,
28- italic : jest . fn ( ) ,
29- underline : jest . fn ( ) ,
30- strikeThrough : jest . fn ( ) ,
31- inlineCode : jest . fn ( ) ,
32- link : jest . fn ( ) ,
33- } as unknown as FormattingFunctions ;
34-
35- const actionStates = {
36- bold : "reversed" ,
37- italic : "reversed" ,
38- underline : "enabled" ,
39- strikeThrough : "enabled" ,
40- inlineCode : "enabled" ,
41- link : "enabled" ,
42- } as AllActionStates ;
25+ const mockWysiwyg = {
26+ bold : jest . fn ( ) ,
27+ italic : jest . fn ( ) ,
28+ underline : jest . fn ( ) ,
29+ strikeThrough : jest . fn ( ) ,
30+ inlineCode : jest . fn ( ) ,
31+ link : jest . fn ( ) ,
32+ orderedList : jest . fn ( ) ,
33+ unorderedList : jest . fn ( ) ,
34+ } as unknown as FormattingFunctions ;
35+
36+ const openLinkModalSpy = jest . spyOn ( LinkModal , "openLinkModal" ) ;
37+
38+ const testCases : Record <
39+ Exclude < ActionTypes , "undo" | "redo" | "clear" > ,
40+ { label : string ; mockFormatFn : jest . Func | jest . SpyInstance }
41+ > = {
42+ bold : { label : "Bold" , mockFormatFn : mockWysiwyg . bold } ,
43+ italic : { label : "Italic" , mockFormatFn : mockWysiwyg . italic } ,
44+ underline : { label : "Underline" , mockFormatFn : mockWysiwyg . underline } ,
45+ strikeThrough : { label : "Strikethrough" , mockFormatFn : mockWysiwyg . strikeThrough } ,
46+ inlineCode : { label : "Code" , mockFormatFn : mockWysiwyg . inlineCode } ,
47+ link : { label : "Link" , mockFormatFn : openLinkModalSpy } ,
48+ orderedList : { label : "Numbered list" , mockFormatFn : mockWysiwyg . orderedList } ,
49+ unorderedList : { label : "Bulleted list" , mockFormatFn : mockWysiwyg . unorderedList } ,
50+ } ;
51+
52+ const createActionStates = ( state : ActionState ) : AllActionStates => {
53+ return Object . fromEntries ( Object . keys ( testCases ) . map ( ( testKey ) => [ testKey , state ] ) ) as AllActionStates ;
54+ } ;
55+
56+ const defaultActionStates = createActionStates ( "enabled" ) ;
57+
58+ const renderComponent = ( props = { } ) => {
59+ return render ( < FormattingButtons composer = { mockWysiwyg } actionStates = { defaultActionStates } { ...props } /> ) ;
60+ } ;
61+
62+ const classes = {
63+ active : "mx_FormattingButtons_active" ,
64+ hover : "mx_FormattingButtons_Button_hover" ,
65+ } ;
4366
67+ describe ( "FormattingButtons" , ( ) => {
4468 afterEach ( ( ) => {
4569 jest . resetAllMocks ( ) ;
4670 } ) ;
4771
48- it ( "Should have the correspond CSS classes" , ( ) => {
49- // When
50- render ( < FormattingButtons composer = { wysiwyg } actionStates = { actionStates } /> ) ;
51-
52- // Then
53- expect ( screen . getByLabelText ( "Bold" ) ) . toHaveClass ( "mx_FormattingButtons_active" ) ;
54- expect ( screen . getByLabelText ( "Italic" ) ) . toHaveClass ( "mx_FormattingButtons_active" ) ;
55- expect ( screen . getByLabelText ( "Underline" ) ) . not . toHaveClass ( "mx_FormattingButtons_active" ) ;
56- expect ( screen . getByLabelText ( "Strikethrough" ) ) . not . toHaveClass ( "mx_FormattingButtons_active" ) ;
57- expect ( screen . getByLabelText ( "Code" ) ) . not . toHaveClass ( "mx_FormattingButtons_active" ) ;
58- expect ( screen . getByLabelText ( "Link" ) ) . not . toHaveClass ( "mx_FormattingButtons_active" ) ;
72+ it ( "Each button should not have active class when enabled" , ( ) => {
73+ renderComponent ( ) ;
74+
75+ Object . values ( testCases ) . forEach ( ( { label } ) => {
76+ expect ( screen . getByLabelText ( label ) ) . not . toHaveClass ( classes . active ) ;
77+ } ) ;
78+ } ) ;
79+
80+ it ( "Each button should have active class when reversed" , ( ) => {
81+ const reversedActionStates = createActionStates ( "reversed" ) ;
82+ renderComponent ( { actionStates : reversedActionStates } ) ;
83+
84+ Object . values ( testCases ) . forEach ( ( testCase ) => {
85+ const { label } = testCase ;
86+ expect ( screen . getByLabelText ( label ) ) . toHaveClass ( classes . active ) ;
87+ } ) ;
5988 } ) ;
6089
61- it ( "Should call wysiwyg function on button click" , ( ) => {
62- // When
63- const spy = jest . spyOn ( LinkModal , "openLinkModal" ) ;
64- render ( < FormattingButtons composer = { wysiwyg } actionStates = { actionStates } /> ) ;
65- screen . getByLabelText ( "Bold" ) . click ( ) ;
66- screen . getByLabelText ( "Italic" ) . click ( ) ;
67- screen . getByLabelText ( "Underline" ) . click ( ) ;
68- screen . getByLabelText ( "Strikethrough" ) . click ( ) ;
69- screen . getByLabelText ( "Code" ) . click ( ) ;
70- screen . getByLabelText ( "Link" ) . click ( ) ;
71-
72- // Then
73- expect ( wysiwyg . bold ) . toHaveBeenCalledTimes ( 1 ) ;
74- expect ( wysiwyg . italic ) . toHaveBeenCalledTimes ( 1 ) ;
75- expect ( wysiwyg . underline ) . toHaveBeenCalledTimes ( 1 ) ;
76- expect ( wysiwyg . strikeThrough ) . toHaveBeenCalledTimes ( 1 ) ;
77- expect ( wysiwyg . inlineCode ) . toHaveBeenCalledTimes ( 1 ) ;
78- expect ( spy ) . toHaveBeenCalledTimes ( 1 ) ;
90+ it ( "Should call wysiwyg function on button click" , async ( ) => {
91+ renderComponent ( ) ;
92+
93+ for ( const testCase of Object . values ( testCases ) ) {
94+ const { label, mockFormatFn } = testCase ;
95+
96+ screen . getByLabelText ( label ) . click ( ) ;
97+ expect ( mockFormatFn ) . toHaveBeenCalledTimes ( 1 ) ;
98+ }
7999 } ) ;
80100
81- it ( "Should display the tooltip on mouse over" , async ( ) => {
82- // When
83- const user = userEvent . setup ( ) ;
84- render ( < FormattingButtons composer = { wysiwyg } actionStates = { actionStates } /> ) ;
85- await user . hover ( screen . getByLabelText ( "Bold" ) ) ;
101+ it ( "Each button should display the tooltip on mouse over" , async ( ) => {
102+ renderComponent ( ) ;
103+
104+ for ( const testCase of Object . values ( testCases ) ) {
105+ const { label } = testCase ;
86106
87- // Then
88- expect ( await screen . findByText ( "Bold" ) ) . toBeTruthy ( ) ;
107+ await userEvent . hover ( screen . getByLabelText ( label ) ) ;
108+ expect ( await screen . findByText ( label ) ) . toBeTruthy ( ) ;
109+ }
89110 } ) ;
90111
91- it ( "Should not have hover style when active" , async ( ) => {
92- // When
93- const user = userEvent . setup ( ) ;
94- render ( < FormattingButtons composer = { wysiwyg } actionStates = { actionStates } /> ) ;
95- await user . hover ( screen . getByLabelText ( "Bold" ) ) ;
112+ it ( "Each button should have hover style when hovered and enabled" , async ( ) => {
113+ renderComponent ( ) ;
114+
115+ for ( const testCase of Object . values ( testCases ) ) {
116+ const { label } = testCase ;
117+
118+ await userEvent . hover ( screen . getByLabelText ( label ) ) ;
119+ expect ( screen . getByLabelText ( label ) ) . toHaveClass ( "mx_FormattingButtons_Button_hover" ) ;
120+ }
121+ } ) ;
96122
97- // Then
98- expect ( screen . getByLabelText ( "Bold" ) ) . not . toHaveClass ( "mx_FormattingButtons_Button_hover" ) ;
123+ it ( "Each button should not have hover style when hovered and reversed" , async ( ) => {
124+ const reversedActionStates = createActionStates ( "reversed" ) ;
125+ renderComponent ( { actionStates : reversedActionStates } ) ;
99126
100- // When
101- await user . hover ( screen . getByLabelText ( "Underline" ) ) ;
127+ for ( const testCase of Object . values ( testCases ) ) {
128+ const { label } = testCase ;
102129
103- // Then
104- expect ( screen . getByLabelText ( "Underline" ) ) . toHaveClass ( "mx_FormattingButtons_Button_hover" ) ;
130+ await userEvent . hover ( screen . getByLabelText ( label ) ) ;
131+ expect ( screen . getByLabelText ( label ) ) . not . toHaveClass ( "mx_FormattingButtons_Button_hover" ) ;
132+ }
105133 } ) ;
106134} ) ;
0 commit comments