chore: Upgrade Cypress to 10.11.0 (#23813)

This commit is contained in:
Kamil Gabryjelski
2023-04-26 16:17:59 +02:00
committed by GitHub
parent e805dec141
commit 40ae074ff0
68 changed files with 3016 additions and 4931 deletions

View File

@@ -0,0 +1,121 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
describe('Visualization > Area', () => {
beforeEach(() => {
cy.intercept('POST', '/superset/explore_json/**').as('getJson');
});
const AREA_FORM_DATA = {
datasource: '2__table',
viz_type: 'area',
slice_id: 48,
granularity_sqla: 'year',
time_grain_sqla: 'P1D',
time_range: '1960-01-01 : now',
metrics: ['sum__SP_POP_TOTL'],
adhoc_filters: [],
groupby: [],
limit: '25',
order_desc: true,
contribution: false,
row_limit: 50000,
show_brush: 'auto',
show_legend: true,
line_interpolation: 'linear',
stacked_style: 'stack',
color_scheme: 'bnbColors',
rich_tooltip: true,
show_controls: false,
x_axis_label: '',
bottom_margin: 'auto',
x_ticks_layout: 'auto',
x_axis_format: 'smart_date',
x_axis_showminmax: false,
y_axis_format: '.3s',
y_log_scale: false,
rolling_type: 'None',
comparison_type: 'values',
annotation_layers: [],
};
function verify(formData) {
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
}
it('should work without groupby', () => {
verify(AREA_FORM_DATA);
cy.get('.nv-area').should('have.length', 1);
});
it('should work with group by', () => {
verify({
...AREA_FORM_DATA,
groupby: ['region'],
});
cy.get('.nv-area').should('have.length', 7);
});
it('should work with groupby and filter', () => {
cy.visitChartByParams({
...AREA_FORM_DATA,
groupby: ['region'],
adhoc_filters: [
{
expressionType: 'SIMPLE',
subject: 'region',
operator: 'IN',
comparator: ['South Asia', 'North America'],
clause: 'WHERE',
sqlExpression: null,
filterOptionName: 'filter_txje2ikiv6_wxmn0qwd1xo',
},
],
});
cy.wait('@getJson').then(async ({ response }) => {
const responseBody = response?.body;
// Make sure data is sorted correctly
const firstRow = responseBody.data[0].values;
const secondRow = responseBody.data[1].values;
expect(firstRow[firstRow.length - 1].y).to.be.greaterThan(
secondRow[secondRow.length - 1].y,
);
cy.verifySliceContainer('svg');
});
cy.get('.nv-area').should('have.length', 2);
});
it('should allow type to search color schemes and apply the scheme', () => {
verify(AREA_FORM_DATA);
cy.get('#controlSections-tab-display').click();
cy.get('.Control[data-test="color_scheme"]').scrollIntoView();
cy.get('.Control[data-test="color_scheme"] input[type="search"]')
.focus()
.type('supersetColors{enter}');
cy.get(
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]',
).should('exist');
cy.get('.area .nv-legend .nv-legend-symbol')
.first()
.should('have.css', 'fill', 'rgb(31, 168, 201)');
});
});

View File

@@ -0,0 +1,82 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { interceptChart } from 'cypress/utils';
describe('Visualization > Big Number with Trendline', () => {
beforeEach(() => {
interceptChart({ legacy: false }).as('chartData');
});
const BIG_NUMBER_FORM_DATA = {
datasource: '2__table',
viz_type: 'big_number',
slice_id: 42,
granularity_sqla: 'year',
time_grain_sqla: 'P1D',
time_range: '2000 : 2014-01-02',
metric: 'sum__SP_POP_TOTL',
adhoc_filters: [],
compare_lag: '10',
compare_suffix: 'over 10Y',
y_axis_format: '.3s',
show_trend_line: true,
start_y_axis_at_zero: true,
color_picker: {
r: 0,
g: 122,
b: 135,
a: 1,
},
};
function verify(formData) {
cy.visitChartByParams(formData);
cy.verifySliceSuccess({
waitAlias: '@chartData',
chartSelector: '.superset-legacy-chart-big-number',
});
}
it('should work', () => {
verify(BIG_NUMBER_FORM_DATA);
cy.get('.chart-container .header-line');
cy.get('.chart-container .subheader-line');
cy.get('.chart-container canvas');
});
it('should work without subheader', () => {
verify({
...BIG_NUMBER_FORM_DATA,
compare_lag: null,
});
cy.get('.chart-container .header-line');
cy.get('.chart-container .subheader-line').should('not.exist');
cy.get('.chart-container canvas');
});
it('should not render trendline when hidden', () => {
verify({
...BIG_NUMBER_FORM_DATA,
show_trend_line: false,
});
cy.get('[data-test="chart-container"] .header-line');
cy.get('[data-test="chart-container"] .subheader-line');
cy.get('[data-test="chart-container"] canvas').should('not.exist');
});
});

View File

@@ -0,0 +1,79 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { interceptChart } from 'cypress/utils';
import { FORM_DATA_DEFAULTS, NUM_METRIC } from './shared.helper';
describe('Visualization > Big Number Total', () => {
beforeEach(() => {
interceptChart({ legacy: false }).as('chartData');
});
const BIG_NUMBER_DEFAULTS = {
...FORM_DATA_DEFAULTS,
viz_type: 'big_number_total',
};
it('Test big number chart with adhoc metric', () => {
const formData = { ...BIG_NUMBER_DEFAULTS, metric: NUM_METRIC };
cy.visitChartByParams(formData);
cy.verifySliceSuccess({
waitAlias: '@chartData',
querySubstring: NUM_METRIC.label,
});
});
it('Test big number chart with simple filter', () => {
const filters = [
{
expressionType: 'SIMPLE',
subject: 'name',
operator: 'IN',
comparator: ['Aaron', 'Amy', 'Andrea'],
clause: 'WHERE',
sqlExpression: null,
filterOptionName: 'filter_4y6teao56zs_ebjsvwy48c',
},
];
const formData = {
...BIG_NUMBER_DEFAULTS,
metric: 'count',
adhoc_filters: filters,
};
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@chartData' });
});
it('Test big number chart ignores groupby', () => {
const formData = {
...BIG_NUMBER_DEFAULTS,
metric: NUM_METRIC,
groupby: ['state'],
};
cy.visitChartByParams(formData);
cy.wait(['@chartData']).then(async ({ response }) => {
cy.verifySliceContainer();
const responseBody = response?.body;
expect(responseBody.result[0].query).not.contains(formData.groupby[0]);
});
});
});

View File

