From 6276304aa33e6f711b1478b9f4c8904bd360ba53 Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Thu, 19 Oct 2017 13:18:26 +0200 Subject: [PATCH 1/6] adding table_test.js --- test/jasmine/tests/table_test.js | 289 +++++++++++++++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 test/jasmine/tests/table_test.js diff --git a/test/jasmine/tests/table_test.js b/test/jasmine/tests/table_test.js new file mode 100644 index 00000000000..419ac8c3858 --- /dev/null +++ b/test/jasmine/tests/table_test.js @@ -0,0 +1,289 @@ +var Plotly = require('@lib/index'); +var Lib = require('@src/lib'); +var Plots = require('@src/plots/plots'); +var Table = require('@src/traces/table'); +var cn = require('@src/traces/table/constants').cn; + +var createGraphDiv = require('../assets/create_graph_div'); +var destroyGraphDiv = require('../assets/destroy_graph_div'); + +var mockMulti = require('@mocks/table_latex_multitrace.json'); + +// mock with two columns; lowest column count of general case +var mock2 = Lib.extendDeep({}, mockMulti); +mock2.data = [mock2.data[2]]; // keep the subplot with two columns + +// mock with one column as special case +var mock1 = Lib.extendDeep({}, mock2); +mock1.data[0].header.values = mock1.data[0].header.values.slice(0, 1); +mock1.data[0].cells.values = mock1.data[0].cells.values.slice(0, 1); + +// mock with zero columns; special case, as no column can be rendered +var mock0 = Lib.extendDeep({}, mock1); +mock0.data[0].header.values = []; +mock0.data[0].cells.values = []; + +var mock = require('@mocks/table_plain_birds.json'); + +describe('table initialization tests', function() { + + 'use strict'; + + describe('table global defaults', function() { + + it('should not coerce trace opacity', function() { + var gd = Lib.extendDeep({}, mock1); + + Plots.supplyDefaults(gd); + + expect(gd._fullData[0].opacity).toBeUndefined(); + }); + + it('should use global font as label, tick and range font defaults', function() { + var gd = Lib.extendDeep({}, mock1); + delete gd.data[0].header.font; + delete gd.data[0].cells.font; + gd.layout.font = { + family: 'Gravitas', + size: 20, + color: 'blue' + }; + + Plots.supplyDefaults(gd); + + var expected = { + family: 'Gravitas', + size: 20, + color: 'blue' + }; + + expect(gd._fullData[0].header.font).toEqual(expected); + expect(gd._fullData[0].cells.font).toEqual(expected); + }); + }); + + describe('table defaults', function() { + + function _supply(traceIn) { + var traceOut = { visible: true }, + defaultColor = '#777', + layout = { font: {family: '"Open Sans", verdana, arial, sans-serif', size: 12, color: '#444'} }; + + Table.supplyDefaults(traceIn, traceOut, defaultColor, layout); + + return traceOut; + } + + it('\'line\' specification should yield a default color', function() { + var fullTrace = _supply({}); + expect(fullTrace.header.fill.color).toEqual('#777'); + expect(fullTrace.cells.fill.color).toEqual('#777'); + }); + + it('\'domain\' specification should have a default', function() { + var fullTrace = _supply({}); + expect(fullTrace.domain).toEqual({x: [0, 1], y: [0, 1]}); + }); + + it('\'*.values\' specification should have a default of an empty array', function() { + var fullTrace = _supply({}); + expect(fullTrace.header.values).toEqual([]); + expect(fullTrace.cells.values).toEqual([]); + }); + + it('\'header\' should be used with default values where attributes are not provided', function() { + var fullTrace = _supply({ + header: { + values: ['A'], + alienProperty: 'Alpha Centauri' + }, + cells: { + values: [1, 2], // otherwise header.values will become [] + alienProperty: 'Betelgeuse' + } + }); + expect(fullTrace.header).toEqual({ + values: ['A'], // only one column remains + format: [], + align: 'center', + height: 28, + line: { width: 1, color: 'grey' }, + fill: { color: '#777' }, + font: {family: '"Open Sans", verdana, arial, sans-serif', size: 12, color: '#444'} + }); + + expect(fullTrace.cells).toEqual({ + values: [1, 2], + format: [], + align: 'center', + height: 28, + line: { width: 1, color: 'grey' }, + fill: { color: '#777' }, + font: {family: '"Open Sans", verdana, arial, sans-serif', size: 12, color: '#444'} + }); + }); + }); +}); + +describe('table', function() { + + afterEach(destroyGraphDiv); + + describe('edge cases', function() { + + it('Works with more than one column', function(done) { + + var mockCopy = Lib.extendDeep({}, mock2); + var gd = createGraphDiv(); + Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(function() { + expect(gd.data.length).toEqual(1); + expect(gd.data[0].header.values.length).toEqual(2); + expect(gd.data[0].cells.values.length).toEqual(2); + expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(2); + done(); + }); + }); + + it('Works with one column', function(done) { + + var mockCopy = Lib.extendDeep({}, mock1); + var gd = createGraphDiv(); + Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(function() { + expect(gd.data.length).toEqual(1); + expect(gd.data[0].header.values.length).toEqual(1); + expect(gd.data[0].cells.values.length).toEqual(1); + expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(1); + done(); + }); + }); + + it('Does not error with zero columns', function(done) { + + var mockCopy = Lib.extendDeep({}, mock0); + var gd = createGraphDiv(); + + Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(function() { + expect(gd.data.length).toEqual(1); + expect(gd.data[0].header.values.length).toEqual(0); + expect(gd.data[0].cells.values.length).toEqual(0); + expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(0); + done(); + }); + }); + + it('Does not raise an error with zero lines', function(done) { + + var mockCopy = Lib.extendDeep({}, mock2); + + mockCopy.layout.width = 320; + mockCopy.data[0].header.values = [[], []]; + mockCopy.data[0].cells.values = [[], []]; + + var gd = createGraphDiv(); + Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(function() { + + expect(gd.data.length).toEqual(1); + expect(gd.data[0].header.values.length).toEqual(2); + expect(gd.data[0].cells.values.length).toEqual(2); + expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(2); + done(); + }); + }); + }); + + describe('basic use', function() { + var mockCopy, + gd; + + beforeEach(function(done) { + mockCopy = Lib.extendDeep({}, mock); + mockCopy.data[0].domain = { + x: [0.1, 0.9], + y: [0.05, 0.85] + }; + gd = createGraphDiv(); + Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(done); + }); + + it('`Plotly.plot` should have proper fields on `gd.data` on initial rendering', function() { + + expect(gd.data.length).toEqual(1); + expect(gd.data[0].header.values.length).toEqual(7); + expect(gd.data[0].cells.values.length).toEqual(7); + expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(7); // one dimension is `visible: false` + }); + + it('Calling `Plotly.plot` again should add the new table trace', function(done) { + + var reversedMockCopy = Lib.extendDeep({}, mockCopy); + reversedMockCopy.data[0].header.values = reversedMockCopy.data[0].header.values.slice().reverse(); + reversedMockCopy.data[0].cells.values = reversedMockCopy.data[0].cells.values.slice().reverse(); + reversedMockCopy.data[0].domain.y = [0, 0.3]; + + Plotly.plot(gd, reversedMockCopy.data, reversedMockCopy.layout).then(function() { + expect(gd.data.length).toEqual(2); + expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(7 * 2); + done(); + }); + + }); + + it('Calling `Plotly.restyle` with a string path should amend the preexisting table', function(done) { + + expect(gd.data.length).toEqual(1); + + Plotly.restyle(gd, 'header.fill.color', 'magenta').then(function() { + + expect(gd.data.length).toEqual(1); + + expect(gd.data[0].header.fill.color).toEqual('magenta'); + expect(gd.data[0].header.values.length).toEqual(7); + expect(gd.data[0].cells.values.length).toEqual(7); + expect(gd.data[0].header.line.color).toEqual('lightgray'); // no change relative to original mock value + expect(gd.data[0].cells.line.color).toEqual(['grey']); // no change relative to original mock value + + done(); + }); + + }); + + it('Calling `Plotly.restyle` for a `header.values` change should amend the preexisting one', function(done) { + + function restyleValues(what, key, setterValue) { + + // array values need to be wrapped in an array; unwrapping here for value comparison + var value = Lib.isArray(setterValue) ? setterValue[0] : setterValue; + + return function() { + return Plotly.restyle(gd, what + '.values[' + key + ']', setterValue).then(function() { + expect(gd.data[0][what].values[key]).toEqual(value, 'for column \'' + key + '\''); + expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(7); + }); + }; + } + + restyleValues('cells', 0, [['new cell content 1', 'new cell content 2']])() + .then(restyleValues('cells', 2, [[0, 0.1]])) + .then(restyleValues('header', 1, [['Species top', 'Species bottom']])) + .then(done); + }); + + it('Calling `Plotly.relayout` with string should amend the preexisting parcoords', function(done) { + expect(gd.layout.width).toEqual(1000); + Plotly.relayout(gd, 'width', 500).then(function() { + expect(gd.data.length).toEqual(1); + expect(gd.layout.width).toEqual(500); + done(); + }); + }); + + it('Calling `Plotly.relayout` with object should amend the preexisting parcoords', function(done) { + expect(gd.layout.width).toEqual(1000); + Plotly.relayout(gd, {width: 500}).then(function() { + expect(gd.data.length).toEqual(1); + expect(gd.layout.width).toEqual(500); + done(); + }); + }); + }); +}); From b4a5dd74f0a9d21ce585c54f68d51937cf1b3fa9 Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Thu, 19 Oct 2017 23:52:23 +0200 Subject: [PATCH 2/6] fix for non-removed columns and zero row counts --- src/traces/table/plot.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/traces/table/plot.js b/src/traces/table/plot.js index efde0afa16f..e3481104215 100644 --- a/src/traces/table/plot.js +++ b/src/traces/table/plot.js @@ -93,6 +93,8 @@ module.exports = function plot(gd, wrappedTraceHolders) { .append('g') .classed(c.cn.yColumn, true); + yColumn.exit().remove(); + yColumn .attr('transform', function(d) {return 'translate(' + d.x + ' 0)';}) .call(d3.behavior.drag() @@ -242,7 +244,7 @@ function renderScrollbarKit(tableControlView, gd, bypassVisibleBar) { function calcTotalHeight(d) { var blocks = d.rowBlocks; - return firstRowAnchor(blocks, blocks.length - 1) + rowsHeight(blocks[blocks.length - 1], Infinity); + return firstRowAnchor(blocks, blocks.length - 1) + (blocks.length ? rowsHeight(blocks[blocks.length - 1], Infinity) : 1); } var scrollbarKit = tableControlView.selectAll('.' + c.cn.scrollbarKit) @@ -288,7 +290,7 @@ function renderScrollbarKit(tableControlView, gd, bypassVisibleBar) { scrollbarSlider .attr('transform', function(d) { - return 'translate(0 ' + d.scrollbarState.topY + ')'; + return 'translate(0 ' + (d.scrollbarState.topY || 0) + ')'; }); var scrollbarGlyph = scrollbarSlider.selectAll('.' + c.cn.scrollbarGlyph) @@ -603,7 +605,7 @@ function headerBlock(d) {return d.type === 'header';} */ function headerHeight(d) { - var headerBlocks = d.rowBlocks[0].auxiliaryBlocks; + var headerBlocks = d.rowBlocks.length ? d.rowBlocks[0].auxiliaryBlocks : []; return headerBlocks.reduce(function(p, n) {return p + rowsHeight(n, Infinity);}, 0); } @@ -643,6 +645,7 @@ function findPagesAndCacheHeights(blocks, scrollY, scrollHeight) { function updateBlockYPosition(gd, cellsColumnBlock, tableControlView) { var d = flatData(cellsColumnBlock)[0]; + if(d === undefined) return; var blocks = d.rowBlocks; var calcdata = d.calcdata; From 8173259ab32b92748ab1dd4c094b7d4b07511836 Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Thu, 19 Oct 2017 23:53:56 +0200 Subject: [PATCH 3/6] making default cell row heights the same as header row height --- src/traces/table/attributes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/traces/table/attributes.js b/src/traces/table/attributes.js index 947194ba357..d094b9848c0 100644 --- a/src/traces/table/attributes.js +++ b/src/traces/table/attributes.js @@ -183,7 +183,7 @@ module.exports = overrideAll({ height: { valType: 'number', - dflt: 20, + dflt: 28, role: 'style', description: 'The height of cells.' }, From 103e793610907473d095c7d617594fd9537ab7ad Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Thu, 19 Oct 2017 23:56:26 +0200 Subject: [PATCH 4/6] ensuring special cases 0 rows or 0 columns work; noOpacity --- src/traces/table/data_preparation_helper.js | 5 ++- src/traces/table/defaults.js | 41 +++++++++------------ src/traces/table/index.js | 2 +- 3 files changed, 22 insertions(+), 26 deletions(-) diff --git a/src/traces/table/data_preparation_helper.js b/src/traces/table/data_preparation_helper.js index 62e07a248cd..5988cdd29e0 100644 --- a/src/traces/table/data_preparation_helper.js +++ b/src/traces/table/data_preparation_helper.js @@ -16,11 +16,12 @@ module.exports = function calc(gd, trace) { var headerValues = trace.header.values.map(function(c) { return Array.isArray(c) ? c : [c]; }); + var cellsValues = trace.cells.values; var domain = trace.domain; var groupWidth = Math.floor(gd._fullLayout._size.w * (domain.x[1] - domain.x[0])); var groupHeight = Math.floor(gd._fullLayout._size.h * (domain.y[1] - domain.y[0])); - var headerRowHeights = headerValues[0].map(function() {return trace.header.height;}); - var rowHeights = trace.cells.values[0].map(function() {return trace.cells.height;}); + var headerRowHeights = headerValues.length ? headerValues[0].map(function() {return trace.header.height;}) : []; + var rowHeights = cellsValues.length ? cellsValues[0].map(function() {return trace.cells.height;}) : []; var headerHeight = headerRowHeights.reduce(function(a, b) {return a + b;}, 0); var scrollHeight = groupHeight - headerHeight; var minimumFillHeight = scrollHeight + c.uplift; diff --git a/src/traces/table/defaults.js b/src/traces/table/defaults.js index 161a8742802..3edb764ae22 100644 --- a/src/traces/table/defaults.js +++ b/src/traces/table/defaults.js @@ -11,9 +11,9 @@ var Lib = require('../../lib'); var attributes = require('./attributes'); -function defaultColumnOrder(traceIn, coerce) { - var specifiedColumnOrder = traceIn.columnorder || []; - var commonLength = traceIn.header.values.length; +function defaultColumnOrder(traceOut, coerce) { + var specifiedColumnOrder = traceOut.columnorder || []; + var commonLength = traceOut.header.values.length; var truncated = specifiedColumnOrder.slice(0, commonLength); var sorted = truncated.slice().sort(function(a, b) {return a - b;}); var oneStepped = truncated.map(function(d) {return sorted.indexOf(d);}); @@ -28,28 +28,10 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout return Lib.coerce(traceIn, traceOut, attributes, attr, dflt); } - var fontDflt = { - family: layout.font.family, - size: layout.font.size, - color: layout.font.color - }; - coerce('domain.x'); coerce('domain.y'); coerce('columnwidth'); - defaultColumnOrder(traceIn, coerce); - - coerce('cells.values'); - coerce('cells.format'); - coerce('cells.align'); - coerce('cells.prefix'); - coerce('cells.suffix'); - coerce('cells.height'); - coerce('cells.line.width'); - coerce('cells.line.color'); - coerce('cells.fill.color'); - Lib.coerceFont(coerce, 'cells.font', fontDflt); coerce('header.values'); coerce('header.format'); @@ -60,6 +42,19 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout coerce('header.height'); coerce('header.line.width'); coerce('header.line.color'); - coerce('header.fill.color'); - Lib.coerceFont(coerce, 'header.font', fontDflt); + coerce('header.fill.color', defaultColor); + Lib.coerceFont(coerce, 'header.font', Lib.extendFlat({}, layout.font)); + + defaultColumnOrder(traceOut, coerce); + + coerce('cells.values'); + coerce('cells.format'); + coerce('cells.align'); + coerce('cells.prefix'); + coerce('cells.suffix'); + coerce('cells.height'); + coerce('cells.line.width'); + coerce('cells.line.color'); + coerce('cells.fill.color', defaultColor); + Lib.coerceFont(coerce, 'cells.font', Lib.extendFlat({}, layout.font)); }; diff --git a/src/traces/table/index.js b/src/traces/table/index.js index ab5d7080fc1..3eec6ed12e1 100644 --- a/src/traces/table/index.js +++ b/src/traces/table/index.js @@ -18,7 +18,7 @@ Table.plot = require('./plot'); Table.moduleType = 'trace'; Table.name = 'table'; Table.basePlotModule = require('./base_plot'); -Table.categories = []; +Table.categories = ['noOpacity']; Table.meta = { description: [ 'Table view for detailed data viewing.', From 7a5b02cbb0b6caf39e2e493cc656b02d88abcb80 Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Fri, 20 Oct 2017 00:07:05 +0200 Subject: [PATCH 5/6] deferring the cell height change for now --- src/traces/table/attributes.js | 2 +- src/traces/table/defaults.js | 4 ++-- test/jasmine/tests/table_test.js | 11 ++++++----- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/traces/table/attributes.js b/src/traces/table/attributes.js index d094b9848c0..947194ba357 100644 --- a/src/traces/table/attributes.js +++ b/src/traces/table/attributes.js @@ -183,7 +183,7 @@ module.exports = overrideAll({ height: { valType: 'number', - dflt: 28, + dflt: 20, role: 'style', description: 'The height of cells.' }, diff --git a/src/traces/table/defaults.js b/src/traces/table/defaults.js index 3edb764ae22..a30a08f9e47 100644 --- a/src/traces/table/defaults.js +++ b/src/traces/table/defaults.js @@ -42,7 +42,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout coerce('header.height'); coerce('header.line.width'); coerce('header.line.color'); - coerce('header.fill.color', defaultColor); + coerce('header.fill.color'); Lib.coerceFont(coerce, 'header.font', Lib.extendFlat({}, layout.font)); defaultColumnOrder(traceOut, coerce); @@ -55,6 +55,6 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout coerce('cells.height'); coerce('cells.line.width'); coerce('cells.line.color'); - coerce('cells.fill.color', defaultColor); + coerce('cells.fill.color'); Lib.coerceFont(coerce, 'cells.font', Lib.extendFlat({}, layout.font)); }; diff --git a/test/jasmine/tests/table_test.js b/test/jasmine/tests/table_test.js index 419ac8c3858..cfe4186f49b 100644 --- a/test/jasmine/tests/table_test.js +++ b/test/jasmine/tests/table_test.js @@ -2,6 +2,7 @@ var Plotly = require('@lib/index'); var Lib = require('@src/lib'); var Plots = require('@src/plots/plots'); var Table = require('@src/traces/table'); +var attributes = require('@src/traces/table/attributes'); var cn = require('@src/traces/table/constants').cn; var createGraphDiv = require('../assets/create_graph_div'); @@ -76,8 +77,8 @@ describe('table initialization tests', function() { it('\'line\' specification should yield a default color', function() { var fullTrace = _supply({}); - expect(fullTrace.header.fill.color).toEqual('#777'); - expect(fullTrace.cells.fill.color).toEqual('#777'); + expect(fullTrace.header.fill.color).toEqual(attributes.header.fill.color.dflt); + expect(fullTrace.cells.fill.color).toEqual(attributes.cells.fill.color.dflt); }); it('\'domain\' specification should have a default', function() { @@ -108,7 +109,7 @@ describe('table initialization tests', function() { align: 'center', height: 28, line: { width: 1, color: 'grey' }, - fill: { color: '#777' }, + fill: { color: attributes.header.fill.color.dflt }, font: {family: '"Open Sans", verdana, arial, sans-serif', size: 12, color: '#444'} }); @@ -116,9 +117,9 @@ describe('table initialization tests', function() { values: [1, 2], format: [], align: 'center', - height: 28, + height: 20, line: { width: 1, color: 'grey' }, - fill: { color: '#777' }, + fill: { color: attributes.cells.fill.color.dflt }, font: {family: '"Open Sans", verdana, arial, sans-serif', size: 12, color: '#444'} }); }); From 37dd8bafea71fa76a8182a20b2fe4c3c79069d7d Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Fri, 20 Oct 2017 19:27:34 +0200 Subject: [PATCH 6/6] additional test case; minor renames --- src/traces/table/attributes.js | 5 +++- test/jasmine/tests/table_test.js | 50 +++++++++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/src/traces/table/attributes.js b/src/traces/table/attributes.js index 947194ba357..4cb37afe919 100644 --- a/src/traces/table/attributes.js +++ b/src/traces/table/attributes.js @@ -48,7 +48,10 @@ module.exports = overrideAll({ arrayOk: true, dflt: null, role: 'style', - description: 'The width of cells.' + description: [ + 'The width of columns expressed as a ratio. Columns fill the available width', + 'in proportion of their specified column widths.' + ].join(' ') }, columnorder: { diff --git a/test/jasmine/tests/table_test.js b/test/jasmine/tests/table_test.js index cfe4186f49b..5e936838b1d 100644 --- a/test/jasmine/tests/table_test.js +++ b/test/jasmine/tests/table_test.js @@ -192,7 +192,7 @@ describe('table', function() { }); }); - describe('basic use', function() { + describe('basic use and basic data restyling', function() { var mockCopy, gd; @@ -211,7 +211,7 @@ describe('table', function() { expect(gd.data.length).toEqual(1); expect(gd.data[0].header.values.length).toEqual(7); expect(gd.data[0].cells.values.length).toEqual(7); - expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(7); // one dimension is `visible: false` + expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(7); }); it('Calling `Plotly.plot` again should add the new table trace', function(done) { @@ -269,7 +269,7 @@ describe('table', function() { .then(done); }); - it('Calling `Plotly.relayout` with string should amend the preexisting parcoords', function(done) { + it('Calling `Plotly.relayout` with string should amend the preexisting table', function(done) { expect(gd.layout.width).toEqual(1000); Plotly.relayout(gd, 'width', 500).then(function() { expect(gd.data.length).toEqual(1); @@ -278,7 +278,7 @@ describe('table', function() { }); }); - it('Calling `Plotly.relayout` with object should amend the preexisting parcoords', function(done) { + it('Calling `Plotly.relayout` with object should amend the preexisting table', function(done) { expect(gd.layout.width).toEqual(1000); Plotly.relayout(gd, {width: 500}).then(function() { expect(gd.data.length).toEqual(1); @@ -287,4 +287,46 @@ describe('table', function() { }); }); }); + + describe('more restyling tests with scenegraph queries', function() { + var mockCopy, + gd; + + beforeEach(function(done) { + mockCopy = Lib.extendDeep({}, mock2); + gd = createGraphDiv(); + Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(done); + }); + + it('Calling `Plotly.restyle` for a `header.values` change should amend the preexisting one', function(done) { + + function restyleValues(what, fun, setterValue) { + + var value = Lib.isArray(setterValue) ? setterValue[0] : setterValue; + + return function() { + return Plotly.restyle(gd, what, setterValue).then(function() { + expect(fun(gd)).toEqual(value, what + ':::' + value); + expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(2); + expect(document.querySelectorAll('.' + cn.columnBlock).length).toEqual(6); + expect(document.querySelectorAll('.' + cn.columnCell).length).toEqual(6); + expect(document.querySelectorAll('.' + cn.cellRect).length).toEqual(6); + expect(document.querySelectorAll('.' + cn.cellTextHolder).length).toEqual(6); + }); + }; + } + + restyleValues('cells.fill.color', function(gd) {return gd.data[0].cells.fill.color;}, [['green', 'red']])() + .then(restyleValues('cells.line.color', function(gd) {return gd.data[0].cells.line.color;}, [['magenta', 'blue']])) + .then(restyleValues('cells.line.width', function(gd) {return gd.data[0].cells.line.width;}, [[5, 3]])) + .then(restyleValues('cells.format', function(gd) {return gd.data[0].cells.format;}, [['', '']])) + .then(restyleValues('cells.prefix', function(gd) {return gd.data[0].cells.prefix;}, [['p1']])) + .then(restyleValues('cells.suffix', function(gd) {return gd.data[0].cells.suffix;}, [['s1']])) + .then(restyleValues('header.fill.color', function(gd) {return gd.data[0].header.fill.color;}, [['yellow', 'purple']])) + .then(restyleValues('header.line.color', function(gd) {return gd.data[0].header.line.color;}, [['green', 'red']])) + .then(restyleValues('header.line.width', function(gd) {return gd.data[0].header.line.width;}, [[2, 6]])) + .then(restyleValues('header.format', function(gd) {return gd.data[0].header.format;}, [['', '']])) + .then(done); + }); + }); });