text: 'use strict';
  
  var Plotly = require('@lib/index');
  var mouseEvent = require('../assets/mouse_event');
  
  // Test utilities
  var createGraphDiv = require('../assets/create_graph_div');
  var destroyGraphDiv = require('../assets/destroy_graph_div');
  var failTest = require('../assets/fail_test');
  
  
  // Expected shape of projection-related data
  var cameraStructure = {
      projection: {type: jasmine.any(String)},
      up: {x: jasmine.any(Number), y: jasmine.any(Number), z: jasmine.any(Number)},
      center: {x: jasmine.any(Number), y: jasmine.any(Number), z: jasmine.any(Number)},
      eye: {x: jasmine.any(Number), y: jasmine.any(Number), z: jasmine.any(Number)}
  };
  
  function makePlot(gd, mock) {
      return Plotly.plot(gd, mock.data, mock.layout);
  }
  
  function addEventCallback(graphDiv) {
      var relayoutCallback = jasmine.createSpy('relayoutCallback');
      graphDiv.on('plotly_relayout', relayoutCallback);
      return {graphDiv: graphDiv, relayoutCallback: relayoutCallback};
  }
  
  function verifyInteractionEffects(tuple) {
      // One 'drag': simulating fairly thoroughly as the mouseup event is also needed here
      mouseEvent('mousemove', 400, 200);
      mouseEvent('mousedown', 400, 200);
      mouseEvent('mousemove', 320, 320, {buttons: 1});
      mouseEvent('mouseup', 320, 320);
  
      // Check event emission count
      expect(tuple.relayoutCallback).toHaveBeenCalledTimes(1);
  
      // Check structure of event callback value contents
      expect(tuple.relayoutCallback).toHaveBeenCalledWith(jasmine.objectContaining({'scene.camera': cameraStructure}));
  
      // Check camera contents on the DIV layout
      var divCamera = tuple.graphDiv.layout.scene.camera;
  
      expect(divCamera).toEqual(cameraStructure);
  
      return tuple.graphDiv;
  }
  
  function testEvents(plot) {
      return plot.then(function(graphDiv) {
          var tuple = addEventCallback(graphDiv);
          verifyInteractionEffects(tuple);
      });
  }
  
  describe('gl3d plots', function() {
      var gd;
  
      beforeEach(function() {
          gd = createGraphDiv();
      });
  
      afterEach(function() {
          Plotly.purge(gd);
          destroyGraphDiv();
      });
  
      it('@gl should respond to drag interactions with mock of unset camera', function(done) {
          testEvents(makePlot(gd, require('@mocks/gl3d_scatter3d-connectgaps.json')))
              .catch(failTest)
              .then(done);
      });
  
      it('@gl should respond to drag interactions with mock of partially set camera', function(done) {
          testEvents(makePlot(gd, require('@mocks/gl3d_errorbars_zx.json')))
              .catch(failTest)
              .then(done);
      });
  });
  