@@ -0,0 +1,61 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
describe('Visualization > Box Plot', () => {
beforeEach(() => {
cy.intercept('POST', '/api/v1/chart/data*').as('getJson');
});
const BOX_PLOT_FORM_DATA = {
datasource: '2__table',
viz_type: 'box_plot',
slice_id: 49,
granularity_sqla: 'year',
time_grain_sqla: 'P1D',
time_range: '1960-01-01 : now',
metrics: ['sum__SP_POP_TOTL'],
adhoc_filters: [],
groupby: ['region'],
limit: '25',
color_scheme: 'bnbColors',
whisker_options: 'Min/max (no outliers)',
};
function verify(formData) {
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson' });
}
it('should work', () => {
verify(BOX_PLOT_FORM_DATA);
cy.get('.chart-container .box_plot canvas').should('have.length', 1);
});
it('should allow type to search color schemes', () => {
verify(BOX_PLOT_FORM_DATA);
cy.get('#controlSections-tab-display').click();
cy.get('.Control[data-test="color_scheme"]').scrollIntoView();
cy.get('.Control[data-test="color_scheme"] input[type="search"]')
.focus()
.type('supersetColors{enter}');
cy.get(
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]',
).should('exist');
});
});

View File

@@ -0,0 +1,105 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
describe('Visualization > Bubble', () => {
beforeEach(() => {
cy.intercept('POST', '/superset/explore_json/**').as('getJson');
});
const BUBBLE_FORM_DATA = {
datasource: '2__table',
viz_type: 'bubble',
slice_id: 46,
granularity_sqla: 'year',
time_grain_sqla: 'P1D',
time_range: '2011-01-01 : 2011-01-02',
series: 'region',
entity: 'country_name',
x: 'sum__SP_RUR_TOTL_ZS',
y: 'sum__SP_DYN_LE00_IN',
size: 'sum__SP_POP_TOTL',
max_bubble_size: '50',
limit: 0,
color_scheme: 'bnbColors',
show_legend: true,
x_axis_label: '',
left_margin: 'auto',
x_axis_format: '.3s',
x_ticks_layout: 'auto',
x_log_scale: false,
x_axis_showminmax: false,
y_axis_label: '',
bottom_margin: 'auto',
y_axis_format: '.3s',
y_log_scale: false,
y_axis_showminmax: false,
};
function verify(formData) {
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
}
it('should work with filter', () => {
verify({
...BUBBLE_FORM_DATA,
adhoc_filters: [
{
expressionType: 'SIMPLE',
subject: 'region',
operator: '==',
comparator: 'South Asia',
clause: 'WHERE',
sqlExpression: null,
filterOptionName: 'filter_b2tfg1rs8y_8kmrcyxvsqd',
},
],
});
cy.get('[data-test="chart-container"]')
.should('be.visible')
.within(() => {
cy.get('svg').find('.nv-point-clips circle').should('have.length', 8);
})
.then(nodeList => {
// Check that all circles have same color.
const color = nodeList[0].getAttribute('fill');
const circles = Array.prototype.slice.call(nodeList);
expect(circles.every(c => c.getAttribute('fill') === color)).to.equal(
true,
);
});
});
it('should allow type to search color schemes and apply the scheme', () => {
cy.visitChartByParams(BUBBLE_FORM_DATA);
cy.get('.Control[data-test="color_scheme"]').scrollIntoView();
cy.get('.Control[data-test="color_scheme"] input[type="search"]')
.focus()
.type('supersetColors{enter}');
cy.get(
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]',
).should('exist');
cy.get('[data-test=run-query-button]').click();
cy.get('.bubble .nv-legend .nv-legend-symbol').should(
'have.css',
'fill',
'rgb(31, 168, 201)',
);
});
});

View File

@@ -0,0 +1,104 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
describe('Visualization > Compare', () => {
beforeEach(() => {
cy.intercept('POST', '/superset/explore_json/**').as('getJson');
});
const COMPARE_FORM_DATA = {
datasource: '3__table',
viz_type: 'compare',
slice_id: 60,
granularity_sqla: 'ds',
time_grain_sqla: 'P1D',
time_range: '100 years ago : now',
metrics: ['count'],
adhoc_filters: [],
groupby: [],
order_desc: true,
contribution: false,
row_limit: 50000,
color_scheme: 'bnbColors',
x_axis_label: 'Frequency',
bottom_margin: 'auto',
x_ticks_layout: 'auto',
x_axis_format: 'smart_date',
x_axis_showminmax: false,
y_axis_label: 'Num',
left_margin: 'auto',
y_axis_showminmax: false,
y_log_scale: false,
y_axis_format: '.3s',
rolling_type: 'None',
comparison_type: 'values',
annotation_layers: [],
};
function verify(formData) {
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
}
it('should work without groupby', () => {
verify(COMPARE_FORM_DATA);
cy.get('.chart-container .nvd3 path.nv-line').should('have.length', 1);
});
it('should with group by', () => {
verify({
...COMPARE_FORM_DATA,
groupby: ['gender'],
});
cy.get('.chart-container .nvd3 path.nv-line').should('have.length', 2);
});
it('should work with filter', () => {
verify({
...COMPARE_FORM_DATA,
adhoc_filters: [
{
expressionType: 'SIMPLE',
subject: 'gender',
operator: '==',
comparator: 'boy',
clause: 'WHERE',
sqlExpression: null,
filterOptionName: 'filter_tqx1en70hh_7nksse7nqic',
},
],
});
cy.get('.chart-container .nvd3 path.nv-line').should('have.length', 1);
});
it('should allow type to search color schemes and apply the scheme', () => {
verify(COMPARE_FORM_DATA);
cy.get('#controlSections-tab-display').click();
cy.get('.Control[data-test="color_scheme"]').scrollIntoView();
cy.get('.Control[data-test="color_scheme"] input[type="search"]')
.focus()
.type('supersetColors{enter}');
cy.get(
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]',
).should('exist');
cy.get('.compare .nv-legend .nv-legend-symbol')
.first()
.should('have.css', 'fill', 'rgb(31, 168, 201)');
});
});

View File

@@ -0,0 +1,94 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { FORM_DATA_DEFAULTS, NUM_METRIC } from './shared.helper';
describe('Visualization > Distribution bar chart', () => {
beforeEach(() => {
cy.intercept('POST', '/superset/explore_json/**').as('getJson');
});
const VIZ_DEFAULTS = { ...FORM_DATA_DEFAULTS, viz_type: 'dist_bar' };
const DISTBAR_FORM_DATA = {
...VIZ_DEFAULTS,
metrics: NUM_METRIC,
groupby: ['state'],
};
it('should work with adhoc metric', () => {
cy.visitChartByParams(DISTBAR_FORM_DATA);
cy.verifySliceSuccess({
waitAlias: '@getJson',
querySubstring: NUM_METRIC.label,
chartSelector: 'svg',
});
});
it('should work with series', () => {
const formData = {
...VIZ_DEFAULTS,
metrics: NUM_METRIC,
groupby: ['state'],
columns: ['gender'],
};
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
});
it('should work with row limit', () => {
const formData = {
...VIZ_DEFAULTS,
metrics: NUM_METRIC,
groupby: ['state'],
row_limit: 10,
};
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
});
it('should work with contribution', () => {
const formData = {
...VIZ_DEFAULTS,
metrics: NUM_METRIC,
groupby: ['state'],
columns: ['gender'],
contribution: true,
};
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
});
it('should allow type to search color schemes and apply the scheme', () => {
cy.visitChartByParams(DISTBAR_FORM_DATA);
cy.get('#controlSections-tab-display').click();
cy.get('.Control[data-test="color_scheme"]').scrollIntoView();
cy.get('.Control[data-test="color_scheme"] input[type="search"]')
.focus()
.type('bnbColors{enter}');
cy.get(
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="bnbColors"]',
).should('exist');
cy.get('.dist_bar .nv-legend .nv-legend-symbol')
.first()
.should('have.css', 'fill', 'rgb(255, 90, 95)');
});
});

