text: /**
   * Copyright (c) 2013-present, Facebook, Inc.
   * All rights reserved.
   *
   * This source code is licensed under the BSD-style license found in the
   * LICENSE file in the root directory of this source tree. An additional grant
   * of patent rights can be found in the PATENTS file in the same directory.
   *
   * @emails oncall+react_native
   */
  
  'use strict';
  
  const Promise = require('promise');
  
  function expectToBeCalledOnce(fn) {
    expect(fn.mock.calls.length).toBe(1);
  }
  
  function clearTaskQueue(taskQueue) {
    do {
      jest.runAllTimers();
      taskQueue.processNext();
      jest.runAllTimers();
    } while (taskQueue.hasTasksToProcess());
  }
  
  describe('TaskQueue', () => {
    let taskQueue;
    let onMoreTasks;
    let sequenceId;
    function createSequenceTask(expectedSequenceId) {
      return jest.fn(() => {
        expect(++sequenceId).toBe(expectedSequenceId);
      });
    }
    beforeEach(() => {
      jest.resetModules();
      onMoreTasks = jest.fn();
      const TaskQueue = require('../TaskQueue');
      taskQueue = new TaskQueue({onMoreTasks});
      sequenceId = 0;
    });
  
  
    it('should run a basic task', () => {
      const task1 = createSequenceTask(1);
      taskQueue.enqueue({run: task1, name: 'run1'});
      expect(taskQueue.hasTasksToProcess()).toBe(true);
      taskQueue.processNext();
      expectToBeCalledOnce(task1);
    });
  
    it('should handle blocking promise task', () => {
      const task1 = jest.fn(() => {
        return new Promise(resolve => {
          setTimeout(() => {
            expect(++sequenceId).toBe(1);
            resolve();
          }, 1);
        });
      });
      const task2 = createSequenceTask(2);
      taskQueue.enqueue({gen: task1, name: 'gen1'});
      taskQueue.enqueue({run: task2, name: 'run2'});
  
      taskQueue.processNext();
  
      expectToBeCalledOnce(task1);
      expect(task2).not.toBeCalled();
      expect(onMoreTasks).not.toBeCalled();
      expect(taskQueue.hasTasksToProcess()).toBe(false);
  
      clearTaskQueue(taskQueue);
  
      expectToBeCalledOnce(onMoreTasks);
      expectToBeCalledOnce(task2);
    });
  
    it('should handle nested simple tasks', () => {
      const task1 = jest.fn(() => {
        expect(++sequenceId).toBe(1);
        taskQueue.enqueue({run: task3, name: 'run3'});
      });
      const task2 = createSequenceTask(2);
      const task3 = createSequenceTask(3);
      taskQueue.enqueue({run: task1, name: 'run1'});
      taskQueue.enqueue({run: task2, name: 'run2'}); // not blocked by task 1
  
      clearTaskQueue(taskQueue);
  
      expectToBeCalledOnce(task1);
      expectToBeCalledOnce(task2);
      expectToBeCalledOnce(task3);
    });
  
    it('should handle nested promises', () => {
      const task1 = jest.fn(() => {
        return new Promise(resolve => {
          setTimeout(() => {
            expect(++sequenceId).toBe(1);
            taskQueue.enqueue({gen: task2, name: 'gen2'});
            taskQueue.enqueue({run: resolve, name: 'resolve1'});
          }, 1);
        });
      });
      const task2 = jest.fn(() => {
        return new Promise(resolve => {
          setTimeout(() => {
            expect(++sequenceId).toBe(2);
            taskQueue.enqueue({run: task3, name: 'run3'});
            taskQueue.enqueue({run: resolve, name: 'resolve2'});
          }, 1);
        });
      });
      const task3 = createSequenceTask(3);
      const task4 = createSequenceTask(4);
      taskQueue.enqueue({gen: task1, name: 'gen1'});
      taskQueue.enqueue({run: task4, name: 'run4'}); // blocked by task 1 promise
  
      clearTaskQueue(taskQueue);
  
      expectToBeCalledOnce(task1);
      expectToBeCalledOnce(task2);
      expectToBeCalledOnce(task3);
      expectToBeCalledOnce(task4);
    });
  
    it('should be able to cancel tasks', () => {
      const task1 = jest.fn();
      const task2 = createSequenceTask(1);
      const task3 = jest.fn();
      const task4 = createSequenceTask(2);
      taskQueue.enqueue(task1);
      taskQueue.enqueue(task2);
      taskQueue.enqueue(task3);
      taskQueue.enqueue(task4);
      taskQueue.cancelTasks([task1, task3]);
      clearTaskQueue(taskQueue);
      expect(task1).not.toBeCalled();
      expect(task3).not.toBeCalled();
      expectToBeCalledOnce(task2);
      expectToBeCalledOnce(task4);
      expect(taskQueue.hasTasksToProcess()).toBe(false);
    });
  
    it('should not crash when last task is cancelled', () => {
      const task1 = jest.fn();
      taskQueue.enqueue(task1);
      taskQueue.cancelTasks([task1]);
      clearTaskQueue(taskQueue);
      expect(task1).not.toBeCalled();
      expect(taskQueue.hasTasksToProcess()).toBe(false);
    });
  });
  