196 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			196 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
import $ from 'jquery';
 | 
						|
import { assignIn } from 'lodash';
 | 
						|
import waitForPromises from 'helpers/wait_for_promises';
 | 
						|
import SmartInterval from '~/smart_interval';
 | 
						|
 | 
						|
let interval;
 | 
						|
 | 
						|
describe('SmartInterval', () => {
 | 
						|
  const DEFAULT_MAX_INTERVAL = 100;
 | 
						|
  const DEFAULT_STARTING_INTERVAL = 5;
 | 
						|
  const DEFAULT_INCREMENT_FACTOR = 2;
 | 
						|
 | 
						|
  function createDefaultSmartInterval(config) {
 | 
						|
    const defaultParams = {
 | 
						|
      callback: () => Promise.resolve(),
 | 
						|
      startingInterval: DEFAULT_STARTING_INTERVAL,
 | 
						|
      maxInterval: DEFAULT_MAX_INTERVAL,
 | 
						|
      incrementByFactorOf: DEFAULT_INCREMENT_FACTOR,
 | 
						|
      lazyStart: false,
 | 
						|
      immediateExecution: false,
 | 
						|
      hiddenInterval: null,
 | 
						|
    };
 | 
						|
 | 
						|
    if (config) {
 | 
						|
      assignIn(defaultParams, config);
 | 
						|
    }
 | 
						|
 | 
						|
    return new SmartInterval(defaultParams);
 | 
						|
  }
 | 
						|
 | 
						|
  afterEach(() => {
 | 
						|
    interval.destroy();
 | 
						|
  });
 | 
						|
 | 
						|
  describe('Increment Interval', () => {
 | 
						|
    it('should increment the interval delay', () => {
 | 
						|
      interval = createDefaultSmartInterval();
 | 
						|
 | 
						|
      jest.runOnlyPendingTimers();
 | 
						|
 | 
						|
      return waitForPromises().then(() => {
 | 
						|
        const intervalConfig = interval.cfg;
 | 
						|
        const iterationCount = 4;
 | 
						|
        const maxIntervalAfterIterations =
 | 
						|
          intervalConfig.startingInterval * intervalConfig.incrementByFactorOf ** iterationCount;
 | 
						|
        const currentInterval = interval.getCurrentInterval();
 | 
						|
 | 
						|
        // Provide some flexibility for performance of testing environment
 | 
						|
        expect(currentInterval).toBeGreaterThan(intervalConfig.startingInterval);
 | 
						|
        expect(currentInterval).toBeLessThanOrEqual(maxIntervalAfterIterations);
 | 
						|
      });
 | 
						|
    });
 | 
						|
 | 
						|
    it('should not increment past maxInterval', () => {
 | 
						|
      interval = createDefaultSmartInterval({ maxInterval: DEFAULT_STARTING_INTERVAL });
 | 
						|
 | 
						|
      jest.runOnlyPendingTimers();
 | 
						|
 | 
						|
      return waitForPromises().then(() => {
 | 
						|
        const currentInterval = interval.getCurrentInterval();
 | 
						|
 | 
						|
        expect(currentInterval).toBe(interval.cfg.maxInterval);
 | 
						|
      });
 | 
						|
    });
 | 
						|
 | 
						|
    it('does not increment while waiting for callback', () => {
 | 
						|
      interval = createDefaultSmartInterval({
 | 
						|
        callback: () => new Promise($.noop),
 | 
						|
      });
 | 
						|
 | 
						|
      jest.runOnlyPendingTimers();
 | 
						|
 | 
						|
      return waitForPromises().then(() => {
 | 
						|
        const oneInterval = interval.cfg.startingInterval * DEFAULT_INCREMENT_FACTOR;
 | 
						|
 | 
						|
        expect(interval.getCurrentInterval()).toEqual(oneInterval);
 | 
						|
      });
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('Public methods', () => {
 | 
						|
    beforeEach(() => {
 | 
						|
      interval = createDefaultSmartInterval();
 | 
						|
    });
 | 
						|
 | 
						|
    it('should cancel an interval', () => {
 | 
						|
      jest.runOnlyPendingTimers();
 | 
						|
 | 
						|
      interval.cancel();
 | 
						|
 | 
						|
      return waitForPromises().then(() => {
 | 
						|
        const { intervalId } = interval.state;
 | 
						|
        const currentInterval = interval.getCurrentInterval();
 | 
						|
        const intervalLowerLimit = interval.cfg.startingInterval;
 | 
						|
 | 
						|
        expect(intervalId).toBeUndefined();
 | 
						|
        expect(currentInterval).toBe(intervalLowerLimit);
 | 
						|
      });
 | 
						|
    });
 | 
						|
 | 
						|
    it('should resume an interval', () => {
 | 
						|
      jest.runOnlyPendingTimers();
 | 
						|
 | 
						|
      interval.cancel();
 | 
						|
 | 
						|
      interval.resume();
 | 
						|
 | 
						|
      return waitForPromises().then(() => {
 | 
						|
        const { intervalId } = interval.state;
 | 
						|
 | 
						|
        expect(intervalId).toBeTruthy();
 | 
						|
      });
 | 
						|
    });
 | 
						|
  });
 | 
						|
 | 
						|
  describe('DOM Events', () => {
 | 
						|
    beforeEach(() => {
 | 
						|
      // This ensures DOM and DOM events are initialized for these specs.
 | 
						|
      setFixtures('<div></div>');
 | 
						|
 | 
						|
      interval = createDefaultSmartInterval();
 | 
						|
    });
 | 
						|
 | 
						|
    it('should pause when page is not visible', () => {
 | 
						|
      jest.runOnlyPendingTimers();
 | 
						|
 | 
						|
      return waitForPromises().then(() => {
 | 
						|
        expect(interval.state.intervalId).toBeTruthy();
 | 
						|
 | 
						|
        // simulates triggering of visibilitychange event
 | 
						|
        interval.onVisibilityChange({ target: { visibilityState: 'hidden' } });
 | 
						|
 | 
						|
        expect(interval.state.intervalId).toBeUndefined();
 | 
						|
      });
 | 
						|
    });
 | 
						|
 | 
						|
    it('should change to the hidden interval when page is not visible', () => {
 | 
						|
      interval.destroy();
 | 
						|
 | 
						|
      const HIDDEN_INTERVAL = 1500;
 | 
						|
      interval = createDefaultSmartInterval({ hiddenInterval: HIDDEN_INTERVAL });
 | 
						|
 | 
						|
      jest.runOnlyPendingTimers();
 | 
						|
 | 
						|
      return waitForPromises().then(() => {
 | 
						|
        expect(interval.state.intervalId).toBeTruthy();
 | 
						|
        expect(
 | 
						|
          interval.getCurrentInterval() >= DEFAULT_STARTING_INTERVAL &&
 | 
						|
            interval.getCurrentInterval() <= DEFAULT_MAX_INTERVAL,
 | 
						|
        ).toBeTruthy();
 | 
						|
 | 
						|
        // simulates triggering of visibilitychange event
 | 
						|
        interval.onVisibilityChange({ target: { visibilityState: 'hidden' } });
 | 
						|
 | 
						|
        expect(interval.state.intervalId).toBeTruthy();
 | 
						|
        expect(interval.getCurrentInterval()).toBe(HIDDEN_INTERVAL);
 | 
						|
      });
 | 
						|
    });
 | 
						|
 | 
						|
    it('should resume when page is becomes visible at the previous interval', () => {
 | 
						|
      jest.runOnlyPendingTimers();
 | 
						|
 | 
						|
      return waitForPromises().then(() => {
 | 
						|
        expect(interval.state.intervalId).toBeTruthy();
 | 
						|
 | 
						|
        // simulates triggering of visibilitychange event
 | 
						|
        interval.onVisibilityChange({ target: { visibilityState: 'hidden' } });
 | 
						|
 | 
						|
        expect(interval.state.intervalId).toBeUndefined();
 | 
						|
 | 
						|
        // simulates triggering of visibilitychange event
 | 
						|
        interval.onVisibilityChange({ target: { visibilityState: 'visible' } });
 | 
						|
 | 
						|
        expect(interval.state.intervalId).toBeTruthy();
 | 
						|
      });
 | 
						|
    });
 | 
						|
 | 
						|
    it('should cancel on page unload', () => {
 | 
						|
      jest.runOnlyPendingTimers();
 | 
						|
 | 
						|
      return waitForPromises().then(() => {
 | 
						|
        $(document).triggerHandler('beforeunload');
 | 
						|
 | 
						|
        expect(interval.state.intervalId).toBeUndefined();
 | 
						|
        expect(interval.getCurrentInterval()).toBe(interval.cfg.startingInterval);
 | 
						|
      });
 | 
						|
    });
 | 
						|
 | 
						|
    it('should execute callback before first interval', () => {
 | 
						|
      interval = createDefaultSmartInterval({ immediateExecution: true });
 | 
						|
 | 
						|
      expect(interval.cfg.immediateExecution).toBeFalsy();
 | 
						|
    });
 | 
						|
  });
 | 
						|
});
 |