View File

@@ -0,0 +1,47 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { FORM_DATA_DEFAULTS, NUM_METRIC } from './shared.helper';
describe('Download Chart > Distribution bar chart', () => {
const VIZ_DEFAULTS = { ...FORM_DATA_DEFAULTS, viz_type: 'dist_bar' };
beforeEach(() => {
cy.intercept('POST', '/superset/explore_json/**').as('getJson');
});
it('download chart with image works', () => {
const formData = {
...VIZ_DEFAULTS,
metrics: NUM_METRIC,
groupby: ['state'],
};
cy.visitChartByParams(formData);
cy.get('.header-with-actions .ant-dropdown-trigger').click();
cy.get(':nth-child(3) > .ant-dropdown-menu-submenu-title').click();
cy.get(
'.ant-dropdown-menu-submenu > .ant-dropdown-menu li:nth-child(3)',
).click();
cy.verifyDownload('.jpg', {
contains: true,
timeout: 25000,
interval: 600,
});
});
});

View File

@@ -0,0 +1,84 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
describe('Visualization > Dual Line', () => {
beforeEach(() => {
cy.intercept('POST', '/superset/explore_json/**').as('getJson');
});
const DUAL_LINE_FORM_DATA = {
datasource: '3__table',
viz_type: 'dual_line',
slice_id: 58,
granularity_sqla: 'ds',
time_grain_sqla: 'P1D',
time_range: '100 years ago : now',
color_scheme: 'bnbColors',
x_axis_format: 'smart_date',
metric: 'sum__num',
y_axis_format: '.3s',
metric_2: 'count',
y_axis_2_format: '.3s',
adhoc_filters: [],
annotation_layers: [],
};
function verify(formData) {
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
}
it('should work', () => {
verify(DUAL_LINE_FORM_DATA);
cy.get('.chart-container svg path.nv-line').should('have.length', 2);
});
it('should work with filter', () => {
verify({
...DUAL_LINE_FORM_DATA,
adhoc_filters: [
{
expressionType: 'SIMPLE',
subject: 'gender',
operator: '==',
comparator: 'girl',
clause: 'WHERE',
sqlExpression: null,
filterOptionName: 'filter_1ep6q50g8vk_48jj6qxdems',
},
],
});
cy.get('.chart-container svg path.nv-line').should('have.length', 2);
});
it('should allow type to search color schemes and apply the scheme', () => {
verify(DUAL_LINE_FORM_DATA);
cy.get('#controlSections-tab-display').click();
cy.get('.Control[data-test="color_scheme"]').scrollIntoView();
cy.get('.Control[data-test="color_scheme"] input[type="search"]')
.focus()
.type('supersetColors{enter}');
cy.get(
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]',
).should('exist');
cy.get('.dual_line .nv-legend .nv-legend-symbol')
.first()
.should('have.css', 'fill', 'rgb(31, 168, 201)');
});
});

View File

@@ -0,0 +1,76 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
describe('Visualization > Gauge', () => {
beforeEach(() => {
cy.intercept('POST', '/api/v1/chart/data*').as('getJson');
});
const GAUGE_FORM_DATA = {
datasource: '3__table',
viz_type: 'gauge_chart',
metric: 'count',
adhoc_filters: [],
slice_id: 54,
row_limit: 10,
};
function verify(formData) {
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson' });
}
it('should work', () => {
verify(GAUGE_FORM_DATA);
cy.get('.chart-container .gauge_chart canvas').should('have.length', 1);
});
it('should work with simple filter', () => {
verify({
...GAUGE_FORM_DATA,
adhoc_filters: [
{
expressionType: 'SIMPLE',
subject: 'country_code',
operator: '==',
comparator: 'USA',
clause: 'WHERE',
sqlExpression: null,
isExtra: false,
isNew: false,
filterOptionName: 'filter_jaemvkxd5h_ku22m3wyo',
},
],
});
cy.get('.chart-container .gauge_chart canvas').should('have.length', 1);
});
it('should allow type to search color schemes', () => {
verify(GAUGE_FORM_DATA);
cy.get('#controlSections-tab-display').click();
cy.get('.Control[data-test="color_scheme"]').scrollIntoView();
cy.get('.Control[data-test="color_scheme"] input[type="search"]')
.focus()
.type('bnbColors{enter}');
cy.get(
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="bnbColors"]',
).should('exist');
});
});

View File

@@ -0,0 +1,92 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
type adhocFilter = {
expressionType: string;
subject: string;
operator: string;
comparator: string;
clause: string;
sqlExpression: string | null;
filterOptionName: string;
};
describe('Visualization > Graph', () => {
beforeEach(() => {
cy.intercept('POST', '/api/v1/chart/data*').as('getJson');
});
const GRAPH_FORM_DATA = {
datasource: '1__table',
viz_type: 'graph_chart',
slice_id: 55,
granularity_sqla: 'ds',
time_grain_sqla: 'P1D',
time_range: '100 years ago : now',
metric: 'sum__value',
adhoc_filters: [],
source: 'source',
target: 'target',
row_limit: 50000,
show_legend: true,
color_scheme: 'bnbColors',
};
function verify(formData: {
[name: string]: string | boolean | number | Array<adhocFilter>;
}): void {
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson' });
}
it('should work with ad-hoc metric', () => {
verify(GRAPH_FORM_DATA);
cy.get('.chart-container .graph_chart canvas').should('have.length', 1);
});
it('should work with simple filter', () => {
verify({
...GRAPH_FORM_DATA,
adhoc_filters: [
{
expressionType: 'SIMPLE',
subject: 'source',
operator: '==',
comparator: 'Agriculture',
clause: 'WHERE',
sqlExpression: null,
filterOptionName: 'filter_tqx1en70hh_7nksse7nqic',
},
],
});
cy.get('.chart-container .graph_chart canvas').should('have.length', 1);
});
it('should allow type to search color schemes', () => {
verify(GRAPH_FORM_DATA);
cy.get('#controlSections-tab-display').click();
cy.get('.Control[data-test="color_scheme"]').scrollIntoView();
cy.get('.Control[data-test="color_scheme"] input[type="search"]')
.focus()
.type('bnbColors{enter}');
cy.get(
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="bnbColors"]',
).should('exist');
});
});

View File

