|
| 1 | +var Plotly = require('@lib/index'); |
| 2 | +var Lib = require('@src/lib'); |
| 3 | +var Plots = require('@src/plots/plots'); |
| 4 | +var Table = require('@src/traces/table'); |
| 5 | +var cn = require('@src/traces/table/constants').cn; |
| 6 | + |
| 7 | +var createGraphDiv = require('../assets/create_graph_div'); |
| 8 | +var destroyGraphDiv = require('../assets/destroy_graph_div'); |
| 9 | + |
| 10 | +var mockMulti = require('@mocks/table_latex_multitrace.json'); |
| 11 | + |
| 12 | +// mock with two columns; lowest column count of general case |
| 13 | +var mock2 = Lib.extendDeep({}, mockMulti); |
| 14 | +mock2.data = [mock2.data[2]]; // keep the subplot with two columns |
| 15 | + |
| 16 | +// mock with one column as special case |
| 17 | +var mock1 = Lib.extendDeep({}, mock2); |
| 18 | +mock1.data[0].header.values = mock1.data[0].header.values.slice(0, 1); |
| 19 | +mock1.data[0].cells.values = mock1.data[0].cells.values.slice(0, 1); |
| 20 | + |
| 21 | +// mock with zero columns; special case, as no column can be rendered |
| 22 | +var mock0 = Lib.extendDeep({}, mock1); |
| 23 | +mock0.data[0].header.values = []; |
| 24 | +mock0.data[0].cells.values = []; |
| 25 | + |
| 26 | +var mock = require('@mocks/table_plain_birds.json'); |
| 27 | + |
| 28 | +describe('table initialization tests', function() { |
| 29 | + |
| 30 | + 'use strict'; |
| 31 | + |
| 32 | + describe('table global defaults', function() { |
| 33 | + |
| 34 | + it('should not coerce trace opacity', function() { |
| 35 | + var gd = Lib.extendDeep({}, mock1); |
| 36 | + |
| 37 | + Plots.supplyDefaults(gd); |
| 38 | + |
| 39 | + expect(gd._fullData[0].opacity).toBeUndefined(); |
| 40 | + }); |
| 41 | + |
| 42 | + it('should use global font as label, tick and range font defaults', function() { |
| 43 | + var gd = Lib.extendDeep({}, mock1); |
| 44 | + delete gd.data[0].header.font; |
| 45 | + delete gd.data[0].cells.font; |
| 46 | + gd.layout.font = { |
| 47 | + family: 'Gravitas', |
| 48 | + size: 20, |
| 49 | + color: 'blue' |
| 50 | + }; |
| 51 | + |
| 52 | + Plots.supplyDefaults(gd); |
| 53 | + |
| 54 | + var expected = { |
| 55 | + family: 'Gravitas', |
| 56 | + size: 20, |
| 57 | + color: 'blue' |
| 58 | + }; |
| 59 | + |
| 60 | + expect(gd._fullData[0].header.font).toEqual(expected); |
| 61 | + expect(gd._fullData[0].cells.font).toEqual(expected); |
| 62 | + }); |
| 63 | + }); |
| 64 | + |
| 65 | + describe('table defaults', function() { |
| 66 | + |
| 67 | + function _supply(traceIn) { |
| 68 | + var traceOut = { visible: true }, |
| 69 | + defaultColor = '#777', |
| 70 | + layout = { font: {family: '"Open Sans", verdana, arial, sans-serif', size: 12, color: '#444'} }; |
| 71 | + |
| 72 | + Table.supplyDefaults(traceIn, traceOut, defaultColor, layout); |
| 73 | + |
| 74 | + return traceOut; |
| 75 | + } |
| 76 | + |
| 77 | + it('\'line\' specification should yield a default color', function() { |
| 78 | + var fullTrace = _supply({}); |
| 79 | + expect(fullTrace.header.fill.color).toEqual('#777'); |
| 80 | + expect(fullTrace.cells.fill.color).toEqual('#777'); |
| 81 | + }); |
| 82 | + |
| 83 | + it('\'domain\' specification should have a default', function() { |
| 84 | + var fullTrace = _supply({}); |
| 85 | + expect(fullTrace.domain).toEqual({x: [0, 1], y: [0, 1]}); |
| 86 | + }); |
| 87 | + |
| 88 | + it('\'*.values\' specification should have a default of an empty array', function() { |
| 89 | + var fullTrace = _supply({}); |
| 90 | + expect(fullTrace.header.values).toEqual([]); |
| 91 | + expect(fullTrace.cells.values).toEqual([]); |
| 92 | + }); |
| 93 | + |
| 94 | + it('\'header\' should be used with default values where attributes are not provided', function() { |
| 95 | + var fullTrace = _supply({ |
| 96 | + header: { |
| 97 | + values: ['A'], |
| 98 | + alienProperty: 'Alpha Centauri' |
| 99 | + }, |
| 100 | + cells: { |
| 101 | + values: [1, 2], // otherwise header.values will become [] |
| 102 | + alienProperty: 'Betelgeuse' |
| 103 | + } |
| 104 | + }); |
| 105 | + expect(fullTrace.header).toEqual({ |
| 106 | + values: ['A'], // only one column remains |
| 107 | + format: [], |
| 108 | + align: 'center', |
| 109 | + height: 28, |
| 110 | + line: { width: 1, color: 'grey' }, |
| 111 | + fill: { color: '#777' }, |
| 112 | + font: {family: '"Open Sans", verdana, arial, sans-serif', size: 12, color: '#444'} |
| 113 | + }); |
| 114 | + |
| 115 | + expect(fullTrace.cells).toEqual({ |
| 116 | + values: [1, 2], |
| 117 | + format: [], |
| 118 | + align: 'center', |
| 119 | + height: 28, |
| 120 | + line: { width: 1, color: 'grey' }, |
| 121 | + fill: { color: '#777' }, |
| 122 | + font: {family: '"Open Sans", verdana, arial, sans-serif', size: 12, color: '#444'} |
| 123 | + }); |
| 124 | + }); |
| 125 | + }); |
| 126 | +}); |
| 127 | + |
| 128 | +describe('table', function() { |
| 129 | + |
| 130 | + afterEach(destroyGraphDiv); |
| 131 | + |
| 132 | + describe('edge cases', function() { |
| 133 | + |
| 134 | + it('Works with more than one column', function(done) { |
| 135 | + |
| 136 | + var mockCopy = Lib.extendDeep({}, mock2); |
| 137 | + var gd = createGraphDiv(); |
| 138 | + Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(function() { |
| 139 | + expect(gd.data.length).toEqual(1); |
| 140 | + expect(gd.data[0].header.values.length).toEqual(2); |
| 141 | + expect(gd.data[0].cells.values.length).toEqual(2); |
| 142 | + expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(2); |
| 143 | + done(); |
| 144 | + }); |
| 145 | + }); |
| 146 | + |
| 147 | + it('Works with one column', function(done) { |
| 148 | + |
| 149 | + var mockCopy = Lib.extendDeep({}, mock1); |
| 150 | + var gd = createGraphDiv(); |
| 151 | + Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(function() { |
| 152 | + expect(gd.data.length).toEqual(1); |
| 153 | + expect(gd.data[0].header.values.length).toEqual(1); |
| 154 | + expect(gd.data[0].cells.values.length).toEqual(1); |
| 155 | + expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(1); |
| 156 | + done(); |
| 157 | + }); |
| 158 | + }); |
| 159 | + |
| 160 | + it('Does not error with zero columns', function(done) { |
| 161 | + |
| 162 | + var mockCopy = Lib.extendDeep({}, mock0); |
| 163 | + var gd = createGraphDiv(); |
| 164 | + |
| 165 | + Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(function() { |
| 166 | + expect(gd.data.length).toEqual(1); |
| 167 | + expect(gd.data[0].header.values.length).toEqual(0); |
| 168 | + expect(gd.data[0].cells.values.length).toEqual(0); |
| 169 | + expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(0); |
| 170 | + done(); |
| 171 | + }); |
| 172 | + }); |
| 173 | + |
| 174 | + it('Does not raise an error with zero lines', function(done) { |
| 175 | + |
| 176 | + var mockCopy = Lib.extendDeep({}, mock2); |
| 177 | + |
| 178 | + mockCopy.layout.width = 320; |
| 179 | + mockCopy.data[0].header.values = [[], []]; |
| 180 | + mockCopy.data[0].cells.values = [[], []]; |
| 181 | + |
| 182 | + var gd = createGraphDiv(); |
| 183 | + Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(function() { |
| 184 | + |
| 185 | + expect(gd.data.length).toEqual(1); |
| 186 | + expect(gd.data[0].header.values.length).toEqual(2); |
| 187 | + expect(gd.data[0].cells.values.length).toEqual(2); |
| 188 | + expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(2); |
| 189 | + done(); |
| 190 | + }); |
| 191 | + }); |
| 192 | + }); |
| 193 | + |
| 194 | + describe('basic use', function() { |
| 195 | + var mockCopy, |
| 196 | + gd; |
| 197 | + |
| 198 | + beforeEach(function(done) { |
| 199 | + mockCopy = Lib.extendDeep({}, mock); |
| 200 | + mockCopy.data[0].domain = { |
| 201 | + x: [0.1, 0.9], |
| 202 | + y: [0.05, 0.85] |
| 203 | + }; |
| 204 | + gd = createGraphDiv(); |
| 205 | + Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(done); |
| 206 | + }); |
| 207 | + |
| 208 | + it('`Plotly.plot` should have proper fields on `gd.data` on initial rendering', function() { |
| 209 | + |
| 210 | + expect(gd.data.length).toEqual(1); |
| 211 | + expect(gd.data[0].header.values.length).toEqual(7); |
| 212 | + expect(gd.data[0].cells.values.length).toEqual(7); |
| 213 | + expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(7); // one dimension is `visible: false` |
| 214 | + }); |
| 215 | + |
| 216 | + it('Calling `Plotly.plot` again should add the new table trace', function(done) { |
| 217 | + |
| 218 | + var reversedMockCopy = Lib.extendDeep({}, mockCopy); |
| 219 | + reversedMockCopy.data[0].header.values = reversedMockCopy.data[0].header.values.slice().reverse(); |
| 220 | + reversedMockCopy.data[0].cells.values = reversedMockCopy.data[0].cells.values.slice().reverse(); |
| 221 | + reversedMockCopy.data[0].domain.y = [0, 0.3]; |
| 222 | + |
| 223 | + Plotly.plot(gd, reversedMockCopy.data, reversedMockCopy.layout).then(function() { |
| 224 | + expect(gd.data.length).toEqual(2); |
| 225 | + expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(7 * 2); |
| 226 | + done(); |
| 227 | + }); |
| 228 | + |
| 229 | + }); |
| 230 | + |
| 231 | + it('Calling `Plotly.restyle` with a string path should amend the preexisting table', function(done) { |
| 232 | + |
| 233 | + expect(gd.data.length).toEqual(1); |
| 234 | + |
| 235 | + Plotly.restyle(gd, 'header.fill.color', 'magenta').then(function() { |
| 236 | + |
| 237 | + expect(gd.data.length).toEqual(1); |
| 238 | + |
| 239 | + expect(gd.data[0].header.fill.color).toEqual('magenta'); |
| 240 | + expect(gd.data[0].header.values.length).toEqual(7); |
| 241 | + expect(gd.data[0].cells.values.length).toEqual(7); |
| 242 | + expect(gd.data[0].header.line.color).toEqual('lightgray'); // no change relative to original mock value |
| 243 | + expect(gd.data[0].cells.line.color).toEqual(['grey']); // no change relative to original mock value |
| 244 | + |
| 245 | + done(); |
| 246 | + }); |
| 247 | + |
| 248 | + }); |
| 249 | + |
| 250 | + it('Calling `Plotly.restyle` for a `header.values` change should amend the preexisting one', function(done) { |
| 251 | + |
| 252 | + function restyleValues(what, key, setterValue) { |
| 253 | + |
| 254 | + // array values need to be wrapped in an array; unwrapping here for value comparison |
| 255 | + var value = Lib.isArray(setterValue) ? setterValue[0] : setterValue; |
| 256 | + |
| 257 | + return function() { |
| 258 | + return Plotly.restyle(gd, what + '.values[' + key + ']', setterValue).then(function() { |
| 259 | + expect(gd.data[0][what].values[key]).toEqual(value, 'for column \'' + key + '\''); |
| 260 | + expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(7); |
| 261 | + }); |
| 262 | + }; |
| 263 | + } |
| 264 | + |
| 265 | + restyleValues('cells', 0, [['new cell content 1', 'new cell content 2']])() |
| 266 | + .then(restyleValues('cells', 2, [[0, 0.1]])) |
| 267 | + .then(restyleValues('header', 1, [['Species top', 'Species bottom']])) |
| 268 | + .then(done); |
| 269 | + }); |
| 270 | + |
| 271 | + it('Calling `Plotly.relayout` with string should amend the preexisting parcoords', function(done) { |
| 272 | + expect(gd.layout.width).toEqual(1000); |
| 273 | + Plotly.relayout(gd, 'width', 500).then(function() { |
| 274 | + expect(gd.data.length).toEqual(1); |
| 275 | + expect(gd.layout.width).toEqual(500); |
| 276 | + done(); |
| 277 | + }); |
| 278 | + }); |
| 279 | + |
| 280 | + it('Calling `Plotly.relayout` with object should amend the preexisting parcoords', function(done) { |
| 281 | + expect(gd.layout.width).toEqual(1000); |
| 282 | + Plotly.relayout(gd, {width: 500}).then(function() { |
| 283 | + expect(gd.data.length).toEqual(1); |
| 284 | + expect(gd.layout.width).toEqual(500); |
| 285 | + done(); |
| 286 | + }); |
| 287 | + }); |
| 288 | + }); |
| 289 | +}); |
0 commit comments