<commit_before>var Plotly = require('@lib/index');
var Plots = require('@src/plots/plots');
var Lib = require('@src/lib');
var Registry = require('@src/registry');

var d3Select = require('../../strict-d3').select;
var d3SelectAll = require('../../strict-d3').selectAll;
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var supplyAllDefaults = require('../assets/supply_defaults');


describe('Test Plots', function() {
    'use strict';

    describe('Plots.supplyDefaults', function() {
        it('should not coerce `minsize` when `uniformtext.mode` is *false*', function() {
            var gd = {};
            supplyAllDefaults(gd);
            expect(gd._fullLayout.uniformtext.minsize).toBe(undefined);
        });

        it('should not accept ranges where the end is not greater than the start', function() {
            var gd = {
                data: [{
                    type: 'pie',
                    domain: {
                        x: [0.4, 0],
                        y: [0.5, 0.5]
                    },
                    values: [1, 2, 3, 4],
                    labels: ['a', 'b', 'c', 'd'],
                    text: ['text', 'should', 'be', 'inside']
                }]
            };

            supplyAllDefaults(gd);
            expect(gd._fullData[0].domain.x[0]).toBe(0);
            expect(gd._fullData[0].domain.y[1]).toBe(1);
            expect(gd._fullData[0].domain.x[0]).toBe(0);
            expect(gd._fullData[0].domain.y[1]).toBe(1);
        });

        it('should not throw an error when gd is a plain object', function() {
            var height = 100;
            var gd = {
                layout: {
                    height: height
                }
            };

            supplyAllDefaults(gd);
            expect(gd.layout.height).toBe(height);
            expect(gd._fullLayout).toBeDefined();
            expect(gd._fullLayout.height).toBe(height);
            expect(gd._fullLayout.width).toBe(Plots.layoutAttributes.width.dflt);
            expect(gd._fullData).toBeDefined();
        });

        it('should relink private keys', function() {
            var oldFullData = [{
                type: 'scatter3d',
                z: [1, 2, 3]
            }, {
                type: 'contour',
                _empties: [1, 2, 3]
            }];
            oldFullData.forEach(function(trace) { trace._fullInput = trace; });

            var oldFullLayout = {
                _plots: { xy: { plot: {} } },
                xaxis: { c2p: function() {}, layer: 'above traces' },
                yaxis: { _m: 20, layer: 'above traces' },
                scene: { _scene: {} },
                annotations: [{ _min: 10, }, { _max: 20 }],
                someFunc: function() {}
            };

            Lib.extendFlat(oldFullLayout._plots.xy, {
                xaxis: oldFullLayout.xaxis,
                yaxis: oldFullLayout.yaxis
            });

            var newData = [{
                type: 'scatter3d',
                z: [1, 2, 3, 4]
            }, {
                type: 'contour',
                z: [[1, 2, 3], [2, 3, 4]]
            }];

            var newLayout = {
                annotations: [{}, {}, {}]
            };

            var gd = {
                _fullData: oldFullData,
                _fullLayout: oldFullLayout,
                data: newData,
                layout: newLayout
            };

            supplyAllDefaults(gd);

            expect(gd._fullData[0].z).toBe(newData[0].z);
            expect(gd._fullData[1].z).toBe(newData[1].z);
            expect(gd._fullData[1]._empties).toBe(oldFullData[1]._empties);
            expect(gd._fullLayout.scene._scene).toBe(oldFullLayout.scene._scene);
            expect(gd._fullLayout._plots.plot).toBe(oldFullLayout._plots.plot);
            expect(gd._fullLayout.annotations[0]._min).toBe(oldFullLayout.annotations[0]._min);
            expect(gd._fullLayout.annotations[1]._max).toBe(oldFullLayout.annotations[1]._max);
            expect(gd._fullLayout.someFunc).toBe(oldFullLayout.someFunc);

            expect(gd._fullLayout.xaxis.c2p)
                .not.toBe(oldFullLayout.xaxis.c2p, '(set during setConvert)');
            expect(gd._fullLayout.yaxis._m)
                .toBe(oldFullLayout.yaxis._m, '(we don\'t run ax.setScale here)');
        });

        it('should include the correct reference to user data', function() {
            var trace0 = { y: [1, 2, 3] };
            var trace1 = { y: [5, 2, 3] };

            var data = [trace0, trace1];
            var gd = { data: data };

            supplyAllDefaults(gd);

            expect(gd.data).toBe(data);

            expect(gd._fullData[0].index).toEqual(0);
            expect(gd._fullData[1].index).toEqual(1);

            expect(gd._fullData[0]._expandedIndex).toEqual(0);
            expect(gd._fullData[1]._expandedIndex).toEqual(1);

            expect(gd._fullData[0]._input).toBe(trace0);
            expect(gd._fullData[1]._input).toBe(trace1);

            expect(gd._fullData[0]._fullInput).toBe(gd._fullData[0]);
            expect(gd._fullData[1]._fullInput).toBe(gd._fullData[1]);

            expect(gd._fullData[0]._expandedInput).toBe(gd._fullData[0]);
            expect(gd._fullData[1]._expandedInput).toBe(gd._fullData[1]);
        });

        function testSanitizeMarginsHasBeenCalledOnlyOnce(gd) {
            spyOn(Plots, 'sanitizeMargins').and.callThrough();
            supplyAllDefaults(gd);
            expect(Plots.sanitizeMargins).toHaveBeenCalledTimes(1);
        }

        it('should call sanitizeMargins only once when both width and height are defined', function() {
            var gd = {
                layout: {
                    width: 100,
                    height: 100
                }
            };

            testSanitizeMarginsHasBeenCalledOnlyOnce(gd);
        });

        it('should call sanitizeMargins only once when autosize is false', function() {
            var gd = {
                layout: {
                    autosize: false,
                    height: 100
                }
            };

            testSanitizeMarginsHasBeenCalledOnlyOnce(gd);
        });

        it('should call sanitizeMargins only once when autosize is true', function() {
            var gd = {
                layout: {
                    autosize: true,
                    height: 100
                }
            };

            testSanitizeMarginsHasBeenCalledOnlyOnce(gd);
        });

        it('should accept trace uids as non-empty strings or numbers', function() {
            var gd = {
                data: [{}, {uid: false}, {uid: 'my-id'}, {uid: ''}, {uid: 0}, {uid: 2}]
            };
            supplyAllDefaults(gd);

            var traceUids = gd._fullLayout._traceUids;
            expect(traceUids.length).toBe(6, '# of trace uids');
            expect(traceUids[2]).toBe('my-id');
            expect(traceUids[4]).toBe('0');
            expect(traceUids[5]).toBe('2');

            var indicesOfRandomUid = [0, 1, 3];
            indicesOfRandomUid.forEach(function(ind) {
                var msg = 'fullData[' + ind + '].uid';
                expect(typeof traceUids[ind]).toBe('string', msg + 'is a string');
                expect(traceUids[ind].length).toBe(6, msg + 'is of length 6');
            });
        });
    });

    describe('Plots.supplyLayoutGlobalDefaults should', function() {
        var layoutIn,
            layoutOut,
            expected;

        var formatObj = require('@src/locale-en').format;

        function supplyLayoutDefaults(layoutIn, layoutOut) {
            layoutOut._dfltTitle = {
                plot: 'ppplot'
            };
            return Plots.supplyLayoutGlobalDefaults(layoutIn, layoutOut, formatObj);
        }

        beforeEach(function() {
            layoutOut = {};
        });

        it('should sanitize margins when they are wider than the plot', function() {
            layoutIn = {
                width: 500,
                height: 500,
                margin: {
                    l: 400,
                    r: 200
                }
            };
            expected = {
                l: 332,
                r: 166,
                t: 100,
                b: 80,
                pad: 0,
                autoexpand: true
            };

            supplyLayoutDefaults(layoutIn, layoutOut);
            expect(layoutOut.margin).toEqual(expected);
        });

        it('should sanitize margins when they are taller than the plot', function() {
            layoutIn = {
                width: 500,
                height: 500,
                margin: {
                    l: 400,
                    r: 200,
                    t: 300,
                    b: 500
                }
            };
            expected = {
                l: 332,
                r: 166,
                t: 187,
                b: 311,
                pad: 0,
                autoexpand: true
            };

            supplyLayoutDefaults(layoutIn, layoutOut);
            expect(layoutOut.margin).toEqual(expected);
        });
    });

    describe('Plots.supplyTraceDefaults', function() {
        var supplyTraceDefaults = Plots.supplyTraceDefaults;
        var layout = {_subplots: {cartesian: ['xy'], xaxis: ['x'], yaxis: ['y']}};

        var traceIn, traceOut;

        describe('should coerce hoverinfo', function() {
            it('without *name* for single-trace graphs by default', function() {
                layout._dataLength = 1;

                traceIn = {};
                traceOut = supplyTraceDefaults(traceIn, {type: 'scatter'}, 0, layout);
                expect(traceOut.hoverinfo).toEqual('x+y+z+text');

                traceIn = { hoverinfo: 'name' };
                traceOut = supplyTraceDefaults(traceIn, {type: 'scatter'}, 0, layout);
                expect(traceOut.hoverinfo).toEqual('name');
            });

            it('with *name* for multi-trace graphs by default', function() {
                layout._dataLength = 2;

                traceIn = {};
                traceOut = supplyTraceDefaults(traceIn, {type: 'scatter'}, 0, layout);
                expect(traceOut.hoverinfo).toEqual('all');

                traceIn = { hoverinfo: 'name' };
                traceOut = supplyTraceDefaults(traceIn, {type: 'scatter'}, 0, layout);
                expect(traceOut.hoverinfo).toEqual('name');
            });

            it('only if hovertemplate is not defined', function() {
                layout._dataLength = 1;

                traceIn = {};
                traceOut = supplyTraceDefaults(traceIn, {type: 'scatter', hovertemplate: '%{y}'}, 0, layout);
                expect(traceOut.hoverinfo).toBeUndefined();
            });
        });
    });

    describe('Plots.supplyTransformDefaults', function() {
        it('should accept an empty layout when transforms present', function() {
            var traceOut = {y: [1], _length: 1};
            Plots.supplyTransformDefaults({}, traceOut, {
                _globalTransforms: [{ type: 'filter'}]
            });

            // This isn't particularly interesting. More relevant is that
            // the above supplyTransformDefaults call didn't fail due to
            // missing transformModules data.
            expect(traceOut.transforms.length).toEqual(1);
        });
    });

    describe('Plots.resize:', function() {
        var gd;

        describe('on graph div DOM style changes', function() {
            beforeAll(function(done) {
                gd = createGraphDiv();

                Plotly.newPlot(gd, [{ x: [1, 2, 3], y: [2, 3, 4] }])
                    .then(function() {
                        gd.style.width = '400px';
                        gd.style.height = '400px';

                        return Plots.resize(gd);
                    })
                    .then(done);
            });

            afterAll(destroyGraphDiv);

            it('should resize the plot clip', function() {
                var uid = gd._fullLayout._uid;

                var plotClip = document.getElementById('clip' + uid + 'xyplot');
                var clipRect = plotClip.children[0];
                var clipWidth = +clipRect.getAttribute('width');
                var clipHeight = +clipRect.getAttribute('height');

                expect(clipWidth).toBe(240);
                expect(clipHeight).toBe(220);
            });

            it('should resize the main svgs', function() {
                var mainSvgs = document.getElementsByClassName('main-svg');
                expect(mainSvgs.length).toBe(3);

                for(var i = 0; i < mainSvgs.length; i++) {
                    var svg = mainSvgs[i];
                    var svgWidth = +svg.getAttribute('width');
                    var svgHeight = +svg.getAttribute('height');

                    expect(svgWidth).toBe(400);
                    expect(svgHeight).toBe(400);
                }
            });

            it('should update the axis scales', function() {
                var mainSvgs = document.getElementsByClassName('main-svg');
                expect(mainSvgs.length).toBe(3);

                var fullLayout = gd._fullLayout;
                var plotinfo = fullLayout._plots.xy;

                expect(fullLayout.xaxis._length).toEqual(240);
                expect(fullLayout.yaxis._length).toEqual(220);

                expect(plotinfo.xaxis._length).toEqual(240);
                expect(plotinfo.yaxis._length).toEqual(220);
            });

            it('should allow resizing by plot ID', function(done) {
                var mainSvgs = document.getElementsByClassName('main-svg');
                expect(mainSvgs.length).toBe(3);

                expect(typeof gd.id).toBe('string');
                expect(gd.id).toBeTruthy();

                Plots.resize(gd.id)
                .then(done, done.fail);
            });
        });

        describe('on styled graph div', function() {
            afterEach(destroyGraphDiv);

            it('should sanitize margins', function(done) {
                gd = createGraphDiv();
                gd.style.width = '150px';
                gd.style.height = '150px';

                function _assert(exp) {
                    var margin = gd._fullLayout.margin || {};
                    for(var k in exp) {
                        expect(margin[k]).toBe(exp[k], ' - margin.' + k);
                    }
                }

                Plotly.newPlot(gd, [], {})
                    .then(function() { _assert({l: 74, r: 74, t: 82, b: 66}); })
                    .then(function() { return Plots.resize(gd); })
                    .then(function() { _assert({l: 74, r: 74, t: 82, b: 66}); })
                    .then(done, done.fail);
            });
        });

        describe('returns Promises', function() {
            afterEach(destroyGraphDiv);

            it('should resolve them all', function(done) {
                gd = createGraphDiv();
                var p = [];
                Plotly.newPlot(gd, [{y: [5, 2, 5]}])
                    .then(function() {
                        gd.style.width = '500px';
                        gd.style.height = '500px';
                        p.push(Plots.resize(gd));
                        p.push(Plots.resize(gd));
                        p.push(Plots.resize(gd));
                        return Promise.all(p);
                    })
                    .then(function(v) {
                        // Make sure they all resolve to the same value
                        expect(v[0]).toEqual(v[1]);
                        expect(v[1]).toEqual(v[2]);
                    })
                    .then(done, done.fail);
            });
        });
    });

    describe('Plots.purge', function() {
        var gd;
<commit_msg>use Plotly.plots from the API in plots tests<commit_after>var Plotly = require('@lib/index');
var Plots = require('@src/plots/plots');
var Lib = require('@src/lib');
var Registry = require('@src/registry');

var d3Select = require('../../strict-d3').select;
var d3SelectAll = require('../../strict-d3').selectAll;
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var supplyAllDefaults = require('../assets/supply_defaults');


describe('Test Plots', function() {
    'use strict';

    describe('Plots.supplyDefaults', function() {
        it('should not coerce `minsize` when `uniformtext.mode` is *false*', function() {
            var gd = {};
            supplyAllDefaults(gd);
            expect(gd._fullLayout.uniformtext.minsize).toBe(undefined);
        });

        it('should not accept ranges where the end is not greater than the start', function() {
            var gd = {
                data: [{
                    type: 'pie',
                    domain: {
                        x: [0.4, 0],
                        y: [0.5, 0.5]
                    },
                    values: [1, 2, 3, 4],
                    labels: ['a', 'b', 'c', 'd'],
                    text: ['text', 'should', 'be', 'inside']
                }]
            };

            supplyAllDefaults(gd);
            expect(gd._fullData[0].domain.x[0]).toBe(0);
            expect(gd._fullData[0].domain.y[1]).toBe(1);
            expect(gd._fullData[0].domain.x[0]).toBe(0);
            expect(gd._fullData[0].domain.y[1]).toBe(1);
        });

        it('should not throw an error when gd is a plain object', function() {
            var height = 100;
            var gd = {
                layout: {
                    height: height
                }
            };

            supplyAllDefaults(gd);
            expect(gd.layout.height).toBe(height);
            expect(gd._fullLayout).toBeDefined();
            expect(gd._fullLayout.height).toBe(height);
            expect(gd._fullLayout.width).toBe(Plots.layoutAttributes.width.dflt);
            expect(gd._fullData).toBeDefined();
        });

        it('should relink private keys', function() {
            var oldFullData = [{
                type: 'scatter3d',
                z: [1, 2, 3]
            }, {
                type: 'contour',
                _empties: [1, 2, 3]
            }];
            oldFullData.forEach(function(trace) { trace._fullInput = trace; });

            var oldFullLayout = {
                _plots: { xy: { plot: {} } },
                xaxis: { c2p: function() {}, layer: 'above traces' },
                yaxis: { _m: 20, layer: 'above traces' },
                scene: { _scene: {} },
                annotations: [{ _min: 10, }, { _max: 20 }],
                someFunc: function() {}
            };

            Lib.extendFlat(oldFullLayout._plots.xy, {
                xaxis: oldFullLayout.xaxis,
                yaxis: oldFullLayout.yaxis
            });

            var newData = [{
                type: 'scatter3d',
                z: [1, 2, 3, 4]
            }, {
                type: 'contour',
                z: [[1, 2, 3], [2, 3, 4]]
            }];

            var newLayout = {
                annotations: [{}, {}, {}]
            };

            var gd = {
                _fullData: oldFullData,
                _fullLayout: oldFullLayout,
                data: newData,
                layout: newLayout
            };

            supplyAllDefaults(gd);

            expect(gd._fullData[0].z).toBe(newData[0].z);
            expect(gd._fullData[1].z).toBe(newData[1].z);
            expect(gd._fullData[1]._empties).toBe(oldFullData[1]._empties);
            expect(gd._fullLayout.scene._scene).toBe(oldFullLayout.scene._scene);
            expect(gd._fullLayout._plots.plot).toBe(oldFullLayout._plots.plot);
            expect(gd._fullLayout.annotations[0]._min).toBe(oldFullLayout.annotations[0]._min);
            expect(gd._fullLayout.annotations[1]._max).toBe(oldFullLayout.annotations[1]._max);
            expect(gd._fullLayout.someFunc).toBe(oldFullLayout.someFunc);

            expect(gd._fullLayout.xaxis.c2p)
                .not.toBe(oldFullLayout.xaxis.c2p, '(set during setConvert)');
            expect(gd._fullLayout.yaxis._m)
                .toBe(oldFullLayout.yaxis._m, '(we don\'t run ax.setScale here)');
        });

        it('should include the correct reference to user data', function() {
            var trace0 = { y: [1, 2, 3] };
            var trace1 = { y: [5, 2, 3] };

            var data = [trace0, trace1];
            var gd = { data: data };

            supplyAllDefaults(gd);

            expect(gd.data).toBe(data);

            expect(gd._fullData[0].index).toEqual(0);
            expect(gd._fullData[1].index).toEqual(1);

            expect(gd._fullData[0]._expandedIndex).toEqual(0);
            expect(gd._fullData[1]._expandedIndex).toEqual(1);

            expect(gd._fullData[0]._input).toBe(trace0);
            expect(gd._fullData[1]._input).toBe(trace1);

            expect(gd._fullData[0]._fullInput).toBe(gd._fullData[0]);
            expect(gd._fullData[1]._fullInput).toBe(gd._fullData[1]);

            expect(gd._fullData[0]._expandedInput).toBe(gd._fullData[0]);
            expect(gd._fullData[1]._expandedInput).toBe(gd._fullData[1]);
        });

        function testSanitizeMarginsHasBeenCalledOnlyOnce(gd) {
            spyOn(Plots, 'sanitizeMargins').and.callThrough();
            supplyAllDefaults(gd);
            expect(Plots.sanitizeMargins).toHaveBeenCalledTimes(1);
        }

        it('should call sanitizeMargins only once when both width and height are defined', function() {
            var gd = {
                layout: {
                    width: 100,
                    height: 100
                }
            };

            testSanitizeMarginsHasBeenCalledOnlyOnce(gd);
        });

        it('should call sanitizeMargins only once when autosize is false', function() {
            var gd = {
                layout: {
                    autosize: false,
                    height: 100
                }
            };

            testSanitizeMarginsHasBeenCalledOnlyOnce(gd);
        });

        it('should call sanitizeMargins only once when autosize is true', function() {
            var gd = {
                layout: {
                    autosize: true,
                    height: 100
                }
            };

            testSanitizeMarginsHasBeenCalledOnlyOnce(gd);
        });

        it('should accept trace uids as non-empty strings or numbers', function() {
            var gd = {
                data: [{}, {uid: false}, {uid: 'my-id'}, {uid: ''}, {uid: 0}, {uid: 2}]
            };
            supplyAllDefaults(gd);

            var traceUids = gd._fullLayout._traceUids;
            expect(traceUids.length).toBe(6, '# of trace uids');
            expect(traceUids[2]).toBe('my-id');
            expect(traceUids[4]).toBe('0');
            expect(traceUids[5]).toBe('2');

            var indicesOfRandomUid = [0, 1, 3];
            indicesOfRandomUid.forEach(function(ind) {
                var msg = 'fullData[' + ind + '].uid';
                expect(typeof traceUids[ind]).toBe('string', msg + 'is a string');
                expect(traceUids[ind].length).toBe(6, msg + 'is of length 6');
            });
        });
    });

    describe('Plots.supplyLayoutGlobalDefaults should', function() {
        var layoutIn,
            layoutOut,
            expected;

        var formatObj = require('@src/locale-en').format;

        function supplyLayoutDefaults(layoutIn, layoutOut) {
            layoutOut._dfltTitle = {
                plot: 'ppplot'
            };
            return Plots.supplyLayoutGlobalDefaults(layoutIn, layoutOut, formatObj);
        }

        beforeEach(function() {
            layoutOut = {};
        });

        it('should sanitize margins when they are wider than the plot', function() {
            layoutIn = {
                width: 500,
                height: 500,
                margin: {
                    l: 400,
                    r: 200
                }
            };
            expected = {
                l: 332,
                r: 166,
                t: 100,
                b: 80,
                pad: 0,
                autoexpand: true
            };

            supplyLayoutDefaults(layoutIn, layoutOut);
            expect(layoutOut.margin).toEqual(expected);
        });

        it('should sanitize margins when they are taller than the plot', function() {
            layoutIn = {
                width: 500,
                height: 500,
                margin: {
                    l: 400,
                    r: 200,
                    t: 300,
                    b: 500
                }
            };
            expected = {
                l: 332,
                r: 166,
                t: 187,
                b: 311,
                pad: 0,
                autoexpand: true
            };

            supplyLayoutDefaults(layoutIn, layoutOut);
            expect(layoutOut.margin).toEqual(expected);
        });
    });

    describe('Plots.supplyTraceDefaults', function() {
        var supplyTraceDefaults = Plots.supplyTraceDefaults;
        var layout = {_subplots: {cartesian: ['xy'], xaxis: ['x'], yaxis: ['y']}};

        var traceIn, traceOut;

        describe('should coerce hoverinfo', function() {
            it('without *name* for single-trace graphs by default', function() {
                layout._dataLength = 1;

                traceIn = {};
                traceOut = supplyTraceDefaults(traceIn, {type: 'scatter'}, 0, layout);
                expect(traceOut.hoverinfo).toEqual('x+y+z+text');

                traceIn = { hoverinfo: 'name' };
                traceOut = supplyTraceDefaults(traceIn, {type: 'scatter'}, 0, layout);
                expect(traceOut.hoverinfo).toEqual('name');
            });

            it('with *name* for multi-trace graphs by default', function() {
                layout._dataLength = 2;

                traceIn = {};
                traceOut = supplyTraceDefaults(traceIn, {type: 'scatter'}, 0, layout);
                expect(traceOut.hoverinfo).toEqual('all');

                traceIn = { hoverinfo: 'name' };
                traceOut = supplyTraceDefaults(traceIn, {type: 'scatter'}, 0, layout);
                expect(traceOut.hoverinfo).toEqual('name');
            });

            it('only if hovertemplate is not defined', function() {
                layout._dataLength = 1;

                traceIn = {};
                traceOut = supplyTraceDefaults(traceIn, {type: 'scatter', hovertemplate: '%{y}'}, 0, layout);
                expect(traceOut.hoverinfo).toBeUndefined();
            });
        });
    });

    describe('Plots.supplyTransformDefaults', function() {
        it('should accept an empty layout when transforms present', function() {
            var traceOut = {y: [1], _length: 1};
            Plots.supplyTransformDefaults({}, traceOut, {
                _globalTransforms: [{ type: 'filter'}]
            });

            // This isn't particularly interesting. More relevant is that
            // the above supplyTransformDefaults call didn't fail due to
            // missing transformModules data.
            expect(traceOut.transforms.length).toEqual(1);
        });
    });

    describe('Plots.resize:', function() {
        var gd;

        describe('on graph div DOM style changes', function() {
            beforeAll(function(done) {
                gd = createGraphDiv();

                Plotly.newPlot(gd, [{ x: [1, 2, 3], y: [2, 3, 4] }])
                    .then(function() {
                        gd.style.width = '400px';
                        gd.style.height = '400px';

                        return Plotly.Plots.resize(gd);
                    })
                    .then(done);
            });

            afterAll(destroyGraphDiv);

            it('should resize the plot clip', function() {
                var uid = gd._fullLayout._uid;

                var plotClip = document.getElementById('clip' + uid + 'xyplot');
                var clipRect = plotClip.children[0];
                var clipWidth = +clipRect.getAttribute('width');
                var clipHeight = +clipRect.getAttribute('height');

                expect(clipWidth).toBe(240);
                expect(clipHeight).toBe(220);
            });

            it('should resize the main svgs', function() {
                var mainSvgs = document.getElementsByClassName('main-svg');
                expect(mainSvgs.length).toBe(3);

                for(var i = 0; i < mainSvgs.length; i++) {
                    var svg = mainSvgs[i];
                    var svgWidth = +svg.getAttribute('width');
                    var svgHeight = +svg.getAttribute('height');

                    expect(svgWidth).toBe(400);
                    expect(svgHeight).toBe(400);
                }
            });

            it('should update the axis scales', function() {
                var mainSvgs = document.getElementsByClassName('main-svg');
                expect(mainSvgs.length).toBe(3);

                var fullLayout = gd._fullLayout;
                var plotinfo = fullLayout._plots.xy;

                expect(fullLayout.xaxis._length).toEqual(240);
                expect(fullLayout.yaxis._length).toEqual(220);

                expect(plotinfo.xaxis._length).toEqual(240);
                expect(plotinfo.yaxis._length).toEqual(220);
            });

            it('should allow resizing by plot ID', function(done) {
                var mainSvgs = document.getElementsByClassName('main-svg');
                expect(mainSvgs.length).toBe(3);

                expect(typeof gd.id).toBe('string');
                expect(gd.id).toBeTruthy();

                Plotly.Plots.resize(gd.id)
                .then(done, done.fail);
            });
        });

        describe('on styled graph div', function() {
            afterEach(destroyGraphDiv);

            it('should sanitize margins', function(done) {
                gd = createGraphDiv();
                gd.style.width = '150px';
                gd.style.height = '150px';

                function _assert(exp) {
                    var margin = gd._fullLayout.margin || {};
                    for(var k in exp) {
                        expect(margin[k]).toBe(exp[k], ' - margin.' + k);
                    }
                }

                Plotly.newPlot(gd, [], {})
                    .then(function() { _assert({l: 74, r: 74, t: 82, b: 66}); })
                    .then(function() { return Plotly.Plots.resize(gd); })
                    .then(function() { _assert({l: 74, r: 74, t: 82, b: 66}); })
                    .then(done, done.fail);
            });
        });

        describe('returns Promises', function() {
            afterEach(destroyGraphDiv);

            it('should resolve them all', function(done) {
                gd = createGraphDiv();
                var p = [];
                Plotly.newPlot(gd, [{y: [5, 2, 5]}])
                    .then(function() {
                        gd.style.width = '500px';
                        gd.style.height = '500px';
                        p.push(Plotly.Plots.resize(gd));
                        p.push(Plotly.Plots.resize(gd));
                        p.push(Plotly.Plots.resize(gd));
                        return Promise.all(p);
                    })
                    .then(function(v) {
                        // Make sure they all resolve to the same value
                        expect(v[0]).toEqual(v[1]);
                        expect(v[1]).toEqual(v[2]);
                    })
                    .then(done, done.fail);
            });
        });
    });

    describe('Plots.purge', function() {
        var gd;

{'fraction_non_alphanumeric': 0.13288733942648953, 'fraction_numerical': 0.016646251452621, 'mean_word_length': 1.456221553652704, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5980247', 'n_tokens_mistral': 9306, 'n_tokens_neox': 8442, 'n_words': 1689}