@@ -0,0 +1,103 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { QueryFormData } from '@superset-ui/core';
describe('Visualization > Histogram', () => {
beforeEach(() => {
cy.intercept('POST', '/superset/explore_json/**').as('getJson');
});
const HISTOGRAM_FORM_DATA: QueryFormData = {
datasource: '3__table',
viz_type: 'histogram',
slice_id: 60,
granularity_sqla: 'ds',
time_grain_sqla: 'P1D',
time_range: '100 years ago : now',
all_columns_x: ['num'],
adhoc_filters: [],
row_limit: 50000,
groupby: [],
color_scheme: 'bnbColors',
link_length: 5, // number of bins
x_axis_label: 'Frequency',
y_axis_label: 'Num',
global_opacity: 1,
normalized: false,
};
function verify(formData: QueryFormData) {
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
}
it('should work without groupby', () => {
verify(HISTOGRAM_FORM_DATA);
cy.get('.chart-container svg .vx-bar').should(
'have.length',
HISTOGRAM_FORM_DATA.link_length,
);
});
it('should work with group by', () => {
verify({
...HISTOGRAM_FORM_DATA,
groupby: ['gender'],
});
cy.get('.chart-container svg .vx-bar').should(
'have.length',
HISTOGRAM_FORM_DATA.link_length * 2,
);
});
it('should work with filter and update num bins', () => {
const numBins = 2;
verify({
...HISTOGRAM_FORM_DATA,
link_length: numBins,
adhoc_filters: [
{
expressionType: 'SIMPLE',
clause: 'WHERE',
subject: 'state',
operator: '==',
comparator: 'CA',
},
],
});
cy.get('.chart-container svg .vx-bar').should('have.length', numBins);
});
it('should allow type to search color schemes and apply the scheme', () => {
verify(HISTOGRAM_FORM_DATA);
cy.get('#controlSections-tab-display').click();
cy.get('.Control[data-test="color_scheme"]').scrollIntoView();
cy.get('.Control[data-test="color_scheme"] input[type="search"]')
.focus()
.type('supersetColors{enter}');
cy.get(
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]',
).should('exist');
cy.get('.histogram .vx-legend .vx-legend-shape div')
.first()
.should('have.css', 'background')
.and('contains', 'rgb(31, 168, 201)');
});
});

View File

@@ -0,0 +1,303 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { FORM_DATA_DEFAULTS, NUM_METRIC, SIMPLE_FILTER } from './shared.helper';
describe('Visualization > Line', () => {
beforeEach(() => {
cy.intercept('POST', '/superset/explore_json/**').as('getJson');
});
const LINE_CHART_DEFAULTS = { ...FORM_DATA_DEFAULTS, viz_type: 'line' };
it('should show validator error when no metric', () => {
const formData = { ...LINE_CHART_DEFAULTS, metrics: [] };
cy.visitChartByParams(formData);
cy.get('.panel-body').contains(
`Add required control values to preview chart`,
);
});
it('should not show validator error when metric added', () => {
const formData = { ...LINE_CHART_DEFAULTS, metrics: [] };
cy.visitChartByParams(formData);
cy.get('.panel-body').contains(
`Add required control values to preview chart`,
);
cy.get('[data-test="metrics-header"]').contains('Metrics');
cy.get('[data-test="metrics-header"] [data-test="error-tooltip"]').should(
'exist',
);
cy.get('[data-test=metrics]')
.contains('Drop columns/metrics here or click')
.click();
// Title edit for saved metrics is disabled - switch to Simple
cy.get('[id="adhoc-metric-edit-tabs-tab-SIMPLE"]').click();
cy.get('input[aria-label="Select column"]').click().type('num{enter}');
cy.get('input[aria-label="Select aggregate options"]')
.click()
.type('sum{enter}');
cy.get('[data-test="AdhocMetricEdit#save"]').contains('Save').click();
cy.get('[data-test="metrics-header"]').contains('Metrics');
cy.get('[data-test="metrics-header"] [data-test="error-tooltip"]').should(
'not.exist',
);
cy.get('.ant-alert-warning').should('not.exist');
});
it('should allow negative values in Y bounds', () => {
const formData = { ...LINE_CHART_DEFAULTS, metrics: [NUM_METRIC] };
cy.visitChartByParams(formData);
cy.get('#controlSections-tab-display').click();
cy.get('span').contains('Y Axis Bounds').scrollIntoView();
cy.get('input[placeholder="Min"]').type('-0.1', { delay: 100 });
cy.get('.ant-alert-warning').should('not.exist');
});
it('should allow type to search color schemes and apply the scheme', () => {
cy.get('#controlSections-tab-display').click();
cy.get('.Control[data-test="color_scheme"]').scrollIntoView();
cy.get('.Control[data-test="color_scheme"] input[type="search"]')
.focus()
.type('bnbColors{enter}');
cy.get(
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="bnbColors"]',
).should('exist');
cy.get('.line .nv-legend .nv-legend-symbol')
.first()
.should('have.css', 'fill', 'rgb(255, 90, 95)');
});
it('should work with adhoc metric', () => {
const formData = { ...LINE_CHART_DEFAULTS, metrics: [NUM_METRIC] };
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
});
it('should work with groupby', () => {
const metrics = ['count'];
const groupby = ['gender'];
const formData = { ...LINE_CHART_DEFAULTS, metrics, groupby };
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
});
it('should work with simple filter', () => {
const metrics = ['count'];
const filters = [SIMPLE_FILTER];
const formData = {
...LINE_CHART_DEFAULTS,
metrics,
adhoc_filters: filters,
};
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
});
it('should work with series limit sort asc', () => {
const formData = {
...LINE_CHART_DEFAULTS,
metrics: [NUM_METRIC],
limit: 10,
groupby: ['name'],
timeseries_limit_metric: NUM_METRIC,
};
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
});
it('should work with series limit sort desc', () => {
const formData = {
...LINE_CHART_DEFAULTS,
metrics: [NUM_METRIC],
limit: 10,
groupby: ['name'],
timeseries_limit_metric: NUM_METRIC,
order_desc: true,
};
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
});
it('should work with rolling avg', () => {
const metrics = [NUM_METRIC];
const formData = {
...LINE_CHART_DEFAULTS,
metrics,
rolling_type: 'mean',
rolling_periods: 10,
};
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
});
it('should work with time shift 1 year', () => {
const metrics = [NUM_METRIC];
const formData = {
...LINE_CHART_DEFAULTS,
metrics,
time_compare: ['1 year'],
comparison_type: 'values',
groupby: ['gender'],
};
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
// Offset color should match original line color
cy.get('.nv-legend-text')
.contains('boy')
.siblings()
.first()
.should('have.attr', 'style')
.then(style => {
cy.get('.nv-legend-text')
.contains('boy, 1 year offset')
.siblings()
.first()
.should('have.attr', 'style')
.and('eq', style);
});
cy.get('.nv-legend-text')
.contains('girl')
.siblings()
.first()
.should('have.attr', 'style')
.then(style => {
cy.get('.nv-legend-text')
.contains('girl, 1 year offset')
.siblings()
.first()
.should('have.attr', 'style')
.and('eq', style);
});
});
it('should work with time shift yoy', () => {
const metrics = [NUM_METRIC];
const formData = {
...LINE_CHART_DEFAULTS,
metrics,
time_compare: ['1 year'],
comparison_type: 'ratio',
};
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
});
it('should work with time shift percentage change', () => {
const metrics = [NUM_METRIC];
const formData = {
...LINE_CHART_DEFAULTS,
metrics,
time_compare: ['1 year'],
comparison_type: 'percentage',
};
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
});
it('Test verbose name shows up in legend', () => {
const formData = {
...LINE_CHART_DEFAULTS,
metrics: ['count'],
};
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
cy.get('text.nv-legend-text').contains('COUNT(*)');
});
it('Test hidden annotation', () => {
const formData = {
...LINE_CHART_DEFAULTS,
metrics: ['count'],
annotation_layers: [
{
name: 'Goal line',
annotationType: 'FORMULA',
sourceType: '',
value: 'y=140000',
overrides: { time_range: null },
show: false,
showLabel: false,
titleColumn: '',
descriptionColumns: [],
timeColumn: '',
intervalEndColumn: '',
color: null,
opacity: '',
style: 'solid',
width: 1,
showMarkers: false,
hideLine: false,
},
],
};
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
cy.get('.slice_container').within(() => {
// Goal line annotation doesn't show up in legend
cy.get('.nv-legend-text').should('have.length', 1);
});
});
it('Test event annotation time override', () => {
cy.request('/chart/api/read?_flt_3_slice_name=Daily+Totals').then(
response => {
const value = response.body.pks[0];
const formData = {
...LINE_CHART_DEFAULTS,
metrics: ['count'],
annotation_layers: [
{
name: 'Yearly date',
annotationType: 'EVENT',
sourceType: 'table',
value,
overrides: { time_range: null },
show: true,
showLabel: false,
titleColumn: 'ds',
descriptionColumns: ['ds'],
timeColumn: 'ds',
color: null,
opacity: '',
style: 'solid',
width: 1,
showMarkers: false,
hideLine: false,
},
],
};
cy.visitChartByParams(formData);
},
);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
cy.get('.slice_container').within(() => {
cy.get('.nv-event-annotation-layer-0')
.children()
.should('have.length', 44);
});
});
});

