Widgets.test.jsx (15444B)
1 import React from "react"; 2 import { mount } from "enzyme"; 3 import { Provider } from "react-redux"; 4 import { INITIAL_STATE, reducers } from "common/Reducers.sys.mjs"; 5 import { combineReducers, createStore } from "redux"; 6 import { 7 Widgets, 8 resetTimerToDefaults, 9 } from "content-src/components/Widgets/Widgets"; 10 import { Lists } from "content-src/components/Widgets/Lists/Lists"; 11 import { actionTypes as at } from "common/Actions.mjs"; 12 import { FocusTimer } from "content-src/components/Widgets/FocusTimer/FocusTimer"; 13 14 const PREF_WIDGETS_LISTS_ENABLED = "widgets.lists.enabled"; 15 const PREF_WIDGETS_SYSTEM_LISTS_ENABLED = "widgets.system.lists.enabled"; 16 const PREF_WIDGETS_TIMER_ENABLED = "widgets.focusTimer.enabled"; 17 const PREF_WIDGETS_SYSTEM_TIMER_ENABLED = "widgets.system.focusTimer.enabled"; 18 19 function WrapWithProvider({ children, state = INITIAL_STATE }) { 20 const store = createStore(combineReducers(reducers), state); 21 return <Provider store={store}>{children}</Provider>; 22 } 23 24 describe("<Widgets>", () => { 25 it("should render and show <Lists> if list prefs are enabled", () => { 26 const state = { 27 ...INITIAL_STATE, 28 Prefs: { 29 ...INITIAL_STATE.Prefs, 30 values: { 31 ...INITIAL_STATE.Prefs.values, 32 [PREF_WIDGETS_LISTS_ENABLED]: true, 33 [PREF_WIDGETS_SYSTEM_LISTS_ENABLED]: true, 34 }, 35 }, 36 }; 37 const wrapper = mount( 38 <WrapWithProvider state={state}> 39 <Widgets /> 40 </WrapWithProvider> 41 ); 42 assert.ok(wrapper.exists()); 43 assert.ok(wrapper.find(".widgets-container").exists()); 44 assert.ok(wrapper.find(Lists).exists()); 45 }); 46 47 it("should render and show <FocusTimer> if timer prefs are enabled", () => { 48 const state = { 49 ...INITIAL_STATE, 50 Prefs: { 51 ...INITIAL_STATE.Prefs, 52 values: { 53 ...INITIAL_STATE.Prefs.values, 54 [PREF_WIDGETS_TIMER_ENABLED]: true, 55 [PREF_WIDGETS_SYSTEM_TIMER_ENABLED]: true, 56 }, 57 }, 58 }; 59 const wrapper = mount( 60 <WrapWithProvider state={state}> 61 <Widgets /> 62 </WrapWithProvider> 63 ); 64 assert.ok(wrapper.exists()); 65 assert.ok(wrapper.find(".widgets-container").exists()); 66 assert.ok(wrapper.find(FocusTimer).exists()); 67 }); 68 69 it("should not render FocusTimer when timer pref is disabled", () => { 70 const state = { 71 ...INITIAL_STATE, 72 Prefs: { 73 ...INITIAL_STATE.Prefs, 74 values: { 75 ...INITIAL_STATE.Prefs.values, 76 [PREF_WIDGETS_TIMER_ENABLED]: false, 77 [PREF_WIDGETS_SYSTEM_TIMER_ENABLED]: true, 78 }, 79 }, 80 }; 81 const wrapper = mount( 82 <WrapWithProvider state={state}> 83 <Widgets /> 84 </WrapWithProvider> 85 ); 86 assert.ok(!wrapper.find(FocusTimer).exists()); 87 }); 88 89 describe("resetTimerToDefaults", () => { 90 it("should dispatch WIDGETS_TIMER_RESET with focus timer defaults", () => { 91 const dispatch = sinon.spy(); 92 const timerType = "focus"; 93 94 resetTimerToDefaults(dispatch, timerType); 95 96 const resetCall = dispatch 97 .getCalls() 98 .find(call => call.args[0]?.type === at.WIDGETS_TIMER_RESET); 99 const setTypeCall = dispatch 100 .getCalls() 101 .find(call => call.args[0]?.type === at.WIDGETS_TIMER_SET_TYPE); 102 103 assert.ok(resetCall, "should dispatch WIDGETS_TIMER_RESET"); 104 assert.ok(setTypeCall, "should dispatch WIDGETS_TIMER_SET_TYPE"); 105 assert.equal( 106 resetCall.args[0].data.duration, 107 1500, 108 "should reset focus to 25 minutes" 109 ); 110 assert.equal(resetCall.args[0].data.initialDuration, 1500); 111 assert.equal(resetCall.args[0].data.timerType, "focus"); 112 assert.equal(setTypeCall.args[0].data.timerType, "focus"); 113 }); 114 115 it("should dispatch WIDGETS_TIMER_RESET with break timer defaults", () => { 116 const dispatch = sinon.spy(); 117 const timerType = "break"; 118 119 resetTimerToDefaults(dispatch, timerType); 120 121 const resetCall = dispatch 122 .getCalls() 123 .find(call => call.args[0]?.type === at.WIDGETS_TIMER_RESET); 124 125 assert.ok(resetCall, "should dispatch WIDGETS_TIMER_RESET"); 126 assert.equal( 127 resetCall.args[0].data.duration, 128 300, 129 "should reset break to 5 minutes" 130 ); 131 assert.equal(resetCall.args[0].data.initialDuration, 300); 132 assert.equal(resetCall.args[0].data.timerType, "break"); 133 }); 134 }); 135 136 describe("handleHideAllWidgets", () => { 137 let wrapper; 138 let state; 139 let store; 140 141 beforeEach(() => { 142 state = { 143 ...INITIAL_STATE, 144 Prefs: { 145 ...INITIAL_STATE.Prefs, 146 values: { 147 ...INITIAL_STATE.Prefs.values, 148 [PREF_WIDGETS_LISTS_ENABLED]: true, 149 [PREF_WIDGETS_SYSTEM_LISTS_ENABLED]: true, 150 [PREF_WIDGETS_TIMER_ENABLED]: true, 151 [PREF_WIDGETS_SYSTEM_TIMER_ENABLED]: true, 152 }, 153 }, 154 }; 155 store = createStore(combineReducers(reducers), state); 156 sinon.spy(store, "dispatch"); 157 wrapper = mount( 158 <Provider store={store}> 159 <Widgets /> 160 </Provider> 161 ); 162 }); 163 164 afterEach(() => { 165 store.dispatch.restore(); 166 }); 167 168 it("should dispatch SetPref actions when hide button is clicked", () => { 169 const hideButton = wrapper.find("#hide-all-widgets-button"); 170 assert.ok(hideButton.exists(), "hide all button should exist"); 171 172 // Get the onClick handler and call it 173 const onClickHandler = hideButton.prop("onClick"); 174 assert.ok(onClickHandler, "onClick handler should exist"); 175 onClickHandler({ preventDefault: () => {} }); 176 177 const allCalls = store.dispatch.getCalls(); 178 const setPrefCalls = allCalls.filter( 179 call => call.args[0]?.type === at.SET_PREF 180 ); 181 182 assert.equal( 183 setPrefCalls.length, 184 2, 185 `should dispatch two SetPref actions, got ${setPrefCalls.length}.` 186 ); 187 188 const listsPrefCall = setPrefCalls.find( 189 call => call.args[0].data?.name === PREF_WIDGETS_LISTS_ENABLED 190 ); 191 const timerPrefCall = setPrefCalls.find( 192 call => call.args[0].data?.name === PREF_WIDGETS_TIMER_ENABLED 193 ); 194 195 assert.ok(listsPrefCall, "should dispatch SetPref for lists"); 196 assert.equal( 197 listsPrefCall.args[0].data.value, 198 false, 199 "should set lists pref to false" 200 ); 201 202 assert.ok(timerPrefCall, "should dispatch SetPref for timer"); 203 assert.equal( 204 timerPrefCall.args[0].data.value, 205 false, 206 "should set timer pref to false" 207 ); 208 }); 209 210 it("should dispatch SetPref actions when Enter key is pressed on hide button", () => { 211 const hideButton = wrapper.find("#hide-all-widgets-button"); 212 213 // Trigger onKeyDown handler directly with Enter key 214 hideButton.prop("onKeyDown")({ key: "Enter", preventDefault: () => {} }); 215 216 const setPrefCalls = store.dispatch 217 .getCalls() 218 .filter(call => call.args[0]?.type === at.SET_PREF); 219 220 assert.equal( 221 setPrefCalls.length, 222 2, 223 "should dispatch two SetPref actions" 224 ); 225 226 const listsPrefCall = setPrefCalls.find( 227 call => call.args[0].data?.name === PREF_WIDGETS_LISTS_ENABLED 228 ); 229 const timerPrefCall = setPrefCalls.find( 230 call => call.args[0].data?.name === PREF_WIDGETS_TIMER_ENABLED 231 ); 232 233 assert.ok(listsPrefCall, "should dispatch SetPref for lists"); 234 assert.equal( 235 listsPrefCall.args[0].data.value, 236 false, 237 "should set lists pref to false" 238 ); 239 240 assert.ok(timerPrefCall, "should dispatch SetPref for timer"); 241 assert.equal( 242 timerPrefCall.args[0].data.value, 243 false, 244 "should set timer pref to false" 245 ); 246 }); 247 248 it("should dispatch SetPref actions when Space key is pressed on hide button", () => { 249 const hideButton = wrapper.find("#hide-all-widgets-button"); 250 251 // Trigger onKeyDown handler directly with Space key 252 hideButton.prop("onKeyDown")({ key: " ", preventDefault: () => {} }); 253 254 const setPrefCalls = store.dispatch 255 .getCalls() 256 .filter(call => call.args[0]?.type === at.SET_PREF); 257 258 assert.equal( 259 setPrefCalls.length, 260 2, 261 "should dispatch two SetPref actions" 262 ); 263 264 const listsPrefCall = setPrefCalls.find( 265 call => call.args[0].data?.name === PREF_WIDGETS_LISTS_ENABLED 266 ); 267 const timerPrefCall = setPrefCalls.find( 268 call => call.args[0].data?.name === PREF_WIDGETS_TIMER_ENABLED 269 ); 270 271 assert.ok(listsPrefCall, "should dispatch SetPref for lists"); 272 assert.equal( 273 listsPrefCall.args[0].data.value, 274 false, 275 "should set lists pref to false" 276 ); 277 278 assert.ok(timerPrefCall, "should dispatch SetPref for timer"); 279 assert.equal( 280 timerPrefCall.args[0].data.value, 281 false, 282 "should set timer pref to false" 283 ); 284 }); 285 286 it("should not dispatch SetPref actions when other keys are pressed", () => { 287 const hideButton = wrapper.find("#hide-all-widgets-button"); 288 289 const testKeys = ["Escape", "Tab", "a", "ArrowDown"]; 290 291 for (const key of testKeys) { 292 store.dispatch.resetHistory(); 293 // Trigger onKeyDown handler directly 294 hideButton.prop("onKeyDown")({ key }); 295 296 const setPrefCalls = store.dispatch 297 .getCalls() 298 .filter(call => call.args[0]?.type === at.SET_PREF); 299 300 assert.equal( 301 setPrefCalls.length, 302 0, 303 `should not dispatch SetPref for key: ${key}` 304 ); 305 } 306 }); 307 }); 308 309 describe("handleToggleMaximize", () => { 310 let wrapper; 311 let state; 312 let store; 313 314 beforeEach(() => { 315 state = { 316 ...INITIAL_STATE, 317 Prefs: { 318 ...INITIAL_STATE.Prefs, 319 values: { 320 ...INITIAL_STATE.Prefs.values, 321 [PREF_WIDGETS_LISTS_ENABLED]: true, 322 [PREF_WIDGETS_SYSTEM_LISTS_ENABLED]: true, 323 "widgets.maximized": false, 324 "widgets.system.maximized": true, 325 }, 326 }, 327 }; 328 store = createStore(combineReducers(reducers), state); 329 sinon.spy(store, "dispatch"); 330 wrapper = mount( 331 <Provider store={store}> 332 <Widgets /> 333 </Provider> 334 ); 335 }); 336 337 afterEach(() => { 338 store.dispatch.restore(); 339 }); 340 341 it("should dispatch SetPref action when toggle button is clicked", () => { 342 const toggleButton = wrapper.find("#toggle-widgets-size-button"); 343 assert.ok(toggleButton.exists(), "toggle button should exist"); 344 345 // Get the onClick handler and call it 346 const onClickHandler = toggleButton.prop("onClick"); 347 assert.ok(onClickHandler, "onClick handler should exist"); 348 onClickHandler({ preventDefault: () => {} }); 349 350 const allCalls = store.dispatch.getCalls(); 351 const setPrefCalls = allCalls.filter( 352 call => call.args[0]?.type === at.SET_PREF 353 ); 354 355 assert.equal( 356 setPrefCalls.length, 357 1, 358 `should dispatch one SetPref action, got ${setPrefCalls.length}.` 359 ); 360 361 const maximizedPrefCall = setPrefCalls.find( 362 call => call.args[0].data?.name === "widgets.maximized" 363 ); 364 365 assert.ok(maximizedPrefCall, "should dispatch SetPref for maximized"); 366 assert.equal( 367 maximizedPrefCall.args[0].data.value, 368 true, 369 "should toggle maximized pref to true" 370 ); 371 }); 372 373 it("should dispatch SetPref action when Enter key is pressed on toggle button", () => { 374 const toggleButton = wrapper.find("#toggle-widgets-size-button"); 375 376 // Trigger onKeyDown handler directly with Enter key 377 toggleButton.prop("onKeyDown")({ 378 key: "Enter", 379 preventDefault: () => {}, 380 }); 381 382 const setPrefCalls = store.dispatch 383 .getCalls() 384 .filter(call => call.args[0]?.type === at.SET_PREF); 385 386 assert.equal( 387 setPrefCalls.length, 388 1, 389 "should dispatch one SetPref action" 390 ); 391 392 const maximizedPrefCall = setPrefCalls.find( 393 call => call.args[0].data?.name === "widgets.maximized" 394 ); 395 396 assert.ok(maximizedPrefCall, "should dispatch SetPref for maximized"); 397 assert.equal( 398 maximizedPrefCall.args[0].data.value, 399 true, 400 "should toggle maximized pref to true" 401 ); 402 }); 403 404 it("should dispatch SetPref action when Space key is pressed on toggle button", () => { 405 const toggleButton = wrapper.find("#toggle-widgets-size-button"); 406 407 // Trigger onKeyDown handler directly with Space key 408 toggleButton.prop("onKeyDown")({ key: " ", preventDefault: () => {} }); 409 410 const setPrefCalls = store.dispatch 411 .getCalls() 412 .filter(call => call.args[0]?.type === at.SET_PREF); 413 414 assert.equal( 415 setPrefCalls.length, 416 1, 417 "should dispatch one SetPref action" 418 ); 419 420 const maximizedPrefCall = setPrefCalls.find( 421 call => call.args[0].data?.name === "widgets.maximized" 422 ); 423 424 assert.ok(maximizedPrefCall, "should dispatch SetPref for maximized"); 425 assert.equal( 426 maximizedPrefCall.args[0].data.value, 427 true, 428 "should toggle maximized pref to true" 429 ); 430 }); 431 432 it("should not dispatch SetPref actions when other keys are pressed", () => { 433 const toggleButton = wrapper.find("#toggle-widgets-size-button"); 434 435 const testKeys = ["Escape", "Tab", "a", "ArrowDown"]; 436 437 for (const key of testKeys) { 438 store.dispatch.resetHistory(); 439 // Trigger onKeyDown handler directly 440 toggleButton.prop("onKeyDown")({ key }); 441 442 const setPrefCalls = store.dispatch 443 .getCalls() 444 .filter(call => call.args[0]?.type === at.SET_PREF); 445 446 assert.equal( 447 setPrefCalls.length, 448 0, 449 `should not dispatch SetPref for key: ${key}` 450 ); 451 } 452 }); 453 454 it("should toggle from maximized to minimized state", () => { 455 // Update state to start with maximized = true 456 const maximizedState = { 457 ...INITIAL_STATE, 458 Prefs: { 459 ...INITIAL_STATE.Prefs, 460 values: { 461 ...INITIAL_STATE.Prefs.values, 462 [PREF_WIDGETS_LISTS_ENABLED]: true, 463 [PREF_WIDGETS_SYSTEM_LISTS_ENABLED]: true, 464 "widgets.maximized": true, 465 "widgets.system.maximized": true, 466 }, 467 }, 468 }; 469 const maximizedStore = createStore( 470 combineReducers(reducers), 471 maximizedState 472 ); 473 sinon.spy(maximizedStore, "dispatch"); 474 const maximizedWrapper = mount( 475 <Provider store={maximizedStore}> 476 <Widgets /> 477 </Provider> 478 ); 479 480 const toggleButton = maximizedWrapper.find("#toggle-widgets-size-button"); 481 toggleButton.prop("onClick")({ preventDefault: () => {} }); 482 483 const setPrefCalls = maximizedStore.dispatch 484 .getCalls() 485 .filter(call => call.args[0]?.type === at.SET_PREF); 486 487 const maximizedPrefCall = setPrefCalls.find( 488 call => call.args[0].data?.name === "widgets.maximized" 489 ); 490 491 assert.ok(maximizedPrefCall, "should dispatch SetPref for maximized"); 492 assert.equal( 493 maximizedPrefCall.args[0].data.value, 494 false, 495 "should toggle maximized pref to false" 496 ); 497 498 maximizedStore.dispatch.restore(); 499 }); 500 }); 501 });