Skip to content

Commit a2ac023

Browse files
committed
Fix tests to pass if plotly#6828 is addressed
1 parent db1f82e commit a2ac023

File tree

1 file changed

+153
-110
lines changed

1 file changed

+153
-110
lines changed

test/jasmine/tests/pikul_test.js

+153-110
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ var createGraphDiv = require('../assets/create_graph_div');
55
var destroyGraphDiv = require('../assets/destroy_graph_div');
66

77
// Boilerplate taken from axes_test.js
8-
describe('tickmode proportional', function() {
8+
describe('When generating axes w/ `tickmode`:"proportional",', function() {
99
var gd;
1010

1111
beforeEach(function() {
@@ -16,7 +16,7 @@ describe('tickmode proportional', function() {
1616

1717
// These enums are `ticklen`s- it's how DOM analysis differentiates wrt major/minor
1818
// Passed as tickLen argument to specify major or minor tick config
19-
const MAJOR = 202, MINOR = 101;
19+
const MAJOR = 10, MINOR = 5;
2020
function generateTickConfig(tickLen){
2121
// Intentionally configure to produce a single `(x|y)tick` class per tick
2222
// labels and tick marks each produce one, so one or the other
@@ -33,119 +33,162 @@ describe('tickmode proportional', function() {
3333
standardConfig['tickvals'] = tickVals;
3434
return standardConfig;
3535
}
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";
36+
37+
// See comment below for explanation of parameterization
38+
const XMAJOR = 0b0001;
39+
const XMINOR = 0b0010;
40+
const YMAJOR = 0b0100;
41+
const YMINOR = 0b1000;
42+
// Converts binary to list of tick types indicated by binary
43+
function binaryToTickType(bin) {
44+
str = [];
45+
if (bin & XMAJOR) str.push("xMajor");
46+
if (bin & XMINOR) str.push("xMinor");
47+
if (bin & YMAJOR) str.push("yMajor");
48+
if (bin & YMINOR) str.push("yMinor");
49+
if (str.length) {
50+
return str.join(', ');
51+
}
52+
return "";
4253
}
54+
4355
// the var `tickConfig` represents every possible configuration. It is in an int 0-15.
4456
// 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'])
57+
// We add a fourth to switch between linear and log
58+
for(let tickConfig = 1; tickConfig <= 0b1111; tickConfig++) {
59+
var graphTypes = [
60+
{ type:'linear' },
61+
{ type:'log'},
62+
{ type:'date'},
63+
{ type:'category'},
64+
];
65+
for (let graphTypeIndex = 0; graphTypeIndex < graphTypes.length; graphTypeIndex++) {
66+
var xGraphType = graphTypes[graphTypeIndex]; // Only with X for now
67+
(function(tickConfig, xGraphType) { // wrap in func or else it() can't see variable because of javascript closure scope
68+
it('fraction mapping to geometries for config ' + binaryToTickType(tickConfig) , function(done) {
69+
// We will check all four tick sets, these will resolve to true or false:
70+
var xMajor = tickConfig & XMAJOR;
71+
var xMinor = tickConfig & XMINOR;
72+
var yMajor = tickConfig & YMAJOR;
73+
var yMinor = tickConfig & YMINOR;
74+
ticksOff = {ticklen: 0, showticklabels: false};
75+
var xMajorConfig = xMajor ? generateTickConfig(MAJOR) : ticksOff; // generate separate configs for each
76+
var xMinorConfig = xMinor ? generateTickConfig(MINOR) : ticksOff;
77+
var yMajorConfig = yMajor ? generateTickConfig(MAJOR) : ticksOff;
78+
var yMinorConfig = yMinor ? generateTickConfig(MINOR) : ticksOff;
79+
var configInfo = ""
80+
configInfo += xMajor ? "\n " + `xMajor: ${[...new Set(xMajorConfig['tickvals'])].length} unique vals` : "";
81+
configInfo += xMinor ? "\n " + `xMinor: ${[...new Set(xMinorConfig['tickvals'])].length} unique vals` : "";
82+
configInfo += yMajor ? "\n " + `yMajor: ${[...new Set(yMajorConfig['tickvals'])].length} unique vals` : "";
83+
configInfo += yMinor ? "\n " + `yMinor: ${[...new Set(yMinorConfig['tickvals'])].length} unique vals` : "";
84+
Plotly.newPlot(gd, {
85+
data: [{
86+
x: [0, 1],
87+
y: [0, 1]
88+
}],
89+
layout: {
90+
width: 400,
91+
height: 400,
92+
margin: { t: 40, b: 40, l: 40, r: 40, },
93+
...xGraphType,
94+
xaxis: {
95+
autorange: true,
96+
...xMajorConfig, // explode config into this key
97+
minor: xMinorConfig, // set config to this key
98+
},
99+
yaxis: { // same as above
100+
autorange: true,
101+
...yMajorConfig,
102+
minor: yMinorConfig,
103+
},
104+
}}).then(function() {
105+
// This regex is for extracting geometric position of... should have used getBoundingClientRect()
106+
//
107+
// regex: `.source` converts to string, laid out this way to make for easier reading
108+
const funcName = "translate" + /\(/.source; // literally simplest way to regex '('
109+
const integerPart = /\d+/.source; // numbers left of decimal
110+
const fractionalPart = /(?:\.\d+)?/.source; // decimal + numbers to right
111+
const floatNum = integerPart + fractionalPart; // all together
112+
const any = /.+/.source;
113+
const close = /\)/.source;
114+
const reX = new RegExp(funcName + '(' + floatNum + '),' + any + close); // parens are capture not fn()
115+
const reY = new RegExp(funcName + any + ',(' + floatNum + ')' + close); // parens are capture not fn()
112116

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);
117+
for(let runNumber = 0b1; runNumber <= 0b1000; runNumber <<= 0b1) { // Check all ticks on all axes ☺
118+
var runInfo = "\n Checking: " + binaryToTickType(runNumber);
119+
var elementName = "";
120+
var targetConfig;
121+
var re;
122+
if(runNumber & xMajor) { // ie. (this run wants xMajor) & (xMajor was set in config above)
123+
elementName = "xtick";
124+
targetConfig = xMajorConfig;
125+
re = reX;
126+
} else if(runNumber & xMinor) {
127+
elementName = "xtick";
128+
targetConfig = xMinorConfig;
129+
re = reX;
130+
} else if(runNumber & yMajor) {
131+
elementName = "ytick";
132+
targetConfig = yMajorConfig;
133+
re = reY;
134+
} else if(runNumber & yMinor) {
135+
elementName = "ytick";
136+
targetConfig = yMinorConfig;
137+
re = reY;
138+
} else continue; // This run would have been to check ticks that don't exist
139+
140+
var tickElements = document.getElementsByClassName(elementName);
141+
var tickValsUnique = [...new Set(targetConfig['tickvals'])];
142+
var expectedTickLen = String(targetConfig['ticklen'])
143+
144+
145+
// Filter out major/minor and grab geometry
146+
transformVals = []; // "transform" ie the positional property
147+
for(let i = 0; i < tickElements.length; i++) {
148+
if(!tickElements[i].getAttribute("d").endsWith(expectedTickLen)) continue;
149+
var translate = tickElements[i].getAttribute("transform");
150+
transformVals.push(Number(translate.match(re)[1]));
151+
}
152+
153+
var debugInfo = "\n " + `tickElements: (${tickElements.length}) ${tickElements}` + "\n " +
154+
`tickVals/Unique: (${targetConfig['tickvals'].length}/${tickValsUnique.length}) {tickValsUnique}`;
155+
156+
expect(transformVals.length).toBe(tickValsUnique.length,
157+
"filtered tick elements vs tickvals failed" + runInfo + configInfo + debugInfo);
158+
if(transformVals.length < 2) return; // Can't test proportions with < 2 ticks (since no fixed reference)
159+
160+
161+
// To test geometries without using fixed point or data values
162+
// We can check consistency of y = mx+b
163+
// if x = 0 then y = b, but we may not have a 0 valued x
164+
// m = (y1 - y2) / (x1 - x2)
165+
// b = y1 - mx1
166+
y = transformVals;
167+
x = tickValsUnique;
168+
var m, b;
169+
var b_index = x.indexOf(0);
170+
171+
m = (y[0] - y[1]) / (x[0] - x[1]);
172+
b = (b_index != -1) ? b = y[b_index] : y[0] - m*x[0];
173+
174+
calculatedY = [];
175+
for(let i = 0; i < x.length; i++) calculatedY.push(m*x[i] + b);
176+
128177

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
178+
/* **** Close this comment line to manually inspect output -->
179+
yout = [];
180+
ycalcout = [];
181+
for (i = 0; i < Math.min(x.length, 10); i++) {
182+
yout.push(Number.parseFloat(y[i]).toFixed(2));
183+
ycalcout.push(Number.parseFloat(calculatedY[i]).toFixed(2));
184+
}
185+
console.log(yout);
186+
console.log(ycalcout);/* */
187+
expect(y).toBeCloseToArray(calculatedY, `y=mx+b test failed comparing\n${y}\n${calculatedY}`);
145188
}
146-
}
147-
}).then(done, done.fail);
148-
});
149-
})(tickConfig);
189+
}).then(done, done.fail);
190+
});
191+
})(tickConfig, xGraphType);
192+
}
150193
}
151194
});

0 commit comments

Comments
 (0)