View File

@@ -0,0 +1,83 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
describe('Visualization > Pie', () => {
beforeEach(() => {
cy.intercept('POST', '/api/v1/chart/data*').as('getJson');
});
const PIE_FORM_DATA = {
datasource: '3__table',
viz_type: 'pie',
slice_id: 55,
granularity_sqla: 'ds',
time_grain_sqla: 'P1D',
time_range: '100 years ago : now',
metric: 'sum__num',
adhoc_filters: [],
groupby: ['gender'],
row_limit: 50000,
pie_label_type: 'key',
donut: false,
show_legend: true,
show_labels: true,
labels_outside: true,
color_scheme: 'bnbColors',
};
function verify(formData) {
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson' });
}
it('should work with ad-hoc metric', () => {
verify(PIE_FORM_DATA);
cy.get('.chart-container .pie canvas').should('have.length', 1);
});
it('should work with simple filter', () => {
verify({
...PIE_FORM_DATA,
adhoc_filters: [
{
expressionType: 'SIMPLE',
subject: 'gender',
operator: '==',
comparator: 'boy',
clause: 'WHERE',
sqlExpression: null,
filterOptionName: 'filter_tqx1en70hh_7nksse7nqic',
},
],
});
cy.get('.chart-container .pie canvas').should('have.length', 1);
});
it('should allow type to search color schemes', () => {
verify(PIE_FORM_DATA);
cy.get('#controlSections-tab-display').click();
cy.get('.Control[data-test="color_scheme"]').scrollIntoView();
cy.get('.Control[data-test="color_scheme"] input[type="search"]')
.focus()
.type('supersetColors{enter}');
cy.get(
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]',
).should('exist');
});
});

View File

@@ -0,0 +1,105 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
describe('Visualization > Pivot Table', () => {
beforeEach(() => {
cy.intercept('POST', '/superset/explore_json/**').as('getJson');
});
const PIVOT_TABLE_FORM_DATA = {
datasource: '3__table',
viz_type: 'pivot_table',
slice_id: 61,
granularity_sqla: 'ds',
time_grain_sqla: 'P1D',
time_range: '100 years ago : now',
metrics: ['sum__num'],
adhoc_filters: [],
groupby: ['name'],
columns: ['state'],
row_limit: 5000,
pandas_aggfunc: 'sum',
pivot_margins: true,
number_format: '.3s',
combine_metric: false,
};
const TEST_METRIC = {
expressionType: 'SIMPLE',
column: {
id: 338,
column_name: 'num_boys',
expression: '',
filterable: false,
groupby: false,
is_dttm: false,
type: 'BIGINT',
optionName: '_col_num_boys',
},
aggregate: 'SUM',
hasCustomLabel: false,
label: 'SUM(num_boys)',
optionName: 'metric_gvpdjt0v2qf_6hkf56o012',
};
function verify(formData) {
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'table' });
}
it('should work with single groupby', () => {
verify(PIVOT_TABLE_FORM_DATA);
cy.get('.chart-container tr:eq(0) th:eq(1)').contains('sum__num');
cy.get('.chart-container tr:eq(1) th:eq(0)').contains('state');
cy.get('.chart-container tr:eq(2) th:eq(0)').contains('name');
});
it('should work with more than one groupby', () => {
verify({
...PIVOT_TABLE_FORM_DATA,
groupby: ['name', 'gender'],
});
cy.get('.chart-container tr:eq(0) th:eq(2)').contains('sum__num');
cy.get('.chart-container tr:eq(1) th:eq(1)').contains('state');
cy.get('.chart-container tr:eq(2) th:eq(0)').contains('name');
cy.get('.chart-container tr:eq(2) th:eq(1)').contains('gender');
});
it('should work with multiple metrics', () => {
verify({
...PIVOT_TABLE_FORM_DATA,
metrics: ['sum__num', TEST_METRIC],
});
cy.get('.chart-container tr:eq(0) th:eq(1)').contains('sum__num');
cy.get('.chart-container tr:eq(0) th:eq(2)').contains('SUM(num_boys)');
cy.get('.chart-container tr:eq(1) th:eq(0)').contains('state');
cy.get('.chart-container tr:eq(2) th:eq(0)').contains('name');
});
it('should work with multiple groupby and multiple metrics', () => {
verify({
...PIVOT_TABLE_FORM_DATA,
groupby: ['name', 'gender'],
metrics: ['sum__num', TEST_METRIC],
});
cy.get('.chart-container tr:eq(0) th:eq(2)').contains('sum__num');
cy.get('.chart-container tr:eq(0) th:eq(3)').contains('SUM(num_boys)');
cy.get('.chart-container tr:eq(2) th:eq(0)').contains('name');
cy.get('.chart-container tr:eq(2) th:eq(1)').contains('gender');
});
});

View File

