master.spec.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import { act, render, RenderResult } from '@testing-library/react';
  2. import React from 'react';
  3. import { masterSet } from '../actions';
  4. import { DispatchContext, StateContext } from '../context/state';
  5. import { GlobalState, initialState, nullPlayer } from '../reducer';
  6. import { useMaster } from './master';
  7. describe(useMaster.name, () => {
  8. const dispatch = jest.fn();
  9. const TestComponent: React.FC = () => {
  10. useMaster();
  11. return null;
  12. };
  13. const setup = (state: GlobalState, options: Partial<RenderResult> = {}): RenderResult =>
  14. render(
  15. <StateContext.Provider value={state}>
  16. <DispatchContext.Provider value={dispatch}>
  17. <TestComponent />
  18. </DispatchContext.Provider>
  19. </StateContext.Provider>,
  20. options,
  21. );
  22. describe('when there is no master initially', () => {
  23. const stateNoMaster: GlobalState = {
  24. ...initialState,
  25. myClientName: 'my-client-name',
  26. player: {
  27. ...nullPlayer,
  28. master: '',
  29. },
  30. };
  31. it('should take control of master', () => {
  32. expect.assertions(2);
  33. jest.useFakeTimers();
  34. const { unmount } = setup(stateNoMaster);
  35. act(() => {
  36. jest.runOnlyPendingTimers();
  37. });
  38. expect(dispatch).toHaveBeenCalledTimes(1);
  39. expect(dispatch).toHaveBeenCalledWith(masterSet('my-client-name'));
  40. unmount();
  41. jest.useRealTimers();
  42. });
  43. });
  44. describe('when master goes away', () => {
  45. const stateWithMaster: GlobalState = {
  46. ...initialState,
  47. myClientName: 'my-client-name',
  48. clientList: [
  49. { name: 'master-client-a', lastPing: 0 },
  50. { name: 'my-client-name', lastPing: 0 },
  51. { name: 'other-slave-client', lastPing: 0 },
  52. ],
  53. player: {
  54. songId: 123,
  55. playing: true,
  56. currentTime: 17,
  57. seekTime: -1,
  58. master: 'master-client-a',
  59. activeClients: [],
  60. queue: [],
  61. shuffleMode: false,
  62. },
  63. };
  64. const stateMasterWentAway: GlobalState = {
  65. ...stateWithMaster,
  66. clientList: [
  67. { name: 'my-client-name', lastPing: 0 },
  68. { name: 'other-slave-client', lastPing: 0 },
  69. ],
  70. };
  71. it('should take control of master after a delay, and pause the client', () => {
  72. expect.assertions(2);
  73. jest.useFakeTimers();
  74. const { container, unmount } = setup(stateWithMaster);
  75. act(() => {
  76. setup(stateMasterWentAway, { container });
  77. });
  78. expect(dispatch).not.toHaveBeenCalled();
  79. act(() => {
  80. jest.runAllTimers();
  81. });
  82. expect(dispatch).toHaveBeenCalledWith(masterSet());
  83. unmount();
  84. jest.useRealTimers();
  85. });
  86. describe('and a third client takes over control', () => {
  87. const stateMasterWentAwayAnotherTookControl: GlobalState = {
  88. ...stateMasterWentAway,
  89. clientList: [
  90. { name: 'my-client-name', lastPing: 0 },
  91. { name: 'other-slave-client', lastPing: 0 },
  92. ],
  93. player: {
  94. ...stateMasterWentAway.player,
  95. master: 'other-slave-client',
  96. },
  97. };
  98. it('should not take control of master', () => {
  99. expect.assertions(1);
  100. jest.useFakeTimers();
  101. const { container, unmount } = setup(stateWithMaster);
  102. act(() => {
  103. setup(stateMasterWentAway, { container });
  104. });
  105. setImmediate(() => {
  106. act(() => {
  107. setup(stateMasterWentAwayAnotherTookControl, { container });
  108. });
  109. });
  110. act(() => {
  111. jest.runAllTimers();
  112. });
  113. expect(dispatch).not.toHaveBeenCalled();
  114. unmount();
  115. jest.useRealTimers();
  116. });
  117. });
  118. });
  119. });