| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- import { act, render, RenderResult } from '@testing-library/react';
- import React from 'react';
- import { masterSet, stateSet } from '../actions';
- import { masterStateUpdateTimeout } from '../constants/system';
- import { DispatchContext, StateContext } from '../context/state';
- import { GlobalState, initialState, nullPlayer } from '../reducer';
- import { useMaster } from './master';
- describe(useMaster.name, () => {
- const dispatch = jest.fn();
- const TestComponent: React.FC = () => {
- useMaster();
- return null;
- };
- const setup = (state: GlobalState, options: Partial<RenderResult> = {}): RenderResult =>
- render(
- <StateContext.Provider value={state}>
- <DispatchContext.Provider value={dispatch}>
- <TestComponent />
- </DispatchContext.Provider>
- </StateContext.Provider>,
- options,
- );
- describe('when there is no master initially', () => {
- const stateNoMaster: GlobalState = {
- ...initialState,
- myClientName: 'my-client-name',
- player: {
- ...nullPlayer,
- master: '',
- },
- };
- it('should take control of master', () => {
- expect.assertions(2);
- jest.useFakeTimers();
- const { unmount } = setup(stateNoMaster);
- act(() => {
- jest.runOnlyPendingTimers();
- });
- expect(dispatch).toHaveBeenCalledTimes(1);
- expect(dispatch).toHaveBeenCalledWith(stateSet({ master: 'my-client-name' }));
- unmount();
- jest.useRealTimers();
- });
- });
- describe('when master goes away', () => {
- const stateWithMaster: GlobalState = {
- ...initialState,
- myClientName: 'my-client-name',
- clientList: [
- { name: 'master-client-a', lastPing: 0 },
- { name: 'my-client-name', lastPing: 0 },
- { name: 'other-slave-client', lastPing: 0 },
- ],
- player: {
- songId: 123,
- playing: true,
- currentTime: 17,
- seekTime: -1,
- master: 'master-client-a',
- activeClients: [],
- queue: [],
- },
- };
- const stateMasterWentAway: GlobalState = {
- ...stateWithMaster,
- clientList: [
- { name: 'my-client-name', lastPing: 0 },
- { name: 'other-slave-client', lastPing: 0 },
- ],
- };
- it('should take control of master after a delay, and pause the client', () => {
- expect.assertions(2);
- jest.useFakeTimers();
- const { container, unmount } = setup(stateWithMaster);
- act(() => {
- setup(stateMasterWentAway, { container });
- });
- expect(dispatch).not.toHaveBeenCalled();
- act(() => {
- jest.runAllTimers();
- });
- expect(dispatch).toHaveBeenCalledWith(masterSet());
- unmount();
- jest.useRealTimers();
- });
- describe('and a third client takes over control', () => {
- const stateMasterWentAwayAnotherTookControl: GlobalState = {
- ...stateMasterWentAway,
- clientList: [
- { name: 'my-client-name', lastPing: 0 },
- { name: 'other-slave-client', lastPing: 0 },
- ],
- player: {
- ...stateMasterWentAway.player,
- master: 'other-slave-client',
- },
- };
- it('should not take control of master', () => {
- expect.assertions(1);
- jest.useFakeTimers();
- const { container, unmount } = setup(stateWithMaster);
- act(() => {
- setup(stateMasterWentAway, { container });
- });
- setImmediate(() => {
- act(() => {
- setup(stateMasterWentAwayAnotherTookControl, { container });
- });
- });
- act(() => {
- jest.runAllTimers();
- });
- expect(dispatch).not.toHaveBeenCalled();
- unmount();
- jest.useRealTimers();
- });
- });
- });
- describe('when the client is master', () => {
- const stateMaster: GlobalState = {
- ...initialState,
- myClientName: 'the-master-client',
- clientList: [{ name: 'the-master-client', lastPing: 0 }],
- player: {
- ...nullPlayer,
- master: 'the-master-client',
- },
- };
- it('should continually refresh the server with the current state', () => {
- expect.assertions(6);
- const clock = jest.useFakeTimers();
- const { unmount } = setup(stateMaster);
- act(() => {
- clock.runOnlyPendingTimers();
- });
- dispatch.mockClear();
- act(() => {
- clock.runTimersToTime(masterStateUpdateTimeout - 1);
- });
- expect(dispatch).toHaveBeenCalledTimes(0);
- act(() => {
- clock.runTimersToTime(1);
- });
- expect(dispatch).toHaveBeenCalledTimes(1);
- expect(dispatch).toHaveBeenCalledWith(stateSet());
- dispatch.mockClear();
- expect(dispatch).toHaveBeenCalledTimes(0);
- act(() => {
- clock.runTimersToTime(masterStateUpdateTimeout);
- });
- expect(dispatch).toHaveBeenCalledTimes(1);
- expect(dispatch).toHaveBeenCalledWith(stateSet());
- unmount();
- jest.useRealTimers();
- });
- });
- describe('when the client is a slave', () => {
- const stateSlave: GlobalState = {
- ...initialState,
- myClientName: 'a-slave-client',
- clientList: [
- { name: 'the-master-client', lastPing: 0 },
- { name: 'a-slave-client', lastPing: 0 },
- ],
- player: {
- ...nullPlayer,
- master: 'the-master-client',
- },
- };
- it('should not send state updates periodically', () => {
- expect.assertions(1);
- const clock = jest.useFakeTimers();
- const { unmount } = setup(stateSlave);
- act(() => {
- clock.runTimersToTime(masterStateUpdateTimeout);
- });
- expect(dispatch).not.toHaveBeenCalled();
- unmount();
- jest.useRealTimers();
- });
- });
- });
|