gristlabs_grist-core/test/nbrowser/ChartView1.ts
Jarosław Sadziński 8162a6d959 (core) Treating x axis as category for bar chart
Summary: Forcing category xaxis type for bar chart when labels are not numerical.

Test Plan: Added new and updated existing

Reviewers: paulfitz

Reviewed By: paulfitz

Differential Revision: https://phab.getgrist.com/D4297
2024-07-23 15:41:38 +02:00

846 lines
32 KiB
TypeScript

import {UserAPI} from 'app/common/UserAPI';
import {assert, driver, Key} from 'mocha-webdriver';
import {addYAxis, checkAxisConfig, checkAxisRange, findYAxis, getAxisTitle, getChartData,
removeYAxis, selectChartType, selectXAxis,
setSplitSeries} from 'test/nbrowser/chartViewTestUtils';
import * as gu from 'test/nbrowser/gristUtils';
import {setupTestSuite} from 'test/nbrowser/testUtils';
describe('ChartView1', function() {
this.timeout(20000);
const cleanup = setupTestSuite();
let api: UserAPI;
let doc: any;
before(async function() {
const session = await gu.session().teamSite.login();
doc = await session.tempDoc(cleanup, 'ChartData.grist');
api = session.createHomeApi();
});
gu.bigScreen();
afterEach(() => gu.checkForErrors());
it('should treat text as category', async function() {
const revert = await gu.begin();
await gu.sendActions([
['AddTable', 'Text', [
{id: 'X', type: 'Int'},
{id: 'Y', type: 'Int'}
]],
['AddRecord', 'Text', null, {X: 1, Y: 1}],
['AddRecord', 'Text', null, {X: 100, Y: 2}],
['AddRecord', 'Text', null, {X: 101, Y: 3}],
['AddRecord', 'Text', null, {X: 102, Y: 4}],
]);
await gu.openPage('Text');
await gu.addNewSection('Chart', 'Text');
const layout = () => getChartData().then(d => d.layout);
await gu.waitToPass(async () => {
// Check to make sure initial values are correct.
assert.deepEqual((await layout()).xaxis.type, 'linear');
});
// Now convert X to text.
await gu.sendActions([
['ModifyColumn', 'Text', 'X', {type: 'Text'}],
]);
assert.deepEqual((await layout()).xaxis.type, 'category');
// Invert the chart.
await gu.selectSectionByTitle('Text Chart');
await gu.toggleSidePanel('right', 'open');
await driver.find('.test-chart-orientation .test-select-open').click();
await driver.findContent('.test-select-menu', 'Horizontal').click();
await gu.waitForServer();
assert.deepEqual((await layout()).yaxis.type, 'category');
assert.deepEqual((await layout()).xaxis.type, 'linear');
await revert();
await gu.toggleSidePanel('right', 'close');
});
it('should allow adding and removing chart viewsections', async function() {
// Starting out with one section
assert.lengthOf(await driver.findAll('.test-gristdoc .view_leaf'), 1);
// Add a new chart section
await gu.addNewSection(/Chart/, /ChartData/);
// Check that there are now two sections
assert.lengthOf(await driver.findAll('.test-gristdoc .view_leaf'), 2);
// Delete the newly added one
await gu.openSectionMenu('viewLayout', 'CHARTDATA Chart');
await driver.find('.test-section-delete').click();
await gu.waitForServer();
// Check that there is now only one section
assert.lengthOf(await driver.findAll('.test-gristdoc .view_leaf'), 1);
});
it('should display a bar chart by default', async function() {
// Add a new chart section, and make sure it has focus
await gu.addNewSection(/Chart/, /ChartData/);
const section = await gu.getSection('CHARTDATA Chart');
assert.equal(await section.matches('.active_section'), true);
const chartDom = await section.find('.test-chart-container');
assert.equal(await chartDom.isDisplayed(), true);
const data = (await getChartData(chartDom)).data;
assert.deepEqual(data[0].type, 'bar');
assert.deepEqual(data[0].x, [ 6, 5, 4, 3, 2, 1 ]);
assert.deepEqual(data[0].y, [ 1, 2, 3, 4, 5, 6 ]);
});
it('should allow viewing raw data underlying chart', async function() {
// No raw data overlay at first
assert.isFalse(await driver.find('.test-raw-data-overlay').isPresent());
// Show raw data overlay
await gu.openSectionMenu('viewLayout');
await driver.find('.test-show-raw-data').click();
// Test that overlay is showed.
assert.isTrue(await driver.findWait('.test-raw-data-overlay', 100).isDisplayed());
// Test that the widget menu doesn't have the raw data option any more
await gu.openSectionMenu('viewLayout');
assert.isTrue(await driver.findContentWait('.grist-floating-menu li', 'Print widget', 100).isDisplayed());
assert.isFalse(await driver.findContent('.grist-floating-menu li', 'Show raw data').isPresent());
// Go back and confirm that the overlay is gone again
await driver.find('.test-raw-data-close-button').click();
assert.isFalse(await driver.find('.test-raw-data-overlay').isPresent());
// Open once again and close by escaping.
await gu.openSectionMenu('viewLayout');
await driver.find('.test-show-raw-data').click();
assert.isTrue(await driver.findWait('.test-raw-data-overlay', 100).isDisplayed());
await gu.sendKeys(Key.ESCAPE);
assert.isFalse(await driver.find('.test-raw-data-overlay').isPresent());
});
it('should update as the underlying data changes', async function() {
await gu.getCell({section: 'ChartData', col: 0, rowNum: 1}).click();
await driver.sendKeys(Key.ENTER, '1', Key.ENTER); // Change from 6 to 61
await gu.waitForServer();
const chartDom = await driver.find('.test-chart-container');
let data = (await getChartData(chartDom)).data;
assert.deepEqual(data[0].type, 'bar');
assert.deepEqual(data[0].x, [ 61, 5, 4, 3, 2, 1 ]);
assert.deepEqual(data[0].y, [ 1, 2, 3, 4, 5, 6 ]);
await gu.getCell({section: 'ChartData', col: 1, rowNum: 1}).click();
await driver.sendKeys(Key.ENTER, '6', Key.ENTER); // Change from 1 to 16
await gu.waitForServer();
data = (await getChartData(chartDom)).data;
assert.deepEqual(data[0].type, 'bar');
assert.deepEqual(data[0].x, [ 61, 5, 4, 3, 2, 1 ]);
assert.deepEqual(data[0].y, [ 16, 2, 3, 4, 5, 6 ]);
});
it('should skip empty points', async function() {
const chartDom = await driver.find('.test-chart-container');
let data = (await getChartData(chartDom)).data;
assert.deepEqual(data[0].x, [ 61, 5, 4, 3, 2, 1 ]);
assert.deepEqual(data[0].y, [ 16, 2, 3, 4, 5, 6 ]);
// Enter some blank values and a zero. The zero should be included in the plot, but blanks
// should not.
await gu.getCell({col: 1, rowNum: 1}).click();
await driver.sendKeys(Key.DELETE);
await gu.getCell({col: 1, rowNum: 4}).click();
await driver.sendKeys(Key.DELETE);
await gu.getCell({col: 1, rowNum: 6}).click();
await driver.sendKeys('0', Key.ENTER);
await gu.waitForServer();
data = (await getChartData(chartDom)).data;
assert.deepEqual(data[0].x, [ 5, 4, 2, 1 ]);
assert.deepEqual(data[0].y, [ 2, 3, 5, 0 ]);
// Undo and verify that the range is restored.
await gu.undo(3);
data = (await getChartData(chartDom)).data;
assert.deepEqual(data[0].x, [ 61, 5, 4, 3, 2, 1 ]);
assert.deepEqual(data[0].y, [ 16, 2, 3, 4, 5, 6 ]);
});
it('should update chart when new columns are included', async function() {
const chartDom = await driver.find('.test-chart-container');
// Check to make sure initial values are correct.
let data = (await getChartData(chartDom)).data;
assert.deepEqual(data[0].type, 'bar');
assert.deepEqual(data[0].x, [ 61, 5, 4, 3, 2, 1 ]);
assert.deepEqual(data[0].y, [ 16, 2, 3, 4, 5, 6 ]);
// Check that the intial scales are correct for the dataset.
checkAxisRange(await getChartData(chartDom), 0.5, 61.5, 0, 16.5);
// Open the view config pane for the Chart section.
await gu.getSection('ChartData chart').find('.viewsection_title').click();
await gu.toggleSidePanel('right', 'open');
await driver.find('.test-right-tab-pagewidget').click();
await driver.find('.test-config-widget').click();
// Check intial visible fields.
await checkAxisConfig({
xaxis: 'label',
yaxis: ['value']
});
// Adds 'largeValue'
await driver.find('.test-chart-add-y-axis').click();
await driver.findContent('.grist-floating-menu li', 'largeValue').click();
await gu.waitForServer();
// Check axis are correct
await checkAxisConfig({
xaxis: 'label',
yaxis: ['value', 'largeValue']
});
// Move 'largeValue' above 'value'. Scroll it into view first, since dragging is a bit messed
// up when it causes the pane to scroll.
await gu.scrollIntoView(findYAxis('largeValue'));
await driver.withActions((actions) => actions.dragAndDrop(findYAxis('largeValue'), findYAxis('value')));
await gu.waitForServer();
await checkAxisConfig({
xaxis: 'label',
yaxis: ['largeValue', 'value']
});
// Make sure only y axis updates to the new column of data
await driver.sleep(50);
data = (await getChartData(chartDom)).data;
assert.deepEqual(data[0].type, 'bar');
assert.deepEqual(data[0].x, [ 61, 5, 4, 3, 2, 1 ]);
assert.deepEqual(data[0].y, [ 22, 33, 11, 44, 22, 55 ]);
assert.deepEqual(data[1].type, 'bar');
assert.deepEqual(data[1].x, [ 61, 5, 4, 3, 2, 1 ]);
assert.deepEqual(data[1].y, [ 16, 2, 3, 4, 5, 6 ]);
// Check that the scales are correct for the new y values.
checkAxisRange(await getChartData(chartDom), 0.5, 61.5, 0, 57);
// select 'largeValue' as x axis
await selectXAxis('largeValue');
// check x-axis is correct
await checkAxisConfig({
xaxis: 'largeValue',
yaxis: ['value'] // note: 'largeValue' was correctly removed from y-axis
});
// adds 'label' as y axis
await addYAxis('label');
// check axis are correct
await checkAxisConfig({
xaxis: 'largeValue',
yaxis: ['value', 'label']
});
// Reverse the order of the columns and make sure the data updates to reflect that.
await driver.sleep(50);
data = (await getChartData(chartDom)).data;
assert.deepEqual(data[0].type, 'bar');
assert.deepEqual(data[0].x, [ 22, 33, 11, 44, 55 ]);
assert.deepEqual(data[0].y, [ 16, 2, 3, 4, 6 ]);
assert.deepEqual(data[1].type, 'bar');
assert.deepEqual(data[1].x, [ 22, 33, 11, 44, 55 ]);
assert.deepEqual(data[1].y, [ 61, 5, 4, 3, 1 ]);
// Check that the scales are correct for the new values.
checkAxisRange(await getChartData(chartDom), 5.5, 60.5, 0, 61);
// select 'label' as x axis
await selectXAxis('label');
// adds 'largeValue' as y axis
await addYAxis('largeValue');
// moves 'largeValue' above 'value'
await driver.withActions((actions) => actions.dragAndDrop(findYAxis('largeValue'), findYAxis('value')));
await gu.waitForServer();
// check axis correctness
await checkAxisConfig({
xaxis: 'label',
yaxis: ['largeValue', 'value']
});
});
it('should be able to render different types of charts', async function() {
const chartDom = await driver.find('.test-chart-container');
await selectChartType('Pie Chart');
let data = (await getChartData(chartDom)).data;
assert.deepEqual(data[0].type, 'pie');
assert.equal(await driver.find('.test-chart-first-field-label').getText(), 'LABEL');
await selectChartType('Line Chart');
data = (await getChartData(chartDom)).data;
assert.deepEqual(data[0].type, 'scatter');
// Make sure we are not grouping (which would produce names like "1 · value")
assert.equal(data[0].name, 'largeValue');
assert.equal(data[1].name, 'value');
assert.equal(await driver.find('.test-chart-first-field-label').getText(), 'X-AXIS');
await selectChartType('Area Chart');
data = (await getChartData(chartDom)).data;
assert.deepEqual(data[0].type, 'scatter');
assert.deepEqual(data[0].line!.shape, 'spline');
assert.deepEqual(data[0].fill, 'tozeroy');
assert.equal(await driver.find('.test-chart-type').getText(), 'Area Chart');
// Make sure first field of scatter plot is marked label, not x-axis.
await selectChartType('Scatter Plot');
assert.equal(await driver.find('.test-chart-first-field-label').getText(), 'LABEL');
// Make sure first field of Kaplan-Meier plot is marked label, not x-axis.
await selectChartType('Kaplan-Meier Plot');
assert.equal(await driver.find('.test-chart-first-field-label').getText(), 'LABEL');
// Return to Area Chart.
await selectChartType('Area Chart');
});
it('should render pie charts with a single series, or counts', async function() {
await selectChartType('Pie Chart');
// select 'person' for x axis
await selectXAxis('person');
// adds 'label' and move to be first y axis
await addYAxis('label');
await driver.withActions((actions) => actions.dragAndDrop(findYAxis('label'), findYAxis('largeValue')));
await gu.waitForServer();
// check axis
await checkAxisConfig({
xaxis: 'person',
yaxis: ['label', 'largeValue', 'value']
});
const chartDom = await driver.find('.test-chart-container');
let data = (await getChartData(chartDom)).data;
// Only the first series of values is included.
assert.deepEqual(data[0].values, [ 61, 4, 2, 5, 3, 1 ]);
assert.lengthOf(data, 1);
// When no series is included, just counts are used.
await removeYAxis('largeValue');
await removeYAxis('label');
await removeYAxis('value');
data = (await getChartData(chartDom)).data;
assert.deepEqual(data[0].values, [1, 1, 1, 1, 1, 1]);
assert.lengthOf(data, 1);
await gu.undo(7);
// check axis
await checkAxisConfig({
xaxis: 'label',
yaxis: ['largeValue', 'value']
});
// check chart type
assert.equal(await driver.find('.test-chart-type').getText(), 'Area Chart');
});
it('should support Y-axis options', async function() {
const chartDom = await driver.find('.test-chart-container');
await selectChartType('Bar Chart');
checkAxisRange(await getChartData(chartDom), 0.5, 61.5, 0, 57);
await driver.findContent('label', /Invert Y-axis/).find('input').click();
await gu.waitForServer();
checkAxisRange(await getChartData(chartDom), 0.5, 61.5, 57, 0);
await driver.findContent('label', /Invert Y-axis/).find('input').click();
await driver.findContent('label', /Log scale Y-axis/).find('input').click();
await gu.waitForServer();
checkAxisRange(await getChartData(chartDom), 0.5, 61.5, 0.22, 1.82);
await gu.undo(4);
// check axis
await checkAxisConfig({
xaxis: 'label',
yaxis: ['largeValue', 'value']
});
// check chart type
assert.equal(await driver.find('.test-chart-type').getText(), 'Area Chart');
});
it('should be able to render multiseries line charts', async function() {
const chartDom = await driver.find('.test-chart-container');
// switch type to line chart
await selectChartType('Line Chart');
// pick 'largeValue' as the x axis
await selectXAxis('largeValue');
// set 'label' as the groupby column
await setSplitSeries('label');
let {data, layout} = await getChartData(chartDom);
assert.deepEqual(data[0].type, 'scatter');
assert.deepEqual(data.map(d => d.name), ['1', '2', '3', '4', '5', '61']);
assert.equal(getAxisTitle(layout.xaxis), 'largeValue');
assert.equal(getAxisTitle(layout.yaxis), 'value');
// Select person for grouping by column
await setSplitSeries('person');
await checkAxisConfig({
groupingByColumn: 'person',
xaxis: 'largeValue',
yaxis: ['value'],
});
({data, layout} = await getChartData(chartDom));
assert.deepEqual(data[0].type, 'scatter');
assert.deepEqual(data.map(d => d.name), ['Alice', 'Bob']);
assert.equal(getAxisTitle(layout.xaxis), 'largeValue');
assert.equal(getAxisTitle(layout.yaxis), 'value');
// Add a second series. If we have more than one, its name should be included into the series
// names rather than in the yaxis.title.
await addYAxis('label');
await checkAxisConfig({
groupingByColumn: 'person',
xaxis: 'largeValue',
yaxis: ['value', 'label'],
});
({data, layout} = await getChartData(chartDom));
assert.deepEqual(data[0].type, 'scatter');
assert.deepEqual(data.map(d => d.name), ['Alice • value', 'Alice • label', 'Bob • value', 'Bob • label']);
assert.equal(getAxisTitle(layout.xaxis), 'largeValue');
assert.equal(getAxisTitle(layout.yaxis), undefined);
await gu.undo(5);
await checkAxisConfig({
groupingByColumn: false,
xaxis: 'label',
yaxis: ['largeValue', 'value'],
});
// check chart type
assert.equal(await driver.find('.test-chart-type').getText(), 'Area Chart');
});
it('should get options for SPLIT SERIES and X AXIS in sync when table changes', async function() {
// click change widget
await driver.findContent('button', 'Change Widget').click();
// click sum symbol
await driver.findContent('.test-wselect-table', 'People').click();
// click save
await driver.find('.test-wselect-addBtn').click();
await gu.waitForServer();
// click Split series
await driver.findContent('label', 'Split series').click();
// open split series options
await driver.find('.test-chart-group-by-column').click();
// check group-data options
assert.deepEqual(
await driver.findAll('.test-select-menu li', e => e.getText()),
['Pick a column', 'Name', 'B']
);
// send ESCAPE to close menu
await driver.sendKeys(Key.ESCAPE);
// open x axis options
await driver.find('.test-chart-x-axis').click();
// check x axis options
assert.deepEqual(
await driver.findAll('.test-select-menu li', e => e.getText()),
['Name', 'B']
);
// send ESCAPE to close menu
await driver.sendKeys(Key.ESCAPE);
// undo
await gu.undo(1);
});
it('should get series name right when grouped column has \'\' values', async function() {
// remove series 'value'
await removeYAxis('value');
// add a row with person left as blank
const {retValues} = await api.applyUserActions(doc.id, [
['AddRecord', 'ChartData', 7, {largeValue: 44}]
]);
await setSplitSeries('person');
// check that series name is correct
const data = (await getChartData()).data;
assert.deepEqual(data.map(d => d.name), ['[Blank]', 'Alice', 'Bob']);
// remove row
await api.applyUserActions(doc.id, [
['RemoveRecord', 'ChartData', retValues[0]]
]);
// undo
await gu.undo(2);
});
it('should disabled split series option for pie charts', async function() {
// start with line chart type
await selectChartType('Line Chart');
// check the split series option is present
assert.equal(await driver.findContent('label', /Split series/).isPresent(), true);
assert.equal(await driver.find('.test-chart-group-by-column').isPresent(), true);
// select 'person' as the split series column
await setSplitSeries('person');
// check split series option
assert.equal(await driver.findContent('label', /Split series/).isPresent(), true);
assert.equal(await driver.find('.test-chart-group-by-column').isPresent(), true);
// check axis
await checkAxisConfig({
groupingByColumn: 'person',
xaxis: 'label',
yaxis: ['largeValue', 'value'],
});
// select pie chart type
await selectChartType('Pie Chart');
// check that the split series option is not present
assert.equal(await driver.findContent('label', /Split series/).isPresent(), false);
assert.equal(await driver.find('.test-chart-group-by-column').isPresent(), false);
// check axis
await checkAxisConfig({
groupingByColumn: false,
xaxis: 'label',
yaxis: ['largeValue', 'value'],
});
assert.equal(await driver.find('.test-chart-type').getText(), 'Pie Chart');
// undo
await gu.undo(2);
await checkAxisConfig({
groupingByColumn: false,
xaxis: 'label',
yaxis: ['largeValue', 'value'],
});
assert.equal(await driver.find('.test-chart-type').getText(), 'Line Chart');
});
it('should render dates properly on X-axis', async function() {
await gu.getSection('ChartData').find('.viewsection_title').click();
// Add a new first column.
await gu.getCell({col: 0, rowNum: 1}).click();
// driver.sendKeys() doesn't support key combinations, but elem.sendKeys() does.
await driver.find('body').sendKeys(Key.chord(Key.ALT, Key.SHIFT, '='));
await gu.waitForServer();
await driver.find('.test-column-title-label').sendKeys('MyDate', Key.ENTER);
await gu.waitForServer();
// Convert it to Date
await gu.toggleSidePanel('right', 'open');
await driver.find('.test-right-tab-field').click();
await gu.setType(/Date/);
await gu.waitForServer();
// Enter some values.
await gu.enterGridRows({col: 0, rowNum: 1}, [
["2018-01-15"], ["2018-01-31"], ["2018-02-14"], ["2018-03-04"], ["2018-03-14"], ["2018-03-26"]
]);
// Open the view config pane for the Chart section.
await gu.getSection('ChartData chart').find('.viewsection_title').click();
await driver.find('.test-right-tab-pagewidget').click();
// select MyDate for x axis
await selectXAxis('MyDate');
const chartDom = await driver.find('.test-chart-container');
const {data, layout} = await getChartData(chartDom);
// This check helps understand Plotly's actual interpretation of the dates. E.g. if the range
// endpoints are like '2018-03-25 20:00', plotly is misinterpreting the timezone.
assert.deepEqual(layout.xaxis.range, ['2018-01-15', '2018-03-26']);
assert.deepEqual(data[0].type, 'scatter');
assert.deepEqual(data[0].name, 'largeValue');
assert.deepEqual(data[0].x, [
"2018-01-15T00:00:00.000Z", "2018-01-31T00:00:00.000Z", "2018-02-14T00:00:00.000Z",
"2018-03-04T00:00:00.000Z", "2018-03-14T00:00:00.000Z", "2018-03-26T00:00:00.000Z"
]);
assert.deepEqual(data[0].y, [22, 33, 11, 44, 22, 55]);
assert.deepEqual(data[1].type, 'scatter');
assert.deepEqual(data[1].name, 'value');
assert.deepEqual(data[0].x, [
"2018-01-15T00:00:00.000Z", "2018-01-31T00:00:00.000Z", "2018-02-14T00:00:00.000Z",
"2018-03-04T00:00:00.000Z", "2018-03-14T00:00:00.000Z", "2018-03-26T00:00:00.000Z"
]);
assert.deepEqual(data[1].y, [16, 2, 3, 4, 5, 6]);
});
it('should support error bars', async function() {
// We start with a line chart with MyDate on X-axis, and two series: largeValue and value.
await selectChartType('Line Chart');
await checkAxisConfig({xaxis: 'MyDate', yaxis: ['largeValue', 'value']});
// Symmetric error bars should leave only the largeValue series, with 'value' for error bars.
await driver.find('.test-chart-error-bars .test-select-open').click();
await driver.findContent('.test-select-menu li', /Symmetric/).click();
await gu.waitForServer();
const chartDom = await driver.find('.test-chart-container');
let data = (await getChartData(chartDom)).data;
assert.deepEqual(data[0].type, 'scatter');
assert.deepEqual(data[0].name, 'largeValue');
assert.deepEqual(data[0].y, [22, 33, 11, 44, 22, 55]);
assert.deepEqual((data[0].error_y as any).array, [16, 2, 3, 4, 5, 6]);
assert.deepEqual(data[0].error_y!.symmetric, true);
assert.lengthOf(data, 1);
// Using separate error bars for above+below will leave just the "above" error bars.
await driver.find('.test-chart-error-bars .test-select-open').click();
await driver.findContent('.test-select-menu li', /Above.*Below/).click();
await gu.waitForServer();
data = (await getChartData(chartDom)).data;
assert.deepEqual(data[0].y, [22, 33, 11, 44, 22, 55]);
assert.deepEqual((data[0].error_y as any).array, [16, 2, 3, 4, 5, 6]);
assert.deepEqual((data[0].error_y as any).arrayminus, null);
assert.deepEqual(data[0].error_y!.symmetric, false);
assert.lengthOf(data, 1);
// If we add another line, it'll be used for "below" error bars.
await addYAxis('label');
data = (await getChartData(chartDom)).data;
assert.deepEqual(data[0].y, [22, 33, 11, 44, 22, 55]);
assert.deepEqual((data[0].error_y as any).array, [16, 2, 3, 4, 5, 6]);
assert.deepEqual((data[0].error_y as any).arrayminus, [61, 5, 4, 3, 2, 1]);
assert.deepEqual(data[0].error_y!.symmetric, false);
assert.lengthOf(data, 1);
// Should work also for bar charts
await selectChartType('Bar Chart');
data = (await getChartData(chartDom)).data;
assert.deepEqual(data[0].type, 'bar');
assert.deepEqual(data[0].y, [22, 33, 11, 44, 22, 55]);
assert.deepEqual((data[0].error_y as any).array, [16, 2, 3, 4, 5, 6]);
assert.deepEqual((data[0].error_y as any).arrayminus, [61, 5, 4, 3, 2, 1]);
assert.deepEqual(data[0].error_y!.symmetric, false);
assert.lengthOf(data, 1);
await gu.undo(1);
await gu.undo(3);
});
it('should fetch data for tables not yet loaded', async function() {
// Create a Page that only has a Chart, no other sections.
await gu.addNewPage(/Chart/, /ChartData/);
let chartDom = await driver.findWait('.test-chart-container', 1000);
assert.equal(await chartDom.isDisplayed(), true);
let data = (await getChartData(chartDom)).data;
assert.lengthOf(data, 1);
assert.deepEqual(data[0].type, 'bar');
assert.deepEqual(data[0].y, [ 61, 5, 4, 3, 2, 1 ]);
// Reload the page and test that the chart loaded.
await driver.navigate().refresh();
await gu.waitForDocToLoad();
await driver.sleep(1000);
chartDom = await driver.findWait('.test-chart-container', 1000);
assert.equal(await chartDom.isDisplayed(), true);
data = (await getChartData(chartDom)).data;
assert.lengthOf(data, 1);
assert.deepEqual(data[0].type, 'bar');
assert.deepEqual(data[0].y, [ 61, 5, 4, 3, 2, 1 ]);
});
it('should resize chart when side panels open or close', async function() {
// Open a document with some chart data.
const session = await gu.session().teamSite.login();
doc = await session.tempDoc(cleanup, 'ChartData.grist');
await gu.toggleSidePanel('right', 'close');
// Add a chart section.
await gu.addNewSection(/Chart/, /ChartData/);
const chart = await driver.findWait('.viewsection_content .svg-container', 1000);
const initialRect = await chart.getRect();
// We expect the left panel open initially.
assert.equal(await gu.isSidePanelOpen('left'), true);
// Open the RightPanel, check that chart's width was reduced.
await gu.toggleSidePanel('right', 'open');
await driver.wait(async () => (await chart.getRect()).width < initialRect.width, 1000);
// Close the panel and check the chart went back to initial size.
await gu.toggleSidePanel('right', 'close');
await driver.wait(async () => (await chart.getRect()).width === initialRect.width, 1000);
assert.deepEqual(await chart.getRect(), initialRect);
// Close the left panel, and check that chart width was increased.
await gu.toggleSidePanel('left', 'close');
await driver.wait(async () => (await chart.getRect()).width > initialRect.width, 1000);
// Reopen the left panel and check the chart went back to initial size.
await gu.toggleSidePanel('left', 'open');
await driver.wait(async () => (await chart.getRect()).width === initialRect.width, 1000);
assert.deepEqual(await chart.getRect(), initialRect);
});
// Tests a bug where js errors would be thrown when fewer than 2 series were visible
// and any chart settings were changed.
it('should not throw errors when no y-axis are set', async function() {
// Open the RightPanel and hide both series.
await gu.toggleSidePanel('right', 'open');
await removeYAxis('value');
// Invert the y-axis. (This is meant to trigger js errors if the bug is present)
await driver.findContent('label', /Invert Y-axis/).find('input').click();
await gu.waitForServer();
// Group by the first column. (This is meant to trigger js errors if the bug is present)
await setSplitSeries('value');
// Disable groupby column
await setSplitSeries(false);
// Revert changes.
await gu.undo(3);
});
// Tests a bug where hitting enter would try to edit a non-existent cell for summary charts.
it('should not throw errors when pressing enter on summary charts', async function() {
// Click the section and press 'Enter'.
await gu.getSection('ChartData chart').click();
await driver.sendKeys(Key.ENTER);
await gu.checkForErrors();
});
it('should not throw errors when switching to a chart page', async function() {
await gu.getPageItem('People').click();
await gu.waitForServer();
await gu.getPageItem('ChartData').click();
await gu.waitForServer();
const chartDom = await gu.getSection('ChartData chart').find('.test-chart-container');
assert.equal(await chartDom.isDisplayed(), true);
await gu.checkForErrors();
});
it('should not throw errors when summarizing or un-summarizing underlying table', async function() {
// activate the chart widget
await gu.getSection('ChartData chart').click();
// open widget option
await gu.openSectionMenu('viewLayout');
await driver.findContent('.grist-floating-menu li', 'Widget options').click();
// open the page widget picker
await driver.findContent('.test-right-panel button', 'Change Widget').click();
// click the summarize button
await driver.findContent('.test-wselect-table', 'ChartData').find('.test-wselect-pivot').click();
// click save
await driver.find('.test-wselect-addBtn').click();
// wait for server
await gu.waitForServer();
// wait for chart to be changed
await gu.waitToPass(async () => {
assert.equal(
await gu.getActiveSectionTitle(),
'CHARTDATA [Totals] Chart'
);
});
// check for error
await gu.checkForErrors();
// undo 1
await gu.undo(1);
});
it('should sort x-axis values', async function() {
// Import a small table of numbers to test this.
await gu.importFileDialog('uploads/ChartData-Sort_Test.csv');
await driver.find('.test-modal-confirm').click();
await gu.waitForServer();
// Add a chart of this data, and configure it first to just show X and Y1, Y2 series.
await gu.addNewSection(/Chart/, /ChartData-Sort_Test/);
await gu.toggleSidePanel('right', 'open');
await selectChartType('Line Chart');
// Show series X, Y1, Y2, grouped by Group.
await selectXAxis('X');
await setSplitSeries('Group');
await addYAxis('Y1');
await addYAxis('Y2');
const chartDom = await driver.findWait('.test-chart-container', 1000);
let {data} = await getChartData(chartDom);
assert.lengthOf(data, 4);
assert.deepInclude(data[0], {type: 'scatter', name: 'Bar • Y1'});
assert.deepInclude(data[1], {type: 'scatter', name: 'Bar • Y2'});
assert.deepInclude(data[2], {type: 'scatter', name: 'Foo • Y1'});
assert.deepInclude(data[3], {type: 'scatter', name: 'Foo • Y2'});
assert.deepEqual(data[0].x, [ 1.5, 2.5, 3.5, 4.5, 5.5 ]);
assert.deepEqual(data[0].y, [ 1.5, 1, 3.5, 2.5, 4 ]);
assert.deepEqual(data[1].x, [ 1.5, 2.5, 3.5, 4.5, 5.5 ]);
assert.deepEqual(data[1].y, [ 6.9, 6, 4.9, 5, 7 ]);
assert.deepEqual(data[2].x, [ 1, 2, 3, 4, 5 ]);
assert.deepEqual(data[2].y, [ 1.5, 1, 3.5, 2.5, 4 ]);
assert.deepEqual(data[3].x, [ 1, 2, 3, 4, 5 ]);
assert.deepEqual(data[3].y, [ 6.9, 6, 4.9, 5, 7 ]);
// Now show series ungrouped.
await setSplitSeries(false);
({data} = await getChartData(chartDom));
assert.lengthOf(data, 2);
assert.deepInclude(data[0], {type: 'scatter', name: 'Y1'});
assert.deepInclude(data[1], {type: 'scatter', name: 'Y2'});
assert.deepEqual(data[0].x, [ 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5 ]);
assert.deepEqual(data[0].y, [ 1.5, 1.5, 1, 1, 3.5, 3.5, 2.5, 2.5, 4, 4 ]);
assert.deepEqual(data[1].x, [ 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5 ]);
assert.deepEqual(data[1].y, [ 6.9, 6.9, 6, 6, 4.9, 4.9, 5, 5, 7, 7 ]);
});
it('should not throw when picking the grouping by column for the x-axis', async function() {
await checkAxisConfig({xaxis: 'X', yaxis: ['Y1', 'Y2']});
await setSplitSeries('Group');
await checkAxisConfig({xaxis: 'X', yaxis: ['Y1', 'Y2'], groupingByColumn: 'Group'});
await selectXAxis('Group');
await checkAxisConfig({xaxis: 'Group', yaxis: ['Y1', 'Y2']});
await gu.checkForErrors();
await gu.undo(2);
});
});