text: 'use strict';
  
  const MockPointer = require('./MockPointer');
  
  describe('PIXI.interaction.InteractionManager', function ()
  {
      afterEach(function ()
      {
          // if we made a MockPointer for the test, clean it up
          if (this.pointer)
          {
              this.pointer.cleanUp();
              this.pointer = null;
          }
      });
  
      describe('event basics', function ()
      {
          it('should call mousedown handler', function ()
          {
              const stage = new PIXI.Container();
              const graphics = new PIXI.Graphics();
              const eventSpy = sinon.spy();
              const pointer = this.pointer = new MockPointer(stage);
  
              stage.addChild(graphics);
              graphics.beginFill(0xFFFFFF);
              graphics.drawRect(0, 0, 50, 50);
              graphics.interactive = true;
              graphics.on('mousedown', eventSpy);
  
              pointer.mousedown(10, 10);
  
              expect(eventSpy).to.have.been.calledOnce;
          });
  
          it('should call mouseup handler', function ()
          {
              const stage = new PIXI.Container();
              const graphics = new PIXI.Graphics();
              const eventSpy = sinon.spy();
              const pointer = this.pointer = new MockPointer(stage);
  
              stage.addChild(graphics);
              graphics.beginFill(0xFFFFFF);
              graphics.drawRect(0, 0, 50, 50);
              graphics.interactive = true;
              graphics.on('mouseup', eventSpy);
  
              pointer.click(10, 10);
  
              expect(eventSpy).to.have.been.called;
          });
  
          it('should call mouseupoutside handler', function ()
          {
              const stage = new PIXI.Container();
              const graphics = new PIXI.Graphics();
              const eventSpy = sinon.spy();
              const pointer = this.pointer = new MockPointer(stage);
  
              stage.addChild(graphics);
              graphics.beginFill(0xFFFFFF);
              graphics.drawRect(0, 0, 50, 50);
              graphics.interactive = true;
              graphics.on('mouseupoutside', eventSpy);
  
              pointer.mousedown(10, 10);
              pointer.mouseup(60, 60);
  
              expect(eventSpy).to.have.been.called;
          });
  
          it('should call mouseover handler', function ()
          {
              const stage = new PIXI.Container();
              const graphics = new PIXI.Graphics();
              const eventSpy = sinon.spy();
              const pointer = this.pointer = new MockPointer(stage);
  
              stage.addChild(graphics);
              graphics.beginFill(0xFFFFFF);
              graphics.drawRect(0, 0, 50, 50);
              graphics.interactive = true;
              graphics.on('mouseover', eventSpy);
  
              pointer.mousemove(10, 10);
  
              expect(eventSpy).to.have.been.called;
          });
  
          it('should call mouseout handler', function ()
          {
              const stage = new PIXI.Container();
              const graphics = new PIXI.Graphics();
              const eventSpy = sinon.spy();
              const pointer = this.pointer = new MockPointer(stage);
  
              stage.addChild(graphics);
              graphics.beginFill(0xFFFFFF);
              graphics.drawRect(0, 0, 50, 50);
              graphics.interactive = true;
              graphics.on('mouseout', eventSpy);
  
              pointer.mousemove(10, 10);
              pointer.mousemove(60, 60);
  
              expect(eventSpy).to.have.been.called;
          });
      });
  
      describe('add/remove events', function ()
      {
          let stub;
  
          before(function ()
          {
              stub = sinon.stub(PIXI.interaction.InteractionManager.prototype, 'setTargetElement');
          });
  
          after(function ()
          {
              stub.restore();
          });
  
          it('should add and remove pointer events to document', function ()
          {
              const manager = new PIXI.interaction.InteractionManager(sinon.stub());
              const addSpy = sinon.spy(window.document, 'addEventListener');
              const removeSpy = sinon.spy(window.document, 'removeEventListener');
  
              manager.interactionDOMElement = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
              manager.supportsPointerEvents = true;
  
              manager.addEvents();
  
              expect(addSpy).to.have.been.calledOnce;
              expect(addSpy).to.have.been.calledWith('pointermove');
  
              manager.removeEvents();
  
              expect(removeSpy).to.have.been.calledOnce;
              expect(removeSpy).to.have.been.calledWith('pointermove');
  
              addSpy.restore();
              removeSpy.restore();
          });
  
          it('should add and remove pointer events to window', function ()
          {
              const manager = new PIXI.interaction.InteractionManager(sinon.stub());
              const addSpy = sinon.spy(window, 'addEventListener');
              const removeSpy = sinon.spy(window, 'removeEventListener');
  
              manager.interactionDOMElement = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
              manager.supportsPointerEvents = true;
  
              manager.addEvents();
  
              expect(addSpy).to.have.been.calledTwice;
              expect(addSpy).to.have.been.calledWith('pointercancel');
              expect(addSpy).to.have.been.calledWith('pointerup');
  
              manager.removeEvents();
  
              expect(removeSpy).to.have.been.calledTwice;
              expect(removeSpy).to.have.been.calledWith('pointercancel');
              expect(removeSpy).to.have.been.calledWith('pointerup');
  
              addSpy.restore();
              removeSpy.restore();
          });
  
          it('should add and remove pointer events to element', function ()
          {
              const manager = new PIXI.interaction.InteractionManager(sinon.stub());
              const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
  
              manager.interactionDOMElement = element;
              manager.supportsPointerEvents = true;
  
              manager.addEvents();
  
              expect(element.addEventListener).to.have.been.calledThrice;
              expect(element.addEventListener).to.have.been.calledWith('pointerdown');
              expect(element.addEventListener).to.have.been.calledWith('pointerleave');
              expect(element.addEventListener).to.have.been.calledWith('pointerover');
  
              manager.removeEvents();
  
              expect(element.removeEventListener).to.have.been.calledThrice;
              expect(element.removeEventListener).to.have.been.calledWith('pointerdown');
              expect(element.removeEventListener).to.have.been.calledWith('pointerleave');
              expect(element.removeEventListener).to.have.been.calledWith('pointerover');
          });
  
          it('should add and remove mouse events to document', function ()
          {
              const manager = new PIXI.interaction.InteractionManager(sinon.stub());
              const addSpy = sinon.spy(window.document, 'addEventListener');
              const removeSpy = sinon.spy(window.document, 'removeEventListener');
  
              manager.interactionDOMElement = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
              manager.supportsPointerEvents = false;
  
              manager.addEvents();
  
              expect(addSpy).to.have.been.calledOnce;
              expect(addSpy).to.have.been.calledWith('mousemove');
  
              manager.removeEvents();
  
              expect(removeSpy).to.have.been.calledOnce;
              expect(removeSpy).to.have.been.calledWith('mousemove');
  
              addSpy.restore();
              removeSpy.restore();
          });
  
          it('should add and remove mouse events to window', function ()
          {
              const manager = new PIXI.interaction.InteractionManager(sinon.stub());
              const addSpy = sinon.spy(window, 'addEventListener');
              const removeSpy = sinon.spy(window, 'removeEventListener');
  
              manager.interactionDOMElement = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
              manager.supportsPointerEvents = false;
  
              manager.addEvents();
  
              expect(addSpy).to.have.been.calledOnce;
              expect(addSpy).to.have.been.calledWith('mouseup');
  
              manager.removeEvents();
  
              expect(removeSpy).to.have.been.calledOnce;
              expect(removeSpy).to.have.been.calledWith('mouseup');
  
              addSpy.restore();
              removeSpy.restore();
          });
  
          it('should add and remove mouse events to element', function ()
          {
              const manager = new PIXI.interaction.InteractionManager(sinon.stub());
              const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
  
              manager.interactionDOMElement = element;
              manager.supportsPointerEvents = false;
              manager.supportsTouchEvents = false;
  
              manager.addEvents();
  
              expect(element.addEventListener).to.have.been.calledThrice;
              expect(element.addEventListener).to.have.been.calledWith('mousedown');
              expect(element.addEventListener).to.have.been.calledWith('mouseout');
              expect(element.addEventListener).to.have.been.calledWith('mouseover');
  
              manager.removeEvents();
  
              expect(element.removeEventListener).to.have.been.calledThrice;
              expect(element.removeEventListener).to.have.been.calledWith('mousedown');
              expect(element.removeEventListener).to.have.been.calledWith('mouseout');
              expect(element.removeEventListener).to.have.been.calledWith('mouseover');
          });
  
          it('should add and remove touch events to element', function ()
          {
              const manager = new PIXI.interaction.InteractionManager(sinon.stub());
              const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
  
              manager.interactionDOMElement = element;
              manager.supportsPointerEvents = false;
              manager.supportsTouchEvents = true;
  
              manager.addEvents();
  
              expect(element.addEventListener).to.have.been.calledWith('touchstart');
              expect(element.addEventListener).to.have.been.calledWith('touchcancel');
              expect(element.addEventListener).to.have.been.calledWith('touchend');
              expect(element.addEventListener).to.have.been.calledWith('touchmove');
  
              manager.removeEvents();
  
              expect(element.removeEventListener).to.have.been.calledWith('touchstart');
              expect(element.removeEventListener).to.have.been.calledWith('touchcancel');
              expect(element.removeEventListener).to.have.been.calledWith('touchend');
              expect(element.removeEventListener).to.have.been.calledWith('touchmove');
          });
      });
  
      describe('onClick', function ()
      {
          it('should call handler when inside', function ()
          {
              const stage = new PIXI.Container();
              const graphics = new PIXI.Graphics();
              const clickSpy = sinon.spy();
              const pointer = this.pointer = new MockPointer(stage);
  
              stage.addChild(graphics);
              graphics.beginFill(0xFFFFFF);
              graphics.drawRect(0, 0, 50, 50);
              graphics.interactive = true;
              graphics.on('click', clickSpy);
  
              pointer.click(10, 10);
  
              expect(clickSpy).to.have.been.calledOnce;
          });
  
          it('should not call handler when outside', function ()
          {
              const stage = new PIXI.Container();
              const graphics = new PIXI.Graphics();
              const clickSpy = sinon.spy();
              const pointer = this.pointer = new MockPointer(stage);
  
              stage.addChild(graphics);
              graphics.beginFill(0xFFFFFF);
              graphics.drawRect(0, 0, 50, 50);
              graphics.interactive = true;
              graphics.on('click', clickSpy);
  
              pointer.click(60, 60);
  
              expect(clickSpy).to.not.have.been.called;
          });
  
          it('should not call handler when mousedown not received', function ()
          {
              const stage = new PIXI.Container();
              const graphics = new PIXI.Graphics();
              const clickSpy = sinon.spy();
              const pointer = new MockPointer(stage);
  
              stage.addChild(graphics);
              graphics.beginFill(0xFFFFFF);
              graphics.drawRect(0, 0, 50, 50);
              graphics.interactive = true;
              graphics.on('click', clickSpy);
  
              pointer.mouseup(10, 10);
  
              expect(clickSpy, 'click should not happen on first mouseup').to.not.have.been.called;
  
              // test again, just because it was a bug that was reported
              pointer.mouseup(20, 20);
  
              expect(clickSpy, 'click should not happen on second mouseup').to.not.have.been.called;
          });
      });
  
      describe('onTap', function ()
      {
          it('should call handler when inside', function ()
          {
              const stage = new PIXI.Container();
              const graphics = new PIXI.Graphics();
              const clickSpy = sinon.spy();
              const pointer = this.pointer = new MockPointer(stage);
  
              stage.addChild(graphics);
              graphics.beginFill(0xFFFFFF);
              graphics.drawRect(0, 0, 50, 50);
              graphics.interactive = true;
              graphics.on('tap', clickSpy);
  
              pointer.tap(10, 10);
  
              expect(clickSpy).to.have.been.calledOnce;
          });
  
          it('should not call handler when outside', function ()
          {
              const stage = new PIXI.Container();
              const graphics = new PIXI.Graphics();
              const clickSpy = sinon.spy();
              const pointer = this.pointer = new MockPointer(stage);
  
              stage.addChild(graphics);
              graphics.beginFill(0xFFFFFF);
              graphics.drawRect(0, 0, 50, 50);
              graphics.interactive = true;
              graphics.on('tap', clickSpy);
  
              pointer.tap(60, 60);
  
              expect(clickSpy).to.not.have.been.called;
          });
      });
  
      describe('overlapping children', function ()
      {
          function getScene(callbackEventName)
          {
              const behindChild = new PIXI.Graphics();
              const frontChild = new PIXI.Graphics();
              const parent = new PIXI.Container();
              const behindChildCallback = sinon.spy();
              const frontChildCallback = sinon.spy();
              const parentCallback = sinon.spy();
  
              behindChild.beginFill(0xFF);
              behindChild.drawRect(0, 0, 50, 50);
              behindChild.on(callbackEventName, behindChildCallback);
  
              frontChild.beginFill(0x00FF);
              frontChild.drawRect(0, 0, 50, 50);
              frontChild.on(callbackEventName, frontChildCallback);
  
              parent.addChild(behindChild, frontChild);
              parent.on(callbackEventName, parentCallback);
  
              return {
                  behindChild,
                  frontChild,
                  parent,
                  behindChildCallback,
                  frontChildCallback,
                  parentCallback,
              };
          }
  
          describe('when parent is non-interactive', function ()
          {
              describe('when both children are interactive', function ()
              {
                  it('should callback front child when clicking front child', function ()
                  {
                      const stage = new PIXI.Container();
                      const pointer = this.pointer = new MockPointer(stage);
                      const scene = getScene('click');
  
                      scene.behindChild.interactive = true;
                      scene.behindChild.x = 25;
                      scene.frontChild.interactive = true;
  
                      stage.addChild(scene.parent);
                      pointer.click(10, 10);
  
                      expect(scene.behindChildCallback).to.not.have.been.called;
                      expect(scene.frontChildCallback).to.have.been.calledOnce;
                      expect(scene.parentCallback).to.not.have.been.called;
                  });
  
                  it('should callback front child when clicking overlap', function ()
                  {
                      const stage = new PIXI.Container();
                      const pointer = this.pointer = new MockPointer(stage);
                      const scene = getScene('click');
  
                      scene.behindChild.interactive = true;
                      scene.behindChild.x = 25;
                      scene.frontChild.interactive = true;
  
                      stage.addChild(scene.parent);
                      pointer.click(40, 10);
  
                      expect(scene.behindChildCallback).to.not.have.been.called;
                      expect(scene.frontChildCallback).to.have.been.calledOnce;
                      expect(scene.parentCallback).to.not.have.been.called;
                  });
  
                  it('should callback behind child when clicking behind child', function ()
                  {
                      const stage = new PIXI.Container();
                      const pointer = this.pointer = new MockPointer(stage);
                      const scene = getScene('click');
  
                      scene.behindChild.interactive = true;
                      scene.behindChild.x = 25;
                      scene.frontChild.interactive = true;
  
                      stage.addChild(scene.parent);
                      pointer.click(60, 10);
  
                      expect(scene.frontChildCallback).to.not.have.been.called;
                      expect(scene.behindChildCallback).to.have.been.calledOnce;
                      expect(scene.parentCallback).to.not.have.been.called;
                  });
              });
  
              describe('when front child is non-interactive', function ()
              {
                  it('should not callback when clicking front child', function ()
                  {
                      const stage = new PIXI.Container();
                      const pointer = this.pointer = new MockPointer(stage);
                      const scene = getScene('click');
  
                      scene.behindChild.interactive = true;
                      scene.behindChild.x = 25;
  
                      stage.addChild(scene.parent);
                      pointer.click(10, 10);
  
                      expect(scene.behindChildCallback).to.not.have.been.called;
                      expect(scene.frontChildCallback).to.not.have.been.called;
                      expect(scene.parentCallback).to.not.have.been.called;
                  });
  
                  it('should callback behind child when clicking overlap', function ()
                  {
                      const stage = new PIXI.Container();
                      const pointer = this.pointer = new MockPointer(stage);
                      const scene = getScene('click');
  
                      scene.behindChild.interactive = true;
                      scene.behindChild.x = 25;
  
                      stage.addChild(scene.parent);
                      pointer.click(40, 10);
  
                      expect(scene.behindChildCallback).to.have.been.calledOnce;
                      expect(scene.frontChildCallback).to.not.have.been.called;
                      expect(scene.parentCallback).to.not.have.been.called;
                  });
  
                  it('should callback behind child when clicking behind child', function ()
                  {
                      const stage = new PIXI.Container();
                      const pointer = this.pointer = new MockPointer(stage);
                      const scene = getScene('click');
  
                      scene.behindChild.interactive = true;
                      scene.behindChild.x = 25;
  
                      stage.addChild(scene.parent);
                      pointer.click(60, 10);
  
                      expect(scene.frontChildCallback).to.not.have.been.called;
                      expect(scene.behindChildCallback).to.have.been.calledOnce;
                      expect(scene.parentCallback).to.not.have.been.called;
                  });
              });
  
              describe('when behind child is non-interactive', function ()
              {
                  it('should callback front child when clicking front child', function ()
                  {
                      const stage = new PIXI.Container();
                      const pointer = this.pointer = new MockPointer(stage);
                      const scene = getScene('click');
  
                      scene.behindChild.x = 25;
                      scene.frontChild.interactive = true;
  
                      stage.addChild(scene.parent);
                      pointer.click(10, 10);
  
                      expect(scene.behindChildCallback).to.not.have.been.called;
                      expect(scene.frontChildCallback).to.have.been.calledOnce;
                      expect(scene.parentCallback).to.not.have.been.called;
                  });
  
                  it('should callback front child when clicking overlap', function ()
                  {
                      const stage = new PIXI.Container();
                      const pointer = this.pointer = new MockPointer(stage);
                      const scene = getScene('click');
  
                      scene.behindChild.x = 25;
                      scene.frontChild.interactive = true;
  
                      stage.addChild(scene.parent);
                      pointer.click(40, 10);
  
                      expect(scene.behindChildCallback).to.not.have.been.called;
                      expect(scene.frontChildCallback).to.have.been.calledOnce;
                      expect(scene.parentCallback).to.not.have.been.called;
                  });
  
                  it('should not callback when clicking behind child', function ()
                  {
                      const stage = new PIXI.Container();
                      const pointer = this.pointer = new MockPointer(stage);
                      const scene = getScene('click');
  
                      scene.behindChild.x = 25;
                      scene.frontChild.interactive = true;
  
                      stage.addChild(scene.parent);
                      pointer.click(60, 10);
  
                      expect(scene.frontChildCallback).to.not.have.been.called;
                      expect(scene.behindChildCallback).to.not.have.been.called;
                      expect(scene.parentCallback).to.not.have.been.called;
                  });
              });
          });
  
          describe('when parent is interactive', function ()
          {
              describe('when both children are interactive', function ()
              {
                  it('should callback parent and front child when clicking front child', function ()
                  {
                      const stage = new PIXI.Container();
                      const pointer = this.pointer = new MockPointer(stage);
                      const scene = getScene('click');
  
                      scene.behindChild.interactive = true;
                      scene.behindChild.x = 25;
                      scene.frontChild.interactive = true;
                      scene.parent.interactive = true;
  
                      stage.addChild(scene.parent);
                      pointer.click(10, 10);
  
                      expect(scene.behindChildCallback).to.not.have.been.called;
                      expect(scene.frontChildCallback).to.have.been.calledOnce;
                      expect(scene.parentCallback).to.have.been.calledOnce;
                  });
  
                  it('should callback parent and front child when clicking overlap', function ()
                  {
                      const stage = new PIXI.Container();
                      const pointer = this.pointer = new MockPointer(stage);
                      const scene = getScene('click');
  
                      scene.behindChild.interactive = true;
                      scene.behindChild.x = 25;
                      scene.frontChild.interactive = true;
                      scene.parent.interactive = true;
  
                      stage.addChild(scene.parent);
                      pointer.click(40, 10);
  
                      expect(scene.behindChildCallback).to.not.have.been.called;
                      expect(scene.frontChildCallback).to.have.been.calledOnce;
                      expect(scene.parentCallback).to.have.been.calledOnce;
                  });
  
                  it('should callback parent and behind child when clicking behind child', function ()
                  {
                      const stage = new PIXI.Container();
                      const pointer = this.pointer = new MockPointer(stage);
                      const scene = getScene('click');
  
                      scene.behindChild.interactive = true;
                      scene.behindChild.x = 25;
                      scene.frontChild.interactive = true;
                      scene.parent.interactive = true;
  
                      stage.addChild(scene.parent);
                      pointer.click(60, 10);
  
                      expect(scene.frontChildCallback).to.not.have.been.called;
                      expect(scene.behindChildCallback).to.have.been.calledOnce;
                      expect(scene.parentCallback).to.have.been.calledOnce;
                  });
              });
  
              describe('when front child is non-interactive', function ()
              {
                  it('should callback parent when clicking front child', function ()
                  {
                      const stage = new PIXI.Container();
                      const pointer = this.pointer = new MockPointer(stage);
                      const scene = getScene('click');
  
                      scene.behindChild.interactive = true;
                      scene.behindChild.x = 25;
                      scene.parent.interactive = true;
  
                      stage.addChild(scene.parent);
                      pointer.click(10, 10);
  
                      expect(scene.behindChildCallback).to.not.have.been.called;
                      expect(scene.frontChildCallback).to.not.have.been.called;
                      expect(scene.parentCallback).to.have.been.calledOnce;
                  });
  
                  it('should callback parent and behind child when clicking overlap', function ()
                  {
                      const stage = new PIXI.Container();
                      const pointer = this.pointer = new MockPointer(stage);
                      const scene = getScene('click');
  
                      scene.behindChild.interactive = true;
                      scene.behindChild.x = 25;
                      scene.parent.interactive = true;
  
                      stage.addChild(scene.parent);
                      pointer.click(40, 10);
  
                      expect(scene.behindChildCallback).to.have.been.calledOnce;
                      expect(scene.frontChildCallback).to.not.have.been.called;
                      expect(scene.parentCallback).to.have.been.calledOnce;
                  });
  
                  it('should callback parent and behind child when clicking behind child', function ()
                  {
                      const stage = new PIXI.Container();
                      const pointer = this.pointer = new MockPointer(stage);
                      const scene = getScene('click');
  
                      scene.behindChild.interactive = true;
                      scene.behindChild.x = 25;
                      scene.parent.interactive = true;
  
                      stage.addChild(scene.parent);
                      pointer.click(60, 10);
  
                      expect(scene.frontChildCallback).to.not.have.been.called;
                      expect(scene.behindChildCallback).to.have.been.calledOnce;
                      expect(scene.parentCallback).to.have.been.calledOnce;
                  });
              });
  
              describe('when behind child is non-interactive', function ()
              {
                  it('should callback parent and front child when clicking front child', function ()
                  {
                      const stage = new PIXI.Container();
                      const pointer = this.pointer = new MockPointer(stage);
                      const scene = getScene('click');
  
                      scene.behindChild.x = 25;
                      scene.frontChild.interactive = true;
                      scene.parent.interactive = true;
  
                      stage.addChild(scene.parent);
                      pointer.click(10, 10);
  
                      expect(scene.behindChildCallback).to.not.have.been.called;
                      expect(scene.frontChildCallback).to.have.been.calledOnce;
                      expect(scene.parentCallback).to.have.been.calledOnce;
                  });
  
                  it('should callback parent and front child when clicking overlap', function ()
                  {
                      const stage = new PIXI.Container();
                      const pointer = this.pointer = new MockPointer(stage);
                      const scene = getScene('click');
  
                      scene.behindChild.x = 25;
                      scene.frontChild.interactive = true;
                      scene.parent.interactive = true;
  
                      stage.addChild(scene.parent);
                      pointer.click(40, 10);
  
                      expect(scene.behindChildCallback).to.not.have.been.called;
                      expect(scene.frontChildCallback).to.have.been.calledOnce;
                      expect(scene.parentCallback).to.have.been.calledOnce;
                  });
  
                  it('should callback parent when clicking behind child', function ()
                  {
                      const stage = new PIXI.Container();
                      const pointer = this.pointer = new MockPointer(stage);
                      const scene = getScene('click');
  
                      scene.behindChild.x = 25;
                      scene.frontChild.interactive = true;
                      scene.parent.interactive = true;
  
                      stage.addChild(scene.parent);
                      pointer.click(60, 10);
  
                      expect(scene.frontChildCallback).to.not.have.been.called;
                      expect(scene.behindChildCallback).to.not.have.been.called;
                      expect(scene.parentCallback).to.have.been.calledOnce;
                  });
              });
          });
      });
  
      describe('cursor changes', function ()
      {
          it('cursor should be the cursor of interactive item', function ()
          {
              const stage = new PIXI.Container();
              const graphics = new PIXI.Graphics();
              const pointer = this.pointer = new MockPointer(stage);
  
              stage.addChild(graphics);
              graphics.beginFill(0xFFFFFF);
              graphics.drawRect(0, 0, 50, 50);
              graphics.interactive = true;
              graphics.cursor = 'help';
              pointer.interaction.cursorStyles.help = 'help';
  
              pointer.mousemove(10, 10);
  
              expect(pointer.renderer.view.style.cursor).to.equal('help');
          });
  
          it('should return cursor to default on mouseout', function ()
          {
              const stage = new PIXI.Container();
              const graphics = new PIXI.Graphics();
              const pointer = this.pointer = new MockPointer(stage);
  
              stage.addChild(graphics);
              graphics.beginFill(0xFFFFFF);
              graphics.drawRect(0, 0, 50, 50);
              graphics.interactive = true;
              graphics.cursor = 'help';
              pointer.interaction.cursorStyles.help = 'help';
  
              pointer.mousemove(10, 10);
              pointer.mousemove(60, 60);
  
              expect(pointer.renderer.view.style.cursor).to.equal(pointer.interaction.cursorStyles.default);
          });
  
          it('should still be the over cursor after a click', function ()
          {
              const stage = new PIXI.Container();
              const graphics = new PIXI.Graphics();
              const pointer = this.pointer = new MockPointer(stage);
  
              stage.addChild(graphics);
              graphics.beginFill(0xFFFFFF);
              graphics.drawRect(0, 0, 50, 50);
              graphics.interactive = true;
              graphics.cursor = 'help';
              pointer.interaction.cursorStyles.help = 'help';
  
              pointer.mousemove(10, 10);
              pointer.click(10, 10);
  
              expect(pointer.renderer.view.style.cursor).to.equal('help');
          });
  
          it('should return cursor to default when mouse leaves renderer', function ()
          {
              const stage = new PIXI.Container();
              const graphics = new PIXI.Graphics();
              const pointer = this.pointer = new MockPointer(stage);
  
              stage.addChild(graphics);
              graphics.beginFill(0xFFFFFF);
              graphics.drawRect(0, 0, 50, 50);
              graphics.interactive = true;
              graphics.cursor = 'help';
              pointer.interaction.cursorStyles.help = 'help';
  
              pointer.mousemove(10, 10);
              pointer.mousemove(-10, 60);
  
              expect(pointer.renderer.view.style.cursor).to.equal(pointer.interaction.cursorStyles.default);
          });
  
          it('cursor callback should be called', function ()
          {
              const stage = new PIXI.Container();
              const graphics = new PIXI.Graphics();
              const overSpy = sinon.spy();
              const defaultSpy = sinon.spy();
              const pointer = this.pointer = new MockPointer(stage);
  
              stage.addChild(graphics);
              graphics.beginFill(0xFFFFFF);
              graphics.drawRect(0, 0, 50, 50);
              graphics.interactive = true;
              graphics.cursor = 'help';
              pointer.interaction.cursorStyles.help = overSpy;
              pointer.interaction.cursorStyles.default = defaultSpy;
  
              pointer.mousemove(10, 10);
              pointer.mousemove(60, 60);
  
              expect(overSpy).to.have.been.called;
              expect(defaultSpy).to.have.been.called;
          });
  
          it('cursor callback should only be called if the cursor actually changed', function ()
          {
              const stage = new PIXI.Container();
              const graphics = new PIXI.Graphics();
              const defaultSpy = sinon.spy();
              const pointer = this.pointer = new MockPointer(stage);
  
              stage.addChild(graphics);
              graphics.beginFill(0xFFFFFF);
              graphics.drawRect(0, 0, 50, 50);
              graphics.interactive = true;
              graphics.cursor = null;
              pointer.interaction.cursorStyles.default = defaultSpy;
  
              pointer.mousemove(10, 10);
              pointer.mousemove(20, 20);
  
              expect(defaultSpy).to.have.been.calledOnce;
          });
  
          it('cursor style object should be fully applied', function ()
          {
              const stage = new PIXI.Container();
              const graphics = new PIXI.Graphics();
              const pointer = this.pointer = new MockPointer(stage);
  
              stage.addChild(graphics);
              graphics.beginFill(0xFFFFFF);
              graphics.drawRect(0, 0, 50, 50);
              graphics.interactive = true;
              graphics.cursor = 'help';
              pointer.interaction.cursorStyles.help = {
                  cursor: 'none',
                  display: 'none',
              };
  
              pointer.mousemove(10, 10);
  
              expect(pointer.renderer.view.style.cursor).to.equal('none');
              expect(pointer.renderer.view.style.display).to.equal('none');
          });
  
          it('should not change cursor style if no cursor style provided', function ()
          {
              const stage = new PIXI.Container();
              const graphics = new PIXI.Graphics();
              const pointer = this.pointer = new MockPointer(stage);
  
              stage.addChild(graphics);
              graphics.beginFill(0xFFFFFF);
              graphics.drawRect(0, 0, 50, 50);
              graphics.interactive = true;
              graphics.cursor = 'pointer';
              pointer.interaction.cursorStyles.pointer = null;
              pointer.interaction.cursorStyles.default = null;
  
              pointer.mousemove(10, 10);
              expect(pointer.renderer.view.style.cursor).to.equal('');
  
              pointer.mousemove(60, 60);
              expect(pointer.renderer.view.style.cursor).to.equal('');
          });
      });
  
      describe('recursive hitTesting', function ()
      {
          function getScene()
          {
              const stage = new PIXI.Container();
              const behindChild = new PIXI.Graphics();
              const middleChild = new PIXI.Graphics();
              const frontChild = new PIXI.Graphics();
  
              behindChild.beginFill(0xFF);
              behindChild.drawRect(0, 0, 50, 50);
  
              middleChild.beginFill(0xFF00);
              middleChild.drawRect(0, 0, 50, 50);
  
              frontChild.beginFill(0xFF0000);
              frontChild.drawRect(0, 0, 50, 50);
  
              stage.addChild(behindChild, middleChild, frontChild);
  
              return {
                  behindChild,
                  middleChild,
                  frontChild,
                  stage,
              };
          }
  
          describe('when frontChild is interactive', function ()
          {
              it('should stop hitTesting after first hit', function ()
              {
                  const scene = getScene();
                  const pointer = this.pointer = new MockPointer(scene.stage);
                  const frontHitTest = sinon.spy(scene.frontChild, 'containsPoint');
                  const middleHitTest = sinon.spy(scene.middleChild, 'containsPoint');
                  const behindHitTest = sinon.spy(scene.behindChild, 'containsPoint');
  
                  scene.frontChild.interactive = true;
                  scene.middleChild.interactive = true;
                  scene.behindChild.interactive = true;
  
                  pointer.mousedown(25, 25);
  
                  expect(frontHitTest).to.have.been.calledOnce;
                  expect(middleHitTest).to.not.have.been.called;
                  expect(behindHitTest).to.not.have.been.called;
              });
          });
  
          describe('when frontChild is not interactive', function ()
          {
              it('should stop hitTesting after first hit', function ()
              {
                  const scene = getScene();
                  const pointer = this.pointer = new MockPointer(scene.stage);
                  const frontHitTest = sinon.spy(scene.frontChild, 'containsPoint');
                  const middleHitTest = sinon.spy(scene.middleChild, 'containsPoint');
                  const behindHitTest = sinon.spy(scene.behindChild, 'containsPoint');
  
                  scene.frontChild.interactive = false;
                  scene.middleChild.interactive = true;
                  scene.behindChild.interactive = true;
  
                  pointer.mousedown(25, 25);
  
                  expect(frontHitTest).to.not.have.been.called;
                  expect(middleHitTest).to.have.been.calledOnce;
                  expect(behindHitTest).to.not.have.been.called;
              });
          });
      });
  
      describe('pointer handling', function ()
      {
          it('pointer event from mouse should use single mouse data', function ()
          {
              const stage = new PIXI.Container();
              const graphics = new PIXI.Graphics();
              const pointer = this.pointer = new MockPointer(stage, 100, 100, true);
  
              stage.addChild(graphics);
              graphics.beginFill(0xFFFFFF);
              graphics.drawRect(0, 0, 50, 50);
              graphics.interactive = true;
  
              pointer.mousemove(20, 10, true);
  
              expect(pointer.interaction.mouse.global.x).to.equal(20);
              expect(pointer.interaction.mouse.global.y).to.equal(10);
          });
      });
  });
  