@@ -0,0 +1,88 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
describe('Visualization > Sankey', () => {
beforeEach(() => {
cy.intercept('POST', '/superset/explore_json/**').as('getJson');
});
const SANKEY_FORM_DATA = {
datasource: '1__table',
viz_type: 'sankey',
slice_id: 1,
url_params: {},
granularity_sqla: null,
time_grain_sqla: 'P1D',
time_range: 'Last week',
groupby: ['source', 'target'],
metric: 'sum__value',
adhoc_filters: [],
row_limit: '5000',
color_scheme: 'bnbColors',
};
function verify(formData) {
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
}
it('should work', () => {
verify(SANKEY_FORM_DATA);
cy.get('.chart-container svg g.node rect').should('have.length', 41);
});
it('should work with filter', () => {
verify({
...SANKEY_FORM_DATA,
adhoc_filters: [
{
expressionType: 'SQL',
sqlExpression: 'SUM(value) > 0',
clause: 'HAVING',
subject: null,
operator: null,
comparator: null,
filterOptionName: 'filter_jbdwe0hayaj_h9jfer8fy58',
},
{
expressionType: 'SIMPLE',
subject: 'source',
operator: '==',
comparator: 'Energy',
clause: 'WHERE',
sqlExpression: null,
filterOptionName: 'filter_8e0otka9uif_vmqri4gmbqc',
},
],
});
cy.get('.chart-container svg g.node rect').should('have.length', 6);
});
it('should allow type to search color schemes', () => {
verify(SANKEY_FORM_DATA);
cy.get('#controlSections-tab-display').click();
cy.get('.Control[data-test="color_scheme"]').scrollIntoView();
cy.get('.Control[data-test="color_scheme"] input[type="search"]')
.focus()
.type('bnbColors{enter}');
cy.get(
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="bnbColors"]',
).should('exist');
});
});

View File

@@ -0,0 +1,108 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
// ***********************************************
// Constants for visualization tests
// ***********************************************
export const FORM_DATA_DEFAULTS = {
datasource: '3__table',
granularity_sqla: 'ds',
time_grain_sqla: null,
time_range: '100 years ago : now',
adhoc_filters: [],
groupby: [],
limit: null,
timeseries_limit_metric: null,
order_desc: false,
contribution: false,
};
export const HEALTH_POP_FORM_DATA_DEFAULTS = {
datasource: '2__table',
granularity_sqla: 'ds',
time_grain_sqla: 'P1D',
time_range: '1960-01-01 : 2014-01-02',
};
export const NUM_METRIC = {
expressionType: 'SIMPLE',
column: {
id: 336,
column_name: 'num',
verbose_name: null,
description: null,
expression: '',
filterable: false,
groupby: false,
is_dttm: false,
type: 'BIGINT',
database_expression: null,
python_date_format: null,
optionName: '_col_num',
},
aggregate: 'SUM',
sqlExpression: null,
hasCustomLabel: false,
label: 'Sum(num)',
optionName: 'metric_1de0s4viy5d_ly7y8k6ghvk',
};
export const MAX_DS = {
aggregate: 'MAX',
column: {
column_name: 'ds',
description: null,
expression: null,
filterable: true,
groupby: true,
id: 333,
is_dttm: true,
optionName: '_col_ds',
python_date_format: null,
type: 'TIMESTAMP WITHOUT TIME ZONE',
verbose_name: null,
},
expressionType: 'SIMPLE',
hasCustomLabel: false,
isNew: false,
label: 'MAX(ds)',
optionName: 'metric_pbib7j9m15a_js80vs9vca',
sqlExpression: null,
};
export const MAX_STATE = {
expressionType: 'SQL',
sqlExpression: 'MAX(UPPER(state))',
column: null,
aggregate: null,
isNew: false,
hasCustomLabel: false,
label: 'MAX(UPPER(state))',
optionName: 'metric_kvval50pvbo_hewj3pzacb',
};
export const SIMPLE_FILTER = {
expressionType: 'SIMPLE',
subject: 'name',
operator: 'IN',
comparator: ['Aaron', 'Amy', 'Andrea'],
clause: 'WHERE',
sqlExpression: null,
filterOptionName: 'filter_4y6teao56zs_ebjsvwy48c',
};

View File

@@ -0,0 +1,95 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
describe('Visualization > Sunburst', () => {
beforeEach(() => {
cy.intercept('POST', '/superset/explore_json/**').as('getJson');
});
const SUNBURST_FORM_DATA = {
datasource: '2__table',
viz_type: 'sunburst',
slice_id: 47,
granularity_sqla: 'year',
time_grain_sqla: 'P1D',
time_range: 'No filter',
groupby: ['region'],
metric: 'sum__SP_POP_TOTL',
adhoc_filters: [],
row_limit: 50000,
color_scheme: 'bnbColors',
};
function verify(formData) {
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
}
it('should work without secondary metric', () => {
verify(SUNBURST_FORM_DATA);
// There should be 7 visible arcs + 1 hidden
cy.get('.chart-container svg g#arcs path').should('have.length', 8);
});
it('should work with secondary metric', () => {
verify({
...SUNBURST_FORM_DATA,
secondary_metric: 'sum__SP_RUR_TOTL',
});
cy.get('.chart-container svg g#arcs path').should('have.length', 8);
});
it('should work with multiple groupbys', () => {
verify({
...SUNBURST_FORM_DATA,
groupby: ['region', 'country_name'],
});
cy.get('.chart-container svg g#arcs path').should('have.length', 117);
});
it('should work with filter', () => {
verify({
...SUNBURST_FORM_DATA,
adhoc_filters: [
{
expressionType: 'SIMPLE',
subject: 'region',
operator: 'IN',
comparator: ['South Asia', 'North America'],
clause: 'WHERE',
sqlExpression: null,
filterOptionName: 'filter_txje2ikiv6_wxmn0qwd1xo',
},
],
});
cy.get('.chart-container svg g#arcs path').should('have.length', 3);
});
it('should allow type to search color schemes', () => {
verify(SUNBURST_FORM_DATA);
cy.get('#controlSections-tab-display').click();
cy.get('.Control[data-test="color_scheme"]').scrollIntoView();
cy.get('.Control[data-test="color_scheme"] input[type="search"]')
.focus()
.type('supersetColors{enter}');
cy.get(
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]',
).should('exist');
});
});

View File

