diff --git a/.circleci/config.yml b/.circleci/config.yml index 2630b369840..a9b0d85d804 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -53,7 +53,7 @@ jobs: docker: # need '-browsers' version to test in real (xvfb-wrapped) browsers - image: circleci/node:10.9.0-browsers - parallelism: 2 + parallelism: 3 working_directory: ~/plotly.js steps: - attach_workspace: @@ -74,6 +74,18 @@ jobs: name: Run jasmine tests (batch 3) command: ./.circleci/test.sh jasmine3 + test-jasmine4: + docker: + # need '-browsers' version to test in real (xvfb-wrapped) browsers + - image: circleci/node:10.9.0-browsers + working_directory: ~/plotly.js + steps: + - attach_workspace: + at: ~/ + - run: + name: Run jasmine tests (batch 4) + command: ./.circleci/test.sh jasmine4 + test-image: docker: - image: plotly/testbed:latest @@ -184,6 +196,9 @@ workflows: - test-jasmine3: requires: - build + - test-jasmine4: + requires: + - build - test-image: requires: - build diff --git a/.circleci/test.sh b/.circleci/test.sh index 271ebd1e382..7284ea2c7b1 100755 --- a/.circleci/test.sh +++ b/.circleci/test.sh @@ -6,7 +6,7 @@ set +o pipefail ROOT=$(dirname $0)/.. EXIT_STATE=0 -MAX_AUTO_RETRY=5 +MAX_AUTO_RETRY=1 log () { echo -e "\n$1" @@ -44,8 +44,10 @@ case $1 in jasmine) set_tz + MAX_AUTO_RETRY=10 + SUITE=$(circleci tests glob "$ROOT/test/jasmine/tests/*" | circleci tests split) - npm run test-jasmine -- $SUITE --skip-tags=gl,noCI,flaky --showSkipped || EXIT_STATE=$? + npm run test-jasmine -- $SUITE --skip-tags=dbgl,gl,noCI,flaky --showSkipped || EXIT_STATE=$? exit $EXIT_STATE ;; @@ -53,7 +55,9 @@ case $1 in jasmine2) set_tz - SHARDS=($(node $ROOT/tasks/shard_jasmine_tests.js --limit=5 --tag=gl | circleci tests split)) + MAX_AUTO_RETRY=5 + + SHARDS=($(node $ROOT/tasks/shard_jasmine_tests.js --limit=1 --tag=gl | circleci tests split)) for s in ${SHARDS[@]}; do retry npm run test-jasmine -- "$s" --tags=gl --skip-tags=noCI --showSkipped done @@ -64,6 +68,8 @@ case $1 in jasmine3) set_tz + MAX_AUTO_RETRY=5 + SHARDS=($(node $ROOT/tasks/shard_jasmine_tests.js --limit=1 --tag=flaky | circleci tests split)) for s in ${SHARDS[@]}; do @@ -73,6 +79,19 @@ case $1 in exit $EXIT_STATE ;; + jasmine4) + set_tz + + MAX_AUTO_RETRY=10 + + SHARDS=($(node $ROOT/tasks/shard_jasmine_tests.js --limit=1 --tag=dbgl | circleci tests split)) + for s in ${SHARDS[@]}; do + retry npm run test-jasmine -- "$s" --tags=dbgl --skip-tags=noCI --showSkipped + done + + exit $EXIT_STATE + ;; + image) SUITE=$(find $ROOT/test/image/mocks/ -type f -printf "%f\n" | circleci tests split) npm run test-image -- $SUITE --filter || EXIT_STATE=$? diff --git a/tasks/test_syntax.js b/tasks/test_syntax.js index e3018d5460b..b5a48f932db 100644 --- a/tasks/test_syntax.js +++ b/tasks/test_syntax.js @@ -33,7 +33,7 @@ assertES5(); // check for for focus and exclude jasmine blocks function assertJasmineSuites() { var BLACK_LIST = ['fdescribe', 'fit', 'xdescribe', 'xit']; - var TAGS = ['noCI', 'noCIdep', 'gl', 'flaky']; + var TAGS = ['noCI', 'noCIdep', 'gl', 'dbgl', 'flaky']; var IT_ONLY_TAGS = ['gl', 'flaky']; var logs = []; diff --git a/test/jasmine/tests/gl2d_double_click_test.js b/test/jasmine/tests/gl2d_double_click_test.js index 3881223558d..01120bcc578 100644 --- a/test/jasmine/tests/gl2d_double_click_test.js +++ b/test/jasmine/tests/gl2d_double_click_test.js @@ -19,6 +19,49 @@ Plotly.register([ require('@lib/contourgl') ]); +var gd; +var selectPath = [[98, 193], [108, 193]]; +var selectPath2 = [[118, 193], [128, 193]]; +var lassoPath = [[316, 171], [318, 239], [335, 243], [328, 169]]; +var lassoPath2 = [[98, 193], [108, 193], [108, 500], [98, 500], [98, 193]]; + +function drag(path) { + var len = path.length; + var el = d3.select(gd).select('rect.nsewdrag').node(); + var opts = { element: el }; + + Lib.clearThrottle(); + mouseEvent('mousemove', path[0][0], path[0][1], opts); + mouseEvent('mousedown', path[0][0], path[0][1], opts); + + path.slice(1, len).forEach(function(pt) { + Lib.clearThrottle(); + mouseEvent('mousemove', pt[0], pt[1], opts); + }); + + mouseEvent('mouseup', path[len - 1][0], path[len - 1][1], opts); +} + +function select(path) { + return new Promise(function(resolve, reject) { + gd.once('plotly_selected', resolve); + setTimeout(function() { reject('did not trigger *plotly_selected*'); }, 200); + drag(path); + }); +} + +function assertEventData(actual, expected) { + expect(actual.points.length).toBe(expected.points.length); + + expected.points.forEach(function(e, i) { + var a = actual.points[i]; + if(a) { + expect(a.x).toBe(e.x, 'x'); + expect(a.y).toBe(e.y, 'y'); + } + }); +} + describe('Test gl2d lasso/select:', function() { var mockFancy = require('@mocks/gl2d_14.json'); delete mockFancy.layout.xaxis.autorange; @@ -27,7 +70,7 @@ describe('Test gl2d lasso/select:', function() { mockFancy.layout.yaxis.range = [-0.9248866483012275, 1.3232607344525835]; var mockFast = Lib.extendDeep({}, mockFancy, { - data: [{mode: 'markers'}], + data: [{ mode: 'markers' }], layout: { xaxis: { type: 'linear', @@ -40,170 +83,127 @@ describe('Test gl2d lasso/select:', function() { } }); - var gd; - var selectPath = [[98, 193], [108, 193]]; - var selectPath2 = [[118, 193], [128, 193]]; - var lassoPath = [[316, 171], [318, 239], [335, 243], [328, 169]]; - var lassoPath2 = [[98, 193], [108, 193], [108, 500], [98, 500], [98, 193]]; - afterEach(function() { Plotly.purge(gd); destroyGraphDiv(); }); - function drag(path) { - var len = path.length; - var el = d3.select(gd).select('rect.nsewdrag').node(); - var opts = {element: el}; - - Lib.clearThrottle(); - mouseEvent('mousemove', path[0][0], path[0][1], opts); - mouseEvent('mousedown', path[0][0], path[0][1], opts); - - path.slice(1, len).forEach(function(pt) { - Lib.clearThrottle(); - mouseEvent('mousemove', pt[0], pt[1], opts); - }); - - mouseEvent('mouseup', path[len - 1][0], path[len - 1][1], opts); - } - - function select(path) { - return new Promise(function(resolve, reject) { - gd.once('plotly_selected', resolve); - setTimeout(function() { reject('did not trigger *plotly_selected*');}, 200); - drag(path); - }); - } - - function assertEventData(actual, expected) { - expect(actual.points.length).toBe(expected.points.length); - - expected.points.forEach(function(e, i) { - var a = actual.points[i]; - if(a) { - expect(a.x).toBe(e.x, 'x'); - expect(a.y).toBe(e.y, 'y'); - } - }); - } - - it('@gl should work under fast mode with *select* dragmode', function(done) { + it('@dbgl should work under fast mode with *select* dragmode', function(done) { var _mock = Lib.extendDeep({}, mockFast); _mock.layout.dragmode = 'select'; gd = createGraphDiv(); Plotly.plot(gd, _mock) - .then(delay(20)) - .then(function() { - expect(gd._fullLayout._plots.xy._scene.select2d).not.toBe(undefined, 'scatter2d renderer'); + .then(delay(20)) + .then(function() { + expect(gd._fullLayout._plots.xy._scene.select2d).not.toBe(undefined, 'scatter2d renderer'); - return select(selectPath); - }) - .then(delay(20)) - .then(function(eventData) { - assertEventData(eventData, { - points: [ - {pointNumber: 25, x: 1.425, y: 0.538}, - {pointNumber: 26, x: 1.753, y: 0.5}, - {pointNumber: 27, x: 2.22, y: 0.45} - ] - }); - }) - .catch(failTest) - .then(done); + return select(selectPath); + }) + .then(delay(20)) + .then(function(eventData) { + assertEventData(eventData, { + points: [ + { pointNumber: 25, x: 1.425, y: 0.538 }, + { pointNumber: 26, x: 1.753, y: 0.5 }, + { pointNumber: 27, x: 2.22, y: 0.45 } + ] + }); + }) + .catch(failTest) + .then(done); }); - it('@gl should work under fast mode with *lasso* dragmode', function(done) { + it('@dbgl should work under fast mode with *lasso* dragmode', function(done) { var _mock = Lib.extendDeep({}, mockFast); _mock.layout.dragmode = 'lasso'; gd = createGraphDiv(); Plotly.plot(gd, _mock) - .then(delay(20)) - .then(function() { - return select(lassoPath2); - }) - .then(delay(20)) - .then(function(eventData) { - assertEventData(eventData, { - points: [ - {pointNumber: 25, x: 1.425, y: 0.538}, - {pointNumber: 26, x: 1.753, y: 0.5}, - {pointNumber: 27, x: 2.22, y: 0.45} - ] - }); - }) - .catch(failTest) - .then(done); + .then(delay(20)) + .then(function() { + return select(lassoPath2); + }) + .then(delay(20)) + .then(function(eventData) { + assertEventData(eventData, { + points: [ + { pointNumber: 25, x: 1.425, y: 0.538 }, + { pointNumber: 26, x: 1.753, y: 0.5 }, + { pointNumber: 27, x: 2.22, y: 0.45 } + ] + }); + }) + .catch(failTest) + .then(done); }); - it('@gl should work under fancy mode with *select* dragmode', function(done) { + it('@dbgl should work under fancy mode with *select* dragmode', function(done) { var _mock = Lib.extendDeep({}, mockFancy); _mock.layout.dragmode = 'select'; gd = createGraphDiv(); Plotly.plot(gd, _mock) - .then(delay(20)) - .then(function() { - return select(selectPath2); - }) - .then(delay(20)) - .then(function(eventData) { - assertEventData(eventData, { - points: [{x: 0.004, y: 12.5}] - }); - }) - .catch(failTest) - .then(done); + .then(delay(20)) + .then(function() { + return select(selectPath2); + }) + .then(delay(20)) + .then(function(eventData) { + assertEventData(eventData, { + points: [{ x: 0.004, y: 12.5 }] + }); + }) + .catch(failTest) + .then(done); }); - it('@gl should work under fancy mode with *lasso* dragmode', function(done) { + it('@dbgl should work under fancy mode with *lasso* dragmode', function(done) { var _mock = Lib.extendDeep({}, mockFancy); _mock.layout.dragmode = 'lasso'; gd = createGraphDiv(); Plotly.plot(gd, _mock) - .then(delay(20)) - .then(function() { - return select(lassoPath); - }) - .then(function(eventData) { - assertEventData(eventData, { - points: [{ x: 0.099, y: 2.75 }] - }); - }) - .catch(failTest) - .then(done); + .then(delay(20)) + .then(function() { + return select(lassoPath); + }) + .then(function(eventData) { + assertEventData(eventData, { + points: [{ x: 0.099, y: 2.75 }] + }); + }) + .catch(failTest) + .then(done); }); - it('@gl should work on trace with enabled transforms', function(done) { + it('@dbgl should work on trace with enabled transforms', function(done) { var fig = Lib.extendDeep({}, require('@mocks/gl2d_transforms.json')); fig.layout.dragmode = 'select'; - fig.layout.margin = {t: 0, b: 0, l: 0, r: 0}; + fig.layout.margin = { t: 0, b: 0, l: 0, r: 0 }; fig.layout.height = 500; fig.layout.width = 500; gd = createGraphDiv(); Plotly.plot(gd, fig) - .then(delay(20)) - .then(function() { return select([[100, 100], [250, 250]]); }) - .then(function(eventData) { - assertEventData(eventData, { - points: [ - { x: 3, y: 4 }, - { x: 2, y: 4 } - ] - }); - }) - .catch(failTest) - .then(done); + .then(delay(20)) + .then(function() { return select([[100, 100], [250, 250]]); }) + .then(function(eventData) { + assertEventData(eventData, { + points: [ + { x: 3, y: 4 }, + { x: 2, y: 4 } + ] + }); + }) + .catch(failTest) + .then(done); }); - it('@gl should work on gl text charts', function(done) { + it('@dbgl should work on gl text charts', function(done) { var fig = Lib.extendDeep({}, require('@mocks/gl2d_text_chart_basic.json')); fig.layout.dragmode = 'select'; - fig.layout.margin = {t: 0, b: 0, l: 0, r: 0}; + fig.layout.margin = { t: 0, b: 0, l: 0, r: 0 }; fig.layout.height = 500; fig.layout.width = 500; gd = createGraphDiv(); @@ -217,76 +217,76 @@ describe('Test gl2d lasso/select:', function() { } Plotly.plot(gd, fig) - .then(delay(20)) - .then(function() { - _assertGlTextOpts('base', { - rgba: [ - [68, 68, 68, 255], - [68, 68, 68, 255], - [68, 68, 68, 255] - ] - }); - }) - .then(function() { return select([[100, 100], [250, 250]]); }) - .then(function(eventData) { - assertEventData(eventData, { - points: [{x: 1, y: 2}] - }); - _assertGlTextOpts('after selection', { - rgba: [ - [ - 68, 68, 68, 51, - 68, 68, 68, 51, - 68, 68, 68, 51, - ], - [ - 68, 68, 68, 51, - // this is the selected pt! - 68, 68, 68, 255, - 68, 68, 68, 51 - ], - [ - 68, 68, 68, 51, - 68, 68, 68, 51, - 68, 68, 68, 51 + .then(delay(20)) + .then(function() { + _assertGlTextOpts('base', { + rgba: [ + [68, 68, 68, 255], + [68, 68, 68, 255], + [68, 68, 68, 255] ] - ] - }); - }) - .then(function() { - return Plotly.restyle(gd, 'selected.textfont.color', 'red'); - }) - .then(function() { return select([[100, 100], [250, 250]]); }) - .then(function() { - _assertGlTextOpts('after selection - with set selected.textfont.color', { - rgba: [ - [ - 68, 68, 68, 255, - 68, 68, 68, 255, - 68, 68, 68, 255, - ], - [ - 68, 68, 68, 255, - // this is the selected pt! - 255, 0, 0, 255, - 68, 68, 68, 255 - ], - [ - 68, 68, 68, 255, - 68, 68, 68, 255, - 68, 68, 68, 255 + }); + }) + .then(function() { return select([[100, 100], [250, 250]]); }) + .then(function(eventData) { + assertEventData(eventData, { + points: [{ x: 1, y: 2 }] + }); + _assertGlTextOpts('after selection', { + rgba: [ + [ + 68, 68, 68, 51, + 68, 68, 68, 51, + 68, 68, 68, 51, + ], + [ + 68, 68, 68, 51, + // this is the selected pt! + 68, 68, 68, 255, + 68, 68, 68, 51 + ], + [ + 68, 68, 68, 51, + 68, 68, 68, 51, + 68, 68, 68, 51 + ] ] - ] - }); - }) - .catch(failTest) - .then(done); + }); + }) + .then(function() { + return Plotly.restyle(gd, 'selected.textfont.color', 'red'); + }) + .then(function() { return select([[100, 100], [250, 250]]); }) + .then(function() { + _assertGlTextOpts('after selection - with set selected.textfont.color', { + rgba: [ + [ + 68, 68, 68, 255, + 68, 68, 68, 255, + 68, 68, 68, 255, + ], + [ + 68, 68, 68, 255, + // this is the selected pt! + 255, 0, 0, 255, + 68, 68, 68, 255 + ], + [ + 68, 68, 68, 255, + 68, 68, 68, 255, + 68, 68, 68, 255 + ] + ] + }); + }) + .catch(failTest) + .then(done); }); - it('@gl should work on gl text charts with array textfont.color', function(done) { + it('@dbgl should work on gl text charts with array textfont.color', function(done) { var fig = Lib.extendDeep({}, require('@mocks/gl2d_text_chart_arrays.json')); fig.layout.dragmode = 'select'; - fig.layout.margin = {t: 0, b: 0, l: 0, r: 0}; + fig.layout.margin = { t: 0, b: 0, l: 0, r: 0 }; fig.layout.height = 500; fig.layout.width = 500; gd = createGraphDiv(); @@ -300,70 +300,70 @@ describe('Test gl2d lasso/select:', function() { } Plotly.plot(gd, fig) - .then(delay(20)) - .then(function() { - _assertGlTextOpts('base', { - rgba: [ - [ - 255, 0, 0, 255, - 0, 0, 255, 255, - 0, 128, 0, 255 - ], - [ - 0, 0, 0, 255, - 211, 211, 210, 255, - 237, 97, 0, 255 + .then(delay(20)) + .then(function() { + _assertGlTextOpts('base', { + rgba: [ + [ + 255, 0, 0, 255, + 0, 0, 255, 255, + 0, 128, 0, 255 + ], + [ + 0, 0, 0, 255, + 211, 211, 210, 255, + 237, 97, 0, 255 + ] ] - ] - }); - }) - .then(function() { return select([[100, 10], [250, 100]]); }) - .then(function(eventData) { - assertEventData(eventData, { - points: [{x: 1, y: 2}] - }); - _assertGlTextOpts('after selection', { - rgba: [ - [ - 255, 0, 0, 51, - 0, 0, 255, 51, - 0, 128, 0, 51 - ], - [ - 0, 0, 0, 51, - // this is the selected pt! - 211, 211, 210, 255, - 237, 97, 0, 51 + }); + }) + .then(function() { return select([[100, 10], [250, 100]]); }) + .then(function(eventData) { + assertEventData(eventData, { + points: [{ x: 1, y: 2 }] + }); + _assertGlTextOpts('after selection', { + rgba: [ + [ + 255, 0, 0, 51, + 0, 0, 255, 51, + 0, 128, 0, 51 + ], + [ + 0, 0, 0, 51, + // this is the selected pt! + 211, 211, 210, 255, + 237, 97, 0, 51 + ] ] - ] - }); - }) - .then(function() { - return Plotly.restyle(gd, 'selected.textfont.color', 'red'); - }) - .then(function() { return select([[100, 10], [250, 100]]); }) - .then(function() { - _assertGlTextOpts('after selection - with set selected.textfont.color', { - rgba: [ - [ - 255, 0, 0, 255, - 0, 0, 255, 255, - 0, 128, 0, 255 - ], - [ - 0, 0, 0, 255, - // this is the selected pt! - 255, 0, 0, 255, - 237, 97, 0, 255 + }); + }) + .then(function() { + return Plotly.restyle(gd, 'selected.textfont.color', 'red'); + }) + .then(function() { return select([[100, 10], [250, 100]]); }) + .then(function() { + _assertGlTextOpts('after selection - with set selected.textfont.color', { + rgba: [ + [ + 255, 0, 0, 255, + 0, 0, 255, 255, + 0, 128, 0, 255 + ], + [ + 0, 0, 0, 255, + // this is the selected pt! + 255, 0, 0, 255, + 237, 97, 0, 255 + ] ] - ] - }); - }) - .catch(failTest) - .then(done); + }); + }) + .catch(failTest) + .then(done); }); - it('@gl should work after a width/height relayout', function(done) { + it('@dbgl should work after a width/height relayout', function(done) { gd = createGraphDiv(); var w = 500; @@ -388,122 +388,123 @@ describe('Test gl2d lasso/select:', function() { y: [2, 1, 2] }], { dragmode: 'select', - margin: {t: 0, b: 0, l: 0, r: 0}, + margin: { t: 0, b: 0, l: 0, r: 0 }, width: w, height: h }) - .then(delay(20)) - .then(function() { - expect(readContext()).toBeGreaterThan(1e4, 'base context'); - expect(readFocus()).toBe(0, 'base focus'); - }) - .then(function() { return select([[pad, pad], [w - pad, h - pad]]); }) - .then(function() { - expect(readContext()).toBe(0, 'select context'); - expect(readFocus()).toBeGreaterThan(1e4, 'select focus'); - }) - .then(function() { - return Plotly.update(gd, - {selectedpoints: null}, - {width: w2, height: h2} - ); - }) - .then(function() { - expect(readContext()).toBeGreaterThan(1e4, 'update context'); - expect(readFocus()).toBe(0, 'update focus'); - }) - .then(function() { return select([[pad, pad], [w2 - pad, h2 - pad]]); }) - .then(function() { - // make sure full w2/h2 context canvas is cleared! - // from https://github.com/plotly/plotly.js/issues/2731 - expect(readContext()).toBe(0, 'update+select context'); - expect(readFocus()).toBeGreaterThan(1e4, 'update+select focus'); - }) - .catch(failTest) - .then(done); + .then(delay(20)) + .then(function() { + expect(readContext()).toBeGreaterThan(1e4, 'base context'); + expect(readFocus()).toBe(0, 'base focus'); + }) + .then(function() { return select([[pad, pad], [w - pad, h - pad]]); }) + .then(function() { + expect(readContext()).toBe(0, 'select context'); + expect(readFocus()).toBeGreaterThan(1e4, 'select focus'); + }) + .then(function() { + return Plotly.update(gd, + { selectedpoints: null }, + { width: w2, height: h2 } + ); + }) + .then(function() { + expect(readContext()).toBeGreaterThan(1e4, 'update context'); + expect(readFocus()).toBe(0, 'update focus'); + }) + .then(function() { return select([[pad, pad], [w2 - pad, h2 - pad]]); }) + .then(function() { + // make sure full w2/h2 context canvas is cleared! + // from https://github.com/plotly/plotly.js/issues/2731 + expect(readContext()).toBe(0, 'update+select context'); + expect(readFocus()).toBeGreaterThan(1e4, 'update+select focus'); + }) + .catch(failTest) + .then(done); }); +}); +describe('select+doubleclick+pan scenarios:', function() { function grabScene() { return gd.calcdata[0][0].t._scene; } - describe('select+doubleclick+pan scenarios:', function() { - function init() { - var scene = grabScene(); - spyOn(scene.scatter2d, 'update').and.callThrough(); - spyOn(scene.scatter2d, 'draw').and.callThrough(); - } - - function _assert(msg, exp) { - var scene = grabScene(); - var scatter2d = scene.scatter2d; - - expect((scene.markerOptions || [])[0].opacity) - .toBe(1, 'marker.opacity - ' + msg); - expect((scene.markerSelectedOptions || [])[0].opacity) - .toBe(1, 'selected.marker.opacity - ' + msg); - expect((scene.markerUnselectedOptions || [])[0].opacity) - .toBe(0.2, 'unselected.marker.opacity - ' + msg); - - expect(scene.selectBatch).toEqual(exp.selectBatch); - expect(scene.unselectBatch).toEqual(exp.unselectBatch); - - var updateCalls = scatter2d.update.calls.all(); - var drawCalls = scatter2d.draw.calls.all(); - - expect(updateCalls.length).toBe( - exp.updateArgs.length, - 'scatter2d.update has been called the correct number of times - ' + msg - ); - updateCalls.forEach(function(d, i) { - d.args.forEach(function(arg, j) { - if(Array.isArray(arg) && 'range' in arg[0]) { - // no need to assert range value in detail - expect(exp.updateArgs[i][j]).toBe( - 'range', - 'scatter.update range update - ' + msg - ); - } else { - expect(arg).toEqual( - exp.updateArgs[i][j], - 'scatter.update call' + i + ' arg' + j + ' - ' + msg - ); - } - }); - }); + function init() { + var scene = grabScene(); + spyOn(scene.scatter2d, 'update').and.callThrough(); + spyOn(scene.scatter2d, 'draw').and.callThrough(); + } - expect(drawCalls.length).toBe( - exp.drawArgs.length, - 'scatter2d.draw has been called the correct number of times - ' + msg - ); - drawCalls.forEach(function(d, i) { - d.args.forEach(function(arg, j) { + function _assert(msg, exp) { + var scene = grabScene(); + var scatter2d = scene.scatter2d; + + expect((scene.markerOptions || [])[0].opacity) + .toBe(1, 'marker.opacity - ' + msg); + expect((scene.markerSelectedOptions || [])[0].opacity) + .toBe(1, 'selected.marker.opacity - ' + msg); + expect((scene.markerUnselectedOptions || [])[0].opacity) + .toBe(0.2, 'unselected.marker.opacity - ' + msg); + + expect(scene.selectBatch).toEqual(exp.selectBatch); + expect(scene.unselectBatch).toEqual(exp.unselectBatch); + + var updateCalls = scatter2d.update.calls.all(); + var drawCalls = scatter2d.draw.calls.all(); + + expect(updateCalls.length).toBe( + exp.updateArgs.length, + 'scatter2d.update has been called the correct number of times - ' + msg + ); + updateCalls.forEach(function(d, i) { + d.args.forEach(function(arg, j) { + if(Array.isArray(arg) && 'range' in arg[0]) { + // no need to assert range value in detail + expect(exp.updateArgs[i][j]).toBe( + 'range', + 'scatter.update range update - ' + msg + ); + } else { expect(arg).toEqual( - exp.drawArgs[i][j], - 'scatter.draw call' + i + ' arg' + j + ' - ' + msg + exp.updateArgs[i][j], + 'scatter.update call' + i + ' arg' + j + ' - ' + msg ); - }); + } }); + }); - scene.scatter2d.update.calls.reset(); - scene.scatter2d.draw.calls.reset(); - } + expect(drawCalls.length).toBe( + exp.drawArgs.length, + 'scatter2d.draw has been called the correct number of times - ' + msg + ); + drawCalls.forEach(function(d, i) { + d.args.forEach(function(arg, j) { + expect(arg).toEqual( + exp.drawArgs[i][j], + 'scatter.draw call' + i + ' arg' + j + ' - ' + msg + ); + }); + }); - it('@gl should behave correctly during select -> doubleclick -> pan:', function(done) { - gd = createGraphDiv(); + scene.scatter2d.update.calls.reset(); + scene.scatter2d.draw.calls.reset(); + } - // See https://github.com/plotly/plotly.js/issues/2767 + it('@dbgl should behave correctly during select -> doubleclick -> pan:', function(done) { + gd = createGraphDiv(); - Plotly.newPlot(gd, [{ - type: 'scattergl', - mode: 'markers', - y: [1, 2, 1], - marker: {size: 30} - }], { - dragmode: 'select', - margin: {t: 0, b: 0, l: 0, r: 0}, - width: 500, - height: 500 - }) + // See https://github.com/plotly/plotly.js/issues/2767 + + Plotly.newPlot(gd, [{ + type: 'scattergl', + mode: 'markers', + y: [1, 2, 1], + marker: { size: 30 } + }], { + dragmode: 'select', + margin: { t: 0, b: 0, l: 0, r: 0 }, + width: 500, + height: 500 + }) .then(delay(20)) .then(init) .then(function() { @@ -588,22 +589,22 @@ describe('Test gl2d lasso/select:', function() { }) .catch(failTest) .then(done); - }); + }); - it('@gl should behave correctly when doubleclick before selecting anything', function(done) { - gd = createGraphDiv(); + it('@dbgl should behave correctly when doubleclick before selecting anything', function(done) { + gd = createGraphDiv(); - Plotly.newPlot(gd, [{ - type: 'scattergl', - mode: 'markers', - y: [1, 2, 1], - marker: {size: 30} - }], { - dragmode: 'select', - margin: {t: 0, b: 0, l: 0, r: 0}, - width: 500, - height: 500 - }) + Plotly.newPlot(gd, [{ + type: 'scattergl', + mode: 'markers', + y: [1, 2, 1], + marker: { size: 30 } + }], { + dragmode: 'select', + margin: { t: 0, b: 0, l: 0, r: 0 }, + width: 500, + height: 500 + }) .then(delay(20)) .then(init) .then(function() { return doubleClick(250, 250); }) @@ -624,24 +625,24 @@ describe('Test gl2d lasso/select:', function() { }) .catch(failTest) .then(done); - }); + }); - it('@gl should behave correctly during select -> doubleclick -> dragmode:mode -> dragmode:select', function(done) { - gd = createGraphDiv(); + it('@dbgl should behave correctly during select -> doubleclick -> dragmode:mode -> dragmode:select', function(done) { + gd = createGraphDiv(); - // https://github.com/plotly/plotly.js/issues/2958 + // https://github.com/plotly/plotly.js/issues/2958 - Plotly.newPlot(gd, [{ - type: 'scattergl', - mode: 'markers', - y: [1, 2, 1], - marker: {size: 30} - }], { - dragmode: 'select', - margin: {t: 0, b: 0, l: 0, r: 0}, - width: 500, - height: 500 - }) + Plotly.newPlot(gd, [{ + type: 'scattergl', + mode: 'markers', + y: [1, 2, 1], + marker: { size: 30 } + }], { + dragmode: 'select', + margin: { t: 0, b: 0, l: 0, r: 0 }, + width: 500, + height: 500 + }) .then(delay(20)) .then(init) .then(function() { @@ -676,10 +677,10 @@ describe('Test gl2d lasso/select:', function() { }) .catch(failTest) .then(done); - }); }); - it('@gl should draw parts in correct order during selections', function(done) { + + it('@dbgl should draw parts in correct order during selections', function(done) { gd = createGraphDiv(); // https://github.com/plotly/plotly.js/issues/3740 @@ -706,59 +707,59 @@ describe('Test gl2d lasso/select:', function() { type: 'scattergl', mode: 'markers', y: [1, 2, 1], - marker: {size: 30} + marker: { size: 30 } }, { type: 'scattergl', mode: 'lines', y: [1, 2, 1] }], { dragmode: 'select', - margin: {t: 0, b: 0, l: 0, r: 0}, + margin: { t: 0, b: 0, l: 0, r: 0 }, width: 500, height: 500 }) - .then(delay(20)) - .then(function() { - var scene = grabScene(); - spyOn(scene.scatter2d, 'draw').and.callFake(function() { - tracker.push(['scatter2d', arguments]); - }); - spyOn(scene.line2d, 'draw').and.callFake(function() { - tracker.push(['line2d', arguments]); - }); - spyOn(scene.select2d, 'draw').and.callFake(function() { - tracker.push(['select2d', arguments]); - }); - }) - .then(function() { return Plotly.relayout(gd, 'xaxis.range', [0, 4]); }) - .then(function() { - _assert('base', [ - ['scatter2d', [0]], - ['line2d', [1]], - ['select2d', [[[], []]]] - ]); - }) - .then(function() { return select([[20, 20], [480, 250]]); }) - .then(function() { - _assert('on selection', [ - ['scatter2d', [[[0, 2], []]]], - ['line2d', [1]], - ['select2d', [[[1], []]]] - ]); - }) - .then(function() { return doubleClick(250, 250); }) - .then(function() { - _assert('after double-click', [ - ['scatter2d', [0]], - ['line2d', [1]], - ['select2d', [[[], []]]] - ]); - }) - .catch(failTest) - .then(done); + .then(delay(20)) + .then(function() { + var scene = grabScene(); + spyOn(scene.scatter2d, 'draw').and.callFake(function() { + tracker.push(['scatter2d', arguments]); + }); + spyOn(scene.line2d, 'draw').and.callFake(function() { + tracker.push(['line2d', arguments]); + }); + spyOn(scene.select2d, 'draw').and.callFake(function() { + tracker.push(['select2d', arguments]); + }); + }) + .then(function() { return Plotly.relayout(gd, 'xaxis.range', [0, 4]); }) + .then(function() { + _assert('base', [ + ['scatter2d', [0]], + ['line2d', [1]], + ['select2d', [[[], []]]] + ]); + }) + .then(function() { return select([[20, 20], [480, 250]]); }) + .then(function() { + _assert('on selection', [ + ['scatter2d', [[[0, 2], []]]], + ['line2d', [1]], + ['select2d', [[[1], []]]] + ]); + }) + .then(function() { return doubleClick(250, 250); }) + .then(function() { + _assert('after double-click', [ + ['scatter2d', [0]], + ['line2d', [1]], + ['select2d', [[[], []]]] + ]); + }) + .catch(failTest) + .then(done); }); - it('@gl should work on overlaid subplots', function(done) { + it('@dbgl should work on overlaid subplots', function(done) { gd = createGraphDiv(); var scene, scene2; @@ -775,28 +776,28 @@ describe('Test gl2d lasso/select:', function() { type: 'scattergl', mode: 'markers' }], { - xaxis: {domain: [0.2, 1]}, - yaxis2: {overlaying: 'y', side: 'left', position: 0}, + xaxis: { domain: [0.2, 1] }, + yaxis2: { overlaying: 'y', side: 'left', position: 0 }, showlegend: false, - margin: {l: 0, t: 0, b: 0, r: 0}, + margin: { l: 0, t: 0, b: 0, r: 0 }, width: 400, height: 400, dragmode: 'select' }) - .then(delay(20)) - .then(function() { - scene = gd._fullLayout._plots.xy._scene; - scene2 = gd._fullLayout._plots.xy2._scene; + .then(delay(20)) + .then(function() { + scene = gd._fullLayout._plots.xy._scene; + scene2 = gd._fullLayout._plots.xy2._scene; - spyOn(scene.scatter2d, 'draw'); - spyOn(scene2.scatter2d, 'draw'); - }) - .then(function() { return select([[20, 20], [380, 250]]); }) - .then(function() { - expect(scene.scatter2d.draw).toHaveBeenCalledTimes(1); - expect(scene2.scatter2d.draw).toHaveBeenCalledTimes(1); - }) - .catch(failTest) - .then(done); + spyOn(scene.scatter2d, 'draw'); + spyOn(scene2.scatter2d, 'draw'); + }) + .then(function() { return select([[20, 20], [380, 250]]); }) + .then(function() { + expect(scene.scatter2d.draw).toHaveBeenCalledTimes(1); + expect(scene2.scatter2d.draw).toHaveBeenCalledTimes(1); + }) + .catch(failTest) + .then(done); }); });