201 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			201 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
| import $ from 'jquery';
 | |
| import { assignIn } from 'lodash';
 | |
| import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
 | |
| 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).not.toBeUndefined();
 | |
|       });
 | |
|     });
 | |
|   });
 | |
| 
 | |
|   describe('DOM Events', () => {
 | |
|     beforeEach(() => {
 | |
|       // This ensures DOM and DOM events are initialized for these specs.
 | |
|       setHTMLFixture('<div></div>');
 | |
| 
 | |
|       interval = createDefaultSmartInterval();
 | |
|     });
 | |
| 
 | |
|     afterEach(() => {
 | |
|       resetHTMLFixture();
 | |
|     });
 | |
| 
 | |
|     it('should pause when page is not visible', () => {
 | |
|       jest.runOnlyPendingTimers();
 | |
| 
 | |
|       return waitForPromises().then(() => {
 | |
|         expect(interval.state.intervalId).not.toBeUndefined();
 | |
| 
 | |
|         // 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).not.toBeUndefined();
 | |
|         expect(
 | |
|           interval.getCurrentInterval() >= DEFAULT_STARTING_INTERVAL &&
 | |
|             interval.getCurrentInterval() <= DEFAULT_MAX_INTERVAL,
 | |
|         ).toBe(true);
 | |
| 
 | |
|         // simulates triggering of visibilitychange event
 | |
|         interval.onVisibilityChange({ target: { visibilityState: 'hidden' } });
 | |
| 
 | |
|         expect(interval.state.intervalId).not.toBeUndefined();
 | |
|         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).not.toBeUndefined();
 | |
| 
 | |
|         // 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).not.toBeUndefined();
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     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).toBe(false);
 | |
|     });
 | |
|   });
 | |
| });
 |