@@ -0,0 +1,254 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { interceptChart } from 'cypress/utils';
import {
FORM_DATA_DEFAULTS,
NUM_METRIC,
MAX_DS,
MAX_STATE,
SIMPLE_FILTER,
} from './shared.helper';
// Table
describe('Visualization > Table', () => {
beforeEach(() => {
interceptChart({ legacy: false }).as('chartData');
});
const VIZ_DEFAULTS = {
...FORM_DATA_DEFAULTS,
viz_type: 'table',
row_limit: 1000,
};
const PERCENT_METRIC = {
expressionType: 'SQL',
sqlExpression: 'CAST(SUM(num_girls) AS FLOAT)/SUM(num)',
column: null,
aggregate: null,
hasCustomLabel: true,
label: 'Girls',
optionName: 'metric_6qwzgc8bh2v_zox7hil1mzs',
};
it('Use default time column', () => {
cy.visitChartByParams({
...VIZ_DEFAULTS,
granularity_sqla: undefined,
metrics: ['count'],
});
cy.get('[data-test=adhoc_filters]').contains('ds');
});
it('Format non-numeric metrics correctly', () => {
cy.visitChartByParams({
...VIZ_DEFAULTS,
include_time: true,
granularity_sqla: 'ds',
time_grain_sqla: 'P3M',
metrics: [NUM_METRIC, MAX_DS, MAX_STATE],
});
// when format with smart_date, time column use format by granularity
cy.get('.chart-container td:nth-child(1)').contains('2008 Q1');
// other column with timestamp use adaptive formatting
cy.get('.chart-container td:nth-child(3)').contains('2008');
cy.get('.chart-container td:nth-child(4)').contains('TX');
});
it('Format with table_timestamp_format', () => {
cy.visitChartByParams({
...VIZ_DEFAULTS,
include_time: true,
granularity_sqla: 'ds',
time_grain_sqla: 'P3M',
table_timestamp_format: '%Y-%m-%d %H:%M',
metrics: [NUM_METRIC, MAX_DS, MAX_STATE],
});
// time column and MAX(ds) metric column both use UTC time
cy.get('.chart-container td:nth-child(1)').contains('2008-01-01 00:00');
cy.get('.chart-container td:nth-child(3)').contains('2008-01-01 00:00');
cy.get('.chart-container td')
.contains('2008-01-01 08:00')
.should('not.exist');
// time column should not use time granularity when timestamp format is set
cy.get('.chart-container td').contains('2008 Q1').should('not.exist');
// other num numeric metric column should stay as string
cy.get('.chart-container td').contains('TX');
});
it('Test table with groupby', () => {
cy.visitChartByParams({
...VIZ_DEFAULTS,
metrics: [NUM_METRIC, MAX_DS],
groupby: ['name'],
});
cy.verifySliceSuccess({
waitAlias: '@chartData',
querySubstring: /group by.*name/i,
chartSelector: 'table',
});
});
it('Test table with groupby + time column', () => {
cy.visitChartByParams({
...VIZ_DEFAULTS,
include_time: true,
granularity_sqla: 'ds',
time_grain_sqla: 'P3M',
metrics: [NUM_METRIC, MAX_DS],
groupby: ['name'],
});
cy.wait('@chartData').then(({ response }) => {
cy.verifySliceContainer('table');
const records = response?.body.result[0].data;
// should sort by first metric when no sort by metric is set
expect(records[0][NUM_METRIC.label]).greaterThan(
records[1][NUM_METRIC.label],
);
});
// should handle frontend sorting correctly
cy.get('.chart-container th').contains('name').click();
cy.get('.chart-container td:nth-child(2):eq(0)').contains('Adam');
cy.get('.chart-container th').contains('ds').click().click();
cy.get('.chart-container td:nth-child(1):eq(0)').contains('2008');
});
it('Test table with percent metrics and groupby', () => {
cy.visitChartByParams({
...VIZ_DEFAULTS,
percent_metrics: PERCENT_METRIC,
metrics: [],
groupby: ['name'],
});
cy.verifySliceSuccess({ waitAlias: '@chartData', chartSelector: 'table' });
});
it('Test table with groupby order desc', () => {
cy.visitChartByParams({
...VIZ_DEFAULTS,
metrics: NUM_METRIC,
groupby: ['name'],
order_desc: true,
});
cy.verifySliceSuccess({ waitAlias: '@chartData', chartSelector: 'table' });
});
it('Test table with groupby + order by + no metric', () => {
cy.visitChartByParams({
...VIZ_DEFAULTS,
metrics: [],
groupby: ['name'],
timeseries_limit_metric: NUM_METRIC,
order_desc: true,
});
// should contain only the group by column
cy.get('.chart-container th').its('length').should('eq', 1);
// should order correctly
cy.get('.chart-container td:eq(0)').contains('Michael');
cy.verifySliceSuccess({ waitAlias: '@chartData', chartSelector: 'table' });
});
it('Test table with groupby and limit', () => {
const limit = 10;
const formData = {
...VIZ_DEFAULTS,
metrics: NUM_METRIC,
groupby: ['name'],
row_limit: limit,
};
cy.visitChartByParams(formData);
cy.wait('@chartData').then(({ response }) => {
cy.verifySliceContainer('table');
expect(response?.body.result[0].data.length).to.eq(limit);
});
cy.get('[data-test="row-count-label"]').contains('10 rows');
});
it('Test table with columns and row limit', () => {
cy.visitChartByParams({
...VIZ_DEFAULTS,
// should still work when query_mode is not-set/invalid
query_mode: undefined,
all_columns: ['state'],
metrics: [],
row_limit: 100,
});
// should display in raw records mode
cy.get('div[data-test="query_mode"] .btn.active').contains('Raw records');
cy.get('div[data-test="all_columns"]').should('be.visible');
cy.get('div[data-test="groupby"]').should('not.exist');
cy.verifySliceSuccess({ waitAlias: '@chartData', chartSelector: 'table' });
cy.get('[data-test="row-count-label"]').contains('100 rows');
// should allow switch back to aggregate mode
cy.get('div[data-test="query_mode"] .btn').contains('Aggregate').click();
cy.get('div[data-test="query_mode"] .btn.active').contains('Aggregate');
cy.get('div[data-test="all_columns"]').should('not.exist');
cy.get('div[data-test="groupby"]').should('be.visible');
});
it('Test table with columns, ordering, and row limit', () => {
const limit = 10;
const formData = {
...VIZ_DEFAULTS,
query_mode: 'raw',
all_columns: ['name', 'state', 'ds', 'num'],
metrics: [],
row_limit: limit,
order_by_cols: ['["num", false]'],
};
cy.visitChartByParams(formData);
cy.wait('@chartData').then(({ response }) => {
cy.verifySliceContainer('table');
const records = response?.body.result[0].data;
expect(records[0].num).greaterThan(records[records.length - 1].num);
});
});
it('Test table with simple filter', () => {
const metrics = ['count'];
const filters = [SIMPLE_FILTER];
const formData = { ...VIZ_DEFAULTS, metrics, adhoc_filters: filters };
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@chartData', chartSelector: 'table' });
});
it('Tests table number formatting with % in metric name', () => {
const formData = {
...VIZ_DEFAULTS,
percent_metrics: PERCENT_METRIC,
groupby: ['state'],
};
cy.visitChartByParams(formData);
cy.verifySliceSuccess({
waitAlias: '@chartData',
querySubstring: /group by.*state/i,
chartSelector: 'table',
});
cy.get('td').contains(/\d*%/);
});
});

View File

