mirror of https://github.com/apache/superset.git
[cypress] add SQL lab tests (#5974)
* [cypress] add sqllab/sourcePanel integration tests * [cypress] add tests for SQL Lab query panel * [cypress] add selectors/ * [cypress] add tests for SQL Lab tabs * [cypress][sqllab] remove nested assertions where possible, update to single test index file * [cypress][sqllab] try force click * [cypress][sqllab] wait for saved query to load * [cypress][sqllab] unnest, use visit for href * [cypress][sqllab] try 1s wait :O * [cypress][sqllab] wait for savedquery api response * [cypress][sqllab] fix wait syntax * [cypress][sqllab] add route wait in sourcepanel for flakiness * [cypress] use *.test.js pattern for tests * [cypress] fix paths * [cypress][sqllab] actually try running lint * [cypress][dashboards] use *.test.js pattern for tests * [cypress][sqllab] combine tests, remove nesting * [cypress][sqllab] explicitly wait for query results
This commit is contained in:
parent
ee472af14d
commit
9b4cf856dd
|
@ -1,9 +1,6 @@
|
||||||
{
|
{
|
||||||
"baseUrl": "http://localhost:8081",
|
"baseUrl": "http://localhost:8081",
|
||||||
"videoUploadOnPasses": false,
|
"videoUploadOnPasses": false,
|
||||||
"ignoreTestFiles": [
|
"ignoreTestFiles": ["**/!(*.test.js)"],
|
||||||
"_*.js",
|
|
||||||
"*.helper.js"
|
|
||||||
],
|
|
||||||
"projectId": "fbf96q"
|
"projectId": "fbf96q"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
import DashboardControlsTest from './_controls';
|
|
||||||
import DashboardEditModeTest from './_edit_mode';
|
|
||||||
import DashboardFilterTest from './_filter';
|
|
||||||
import DashboardLoadTest from './_load';
|
|
||||||
|
|
||||||
describe('Dashboard', () => {
|
|
||||||
DashboardControlsTest();
|
|
||||||
DashboardEditModeTest();
|
|
||||||
DashboardFilterTest();
|
|
||||||
DashboardLoadTest();
|
|
||||||
});
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
import DashboardControlsTest from './controls';
|
||||||
|
import DashboardEditModeTest from './edit_mode';
|
||||||
|
import DashboardFilterTest from './filter';
|
||||||
|
import DashboardLoadTest from './load';
|
||||||
|
|
||||||
|
describe('Dashboard', () => {
|
||||||
|
DashboardControlsTest();
|
||||||
|
DashboardEditModeTest();
|
||||||
|
DashboardFilterTest();
|
||||||
|
DashboardLoadTest();
|
||||||
|
});
|
|
@ -1,35 +0,0 @@
|
||||||
import AreaTest from './_area';
|
|
||||||
import BigNumberTest from './_big_number';
|
|
||||||
import BigNumberTotalTest from './_big_number_total';
|
|
||||||
import BubbleTest from './_bubble';
|
|
||||||
import CompareTest from './_compare';
|
|
||||||
import DistBarTest from './_dist_bar';
|
|
||||||
import DualLineTest from './_dual_line';
|
|
||||||
import HistogramTest from './_histogram';
|
|
||||||
import LineTest from './_line';
|
|
||||||
import PieTest from './_pie';
|
|
||||||
import PivotTableTest from './_pivot_table';
|
|
||||||
import SankeyTest from './_sankey';
|
|
||||||
import SunburstTest from './_sunburst';
|
|
||||||
import TableTest from './_table';
|
|
||||||
import TreemapTest from './_treemap';
|
|
||||||
import WorldMapTest from './_world_map';
|
|
||||||
|
|
||||||
describe('All Visualizations', () => {
|
|
||||||
AreaTest();
|
|
||||||
BigNumberTest();
|
|
||||||
BigNumberTotalTest();
|
|
||||||
BubbleTest();
|
|
||||||
CompareTest();
|
|
||||||
DistBarTest();
|
|
||||||
DualLineTest();
|
|
||||||
HistogramTest();
|
|
||||||
LineTest();
|
|
||||||
PieTest();
|
|
||||||
PivotTableTest();
|
|
||||||
SankeyTest();
|
|
||||||
SunburstTest();
|
|
||||||
TableTest();
|
|
||||||
TreemapTest();
|
|
||||||
WorldMapTest();
|
|
||||||
});
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
import AreaTest from './area';
|
||||||
|
import BigNumberTest from './big_number';
|
||||||
|
import BigNumberTotalTest from './big_number_total';
|
||||||
|
import BubbleTest from './bubble';
|
||||||
|
import CompareTest from './compare';
|
||||||
|
import DistBarTest from './dist_bar';
|
||||||
|
import DualLineTest from './dual_line';
|
||||||
|
import HistogramTest from './histogram';
|
||||||
|
import LineTest from './line';
|
||||||
|
import PieTest from './pie';
|
||||||
|
import PivotTableTest from './pivot_table';
|
||||||
|
import SankeyTest from './sankey';
|
||||||
|
import SunburstTest from './sunburst';
|
||||||
|
import TableTest from './table';
|
||||||
|
import TreemapTest from './treemap';
|
||||||
|
import WorldMapTest from './world_map';
|
||||||
|
|
||||||
|
describe('All Visualizations', () => {
|
||||||
|
AreaTest();
|
||||||
|
BigNumberTest();
|
||||||
|
BigNumberTotalTest();
|
||||||
|
BubbleTest();
|
||||||
|
CompareTest();
|
||||||
|
DistBarTest();
|
||||||
|
DualLineTest();
|
||||||
|
HistogramTest();
|
||||||
|
LineTest();
|
||||||
|
PieTest();
|
||||||
|
PivotTableTest();
|
||||||
|
SankeyTest();
|
||||||
|
SunburstTest();
|
||||||
|
TableTest();
|
||||||
|
TreemapTest();
|
||||||
|
WorldMapTest();
|
||||||
|
});
|
|
@ -0,0 +1,9 @@
|
||||||
|
import queryTests from './query';
|
||||||
|
import sourcePanelTests from './sourcePanel';
|
||||||
|
import tabsTests from './tabs';
|
||||||
|
|
||||||
|
describe('All SqlLab tests', () => {
|
||||||
|
queryTests();
|
||||||
|
sourcePanelTests();
|
||||||
|
tabsTests();
|
||||||
|
});
|
|
@ -0,0 +1,103 @@
|
||||||
|
import shortid from 'shortid';
|
||||||
|
import { selectResultsTab, assertSQLLabResultsAreEqual } from './sqllab.helper';
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
describe('SqlLab query panel', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.login();
|
||||||
|
cy.server();
|
||||||
|
cy.visit('/superset/sqllab');
|
||||||
|
|
||||||
|
cy.route('POST', '/superset/sql_json/**').as('sqlLabQuery');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('supports entering and running a query', () => {
|
||||||
|
// row limit has to be < ~10 for us to be able to determine how many rows
|
||||||
|
// are fetched below (because React _Virtualized_ does not render all rows)
|
||||||
|
const rowLimit = 3;
|
||||||
|
|
||||||
|
cy.get('#brace-editor textarea').type(
|
||||||
|
`{selectall}{backspace}SELECT ds, gender, name, num FROM main.birth_names LIMIT ${rowLimit}`,
|
||||||
|
{ force: true },
|
||||||
|
);
|
||||||
|
cy.get('#js-sql-toolbar button')
|
||||||
|
.eq(0)
|
||||||
|
.click();
|
||||||
|
|
||||||
|
cy.wait('@sqlLabQuery');
|
||||||
|
|
||||||
|
cy.get('.SouthPane .ReactVirtualized__Table')
|
||||||
|
.eq(0) // ensures results tab in case preview tab exists
|
||||||
|
.then((tableNodes) => {
|
||||||
|
const [header, bodyWrapper] = tableNodes[0].childNodes;
|
||||||
|
const body = bodyWrapper.childNodes[0];
|
||||||
|
const expectedColCount = header.childNodes.length;
|
||||||
|
const expectedRowCount = body.childNodes.length;
|
||||||
|
expect(expectedColCount).to.equal(4);
|
||||||
|
expect(expectedRowCount).to.equal(rowLimit);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('successfully saves a query', () => {
|
||||||
|
cy.route('savedqueryviewapi/**').as('getSavedQuery');
|
||||||
|
|
||||||
|
const query = 'SELECT ds, gender, name, num FROM main.birth_names ORDER BY name LIMIT 3';
|
||||||
|
const savedQueryTitle = `CYPRESS TEST QUERY ${shortid.generate()}`;
|
||||||
|
|
||||||
|
// we will assert that the results of the query we save, and the saved query are the same
|
||||||
|
let initialResultsTable = null;
|
||||||
|
let savedQueryResultsTable = null;
|
||||||
|
|
||||||
|
cy.get('#brace-editor textarea')
|
||||||
|
.type(`{selectall}{backspace}${query}`, { force: true })
|
||||||
|
.focus() // focus => blur is required for updating the query that is to be saved
|
||||||
|
.blur();
|
||||||
|
|
||||||
|
// ctrl + r also runs query
|
||||||
|
cy.get('#brace-editor textarea').type('{ctrl}r', { force: true });
|
||||||
|
|
||||||
|
cy.wait('@sqlLabQuery');
|
||||||
|
|
||||||
|
// Save results to check agains below
|
||||||
|
selectResultsTab().then((resultsA) => {
|
||||||
|
initialResultsTable = resultsA[0];
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.get('#js-sql-toolbar button')
|
||||||
|
.eq(1) // save query
|
||||||
|
.click();
|
||||||
|
|
||||||
|
// Enter name + save into modal
|
||||||
|
cy.get('.modal-sm input').type(`{selectall}{backspace}${savedQueryTitle}`, {
|
||||||
|
force: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.get('.modal-sm .modal-body button')
|
||||||
|
.eq(0) // save
|
||||||
|
.click();
|
||||||
|
|
||||||
|
// visit saved queries
|
||||||
|
cy.visit('/sqllab/my_queries/');
|
||||||
|
|
||||||
|
// first row contains most recent link, follow back to SqlLab
|
||||||
|
cy.get('table tr:first-child a[href*="savedQueryId"').click();
|
||||||
|
|
||||||
|
// will timeout without explicitly waiting here
|
||||||
|
cy.wait('@getSavedQuery');
|
||||||
|
|
||||||
|
// run the saved query
|
||||||
|
cy.get('#js-sql-toolbar button')
|
||||||
|
.eq(0) // run query
|
||||||
|
.click();
|
||||||
|
|
||||||
|
cy.wait('@sqlLabQuery');
|
||||||
|
|
||||||
|
// assert the results of the saved query match the initial results
|
||||||
|
selectResultsTab().then((resultsB) => {
|
||||||
|
savedQueryResultsTable = resultsB[0];
|
||||||
|
|
||||||
|
assertSQLLabResultsAreEqual(initialResultsTable, savedQueryResultsTable);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,57 @@
|
||||||
|
import { selectResultsTab } from './sqllab.helper';
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
describe('SqlLab datasource panel', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.login();
|
||||||
|
cy.server();
|
||||||
|
cy.visit('/superset/sqllab');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates a table schema and preview when a database, schema, and table are selected', () => {
|
||||||
|
cy.route('/superset/table/**').as('tableMetadata');
|
||||||
|
|
||||||
|
// it should have dropdowns to select database, schema, and table
|
||||||
|
cy.get('.sql-toolbar .Select').should('have.length', 3);
|
||||||
|
|
||||||
|
cy.get('.sql-toolbar .table-schema').should('not.exist');
|
||||||
|
cy.get('.SouthPane .tab-content .filterable-table-container').should('not.exist');
|
||||||
|
|
||||||
|
cy.get('.sql-toolbar .Select')
|
||||||
|
.eq(0) // database select
|
||||||
|
.within(() => {
|
||||||
|
// note: we have to set force: true because the input is invisible / cypress throws
|
||||||
|
cy.get('input').type('main{enter}', { force: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.get('.sql-toolbar .Select')
|
||||||
|
.eq(1) // schema select
|
||||||
|
.within(() => {
|
||||||
|
cy.get('input').type('main{enter}', { force: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.get('.sql-toolbar .Select')
|
||||||
|
.eq(2) // table select
|
||||||
|
.within(() => {
|
||||||
|
cy.get('input').type('birth_names{enter}', { force: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.wait('@tableMetadata');
|
||||||
|
|
||||||
|
cy.get('.sql-toolbar .table-schema').should('have.length', 1);
|
||||||
|
selectResultsTab().should('have.length', 1);
|
||||||
|
|
||||||
|
// add another table and check for added schema + preview
|
||||||
|
cy.get('.sql-toolbar .Select')
|
||||||
|
.eq(2)
|
||||||
|
.within(() => {
|
||||||
|
cy.get('input').type('logs{enter}', { force: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
cy.wait('@tableMetadata');
|
||||||
|
|
||||||
|
cy.get('.sql-toolbar .table-schema').should('have.length', 2);
|
||||||
|
selectResultsTab().should('have.length', 2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,22 @@
|
||||||
|
export const selectResultsTab = () => cy.get('.SouthPane .ReactVirtualized__Table');
|
||||||
|
|
||||||
|
// this function asserts that the result set for two SQL lab table results are equal
|
||||||
|
export const assertSQLLabResultsAreEqual = (resultsA, resultsB) => {
|
||||||
|
const [headerA, bodyWrapperA] = resultsA.childNodes;
|
||||||
|
const bodyA = bodyWrapperA.childNodes[0];
|
||||||
|
|
||||||
|
const [headerB, bodyWrapperB] = resultsB.childNodes;
|
||||||
|
const bodyB = bodyWrapperB.childNodes[0];
|
||||||
|
|
||||||
|
expect(headerA.childNodes.length).to.equal(headerB.childNodes.length);
|
||||||
|
expect(bodyA.childNodes.length).to.equal(bodyB.childNodes.length);
|
||||||
|
|
||||||
|
bodyA.childNodes.forEach((rowA, rowIndex) => {
|
||||||
|
const rowB = bodyB.childNodes[rowIndex];
|
||||||
|
|
||||||
|
rowA.childNodes.forEach((cellA, columnIndex) => {
|
||||||
|
const cellB = rowB.childNodes[columnIndex];
|
||||||
|
expect(cellA.innerText).to.equal(cellB.innerText);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,38 @@
|
||||||
|
export default () => {
|
||||||
|
describe('SqlLab query tabs', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.login();
|
||||||
|
cy.server();
|
||||||
|
cy.visit('/superset/sqllab');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allows you to create a tab', () => {
|
||||||
|
cy.get('#a11y-query-editor-tabs > ul > li').then((tabList) => {
|
||||||
|
const initialTabCount = tabList.length;
|
||||||
|
|
||||||
|
// add tab
|
||||||
|
cy.get('#a11y-query-editor-tabs > ul > li')
|
||||||
|
.last()
|
||||||
|
.click();
|
||||||
|
|
||||||
|
cy.get('#a11y-query-editor-tabs > ul > li').should('have.length', initialTabCount + 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allows you to close a tab', () => {
|
||||||
|
cy.get('#a11y-query-editor-tabs > ul > li').then((tabListA) => {
|
||||||
|
const initialTabCount = tabListA.length;
|
||||||
|
|
||||||
|
// open the tab dropdown to remove
|
||||||
|
cy.get('#a11y-query-editor-tabs > ul > li:first button').click();
|
||||||
|
|
||||||
|
// first item is close
|
||||||
|
cy.get('#a11y-query-editor-tabs > ul > li:first ul li a')
|
||||||
|
.eq(0)
|
||||||
|
.click();
|
||||||
|
|
||||||
|
cy.get('#a11y-query-editor-tabs > ul > li').should('have.length', initialTabCount - 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
|
@ -216,7 +216,7 @@ class TableElement extends React.PureComponent {
|
||||||
transitionAppear
|
transitionAppear
|
||||||
onExited={this.removeFromStore.bind(this)}
|
onExited={this.removeFromStore.bind(this)}
|
||||||
>
|
>
|
||||||
<div className="TableElement m-b-10">
|
<div className="TableElement table-schema m-b-10">
|
||||||
{this.renderHeader()}
|
{this.renderHeader()}
|
||||||
<div>
|
<div>
|
||||||
{this.renderBody()}
|
{this.renderBody()}
|
||||||
|
|
Loading…
Reference in New Issue