Skip to content

Commit db1f82e

Browse files
committed
Add parameterized tests:
These tests currently fail but this commit currently doesn't include fundamental bug fixes.
1 parent 5d7b1b9 commit db1f82e

File tree

1 file changed

+151
-0
lines changed

1 file changed

+151
-0
lines changed

test/jasmine/tests/pikul_test.js

+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
2+
var Plotly = require('../../../lib/index');
3+
4+
var createGraphDiv = require('../assets/create_graph_div');
5+
var destroyGraphDiv = require('../assets/destroy_graph_div');
6+
7+
// Boilerplate taken from axes_test.js
8+
describe('tickmode proportional', function() {
9+
var gd;
10+
11+
beforeEach(function() {
12+
gd = createGraphDiv();
13+
});
14+
15+
afterEach(destroyGraphDiv);
16+
17+
// These enums are `ticklen`s- it's how DOM analysis differentiates wrt major/minor
18+
// Passed as tickLen argument to specify major or minor tick config
19+
const MAJOR = 202, MINOR = 101;
20+
function generateTickConfig(tickLen){
21+
// Intentionally configure to produce a single `(x|y)tick` class per tick
22+
// labels and tick marks each produce one, so one or the other
23+
standardConfig = {tickmode: 'proportional', ticklen: tickLen, showticklabels: false};
24+
25+
// Tick values will be random:
26+
var n = Math.floor(Math.random() * 100);
27+
tickVals = [];
28+
29+
for(let i = 0; i <= n; i++){
30+
intermediate = (Math.trunc(Math.random()*150) - 25) / 100; // Number between -.25 and 1.25 w/ 2 decimals max
31+
tickVals.push(Math.min(Math.max(intermediate, 0), 1)); // 2 decimal number between 0 and 1 w/ higher odds of 0 or 1
32+
}
33+
standardConfig['tickvals'] = tickVals;
34+
return standardConfig;
35+
}
36+
37+
function binaryToString(bin) {
38+
if (bin == 0b1) return "xMajor";
39+
if (bin == 0b10) return "xMinor";
40+
if (bin == 0b100) return "yMajor";
41+
if (bin == 0b1000) return "yMinor";
42+
}
43+
// the var `tickConfig` represents every possible configuration. It is in an int 0-15.
44+
// The binary is 0001, 0010, 0011, etc. IE every possible combination of 4 booleans.
45+
for(let tickConfig = 1; tickConfig <= 15; tickConfig++) {
46+
(function(tickConfig) { // tickConfig needs to be a closure otherwise it won't get the parameterized value
47+
it('maps proportional values to correct range values', function(done) {
48+
var xMajor = tickConfig & 0b0001; // check if xMajor position is 1 (True)
49+
var xMinor = tickConfig & 0b0010;
50+
var yMajor = tickConfig & 0b0100;
51+
var yMinor = tickConfig & 0b1000;
52+
xMajorConfig = xMajor ? generateTickConfig(MAJOR) : {}; // generate separate configs for each
53+
xMinorConfig = xMinor ? generateTickConfig(MAJOR) : {};
54+
yMajorConfig = yMajor ? generateTickConfig(MINOR) : {};
55+
yMinorConfig = yMinor ? generateTickConfig(MINOR) : {};
56+
var configInfo = ""
57+
configInfo += xMajor ? "\n" + `xMajor: ${xMajorConfig['tickvals'].length} non-unique vals` : "";
58+
configInfo += xMinor ? "\n" + `xMinor: ${xMinorConfig['tickvals'].length} non-unique vals` : "";
59+
configInfo += yMajor ? "\n" + `yMajor: ${yMajorConfig['tickvals'].length} non-unique vals` : "";
60+
configInfo += yMinor ? "\n" + `yMinor: ${yMinorConfig['tickvals'].length} non-unique vals` : "";
61+
Plotly.newPlot(gd, {
62+
data: [{
63+
x: [0, 1],
64+
y: [0, 1]
65+
}],
66+
layout: {
67+
width: 400,
68+
height: 400,
69+
margin: { t: 40, b: 40, l: 40, r: 40, },
70+
xaxis: {
71+
range: [0, 10],
72+
...xMajorConfig, // explode config into this key
73+
minor: xMinorConfig, // set config to this key
74+
},
75+
yaxis: { // same as above
76+
autorange: true,
77+
...yMajorConfig,
78+
minor: yMinorConfig,
79+
},
80+
}}).then(function() {
81+
// This regex is for extracting geometric position of... should have used getBoundingClientRect()
82+
//
83+
// regex: `.source` converts to string, laid out this way to make for easier reading
84+
const funcName = "translate" + /\(/.source; // literally simplest way to regex '('
85+
const integerPart = /\d+/.source; // numbers left of decimal
86+
const fractionalPart = /(?:\.\d+)?/.source; // decimal + numbers to right
87+
const floatNum = integerPart + fractionalPart; // all together
88+
const any = /.+/.source;
89+
const close = /\)/.source;
90+
const re = new RegExp(funcName + '(' + floatNum + '),' + any + close); // parens are capture not fn()
91+
for(let runNumber = 0b1; runNumber <= 0b1000; runNumber <<= 0b1) { // Check all ticks on all axes ☺
92+
var elementName = "";
93+
var targetConfig;
94+
var runInfo = "\n Checking: " + binaryToString(runNumber);
95+
if(runNumber & xMajor) { // ie. this run wants xMajor and xMajor was set in config above
96+
elementName = "xtick";
97+
targetConfig = xMajorConfig;
98+
} else if (runNumber & xMinor) {
99+
elementName = "xtick";
100+
targetConfig = xMinorConfig;
101+
} else if (runNumber & yMajor) {
102+
elementName = "ytick";
103+
targetConfig = yMajorConfig;
104+
} else if (runNumber & yMinor) {
105+
elementName = "ytick";
106+
targetConfig = yMinorConfig;
107+
} else continue; // This test isn't doing that type of test
108+
109+
var tickElements = document.getElementsByClassName(elementName);
110+
var tickValsUnique = [...new Set(targetConfig['tickvals'])];
111+
var expectedTickLen = String(targetConfig['ticklen'])
112+
113+
if(tickElements.length < 2) return; // Can't test proportions with < 2 ticks (since no fixed reference)
114+
115+
// Filter out major/minor and grab geometry
116+
transformVals = []; // "transform" ie the positional property
117+
for(let i = 0; i < tickElements.length; i++) {
118+
if(!tickElements[i].getAttribute("d").endsWith(expectedTickLen)) continue;
119+
var translate = tickElements[i].getAttribute("transform");
120+
transformVals.push(Number(translate.match(re)[1]));
121+
}
122+
123+
var debugInfo = "\n " + `tickElements: (${tickElements.length}) ${tickElements}` + "\n" +
124+
`tickVals/Unique: (${targetConfig['tickvals'].length}/${tickValsUnique.length}) {tickValsUnique}`;
125+
126+
expect(transformVals.length).toBe(tickValsUnique.length,
127+
"test html vs tickvals failed" + runInfo + configInfo + debugInfo);
128+
129+
130+
// To test geometries without using fixed point or data values
131+
// We can check consistency of y = mx+b
132+
// if x = 0 then y = b, but we may not have a 0 valued x
133+
// m = (y1 - y2) / (x1 - x2)
134+
// b = y1 - mx1
135+
y = transformVals;
136+
x = tickValsUnique;
137+
var m, b;
138+
var b_index = x.indexOf(0);
139+
140+
m = (y[0] - y[1]) / (x[0] - x[1]);
141+
b = (b_index != -1) ? b = y[b_index] : y[0] - m*x[0];
142+
143+
for(let i = 0; i < x.length; i++) {
144+
expect(y[i]).toBeCloseTo(m * x[i] + b, 1, "y=mx+b test failed" + runInfo + configInfo + debugInfo) // not sure about toBeCloseTo
145+
}
146+
}
147+
}).then(done, done.fail);
148+
});
149+
})(tickConfig);
150+
}
151+
});

0 commit comments

Comments
 (0)