@@ -0,0 +1,130 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { FORM_DATA_DEFAULTS, NUM_METRIC } from './shared.helper';
describe('Visualization > Time TableViz', () => {
beforeEach(() => {
cy.intercept('POST', '/superset/explore_json/**').as('getJson');
});
const VIZ_DEFAULTS = { ...FORM_DATA_DEFAULTS, viz_type: 'time_table' };
it('Test time series table multiple metrics last year total', () => {
const formData = {
...VIZ_DEFAULTS,
metrics: [NUM_METRIC, 'count'],
column_collection: [
{
key: '9g4K-B-YL',
label: 'Last Year',
colType: 'time',
timeLag: '1',
comparisonType: 'value',
},
],
url: '',
};
cy.visitChartByParams(formData);
cy.verifySliceSuccess({
waitAlias: '@getJson',
querySubstring: NUM_METRIC.label,
});
cy.get('[data-test="time-table"]').within(() => {
cy.get('span').contains('Sum(num)');
cy.get('span').contains('COUNT(*)');
});
});
it('Test time series table metric and group by last year total', () => {
const formData = {
...VIZ_DEFAULTS,
metrics: [NUM_METRIC],
groupby: ['gender'],
column_collection: [
{
key: '9g4K-B-YL',
label: 'Last Year',
colType: 'time',
timeLag: '1',
comparisonType: 'value',
},
],
url: '',
};
cy.visitChartByParams(formData);
cy.verifySliceSuccess({
waitAlias: '@getJson',
querySubstring: NUM_METRIC.label,
});
cy.get('[data-test="time-table"]').within(() => {
cy.get('td').contains('boy');
cy.get('td').contains('girl');
});
});
it('Test time series various time columns', () => {
const formData = {
...VIZ_DEFAULTS,
metrics: [NUM_METRIC, 'count'],
column_collection: [
{ key: 'LHHNPhamU', label: 'Current', colType: 'time', timeLag: 0 },
{
key: '9g4K-B-YL',
label: 'Last Year',
colType: 'time',
timeLag: '1',
comparisonType: 'value',
},
{
key: 'JVZXtNu7_',
label: 'YoY',
colType: 'time',
timeLag: 1,
comparisonType: 'perc',
d3format: '%',
},
{ key: 'tN5Gba36u', label: 'Trend', colType: 'spark' },
],
url: '',
};
cy.visitChartByParams(formData);
cy.verifySliceSuccess({
waitAlias: '@getJson',
querySubstring: NUM_METRIC.label,
});
cy.get('[data-test="time-table"]').within(() => {
cy.get('th').contains('Current');
cy.get('th').contains('Last Year');
cy.get('th').contains('YoY');
cy.get('th').contains('Trend');
cy.get('span').contains('%');
cy.get('svg')
.first()
.then(charts => {
const firstChart = charts[0];
expect(firstChart.clientWidth).greaterThan(0);
expect(firstChart.clientHeight).greaterThan(0);
});
});
});
});

View File

@@ -0,0 +1,96 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
describe('Visualization > Treemap', () => {
beforeEach(() => {
cy.intercept('POST', '/superset/explore_json/**').as('getJson');
});
const TREEMAP_FORM_DATA = {
datasource: '2__table',
viz_type: 'treemap',
slice_id: 10,
granularity_sqla: 'year',
time_grain_sqla: 'P1D',
time_range: 'No filter',
metrics: ['sum__SP_POP_TOTL'],
adhoc_filters: [],
groupby: ['country_code'],
row_limit: 50000,
color_scheme: 'bnbColors',
treemap_ratio: 1.618033988749895,
number_format: '.3s',
};
const level0 = '.chart-container rect[style="fill: rgb(255, 90, 95);"]';
const level1 = '.chart-container rect[style="fill: rgb(123, 0, 81);"]';
const level2 = '.chart-container rect[style="fill: rgb(0, 122, 135);"]';
function verify(formData) {
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
}
it('should work', () => {
verify(TREEMAP_FORM_DATA);
cy.get(level0).should('have.length', 1);
cy.get(level1).should('have.length', 214);
});
it('should work with multiple groupby', () => {
verify({
...TREEMAP_FORM_DATA,
groupby: ['region', 'country_code'],
});
cy.get(level0).should('have.length', 1);
cy.get(level1).should('have.length', 7);
cy.get(level2).should('have.length', 214);
});
it('should work with filter', () => {
verify({
...TREEMAP_FORM_DATA,
adhoc_filters: [
{
expressionType: 'SIMPLE',
subject: 'region',
operator: '==',
comparator: 'South Asia',
clause: 'WHERE',
sqlExpression: null,
filterOptionName: 'filter_8aqxcf5co1a_x7lm2d1fq0l',
},
],
});
cy.get(level1).should('have.length', 8);
});
it('should allow type to search color schemes and apply the scheme', () => {
verify(TREEMAP_FORM_DATA);
cy.get('.Control[data-test="color_scheme"]').scrollIntoView();
cy.get('.Control[data-test="color_scheme"] input[type="search"]')
.focus()
.type('supersetColors{enter}');
cy.get(
'.Control[data-test="color_scheme"] .ant-select-selection-item [data-test="supersetColors"]',
).should('exist');
cy.get('[data-test=run-query-button]').click();
cy.get('#rect-IND').should('have.css', 'fill', 'rgb(69, 78, 124)');
});
});

View File

@@ -0,0 +1,94 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
describe('Visualization > World Map', () => {
beforeEach(() => {
cy.intercept('POST', '/superset/explore_json/**').as('getJson');
});
const WORLD_MAP_FORM_DATA = {
datasource: '2__table',
viz_type: 'world_map',
slice_id: 45,
granularity_sqla: 'year',
time_grain_sqla: 'P1D',
time_range: '2014-01-01 : 2014-01-02',
entity: 'country_code',
country_fieldtype: 'cca3',
metric: 'sum__SP_RUR_TOTL_ZS',
adhoc_filters: [],
row_limit: 50000,
show_bubbles: true,
secondary_metric: 'sum__SP_POP_TOTL',
max_bubble_size: '25',
};
function verify(formData) {
cy.visitChartByParams(formData);
cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' });
}
it('should work with ad-hoc metric', () => {
verify(WORLD_MAP_FORM_DATA);
cy.get('.bubbles circle.datamaps-bubble').should('have.length', 206);
});
it('should work with simple filter', () => {
verify({
...WORLD_MAP_FORM_DATA,
metric: 'count',
adhoc_filters: [
{
expressionType: 'SIMPLE',
subject: 'region',
operator: '==',
comparator: 'South Asia',
clause: 'WHERE',
sqlExpression: null,
filterOptionName: 'filter_8aqxcf5co1a_x7lm2d1fq0l',
},
],
});
cy.get('.bubbles circle.datamaps-bubble').should('have.length', 8);
});
it('should hide bubbles when told so', () => {
verify({
...WORLD_MAP_FORM_DATA,
show_bubbles: false,
});
cy.get('.slice_container').then(containers => {
expect(
containers[0].querySelectorAll('.bubbles circle.datamaps-bubble')
.length,
).to.equal(0);
});
});
it('should allow type to search color schemes', () => {
verify(WORLD_MAP_FORM_DATA);
cy.get('.Control[data-test="linear_color_scheme"]').scrollIntoView();
cy.get('.Control[data-test="linear_color_scheme"] input[type="search"]')
.focus()
.type('greens{enter}');
cy.get(
'.Control[data-test="linear_color_scheme"] .ant-select-selection-item [data-test="greens"]',
).should('exist');
});
});