From 9366d170daafd629025086e7f100de2013b32931 Mon Sep 17 00:00:00 2001 From: geido Date: Tue, 30 Aug 2022 18:55:22 +0300 Subject: [PATCH 01/31] Enhance dashboards list tests --- .../dashboard_list/card_view.test.ts | 124 ------------ .../integration/dashboard_list/list.test.ts | 184 ++++++++++++++++++ .../dashboard_list/list_view.test.ts | 61 ------ .../cypress-base/cypress/support/index.ts | 34 ++++ .../cypress-base/cypress/utils/urls.ts | 20 ++ 5 files changed, 238 insertions(+), 185 deletions(-) delete mode 100644 superset-frontend/cypress-base/cypress/integration/dashboard_list/card_view.test.ts create mode 100644 superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts delete mode 100644 superset-frontend/cypress-base/cypress/integration/dashboard_list/list_view.test.ts create mode 100644 superset-frontend/cypress-base/cypress/utils/urls.ts diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/card_view.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/card_view.test.ts deleted file mode 100644 index 8bfc35d71c846..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/dashboard_list/card_view.test.ts +++ /dev/null @@ -1,124 +0,0 @@ -/** - * 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 { DASHBOARD_LIST } from './dashboard_list.helper'; - -describe('Dashboard card view', () => { - beforeEach(() => { - cy.login(); - cy.visit(DASHBOARD_LIST); - cy.get('[aria-label="card-view"]').click(); - }); - - xit('should load cards', () => { - cy.get('[data-test="dashboard-list-view"]'); - cy.get('[data-test="styled-card"]').should('be.visible'); - cy.get('[data-test="styled-card"]').should('have.length', 4); // failed, xit-ed - }); - - it('should allow to favorite/unfavorite dashboard card', () => { - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-selected']") - .should('not.exist'); - cy.get("[data-test='card-actions']") - .find("[aria-label='favorite-unselected']") - .first() - .click(); - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-selected']") - .should('be.visible'); - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-unselected']") - .should('not.exist'); - - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-unselected']") - .should('not.exist'); - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-selected']") - .click(); - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-unselected']") - .should('be.visible'); - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-selected']") - .should('not.exist'); - }); - - xit('should sort correctly', () => { - // sort alphabetical - cy.get('.Select__control').last().should('be.visible'); - cy.get('.Select__control').last().click({ force: true }); - cy.get('.Select__menu').contains('Alphabetical').click(); - cy.get('[data-test="dashboard-list-view"]').should('be.visible'); - // TODO this line was flaky - cy.get('[data-test="styled-card"]').first().contains('Tabbed Dashboard'); - cy.get('[data-test="styled-card"]').last().contains("World Bank's Data"); - - // sort recently modified - cy.get('.Select__control').last().should('be.visible'); - cy.get('.Select__control').last().click({ force: true }); - cy.get('.Select__menu').contains('Recently Modified').click(); - cy.get('[data-test="dashboard-list-view"]').should('be.visible'); - cy.get('[data-test="styled-card"]').first().contains('Tabbed Dashboard'); - cy.get('[data-test="styled-card"]').last().contains("World Bank's Data"); - }); - - // real flaky - xit('should delete correctly', () => { - // show delete modal - cy.get('[data-test="more-horiz"]').last().trigger('mouseover'); - cy.get('[data-test="dashboard-card-option-delete-button"]') - .last() - .should('be.visible') - .click(); - cy.get('[data-test="modal-confirm-button"]').should( - 'have.attr', - 'disabled', - ); - cy.get('[data-test="Please Confirm-modal"]').should('be.visible'); - cy.get("[data-test='delete-modal-input']").type('DELETE'); - cy.get('[data-test="modal-confirm-button"]').should( - 'not.have.attr', - 'disabled', - ); - cy.get('[data-test="modal-cancel-button"]').click(); - }); - - // real flaky - xit('should edit correctly', () => { - // show edit modal - cy.get('[data-test="more-horiz"]').last().trigger('mouseover'); - cy.get('[data-test="dashboard-card-option-edit-button"]') - .last() - .should('be.visible') - .click(); - cy.get('[data-test="dashboard-edit-properties-form"]').should('be.visible'); - cy.get('[data-test="dashboard-title-input"]').should('not.have.value'); - cy.get('[data-test="properties-modal-cancel-button"]') - .contains('Cancel') - .click(); - }); -}); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts new file mode 100644 index 0000000000000..d8dc3285ec7b5 --- /dev/null +++ b/superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts @@ -0,0 +1,184 @@ +/** + * 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 { DASHBOARD_LIST } from 'cypress/utils/urls'; + +function refresh() { + cy.loginGoTo(DASHBOARD_LIST); +} + +function revertChanges() { + cy.deleteDashboardByName('0 - Sample dashboard'); + cy.deleteDashboardByName('1 - Sample dashboard'); + cy.deleteDashboardByName('0 - Sample dashboard | EDITED'); +} + +function ensureAuth() { + cy.login(); +} + +function toggleBulkSelect() { + cy.getBySel("bulk-select").click(); +} + +function setGridMode(type: 'card' | 'list') { + cy.get(`[aria-label="${type}-view"]`).click(); +} + +function orderAlphabetical() { + cy.get('[aria-label="Sort"]').first().click(); + cy.get('[title="Alphabetical"]').click(); +} + +describe('Dashboards list', () => { + beforeEach(() => { + ensureAuth(); + revertChanges(); + }); + + describe('list mode', () => { + before(() => { + refresh() + setGridMode('list'); + }); + + it('should load rows in list mode', () => { + cy.getBySel("listview-table").should('be.visible'); + cy.getBySel("sort-header").eq(1).contains('Title'); + cy.getBySel("sort-header").eq(2).contains('Modified by'); + cy.getBySel("sort-header").eq(3).contains('Status'); + cy.getBySel("sort-header").eq(4).contains('Modified'); + cy.getBySel("sort-header").eq(5).contains('Created by'); + cy.getBySel("sort-header").eq(6).contains('Owners'); + cy.getBySel("sort-header").eq(7).contains('Actions'); + }); + + it('should sort correctly in list mode', () => { + cy.getBySel("sort-header").eq(1).click(); + cy.getBySel("table-row").first() + .contains("ECharts Dashboard"); + cy.getBySel("sort-header").eq(1).click(); + cy.getBySel("table-row").first() + .contains("World Bank's Data"); + cy.getBySel("sort-header").eq(1).click(); + }); + + it('should bulk select in list mode', () => { + toggleBulkSelect(); + cy.get('#header-toggle-all').click(); + cy.get('[aria-label="checkbox-on"]').should('have.length', 6); + cy.getBySel("bulk-select-copy").contains('5 Selected'); + cy.getBySel("bulk-select-action").should('have.length', 2).then($btns => { + expect($btns).to.contain('Delete'); + expect($btns).to.contain('Export'); + }); + cy.getBySel("bulk-select-deselect-all").click(); + cy.get('[aria-label="checkbox-on"]').should('have.length', 0); + cy.getBySel("bulk-select-copy").contains('0 Selected'); + cy.getBySel("bulk-select-action").should('not.exist'); + }); + }); + + describe('card mode', () => { + before(() => { + refresh(); + setGridMode('card'); + }); + + it('should load rows in card mode', () => { + cy.getBySel("listview-table").should('not.exist'); + cy.getBySel("styled-card").should('have.length', 5); + }); + + it('should bulk select in card mode', () => { + toggleBulkSelect(); + cy.getBySel("styled-card").click({multiple: true}); + cy.getBySel("bulk-select-copy").contains('5 Selected'); + cy.getBySel("bulk-select-action").should('have.length', 2).then($btns => { + expect($btns).to.contain('Delete'); + expect($btns).to.contain('Export'); + }); + cy.getBySel("bulk-select-deselect-all").click(); + cy.getBySel("bulk-select-copy").contains('0 Selected'); + cy.getBySel("bulk-select-action").should('not.exist'); + }); + + it('should sort in card mode', () => { + orderAlphabetical(); + cy.getBySel("styled-card").first().contains('ECharts Dashboard'); + }); + }); + + describe('common actions', () => { + beforeEach(() => { + cy.createDashboard('0 - Sample dashboard'); + cy.createDashboard('1 - Sample dashboard'); + refresh(); + setGridMode('card'); + orderAlphabetical(); + }); + + it('should allow to favorite/unfavorite dashboard', () => { + cy.intercept(`/superset/favstar/Dashboard/*/select/`).as('select'); + cy.intercept(`/superset/favstar/Dashboard/*/unselect/`).as('unselect'); + + cy.getBySel('styled-card').first().contains('0 - Sample dashboard') + cy.getBySel('styled-card').first().find("[aria-label='favorite-unselected']") + .click(); + cy.wait('@select'); + cy.getBySel('styled-card').first().find("[aria-label='favorite-selected']") + .click(); + cy.wait('@unselect'); + cy.getBySel('styled-card') + .first() + .find("[aria-label='favorite-selected']") + .should('not.exist'); + }); + + it('should bulk delete correctly', () => { + toggleBulkSelect(); + + cy.getBySel("styled-card").eq(0).contains('0 - Sample dashboard').click(); + cy.getBySel("styled-card").eq(1).contains('1 - Sample dashboard').click(); + cy.getBySel("bulk-select-action").eq(0).contains('Delete').click(); + cy.getBySel('delete-modal-input').type('DELETE'); + cy.getBySel('modal-confirm-button').click(); + cy.getBySel("styled-card").eq(0).should('not.contain', '0 - Sample dashboard'); + cy.getBySel("styled-card").eq(1).should('not.contain', '1 - Sample dashboard'); + + }); + + it('should delete correctly', () => { + cy.getBySel("styled-card").eq(0).contains('0 - Sample dashboard'); + cy.get('[aria-label="more-vert"]').first().click(); + cy.getBySel('dashboard-card-option-delete-button').click(); + cy.getBySel('delete-modal-input').type('DELETE'); + cy.getBySel('modal-confirm-button').click(); + cy.getBySel("styled-card").eq(0).should('not.contain', '0 - Sample dashboard'); + }); + + it('should edit correctly', () => { + cy.getBySel("styled-card").eq(0).contains('0 - Sample dashboard'); + cy.get('[aria-label="more-vert"]').first().click(); + cy.getBySel('dashboard-card-option-edit-button').click(); + cy.getBySel('dashboard-title-input').type(' | EDITED'); + cy.get('button:contains("Save")').click(); + cy.getBySel("styled-card").eq(0).contains('0 - Sample dashboard | EDITED'); + }); + }); +}); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/list_view.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/list_view.test.ts deleted file mode 100644 index a758552481f90..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/dashboard_list/list_view.test.ts +++ /dev/null @@ -1,61 +0,0 @@ -/** - * 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 { DASHBOARD_LIST } from './dashboard_list.helper'; - -describe('dashboard list view', () => { - beforeEach(() => { - cy.login(); - cy.visit(DASHBOARD_LIST); - cy.get('[aria-label="list-view"]').click(); - }); - - xit('should load rows', () => { - cy.get('[data-test="listview-table"]').should('be.visible'); - // check dashboard list view header - cy.get('[data-test="sort-header"]').eq(1).contains('Title'); - cy.get('[data-test="sort-header"]').eq(2).contains('Modified by'); - cy.get('[data-test="sort-header"]').eq(3).contains('Status'); - cy.get('[data-test="sort-header"]').eq(4).contains('Modified'); - cy.get('[data-test="sort-header"]').eq(5).contains('Created by'); - cy.get('[data-test="sort-header"]').eq(6).contains('Owners'); - cy.get('[data-test="sort-header"]').eq(7).contains('Actions'); - cy.get('[data-test="table-row"]').should('have.length', 4); // failed, xit-ed - }); - - xit('should sort correctly', () => { - cy.get('[data-test="sort-header"]').eq(1).click(); - cy.get('[data-test="sort-header"]').eq(1).click(); - cy.get('[data-test="table-row"]') - .first() - .find('[data-test="table-row-cell"]') - .find('[data-test="cell-text"]') - .contains("World Bank's Data"); - }); - - it('should bulk delete correctly', () => { - cy.get('[data-test="listview-table"]').should('be.visible'); - cy.get('[data-test="bulk-select"]').eq(0).click(); - cy.get('[aria-label="checkbox-off"]').eq(1).siblings('input').click(); - cy.get('[aria-label="checkbox-off"]').eq(2).siblings('input').click(); - cy.get('[data-test="bulk-select-action"]').eq(0).click(); - cy.get('[data-test="delete-modal-input"]').eq(0).type('DELETE'); - cy.get('[data-test="modal-confirm-button"]').eq(0).click(); - cy.get('[aria-label="checkbox-on"]').should('not.exist'); - }); -}); diff --git a/superset-frontend/cypress-base/cypress/support/index.ts b/superset-frontend/cypress-base/cypress/support/index.ts index 7ededd67a5fee..782490b250bdc 100644 --- a/superset-frontend/cypress-base/cypress/support/index.ts +++ b/superset-frontend/cypress-base/cypress/support/index.ts @@ -24,6 +24,14 @@ const TokenName = Cypress.env('TOKEN_NAME'); require('cy-verify-downloads').addCustomCommand(); +Cypress.Commands.add('getBySel', (selector, ...args) => { + return cy.get(`[data-test=${selector}]`, ...args) +}); + +Cypress.Commands.add('getBySelLike', (selector, ...args) => { + return cy.get(`[data-test*=${selector}]`, ...args) +}); + /* eslint-disable consistent-return */ Cypress.on('uncaught:exception', err => { // ignore ResizeObserver client errors, as they are unrelated to operation @@ -45,6 +53,11 @@ Cypress.Commands.add('login', () => { }); }); +Cypress.Commands.add('loginGoTo', url => { + cy.login(); + cy.visit(url); +}); + Cypress.Commands.add('visitChartByName', name => { cy.request(`/chart/api/read?_flt_3_slice_name=${name}`).then(response => { cy.visit(`${BASE_EXPLORE_URL}{"slice_id": ${response.body.pks[0]}}`); @@ -141,6 +154,27 @@ Cypress.Commands.add( }, ); +Cypress.Commands.add('createDashboard', (dashboardName: string) => + cy + .request({ + method: 'POST', + url: `/api/v1/dashboard/`, + body: { + dashboard_title: dashboardName, + }, + headers: { + Cookie: `csrf_access_token=${window.localStorage.getItem( + 'access_token', + )}`, + 'Content-Type': 'application/json', + Authorization: `Bearer ${TokenName}`, + 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, + Referer: `${Cypress.config().baseUrl}/`, + }, + }) + .then(resp => resp), +); + Cypress.Commands.add('deleteDashboardByName', (name: string) => cy.getDashboards().then((dashboards: any) => { dashboards?.forEach((element: any) => { diff --git a/superset-frontend/cypress-base/cypress/utils/urls.ts b/superset-frontend/cypress-base/cypress/utils/urls.ts new file mode 100644 index 0000000000000..227a627afb810 --- /dev/null +++ b/superset-frontend/cypress-base/cypress/utils/urls.ts @@ -0,0 +1,20 @@ +/** + * 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. + */ + + export const DASHBOARD_LIST = '/dashboard/list/'; \ No newline at end of file From 18641150c40dac1655fa99aff024a5cd8eafb50d Mon Sep 17 00:00:00 2001 From: geido Date: Wed, 31 Aug 2022 16:14:31 +0300 Subject: [PATCH 02/31] Seed/clean up dashboards --- .../cypress/fixtures/dashboards.json | 14 +++ .../dashboard_list/dashboard_list.helper.ts | 19 --- .../dashboardlist.applitools.test.ts | 2 +- .../integration/dashboard_list/list.test.ts | 116 ++++++++++++------ .../cypress-base/cypress/support/index.d.ts | 16 ++- .../cypress-base/cypress/support/index.ts | 71 ++++++----- 6 files changed, 149 insertions(+), 89 deletions(-) create mode 100644 superset-frontend/cypress-base/cypress/fixtures/dashboards.json delete mode 100644 superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboard_list.helper.ts diff --git a/superset-frontend/cypress-base/cypress/fixtures/dashboards.json b/superset-frontend/cypress-base/cypress/fixtures/dashboards.json new file mode 100644 index 0000000000000..6972cb0552e1a --- /dev/null +++ b/superset-frontend/cypress-base/cypress/fixtures/dashboards.json @@ -0,0 +1,14 @@ +[ + { + "dashboard_title": "1 - Sample dashboard" + }, + { + "dashboard_title": "2 - Sample dashboard" + }, + { + "dashboard_title": "3 - Sample dashboard" + }, + { + "dashboard_title": "4 - Sample dashboard" + } +] \ No newline at end of file diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboard_list.helper.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboard_list.helper.ts deleted file mode 100644 index 5ccb39432cd81..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboard_list.helper.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * 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. - */ -export const DASHBOARD_LIST = '/dashboard/list/'; diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboardlist.applitools.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboardlist.applitools.test.ts index d85d9b11aee22..c4c62e6c6c290 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboardlist.applitools.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboardlist.applitools.test.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { DASHBOARD_LIST } from './dashboard_list.helper'; + import { DASHBOARD_LIST } from 'cypress/utils/urls'; describe('dashboard list view', () => { beforeEach(() => { diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts index d8dc3285ec7b5..8378370ba67e3 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts @@ -18,20 +18,6 @@ */ import { DASHBOARD_LIST } from 'cypress/utils/urls'; -function refresh() { - cy.loginGoTo(DASHBOARD_LIST); -} - -function revertChanges() { - cy.deleteDashboardByName('0 - Sample dashboard'); - cy.deleteDashboardByName('1 - Sample dashboard'); - cy.deleteDashboardByName('0 - Sample dashboard | EDITED'); -} - -function ensureAuth() { - cy.login(); -} - function toggleBulkSelect() { cy.getBySel("bulk-select").click(); } @@ -45,15 +31,32 @@ function orderAlphabetical() { cy.get('[title="Alphabetical"]').click(); } +function openProperties() { + cy.get('[aria-label="more-vert"]').first().click(); + cy.getBySel('dashboard-card-option-edit-button').click(); +} + +function openMenu() { + cy.get('[aria-label="more-vert"]').first().click(); +} + +function confirmDelete() { + cy.getBySel('delete-modal-input').type('DELETE'); + cy.getBySel('modal-confirm-button').click(); +} + describe('Dashboards list', () => { + before(() => { + cy.login(); + }); + beforeEach(() => { - ensureAuth(); - revertChanges(); + cy.preserveLogin(); }); describe('list mode', () => { before(() => { - refresh() + cy.visit(DASHBOARD_LIST); setGridMode('list'); }); @@ -96,7 +99,7 @@ describe('Dashboards list', () => { describe('card mode', () => { before(() => { - refresh(); + cy.visit(DASHBOARD_LIST); setGridMode('card'); }); @@ -126,18 +129,18 @@ describe('Dashboards list', () => { describe('common actions', () => { beforeEach(() => { - cy.createDashboard('0 - Sample dashboard'); - cy.createDashboard('1 - Sample dashboard'); - refresh(); - setGridMode('card'); - orderAlphabetical(); + cy.createSampleDashboards(); + cy.visit(DASHBOARD_LIST); }); it('should allow to favorite/unfavorite dashboard', () => { cy.intercept(`/superset/favstar/Dashboard/*/select/`).as('select'); cy.intercept(`/superset/favstar/Dashboard/*/unselect/`).as('unselect'); - cy.getBySel('styled-card').first().contains('0 - Sample dashboard') + setGridMode('card'); + orderAlphabetical(); + + cy.getBySel('styled-card').first().contains('1 - Sample dashboard') cy.getBySel('styled-card').first().find("[aria-label='favorite-unselected']") .click(); cy.wait('@select'); @@ -153,32 +156,67 @@ describe('Dashboards list', () => { it('should bulk delete correctly', () => { toggleBulkSelect(); - cy.getBySel("styled-card").eq(0).contains('0 - Sample dashboard').click(); - cy.getBySel("styled-card").eq(1).contains('1 - Sample dashboard').click(); + // bulk deletes in card-view + setGridMode('card'); + orderAlphabetical(); + + cy.getBySel("styled-card").eq(0).contains('1 - Sample dashboard').click(); + cy.getBySel("styled-card").eq(1).contains('2 - Sample dashboard').click(); cy.getBySel("bulk-select-action").eq(0).contains('Delete').click(); - cy.getBySel('delete-modal-input').type('DELETE'); - cy.getBySel('modal-confirm-button').click(); - cy.getBySel("styled-card").eq(0).should('not.contain', '0 - Sample dashboard'); - cy.getBySel("styled-card").eq(1).should('not.contain', '1 - Sample dashboard'); + confirmDelete(); + cy.getBySel("styled-card").eq(0).should('not.contain', '1 - Sample dashboard'); + cy.getBySel("styled-card").eq(1).should('not.contain', '2 - Sample dashboard'); + // bulk deletes in list-view + setGridMode('list'); + cy.getBySel("table-row").eq(0).contains('3 - Sample dashboard'); + cy.getBySel("table-row").eq(1).contains('4 - Sample dashboard'); + cy.get('[data-test="table-row"] input[type="checkbox"]').eq(0).click(); + cy.get('[data-test="table-row"] input[type="checkbox"]').eq(1).click(); + cy.getBySel("bulk-select-action").eq(0).contains('Delete').click(); + confirmDelete(); + cy.getBySel("table-row").eq(0).should('not.contain', '3 - Sample dashboard'); + cy.getBySel("table-row").eq(1).should('not.contain', '4 - Sample dashboard'); }); it('should delete correctly', () => { - cy.getBySel("styled-card").eq(0).contains('0 - Sample dashboard'); - cy.get('[aria-label="more-vert"]').first().click(); + // deletes in card-view + setGridMode('card'); + orderAlphabetical(); + + cy.getBySel("styled-card").eq(0).contains('1 - Sample dashboard'); + openMenu(); cy.getBySel('dashboard-card-option-delete-button').click(); - cy.getBySel('delete-modal-input').type('DELETE'); - cy.getBySel('modal-confirm-button').click(); - cy.getBySel("styled-card").eq(0).should('not.contain', '0 - Sample dashboard'); + confirmDelete(); + cy.getBySel("styled-card").eq(0).should('not.contain', '1 - Sample dashboard'); + + // deletes in list-view + setGridMode('list'); + cy.getBySel("table-row").eq(0).contains('2 - Sample dashboard'); + cy.getBySel("dashboard-list-trash-icon").eq(0).click(); + confirmDelete(); + cy.getBySel("table-row").eq(0).should('not.contain', '2 - Sample dashboard'); + }); it('should edit correctly', () => { - cy.getBySel("styled-card").eq(0).contains('0 - Sample dashboard'); - cy.get('[aria-label="more-vert"]').first().click(); - cy.getBySel('dashboard-card-option-edit-button').click(); + // edits in card-view + setGridMode('card'); + orderAlphabetical(); + cy.getBySel("styled-card").eq(0).contains('1 - Sample dashboard'); + + // change title + openProperties(); cy.getBySel('dashboard-title-input').type(' | EDITED'); cy.get('button:contains("Save")').click(); - cy.getBySel("styled-card").eq(0).contains('0 - Sample dashboard | EDITED'); + cy.getBySel("styled-card").eq(0).contains('1 - Sample dashboard | EDITED'); + + // edits in list-view + setGridMode('list'); + cy.getBySel("edit-alt").eq(0).click(); + cy.getBySel('dashboard-title-input').clear().type('1 - Sample dashboard'); + cy.get('button:contains("Save")').click(); + cy.getBySel("table-row").eq(0).contains('1 - Sample dashboard'); }); }); }); diff --git a/superset-frontend/cypress-base/cypress/support/index.d.ts b/superset-frontend/cypress-base/cypress/support/index.d.ts index eca68a7ced7fe..edb9a9c18b0de 100644 --- a/superset-frontend/cypress-base/cypress/support/index.d.ts +++ b/superset-frontend/cypress-base/cypress/support/index.d.ts @@ -29,6 +29,15 @@ declare namespace Cypress { * Login test user. */ login(): void; + preserveLogin(): void; + + /** + * + * Utils + */ + + getBySel(selector: string): cy; + getBySelLike(selector: string): cy; visitChartByParams(params: string | Record): cy; visitChartByName(name: string): cy; @@ -54,11 +63,16 @@ declare namespace Cypress { getDashboards(): cy; getCharts(): cy; + /** + * Create + */ + createSampleDashboards(): void; + /** * Delete */ deleteDashboard(id: number): cy; - deleteDashboardByName(name: string): cy; + deleteDashboardByName(dashboardName: string): cy; deleteChartByName(name: string): cy; deleteChart(id: number): cy; } diff --git a/superset-frontend/cypress-base/cypress/support/index.ts b/superset-frontend/cypress-base/cypress/support/index.ts index 782490b250bdc..90442649a2aa4 100644 --- a/superset-frontend/cypress-base/cypress/support/index.ts +++ b/superset-frontend/cypress-base/cypress/support/index.ts @@ -19,10 +19,22 @@ import '@cypress/code-coverage/support'; import '@applitools/eyes-cypress/commands'; +require('cy-verify-downloads').addCustomCommand(); + const BASE_EXPLORE_URL = '/explore/?form_data='; const TokenName = Cypress.env('TOKEN_NAME'); -require('cy-verify-downloads').addCustomCommand(); +function resetSamples() { + cy.fixture('dashboards.json').then((dashboards) => { + dashboards.forEach((d: { dashboard_title: string }) => { + cy.deleteDashboardByName(d.dashboard_title); + }); + }); +} + +beforeEach(() => { + resetSamples(); +}); Cypress.Commands.add('getBySel', (selector, ...args) => { return cy.get(`[data-test=${selector}]`, ...args) @@ -53,9 +65,8 @@ Cypress.Commands.add('login', () => { }); }); -Cypress.Commands.add('loginGoTo', url => { - cy.login(); - cy.visit(url); +Cypress.Commands.add('preserveLogin', () => { + Cypress.Cookies.preserveOnce('session'); }); Cypress.Commands.add('visitChartByName', name => { @@ -154,35 +165,37 @@ Cypress.Commands.add( }, ); -Cypress.Commands.add('createDashboard', (dashboardName: string) => - cy - .request({ - method: 'POST', - url: `/api/v1/dashboard/`, - body: { - dashboard_title: dashboardName, - }, - headers: { - Cookie: `csrf_access_token=${window.localStorage.getItem( - 'access_token', - )}`, - 'Content-Type': 'application/json', - Authorization: `Bearer ${TokenName}`, - 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, - Referer: `${Cypress.config().baseUrl}/`, - }, +Cypress.Commands.add('createSampleDashboards', () => + cy.fixture('dashboards.json').then((dashboards) => { + dashboards.forEach((d: { dashboard_title: string }) => { + cy + .request({ + method: 'POST', + url: `/api/v1/dashboard/`, + body: { + dashboard_title: d.dashboard_title, + }, + headers: { + Cookie: `csrf_access_token=${window.localStorage.getItem( + 'access_token', + )}`, + 'Content-Type': 'application/json', + Authorization: `Bearer ${TokenName}`, + 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, + Referer: `${Cypress.config().baseUrl}/`, + }, + }) + .then(resp => resp); + }); }) - .then(resp => resp), ); -Cypress.Commands.add('deleteDashboardByName', (name: string) => +Cypress.Commands.add('deleteDashboardByName', (dashboardName: string) => cy.getDashboards().then((dashboards: any) => { - dashboards?.forEach((element: any) => { - if (element.dashboard_title === name) { - const elementId = element.id; - cy.deleteDashboard(elementId); - } - }); + const dashboard = dashboards.find(d => d.dashboard_title === dashboardName); + if (dashboard) { + cy.deleteDashboard(dashboard.id); + } }), ); From 04d1a765103d3f730590daf3f5c6d055892107b2 Mon Sep 17 00:00:00 2001 From: geido Date: Wed, 31 Aug 2022 17:01:08 +0300 Subject: [PATCH 03/31] Enhance dashboards list filtering --- .../cypress/integration/dashboard/utils.ts | 47 +++++++ .../integration/dashboard_list/filter.test.ts | 125 ++++++++---------- .../integration/dashboard_list/list.test.ts | 19 ++- 3 files changed, 117 insertions(+), 74 deletions(-) create mode 100644 superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts new file mode 100644 index 0000000000000..1d295202364e2 --- /dev/null +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts @@ -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. + */ + +export function setGridMode(type: 'card' | 'list') { + cy.get(`[aria-label="${type}-view"]`).click(); +} + +export function interceptFiltering() { + cy.intercept('GET', `/api/v1/dashboard/?q=*`).as('filtering'); +} + +export function interceptBulkDelete() { + cy.intercept('DELETE', `/api/v1/dashboard/?q=*`).as('bulkDelete'); +} + +export function interceptDelete() { + cy.intercept('DELETE', `/api/v1/dashboard/*`).as('delete'); +} + +export function interceptUpdate() { + cy.intercept('PUT', `/api/v1/dashboard/*`).as('update'); +} + +export function setFilter(filter: string, option: string) { + interceptFiltering(); + + cy.get(`[aria-label="${filter}"]`).first().click(); + cy.get(`[aria-label="${filter}"] [title="${option}"]`).click(); + + cy.wait('@filtering'); +} \ No newline at end of file diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts index bf852fc62558f..dffeddbe0ae17 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts @@ -16,86 +16,75 @@ * specific language governing permissions and limitations * under the License. */ -import { DASHBOARD_LIST } from './dashboard_list.helper'; + import { DASHBOARD_LIST } from 'cypress/utils/urls'; + import { setGridMode, setFilter } from '../dashboard/utils'; -describe('dashboard filters card view', () => { - beforeEach(() => { +function resetFilters() { + cy.get('[aria-label="close-circle"]').click({ multiple: true, force: true }); +} + +describe('Dashboards filters', () => { + before(() => { cy.login(); cy.visit(DASHBOARD_LIST); - cy.get('[aria-label="card-view"]').click(); }); - it('should filter by owners correctly', () => { - // filter by owners - cy.get('[data-test="filters-select"]').first().click(); - cy.get('.rc-virtual-list').contains('alpha user').click(); - cy.get('[data-test="styled-card"]').should('not.exist'); - cy.get('[data-test="filters-select"]').first().click(); - cy.get('.rc-virtual-list').contains('gamma user').click(); - cy.get('[data-test="styled-card"]').should('not.exist'); + beforeEach(() => { + cy.preserveLogin(); + resetFilters(); }); - it('should filter by created by correctly', () => { - // filter by created by - cy.get('[data-test="filters-select"]').eq(1).click(); - cy.get('.rc-virtual-list').contains('alpha user').click(); - cy.get('.ant-card').should('not.exist'); - cy.get('[data-test="filters-select"]').eq(1).click(); - cy.get('.rc-virtual-list').contains('gamma user').click(); - cy.get('.ant-card').should('not.exist'); - }); + describe('card-view', () => { + before(() => { + setGridMode('card'); + }); - it('should filter by published correctly', () => { - // filter by published - cy.get('[data-test="filters-select"]').eq(2).click(); - cy.get('.rc-virtual-list').contains('Published').click({ timeout: 5000 }); - cy.get('[data-test="styled-card"]').should('have.length', 3); - cy.get('[data-test="styled-card"]') - .contains('USA Births Names') - .should('be.visible'); - cy.get('[data-test="filters-select"]').eq(1).click(); - cy.get('[data-test="filters-select"]').eq(1).type('unpub{enter}'); - cy.get('[data-test="styled-card"]').should('have.length', 3); - }); -}); + it('should filter by owners correctly', () => { + setFilter('Owner', 'alpha user'); + cy.getBySel('styled-card').should('not.exist'); + setFilter('Owner', 'admin user'); + cy.getBySel('styled-card').should('have.length', 1); + }); -describe('dashboard filters list view', () => { - beforeEach(() => { - cy.login(); - cy.visit(DASHBOARD_LIST); - cy.get('[aria-label="list-view"]').click(); - }); + it('should filter by created by correctly', () => { + setFilter('Created by', 'alpha user'); + cy.getBySel('styled-card').should('not.exist'); + setFilter('Created by', 'admin user') + cy.getBySel('styled-card').should('have.length', 1); + }); - it('should filter by owners correctly', () => { - // filter by owners - cy.get('[data-test="filters-select"]').first().click(); - cy.get('.rc-virtual-list').contains('alpha user').click(); - cy.get('[data-test="table-row"]').should('not.exist'); - cy.get('[data-test="filters-select"]').first().click(); - cy.get('.rc-virtual-list').contains('gamma user').click(); - cy.get('[data-test="table-row"]').should('not.exist'); + it('should filter by published correctly', () => { + setFilter('Status', 'Published'); + cy.getBySel('styled-card').should('have.length', 3); + setFilter('Status', 'Draft'); + cy.get('[data-test="styled-card"]').should('have.length', 2); + }); }); - it('should filter by created by correctly', () => { - // filter by created by - cy.get('[data-test="filters-select"]').eq(1).click(); - cy.get('.rc-virtual-list').contains('alpha user').click(); - cy.get('[data-test="table-row"]').should('not.exist'); - cy.get('[data-test="filters-select"]').eq(1).click(); - cy.get('.rc-virtual-list').contains('gamma user').click(); - cy.get('[data-test="table-row"]').should('not.exist'); - }); + describe('list-view', () => { + before(() => { + setGridMode('list'); + }); + + it('should filter by created by correctly', () => { + setFilter('Owner', 'alpha user'); + cy.getBySel('table-row').should('not.exist'); + setFilter('Owner', 'admin user'); + cy.getBySel('table-row').should('have.length', 1); + }); + + it('should filter by created by correctly', () => { + setFilter('Created by', 'alpha user'); + cy.getBySel('table-row').should('not.exist'); + setFilter('Created by', 'admin user') + cy.getBySel('table-row').should('have.length', 1); + }); - it('should filter by published correctly', () => { - // filter by published - cy.get('[data-test="filters-select"]').eq(2).click(); - cy.get('.rc-virtual-list').contains('Published').click(); - cy.get('[data-test="table-row"]').should('have.length', 3); - cy.get('[data-test="table-row"]') - .contains('USA Births Names') - .should('be.visible'); - cy.get('[data-test="filters-select"]').eq(2).click(); - cy.get('[data-test="filters-select"]').eq(2).type('unpub{enter}'); - cy.get('[data-test="table-row"]').should('have.length', 3); + it('should filter by published correctly', () => { + setFilter('Status', 'Published'); + cy.getBySel('table-row').should('have.length', 3); + setFilter('Status', 'Draft'); + cy.getBySel('table-row').should('have.length', 2); + }); }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts index 8378370ba67e3..b1baefd17062e 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts @@ -17,18 +17,14 @@ * under the License. */ import { DASHBOARD_LIST } from 'cypress/utils/urls'; +import { setGridMode, setFilter, interceptBulkDelete, interceptUpdate, interceptDelete } from '../dashboard/utils'; function toggleBulkSelect() { cy.getBySel("bulk-select").click(); } -function setGridMode(type: 'card' | 'list') { - cy.get(`[aria-label="${type}-view"]`).click(); -} - function orderAlphabetical() { - cy.get('[aria-label="Sort"]').first().click(); - cy.get('[title="Alphabetical"]').click(); + setFilter('Sort', 'Alphabetical'); } function openProperties() { @@ -154,6 +150,7 @@ describe('Dashboards list', () => { }); it('should bulk delete correctly', () => { + interceptBulkDelete(); toggleBulkSelect(); // bulk deletes in card-view @@ -164,6 +161,7 @@ describe('Dashboards list', () => { cy.getBySel("styled-card").eq(1).contains('2 - Sample dashboard').click(); cy.getBySel("bulk-select-action").eq(0).contains('Delete').click(); confirmDelete(); + cy.wait('@bulkDelete'); cy.getBySel("styled-card").eq(0).should('not.contain', '1 - Sample dashboard'); cy.getBySel("styled-card").eq(1).should('not.contain', '2 - Sample dashboard'); @@ -175,11 +173,14 @@ describe('Dashboards list', () => { cy.get('[data-test="table-row"] input[type="checkbox"]').eq(1).click(); cy.getBySel("bulk-select-action").eq(0).contains('Delete').click(); confirmDelete(); + cy.wait('@bulkDelete'); cy.getBySel("table-row").eq(0).should('not.contain', '3 - Sample dashboard'); cy.getBySel("table-row").eq(1).should('not.contain', '4 - Sample dashboard'); }); it('should delete correctly', () => { + interceptDelete(); + // deletes in card-view setGridMode('card'); orderAlphabetical(); @@ -188,6 +189,7 @@ describe('Dashboards list', () => { openMenu(); cy.getBySel('dashboard-card-option-delete-button').click(); confirmDelete(); + cy.wait('@delete'); cy.getBySel("styled-card").eq(0).should('not.contain', '1 - Sample dashboard'); // deletes in list-view @@ -195,11 +197,14 @@ describe('Dashboards list', () => { cy.getBySel("table-row").eq(0).contains('2 - Sample dashboard'); cy.getBySel("dashboard-list-trash-icon").eq(0).click(); confirmDelete(); + cy.wait('@delete'); cy.getBySel("table-row").eq(0).should('not.contain', '2 - Sample dashboard'); }); it('should edit correctly', () => { + interceptUpdate(); + // edits in card-view setGridMode('card'); orderAlphabetical(); @@ -209,6 +214,7 @@ describe('Dashboards list', () => { openProperties(); cy.getBySel('dashboard-title-input').type(' | EDITED'); cy.get('button:contains("Save")').click(); + cy.wait('@update'); cy.getBySel("styled-card").eq(0).contains('1 - Sample dashboard | EDITED'); // edits in list-view @@ -216,6 +222,7 @@ describe('Dashboards list', () => { cy.getBySel("edit-alt").eq(0).click(); cy.getBySel('dashboard-title-input').clear().type('1 - Sample dashboard'); cy.get('button:contains("Save")').click(); + cy.wait('@update'); cy.getBySel("table-row").eq(0).contains('1 - Sample dashboard'); }); }); From f5a74cdc0dccd4cef01b83c37b8c0547f5d90a8a Mon Sep 17 00:00:00 2001 From: geido Date: Wed, 31 Aug 2022 19:25:58 +0300 Subject: [PATCH 04/31] Enhance charts list tests --- .../cypress-base/cypress/fixtures/charts.json | 38 +++ .../integration/chart_list/list.test.ts | 244 ++++++++++++++++++ .../integration/chart_list/list_view.test.ts | 73 ------ .../dashboard/nativeFilters.test.ts | 2 +- .../cypress/integration/dashboard/utils.ts | 26 +- .../dashboardlist.applitools.test.ts | 2 +- .../integration/dashboard_list/filter.test.ts | 9 +- .../integration/dashboard_list/list.test.ts | 149 ++++++----- .../cypress/integration/explore/utils.ts | 47 ++++ .../cypress-base/cypress/support/index.d.ts | 9 +- .../cypress-base/cypress/support/index.ts | 148 +++++++---- .../cypress-base/cypress/utils/index.ts | 8 + .../cypress-base/cypress/utils/urls.ts | 3 +- 13 files changed, 548 insertions(+), 210 deletions(-) create mode 100644 superset-frontend/cypress-base/cypress/fixtures/charts.json create mode 100644 superset-frontend/cypress-base/cypress/integration/chart_list/list.test.ts delete mode 100644 superset-frontend/cypress-base/cypress/integration/chart_list/list_view.test.ts create mode 100644 superset-frontend/cypress-base/cypress/integration/explore/utils.ts diff --git a/superset-frontend/cypress-base/cypress/fixtures/charts.json b/superset-frontend/cypress-base/cypress/fixtures/charts.json new file mode 100644 index 0000000000000..6bdeda9e413b6 --- /dev/null +++ b/superset-frontend/cypress-base/cypress/fixtures/charts.json @@ -0,0 +1,38 @@ +[ + { + "slice_name": "1 - Sample chart", + "description": "chart description", + "owners": [1], + "viz_type": "line", + "cache_timeout": 1000, + "datasource_id": 1, + "datasource_type": "table" + }, + { + "slice_name": "2 - Sample chart", + "description": "chart description", + "owners": [1], + "viz_type": "line", + "cache_timeout": 1000, + "datasource_id": 1, + "datasource_type": "table" + }, + { + "slice_name": "3 - Sample chart", + "description": "chart description", + "owners": [1], + "viz_type": "line", + "cache_timeout": 1000, + "datasource_id": 1, + "datasource_type": "table" + }, + { + "slice_name": "4 - Sample chart", + "description": "chart description", + "owners": [1], + "viz_type": "line", + "cache_timeout": 1000, + "datasource_id": 1, + "datasource_type": "table" + } +] \ No newline at end of file diff --git a/superset-frontend/cypress-base/cypress/integration/chart_list/list.test.ts b/superset-frontend/cypress-base/cypress/integration/chart_list/list.test.ts new file mode 100644 index 0000000000000..966725e9217dc --- /dev/null +++ b/superset-frontend/cypress-base/cypress/integration/chart_list/list.test.ts @@ -0,0 +1,244 @@ +/** + * 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 { CHART_LIST } from 'cypress/utils/urls'; +import { setGridMode, toggleBulkSelect } from 'cypress/utils'; +import { + setFilter, + interceptBulkDelete, + interceptUpdate, + interceptDelete, +} from '../explore/utils'; + +function orderAlphabetical() { + setFilter('Sort', 'Alphabetical'); +} + +function openProperties() { + cy.get('[aria-label="more-vert"]').eq(1).click(); + cy.getBySel('chart-list-edit-option').click(); +} + +function openMenu() { + cy.get('[aria-label="more-vert"]').eq(1).click(); +} + +function confirmDelete() { + cy.getBySel('delete-modal-input').type('DELETE'); + cy.getBySel('modal-confirm-button').click(); +} + +describe('Charts list', () => { + before(() => { + cy.login(); + }); + + beforeEach(() => { + cy.preserveLogin(); + }); + + describe('list mode', () => { + before(() => { + cy.visit(CHART_LIST); + setGridMode('list'); + }); + + it('should load rows in list mode', () => { + cy.getBySel('listview-table').should('be.visible'); + cy.getBySel('sort-header').eq(1).contains('Chart'); + cy.getBySel('sort-header').eq(2).contains('Visualization type'); + cy.getBySel('sort-header').eq(3).contains('Dataset'); + cy.getBySel('sort-header').eq(4).contains('Modified by'); + cy.getBySel('sort-header').eq(5).contains('Last modified'); + cy.getBySel('sort-header').eq(6).contains('Created by'); + cy.getBySel('sort-header').eq(7).contains('Actions'); + }); + + it('should sort correctly in list mode', () => { + cy.getBySel('sort-header').eq(1).click(); + cy.getBySel('table-row').first().contains('% Rural'); + cy.getBySel('sort-header').eq(1).click(); + cy.getBySel('table-row').first().contains("World's Population"); + cy.getBySel('sort-header').eq(1).click(); + }); + + it('should bulk select in list mode', () => { + toggleBulkSelect(); + cy.get('#header-toggle-all').click(); + cy.get('[aria-label="checkbox-on"]').should('have.length', 26); + cy.getBySel('bulk-select-copy').contains('25 Selected'); + cy.getBySel('bulk-select-action') + .should('have.length', 2) + .then($btns => { + expect($btns).to.contain('Delete'); + expect($btns).to.contain('Export'); + }); + cy.getBySel('bulk-select-deselect-all').click(); + cy.get('[aria-label="checkbox-on"]').should('have.length', 0); + cy.getBySel('bulk-select-copy').contains('0 Selected'); + cy.getBySel('bulk-select-action').should('not.exist'); + }); + }); + + describe('card mode', () => { + before(() => { + cy.visit(CHART_LIST); + setGridMode('card'); + }); + + it('should load rows in card mode', () => { + cy.getBySel('listview-table').should('not.exist'); + cy.getBySel('styled-card').should('have.length', 25); + }); + + it('should bulk select in card mode', () => { + toggleBulkSelect(); + cy.getBySel('styled-card').click({ multiple: true }); + cy.getBySel('bulk-select-copy').contains('25 Selected'); + cy.getBySel('bulk-select-action') + .should('have.length', 2) + .then($btns => { + expect($btns).to.contain('Delete'); + expect($btns).to.contain('Export'); + }); + cy.getBySel('bulk-select-deselect-all').click(); + cy.getBySel('bulk-select-copy').contains('0 Selected'); + cy.getBySel('bulk-select-action').should('not.exist'); + }); + + it('should sort in card mode', () => { + orderAlphabetical(); + cy.getBySel('styled-card').first().contains('% Rural'); + }); + }); + + describe('common actions', () => { + beforeEach(() => { + cy.createSampleCharts(); + cy.visit(CHART_LIST); + }); + + it('should allow to favorite/unfavorite', () => { + cy.intercept(`/superset/favstar/slice/*/select/`).as('select'); + cy.intercept(`/superset/favstar/slice/*/unselect/`).as('unselect'); + + setGridMode('card'); + orderAlphabetical(); + + cy.getBySel('styled-card').first().contains('% Rural'); + cy.getBySel('styled-card') + .first() + .find("[aria-label='favorite-unselected']") + .click(); + cy.wait('@select'); + cy.getBySel('styled-card') + .first() + .find("[aria-label='favorite-selected']") + .click(); + cy.wait('@unselect'); + cy.getBySel('styled-card') + .first() + .find("[aria-label='favorite-selected']") + .should('not.exist'); + }); + + it('should bulk delete correctly', () => { + interceptBulkDelete(); + toggleBulkSelect(); + + // bulk deletes in card-view + setGridMode('card'); + orderAlphabetical(); + + cy.getBySel('styled-card').eq(1).contains('1 - Sample chart').click(); + cy.getBySel('styled-card').eq(2).contains('2 - Sample chart').click(); + cy.getBySel('bulk-select-action').eq(0).contains('Delete').click(); + confirmDelete(); + cy.wait('@bulkDelete'); + cy.getBySel('styled-card') + .eq(1) + .should('not.contain', '1 - Sample chart'); + cy.getBySel('styled-card') + .eq(2) + .should('not.contain', '2 - Sample chart'); + + // bulk deletes in list-view + setGridMode('list'); + cy.getBySel('table-row').eq(1).contains('3 - Sample chart'); + cy.getBySel('table-row').eq(2).contains('4 - Sample chart'); + cy.get('[data-test="table-row"] input[type="checkbox"]').eq(1).click(); + cy.get('[data-test="table-row"] input[type="checkbox"]').eq(2).click(); + cy.getBySel('bulk-select-action').eq(0).contains('Delete').click(); + confirmDelete(); + cy.wait('@bulkDelete'); + cy.getBySel('table-row').eq(1).should('not.contain', '3 - Sample chart'); + cy.getBySel('table-row').eq(2).should('not.contain', '4 - Sample chart'); + }); + + it('should delete correctly', () => { + interceptDelete(); + + // deletes in card-view + setGridMode('card'); + orderAlphabetical(); + + cy.getBySel('styled-card').eq(1).contains('1 - Sample chart'); + openMenu(); + cy.getBySel('chart-list-delete-option').click(); + confirmDelete(); + cy.wait('@delete'); + cy.getBySel('styled-card') + .eq(1) + .should('not.contain', '1 - Sample chart'); + + // deletes in list-view + setGridMode('list'); + cy.getBySel('table-row').eq(1).contains('2 - Sample chart'); + cy.getBySel('trash').eq(1).click(); + confirmDelete(); + cy.wait('@delete'); + cy.getBySel('table-row').eq(1).should('not.contain', '2 - Sample chart'); + }); + + it('should edit correctly', () => { + interceptUpdate(); + + // edits in card-view + setGridMode('card'); + orderAlphabetical(); + cy.getBySel('styled-card').eq(1).contains('1 - Sample chart'); + + // change title + openProperties(); + cy.getBySel('properties-modal-name-input').type(' | EDITED'); + cy.get('button:contains("Save")').click(); + cy.wait('@update'); + cy.getBySel('styled-card').eq(1).contains('1 - Sample chart | EDITED'); + + // edits in list-view + setGridMode('list'); + cy.getBySel('edit-alt').eq(1).click(); + cy.getBySel('properties-modal-name-input') + .clear() + .type('1 - Sample chart'); + cy.get('button:contains("Save")').click(); + cy.wait('@update'); + cy.getBySel('table-row').eq(1).contains('1 - Sample chart'); + }); + }); +}); diff --git a/superset-frontend/cypress-base/cypress/integration/chart_list/list_view.test.ts b/superset-frontend/cypress-base/cypress/integration/chart_list/list_view.test.ts deleted file mode 100644 index 42313d78495f4..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/chart_list/list_view.test.ts +++ /dev/null @@ -1,73 +0,0 @@ -/** - * 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 { CHART_LIST } from './chart_list.helper'; - -describe('chart list view', () => { - beforeEach(() => { - cy.login(); - }); - - it('should load rows', () => { - cy.visit(CHART_LIST); - cy.get('[aria-label="list-view"]').click(); - - cy.get('[data-test="listview-table"]').should('be.visible'); - // check chart list view header - cy.get('[data-test="sort-header"]').eq(1).contains('Chart'); - cy.get('[data-test="sort-header"]').eq(2).contains('Visualization type'); - cy.get('[data-test="sort-header"]').eq(3).contains('Dataset'); - cy.get('[data-test="sort-header"]').eq(4).contains('Modified by'); - cy.get('[data-test="sort-header"]').eq(5).contains('Last modified'); - cy.get('[data-test="sort-header"]').eq(6).contains('Created by'); - cy.get('[data-test="sort-header"]').eq(7).contains('Actions'); - cy.get('[data-test="table-row"]').should('have.length', 25); - }); - - xit('should sort correctly', () => { - cy.get('[data-test="sort-header"]').eq(2).click(); - cy.get('[data-test="sort-header"]').eq(2).click(); - cy.get('[data-test="table-row"]') - .first() - .find('[data-test="table-row-cell"]') - .find('[data-test="cell-text"]') - .contains('Location of Current Developers'); - }); - - it('should bulk delete correctly', () => { - // Load the chart list order by name asc. - // This will ensure the tests stay consistent, and the - // same charts get deleted every time - cy.visit(CHART_LIST, { - qs: { - sortColumn: 'slice_name', - sortOrder: 'asc', - }, - }); - cy.get('[aria-label="list-view"]').click(); - - cy.get('[data-test="listview-table"]').should('be.visible'); - cy.get('[data-test="bulk-select"]').eq(0).click(); - cy.get('[aria-label="checkbox-off"]').eq(1).siblings('input').click(); - cy.get('[aria-label="checkbox-off"]').eq(2).siblings('input').click(); - cy.get('[data-test="bulk-select-action"]').eq(0).click(); - cy.get('[data-test="delete-modal-input"]').eq(0).type('DELETE'); - cy.get('[data-test="modal-confirm-button"]').eq(0).click(); - cy.get('[aria-label="checkbox-on"]').should('not.exist'); - }); -}); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts index b409aa06d0a2e..b97694ca09b26 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts @@ -56,7 +56,7 @@ import { valueNativeFilterOptions, validateFilterNameOnDashboard, } from './nativeFilter.helper'; -import { DASHBOARD_LIST } from '../dashboard_list/dashboard_list.helper'; +import { DASHBOARD_LIST } from 'cypress/utils/urls'; import { CHART_LIST } from '../chart_list/chart_list.helper'; // TODO: fix flaky init logic and re-enable diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts index 1d295202364e2..645c24dff1b78 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts @@ -17,31 +17,31 @@ * under the License. */ -export function setGridMode(type: 'card' | 'list') { - cy.get(`[aria-label="${type}-view"]`).click(); -} - export function interceptFiltering() { - cy.intercept('GET', `/api/v1/dashboard/?q=*`).as('filtering'); + cy.intercept('GET', `/api/v1/dashboard/?q=*`).as('filtering'); } export function interceptBulkDelete() { - cy.intercept('DELETE', `/api/v1/dashboard/?q=*`).as('bulkDelete'); + cy.intercept('DELETE', `/api/v1/dashboard/?q=*`).as('bulkDelete'); } export function interceptDelete() { - cy.intercept('DELETE', `/api/v1/dashboard/*`).as('delete'); + cy.intercept('DELETE', `/api/v1/dashboard/*`).as('delete'); } export function interceptUpdate() { - cy.intercept('PUT', `/api/v1/dashboard/*`).as('update'); + cy.intercept('PUT', `/api/v1/dashboard/*`).as('update'); +} + +export function interceptPost() { + cy.intercept('POST', `/api/v1/dashboard/`).as('post'); } export function setFilter(filter: string, option: string) { - interceptFiltering(); + interceptFiltering(); - cy.get(`[aria-label="${filter}"]`).first().click(); - cy.get(`[aria-label="${filter}"] [title="${option}"]`).click(); + cy.get(`[aria-label="${filter}"]`).first().click(); + cy.get(`[aria-label="${filter}"] [title="${option}"]`).click(); - cy.wait('@filtering'); -} \ No newline at end of file + cy.wait('@filtering'); +} diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboardlist.applitools.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboardlist.applitools.test.ts index c4c62e6c6c290..5f457ff49ae42 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboardlist.applitools.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard_list/dashboardlist.applitools.test.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - import { DASHBOARD_LIST } from 'cypress/utils/urls'; +import { DASHBOARD_LIST } from 'cypress/utils/urls'; describe('dashboard list view', () => { beforeEach(() => { diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts index dffeddbe0ae17..b2d7cf6e87f03 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts @@ -16,8 +16,9 @@ * specific language governing permissions and limitations * under the License. */ - import { DASHBOARD_LIST } from 'cypress/utils/urls'; - import { setGridMode, setFilter } from '../dashboard/utils'; +import { DASHBOARD_LIST } from 'cypress/utils/urls'; +import { setGridMode } from 'cypress/utils'; +import { setFilter } from '../dashboard/utils'; function resetFilters() { cy.get('[aria-label="close-circle"]').click({ multiple: true, force: true }); @@ -49,7 +50,7 @@ describe('Dashboards filters', () => { it('should filter by created by correctly', () => { setFilter('Created by', 'alpha user'); cy.getBySel('styled-card').should('not.exist'); - setFilter('Created by', 'admin user') + setFilter('Created by', 'admin user'); cy.getBySel('styled-card').should('have.length', 1); }); @@ -76,7 +77,7 @@ describe('Dashboards filters', () => { it('should filter by created by correctly', () => { setFilter('Created by', 'alpha user'); cy.getBySel('table-row').should('not.exist'); - setFilter('Created by', 'admin user') + setFilter('Created by', 'admin user'); cy.getBySel('table-row').should('have.length', 1); }); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts index b1baefd17062e..adfb0ea13db9e 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard_list/list.test.ts @@ -17,11 +17,13 @@ * under the License. */ import { DASHBOARD_LIST } from 'cypress/utils/urls'; -import { setGridMode, setFilter, interceptBulkDelete, interceptUpdate, interceptDelete } from '../dashboard/utils'; - -function toggleBulkSelect() { - cy.getBySel("bulk-select").click(); -} +import { setGridMode, toggleBulkSelect } from 'cypress/utils'; +import { + setFilter, + interceptBulkDelete, + interceptUpdate, + interceptDelete, +} from '../dashboard/utils'; function orderAlphabetical() { setFilter('Sort', 'Alphabetical'); @@ -57,39 +59,39 @@ describe('Dashboards list', () => { }); it('should load rows in list mode', () => { - cy.getBySel("listview-table").should('be.visible'); - cy.getBySel("sort-header").eq(1).contains('Title'); - cy.getBySel("sort-header").eq(2).contains('Modified by'); - cy.getBySel("sort-header").eq(3).contains('Status'); - cy.getBySel("sort-header").eq(4).contains('Modified'); - cy.getBySel("sort-header").eq(5).contains('Created by'); - cy.getBySel("sort-header").eq(6).contains('Owners'); - cy.getBySel("sort-header").eq(7).contains('Actions'); + cy.getBySel('listview-table').should('be.visible'); + cy.getBySel('sort-header').eq(1).contains('Title'); + cy.getBySel('sort-header').eq(2).contains('Modified by'); + cy.getBySel('sort-header').eq(3).contains('Status'); + cy.getBySel('sort-header').eq(4).contains('Modified'); + cy.getBySel('sort-header').eq(5).contains('Created by'); + cy.getBySel('sort-header').eq(6).contains('Owners'); + cy.getBySel('sort-header').eq(7).contains('Actions'); }); it('should sort correctly in list mode', () => { - cy.getBySel("sort-header").eq(1).click(); - cy.getBySel("table-row").first() - .contains("ECharts Dashboard"); - cy.getBySel("sort-header").eq(1).click(); - cy.getBySel("table-row").first() - .contains("World Bank's Data"); - cy.getBySel("sort-header").eq(1).click(); + cy.getBySel('sort-header').eq(1).click(); + cy.getBySel('table-row').first().contains('ECharts Dashboard'); + cy.getBySel('sort-header').eq(1).click(); + cy.getBySel('table-row').first().contains("World Bank's Data"); + cy.getBySel('sort-header').eq(1).click(); }); it('should bulk select in list mode', () => { toggleBulkSelect(); cy.get('#header-toggle-all').click(); cy.get('[aria-label="checkbox-on"]').should('have.length', 6); - cy.getBySel("bulk-select-copy").contains('5 Selected'); - cy.getBySel("bulk-select-action").should('have.length', 2).then($btns => { - expect($btns).to.contain('Delete'); - expect($btns).to.contain('Export'); - }); - cy.getBySel("bulk-select-deselect-all").click(); + cy.getBySel('bulk-select-copy').contains('5 Selected'); + cy.getBySel('bulk-select-action') + .should('have.length', 2) + .then($btns => { + expect($btns).to.contain('Delete'); + expect($btns).to.contain('Export'); + }); + cy.getBySel('bulk-select-deselect-all').click(); cy.get('[aria-label="checkbox-on"]').should('have.length', 0); - cy.getBySel("bulk-select-copy").contains('0 Selected'); - cy.getBySel("bulk-select-action").should('not.exist'); + cy.getBySel('bulk-select-copy').contains('0 Selected'); + cy.getBySel('bulk-select-action').should('not.exist'); }); }); @@ -100,26 +102,28 @@ describe('Dashboards list', () => { }); it('should load rows in card mode', () => { - cy.getBySel("listview-table").should('not.exist'); - cy.getBySel("styled-card").should('have.length', 5); + cy.getBySel('listview-table').should('not.exist'); + cy.getBySel('styled-card').should('have.length', 5); }); it('should bulk select in card mode', () => { toggleBulkSelect(); - cy.getBySel("styled-card").click({multiple: true}); - cy.getBySel("bulk-select-copy").contains('5 Selected'); - cy.getBySel("bulk-select-action").should('have.length', 2).then($btns => { - expect($btns).to.contain('Delete'); - expect($btns).to.contain('Export'); - }); - cy.getBySel("bulk-select-deselect-all").click(); - cy.getBySel("bulk-select-copy").contains('0 Selected'); - cy.getBySel("bulk-select-action").should('not.exist'); + cy.getBySel('styled-card').click({ multiple: true }); + cy.getBySel('bulk-select-copy').contains('5 Selected'); + cy.getBySel('bulk-select-action') + .should('have.length', 2) + .then($btns => { + expect($btns).to.contain('Delete'); + expect($btns).to.contain('Export'); + }); + cy.getBySel('bulk-select-deselect-all').click(); + cy.getBySel('bulk-select-copy').contains('0 Selected'); + cy.getBySel('bulk-select-action').should('not.exist'); }); it('should sort in card mode', () => { orderAlphabetical(); - cy.getBySel("styled-card").first().contains('ECharts Dashboard'); + cy.getBySel('styled-card').first().contains('ECharts Dashboard'); }); }); @@ -136,11 +140,15 @@ describe('Dashboards list', () => { setGridMode('card'); orderAlphabetical(); - cy.getBySel('styled-card').first().contains('1 - Sample dashboard') - cy.getBySel('styled-card').first().find("[aria-label='favorite-unselected']") + cy.getBySel('styled-card').first().contains('1 - Sample dashboard'); + cy.getBySel('styled-card') + .first() + .find("[aria-label='favorite-unselected']") .click(); cy.wait('@select'); - cy.getBySel('styled-card').first().find("[aria-label='favorite-selected']") + cy.getBySel('styled-card') + .first() + .find("[aria-label='favorite-selected']") .click(); cy.wait('@unselect'); cy.getBySel('styled-card') @@ -157,49 +165,60 @@ describe('Dashboards list', () => { setGridMode('card'); orderAlphabetical(); - cy.getBySel("styled-card").eq(0).contains('1 - Sample dashboard').click(); - cy.getBySel("styled-card").eq(1).contains('2 - Sample dashboard').click(); - cy.getBySel("bulk-select-action").eq(0).contains('Delete').click(); + cy.getBySel('styled-card').eq(0).contains('1 - Sample dashboard').click(); + cy.getBySel('styled-card').eq(1).contains('2 - Sample dashboard').click(); + cy.getBySel('bulk-select-action').eq(0).contains('Delete').click(); confirmDelete(); cy.wait('@bulkDelete'); - cy.getBySel("styled-card").eq(0).should('not.contain', '1 - Sample dashboard'); - cy.getBySel("styled-card").eq(1).should('not.contain', '2 - Sample dashboard'); + cy.getBySel('styled-card') + .eq(0) + .should('not.contain', '1 - Sample dashboard'); + cy.getBySel('styled-card') + .eq(1) + .should('not.contain', '2 - Sample dashboard'); // bulk deletes in list-view setGridMode('list'); - cy.getBySel("table-row").eq(0).contains('3 - Sample dashboard'); - cy.getBySel("table-row").eq(1).contains('4 - Sample dashboard'); + cy.getBySel('table-row').eq(0).contains('3 - Sample dashboard'); + cy.getBySel('table-row').eq(1).contains('4 - Sample dashboard'); cy.get('[data-test="table-row"] input[type="checkbox"]').eq(0).click(); cy.get('[data-test="table-row"] input[type="checkbox"]').eq(1).click(); - cy.getBySel("bulk-select-action").eq(0).contains('Delete').click(); + cy.getBySel('bulk-select-action').eq(0).contains('Delete').click(); confirmDelete(); cy.wait('@bulkDelete'); - cy.getBySel("table-row").eq(0).should('not.contain', '3 - Sample dashboard'); - cy.getBySel("table-row").eq(1).should('not.contain', '4 - Sample dashboard'); + cy.getBySel('table-row') + .eq(0) + .should('not.contain', '3 - Sample dashboard'); + cy.getBySel('table-row') + .eq(1) + .should('not.contain', '4 - Sample dashboard'); }); - it('should delete correctly', () => { + it('should delete correctly', () => { interceptDelete(); // deletes in card-view setGridMode('card'); orderAlphabetical(); - cy.getBySel("styled-card").eq(0).contains('1 - Sample dashboard'); + cy.getBySel('styled-card').eq(0).contains('1 - Sample dashboard'); openMenu(); cy.getBySel('dashboard-card-option-delete-button').click(); confirmDelete(); cy.wait('@delete'); - cy.getBySel("styled-card").eq(0).should('not.contain', '1 - Sample dashboard'); + cy.getBySel('styled-card') + .eq(0) + .should('not.contain', '1 - Sample dashboard'); // deletes in list-view setGridMode('list'); - cy.getBySel("table-row").eq(0).contains('2 - Sample dashboard'); - cy.getBySel("dashboard-list-trash-icon").eq(0).click(); + cy.getBySel('table-row').eq(0).contains('2 - Sample dashboard'); + cy.getBySel('dashboard-list-trash-icon').eq(0).click(); confirmDelete(); cy.wait('@delete'); - cy.getBySel("table-row").eq(0).should('not.contain', '2 - Sample dashboard'); - + cy.getBySel('table-row') + .eq(0) + .should('not.contain', '2 - Sample dashboard'); }); it('should edit correctly', () => { @@ -208,22 +227,24 @@ describe('Dashboards list', () => { // edits in card-view setGridMode('card'); orderAlphabetical(); - cy.getBySel("styled-card").eq(0).contains('1 - Sample dashboard'); + cy.getBySel('styled-card').eq(0).contains('1 - Sample dashboard'); // change title openProperties(); cy.getBySel('dashboard-title-input').type(' | EDITED'); cy.get('button:contains("Save")').click(); cy.wait('@update'); - cy.getBySel("styled-card").eq(0).contains('1 - Sample dashboard | EDITED'); + cy.getBySel('styled-card') + .eq(0) + .contains('1 - Sample dashboard | EDITED'); // edits in list-view setGridMode('list'); - cy.getBySel("edit-alt").eq(0).click(); + cy.getBySel('edit-alt').eq(0).click(); cy.getBySel('dashboard-title-input').clear().type('1 - Sample dashboard'); cy.get('button:contains("Save")').click(); cy.wait('@update'); - cy.getBySel("table-row").eq(0).contains('1 - Sample dashboard'); + cy.getBySel('table-row').eq(0).contains('1 - Sample dashboard'); }); }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/utils.ts b/superset-frontend/cypress-base/cypress/integration/explore/utils.ts new file mode 100644 index 0000000000000..0972bac552749 --- /dev/null +++ b/superset-frontend/cypress-base/cypress/integration/explore/utils.ts @@ -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. + */ + +export function interceptFiltering() { + cy.intercept('GET', `/api/v1/chart/?q=*`).as('filtering'); +} + +export function interceptBulkDelete() { + cy.intercept('DELETE', `/api/v1/chart/?q=*`).as('bulkDelete'); +} + +export function interceptDelete() { + cy.intercept('DELETE', `/api/v1/chart/*`).as('delete'); +} + +export function interceptUpdate() { + cy.intercept('PUT', `/api/v1/chart/*`).as('update'); +} + +export function interceptPost() { + cy.intercept('POST', `/api/v1/chart/`).as('post'); +} + +export function setFilter(filter: string, option: string) { + interceptFiltering(); + + cy.get(`[aria-label="${filter}"]`).first().click(); + cy.get(`[aria-label="${filter}"] [title="${option}"]`).click(); + + cy.wait('@filtering'); +} diff --git a/superset-frontend/cypress-base/cypress/support/index.d.ts b/superset-frontend/cypress-base/cypress/support/index.d.ts index edb9a9c18b0de..fc065563d366d 100644 --- a/superset-frontend/cypress-base/cypress/support/index.d.ts +++ b/superset-frontend/cypress-base/cypress/support/index.d.ts @@ -67,14 +67,15 @@ declare namespace Cypress { * Create */ createSampleDashboards(): void; + createSampleCharts(): void; /** * Delete */ - deleteDashboard(id: number): cy; - deleteDashboardByName(dashboardName: string): cy; - deleteChartByName(name: string): cy; - deleteChart(id: number): cy; + deleteDashboard(id: number, failOnStatusCode: boolean): cy; + deleteDashboardByName(dashboardName: string, failOnStatusCode: boolean): cy; + deleteChartByName(name: string, failOnStatusCode: boolean): cy; + deleteChart(id: number, failOnStatusCode: boolean): cy; } } diff --git a/superset-frontend/cypress-base/cypress/support/index.ts b/superset-frontend/cypress-base/cypress/support/index.ts index 90442649a2aa4..5f201200b56fe 100644 --- a/superset-frontend/cypress-base/cypress/support/index.ts +++ b/superset-frontend/cypress-base/cypress/support/index.ts @@ -23,26 +23,48 @@ require('cy-verify-downloads').addCustomCommand(); const BASE_EXPLORE_URL = '/explore/?form_data='; const TokenName = Cypress.env('TOKEN_NAME'); +let SAMPLE_DASHBOARDS: Record[] = []; +let SAMPLE_CHARTS: Record[] = []; function resetSamples() { - cy.fixture('dashboards.json').then((dashboards) => { + cy.login(); + cy.fixture('dashboards.json').then(dashboards => { dashboards.forEach((d: { dashboard_title: string }) => { - cy.deleteDashboardByName(d.dashboard_title); + cy.deleteDashboardByName(d.dashboard_title, false); + }); + }); + cy.fixture('charts.json').then(charts => { + charts.forEach((c: { slice_name: string }) => { + cy.deleteChartByName(c.slice_name, false); }); }); } +function loadSampleData() { + cy.login(); + cy.getCharts().then((slices: any) => { + SAMPLE_CHARTS = slices; + }); + cy.getDashboards().then((dashboards: any) => { + SAMPLE_DASHBOARDS = dashboards; + }); +} + +before(() => { + loadSampleData(); +}); + beforeEach(() => { resetSamples(); }); -Cypress.Commands.add('getBySel', (selector, ...args) => { - return cy.get(`[data-test=${selector}]`, ...args) -}); +Cypress.Commands.add('getBySel', (selector, ...args) => + cy.get(`[data-test=${selector}]`, ...args), +); -Cypress.Commands.add('getBySelLike', (selector, ...args) => { - return cy.get(`[data-test*=${selector}]`, ...args) -}); +Cypress.Commands.add('getBySelLike', (selector, ...args) => + cy.get(`[data-test*=${selector}]`, ...args), +); /* eslint-disable consistent-return */ Cypress.on('uncaught:exception', err => { @@ -165,43 +187,72 @@ Cypress.Commands.add( }, ); -Cypress.Commands.add('createSampleDashboards', () => - cy.fixture('dashboards.json').then((dashboards) => { - dashboards.forEach((d: { dashboard_title: string }) => { - cy - .request({ - method: 'POST', - url: `/api/v1/dashboard/`, - body: { - dashboard_title: d.dashboard_title, - }, - headers: { - Cookie: `csrf_access_token=${window.localStorage.getItem( - 'access_token', - )}`, - 'Content-Type': 'application/json', - Authorization: `Bearer ${TokenName}`, - 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, - Referer: `${Cypress.config().baseUrl}/`, - }, - }) - .then(resp => resp); - }); - }) -); +Cypress.Commands.add('createSampleDashboards', () => { + const requests: any = []; + cy.fixture('dashboards.json').then(dashboards => { + for (let i = 0; i < dashboards.length; i += 1) { + requests.push( + cy.request({ + method: 'POST', + url: `/api/v1/dashboard/`, + body: dashboards[i], + headers: { + Cookie: `csrf_access_token=${window.localStorage.getItem( + 'access_token', + )}`, + 'Content-Type': 'application/json', + Authorization: `Bearer ${TokenName}`, + 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, + Referer: `${Cypress.config().baseUrl}/`, + }, + }), + ); + } + return Promise.all(requests).then(() => loadSampleData()); + }); +}); -Cypress.Commands.add('deleteDashboardByName', (dashboardName: string) => - cy.getDashboards().then((dashboards: any) => { - const dashboard = dashboards.find(d => d.dashboard_title === dashboardName); +Cypress.Commands.add('createSampleCharts', () => { + const requests: any = []; + return cy.fixture('charts.json').then(charts => { + for (let i = 0; i < charts.length; i += 1) { + requests.push( + cy.request({ + method: 'POST', + url: `/api/v1/chart/`, + body: charts[i], + headers: { + Cookie: `csrf_access_token=${window.localStorage.getItem( + 'access_token', + )}`, + 'Content-Type': 'application/json', + Authorization: `Bearer ${TokenName}`, + 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, + Referer: `${Cypress.config().baseUrl}/`, + }, + }), + ); + } + return Promise.all(requests).then(() => loadSampleData()); + }); +}); + +Cypress.Commands.add( + 'deleteDashboardByName', + (dashboardName: string, failOnStatusCode: boolean) => { + const dashboard = SAMPLE_DASHBOARDS.find( + d => d.dashboard_title === dashboardName, + ); if (dashboard) { - cy.deleteDashboard(dashboard.id); + cy.deleteDashboard(dashboard.id, failOnStatusCode); } - }), + }, ); -Cypress.Commands.add('deleteDashboard', (id: number) => +Cypress.Commands.add('deleteDashboard', (id: number, failOnStatusCode = true) => cy .request({ + failOnStatusCode, method: 'DELETE', url: `api/v1/dashboard/${id}`, headers: { @@ -230,9 +281,10 @@ Cypress.Commands.add('getDashboards', () => .then(resp => resp.body.result), ); -Cypress.Commands.add('deleteChart', (id: number) => +Cypress.Commands.add('deleteChart', (id: number, failOnStatusCode = true) => cy .request({ + failOnStatusCode, method: 'DELETE', url: `api/v1/chart/${id}`, headers: { @@ -244,7 +296,6 @@ Cypress.Commands.add('deleteChart', (id: number) => 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, Referer: `${Cypress.config().baseUrl}/`, }, - failOnStatusCode: false, }) .then(resp => resp), ); @@ -262,13 +313,12 @@ Cypress.Commands.add('getCharts', () => .then(resp => resp.body.result), ); -Cypress.Commands.add('deleteChartByName', (name: string) => - cy.getCharts().then((slices: any) => { - slices?.forEach((element: any) => { - if (element.slice_name === name) { - const elementId = element.id; - cy.deleteChart(elementId); - } - }); - }), +Cypress.Commands.add( + 'deleteChartByName', + (sliceName: string, failOnStatusCode: boolean) => { + const chart = SAMPLE_CHARTS.find(c => c.slice_name === sliceName); + if (chart) { + cy.deleteChart(chart.id, failOnStatusCode); + } + }, ); diff --git a/superset-frontend/cypress-base/cypress/utils/index.ts b/superset-frontend/cypress-base/cypress/utils/index.ts index ea0bbdcf437b3..6c22829345f25 100644 --- a/superset-frontend/cypress-base/cypress/utils/index.ts +++ b/superset-frontend/cypress-base/cypress/utils/index.ts @@ -18,3 +18,11 @@ */ export * from './vizPlugins'; export { default as parsePostForm } from './parsePostForm'; + +export function setGridMode(type: 'card' | 'list') { + cy.get(`[aria-label="${type}-view"]`).click(); +} + +export function toggleBulkSelect() { + cy.getBySel('bulk-select').click(); +} diff --git a/superset-frontend/cypress-base/cypress/utils/urls.ts b/superset-frontend/cypress-base/cypress/utils/urls.ts index 227a627afb810..124046b8262b0 100644 --- a/superset-frontend/cypress-base/cypress/utils/urls.ts +++ b/superset-frontend/cypress-base/cypress/utils/urls.ts @@ -17,4 +17,5 @@ * under the License. */ - export const DASHBOARD_LIST = '/dashboard/list/'; \ No newline at end of file +export const DASHBOARD_LIST = '/dashboard/list/'; +export const CHART_LIST = '/chart/list/'; From b429773cb4b9e66a5c4699fe0161b29f41dd6436 Mon Sep 17 00:00:00 2001 From: geido Date: Thu, 1 Sep 2022 15:33:05 +0300 Subject: [PATCH 05/31] Enhance charts filter test --- .../integration/chart_list/card_view.test.ts | 129 -------------- .../chart_list/chart_list.helper.ts | 19 -- .../chart_list/chartlist.applitools.test.ts | 2 +- .../integration/chart_list/filter.test.ts | 167 +++++++----------- .../dashboard/nativeFilters.test.ts | 2 +- .../integration/dashboard_list/filter.test.ts | 10 +- .../cypress-base/cypress/utils/index.ts | 4 + 7 files changed, 76 insertions(+), 257 deletions(-) delete mode 100644 superset-frontend/cypress-base/cypress/integration/chart_list/card_view.test.ts delete mode 100644 superset-frontend/cypress-base/cypress/integration/chart_list/chart_list.helper.ts diff --git a/superset-frontend/cypress-base/cypress/integration/chart_list/card_view.test.ts b/superset-frontend/cypress-base/cypress/integration/chart_list/card_view.test.ts deleted file mode 100644 index 1335fcb422204..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/chart_list/card_view.test.ts +++ /dev/null @@ -1,129 +0,0 @@ -/** - * 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 { CHART_LIST } from './chart_list.helper'; - -describe('chart card view', () => { - beforeEach(() => { - cy.login(); - cy.visit(CHART_LIST); - cy.get('[aria-label="card-view"]').click(); - }); - - it('should load cards', () => { - cy.get('[data-test="chart-list-view"]'); - cy.get('[data-test="styled-card"]').should('be.visible'); - cy.get('[data-test="styled-card"]').should('have.length', 25); - }); - - it('should allow to favorite/unfavorite chart card', () => { - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-selected']") - .should('not.exist'); - cy.get("[data-test='card-actions']") - .find("[aria-label='favorite-unselected']") - .first() - .click(); - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-selected']") - .should('be.visible'); - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-unselected']") - .should('not.exist'); - - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-unselected']") - .should('not.exist'); - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-selected']") - .click(); - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-unselected']") - .should('be.visible'); - cy.get("[data-test='card-actions']") - .first() - .find("[aria-label='favorite-selected']") - .should('not.exist'); - }); - - xit('should sort correctly', () => { - // sort Alphabetical - cy.get('.Select__control').last().should('be.visible'); - cy.get('.Select__control').last().click(); - cy.get('.Select__menu').contains('Alphabetical').click(); - cy.get('[data-test="chart-list-view"]').should('be.visible'); - cy.get('[data-test="styled-card"]').first().contains('% Rural'); - - // sort Recently Modified - cy.get('.Select__control').last().should('be.visible'); - cy.get('.Select__control').last().click(); - cy.get('.Select__menu').contains('Recently Modified').click(); - cy.get('[data-test="chart-list-view"]').should('be.visible'); - // TODO - next line is/was flaky - cy.get('[data-test="styled-card"]').first().contains('Unicode Cloud'); - cy.get('[data-test="styled-card"]') - .last() - .contains('Life Expectancy VS Rural %'); - }); - - // flaky - xit('should delete correctly', () => { - // show delete modal - cy.get('[data-test="more-horiz"]').last().trigger('mouseover'); - cy.get('[data-test="chart-list-delete-option"]') - .last() - .should('be.visible'); - cy.get('[data-test="chart-list-delete-option"]') - .last() - .contains('Delete') - .click(); - cy.get('[data-test="Please Confirm-modal"]').should('be.visible'); - cy.get('[data-test="modal-confirm-button"]').should( - 'have.attr', - 'disabled', - ); - cy.get('[data-test="Please Confirm-modal"]').should('be.visible'); - cy.get("[data-test='delete-modal-input']").type('DELETE'); - cy.get('[data-test="modal-confirm-button"]').should( - 'not.have.attr', - 'disabled', - ); - cy.get('[data-test="modal-cancel-button"]').click(); - }); - - // flaky - xit('should edit correctly', () => { - // show edit modal - cy.get('[data-test="more-horiz"]').last().trigger('mouseover'); - cy.get('[data-test="chart-list-edit-option"]').last().should('be.visible'); - cy.get('[data-test="chart-list-edit-option"]').last().click(); - cy.get('[data-test="properties-edit-modal"]').should('be.visible'); - cy.get('[data-test="properties-modal-name-input"]').should( - 'not.have.value', - ); - cy.get('[data-test="properties-modal-cancel-button"]') - .contains('Cancel') - .click(); - }); -}); diff --git a/superset-frontend/cypress-base/cypress/integration/chart_list/chart_list.helper.ts b/superset-frontend/cypress-base/cypress/integration/chart_list/chart_list.helper.ts deleted file mode 100644 index 0d66010cf4eb7..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/chart_list/chart_list.helper.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * 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. - */ -export const CHART_LIST = '/chart/list/'; diff --git a/superset-frontend/cypress-base/cypress/integration/chart_list/chartlist.applitools.test.ts b/superset-frontend/cypress-base/cypress/integration/chart_list/chartlist.applitools.test.ts index ddbbead4a2d02..045a8b809a39d 100644 --- a/superset-frontend/cypress-base/cypress/integration/chart_list/chartlist.applitools.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/chart_list/chartlist.applitools.test.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { CHART_LIST } from './chart_list.helper'; + import { CHART_LIST } from 'cypress/utils/urls'; describe('charts list view', () => { beforeEach(() => { diff --git a/superset-frontend/cypress-base/cypress/integration/chart_list/filter.test.ts b/superset-frontend/cypress-base/cypress/integration/chart_list/filter.test.ts index 4466cc2ad5899..c5308a87f9f4d 100644 --- a/superset-frontend/cypress-base/cypress/integration/chart_list/filter.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/chart_list/filter.test.ts @@ -16,119 +16,86 @@ * specific language governing permissions and limitations * under the License. */ -import { CHART_LIST } from './chart_list.helper'; + import { CHART_LIST } from 'cypress/utils/urls'; + import { setGridMode, clearAllInputs } from 'cypress/utils'; + import { setFilter } from '../explore/utils'; -describe('chart card view filters', () => { - beforeEach(() => { + describe('Charts filters', () => { + before(() => { cy.login(); cy.visit(CHART_LIST); - cy.get('[aria-label="card-view"]').click(); }); - it('should filter by owners correctly', () => { - // filter by owners - cy.get('[data-test="filters-select"]').first().click(); - cy.get('.rc-virtual-list').contains('alpha user').click(); - cy.get('[data-test="styled-card"]').should('not.exist'); - cy.get('[data-test="filters-select"]').first().click(); - cy.get('.rc-virtual-list').contains('gamma user').click(); - cy.get('[data-test="styled-card"]').should('not.exist'); + beforeEach(() => { + cy.preserveLogin(); + clearAllInputs(); }); - it('should filter by created by correctly', () => { - // filter by created by - cy.get('[data-test="filters-select"]').eq(1).click(); - cy.get('.rc-virtual-list').contains('alpha user').click(); - cy.get('.ant-card').should('not.exist'); - cy.get('[data-test="filters-select"]').eq(1).click(); - cy.get('.rc-virtual-list').contains('gamma user').click(); - cy.get('[data-test="styled-card"]').should('not.exist'); - }); + describe('card-view', () => { + before(() => { + setGridMode('card'); + }); - xit('should filter by viz type correctly', () => { - // filter by viz type - cy.get('[data-test="filters-select"]').eq(2).click(); - cy.get('.rc-virtual-list').contains('area').click({ timeout: 5000 }); - cy.get('[data-test="styled-card"]').its('length').should('be.gt', 0); - cy.get('[data-test="styled-card"]') - .contains("World's Pop Growth") - .should('be.visible'); - cy.get('[data-test="filters-select"]').eq(2).click(); - cy.get('[data-test="filters-select"]').eq(2).type('world_map{enter}'); - cy.get('[data-test="styled-card"]').should('have.length', 1); - cy.get('[data-test="styled-card"]') - .contains('% Rural') - .should('be.visible'); - }); + it('should filter by owners correctly', () => { + setFilter('Owner', 'alpha user'); + cy.getBySel('styled-card').should('not.exist'); + setFilter('Owner', 'admin user'); + cy.getBySel('styled-card').should('have.length', 20); + }); - it('should filter by datasource correctly', () => { - // filter by datasource - cy.get('[data-test="filters-select"]').eq(3).click(); - cy.get('.rc-virtual-list').contains('unicode_test').click(); - cy.get('[data-test="styled-card"]').should('have.length', 1); - cy.get('[data-test="styled-card"]') - .contains('Unicode Cloud') - .should('be.visible'); - cy.get('[data-test="filters-select"]').eq(2).click(); - cy.get('[data-test="filters-select"]') - .eq(2) - .type('energy_usage{enter}{enter}'); - cy.get('[data-test="styled-card"]').its('length').should('be.gt', 0); - }); -}); + it('should filter by created by correctly', () => { + setFilter('Created by', 'alpha user'); + cy.getBySel('styled-card').should('not.exist'); + setFilter('Created by', 'admin user'); + cy.getBySel('styled-card').should('have.length', 20); + }); -describe('chart list view filters', () => { - beforeEach(() => { - cy.login(); - cy.visit(CHART_LIST); - cy.get('[aria-label="list-view"]').click(); - }); + it('should filter by viz type correctly', () => { + setFilter('Chart type', 'Area Chart'); + cy.getBySel('styled-card').should('have.length', 3); + setFilter('Chart type', 'Bubble Chart'); + cy.getBySel('styled-card').should('have.length', 1); + }); - it('should filter by owners correctly', () => { - // filter by owners - cy.get('[data-test="filters-select"]').first().click(); - cy.get('.rc-virtual-list').contains('alpha user').click(); - cy.get('[data-test="table-row"]').should('not.exist'); - cy.get('[data-test="filters-select"]').first().click(); - cy.get('.rc-virtual-list').contains('gamma user').click(); - cy.get('[data-test="table-row"]').should('not.exist'); + it('should filter by datasource correctly', () => { + setFilter('Dataset', 'energy_usage'); + cy.getBySel('styled-card').should('have.length', 3); + setFilter('Dataset', 'unicode_test'); + cy.getBySel('styled-card').should('have.length', 1); + }); }); - it('should filter by created by correctly', () => { - // filter by created by - cy.get('[data-test="filters-select"]').eq(1).click(); - cy.get('.rc-virtual-list').contains('alpha user').click(); - cy.get('[data-test="table-row"]').should('not.exist'); - cy.get('[data-test="filters-select"]').eq(1).click(); - cy.get('.rc-virtual-list').contains('gamma user').click(); - cy.get('[data-test="table-row"]').should('not.exist'); - }); + describe('list-view', () => { + before(() => { + setGridMode('list'); + }); - // this is flaky, but seems to fail along with the card view test of the same name - xit('should filter by viz type correctly', () => { - // filter by viz type - cy.get('[data-test="filters-select"]').eq(2).click(); - cy.get('.rc-virtual-list').contains('area').click({ timeout: 5000 }); - cy.get('[data-test="table-row"]').its('length').should('be.gt', 0); - cy.get('[data-test="table-row"]') - .contains("World's Pop Growth") - .should('exist'); - cy.get('[data-test="filters-select"]').eq(2).click(); - cy.get('[data-test="filters-select"]').eq(2).type('world_map{enter}'); - cy.get('[data-test="table-row"]').should('have.length', 1); - cy.get('[data-test="table-row"]').contains('% Rural').should('exist'); - }); + it('should filter by owners correctly', () => { + setFilter('Owner', 'alpha user'); + cy.getBySel('table-row').should('not.exist'); + setFilter('Owner', 'admin user'); + cy.getBySel('table-row').should('have.length', 20); + }); + + it('should filter by created by correctly', () => { + setFilter('Created by', 'alpha user'); + cy.getBySel('table-row').should('not.exist'); + setFilter('Created by', 'admin user'); + cy.getBySel('table-row').should('have.length', 20); + }); + + it('should filter by viz type correctly', () => { + setFilter('Chart type', 'Area Chart'); + cy.getBySel('table-row').should('have.length', 3); + setFilter('Chart type', 'Bubble Chart'); + cy.getBySel('table-row').should('have.length', 1); + }); - it('should filter by datasource correctly', () => { - // filter by datasource - cy.get('[data-test="filters-select"]').eq(3).click(); - cy.get('.rc-virtual-list').contains('unicode_test').click(); - cy.get('[data-test="table-row"]').should('have.length', 1); - cy.get('[data-test="table-row"]').contains('Unicode Cloud').should('exist'); - cy.get('[data-test="filters-select"]').eq(3).click(); - cy.get('[data-test="filters-select"]') - .eq(3) - .type('energy_usage{enter}{enter}'); - cy.get('[data-test="table-row"]').its('length').should('be.gt', 0); + it('should filter by datasource correctly', () => { + setFilter('Dataset', 'energy_usage'); + cy.getBySel('table-row').should('have.length', 3); + setFilter('Dataset', 'unicode_test'); + cy.getBySel('table-row').should('have.length', 1); + }); }); -}); +}); \ No newline at end of file diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts index b97694ca09b26..d63478ca6b9ed 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts @@ -57,7 +57,7 @@ import { validateFilterNameOnDashboard, } from './nativeFilter.helper'; import { DASHBOARD_LIST } from 'cypress/utils/urls'; -import { CHART_LIST } from '../chart_list/chart_list.helper'; +import { CHART_LIST } from 'cypress/utils/urls'; // TODO: fix flaky init logic and re-enable const milliseconds = new Date().getTime(); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts index b2d7cf6e87f03..c33a8fe9489e0 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts @@ -17,13 +17,9 @@ * under the License. */ import { DASHBOARD_LIST } from 'cypress/utils/urls'; -import { setGridMode } from 'cypress/utils'; +import { setGridMode, clearAllInputs } from 'cypress/utils'; import { setFilter } from '../dashboard/utils'; -function resetFilters() { - cy.get('[aria-label="close-circle"]').click({ multiple: true, force: true }); -} - describe('Dashboards filters', () => { before(() => { cy.login(); @@ -32,7 +28,7 @@ describe('Dashboards filters', () => { beforeEach(() => { cy.preserveLogin(); - resetFilters(); + clearAllInputs(); }); describe('card-view', () => { @@ -58,7 +54,7 @@ describe('Dashboards filters', () => { setFilter('Status', 'Published'); cy.getBySel('styled-card').should('have.length', 3); setFilter('Status', 'Draft'); - cy.get('[data-test="styled-card"]').should('have.length', 2); + cy.getBySel('styled-card').should('have.length', 2); }); }); diff --git a/superset-frontend/cypress-base/cypress/utils/index.ts b/superset-frontend/cypress-base/cypress/utils/index.ts index 6c22829345f25..796f32a76542b 100644 --- a/superset-frontend/cypress-base/cypress/utils/index.ts +++ b/superset-frontend/cypress-base/cypress/utils/index.ts @@ -26,3 +26,7 @@ export function setGridMode(type: 'card' | 'list') { export function toggleBulkSelect() { cy.getBySel('bulk-select').click(); } + +export function clearAllInputs() { + cy.get('[aria-label="close-circle"]').click({ multiple: true, force: true }); +} \ No newline at end of file From c95faa2ad2ab4783098e6fab864d0bee5b27821a Mon Sep 17 00:00:00 2001 From: geido Date: Thu, 1 Sep 2022 15:54:37 +0300 Subject: [PATCH 06/31] Enhance dashboard load tests --- .../integration/dashboard/controls.test.ts | 6 +- .../dashboard/dashboard.applitools.test.ts | 8 +-- .../integration/dashboard/dashboard.helper.ts | 70 ------------------- .../integration/dashboard/edit_mode.test.js | 3 +- .../integration/dashboard/fav_star.test.js | 3 +- .../integration/dashboard/filter.test.ts | 6 +- .../integration/dashboard/key_value.test.ts | 6 +- .../integration/dashboard/load.test.ts | 21 +++--- .../dashboard/nativeFilters.test.ts | 7 +- .../integration/dashboard/save.test.js | 6 +- .../integration/dashboard/url_params.test.ts | 7 +- .../cypress/integration/dashboard/utils.ts | 18 +++++ .../cypress-base/cypress/utils/index.ts | 58 ++++++++++++++- .../cypress-base/cypress/utils/urls.ts | 1 + 14 files changed, 115 insertions(+), 105 deletions(-) diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/controls.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/controls.test.ts index 961e71bfd6397..3c772fdca930b 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/controls.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/controls.test.ts @@ -17,12 +17,12 @@ * under the License. */ import { - WORLD_HEALTH_CHARTS, - WORLD_HEALTH_DASHBOARD, waitForChartLoad, ChartSpec, getChartAliasesBySpec, -} from './dashboard.helper'; +} from 'cypress/utils'; +import { WORLD_HEALTH_CHARTS } from './utils'; +import { WORLD_HEALTH_DASHBOARD } from 'cypress/utils/urls'; import { isLegacyResponse } from '../../utils/vizPlugins'; describe('Dashboard top-level controls', () => { diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.applitools.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.applitools.test.ts index d492175a5e3a6..a604ada58afa3 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.applitools.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.applitools.test.ts @@ -16,11 +16,9 @@ * specific language governing permissions and limitations * under the License. */ -import { - waitForChartLoad, - WORLD_HEALTH_CHARTS, - WORLD_HEALTH_DASHBOARD, -} from './dashboard.helper'; +import { WORLD_HEALTH_CHARTS } from './utils'; +import { WORLD_HEALTH_DASHBOARD } from 'cypress/utils/urls'; +import { waitForChartLoad } from 'cypress/utils'; describe('Dashboard load', () => { beforeEach(() => { diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts index 486833c72be65..39b7fc40c21a9 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts @@ -1,4 +1,3 @@ -import { getChartAlias, Slice } from 'cypress/utils/vizPlugins'; import { dashboardView } from 'cypress/support/directories'; /** @@ -19,7 +18,6 @@ import { dashboardView } from 'cypress/support/directories'; * specific language governing permissions and limitations * under the License. */ -export const WORLD_HEALTH_DASHBOARD = '/superset/dashboard/world_health/'; export const USA_BIRTH_NAMES_DASHBOARD = '/superset/dashboard/births/'; export const testDashboard = '/superset/dashboard/538/'; export const TABBED_DASHBOARD = '/superset/dashboard/tabbed_dash/'; @@ -61,19 +59,6 @@ export const testItems = { export const CHECK_DASHBOARD_FAVORITE_ENDPOINT = '/superset/favstar/Dashboard/*/count'; -export const WORLD_HEALTH_CHARTS = [ - { name: '% Rural', viz: 'world_map' }, - { name: 'Most Populated Countries', viz: 'table' }, - { name: 'Region Filter', viz: 'filter_box' }, - { name: "World's Population", viz: 'big_number' }, - { name: 'Growth Rate', viz: 'line' }, - { name: 'Rural Breakdown', viz: 'sunburst' }, - { name: "World's Pop Growth", viz: 'area' }, - { name: 'Life Expectancy VS Rural %', viz: 'bubble' }, - { name: 'Treemap', viz: 'treemap' }, - { name: 'Box plot', viz: 'box_plot' }, -] as const; - export const ECHARTS_CHARTS = [ { name: 'Number of Girls', viz: 'big_number_total' }, { name: 'Participants', viz: 'big_number' }, @@ -82,61 +67,6 @@ export const ECHARTS_CHARTS = [ { name: 'Energy Force Layout', viz: 'graph_chart' }, ] as const; -/** Used to specify charts expected by the test suite */ -export interface ChartSpec { - name: string; - viz: string; -} - -export function getChartGridComponent({ name, viz }: ChartSpec) { - return cy - .get(`[data-test-chart-name="${name}"]`) - .should('have.attr', 'data-test-viz-type', viz); -} - -export function waitForChartLoad(chart: ChartSpec) { - return getChartGridComponent(chart).then(gridComponent => { - const chartId = gridComponent.attr('data-test-chart-id'); - // the chart should load in under half a minute - return ( - cy - // this id only becomes visible when the chart is loaded - .get(`#chart-id-${chartId}`, { - timeout: 30000, - }) - .should('be.visible') - // return the chart grid component - .then(() => gridComponent) - ); - }); -} - -const toSlicelike = ($chart: JQuery): Slice => ({ - slice_id: parseInt($chart.attr('data-test-chart-id')!, 10), - form_data: { - viz_type: $chart.attr('data-test-viz-type')!, - }, -}); - -export function getChartAliasBySpec(chart: ChartSpec) { - return getChartGridComponent(chart).then($chart => - cy.wrap(getChartAlias(toSlicelike($chart))), - ); -} - -export function getChartAliasesBySpec(charts: readonly ChartSpec[]) { - const aliases: string[] = []; - charts.forEach(chart => - getChartAliasBySpec(chart).then(alias => { - aliases.push(alias); - }), - ); - // Wrapping the aliases is key. - // That way callers can chain off this function - // and actually get the list of aliases. - return cy.wrap(aliases); -} - /** * Drag an element and drop it to another element. * Usage: diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/edit_mode.test.js b/superset-frontend/cypress-base/cypress/integration/dashboard/edit_mode.test.js index 10b8a4a40de1f..0f646cce3d212 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/edit_mode.test.js +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/edit_mode.test.js @@ -16,7 +16,8 @@ * specific language governing permissions and limitations * under the License. */ -import { WORLD_HEALTH_DASHBOARD, drag } from './dashboard.helper'; +import { drag } from './dashboard.helper'; +import { WORLD_HEALTH_DASHBOARD } from 'cypress/utils/urls'; describe('Dashboard edit mode', () => { beforeEach(() => { diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/fav_star.test.js b/superset-frontend/cypress-base/cypress/integration/dashboard/fav_star.test.js index a20b1eb3f5974..9b527a4c7a4fe 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/fav_star.test.js +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/fav_star.test.js @@ -17,10 +17,11 @@ * under the License. */ import { - WORLD_HEALTH_DASHBOARD, CHECK_DASHBOARD_FAVORITE_ENDPOINT, } from './dashboard.helper'; +import { WORLD_HEALTH_DASHBOARD } from 'cypress/utils/urls'; + describe('Dashboard add to favorite', () => { let isFavoriteDashboard = false; diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/filter.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/filter.test.ts index e1dd45cf3c30c..389c181cba730 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/filter.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/filter.test.ts @@ -18,11 +18,11 @@ */ import { isLegacyResponse, parsePostForm } from 'cypress/utils'; import { - WORLD_HEALTH_CHARTS, - WORLD_HEALTH_DASHBOARD, getChartAliasesBySpec, waitForChartLoad, -} from './dashboard.helper'; +} from 'cypress/utils'; +import {WORLD_HEALTH_CHARTS } from './utils'; +import { WORLD_HEALTH_DASHBOARD } from 'cypress/utils/urls'; describe('Dashboard filter', () => { before(() => { diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/key_value.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/key_value.test.ts index 1738ea5bd3d0d..42ac6cf7c7a8a 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/key_value.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/key_value.test.ts @@ -18,10 +18,10 @@ */ import qs from 'querystringify'; import { - WORLD_HEALTH_DASHBOARD, - WORLD_HEALTH_CHARTS, waitForChartLoad, -} from './dashboard.helper'; +} from 'cypress/utils'; +import {WORLD_HEALTH_CHARTS} from './utils'; +import { WORLD_HEALTH_DASHBOARD } from 'cypress/utils/urls'; interface QueryString { native_filters_key: string; diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/load.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/load.test.ts index 9fb84f70c93d8..f1c374b1586b4 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/load.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/load.test.ts @@ -16,17 +16,19 @@ * specific language governing permissions and limitations * under the License. */ -import { - waitForChartLoad, - WORLD_HEALTH_CHARTS, - WORLD_HEALTH_DASHBOARD, -} from './dashboard.helper'; +import { WORLD_HEALTH_CHARTS, interceptLog } from './utils'; +import { WORLD_HEALTH_DASHBOARD } from 'cypress/utils/urls'; +import { waitForChartLoad } from 'cypress/utils'; describe('Dashboard load', () => { - beforeEach(() => { + before(() => { cy.login(); }); + beforeEach(() => { + cy.preserveLogin(); + }); + it('should load dashboard', () => { cy.visit(WORLD_HEALTH_DASHBOARD); WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); @@ -34,7 +36,7 @@ describe('Dashboard load', () => { it('should load in edit mode', () => { cy.visit(`${WORLD_HEALTH_DASHBOARD}?edit=true&standalone=true`); - cy.get('[data-test="discard-changes-button"]').should('be.visible'); + cy.getBySel('discard-changes-button').should('be.visible'); }); it('should load in standalone mode', () => { @@ -44,12 +46,13 @@ describe('Dashboard load', () => { it('should load in edit/standalone mode', () => { cy.visit(`${WORLD_HEALTH_DASHBOARD}?edit=true&standalone=true`); - cy.get('[data-test="discard-changes-button"]').should('be.visible'); + cy.getBySel('discard-changes-button').should('be.visible'); cy.get('#app-menu').should('not.exist'); }); it('should send log data', () => { + interceptLog(); cy.visit(WORLD_HEALTH_DASHBOARD); - cy.intercept('/superset/log/?explode=events&dashboard_id=*'); + cy.wait('@logs'); }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts index d63478ca6b9ed..024f7b6fa3530 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts @@ -27,10 +27,11 @@ import { cleanUp, copyTestDashboard, testItems, - waitForChartLoad, - WORLD_HEALTH_DASHBOARD, - WORLD_HEALTH_CHARTS, } from './dashboard.helper'; +import { waitForChartLoad } from 'cypress/utils'; +import {WORLD_HEALTH_CHARTS} from './utils'; +import { WORLD_HEALTH_DASHBOARD } from 'cypress/utils/urls'; + import { addCountryCodeFilter, addCountryNameFilter, diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/save.test.js b/superset-frontend/cypress-base/cypress/integration/dashboard/save.test.js index 419346cf98ebb..07be4ef626d12 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/save.test.js +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/save.test.js @@ -20,9 +20,9 @@ import shortid from 'shortid'; import { waitForChartLoad, - WORLD_HEALTH_CHARTS, - WORLD_HEALTH_DASHBOARD, -} from './dashboard.helper'; +} from 'cypress/utils'; +import { WORLD_HEALTH_CHARTS } from './utils'; +import { WORLD_HEALTH_DASHBOARD } from 'cypress/utils/urls'; function openDashboardEditProperties() { // open dashboard properties edit modal diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/url_params.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/url_params.test.ts index 5f9ad7382e15c..c5b4c6655f599 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/url_params.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/url_params.test.ts @@ -18,10 +18,11 @@ */ import { parsePostForm, JsonObject } from 'cypress/utils'; import { - WORLD_HEALTH_DASHBOARD, - WORLD_HEALTH_CHARTS, waitForChartLoad, -} from './dashboard.helper'; +} from 'cypress/utils'; + +import { WORLD_HEALTH_CHARTS } from './utils'; +import { WORLD_HEALTH_DASHBOARD } from 'cypress/utils/urls'; describe('Dashboard form data', () => { const urlParams = { param1: '123', param2: 'abc' }; diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts index 645c24dff1b78..b4d2dd3100668 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts @@ -17,6 +17,19 @@ * under the License. */ + export const WORLD_HEALTH_CHARTS = [ + { name: '% Rural', viz: 'world_map' }, + { name: 'Most Populated Countries', viz: 'table' }, + { name: 'Region Filter', viz: 'filter_box' }, + { name: "World's Population", viz: 'big_number' }, + { name: 'Growth Rate', viz: 'line' }, + { name: 'Rural Breakdown', viz: 'sunburst' }, + { name: "World's Pop Growth", viz: 'area' }, + { name: 'Life Expectancy VS Rural %', viz: 'bubble' }, + { name: 'Treemap', viz: 'treemap' }, + { name: 'Box plot', viz: 'box_plot' }, + ] as const; + export function interceptFiltering() { cy.intercept('GET', `/api/v1/dashboard/?q=*`).as('filtering'); } @@ -37,6 +50,10 @@ export function interceptPost() { cy.intercept('POST', `/api/v1/dashboard/`).as('post'); } +export function interceptLog() { + cy.intercept('/superset/log/?explode=events&dashboard_id=*').as('logs'); +} + export function setFilter(filter: string, option: string) { interceptFiltering(); @@ -45,3 +62,4 @@ export function setFilter(filter: string, option: string) { cy.wait('@filtering'); } + diff --git a/superset-frontend/cypress-base/cypress/utils/index.ts b/superset-frontend/cypress-base/cypress/utils/index.ts index 796f32a76542b..3bdbb0f122acb 100644 --- a/superset-frontend/cypress-base/cypress/utils/index.ts +++ b/superset-frontend/cypress-base/cypress/utils/index.ts @@ -16,8 +16,14 @@ * specific language governing permissions and limitations * under the License. */ +import { getChartAlias, Slice } from 'cypress/utils/vizPlugins'; + export * from './vizPlugins'; export { default as parsePostForm } from './parsePostForm'; +export interface ChartSpec { + name: string; + viz: string; + } export function setGridMode(type: 'card' | 'list') { cy.get(`[aria-label="${type}-view"]`).click(); @@ -29,4 +35,54 @@ export function toggleBulkSelect() { export function clearAllInputs() { cy.get('[aria-label="close-circle"]').click({ multiple: true, force: true }); -} \ No newline at end of file +} + + const toSlicelike = ($chart: JQuery): Slice => ({ + slice_id: parseInt($chart.attr('data-test-chart-id')!, 10), + form_data: { + viz_type: $chart.attr('data-test-viz-type')!, + }, + }); + + export function getChartAliasBySpec(chart: ChartSpec) { + return getChartGridComponent(chart).then($chart => + cy.wrap(getChartAlias(toSlicelike($chart))), + ); + } + + export function getChartAliasesBySpec(charts: readonly ChartSpec[]) { + const aliases: string[] = []; + charts.forEach(chart => + getChartAliasBySpec(chart).then(alias => { + aliases.push(alias); + }), + ); + // Wrapping the aliases is key. + // That way callers can chain off this function + // and actually get the list of aliases. + return cy.wrap(aliases); + } + +export function getChartGridComponent({ name, viz }: ChartSpec) { + return cy + .get(`[data-test-chart-name="${name}"]`) + .should('have.attr', 'data-test-viz-type', viz); + } + +export function waitForChartLoad(chart: ChartSpec) { + return getChartGridComponent(chart).then(gridComponent => { + const chartId = gridComponent.attr('data-test-chart-id'); + // the chart should load in under half a minute + return ( + cy + // this id only becomes visible when the chart is loaded + .get(`#chart-id-${chartId}`, { + timeout: 30000, + }) + .should('be.visible') + // return the chart grid component + .then(() => gridComponent) + ); + }); + } + diff --git a/superset-frontend/cypress-base/cypress/utils/urls.ts b/superset-frontend/cypress-base/cypress/utils/urls.ts index 124046b8262b0..2f3cc4d56c411 100644 --- a/superset-frontend/cypress-base/cypress/utils/urls.ts +++ b/superset-frontend/cypress-base/cypress/utils/urls.ts @@ -19,3 +19,4 @@ export const DASHBOARD_LIST = '/dashboard/list/'; export const CHART_LIST = '/chart/list/'; +export const WORLD_HEALTH_DASHBOARD = '/superset/dashboard/world_health/'; \ No newline at end of file From 984baf6bf9af0715619e6ad32c46c15ef5b81596 Mon Sep 17 00:00:00 2001 From: geido Date: Fri, 2 Sep 2022 14:52:36 +0300 Subject: [PATCH 07/31] Refactor edit/save dashboard tests --- .../cypress/fixtures/dashboards.json | 12 +- .../integration/dashboard/dashboard.helper.ts | 24 -- .../integration/dashboard/edit_mode.test.js | 98 ------- .../dashboard/edit_properties.test.ts | 263 ----------------- .../integration/dashboard/editsave.test.ts | 272 ++++++++++++++++++ .../integration/dashboard/markdown.test.ts | 4 +- .../dashboard/nativeFilters.test.ts | 2 +- .../integration/dashboard/save.test.js | 163 ----------- .../cypress-base/cypress/support/index.d.ts | 3 + .../cypress-base/cypress/support/index.ts | 58 ++-- .../cypress-base/cypress/utils/index.ts | 23 ++ .../cypress-base/cypress/utils/urls.ts | 3 +- .../PageHeaderWithActions/index.tsx | 1 + .../components/BuilderComponentPane/index.tsx | 1 + .../src/dashboard/components/Header/index.jsx | 2 +- .../components/PropertiesModal/index.tsx | 1 + 16 files changed, 345 insertions(+), 585 deletions(-) delete mode 100644 superset-frontend/cypress-base/cypress/integration/dashboard/edit_mode.test.js delete mode 100644 superset-frontend/cypress-base/cypress/integration/dashboard/edit_properties.test.ts create mode 100644 superset-frontend/cypress-base/cypress/integration/dashboard/editsave.test.ts delete mode 100644 superset-frontend/cypress-base/cypress/integration/dashboard/save.test.js diff --git a/superset-frontend/cypress-base/cypress/fixtures/dashboards.json b/superset-frontend/cypress-base/cypress/fixtures/dashboards.json index 6972cb0552e1a..68a9984e419d0 100644 --- a/superset-frontend/cypress-base/cypress/fixtures/dashboards.json +++ b/superset-frontend/cypress-base/cypress/fixtures/dashboards.json @@ -1,14 +1,18 @@ [ { - "dashboard_title": "1 - Sample dashboard" + "dashboard_title": "1 - Sample dashboard", + "slug": "1-sample-dashboard" }, { - "dashboard_title": "2 - Sample dashboard" + "dashboard_title": "2 - Sample dashboard", + "slug": "2-sample-dashboard" }, { - "dashboard_title": "3 - Sample dashboard" + "dashboard_title": "3 - Sample dashboard", + "slug": "3-sample-dashboard" }, { - "dashboard_title": "4 - Sample dashboard" + "dashboard_title": "4 - Sample dashboard", + "slug": "4-sample-dashboard" } ] \ No newline at end of file diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts index 39b7fc40c21a9..9868eb5b5e755 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts @@ -67,30 +67,6 @@ export const ECHARTS_CHARTS = [ { name: 'Energy Force Layout', viz: 'graph_chart' }, ] as const; -/** - * Drag an element and drop it to another element. - * Usage: - * drag(source).to(target); - */ -export function drag(selector: string, content: string | number | RegExp) { - const dataTransfer = { data: {} }; - return { - to(target: string | Cypress.Chainable) { - cy.get('.dragdroppable') - .contains(selector, content) - .trigger('mousedown', { which: 1 }) - .trigger('dragstart', { dataTransfer }) - .trigger('drag', {}); - - (typeof target === 'string' ? cy.get(target) : target) - .trigger('dragover', { dataTransfer }) - .trigger('drop', { dataTransfer }) - .trigger('dragend', { dataTransfer }) - .trigger('mouseup', { which: 1 }); - }, - }; -} - export function resize(selector: string) { return { to(cordX: number, cordY: number) { diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/edit_mode.test.js b/superset-frontend/cypress-base/cypress/integration/dashboard/edit_mode.test.js deleted file mode 100644 index 0f646cce3d212..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/edit_mode.test.js +++ /dev/null @@ -1,98 +0,0 @@ -/** - * 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 { drag } from './dashboard.helper'; -import { WORLD_HEALTH_DASHBOARD } from 'cypress/utils/urls'; - -describe('Dashboard edit mode', () => { - beforeEach(() => { - cy.login(); - cy.visit(WORLD_HEALTH_DASHBOARD); - cy.get('.header-with-actions') - .find('[aria-label="Edit dashboard"]') - .click(); - }); - - it('remove, and add chart flow', () => { - // wait for box plot to appear - cy.get('[data-test="grid-container"]').find('.box_plot', { - timeout: 10000, - }); - const elementsCount = 10; - - cy.get('[data-test="dashboard-component-chart-holder"]') - .find('[data-test="dashboard-delete-component-button"]') - .last() - .then($el => { - cy.wrap($el).invoke('show').click(); - // box plot should be gone - cy.get('[data-test="grid-container"]') - .find('.box_plot') - .should('not.exist'); - }); - - // find box plot is available from list - cy.get('[data-test="dashboard-charts-filter-search-input"]').type( - 'Box plot', - ); - cy.get('[data-test="card-title"]').should('have.length', 1); - - drag('[data-test="card-title"]', 'Box plot').to( - '.grid-row.background--transparent:last', - ); - - // add back to dashboard - cy.get('[data-test="grid-container"]') - .find('.box_plot') - .should('be.visible'); - - // should show Save changes button - cy.get('[data-test="header-save-button"]').should('be.visible'); - - // undo first step and expect deleted item - cy.get('[data-test="undo-action"]').click(); - cy.get('[data-test="grid-container"]') - .find('[data-test="chart-container"]') - .should('have.length', elementsCount - 1); - - // Box plot chart should be gone - cy.get('[data-test="grid-container"]') - .find('.box_plot') - .should('not.exist'); - - // undo second step and expect initial items count - cy.get('[data-test="undo-action"]').click(); - cy.get('[data-test="grid-container"]') - .find('[data-test="chart-container"]') - .should('have.length', elementsCount); - cy.get('[data-test="card-title"]').contains('Box plot', { timeout: 5000 }); - - // save changes button should be disabled - cy.get('[data-test="header-save-button"]').should('be.disabled'); - - // no changes, can switch to view mode - cy.get('[data-test="dashboard-edit-actions"]') - .find('[data-test="discard-changes-button"]') - .should('be.visible') - .click(); - cy.get('.header-with-actions').within(() => { - cy.get('[data-test="dashboard-edit-actions"]').should('not.be.visible'); - cy.get('[aria-label="Edit dashboard"]').should('be.visible'); - }); - }); -}); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/edit_properties.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/edit_properties.test.ts deleted file mode 100644 index 57839ebc2cf76..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/edit_properties.test.ts +++ /dev/null @@ -1,263 +0,0 @@ -/** - * 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. - */ - -// eslint-disable-next-line import/no-extraneous-dependencies -import * as ace from 'brace'; -import * as shortid from 'shortid'; -import { USA_BIRTH_NAMES_DASHBOARD } from './dashboard.helper'; - -function selectColorScheme(color: string) { - // open color scheme dropdown - cy.get('.ant-modal-body') - .contains('Color scheme') - .parents('.ControlHeader') - .next('.ant-select') - .click() - .then($colorSelect => { - // select a new color scheme - cy.wrap($colorSelect).find(`[data-test="${color}"]`).click(); - }); -} - -function assertMetadata(text: string) { - const regex = new RegExp(text); - cy.get('.ant-modal-body') - .find('#json_metadata') - .should('be.visible') - .then(() => { - const metadata = cy.$$('#json_metadata')[0]; - - // cypress can read this locally, but not in ci - // so we have to use the ace module directly to fetch the value - expect(ace.edit(metadata).getValue()).to.match(regex); - }); -} -function clear(input: string) { - cy.get(input).type('{selectall}{backspace}'); -} -function type(input: string, text: string) { - cy.get(input).type(text, { parseSpecialCharSequences: false }); -} - -function openAdvancedProperties() { - return cy - .get('.ant-modal-body') - .contains('Advanced') - .should('be.visible') - .click(); -} - -function openDashboardEditProperties() { - // open dashboard properties edit modal - cy.get( - '.header-with-actions .right-button-panel .ant-dropdown-trigger', - ).trigger('click', { - force: true, - }); - cy.get('[data-test=header-actions-menu]') - .contains('Edit properties') - .click({ force: true }); -} - -describe('Dashboard edit action', () => { - beforeEach(() => { - cy.login(); - cy.visit(USA_BIRTH_NAMES_DASHBOARD); - cy.intercept(`/api/v1/dashboard/births`).as('dashboardGet'); - cy.get('.dashboard-grid', { timeout: 50000 }) - .should('be.visible') // wait for 50 secs to load dashboard - .then(() => { - cy.get('.header-with-actions [aria-label="Edit dashboard"]') - .should('be.visible') - .click(); - openDashboardEditProperties(); - }); - }); - - it('should update the title', () => { - const dashboardTitle = `Test dashboard [${shortid.generate()}]`; - - // update title - cy.get('.ant-modal-body') - .should('be.visible') - .contains('Title') - .get('[data-test="dashboard-title-input"]') - .type(`{selectall}{backspace}${dashboardTitle}`); - - // save edit changes - cy.get('.ant-modal-footer') - .contains('Apply') - .click() - .then(() => { - // assert that modal edit window has closed - cy.get('.ant-modal-body').should('not.exist'); - - // assert title has been updated - cy.get('[data-test="editable-title-input"]').should( - 'have.value', - dashboardTitle, - ); - }); - }); - describe('the color picker is changed', () => { - describe('the metadata has a color scheme', () => { - describe('the advanced tab is open', () => { - it('should overwrite the color scheme', () => { - openAdvancedProperties(); - selectColorScheme('d3Category20b'); - assertMetadata('d3Category20b'); - }); - }); - describe('the advanced tab is not open', () => { - it('should overwrite the color scheme', () => { - selectColorScheme('bnbColors'); - openAdvancedProperties(); - assertMetadata('bnbColors'); - }); - }); - }); - }); - describe('a valid colorScheme is entered', () => { - it('should save json metadata color change to dropdown', () => { - // edit json metadata - openAdvancedProperties().then(() => { - clear('#json_metadata'); - type('#json_metadata', '{"color_scheme":"d3Category20"}'); - }); - - // save edit changes - cy.get('.ant-modal-footer') - .contains('Apply') - .click() - .then(() => { - // assert that modal edit window has closed - cy.get('.ant-modal-body').should('not.exist'); - - // assert color has been updated - openDashboardEditProperties(); - openAdvancedProperties().then(() => { - assertMetadata('d3Category20'); - }); - cy.get('.ant-select-selection-item .color-scheme-option').should( - 'have.attr', - 'data-test', - 'd3Category20', - ); - }); - }); - }); - describe('an invalid colorScheme is entered', () => { - it('should throw an error', () => { - // edit json metadata - openAdvancedProperties().then(() => { - clear('#json_metadata'); - type('#json_metadata', '{"color_scheme":"THIS_DOES_NOT_WORK"}'); - }); - - // save edit changes - cy.get('.ant-modal-footer') - .contains('Apply') - .click() - .then(() => { - // assert that modal edit window has closed - cy.get('.ant-modal-body') - .contains('A valid color scheme is required') - .should('be.visible'); - }); - - cy.on('uncaught:exception', err => { - expect(err.message).to.include('something about the error'); - - // return false to prevent the error from - // failing this test - return false; - }); - }); - }); - describe.skip('the color scheme affects the chart colors', () => { - it('should change the chart colors', () => { - openAdvancedProperties().then(() => { - clear('#json_metadata'); - type( - '#json_metadata', - '{"color_scheme":"lyftColors", "label_colors": {}}', - ); - }); - - cy.get('.ant-modal-footer') - .contains('Apply') - .click() - .then(() => { - cy.get('.ant-modal-body').should('not.exist'); - // assert that the chart has changed colors - cy.get('.line .nv-legend-symbol') - .first() - .should('have.css', 'fill', 'rgb(117, 96, 170)'); - }); - }); - it('the label colors should take precedence over the scheme', () => { - openAdvancedProperties().then(() => { - clear('#json_metadata'); - type( - '#json_metadata', - '{"color_scheme":"lyftColors","label_colors":{"Amanda":"red"}}', - ); - }); - - cy.get('.ant-modal-footer') - .contains('Apply') - .click() - .then(() => { - cy.get('.ant-modal-body').should('not.exist'); - // assert that the chart has changed colors - cy.get('.line .nv-legend-symbol') - .first() - .should('have.css', 'fill', 'rgb(255, 0, 0)'); - }); - }); - it('the shared label colors and label colors are applied correctly', () => { - openAdvancedProperties().then(() => { - clear('#json_metadata'); - type( - '#json_metadata', - '{"color_scheme":"lyftColors","label_colors":{"Amanda":"red"}}', - ); - }); - - cy.get('.ant-modal-footer') - .contains('Apply') - .click() - .then(() => { - cy.get('.ant-modal-body').should('not.exist'); - // assert that the chart has changed colors - cy.get('.line .nv-legend-symbol') - .first() - .should('have.css', 'fill', 'rgb(255, 0, 0)'); // label: amanda - cy.get('.line .nv-legend-symbol') - .eq(11) - .should('have.css', 'fill', 'rgb(234, 11, 140)'); // label: jennifer - cy.get('.word_cloud') - .first() - .find('svg text') - .first() - .should('have.css', 'fill', 'rgb(234, 11, 140)'); // label: jennifer - }); - }); - }); -}); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/editsave.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/editsave.test.ts new file mode 100644 index 0000000000000..f456d9473aab5 --- /dev/null +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/editsave.test.ts @@ -0,0 +1,272 @@ +/** + * 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 { SAMPLE_DASHBOARD_1 } from 'cypress/utils/urls'; +import { drag } from 'cypress/utils'; +import { + interceptUpdate, +} from './utils'; +import * as ace from 'brace'; +import {interceptFiltering as interceptCharts} from '../explore/utils'; + +function editDashboard() { + cy.getBySel('edit-dashboard-button').click(); +} + +function closeModal() { + cy.getBySel('properties-modal-cancel-button').click({force: true}); +} + +function openProperties() { + cy.get('body') + .then($body => { + if ($body.find('[data-test="properties-modal-cancel-button"]').length) { + closeModal(); + } + }); + cy.getBySel('actions-trigger').click({ force: true} ); + cy.getBySel('header-actions-menu').contains('Edit properties').click({ force: true} ); + cy.wait(500); +} + +function openAdvancedProperties() { + return cy + .get('.ant-modal-body') + .contains('Advanced') + .should('be.visible') + .click({ force: true }); +} + +function dragChart(chart = 'Unicode Cloud') { + drag('[data-test="card-title"]', chart).to( + '[data-test="grid-content"] [data-test="dragdroppable-object"]', + ); +} + +function discardChanges() { + cy.getBySel('undo-action').click({ force: true }); +} + +function visitEdit() { + interceptCharts(); + cy.visit(SAMPLE_DASHBOARD_1); + editDashboard(); + cy.wait('@filtering'); +} + +function selectColorScheme(color: string) { + cy.get('[data-test="dashboard-edit-properties-form"] [aria-label="Select color scheme"]').first().click(); + cy.getBySel(color).click(); +} + +function applyChanges() { + cy.getBySel('properties-modal-apply-button').click(); +} + +function saveChanges() { + interceptUpdate(); + cy.getBySel('header-save-button').click(); + cy.wait('@update'); +} + +function assertMetadata(text: string) { + const regex = new RegExp(text); + cy.get('.ant-modal-body') + .find('#json_metadata') + .should('be.visible') + .then(() => { + const metadata = cy.$$('#json_metadata')[0]; + + // cypress can read this locally, but not in ci + // so we have to use the ace module directly to fetch the value + expect(ace.edit(metadata).getValue()).to.match(regex); + }); +} +function clearAll(input: string) { + return cy.get(input).type('{selectall}{backspace}'); +} + +describe('Dashboard edit', () => { + beforeEach(() => { + cy.preserveLogin(); + }); + + describe('Edit mode', () => { + before(() => { + cy.createSampleDashboards(); + visitEdit(); + }); + + beforeEach(() => { + discardChanges(); + }); + + it('should enable edit mode', () => { + cy.getBySel('dashboard-builder-sidepane').should('be.visible'); + }); + + it('should edit the title inline', () => { + cy.getBySel('editable-title-input').clear().type('Edited title{enter}'); + cy.getBySel('header-save-button').should('be.enabled'); + }); + + it('should filter charts', () => { + interceptCharts(); + cy.getBySel('dashboard-charts-filter-search-input').type('Unicode'); + cy.wait('@filtering'); + cy.getBySel('chart-card').should('have.length', 1).contains('Unicode Cloud'); + cy.getBySel('dashboard-charts-filter-search-input').clear(); + }); + + }); + + describe('Components', () => { + before(() => { + cy.createSampleDashboards(); + }); + + beforeEach(() => { + visitEdit(); + }); + + it('should add charts', () => { + dragChart(); + cy.getBySel('dashboard-component-chart-holder').should('have.length', 1); + }); + + it('should remove added charts', () => { + dragChart('% Rural'); + cy.getBySel('dashboard-component-chart-holder').should('have.length', 1); + cy.getBySel('dashboard-delete-component-button').click(); + cy.getBySel('dashboard-component-chart-holder').should('have.length', 0); + }); + }); + + describe('Edit properties', () => { + before(() => { + cy.createSampleDashboards(); + visitEdit(); + }); + + beforeEach(() => { + openProperties(); + }); + + it('should overwrite the color scheme when advanced is closed', () => { + selectColorScheme('d3Category20b'); + openAdvancedProperties(); + assertMetadata('d3Category20b'); + applyChanges(); + }); + + it('should overwrite the color scheme when advanced is open', () => { + openAdvancedProperties(); + selectColorScheme('googleCategory10c'); + assertMetadata('googleCategory10c'); + applyChanges(); + }); + + it('should accept a valid color scheme', () => { + openAdvancedProperties(); + clearAll('#json_metadata').then(() => { + cy.get('#json_metadata').type('{"color_scheme":"lyftColors"}', { parseSpecialCharSequences: false }) + applyChanges(); + openProperties(); + openAdvancedProperties(); + assertMetadata('lyftColors'); + applyChanges(); + }) + + }); + + it('should not accept an invalid color scheme', () => { + openAdvancedProperties(); + clearAll('#json_metadata').then(() => { + cy.get('#json_metadata').type('{"color_scheme":"wrongcolorscheme"}', { parseSpecialCharSequences: false }) + applyChanges(); + cy.get('.ant-modal-body') + .contains('A valid color scheme is required') + .should('be.visible'); + }) + }); + + it('should edit the title', () => { + cy.getBySel('dashboard-title-input').clear().type('Edited title'); + applyChanges(); + cy.getBySel('editable-title-input').should('have.value', 'Edited title'); + }); + }); + + describe('Color schemes', () => { + beforeEach(() => { + cy.createSampleDashboards(); + visitEdit(); + }); + + it('should apply a valid color scheme', () => { + dragChart('Top 10 California Names Timeseries'); + openProperties(); + selectColorScheme('lyftColors'); + applyChanges(); + saveChanges(); + cy.get('.line .nv-legend-symbol') + .first() + .should('have.css', 'fill', 'rgb(234, 11, 140)'); + }); + + it('label colors should take the precedence', () => { + dragChart('Top 10 California Names Timeseries'); + openProperties(); + openAdvancedProperties(); + clearAll('#json_metadata').then(() => { + cy.get('#json_metadata').type('{"color_scheme":"lyftColors","label_colors":{"Anthony":"red"}}', { parseSpecialCharSequences: false }) + applyChanges(); + saveChanges(); + cy.get('.line .nv-legend-symbol') + .first() + .should('have.css', 'fill', 'rgb(255, 0, 0)'); + }); + }); + }); + + describe('Save', () => { + before(() => { + cy.createSampleDashboards(); + visitEdit(); + }); + + beforeEach(() => { + discardChanges(); + }) + + it('should disable saving when undoing', () => { + dragChart(); + cy.getBySel('header-save-button').should('be.enabled'); + discardChanges(); + cy.getBySel('header-save-button').should('be.disabled'); + }); + + it('should save', () => { + dragChart(); + cy.getBySel('header-save-button').should('be.enabled'); + saveChanges(); + cy.getBySel('dashboard-component-chart-holder').should('have.length', 1); + cy.getBySel('edit-dashboard-button').should('be.visible'); + }); + }); +}); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/markdown.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/markdown.test.ts index a27382933b532..5d7d8185086f5 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/markdown.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/markdown.test.ts @@ -16,8 +16,8 @@ * specific language governing permissions and limitations * under the License. */ -import { TABBED_DASHBOARD, drag, resize } from './dashboard.helper'; - +import { TABBED_DASHBOARD, resize } from './dashboard.helper'; +import { drag } from 'cypress/utils'; describe('Dashboard edit markdown', () => { beforeEach(() => { cy.login(); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts index 024f7b6fa3530..8b8c048862612 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts @@ -553,7 +553,7 @@ xdescribe('Nativefilters', () => { cy.get('[data-test="Treemap-list-chart-title"]') .should('be.visible', { timeout: 5000 }) .click(); - cy.get('[data-test="query-save-button"]').click(); + cy.get('[data-test="edit-dashboard-button"]').click(); cy.get('[data-test="save-chart-modal-select-dashboard-form"]') .find('input[aria-label="Select a dashboard"]') .type(`${dashboard}`, { force: true }); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/save.test.js b/superset-frontend/cypress-base/cypress/integration/dashboard/save.test.js deleted file mode 100644 index 07be4ef626d12..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/save.test.js +++ /dev/null @@ -1,163 +0,0 @@ -/** - * 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 shortid from 'shortid'; -import { - waitForChartLoad, -} from 'cypress/utils'; -import { WORLD_HEALTH_CHARTS } from './utils'; -import { WORLD_HEALTH_DASHBOARD } from 'cypress/utils/urls'; - -function openDashboardEditProperties() { - // open dashboard properties edit modal - cy.get('.header-with-actions [aria-label="Edit dashboard"]') - .should('be.visible') - .click(); - cy.get( - '.header-with-actions .right-button-panel .ant-dropdown-trigger', - ).trigger('click', { - force: true, - }); - cy.get('[data-test=header-actions-menu]') - .contains('Edit properties') - .click({ force: true }); -} - -describe('Dashboard save action', () => { - beforeEach(() => { - cy.login(); - cy.visit(WORLD_HEALTH_DASHBOARD); - cy.get('#app').then(() => { - cy.get('.dashboard-header-container').then(headerContainerElement => { - const dashboardId = headerContainerElement.attr('data-test-id'); - - cy.intercept('POST', `/superset/copy_dash/${dashboardId}/`).as( - 'copyRequest', - ); - - cy.get('[aria-label="more-horiz"]').trigger('click', { force: true }); - cy.get('[data-test="save-as-menu-item"]').trigger('click', { - force: true, - }); - cy.get('[data-test="modal-save-dashboard-button"]').trigger('click', { - force: true, - }); - }); - }); - }); - - // change to what the title should be - it('should save as new dashboard', () => { - cy.wait('@copyRequest').then(() => { - cy.get('[data-test="editable-title"]').then(element => { - const dashboardTitle = element.attr('title'); - expect(dashboardTitle).to.not.equal(`World Bank's Data`); - }); - }); - }); - - it('should save/overwrite dashboard', () => { - // should load chart - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); - - // remove box_plot chart from dashboard - cy.get('[aria-label="Edit dashboard"]').click({ timeout: 5000 }); - cy.get('[data-test="dashboard-delete-component-button"]') - .last() - .trigger('mouseenter') - .click(); - - cy.get('[data-test="grid-container"]') - .find('.box_plot') - .should('not.exist'); - - cy.intercept('PUT', '/api/v1/dashboard/**').as('putDashboardRequest'); - cy.get('.header-with-actions') - .find('[data-test="header-save-button"]') - .contains('Save') - .click(); - - // go back to view mode - cy.wait('@putDashboardRequest'); - cy.get('.header-with-actions') - .find('[aria-label="Edit dashboard"]') - .click(); - - // deleted boxplot should still not exist - cy.get('[data-test="grid-container"]') - .find('.box_plot', { timeout: 20000 }) - .should('not.exist'); - }); - - it('should save after edit', () => { - cy.get('.dashboard-grid', { timeout: 50000 }) // wait for 50 secs to load dashboard - .then(() => { - const dashboardTitle = `Test dashboard [${shortid.generate()}]`; - - openDashboardEditProperties(); - - // open color scheme dropdown - cy.get('.ant-modal-body') - .contains('Color scheme') - .parents('.ControlHeader') - .next('.ant-select') - .click() - .then(() => { - // select a new color scheme - cy.get('.ant-modal-body') - .find('.ant-select-item-option-active') - .first() - .click(); - }); - - // remove json metadata - cy.get('.ant-modal-body') - .contains('Advanced') - .click() - .then(() => { - cy.get('#json_metadata').type('{selectall}{backspace}'); - }); - - // update title - cy.get('[data-test="dashboard-title-input"]').type( - `{selectall}{backspace}${dashboardTitle}`, - ); - - // save edit changes - cy.get('.ant-modal-footer') - .contains('Apply') - .click() - .then(() => { - // assert that modal edit window has closed - cy.get('.ant-modal-body').should('not.exist'); - - // save dashboard changes - cy.get('.header-with-actions').contains('Save').click(); - - // assert success flash - cy.contains('saved successfully').should('be.visible'); - - // assert title has been updated - cy.get( - '.header-with-actions .title-panel [data-test="editable-title"]', - ).should('have.text', dashboardTitle); - }); - }); - }); -}); diff --git a/superset-frontend/cypress-base/cypress/support/index.d.ts b/superset-frontend/cypress-base/cypress/support/index.d.ts index fc065563d366d..a5011090eeb7a 100644 --- a/superset-frontend/cypress-base/cypress/support/index.d.ts +++ b/superset-frontend/cypress-base/cypress/support/index.d.ts @@ -38,6 +38,9 @@ declare namespace Cypress { getBySel(selector: string): cy; getBySelLike(selector: string): cy; + getSampleData(): void; + cleanCharts(): void; + cleanDashboards(): void; visitChartByParams(params: string | Record): cy; visitChartByName(name: string): cy; diff --git a/superset-frontend/cypress-base/cypress/support/index.ts b/superset-frontend/cypress-base/cypress/support/index.ts index 5f201200b56fe..3c24d167c3502 100644 --- a/superset-frontend/cypress-base/cypress/support/index.ts +++ b/superset-frontend/cypress-base/cypress/support/index.ts @@ -26,36 +26,36 @@ const TokenName = Cypress.env('TOKEN_NAME'); let SAMPLE_DASHBOARDS: Record[] = []; let SAMPLE_CHARTS: Record[] = []; -function resetSamples() { - cy.login(); - cy.fixture('dashboards.json').then(dashboards => { - dashboards.forEach((d: { dashboard_title: string }) => { - cy.deleteDashboardByName(d.dashboard_title, false); - }); - }); - cy.fixture('charts.json').then(charts => { - charts.forEach((c: { slice_name: string }) => { - cy.deleteChartByName(c.slice_name, false); - }); - }); -} - -function loadSampleData() { - cy.login(); +Cypress.Commands.add('getSampleData', () => cy.getCharts().then((slices: any) => { SAMPLE_CHARTS = slices; - }); - cy.getDashboards().then((dashboards: any) => { - SAMPLE_DASHBOARDS = dashboards; - }); -} + cy.getDashboards().then((dashboards: any) => { + SAMPLE_DASHBOARDS = dashboards; + }); + }) +); -before(() => { - loadSampleData(); -}); +Cypress.Commands.add('cleanDashboards', () => + cy.fixture('dashboards.json').then(dashboards => { + for (let i = 0; i < dashboards.length; i += 1) { + cy.deleteDashboardByName(dashboards[i].dashboard_title, false) + } + }) +); -beforeEach(() => { - resetSamples(); +Cypress.Commands.add('cleanCharts', () => + cy.fixture('charts.json').then(charts => { + for (let i = 0; i < charts.length; i += 1) { + cy.deleteChartByName(charts[i].slice_name, false) + } + }) +); + +before(() => { + cy.login(); + cy.cleanDashboards(); + cy.cleanCharts(); + cy.getSampleData(); }); Cypress.Commands.add('getBySel', (selector, ...args) => @@ -189,6 +189,7 @@ Cypress.Commands.add( Cypress.Commands.add('createSampleDashboards', () => { const requests: any = []; + cy.cleanDashboards(); cy.fixture('dashboards.json').then(dashboards => { for (let i = 0; i < dashboards.length; i += 1) { requests.push( @@ -208,11 +209,12 @@ Cypress.Commands.add('createSampleDashboards', () => { }), ); } - return Promise.all(requests).then(() => loadSampleData()); + return Promise.all(requests).then(() => cy.getSampleData()); }); }); Cypress.Commands.add('createSampleCharts', () => { + cy.cleanCharts(); const requests: any = []; return cy.fixture('charts.json').then(charts => { for (let i = 0; i < charts.length; i += 1) { @@ -233,7 +235,7 @@ Cypress.Commands.add('createSampleCharts', () => { }), ); } - return Promise.all(requests).then(() => loadSampleData()); + return Promise.all(requests).then(() => cy.getSampleData()); }); }); diff --git a/superset-frontend/cypress-base/cypress/utils/index.ts b/superset-frontend/cypress-base/cypress/utils/index.ts index 3bdbb0f122acb..949817c84a0db 100644 --- a/superset-frontend/cypress-base/cypress/utils/index.ts +++ b/superset-frontend/cypress-base/cypress/utils/index.ts @@ -86,3 +86,26 @@ export function waitForChartLoad(chart: ChartSpec) { }); } +/** + * Drag an element and drop it to another element. + * Usage: + * drag(source).to(target); + */ + export function drag(selector: string, content: string | number | RegExp) { + const dataTransfer = { data: {} }; + return { + to(target: string | Cypress.Chainable) { + cy.get('.dragdroppable') + .contains(selector, content) + .trigger('mousedown', { which: 1, force: true }) + .trigger('dragstart', { dataTransfer, force: true }) + .trigger('drag', {force: true}); + + (typeof target === 'string' ? cy.get(target) : target) + .trigger('dragover', { dataTransfer, force: true }) + .trigger('drop', { dataTransfer, force: true }) + .trigger('dragend', { dataTransfer, force: true }) + .trigger('mouseup', { which: 1, force: true }); + }, + }; + } \ No newline at end of file diff --git a/superset-frontend/cypress-base/cypress/utils/urls.ts b/superset-frontend/cypress-base/cypress/utils/urls.ts index 2f3cc4d56c411..40eb51a170fad 100644 --- a/superset-frontend/cypress-base/cypress/utils/urls.ts +++ b/superset-frontend/cypress-base/cypress/utils/urls.ts @@ -19,4 +19,5 @@ export const DASHBOARD_LIST = '/dashboard/list/'; export const CHART_LIST = '/chart/list/'; -export const WORLD_HEALTH_DASHBOARD = '/superset/dashboard/world_health/'; \ No newline at end of file +export const WORLD_HEALTH_DASHBOARD = '/superset/dashboard/world_health/'; +export const SAMPLE_DASHBOARD_1 = '/superset/dashboard/1-sample-dashboard/'; \ No newline at end of file diff --git a/superset-frontend/src/components/PageHeaderWithActions/index.tsx b/superset-frontend/src/components/PageHeaderWithActions/index.tsx index e85ccdfc82580..19f1ded4a78cc 100644 --- a/superset-frontend/src/components/PageHeaderWithActions/index.tsx +++ b/superset-frontend/src/components/PageHeaderWithActions/index.tsx @@ -152,6 +152,7 @@ export const PageHeaderWithActions = ({ css={menuTriggerStyles} buttonStyle="tertiary" aria-label={t('Menu actions trigger')} + data-test="actions-trigger" > = ({ {({ height }) => ( diff --git a/superset-frontend/src/dashboard/components/Header/index.jsx b/superset-frontend/src/dashboard/components/Header/index.jsx index 19b7c21ce2311..354ee81bbcfe2 100644 --- a/superset-frontend/src/dashboard/components/Header/index.jsx +++ b/superset-frontend/src/dashboard/components/Header/index.jsx @@ -618,7 +618,7 @@ class Header extends React.PureComponent { - diff --git a/superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx b/superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx index ee99767b310a4..057421a9fb9bb 100644 --- a/superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx +++ b/superset-frontend/src/dashboard/components/SliceHeaderControls/index.tsx @@ -205,6 +205,7 @@ const DashboardChartModalTrigger = ({ {t('Edit chart')} - From 76bb41a6c9d832bc66fc8340bf40906207e88c35 Mon Sep 17 00:00:00 2001 From: geido Date: Mon, 5 Sep 2022 18:50:26 +0300 Subject: [PATCH 17/31] Refactor tabs test --- .../cypress-base/cypress/fixtures/charts.json | 2 +- .../cypress/fixtures/dashboards.json | 2 +- .../cypress/fixtures/example.json | 5 -- .../integration/dashboard/dashboard.helper.ts | 1 - .../integration/dashboard/tabs.test.ts | 86 ++++++++----------- .../cypress-base/cypress/utils/urls.ts | 1 + 6 files changed, 41 insertions(+), 56 deletions(-) delete mode 100644 superset-frontend/cypress-base/cypress/fixtures/example.json diff --git a/superset-frontend/cypress-base/cypress/fixtures/charts.json b/superset-frontend/cypress-base/cypress/fixtures/charts.json index 6bdeda9e413b6..b5a9bb8da89d9 100644 --- a/superset-frontend/cypress-base/cypress/fixtures/charts.json +++ b/superset-frontend/cypress-base/cypress/fixtures/charts.json @@ -35,4 +35,4 @@ "datasource_id": 1, "datasource_type": "table" } -] \ No newline at end of file +] diff --git a/superset-frontend/cypress-base/cypress/fixtures/dashboards.json b/superset-frontend/cypress-base/cypress/fixtures/dashboards.json index 68a9984e419d0..cff35d04c9398 100644 --- a/superset-frontend/cypress-base/cypress/fixtures/dashboards.json +++ b/superset-frontend/cypress-base/cypress/fixtures/dashboards.json @@ -15,4 +15,4 @@ "dashboard_title": "4 - Sample dashboard", "slug": "4-sample-dashboard" } -] \ No newline at end of file +] diff --git a/superset-frontend/cypress-base/cypress/fixtures/example.json b/superset-frontend/cypress-base/cypress/fixtures/example.json deleted file mode 100644 index 02e4254378e97..0000000000000 --- a/superset-frontend/cypress-base/cypress/fixtures/example.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "Using fixtures to represent data", - "email": "hello@cypress.io", - "body": "Fixtures are a great way to mock data for responses to routes" -} diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts index 7201cc203c54e..ec64b50260b95 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts @@ -20,7 +20,6 @@ import { dashboardView } from 'cypress/support/directories'; */ export const USA_BIRTH_NAMES_DASHBOARD = '/superset/dashboard/births/'; export const testDashboard = '/superset/dashboard/538/'; -export const TABBED_DASHBOARD = '/superset/dashboard/tabbed_dash/'; export const testItems = { dashboard: 'Cypress test Dashboard', diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/tabs.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/tabs.test.ts index 4dbb8c712bccf..6c8c559df18df 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/tabs.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/tabs.test.ts @@ -16,42 +16,48 @@ * specific language governing permissions and limitations * under the License. */ -import { parsePostForm } from 'cypress/utils'; import { - TABBED_DASHBOARD, + parsePostForm, waitForChartLoad, getChartAliasBySpec, -} from './dashboard.helper'; +} from 'cypress/utils'; +import { TABBED_DASHBOARD } from 'cypress/utils/urls'; const TREEMAP = { name: 'Treemap', viz: 'treemap' }; const FILTER_BOX = { name: 'Region Filter', viz: 'filter_box' }; const LINE_CHART = { name: 'Growth Rate', viz: 'line' }; const BOX_PLOT = { name: 'Box plot', viz: 'box_plot' }; +const BIG_NUMBER = { name: 'Number of Girls', viz: 'big_number_total' }; +const TABLE = { name: 'Names Sorted by Num in California', viz: 'table' }; + +function topLevelTabs() { + cy.getBySel('dashboard-component-tabs') + .first() + .find('[data-test="nav-list"] .ant-tabs-nav-list > .ant-tabs-tab') + .as('top-level-tabs'); +} + +function resetTabs() { + topLevelTabs(); + cy.get('@top-level-tabs').first().click(); + waitForChartLoad(FILTER_BOX); + waitForChartLoad(TREEMAP); + waitForChartLoad(BIG_NUMBER); + waitForChartLoad(TABLE); +} describe('Dashboard tabs', () => { - // cypress can not handle window.scrollTo - // https://github.com/cypress-io/cypress/issues/2761 - // add this exception handler to pass test - const handleException = () => { - // return false to prevent the error from - // failing this test - cy.on('uncaught:exception', () => false); - }; - - beforeEach(() => { - cy.login(); - + before(() => { cy.visit(TABBED_DASHBOARD); }); - it('should switch active tab on click', () => { - waitForChartLoad(FILTER_BOX); - waitForChartLoad(TREEMAP); + beforeEach(() => { + cy.preserveLogin(); + resetTabs(); + }); - cy.get('[data-test="dashboard-component-tabs"]') - .first() - .find('[data-test="nav-list"] .ant-tabs-nav-list > .ant-tabs-tab') - .as('top-level-tabs'); + it('should switch tabs', () => { + topLevelTabs(); cy.get('@top-level-tabs') .first() @@ -61,6 +67,9 @@ describe('Dashboard tabs', () => { .last() .should('not.have.class', 'ant-tabs-tab-active'); + cy.getBySel('grid-container').find('.box_plot').should('not.exist'); + cy.getBySel('grid-container').find('.line').should('not.exist'); + cy.get('@top-level-tabs') .last() .click() @@ -68,42 +77,23 @@ describe('Dashboard tabs', () => { cy.get('@top-level-tabs') .first() .should('not.have.class', 'ant-tabs-tab-active'); - }); + waitForChartLoad(BOX_PLOT); + cy.getBySel('grid-container').find('.box_plot').should('be.visible'); - it('should load charts when tab is visible', () => { - // landing in first tab, should see 2 charts - waitForChartLoad(FILTER_BOX); - waitForChartLoad(TREEMAP); - cy.get('[data-test="grid-container"]') - .find('.box_plot') - .should('not.exist'); - cy.get('[data-test="grid-container"]').find('.line').should('not.exist'); + resetTabs(); // click row level tab, see 1 more chart - cy.get('[data-test="dashboard-component-tabs"]') - .last() + cy.getBySel('dashboard-component-tabs') + .eq(2) .find('[data-test="nav-list"] .ant-tabs-nav-list > .ant-tabs-tab') .as('row-level-tabs'); cy.get('@row-level-tabs').last().click(); - waitForChartLoad(LINE_CHART); - cy.get('[data-test="grid-container"]').find('.line').should('be.visible'); - - // click top level tab, see 1 more chart - handleException(); - cy.get('[data-test="dashboard-component-tabs"]') - .first() - .find('[data-test="nav-list"] .ant-tabs-nav-list > .ant-tabs-tab') - .as('top-level-tabs'); - - cy.get('@top-level-tabs').last().click(); - - // should exist a visible box_plot element - cy.get('[data-test="grid-container"]').find('.box_plot'); + cy.getBySel('grid-container').find('.line').should('be.visible'); }); - xit('should send new queries when tab becomes visible', () => { + it.skip('should send new queries when tab becomes visible', () => { // landing in first tab waitForChartLoad(FILTER_BOX); waitForChartLoad(TREEMAP); diff --git a/superset-frontend/cypress-base/cypress/utils/urls.ts b/superset-frontend/cypress-base/cypress/utils/urls.ts index 3e8a629428d84..f99b4ca40cb64 100644 --- a/superset-frontend/cypress-base/cypress/utils/urls.ts +++ b/superset-frontend/cypress-base/cypress/utils/urls.ts @@ -22,3 +22,4 @@ export const CHART_LIST = '/chart/list/'; export const WORLD_HEALTH_DASHBOARD = '/superset/dashboard/world_health/'; export const SAMPLE_DASHBOARD_1 = '/superset/dashboard/1-sample-dashboard/'; export const ECHARTS_DASHBOARD = '/superset/dashboard/echarts_dash/'; +export const TABBED_DASHBOARD = '/superset/dashboard/tabbed_dash/'; From 4afedab18290a4ed64020be38165d9feec19b71f Mon Sep 17 00:00:00 2001 From: geido Date: Wed, 7 Sep 2022 16:37:24 +0300 Subject: [PATCH 18/31] Improve nativeFilters tests --- .../integration/dashboard/dashboard.helper.ts | 101 ---- .../dashboard/nativeFilter.helper.ts | 413 ----------------- .../dashboard/nativeFilters.test.ts | 100 ++-- .../cypress/integration/dashboard/utils.ts | 431 ++++++++++++++++++ .../cypress-base/cypress/support/index.d.ts | 1 + .../cypress-base/cypress/support/index.ts | 36 +- 6 files changed, 502 insertions(+), 580 deletions(-) delete mode 100644 superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts delete mode 100644 superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilter.helper.ts diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts deleted file mode 100644 index ec64b50260b95..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/dashboard.helper.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { dashboardView } from 'cypress/support/directories'; - -/** - * 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. - */ -export const USA_BIRTH_NAMES_DASHBOARD = '/superset/dashboard/births/'; -export const testDashboard = '/superset/dashboard/538/'; - -export const testItems = { - dashboard: 'Cypress test Dashboard', - dataset: 'Vehicle Sales', - datasetForNativeFilter: 'wb_health_population', - chart: 'Cypress chart', - newChart: 'New Cypress Chart', - createdDashboard: 'New Dashboard', - defaultNameDashboard: '[ untitled dashboard ]', - newDashboardTitle: `Test dashboard [NEW TEST]`, - bulkFirstNameDashboard: 'First Dash', - bulkSecondNameDashboard: 'Second Dash', - worldBanksDataCopy: `World Bank's Data [copy]`, - filterType: { - value: 'Value', - numerical: 'Numerical range', - timeColumn: 'Time column', - timeGrain: 'Time grain', - timeRange: 'Time range', - }, - topTenChart: { - name: 'Most Populated Countries', - filterColumn: 'country_name', - filterColumnYear: 'year', - filterColumnRegion: 'region', - filterColumnCountryCode: 'country_code', - }, - filterDefaultValue: 'United States', - filterOtherCountry: 'China', - filterTimeGrain: 'Month', - filterTimeColumn: 'created', - filterNumericalColumn: 'SP_RUR_TOTL_ZS', -}; - -export function cleanUp() { - cy.deleteDashboardByName(testItems.dashboard); - cy.deleteDashboardByName(testItems.defaultNameDashboard); - cy.deleteDashboardByName(''); - cy.deleteDashboardByName(testItems.newDashboardTitle); - cy.deleteDashboardByName(testItems.bulkFirstNameDashboard); - cy.deleteDashboardByName(testItems.bulkSecondNameDashboard); - cy.deleteDashboardByName(testItems.createdDashboard); - cy.deleteDashboardByName(testItems.worldBanksDataCopy); - cy.deleteChartByName(testItems.chart); - cy.deleteChartByName(testItems.newChart); -} - -/** ************************************************************************ - * Copy dashboard for testing purpose - * @returns {None} - * @summary helper for copy dashboard for testing purpose - ************************************************************************* */ -export function copyTestDashboard(dashboard: string) { - cy.intercept('POST', '**/copy_dash/**').as('copy'); - cy.intercept('GET', '**/api/v1/dataset/**').as('datasetLoad'); - cy.intercept('**/api/v1/dashboard/?q=**').as('dashboardsList'); - cy.intercept('**/api/v1/dashboard/**').as('dashboard'); - cy.visit('dashboard/list/'); - cy.contains('Actions'); - cy.wait('@dashboardsList').then(xhr => { - const dashboards = xhr.response?.body.result; - /* eslint-disable no-unused-expressions */ - expect(dashboards).not.to.be.undefined; - const testDashboard = dashboards.find( - (d: { dashboard_title: string }) => d.dashboard_title === `${dashboard}`, - ); - cy.visit(testDashboard.url); - }); - cy.get(dashboardView.threeDotsMenuIcon).should('be.visible').click(); - cy.get(dashboardView.saveAsMenuOption).click(); - cy.get(dashboardView.saveModal.dashboardNameInput) - .should('be.visible') - .clear() - .type(testItems.dashboard); - cy.get(dashboardView.saveModal.saveButton).click(); - cy.wait('@copy', { timeout: 45000 }) - .its('response.statusCode') - .should('eq', 200); -} diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilter.helper.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilter.helper.ts deleted file mode 100644 index 5f43b330ceeac..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilter.helper.ts +++ /dev/null @@ -1,413 +0,0 @@ -/** - * 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 { dashboardView, nativeFilters } from 'cypress/support/directories'; -import { testItems } from './dashboard.helper'; - -export const nativeFilterTooltips = { - searchAllFilterOptions: - 'By default, each filter loads at most 1000 choices at the initial page load. Check this box if you have more than 1000 filter values and want to enable dynamically searching that loads filter values as users type (may add stress to your database).', - defaultToFirstItem: 'When using this option, default value can’t be set', - inverseSelection: 'Exclude selected values', - required: 'User must select a value before applying the filter', - multipleSelect: 'Allow selecting multiple values', - defaultValue: - 'Default value must be set when "Filter value is required" is checked', -}; - -export const nativeFilterOptions = [ - 'Filter has default value', - 'Multiple select', - 'Filter value is required', - 'Filter is hierarchical', - 'Default to first item', - 'Inverse selection', - 'Search all filter options', - 'Pre-filter available values', - 'Sort filter values', -]; - -export const valueNativeFilterOptions = [ - 'Pre-filter available values', - 'Sort filter values', - 'Filter has default value', - 'Select first filter value by default', - 'Can select multiple values', - 'Dynamically search all filter values', - 'Inverse selection', - 'Filter value is required', -]; - -/** ************************************************************************ - * Expend Native filter from the left panel on dashboard - * @returns {None} - * @summary helper for expend native filter - ************************************************************************* */ -export function expandFilterOnLeftPanel() { - return cy - .get(nativeFilters.filterFromDashboardView.expand) - .should('be.visible') - .click({ force: true }); -} - -/** ************************************************************************ - * Collapes Native Filter from the left panel on dashboard - * @returns {None} - * @summary helper for collape native filter - ************************************************************************* */ -export function collapseFilterOnLeftPanel() { - cy.get(nativeFilters.filterFromDashboardView.collapse) - .should('be.visible') - .click(); - cy.get(nativeFilters.filterFromDashboardView.collapse).should( - 'not.be.visible', - ); -} - -/** ************************************************************************ - * Enter Native Filter edit modal from the left panel on dashboard - * @returns {None} - * @summary helper for enter native filter edit modal - ************************************************************************* */ -export function enterNativeFilterEditModal() { - cy.get(nativeFilters.filterFromDashboardView.createFilterButton).click({ - force: true, - }); - cy.get(nativeFilters.modal.container).should('be.visible'); -} - -/** ************************************************************************ - * Clicks on new filter button - * @returns {None} - * @summary helper for adding new filter - ************************************************************************* */ -export function clickOnAddFilterInModal() { - return cy - .get(nativeFilters.addFilterButton.button) - .first() - .click() - .then(() => { - cy.get(nativeFilters.addFilterButton.dropdownItem) - .contains('Filter') - .click({ force: true }); - }); -} - -/** ************************************************************************ - * Fills value native filter form with basic information - * @param {string} type type for filter: Value, Numerical range,Time column,Time grain,Time range - * @param {string} name name for filter - * @param {string} dataset which dataset should be used - * @param {string} filterColumn which column should be used - * @returns {None} - * @summary helper for filling value native filter form - ************************************************************************* */ -export function fillNativeFilterForm( - type: string, - name: string, - dataset?: string, - filterColumn?: string, -) { - cy.get(nativeFilters.filtersPanel.filterTypeInput) - .find(nativeFilters.filtersPanel.filterTypeItem) - .click({ multiple: true, force: true }); - cy.get(`[label="${type}"]`).click({ multiple: true, force: true }); - cy.get(nativeFilters.modal.container) - .find(nativeFilters.filtersPanel.filterName) - .last() - .click({ scrollBehavior: false }) - .clear() - .type(name, { scrollBehavior: false }); - if (dataset) { - cy.get(nativeFilters.modal.container) - .find(nativeFilters.filtersPanel.datasetName) - .last() - .click({ force: true, scrollBehavior: false }) - .type(`${dataset}`, { scrollBehavior: false }); - cy.get(nativeFilters.silentLoading).should('not.exist'); - cy.get(`[label="${dataset}"]`).click({ multiple: true, force: true }); - } - cy.get(nativeFilters.silentLoading).should('not.exist'); - if (filterColumn) { - cy.get(nativeFilters.filtersPanel.filterInfoInput) - .last() - .click({ force: true }); - cy.get(nativeFilters.filtersPanel.filterInfoInput) - .last() - .type(filterColumn); - cy.get(nativeFilters.filtersPanel.inputDropdown) - .should('be.visible', { timeout: 20000 }) - .last() - .click(); - } - cy.get(nativeFilters.silentLoading).should('not.exist'); -} - -/** ************************************************************************ - * Get native filter placeholder e.g 9 options - * @param {number} index which input it fills - * @returns cy object for assertions - * @summary helper for getting placeholder value - ************************************************************************* */ -export function getNativeFilterPlaceholderWithIndex(index: number) { - return cy.get(nativeFilters.filtersPanel.columnEmptyInput).eq(index); -} - -/** ************************************************************************ - * Apply native filter value from dashboard view - * @param {number} index which input it fills - * @param {string} value what is filter value - * @returns {null} - * @summary put value to nth native filter input in view - ************************************************************************* */ -export function applyNativeFilterValueWithIndex(index: number, value: string) { - cy.get(nativeFilters.filterFromDashboardView.filterValueInput) - .eq(index) - .parent() - .should('be.visible', { timeout: 10000 }) - .type(`${value}{enter}`); - // click the title to dismiss shown options - cy.get(nativeFilters.filterFromDashboardView.filterName).eq(index).click(); -} - -/** ************************************************************************ - * Fills parent filter input - * @param {number} index which input it fills - * @param {string} value on which filter it depends on - * @returns {null} - * @summary takes first or second input and modify the depends on filter value - ************************************************************************* */ -export function addParentFilterWithValue(index: number, value: string) { - return cy - .get(nativeFilters.filterConfigurationSections.displayedSection) - .within(() => { - cy.get('input[aria-label="Limit type"]') - .eq(index) - .click({ force: true }) - .type(`${value}{enter}`, { delay: 30, force: true }); - }); -} - -/** ************************************************************************ - * Save Native Filter Settings - * @returns {None} - * @summary helper for save native filters settings - ************************************************************************* */ -export function saveNativeFilterSettings() { - cy.get(nativeFilters.modal.footer) - .contains('Save') - .should('be.visible') - .click(); - cy.get(nativeFilters.modal.container).should('not.exist'); -} - -/** ************************************************************************ - * Cancel Native fitler settings - * @returns {None} - * @summary helper for cancel native filters settings - ************************************************************************* */ -export function cancelNativeFilterSettings() { - cy.get(nativeFilters.modal.footer) - .find(nativeFilters.modal.cancelButton) - .should('be.visible') - .click(); - cy.get(nativeFilters.modal.alertXUnsavedFilters) - .should('have.text', 'There are unsaved changes.') - .should('be.visible'); - cy.get(nativeFilters.modal.footer) - .find(nativeFilters.modal.yesCancelButton) - .contains('cancel') - .should('be.visible') - .click(); - cy.get(nativeFilters.modal.container).should('not.exist'); -} - -/** ************************************************************************ - * Close dashboard toast message - * @returns {None} - * @summary helper for close dashboard toast message in order to make test stable - ************************************************************************* */ -export function closeDashboardToastMessage() { - cy.get('body').then($body => { - if ($body.find(dashboardView.dashboardAlert.modal).length > 0) { - // evaluates as true if button exists at all - cy.get(dashboardView.dashboardAlert.modal).then($header => { - if ($header.is(':visible')) { - cy.get(dashboardView.dashboardAlert.closeButton).click({ - force: true, - }); - cy.get(dashboardView.dashboardAlert.closeButton).should('not.exist', { - timeout: 10000, - }); - } - }); - } - }); -} - -/** ************************************************************************ - * Validate filter name on dashboard - * @param name: filter name to validate - * @return {null} - * @summary helper for validate filter name on dashboard - ************************************************************************* */ -export function validateFilterNameOnDashboard(name: string) { - cy.get(nativeFilters.filterFromDashboardView.filterName) - .should('be.visible', { timeout: 40000 }) - .contains(`${name}`); -} - -/** ************************************************************************ - * Validate filter content on dashboard - * @param filterContent: filter content to validate - * @return {null} - * @summary helper for validate filter content on dashboard - ************************************************************************* */ -export function validateFilterContentOnDashboard(filterContent: string) { - cy.get(nativeFilters.filterFromDashboardView.filterContent) - .contains(`${filterContent}`) - .should('be.visible'); -} - -/** ************************************************************************ - * Delete Native filter - * @return {null} - * @summary helper for delete native filter - ************************************************************************* */ -export function deleteNativeFilter() { - cy.get(nativeFilters.filtersList.removeIcon).first().click(); -} - -/** ************************************************************************ - * Undo delete Native filter - * @return {null} - * @summary helper for undo delete native filter - ************************************************************************ */ -export function undoDeleteNativeFilter() { - deleteNativeFilter(); - cy.contains('Undo?').click(); -} - -/** ************************************************************************ - * Check Native Filter tooltip content - * @param index: tooltip indext to check - * @param value: tooltip value to check - * @return {null} - * @summary helper for checking native filter tooltip content by index - ************************************************************************* */ -export function checkNativeFilterTooltip(index: number, value: string) { - cy.get(nativeFilters.filterConfigurationSections.infoTooltip) - .eq(index) - .trigger('mouseover'); - cy.contains(`${value}`); -} - -/** ************************************************************************ - * Apply advanced time range filter on dashboard - * @param startRange: starting time range - * @param endRange: ending time range - * @return {null} - * @summary helper for applying advanced time range filter on dashboard with customize time range - ************************************************************************* */ -export function applyAdvancedTimeRangeFilterOnDashboard( - startRange?: string, - endRange?: string, -) { - cy.get('.control-label').contains('RANGE TYPE').should('be.visible'); - cy.get('.ant-popover-content .ant-select-selector') - .should('be.visible') - .click(); - cy.get(`[label="Advanced"]`).should('be.visible').click(); - cy.get('.section-title').contains('Advanced Time Range').should('be.visible'); - if (startRange) { - cy.get('.ant-popover-inner-content') - .find('[class^=ant-input]') - .first() - .type(`${startRange}`); - } - if (endRange) { - cy.get('.ant-popover-inner-content') - .find('[class^=ant-input]') - .last() - .type(`${endRange}`); - } - cy.get(dashboardView.timeRangeModal.applyButton).click(); - cy.get(nativeFilters.applyFilter).click(); -} - -/** ************************************************************************ - * Input default valule in Native filter in filter settings - * @param defaultValue: default value for native filter - * @return {null} - * @summary helper for input default valule in Native filter in filter settings - ************************************************************************* */ -export function inputNativeFilterDefaultValue(defaultValue: string) { - cy.contains('Filter has default value').click(); - cy.contains('Default value is required').should('be.visible'); - cy.get(nativeFilters.modal.container).within(() => { - cy.get(nativeFilters.filterConfigurationSections.filterPlaceholder) - .contains('options') - .should('be.visible'); - cy.get(nativeFilters.filterConfigurationSections.collapsedSectionContainer) - .first() - .get(nativeFilters.filtersPanel.columnEmptyInput) - .type(`${defaultValue}{enter}`); - }); -} - -/** ************************************************************************ - * add filter for test column 'Country name' - * @return {null} - * @summary helper for add filter for test column 'Country name' - ************************************************************************* */ -export function addCountryNameFilter() { - fillNativeFilterForm( - testItems.filterType.value, - testItems.topTenChart.filterColumn, - testItems.datasetForNativeFilter, - testItems.topTenChart.filterColumn, - ); -} - -/** ************************************************************************ - * add filter for test column 'Region' - * @return {null} - * @summary helper for add filter for test column 'Region' - ************************************************************************* */ -export function addRegionFilter() { - fillNativeFilterForm( - testItems.filterType.value, - testItems.topTenChart.filterColumnRegion, - testItems.datasetForNativeFilter, - testItems.topTenChart.filterColumnRegion, - ); -} - -/** ************************************************************************ - * add filter for test column 'Country Code' - * @return {null} - * @summary helper for add filter for test column 'Country Code' - ************************************************************************* */ -export function addCountryCodeFilter() { - fillNativeFilterForm( - testItems.filterType.value, - testItems.topTenChart.filterColumnCountryCode, - testItems.datasetForNativeFilter, - testItems.topTenChart.filterColumnCountryCode, - ); -} diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts index cde4f70613488..fb3fa145006e3 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts @@ -25,7 +25,6 @@ import { } from 'cypress/support/directories'; import { waitForChartLoad } from 'cypress/utils'; import { - WORLD_HEALTH_DASHBOARD, DASHBOARD_LIST, CHART_LIST, } from 'cypress/utils/urls'; @@ -54,24 +53,24 @@ import { validateFilterContentOnDashboard, valueNativeFilterOptions, validateFilterNameOnDashboard, -} from './nativeFilter.helper'; + testItems, +} from './utils'; import { WORLD_HEALTH_CHARTS } from './utils'; -import { cleanUp, copyTestDashboard, testItems } from './dashboard.helper'; // TODO: fix flaky init logic and re-enable const milliseconds = new Date().getTime(); const dashboard = `Test Dashboard${milliseconds}`; +function setup() { + cy.preserveLogin(); + cy.copyDashboard("World Bank's Data", "Cypress test Dashboard"); + WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); + closeDashboardToastMessage(); +} + describe('Nativefilters tests initial state required', () => { beforeEach(() => { - cy.login(); - cleanUp(); - copyTestDashboard("World Bank's Data"); - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); - closeDashboardToastMessage(); - }); - afterEach(() => { - cleanUp(); + setup(); }); it('Verify that default value is respected after revisit', () => { @@ -79,8 +78,7 @@ describe('Nativefilters tests initial state required', () => { enterNativeFilterEditModal(); addCountryNameFilter(); inputNativeFilterDefaultValue(testItems.filterDefaultValue); - saveNativeFilterSettings(); - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); + saveNativeFilterSettings(WORLD_HEALTH_CHARTS); cy.get(nativeFilters.filterItem) .contains(testItems.filterDefaultValue) .should('be.visible'); @@ -88,16 +86,9 @@ describe('Nativefilters tests initial state required', () => { cy.contains(testItems.filterDefaultValue).should('be.visible'); cy.contains(testItems.filterOtherCountry).should('not.exist'); }); - cy.request( - 'api/v1/dashboard/?q=(order_column:changed_on_delta_humanized,order_direction:desc,page:0,page_size:100)', - ).then(xhr => { - const dashboards = xhr.body.result; - const testDashboard = dashboards.find( - (d: { dashboard_title: string }) => - d.dashboard_title === testItems.dashboard, - ); - cy.visit(testDashboard.url); - }); + + // reload dashboard + cy.reload() WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { cy.contains(testItems.filterDefaultValue).should('be.visible'); @@ -122,9 +113,6 @@ describe('Nativefilters tests initial state required', () => { ); addParentFilterWithValue(0, testItems.topTenChart.filterColumnRegion); cy.wait(1000); - saveNativeFilterSettings(); - // Validate both filter in dashboard view. - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); [ testItems.topTenChart.filterColumnRegion, testItems.topTenChart.filterColumn, @@ -200,9 +188,7 @@ describe('Nativefilters tests initial state required', () => { addParentFilterWithValue(0, testItems.topTenChart.filterColumnRegion); // add value to the second input addParentFilterWithValue(1, testItems.topTenChart.filterColumn); - saveNativeFilterSettings(); - // wait for charts load - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); + saveNativeFilterSettings(WORLD_HEALTH_CHARTS); // filters should be displayed in the left panel [ testItems.topTenChart.filterColumnRegion, @@ -249,7 +235,7 @@ describe('Nativefilters tests initial state required', () => { .click(); }, ); - saveNativeFilterSettings(); + saveNativeFilterSettings(WORLD_HEALTH_CHARTS); enterNativeFilterEditModal(); cy.get(nativeFilters.modal.tabsList.removeTab) .should('be.visible') @@ -257,8 +243,7 @@ describe('Nativefilters tests initial state required', () => { .click({ force: true, }); - saveNativeFilterSettings(); - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); + saveNativeFilterSettings(WORLD_HEALTH_CHARTS); cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { cy.contains(testItems.filterDefaultValue).should('be.visible'); cy.contains(testItems.filterOtherCountry).should('be.visible'); @@ -268,13 +253,7 @@ describe('Nativefilters tests initial state required', () => { describe('Nativefilters initial state not required', () => { beforeEach(() => { - cy.login(); - cy.visit(WORLD_HEALTH_DASHBOARD); - }); - - after(() => { - enterNativeFilterEditModal(); - deleteNativeFilter(); + setup(); }); it('User can expand / retract native filter sidebar on a dashboard', () => { @@ -297,7 +276,7 @@ describe('Nativefilters initial state not required', () => { enterNativeFilterEditModal(); cy.get(nativeFilters.filtersList.removeIcon).first().click(); cy.contains('Restore Filter').should('not.exist', { timeout: 10000 }); - saveNativeFilterSettings(); + saveNativeFilterSettings(WORLD_HEALTH_CHARTS); }); it('User can cancel creating a new filter', () => { @@ -335,7 +314,6 @@ describe('Nativefilters initial state not required', () => { let filterKey: string; const removeFirstChar = (search: string) => search.split('').slice(1, search.length).join(''); - cy.wait(3000); cy.location().then(loc => { const queryParams = qs.parse(removeFirstChar(loc.search)); filterKey = queryParams.native_filters_key as string; @@ -343,8 +321,7 @@ describe('Nativefilters initial state not required', () => { }); enterNativeFilterEditModal(); addCountryNameFilter(); - saveNativeFilterSettings(); - cy.wait(3000); + saveNativeFilterSettings(WORLD_HEALTH_CHARTS); cy.location().then(loc => { const queryParams = qs.parse(removeFirstChar(loc.search)); const newfilterKey = queryParams.native_filters_key; @@ -357,8 +334,7 @@ describe('Nativefilters initial state not required', () => { it('User can undo deleting a native filter', () => { enterNativeFilterEditModal(); addCountryCodeFilter(); - saveNativeFilterSettings(); - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); + saveNativeFilterSettings(WORLD_HEALTH_CHARTS); validateFilterNameOnDashboard( testItems.topTenChart.filterColumnCountryCode, ); @@ -381,7 +357,7 @@ describe('Nativefilters initial state not required', () => { testItems.filterType.timeGrain, testItems.datasetForNativeFilter, ); - saveNativeFilterSettings(); + saveNativeFilterSettings(WORLD_HEALTH_CHARTS); applyNativeFilterValueWithIndex(0, testItems.filterTimeGrain); cy.get(nativeFilters.applyFilter).click(); cy.url().then(u => { @@ -392,13 +368,13 @@ describe('Nativefilters initial state not required', () => { validateFilterContentOnDashboard(testItems.filterTimeGrain); }); - xit('User can create a time range filter', () => { + it.skip('User can create a time range filter', () => { enterNativeFilterEditModal(); fillNativeFilterForm( testItems.filterType.timeRange, testItems.filterType.timeRange, ); - saveNativeFilterSettings(); + saveNativeFilterSettings(WORLD_HEALTH_CHARTS); cy.get(dashboardView.salesDashboardSpecific.vehicleSalesFilterTimeRange) .should('be.visible') .click(); @@ -413,14 +389,14 @@ describe('Nativefilters initial state not required', () => { .should('be.visible'); }); - xit('User can create a time column filter', () => { + it.skip('User can create a time column filter', () => { enterNativeFilterEditModal(); fillNativeFilterForm( testItems.filterType.timeColumn, testItems.filterType.timeColumn, testItems.datasetForNativeFilter, ); - saveNativeFilterSettings(); + saveNativeFilterSettings(WORLD_HEALTH_CHARTS); cy.intercept(`/api/v1/chart/data?form_data=**`).as('chart'); cy.get(nativeFilters.modal.container).should('not.exist'); // assert that native filter is created @@ -439,7 +415,7 @@ describe('Nativefilters initial state not required', () => { testItems.datasetForNativeFilter, testItems.filterNumericalColumn, ); - saveNativeFilterSettings(); + saveNativeFilterSettings(WORLD_HEALTH_CHARTS); // assertions cy.get(nativeFilters.slider.slider).should('be.visible').click('center'); // cy.get(sqlLabView.tooltip).should('be.visible'); @@ -466,8 +442,7 @@ describe('Nativefilters initial state not required', () => { it('User can undo deleting a native filter', () => { enterNativeFilterEditModal(); addCountryNameFilter(); - saveNativeFilterSettings(); - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); + saveNativeFilterSettings(WORLD_HEALTH_CHARTS); validateFilterNameOnDashboard(testItems.topTenChart.filterColumn); enterNativeFilterEditModal(); undoDeleteNativeFilter(); @@ -484,7 +459,7 @@ describe('Nativefilters initial state not required', () => { enterNativeFilterEditModal(); cy.get(nativeFilters.filtersList.removeIcon).first().click(); cy.contains('You have removed this filter.').should('be.visible'); - saveNativeFilterSettings(); + saveNativeFilterSettings(WORLD_HEALTH_CHARTS); }); it('User can create a value filter', () => { @@ -493,15 +468,14 @@ describe('Nativefilters initial state not required', () => { cy.get(nativeFilters.filtersPanel.filterTypeInput) .find(nativeFilters.filtersPanel.filterTypeItem) .should('have.text', testItems.filterType.value); - saveNativeFilterSettings(); + saveNativeFilterSettings(WORLD_HEALTH_CHARTS); validateFilterNameOnDashboard(testItems.topTenChart.filterColumn); }); it('User can apply value filter with selected values', () => { enterNativeFilterEditModal(); addCountryNameFilter(); - saveNativeFilterSettings(); - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); + saveNativeFilterSettings(WORLD_HEALTH_CHARTS); applyNativeFilterValueWithIndex(0, testItems.filterDefaultValue); cy.get(nativeFilters.applyFilter).click(); cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { @@ -514,8 +488,7 @@ describe('Nativefilters initial state not required', () => { enterNativeFilterEditModal(); addCountryNameFilter(); inputNativeFilterDefaultValue(testItems.filterDefaultValue); - saveNativeFilterSettings(); - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); + saveNativeFilterSettings(WORLD_HEALTH_CHARTS); cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { cy.contains(testItems.filterDefaultValue).should('be.visible'); cy.contains(testItems.filterOtherCountry).should('not.exist'); @@ -526,8 +499,7 @@ describe('Nativefilters initial state not required', () => { validateFilterNameOnDashboard(testItems.topTenChart.filterColumn); enterNativeFilterEditModal(); deleteNativeFilter(); - saveNativeFilterSettings(); - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); + saveNativeFilterSettings(WORLD_HEALTH_CHARTS); cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { cy.contains(testItems.filterDefaultValue).should('be.visible'); cy.contains(testItems.filterOtherCountry).should('be.visible'); @@ -535,7 +507,7 @@ describe('Nativefilters initial state not required', () => { }); }); -xdescribe('Nativefilters', () => { +describe.skip('Nativefilters', () => { before(() => { cy.login(); cy.visit(DASHBOARD_LIST); @@ -612,7 +584,7 @@ xdescribe('Nativefilters', () => { cy.contains('USA').should('not.exist'); }); }); - xit('default value is respected after revisit', () => { + it('default value is respected after revisit', () => { cy.get('[data-test="filter-bar__create-filter"]').click(); cy.get('.ant-modal').should('be.visible'); // TODO: replace with proper wait for filter to finish loading @@ -744,7 +716,7 @@ xdescribe('Nativefilters', () => { .click(); cy.get('[data-test="filter-icon"]').should('be.visible'); }); - xit('should parent filter be working', () => { + it('should parent filter be working', () => { cy.get('.treemap').within(() => { cy.contains('SMR').should('be.visible'); cy.contains('Europe & Central Asia').should('be.visible'); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts index 19335ed3debe4..b46d0c991aa2d 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts @@ -17,6 +17,9 @@ * under the License. */ + import { dashboardView, nativeFilters } from 'cypress/support/directories'; +import { waitForChartLoad } from 'cypress/utils'; + export const WORLD_HEALTH_CHARTS = [ { name: '% Rural', viz: 'world_map' }, { name: 'Most Populated Countries', viz: 'table' }, @@ -38,6 +41,73 @@ export const ECHARTS_CHARTS = [ { name: 'Energy Force Layout', viz: 'graph_chart' }, ] as const; +export const testItems = { + dashboard: 'Cypress test Dashboard', + dataset: 'Vehicle Sales', + datasetForNativeFilter: 'wb_health_population', + chart: 'Cypress chart', + newChart: 'New Cypress Chart', + createdDashboard: 'New Dashboard', + defaultNameDashboard: '[ untitled dashboard ]', + newDashboardTitle: `Test dashboard [NEW TEST]`, + bulkFirstNameDashboard: 'First Dash', + bulkSecondNameDashboard: 'Second Dash', + worldBanksDataCopy: `World Bank's Data [copy]`, + filterType: { + value: 'Value', + numerical: 'Numerical range', + timeColumn: 'Time column', + timeGrain: 'Time grain', + timeRange: 'Time range', + }, + topTenChart: { + name: 'Most Populated Countries', + filterColumn: 'country_name', + filterColumnYear: 'year', + filterColumnRegion: 'region', + filterColumnCountryCode: 'country_code', + }, + filterDefaultValue: 'United States', + filterOtherCountry: 'China', + filterTimeGrain: 'Month', + filterTimeColumn: 'created', + filterNumericalColumn: 'SP_RUR_TOTL_ZS', + }; + + export const nativeFilterTooltips = { + searchAllFilterOptions: + 'By default, each filter loads at most 1000 choices at the initial page load. Check this box if you have more than 1000 filter values and want to enable dynamically searching that loads filter values as users type (may add stress to your database).', + defaultToFirstItem: 'When using this option, default value can’t be set', + inverseSelection: 'Exclude selected values', + required: 'User must select a value before applying the filter', + multipleSelect: 'Allow selecting multiple values', + defaultValue: + 'Default value must be set when "Filter value is required" is checked', + }; + + export const nativeFilterOptions = [ + 'Filter has default value', + 'Multiple select', + 'Filter value is required', + 'Filter is hierarchical', + 'Default to first item', + 'Inverse selection', + 'Search all filter options', + 'Pre-filter available values', + 'Sort filter values', + ]; + + export const valueNativeFilterOptions = [ + 'Pre-filter available values', + 'Sort filter values', + 'Filter has default value', + 'Select first filter value by default', + 'Can select multiple values', + 'Dynamically search all filter values', + 'Inverse selection', + 'Filter value is required', + ]; + export function interceptGet() { cy.intercept('/api/v1/dashboard/*').as('get'); } @@ -82,3 +152,364 @@ export function setFilter(filter: string, option: string) { cy.wait('@filtering'); } + + +/** ************************************************************************ + * Expend Native filter from the left panel on dashboard + * @returns {None} + * @summary helper for expend native filter + ************************************************************************* */ + export function expandFilterOnLeftPanel() { + return cy + .get(nativeFilters.filterFromDashboardView.expand) + .should('be.visible') + .click({ force: true }); + } + + /** ************************************************************************ + * Collapes Native Filter from the left panel on dashboard + * @returns {None} + * @summary helper for collape native filter + ************************************************************************* */ + export function collapseFilterOnLeftPanel() { + cy.get(nativeFilters.filterFromDashboardView.collapse) + .should('be.visible') + .click(); + cy.get(nativeFilters.filterFromDashboardView.collapse).should( + 'not.be.visible', + ); + } + + /** ************************************************************************ + * Enter Native Filter edit modal from the left panel on dashboard + * @returns {None} + * @summary helper for enter native filter edit modal + ************************************************************************* */ + export function enterNativeFilterEditModal() { + cy.get(nativeFilters.filterFromDashboardView.createFilterButton).click({ + force: true, + }); + cy.get(nativeFilters.modal.container).should('be.visible'); + } + + /** ************************************************************************ + * Clicks on new filter button + * @returns {None} + * @summary helper for adding new filter + ************************************************************************* */ + export function clickOnAddFilterInModal() { + return cy + .get(nativeFilters.addFilterButton.button) + .first() + .click() + .then(() => { + cy.get(nativeFilters.addFilterButton.dropdownItem) + .contains('Filter') + .click({ force: true }); + }); + } + + /** ************************************************************************ + * Fills value native filter form with basic information + * @param {string} type type for filter: Value, Numerical range,Time column,Time grain,Time range + * @param {string} name name for filter + * @param {string} dataset which dataset should be used + * @param {string} filterColumn which column should be used + * @returns {None} + * @summary helper for filling value native filter form + ************************************************************************* */ + export function fillNativeFilterForm( + type: string, + name: string, + dataset?: string, + filterColumn?: string, + ) { + cy.get(nativeFilters.filtersPanel.filterTypeInput) + .find(nativeFilters.filtersPanel.filterTypeItem) + .click({ multiple: true, force: true }); + cy.get(`[label="${type}"]`).click({ multiple: true, force: true }); + cy.get(nativeFilters.modal.container) + .find(nativeFilters.filtersPanel.filterName) + .last() + .click({ scrollBehavior: false }) + .clear() + .type(name, { scrollBehavior: false }); + if (dataset) { + cy.get(nativeFilters.modal.container) + .find(nativeFilters.filtersPanel.datasetName) + .last() + .click({ force: true, scrollBehavior: false }) + .type(`${dataset}`, { scrollBehavior: false }); + cy.get(nativeFilters.silentLoading).should('not.exist'); + cy.get(`[label="${dataset}"]`).click({ multiple: true, force: true }); + } + cy.get(nativeFilters.silentLoading).should('not.exist'); + if (filterColumn) { + cy.get(nativeFilters.filtersPanel.filterInfoInput) + .last() + .click({ force: true }); + cy.get(nativeFilters.filtersPanel.filterInfoInput) + .last() + .type(filterColumn); + cy.get(nativeFilters.filtersPanel.inputDropdown) + .should('be.visible', { timeout: 20000 }) + .last() + .click(); + } + cy.get(nativeFilters.silentLoading).should('not.exist'); + } + + /** ************************************************************************ + * Get native filter placeholder e.g 9 options + * @param {number} index which input it fills + * @returns cy object for assertions + * @summary helper for getting placeholder value + ************************************************************************* */ + export function getNativeFilterPlaceholderWithIndex(index: number) { + return cy.get(nativeFilters.filtersPanel.columnEmptyInput).eq(index); + } + + /** ************************************************************************ + * Apply native filter value from dashboard view + * @param {number} index which input it fills + * @param {string} value what is filter value + * @returns {null} + * @summary put value to nth native filter input in view + ************************************************************************* */ + export function applyNativeFilterValueWithIndex(index: number, value: string) { + cy.get(nativeFilters.filterFromDashboardView.filterValueInput) + .eq(index) + .parent() + .should('be.visible', { timeout: 10000 }) + .type(`${value}{enter}`); + // click the title to dismiss shown options + cy.get(nativeFilters.filterFromDashboardView.filterName).eq(index).click(); + } + + /** ************************************************************************ + * Fills parent filter input + * @param {number} index which input it fills + * @param {string} value on which filter it depends on + * @returns {null} + * @summary takes first or second input and modify the depends on filter value + ************************************************************************* */ + export function addParentFilterWithValue(index: number, value: string) { + return cy + .get(nativeFilters.filterConfigurationSections.displayedSection) + .within(() => { + cy.get('input[aria-label="Limit type"]') + .eq(index) + .click({ force: true }) + .type(`${value}{enter}`, { delay: 30, force: true }); + }); + } + + /** ************************************************************************ + * Save Native Filter Settings + * @returns {None} + * @summary helper for save native filters settings + ************************************************************************* */ + export function saveNativeFilterSettings(charts: any) { + cy.get(nativeFilters.modal.footer) + .contains('Save') + .should('be.visible') + .click(); + cy.get(nativeFilters.modal.container).should('not.exist'); + charts.forEach(waitForChartLoad); + } + + /** ************************************************************************ + * Cancel Native fitler settings + * @returns {None} + * @summary helper for cancel native filters settings + ************************************************************************* */ + export function cancelNativeFilterSettings() { + cy.get(nativeFilters.modal.footer) + .find(nativeFilters.modal.cancelButton) + .should('be.visible') + .click(); + cy.get(nativeFilters.modal.alertXUnsavedFilters) + .should('have.text', 'There are unsaved changes.') + .should('be.visible'); + cy.get(nativeFilters.modal.footer) + .find(nativeFilters.modal.yesCancelButton) + .contains('cancel') + .should('be.visible') + .click(); + cy.get(nativeFilters.modal.container).should('not.exist'); + } + + /** ************************************************************************ + * Close dashboard toast message + * @returns {None} + * @summary helper for close dashboard toast message in order to make test stable + ************************************************************************* */ + export function closeDashboardToastMessage() { + cy.get('body').then($body => { + if ($body.find(dashboardView.dashboardAlert.modal).length > 0) { + // evaluates as true if button exists at all + cy.get(dashboardView.dashboardAlert.modal).then($header => { + if ($header.is(':visible')) { + cy.get(dashboardView.dashboardAlert.closeButton).click({ + force: true, + }); + cy.get(dashboardView.dashboardAlert.closeButton).should('not.exist', { + timeout: 10000, + }); + } + }); + } + }); + } + + /** ************************************************************************ + * Validate filter name on dashboard + * @param name: filter name to validate + * @return {null} + * @summary helper for validate filter name on dashboard + ************************************************************************* */ + export function validateFilterNameOnDashboard(name: string) { + cy.get(nativeFilters.filterFromDashboardView.filterName) + .should('be.visible', { timeout: 40000 }) + .contains(`${name}`); + } + + /** ************************************************************************ + * Validate filter content on dashboard + * @param filterContent: filter content to validate + * @return {null} + * @summary helper for validate filter content on dashboard + ************************************************************************* */ + export function validateFilterContentOnDashboard(filterContent: string) { + cy.get(nativeFilters.filterFromDashboardView.filterContent) + .contains(`${filterContent}`) + .should('be.visible'); + } + + /** ************************************************************************ + * Delete Native filter + * @return {null} + * @summary helper for delete native filter + ************************************************************************* */ + export function deleteNativeFilter() { + cy.get(nativeFilters.filtersList.removeIcon).first().click(); + } + + /** ************************************************************************ + * Undo delete Native filter + * @return {null} + * @summary helper for undo delete native filter + ************************************************************************ */ + export function undoDeleteNativeFilter() { + deleteNativeFilter(); + cy.contains('Undo?').click(); + } + + /** ************************************************************************ + * Check Native Filter tooltip content + * @param index: tooltip indext to check + * @param value: tooltip value to check + * @return {null} + * @summary helper for checking native filter tooltip content by index + ************************************************************************* */ + export function checkNativeFilterTooltip(index: number, value: string) { + cy.get(nativeFilters.filterConfigurationSections.infoTooltip) + .eq(index) + .trigger('mouseover'); + cy.contains(`${value}`); + } + + /** ************************************************************************ + * Apply advanced time range filter on dashboard + * @param startRange: starting time range + * @param endRange: ending time range + * @return {null} + * @summary helper for applying advanced time range filter on dashboard with customize time range + ************************************************************************* */ + export function applyAdvancedTimeRangeFilterOnDashboard( + startRange?: string, + endRange?: string, + ) { + cy.get('.control-label').contains('RANGE TYPE').should('be.visible'); + cy.get('.ant-popover-content .ant-select-selector') + .should('be.visible') + .click(); + cy.get(`[label="Advanced"]`).should('be.visible').click(); + cy.get('.section-title').contains('Advanced Time Range').should('be.visible'); + if (startRange) { + cy.get('.ant-popover-inner-content') + .find('[class^=ant-input]') + .first() + .type(`${startRange}`); + } + if (endRange) { + cy.get('.ant-popover-inner-content') + .find('[class^=ant-input]') + .last() + .type(`${endRange}`); + } + cy.get(dashboardView.timeRangeModal.applyButton).click(); + cy.get(nativeFilters.applyFilter).click(); + } + + /** ************************************************************************ + * Input default valule in Native filter in filter settings + * @param defaultValue: default value for native filter + * @return {null} + * @summary helper for input default valule in Native filter in filter settings + ************************************************************************* */ + export function inputNativeFilterDefaultValue(defaultValue: string) { + cy.contains('Filter has default value').click(); + cy.contains('Default value is required').should('be.visible'); + cy.get(nativeFilters.modal.container).within(() => { + cy.get(nativeFilters.filterConfigurationSections.filterPlaceholder) + .contains('options') + .should('be.visible'); + cy.get(nativeFilters.filterConfigurationSections.collapsedSectionContainer) + .first() + .get(nativeFilters.filtersPanel.columnEmptyInput) + .type(`${defaultValue}{enter}`); + }); + } + + /** ************************************************************************ + * add filter for test column 'Country name' + * @return {null} + * @summary helper for add filter for test column 'Country name' + ************************************************************************* */ + export function addCountryNameFilter() { + fillNativeFilterForm( + testItems.filterType.value, + testItems.topTenChart.filterColumn, + testItems.datasetForNativeFilter, + testItems.topTenChart.filterColumn, + ); + } + + /** ************************************************************************ + * add filter for test column 'Region' + * @return {null} + * @summary helper for add filter for test column 'Region' + ************************************************************************* */ + export function addRegionFilter() { + fillNativeFilterForm( + testItems.filterType.value, + testItems.topTenChart.filterColumnRegion, + testItems.datasetForNativeFilter, + testItems.topTenChart.filterColumnRegion, + ); + } + + /** ************************************************************************ + * add filter for test column 'Country Code' + * @return {null} + * @summary helper for add filter for test column 'Country Code' + ************************************************************************* */ + export function addCountryCodeFilter() { + fillNativeFilterForm( + testItems.filterType.value, + testItems.topTenChart.filterColumnCountryCode, + testItems.datasetForNativeFilter, + testItems.topTenChart.filterColumnCountryCode, + ); + } diff --git a/superset-frontend/cypress-base/cypress/support/index.d.ts b/superset-frontend/cypress-base/cypress/support/index.d.ts index b884c1c430bb5..69eff5913abab 100644 --- a/superset-frontend/cypress-base/cypress/support/index.d.ts +++ b/superset-frontend/cypress-base/cypress/support/index.d.ts @@ -72,6 +72,7 @@ declare namespace Cypress { */ createSampleDashboards(): void; createSampleCharts(): void; + copyDashboard(originalDashboardName: string, copyDashboardName: string): void; /** * Delete diff --git a/superset-frontend/cypress-base/cypress/support/index.ts b/superset-frontend/cypress-base/cypress/support/index.ts index 8ddb1d082a4cf..0dd0c6004bac2 100644 --- a/superset-frontend/cypress-base/cypress/support/index.ts +++ b/superset-frontend/cypress-base/cypress/support/index.ts @@ -283,7 +283,7 @@ Cypress.Commands.add('createSampleCharts', () => Cypress.Commands.add( 'deleteDashboardByName', - (dashboardName: string, failOnStatusCode: boolean) => + (dashboardName: string, failOnStatusCode = false) => cy.getDashboards().then((sampleDashboards: any) => { const dashboard = sampleDashboards.find( (d: any) => d.dashboard_title === dashboardName, @@ -328,6 +328,38 @@ Cypress.Commands.add('getDashboards', () => .then(resp => resp.body.result), ); +Cypress.Commands.add('copyDashboard', (originalDashboardName, copyDashboardName) => +cy.getDashboards().then((sampleDashboards: any) => { + cy.deleteDashboardByName(copyDashboardName, false).then(() => { + const dashboard = sampleDashboards.find((d: any) => d.dashboard_title === originalDashboardName); + const slugifiedTitle = copyDashboardName.toLowerCase().replace(/ /g, '-'); + const body = new FormData(); + body.append("data", JSON.stringify({ + "dashboard_title": copyDashboardName, + "slug": slugifiedTitle, + "duplicate_slices": false, + })); + if (dashboard) { + cy + .request({ + method: 'POST', + url: `superset/copy_dash/${dashboard.id}/`, + body, + headers: { + 'content-type': 'multipart/form-data', + Authorization: `Bearer ${TokenName}`, + }, + }) + .then(() => + cy.getDashboards().then((sampleDashboards: any) => { + const newDashboard = sampleDashboards.find((d: any) => d.dashboard_title === copyDashboardName); + cy.visit(`/superset/dashboard/${newDashboard.id}/`) + }) + ) + } + }) +})); + Cypress.Commands.add('deleteChart', (id: number, failOnStatusCode = false) => cy .request({ @@ -362,7 +394,7 @@ Cypress.Commands.add('getCharts', () => Cypress.Commands.add( 'deleteChartByName', - (sliceName: string, failOnStatusCode: boolean) => + (sliceName: string, failOnStatusCode = false) => cy.getCharts().then((sampleCharts: any) => { const chart = sampleCharts.find((c: any) => c.slice_name === sliceName); if (chart) { From b50c50873d20eb6c1f7660f8ba494d97380b72fc Mon Sep 17 00:00:00 2001 From: geido Date: Wed, 7 Sep 2022 17:14:50 +0300 Subject: [PATCH 19/31] Improve database tests --- .../dashboard/nativeFilters.test.ts | 13 +- .../cypress/integration/dashboard/utils.ts | 791 +++++++++--------- .../cypress/integration/database/helper.ts | 19 - .../integration/database/modal.test.ts | 27 +- .../cypress-base/cypress/support/index.d.ts | 5 +- .../cypress-base/cypress/support/index.ts | 72 +- .../cypress-base/cypress/utils/urls.ts | 1 + 7 files changed, 465 insertions(+), 463 deletions(-) delete mode 100644 superset-frontend/cypress-base/cypress/integration/database/helper.ts diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts index fb3fa145006e3..d9bd36025caf7 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts @@ -24,10 +24,7 @@ import { dataTestChartName, } from 'cypress/support/directories'; import { waitForChartLoad } from 'cypress/utils'; -import { - DASHBOARD_LIST, - CHART_LIST, -} from 'cypress/utils/urls'; +import { DASHBOARD_LIST, CHART_LIST } from 'cypress/utils/urls'; import { addCountryCodeFilter, @@ -54,8 +51,8 @@ import { valueNativeFilterOptions, validateFilterNameOnDashboard, testItems, + WORLD_HEALTH_CHARTS, } from './utils'; -import { WORLD_HEALTH_CHARTS } from './utils'; // TODO: fix flaky init logic and re-enable const milliseconds = new Date().getTime(); @@ -63,7 +60,7 @@ const dashboard = `Test Dashboard${milliseconds}`; function setup() { cy.preserveLogin(); - cy.copyDashboard("World Bank's Data", "Cypress test Dashboard"); + cy.copyDashboard("World Bank's Data", 'Cypress test Dashboard'); WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); closeDashboardToastMessage(); } @@ -88,7 +85,7 @@ describe('Nativefilters tests initial state required', () => { }); // reload dashboard - cy.reload() + cy.reload(); WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { cy.contains(testItems.filterDefaultValue).should('be.visible'); @@ -112,7 +109,7 @@ describe('Nativefilters tests initial state required', () => { }, ); addParentFilterWithValue(0, testItems.topTenChart.filterColumnRegion); - cy.wait(1000); + saveNativeFilterSettings(WORLD_HEALTH_CHARTS); [ testItems.topTenChart.filterColumnRegion, testItems.topTenChart.filterColumn, diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts index b46d0c991aa2d..9c3ce8be0296c 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts @@ -17,7 +17,7 @@ * under the License. */ - import { dashboardView, nativeFilters } from 'cypress/support/directories'; +import { dashboardView, nativeFilters } from 'cypress/support/directories'; import { waitForChartLoad } from 'cypress/utils'; export const WORLD_HEALTH_CHARTS = [ @@ -42,71 +42,71 @@ export const ECHARTS_CHARTS = [ ] as const; export const testItems = { - dashboard: 'Cypress test Dashboard', - dataset: 'Vehicle Sales', - datasetForNativeFilter: 'wb_health_population', - chart: 'Cypress chart', - newChart: 'New Cypress Chart', - createdDashboard: 'New Dashboard', - defaultNameDashboard: '[ untitled dashboard ]', - newDashboardTitle: `Test dashboard [NEW TEST]`, - bulkFirstNameDashboard: 'First Dash', - bulkSecondNameDashboard: 'Second Dash', - worldBanksDataCopy: `World Bank's Data [copy]`, - filterType: { - value: 'Value', - numerical: 'Numerical range', - timeColumn: 'Time column', - timeGrain: 'Time grain', - timeRange: 'Time range', - }, - topTenChart: { - name: 'Most Populated Countries', - filterColumn: 'country_name', - filterColumnYear: 'year', - filterColumnRegion: 'region', - filterColumnCountryCode: 'country_code', - }, - filterDefaultValue: 'United States', - filterOtherCountry: 'China', - filterTimeGrain: 'Month', - filterTimeColumn: 'created', - filterNumericalColumn: 'SP_RUR_TOTL_ZS', - }; - - export const nativeFilterTooltips = { - searchAllFilterOptions: - 'By default, each filter loads at most 1000 choices at the initial page load. Check this box if you have more than 1000 filter values and want to enable dynamically searching that loads filter values as users type (may add stress to your database).', - defaultToFirstItem: 'When using this option, default value can’t be set', - inverseSelection: 'Exclude selected values', - required: 'User must select a value before applying the filter', - multipleSelect: 'Allow selecting multiple values', - defaultValue: - 'Default value must be set when "Filter value is required" is checked', - }; - - export const nativeFilterOptions = [ - 'Filter has default value', - 'Multiple select', - 'Filter value is required', - 'Filter is hierarchical', - 'Default to first item', - 'Inverse selection', - 'Search all filter options', - 'Pre-filter available values', - 'Sort filter values', - ]; - - export const valueNativeFilterOptions = [ - 'Pre-filter available values', - 'Sort filter values', - 'Filter has default value', - 'Select first filter value by default', - 'Can select multiple values', - 'Dynamically search all filter values', - 'Inverse selection', - 'Filter value is required', - ]; + dashboard: 'Cypress test Dashboard', + dataset: 'Vehicle Sales', + datasetForNativeFilter: 'wb_health_population', + chart: 'Cypress chart', + newChart: 'New Cypress Chart', + createdDashboard: 'New Dashboard', + defaultNameDashboard: '[ untitled dashboard ]', + newDashboardTitle: `Test dashboard [NEW TEST]`, + bulkFirstNameDashboard: 'First Dash', + bulkSecondNameDashboard: 'Second Dash', + worldBanksDataCopy: `World Bank's Data [copy]`, + filterType: { + value: 'Value', + numerical: 'Numerical range', + timeColumn: 'Time column', + timeGrain: 'Time grain', + timeRange: 'Time range', + }, + topTenChart: { + name: 'Most Populated Countries', + filterColumn: 'country_name', + filterColumnYear: 'year', + filterColumnRegion: 'region', + filterColumnCountryCode: 'country_code', + }, + filterDefaultValue: 'United States', + filterOtherCountry: 'China', + filterTimeGrain: 'Month', + filterTimeColumn: 'created', + filterNumericalColumn: 'SP_RUR_TOTL_ZS', +}; + +export const nativeFilterTooltips = { + searchAllFilterOptions: + 'By default, each filter loads at most 1000 choices at the initial page load. Check this box if you have more than 1000 filter values and want to enable dynamically searching that loads filter values as users type (may add stress to your database).', + defaultToFirstItem: 'When using this option, default value can’t be set', + inverseSelection: 'Exclude selected values', + required: 'User must select a value before applying the filter', + multipleSelect: 'Allow selecting multiple values', + defaultValue: + 'Default value must be set when "Filter value is required" is checked', +}; + +export const nativeFilterOptions = [ + 'Filter has default value', + 'Multiple select', + 'Filter value is required', + 'Filter is hierarchical', + 'Default to first item', + 'Inverse selection', + 'Search all filter options', + 'Pre-filter available values', + 'Sort filter values', +]; + +export const valueNativeFilterOptions = [ + 'Pre-filter available values', + 'Sort filter values', + 'Filter has default value', + 'Select first filter value by default', + 'Can select multiple values', + 'Dynamically search all filter values', + 'Inverse selection', + 'Filter value is required', +]; export function interceptGet() { cy.intercept('/api/v1/dashboard/*').as('get'); @@ -153,363 +153,362 @@ export function setFilter(filter: string, option: string) { cy.wait('@filtering'); } - /** ************************************************************************ * Expend Native filter from the left panel on dashboard * @returns {None} * @summary helper for expend native filter ************************************************************************* */ - export function expandFilterOnLeftPanel() { - return cy - .get(nativeFilters.filterFromDashboardView.expand) - .should('be.visible') - .click({ force: true }); - } +export function expandFilterOnLeftPanel() { + return cy + .get(nativeFilters.filterFromDashboardView.expand) + .should('be.visible') + .click({ force: true }); +} - /** ************************************************************************ - * Collapes Native Filter from the left panel on dashboard - * @returns {None} - * @summary helper for collape native filter - ************************************************************************* */ - export function collapseFilterOnLeftPanel() { - cy.get(nativeFilters.filterFromDashboardView.collapse) - .should('be.visible') - .click(); - cy.get(nativeFilters.filterFromDashboardView.collapse).should( - 'not.be.visible', - ); - } +/** ************************************************************************ + * Collapes Native Filter from the left panel on dashboard + * @returns {None} + * @summary helper for collape native filter + ************************************************************************* */ +export function collapseFilterOnLeftPanel() { + cy.get(nativeFilters.filterFromDashboardView.collapse) + .should('be.visible') + .click(); + cy.get(nativeFilters.filterFromDashboardView.collapse).should( + 'not.be.visible', + ); +} - /** ************************************************************************ - * Enter Native Filter edit modal from the left panel on dashboard - * @returns {None} - * @summary helper for enter native filter edit modal - ************************************************************************* */ - export function enterNativeFilterEditModal() { - cy.get(nativeFilters.filterFromDashboardView.createFilterButton).click({ - force: true, - }); - cy.get(nativeFilters.modal.container).should('be.visible'); - } +/** ************************************************************************ + * Enter Native Filter edit modal from the left panel on dashboard + * @returns {None} + * @summary helper for enter native filter edit modal + ************************************************************************* */ +export function enterNativeFilterEditModal() { + cy.get(nativeFilters.filterFromDashboardView.createFilterButton).click({ + force: true, + }); + cy.get(nativeFilters.modal.container).should('be.visible'); +} - /** ************************************************************************ - * Clicks on new filter button - * @returns {None} - * @summary helper for adding new filter - ************************************************************************* */ - export function clickOnAddFilterInModal() { - return cy - .get(nativeFilters.addFilterButton.button) - .first() - .click() - .then(() => { - cy.get(nativeFilters.addFilterButton.dropdownItem) - .contains('Filter') - .click({ force: true }); - }); - } +/** ************************************************************************ + * Clicks on new filter button + * @returns {None} + * @summary helper for adding new filter + ************************************************************************* */ +export function clickOnAddFilterInModal() { + return cy + .get(nativeFilters.addFilterButton.button) + .first() + .click() + .then(() => { + cy.get(nativeFilters.addFilterButton.dropdownItem) + .contains('Filter') + .click({ force: true }); + }); +} - /** ************************************************************************ - * Fills value native filter form with basic information - * @param {string} type type for filter: Value, Numerical range,Time column,Time grain,Time range - * @param {string} name name for filter - * @param {string} dataset which dataset should be used - * @param {string} filterColumn which column should be used - * @returns {None} - * @summary helper for filling value native filter form - ************************************************************************* */ - export function fillNativeFilterForm( - type: string, - name: string, - dataset?: string, - filterColumn?: string, - ) { - cy.get(nativeFilters.filtersPanel.filterTypeInput) - .find(nativeFilters.filtersPanel.filterTypeItem) - .click({ multiple: true, force: true }); - cy.get(`[label="${type}"]`).click({ multiple: true, force: true }); +/** ************************************************************************ + * Fills value native filter form with basic information + * @param {string} type type for filter: Value, Numerical range,Time column,Time grain,Time range + * @param {string} name name for filter + * @param {string} dataset which dataset should be used + * @param {string} filterColumn which column should be used + * @returns {None} + * @summary helper for filling value native filter form + ************************************************************************* */ +export function fillNativeFilterForm( + type: string, + name: string, + dataset?: string, + filterColumn?: string, +) { + cy.get(nativeFilters.filtersPanel.filterTypeInput) + .find(nativeFilters.filtersPanel.filterTypeItem) + .click({ multiple: true, force: true }); + cy.get(`[label="${type}"]`).click({ multiple: true, force: true }); + cy.get(nativeFilters.modal.container) + .find(nativeFilters.filtersPanel.filterName) + .last() + .click({ scrollBehavior: false }) + .clear() + .type(name, { scrollBehavior: false }); + if (dataset) { cy.get(nativeFilters.modal.container) - .find(nativeFilters.filtersPanel.filterName) + .find(nativeFilters.filtersPanel.datasetName) .last() - .click({ scrollBehavior: false }) - .clear() - .type(name, { scrollBehavior: false }); - if (dataset) { - cy.get(nativeFilters.modal.container) - .find(nativeFilters.filtersPanel.datasetName) - .last() - .click({ force: true, scrollBehavior: false }) - .type(`${dataset}`, { scrollBehavior: false }); - cy.get(nativeFilters.silentLoading).should('not.exist'); - cy.get(`[label="${dataset}"]`).click({ multiple: true, force: true }); - } - cy.get(nativeFilters.silentLoading).should('not.exist'); - if (filterColumn) { - cy.get(nativeFilters.filtersPanel.filterInfoInput) - .last() - .click({ force: true }); - cy.get(nativeFilters.filtersPanel.filterInfoInput) - .last() - .type(filterColumn); - cy.get(nativeFilters.filtersPanel.inputDropdown) - .should('be.visible', { timeout: 20000 }) - .last() - .click(); - } + .click({ force: true, scrollBehavior: false }) + .type(`${dataset}`, { scrollBehavior: false }); cy.get(nativeFilters.silentLoading).should('not.exist'); + cy.get(`[label="${dataset}"]`).click({ multiple: true, force: true }); } - - /** ************************************************************************ - * Get native filter placeholder e.g 9 options - * @param {number} index which input it fills - * @returns cy object for assertions - * @summary helper for getting placeholder value - ************************************************************************* */ - export function getNativeFilterPlaceholderWithIndex(index: number) { - return cy.get(nativeFilters.filtersPanel.columnEmptyInput).eq(index); + cy.get(nativeFilters.silentLoading).should('not.exist'); + if (filterColumn) { + cy.get(nativeFilters.filtersPanel.filterInfoInput) + .last() + .click({ force: true }); + cy.get(nativeFilters.filtersPanel.filterInfoInput) + .last() + .type(filterColumn); + cy.get(nativeFilters.filtersPanel.inputDropdown) + .should('be.visible', { timeout: 20000 }) + .last() + .click(); } + cy.get(nativeFilters.silentLoading).should('not.exist'); +} - /** ************************************************************************ - * Apply native filter value from dashboard view - * @param {number} index which input it fills - * @param {string} value what is filter value - * @returns {null} - * @summary put value to nth native filter input in view - ************************************************************************* */ - export function applyNativeFilterValueWithIndex(index: number, value: string) { - cy.get(nativeFilters.filterFromDashboardView.filterValueInput) - .eq(index) - .parent() - .should('be.visible', { timeout: 10000 }) - .type(`${value}{enter}`); - // click the title to dismiss shown options - cy.get(nativeFilters.filterFromDashboardView.filterName).eq(index).click(); - } +/** ************************************************************************ + * Get native filter placeholder e.g 9 options + * @param {number} index which input it fills + * @returns cy object for assertions + * @summary helper for getting placeholder value + ************************************************************************* */ +export function getNativeFilterPlaceholderWithIndex(index: number) { + return cy.get(nativeFilters.filtersPanel.columnEmptyInput).eq(index); +} - /** ************************************************************************ - * Fills parent filter input - * @param {number} index which input it fills - * @param {string} value on which filter it depends on - * @returns {null} - * @summary takes first or second input and modify the depends on filter value - ************************************************************************* */ - export function addParentFilterWithValue(index: number, value: string) { - return cy - .get(nativeFilters.filterConfigurationSections.displayedSection) - .within(() => { - cy.get('input[aria-label="Limit type"]') - .eq(index) - .click({ force: true }) - .type(`${value}{enter}`, { delay: 30, force: true }); - }); - } +/** ************************************************************************ + * Apply native filter value from dashboard view + * @param {number} index which input it fills + * @param {string} value what is filter value + * @returns {null} + * @summary put value to nth native filter input in view + ************************************************************************* */ +export function applyNativeFilterValueWithIndex(index: number, value: string) { + cy.get(nativeFilters.filterFromDashboardView.filterValueInput) + .eq(index) + .parent() + .should('be.visible', { timeout: 10000 }) + .type(`${value}{enter}`); + // click the title to dismiss shown options + cy.get(nativeFilters.filterFromDashboardView.filterName).eq(index).click(); +} - /** ************************************************************************ - * Save Native Filter Settings - * @returns {None} - * @summary helper for save native filters settings - ************************************************************************* */ - export function saveNativeFilterSettings(charts: any) { - cy.get(nativeFilters.modal.footer) - .contains('Save') - .should('be.visible') - .click(); - cy.get(nativeFilters.modal.container).should('not.exist'); - charts.forEach(waitForChartLoad); - } +/** ************************************************************************ + * Fills parent filter input + * @param {number} index which input it fills + * @param {string} value on which filter it depends on + * @returns {null} + * @summary takes first or second input and modify the depends on filter value + ************************************************************************* */ +export function addParentFilterWithValue(index: number, value: string) { + return cy + .get(nativeFilters.filterConfigurationSections.displayedSection) + .within(() => { + cy.get('input[aria-label="Limit type"]') + .eq(index) + .click({ force: true }) + .type(`${value}{enter}`, { delay: 30, force: true }); + }); +} - /** ************************************************************************ - * Cancel Native fitler settings - * @returns {None} - * @summary helper for cancel native filters settings - ************************************************************************* */ - export function cancelNativeFilterSettings() { - cy.get(nativeFilters.modal.footer) - .find(nativeFilters.modal.cancelButton) - .should('be.visible') - .click(); - cy.get(nativeFilters.modal.alertXUnsavedFilters) - .should('have.text', 'There are unsaved changes.') - .should('be.visible'); - cy.get(nativeFilters.modal.footer) - .find(nativeFilters.modal.yesCancelButton) - .contains('cancel') - .should('be.visible') - .click(); - cy.get(nativeFilters.modal.container).should('not.exist'); - } +/** ************************************************************************ + * Save Native Filter Settings + * @returns {None} + * @summary helper for save native filters settings + ************************************************************************* */ +export function saveNativeFilterSettings(charts: any) { + cy.get(nativeFilters.modal.footer) + .contains('Save') + .should('be.visible') + .click(); + cy.get(nativeFilters.modal.container).should('not.exist'); + charts.forEach(waitForChartLoad); +} - /** ************************************************************************ - * Close dashboard toast message - * @returns {None} - * @summary helper for close dashboard toast message in order to make test stable - ************************************************************************* */ - export function closeDashboardToastMessage() { - cy.get('body').then($body => { - if ($body.find(dashboardView.dashboardAlert.modal).length > 0) { - // evaluates as true if button exists at all - cy.get(dashboardView.dashboardAlert.modal).then($header => { - if ($header.is(':visible')) { - cy.get(dashboardView.dashboardAlert.closeButton).click({ - force: true, - }); - cy.get(dashboardView.dashboardAlert.closeButton).should('not.exist', { - timeout: 10000, - }); - } - }); - } - }); - } +/** ************************************************************************ + * Cancel Native fitler settings + * @returns {None} + * @summary helper for cancel native filters settings + ************************************************************************* */ +export function cancelNativeFilterSettings() { + cy.get(nativeFilters.modal.footer) + .find(nativeFilters.modal.cancelButton) + .should('be.visible') + .click(); + cy.get(nativeFilters.modal.alertXUnsavedFilters) + .should('have.text', 'There are unsaved changes.') + .should('be.visible'); + cy.get(nativeFilters.modal.footer) + .find(nativeFilters.modal.yesCancelButton) + .contains('cancel') + .should('be.visible') + .click(); + cy.get(nativeFilters.modal.container).should('not.exist'); +} - /** ************************************************************************ - * Validate filter name on dashboard - * @param name: filter name to validate - * @return {null} - * @summary helper for validate filter name on dashboard - ************************************************************************* */ - export function validateFilterNameOnDashboard(name: string) { - cy.get(nativeFilters.filterFromDashboardView.filterName) - .should('be.visible', { timeout: 40000 }) - .contains(`${name}`); - } +/** ************************************************************************ + * Close dashboard toast message + * @returns {None} + * @summary helper for close dashboard toast message in order to make test stable + ************************************************************************* */ +export function closeDashboardToastMessage() { + cy.get('body').then($body => { + if ($body.find(dashboardView.dashboardAlert.modal).length > 0) { + // evaluates as true if button exists at all + cy.get(dashboardView.dashboardAlert.modal).then($header => { + if ($header.is(':visible')) { + cy.get(dashboardView.dashboardAlert.closeButton).click({ + force: true, + }); + cy.get(dashboardView.dashboardAlert.closeButton).should('not.exist', { + timeout: 10000, + }); + } + }); + } + }); +} - /** ************************************************************************ - * Validate filter content on dashboard - * @param filterContent: filter content to validate - * @return {null} - * @summary helper for validate filter content on dashboard - ************************************************************************* */ - export function validateFilterContentOnDashboard(filterContent: string) { - cy.get(nativeFilters.filterFromDashboardView.filterContent) - .contains(`${filterContent}`) - .should('be.visible'); - } +/** ************************************************************************ + * Validate filter name on dashboard + * @param name: filter name to validate + * @return {null} + * @summary helper for validate filter name on dashboard + ************************************************************************* */ +export function validateFilterNameOnDashboard(name: string) { + cy.get(nativeFilters.filterFromDashboardView.filterName) + .should('be.visible', { timeout: 40000 }) + .contains(`${name}`); +} - /** ************************************************************************ - * Delete Native filter - * @return {null} - * @summary helper for delete native filter - ************************************************************************* */ - export function deleteNativeFilter() { - cy.get(nativeFilters.filtersList.removeIcon).first().click(); - } +/** ************************************************************************ + * Validate filter content on dashboard + * @param filterContent: filter content to validate + * @return {null} + * @summary helper for validate filter content on dashboard + ************************************************************************* */ +export function validateFilterContentOnDashboard(filterContent: string) { + cy.get(nativeFilters.filterFromDashboardView.filterContent) + .contains(`${filterContent}`) + .should('be.visible'); +} - /** ************************************************************************ - * Undo delete Native filter - * @return {null} - * @summary helper for undo delete native filter - ************************************************************************ */ - export function undoDeleteNativeFilter() { - deleteNativeFilter(); - cy.contains('Undo?').click(); - } +/** ************************************************************************ + * Delete Native filter + * @return {null} + * @summary helper for delete native filter + ************************************************************************* */ +export function deleteNativeFilter() { + cy.get(nativeFilters.filtersList.removeIcon).first().click(); +} - /** ************************************************************************ - * Check Native Filter tooltip content - * @param index: tooltip indext to check - * @param value: tooltip value to check - * @return {null} - * @summary helper for checking native filter tooltip content by index - ************************************************************************* */ - export function checkNativeFilterTooltip(index: number, value: string) { - cy.get(nativeFilters.filterConfigurationSections.infoTooltip) - .eq(index) - .trigger('mouseover'); - cy.contains(`${value}`); - } +/** ************************************************************************ + * Undo delete Native filter + * @return {null} + * @summary helper for undo delete native filter + ************************************************************************ */ +export function undoDeleteNativeFilter() { + deleteNativeFilter(); + cy.contains('Undo?').click(); +} - /** ************************************************************************ - * Apply advanced time range filter on dashboard - * @param startRange: starting time range - * @param endRange: ending time range - * @return {null} - * @summary helper for applying advanced time range filter on dashboard with customize time range - ************************************************************************* */ - export function applyAdvancedTimeRangeFilterOnDashboard( - startRange?: string, - endRange?: string, - ) { - cy.get('.control-label').contains('RANGE TYPE').should('be.visible'); - cy.get('.ant-popover-content .ant-select-selector') - .should('be.visible') - .click(); - cy.get(`[label="Advanced"]`).should('be.visible').click(); - cy.get('.section-title').contains('Advanced Time Range').should('be.visible'); - if (startRange) { - cy.get('.ant-popover-inner-content') - .find('[class^=ant-input]') - .first() - .type(`${startRange}`); - } - if (endRange) { - cy.get('.ant-popover-inner-content') - .find('[class^=ant-input]') - .last() - .type(`${endRange}`); - } - cy.get(dashboardView.timeRangeModal.applyButton).click(); - cy.get(nativeFilters.applyFilter).click(); - } +/** ************************************************************************ + * Check Native Filter tooltip content + * @param index: tooltip indext to check + * @param value: tooltip value to check + * @return {null} + * @summary helper for checking native filter tooltip content by index + ************************************************************************* */ +export function checkNativeFilterTooltip(index: number, value: string) { + cy.get(nativeFilters.filterConfigurationSections.infoTooltip) + .eq(index) + .trigger('mouseover'); + cy.contains(`${value}`); +} - /** ************************************************************************ - * Input default valule in Native filter in filter settings - * @param defaultValue: default value for native filter - * @return {null} - * @summary helper for input default valule in Native filter in filter settings - ************************************************************************* */ - export function inputNativeFilterDefaultValue(defaultValue: string) { - cy.contains('Filter has default value').click(); - cy.contains('Default value is required').should('be.visible'); - cy.get(nativeFilters.modal.container).within(() => { - cy.get(nativeFilters.filterConfigurationSections.filterPlaceholder) - .contains('options') - .should('be.visible'); - cy.get(nativeFilters.filterConfigurationSections.collapsedSectionContainer) - .first() - .get(nativeFilters.filtersPanel.columnEmptyInput) - .type(`${defaultValue}{enter}`); - }); +/** ************************************************************************ + * Apply advanced time range filter on dashboard + * @param startRange: starting time range + * @param endRange: ending time range + * @return {null} + * @summary helper for applying advanced time range filter on dashboard with customize time range + ************************************************************************* */ +export function applyAdvancedTimeRangeFilterOnDashboard( + startRange?: string, + endRange?: string, +) { + cy.get('.control-label').contains('RANGE TYPE').should('be.visible'); + cy.get('.ant-popover-content .ant-select-selector') + .should('be.visible') + .click(); + cy.get(`[label="Advanced"]`).should('be.visible').click(); + cy.get('.section-title').contains('Advanced Time Range').should('be.visible'); + if (startRange) { + cy.get('.ant-popover-inner-content') + .find('[class^=ant-input]') + .first() + .type(`${startRange}`); } - - /** ************************************************************************ - * add filter for test column 'Country name' - * @return {null} - * @summary helper for add filter for test column 'Country name' - ************************************************************************* */ - export function addCountryNameFilter() { - fillNativeFilterForm( - testItems.filterType.value, - testItems.topTenChart.filterColumn, - testItems.datasetForNativeFilter, - testItems.topTenChart.filterColumn, - ); + if (endRange) { + cy.get('.ant-popover-inner-content') + .find('[class^=ant-input]') + .last() + .type(`${endRange}`); } + cy.get(dashboardView.timeRangeModal.applyButton).click(); + cy.get(nativeFilters.applyFilter).click(); +} - /** ************************************************************************ - * add filter for test column 'Region' - * @return {null} - * @summary helper for add filter for test column 'Region' - ************************************************************************* */ - export function addRegionFilter() { - fillNativeFilterForm( - testItems.filterType.value, - testItems.topTenChart.filterColumnRegion, - testItems.datasetForNativeFilter, - testItems.topTenChart.filterColumnRegion, - ); - } +/** ************************************************************************ + * Input default valule in Native filter in filter settings + * @param defaultValue: default value for native filter + * @return {null} + * @summary helper for input default valule in Native filter in filter settings + ************************************************************************* */ +export function inputNativeFilterDefaultValue(defaultValue: string) { + cy.contains('Filter has default value').click(); + cy.contains('Default value is required').should('be.visible'); + cy.get(nativeFilters.modal.container).within(() => { + cy.get(nativeFilters.filterConfigurationSections.filterPlaceholder) + .contains('options') + .should('be.visible'); + cy.get(nativeFilters.filterConfigurationSections.collapsedSectionContainer) + .first() + .get(nativeFilters.filtersPanel.columnEmptyInput) + .type(`${defaultValue}{enter}`); + }); +} - /** ************************************************************************ - * add filter for test column 'Country Code' - * @return {null} - * @summary helper for add filter for test column 'Country Code' - ************************************************************************* */ - export function addCountryCodeFilter() { - fillNativeFilterForm( - testItems.filterType.value, - testItems.topTenChart.filterColumnCountryCode, - testItems.datasetForNativeFilter, - testItems.topTenChart.filterColumnCountryCode, - ); - } +/** ************************************************************************ + * add filter for test column 'Country name' + * @return {null} + * @summary helper for add filter for test column 'Country name' + ************************************************************************* */ +export function addCountryNameFilter() { + fillNativeFilterForm( + testItems.filterType.value, + testItems.topTenChart.filterColumn, + testItems.datasetForNativeFilter, + testItems.topTenChart.filterColumn, + ); +} + +/** ************************************************************************ + * add filter for test column 'Region' + * @return {null} + * @summary helper for add filter for test column 'Region' + ************************************************************************* */ +export function addRegionFilter() { + fillNativeFilterForm( + testItems.filterType.value, + testItems.topTenChart.filterColumnRegion, + testItems.datasetForNativeFilter, + testItems.topTenChart.filterColumnRegion, + ); +} + +/** ************************************************************************ + * add filter for test column 'Country Code' + * @return {null} + * @summary helper for add filter for test column 'Country Code' + ************************************************************************* */ +export function addCountryCodeFilter() { + fillNativeFilterForm( + testItems.filterType.value, + testItems.topTenChart.filterColumnCountryCode, + testItems.datasetForNativeFilter, + testItems.topTenChart.filterColumnCountryCode, + ); +} diff --git a/superset-frontend/cypress-base/cypress/integration/database/helper.ts b/superset-frontend/cypress-base/cypress/integration/database/helper.ts deleted file mode 100644 index a339865e1fe6c..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/database/helper.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * 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. - */ -export const DATABASE_LIST = '/databaseview/list'; diff --git a/superset-frontend/cypress-base/cypress/integration/database/modal.test.ts b/superset-frontend/cypress-base/cypress/integration/database/modal.test.ts index 2255021676560..c94adcc2bd74a 100644 --- a/superset-frontend/cypress-base/cypress/integration/database/modal.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/database/modal.test.ts @@ -16,14 +16,25 @@ * specific language governing permissions and limitations * under the License. */ -import { DATABASE_LIST } from './helper'; +import { DATABASE_LIST } from 'cypress/utils/urls'; + +function closeModal() { + cy.get('body').then($body => { + if ($body.find('[data-test="database-modal"]').length) { + cy.get('[aria-label="Close"]').eq(1).click(); + } + }); +} describe('Add database', () => { - beforeEach(() => { - cy.login(); + before(() => { cy.visit(DATABASE_LIST); - cy.wait(3000); - cy.get('[data-test="btn-create-database"]').click(); + }); + + beforeEach(() => { + cy.preserveLogin(); + closeModal(); + cy.getBySel('btn-create-database').click(); }); it('should open dynamic form', () => { @@ -42,11 +53,11 @@ describe('Add database', () => { // click postgres dynamic form cy.get('.preferred > :nth-child(1)').click(); - cy.get('[data-test="sqla-connect-btn"]').click(); + cy.getBySel('sqla-connect-btn').click(); // check if the sqlalchemy form is showing up - cy.get('[data-test=database-name-input]').should('be.visible'); - cy.get('[data-test="sqlalchemy-uri-input"]').should('be.visible'); + cy.getBySel('database-name-input').should('be.visible'); + cy.getBySel('sqlalchemy-uri-input').should('be.visible'); }); it('show error alerts on dynamic form for bad host', () => { diff --git a/superset-frontend/cypress-base/cypress/support/index.d.ts b/superset-frontend/cypress-base/cypress/support/index.d.ts index 69eff5913abab..cb22bc1b89598 100644 --- a/superset-frontend/cypress-base/cypress/support/index.d.ts +++ b/superset-frontend/cypress-base/cypress/support/index.d.ts @@ -72,7 +72,10 @@ declare namespace Cypress { */ createSampleDashboards(): void; createSampleCharts(): void; - copyDashboard(originalDashboardName: string, copyDashboardName: string): void; + copyDashboard( + originalDashboardName: string, + copyDashboardName: string, + ): void; /** * Delete diff --git a/superset-frontend/cypress-base/cypress/support/index.ts b/superset-frontend/cypress-base/cypress/support/index.ts index 0dd0c6004bac2..77dfa2bcc87df 100644 --- a/superset-frontend/cypress-base/cypress/support/index.ts +++ b/superset-frontend/cypress-base/cypress/support/index.ts @@ -328,37 +328,47 @@ Cypress.Commands.add('getDashboards', () => .then(resp => resp.body.result), ); -Cypress.Commands.add('copyDashboard', (originalDashboardName, copyDashboardName) => -cy.getDashboards().then((sampleDashboards: any) => { - cy.deleteDashboardByName(copyDashboardName, false).then(() => { - const dashboard = sampleDashboards.find((d: any) => d.dashboard_title === originalDashboardName); - const slugifiedTitle = copyDashboardName.toLowerCase().replace(/ /g, '-'); - const body = new FormData(); - body.append("data", JSON.stringify({ - "dashboard_title": copyDashboardName, - "slug": slugifiedTitle, - "duplicate_slices": false, - })); - if (dashboard) { - cy - .request({ - method: 'POST', - url: `superset/copy_dash/${dashboard.id}/`, - body, - headers: { - 'content-type': 'multipart/form-data', - Authorization: `Bearer ${TokenName}`, - }, - }) - .then(() => - cy.getDashboards().then((sampleDashboards: any) => { - const newDashboard = sampleDashboards.find((d: any) => d.dashboard_title === copyDashboardName); - cy.visit(`/superset/dashboard/${newDashboard.id}/`) - }) - ) - } - }) -})); +Cypress.Commands.add( + 'copyDashboard', + (originalDashboardName, copyDashboardName) => + cy.getDashboards().then((sampleDashboards: any) => { + cy.deleteDashboardByName(copyDashboardName, false).then(() => { + const dashboard = sampleDashboards.find( + (d: any) => d.dashboard_title === originalDashboardName, + ); + const slugifiedTitle = copyDashboardName + .toLowerCase() + .replace(/ /g, '-'); + const body = new FormData(); + body.append( + 'data', + JSON.stringify({ + dashboard_title: copyDashboardName, + slug: slugifiedTitle, + duplicate_slices: false, + }), + ); + if (dashboard) { + cy.request({ + method: 'POST', + url: `superset/copy_dash/${dashboard.id}/`, + body, + headers: { + 'content-type': 'multipart/form-data', + Authorization: `Bearer ${TokenName}`, + }, + }).then(() => + cy.getDashboards().then((sampleDashboards: any) => { + const newDashboard = sampleDashboards.find( + (d: any) => d.dashboard_title === copyDashboardName, + ); + cy.visit(`/superset/dashboard/${newDashboard.id}/`); + }), + ); + } + }); + }), +); Cypress.Commands.add('deleteChart', (id: number, failOnStatusCode = false) => cy diff --git a/superset-frontend/cypress-base/cypress/utils/urls.ts b/superset-frontend/cypress-base/cypress/utils/urls.ts index f99b4ca40cb64..d47724a2cd62e 100644 --- a/superset-frontend/cypress-base/cypress/utils/urls.ts +++ b/superset-frontend/cypress-base/cypress/utils/urls.ts @@ -23,3 +23,4 @@ export const WORLD_HEALTH_DASHBOARD = '/superset/dashboard/world_health/'; export const SAMPLE_DASHBOARD_1 = '/superset/dashboard/1-sample-dashboard/'; export const ECHARTS_DASHBOARD = '/superset/dashboard/echarts_dash/'; export const TABBED_DASHBOARD = '/superset/dashboard/tabbed_dash/'; +export const DATABASE_LIST = '/databaseview/list'; From abb038c9e8cb17731ac85928dfcdcdcab3925368 Mon Sep 17 00:00:00 2001 From: geido Date: Wed, 7 Sep 2022 17:19:12 +0300 Subject: [PATCH 20/31] Skip unused test --- .../{AdhocFilters.test.ts => _skip.AdhocFilters.test.ts} | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename superset-frontend/cypress-base/cypress/integration/explore/{AdhocFilters.test.ts => _skip.AdhocFilters.test.ts} (95%) diff --git a/superset-frontend/cypress-base/cypress/integration/explore/AdhocFilters.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/_skip.AdhocFilters.test.ts similarity index 95% rename from superset-frontend/cypress-base/cypress/integration/explore/AdhocFilters.test.ts rename to superset-frontend/cypress-base/cypress/integration/explore/_skip.AdhocFilters.test.ts index 6ae5aead2b0c3..1dca8f6e10460 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/AdhocFilters.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/_skip.AdhocFilters.test.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -describe('AdhocFilters', () => { +describe.skip('AdhocFilters', () => { beforeEach(() => { cy.login(); cy.intercept('GET', '/superset/filter/table/*/name').as('filterValues'); @@ -28,7 +28,7 @@ describe('AdhocFilters', () => { let numScripts = 0; - xit('Should load AceEditor scripts when needed', () => { + it('Should load AceEditor scripts when needed', () => { cy.get('script').then(nodes => { numScripts = nodes.length; }); @@ -51,7 +51,7 @@ describe('AdhocFilters', () => { }); }); - xit('Set simple adhoc filter', () => { + it('Set simple adhoc filter', () => { cy.get('[aria-label="Comparator option"] .Select__control').click(); cy.get('[data-test=adhoc-filter-simple-value] input[type=text]') .focus() @@ -70,7 +70,7 @@ describe('AdhocFilters', () => { }); }); - xit('Set custom adhoc filter', () => { + it('Set custom adhoc filter', () => { const filterType = 'name'; const filterContent = "'Amy' OR name = 'Donald'"; From 83578a5af475e08715a35dfde28746c0b2e95b76 Mon Sep 17 00:00:00 2001 From: geido Date: Wed, 7 Sep 2022 17:19:28 +0300 Subject: [PATCH 21/31] Improve dataset test --- .../cypress/integration/dataset/dataset_list.test.ts | 9 ++++++--- superset-frontend/cypress-base/cypress/utils/urls.ts | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/superset-frontend/cypress-base/cypress/integration/dataset/dataset_list.test.ts b/superset-frontend/cypress-base/cypress/integration/dataset/dataset_list.test.ts index 8dda9f2764d6f..9e55d01c3c3f5 100644 --- a/superset-frontend/cypress-base/cypress/integration/dataset/dataset_list.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dataset/dataset_list.test.ts @@ -17,14 +17,17 @@ * under the License. */ -const DATASET_LIST_PATH = 'tablemodelview/list'; +import { DATASET_LIST_PATH } from 'cypress/utils/urls'; describe('Dataset list', () => { - beforeEach(() => { - cy.login(); + before(() => { cy.visit(DATASET_LIST_PATH); }); + beforeEach(() => { + cy.preserveLogin(); + }); + it('should open Explore on dataset name click', () => { cy.intercept('**/api/v1/explore/**').as('explore'); cy.get('[data-test="listview-table"] [data-test="internal-link"]') diff --git a/superset-frontend/cypress-base/cypress/utils/urls.ts b/superset-frontend/cypress-base/cypress/utils/urls.ts index d47724a2cd62e..22ceb8e54f352 100644 --- a/superset-frontend/cypress-base/cypress/utils/urls.ts +++ b/superset-frontend/cypress-base/cypress/utils/urls.ts @@ -24,3 +24,4 @@ export const SAMPLE_DASHBOARD_1 = '/superset/dashboard/1-sample-dashboard/'; export const ECHARTS_DASHBOARD = '/superset/dashboard/echarts_dash/'; export const TABBED_DASHBOARD = '/superset/dashboard/tabbed_dash/'; export const DATABASE_LIST = '/databaseview/list'; +export const DATASET_LIST_PATH = 'tablemodelview/list'; \ No newline at end of file From fe89588cdbf2ce447f371fb5e5c10823b6ccbc39 Mon Sep 17 00:00:00 2001 From: geido Date: Wed, 7 Sep 2022 17:33:41 +0300 Subject: [PATCH 22/31] improve alerts_reports tests --- .../alerts_and_reports/alert_report.helper.ts | 20 ----------- .../alerts_and_reports/alerts.test.ts | 35 ++++++++----------- .../alerts_and_reports/reports.test.ts | 35 ++++++++----------- .../cypress-base/cypress/utils/urls.ts | 4 ++- 4 files changed, 33 insertions(+), 61 deletions(-) delete mode 100644 superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alert_report.helper.ts diff --git a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alert_report.helper.ts b/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alert_report.helper.ts deleted file mode 100644 index dcf8b2b4a2931..0000000000000 --- a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alert_report.helper.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * 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. - */ -export const ALERT_LIST = '/alert/list/'; -export const REPORT_LIST = '/report/list/'; diff --git a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alerts.test.ts b/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alerts.test.ts index 97bf2cc9be854..e1e3966758a39 100644 --- a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alerts.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alerts.test.ts @@ -16,31 +16,26 @@ * specific language governing permissions and limitations * under the License. */ -import { ALERT_LIST } from './alert_report.helper'; +import { ALERT_LIST } from 'cypress/utils/urls'; -describe('alert list view', () => { - beforeEach(() => { - cy.login(); +describe('Alert list view', () => { + before(() => { + cy.visit(ALERT_LIST); }); - afterEach(() => { - cy.eyesClose(); + beforeEach(() => { + cy.preserveLogin(); }); it('should load alert lists', () => { - cy.visit(ALERT_LIST); - - cy.get('[data-test="listview-table"]').should('be.visible'); - // check alert list view header - cy.get('[data-test="sort-header"]').eq(1).contains('Last run'); - cy.get('[data-test="sort-header"]').eq(2).contains('Name'); - cy.get('[data-test="sort-header"]').eq(3).contains('Schedule'); - cy.get('[data-test="sort-header"]').eq(4).contains('Notification method'); - cy.get('[data-test="sort-header"]').eq(5).contains('Created by'); - cy.get('[data-test="sort-header"]').eq(6).contains('Owners'); - cy.get('[data-test="sort-header"]').eq(7).contains('Modified'); - // TODO: this assert is flaky, we need to find a way to make it work consistenly - // cy.get('[data-test="sort-header"]').eq(7).contains('Active'); - // cy.get('[data-test="sort-header"]').eq(8).contains('Actions'); + cy.getBySel("listview-table").should('be.visible'); + cy.getBySel("sort-header").eq(1).contains('Last run'); + cy.getBySel("sort-header").eq(2).contains('Name'); + cy.getBySel("sort-header").eq(3).contains('Schedule'); + cy.getBySel("sort-header").eq(4).contains('Notification method'); + cy.getBySel("sort-header").eq(5).contains('Created by'); + cy.getBySel("sort-header").eq(6).contains('Owners'); + cy.getBySel("sort-header").eq(7).contains('Modified'); + cy.getBySel("sort-header").eq(8).contains('Active'); }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/reports.test.ts b/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/reports.test.ts index ea117c507a6d6..fbca291c0f4eb 100644 --- a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/reports.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/reports.test.ts @@ -16,31 +16,26 @@ * specific language governing permissions and limitations * under the License. */ -import { REPORT_LIST } from './alert_report.helper'; +import { REPORT_LIST } from 'cypress/utils/urls'; -describe('report list view', () => { - beforeEach(() => { - cy.login(); +describe('Report list view', () => { + before(() => { + cy.visit(REPORT_LIST); }); - afterEach(() => { - cy.eyesClose(); + beforeEach(() => { + cy.preserveLogin(); }); it('should load report lists', () => { - cy.visit(REPORT_LIST); - - cy.get('[data-test="listview-table"]').should('be.visible'); - // check report list view header - cy.get('[data-test="sort-header"]').eq(1).contains('Last run'); - cy.get('[data-test="sort-header"]').eq(2).contains('Name'); - cy.get('[data-test="sort-header"]').eq(3).contains('Schedule'); - cy.get('[data-test="sort-header"]').eq(4).contains('Notification method'); - cy.get('[data-test="sort-header"]').eq(5).contains('Created by'); - cy.get('[data-test="sort-header"]').eq(6).contains('Owners'); - cy.get('[data-test="sort-header"]').eq(7).contains('Modified'); - // TODO: this assert is flaky, we need to find a way to make it work consistenly - // cy.get('[data-test="sort-header"]').eq(7).contains('Active'); - // cy.get('[data-test="sort-header"]').eq(8).contains('Actions'); + cy.getBySel("listview-table").should('be.visible'); + cy.getBySel("sort-header").eq(1).contains('Last run'); + cy.getBySel("sort-header").eq(2).contains('Name'); + cy.getBySel("sort-header").eq(3).contains('Schedule'); + cy.getBySel("sort-header").eq(4).contains('Notification method'); + cy.getBySel("sort-header").eq(5).contains('Created by'); + cy.getBySel("sort-header").eq(6).contains('Owners'); + cy.getBySel("sort-header").eq(7).contains('Modified'); + cy.getBySel("sort-header").eq(8).contains('Active'); }); }); diff --git a/superset-frontend/cypress-base/cypress/utils/urls.ts b/superset-frontend/cypress-base/cypress/utils/urls.ts index 22ceb8e54f352..9da074c6f2179 100644 --- a/superset-frontend/cypress-base/cypress/utils/urls.ts +++ b/superset-frontend/cypress-base/cypress/utils/urls.ts @@ -24,4 +24,6 @@ export const SAMPLE_DASHBOARD_1 = '/superset/dashboard/1-sample-dashboard/'; export const ECHARTS_DASHBOARD = '/superset/dashboard/echarts_dash/'; export const TABBED_DASHBOARD = '/superset/dashboard/tabbed_dash/'; export const DATABASE_LIST = '/databaseview/list'; -export const DATASET_LIST_PATH = 'tablemodelview/list'; \ No newline at end of file +export const DATASET_LIST_PATH = 'tablemodelview/list'; +export const ALERT_LIST = '/alert/list/'; +export const REPORT_LIST = '/report/list/'; \ No newline at end of file From b99051d15136257cbec01993c9c978676e9474fd Mon Sep 17 00:00:00 2001 From: geido Date: Wed, 7 Sep 2022 17:36:07 +0300 Subject: [PATCH 23/31] Skip unused test --- ...{sourcePanel.index.test.js => _skip.sourcePanel.index.test.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename superset-frontend/cypress-base/cypress/integration/sqllab/{sourcePanel.index.test.js => _skip.sourcePanel.index.test.js} (100%) diff --git a/superset-frontend/cypress-base/cypress/integration/sqllab/sourcePanel.index.test.js b/superset-frontend/cypress-base/cypress/integration/sqllab/_skip.sourcePanel.index.test.js similarity index 100% rename from superset-frontend/cypress-base/cypress/integration/sqllab/sourcePanel.index.test.js rename to superset-frontend/cypress-base/cypress/integration/sqllab/_skip.sourcePanel.index.test.js From fadbec6a6dbab4cf74936a8bd40e7046f3eb27cf Mon Sep 17 00:00:00 2001 From: geido Date: Wed, 7 Sep 2022 19:17:46 +0300 Subject: [PATCH 24/31] Lint --- .../alerts_and_reports/alerts.test.ts | 18 +++++++++--------- .../alerts_and_reports/reports.test.ts | 18 +++++++++--------- .../cypress-base/cypress/utils/urls.ts | 2 +- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alerts.test.ts b/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alerts.test.ts index e1e3966758a39..5135d653b1539 100644 --- a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alerts.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alerts.test.ts @@ -28,14 +28,14 @@ describe('Alert list view', () => { }); it('should load alert lists', () => { - cy.getBySel("listview-table").should('be.visible'); - cy.getBySel("sort-header").eq(1).contains('Last run'); - cy.getBySel("sort-header").eq(2).contains('Name'); - cy.getBySel("sort-header").eq(3).contains('Schedule'); - cy.getBySel("sort-header").eq(4).contains('Notification method'); - cy.getBySel("sort-header").eq(5).contains('Created by'); - cy.getBySel("sort-header").eq(6).contains('Owners'); - cy.getBySel("sort-header").eq(7).contains('Modified'); - cy.getBySel("sort-header").eq(8).contains('Active'); + cy.getBySel('listview-table').should('be.visible'); + cy.getBySel('sort-header').eq(1).contains('Last run'); + cy.getBySel('sort-header').eq(2).contains('Name'); + cy.getBySel('sort-header').eq(3).contains('Schedule'); + cy.getBySel('sort-header').eq(4).contains('Notification method'); + cy.getBySel('sort-header').eq(5).contains('Created by'); + cy.getBySel('sort-header').eq(6).contains('Owners'); + cy.getBySel('sort-header').eq(7).contains('Modified'); + cy.getBySel('sort-header').eq(8).contains('Active'); }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/reports.test.ts b/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/reports.test.ts index fbca291c0f4eb..8080183eeb765 100644 --- a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/reports.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/reports.test.ts @@ -28,14 +28,14 @@ describe('Report list view', () => { }); it('should load report lists', () => { - cy.getBySel("listview-table").should('be.visible'); - cy.getBySel("sort-header").eq(1).contains('Last run'); - cy.getBySel("sort-header").eq(2).contains('Name'); - cy.getBySel("sort-header").eq(3).contains('Schedule'); - cy.getBySel("sort-header").eq(4).contains('Notification method'); - cy.getBySel("sort-header").eq(5).contains('Created by'); - cy.getBySel("sort-header").eq(6).contains('Owners'); - cy.getBySel("sort-header").eq(7).contains('Modified'); - cy.getBySel("sort-header").eq(8).contains('Active'); + cy.getBySel('listview-table').should('be.visible'); + cy.getBySel('sort-header').eq(1).contains('Last run'); + cy.getBySel('sort-header').eq(2).contains('Name'); + cy.getBySel('sort-header').eq(3).contains('Schedule'); + cy.getBySel('sort-header').eq(4).contains('Notification method'); + cy.getBySel('sort-header').eq(5).contains('Created by'); + cy.getBySel('sort-header').eq(6).contains('Owners'); + cy.getBySel('sort-header').eq(7).contains('Modified'); + cy.getBySel('sort-header').eq(8).contains('Active'); }); }); diff --git a/superset-frontend/cypress-base/cypress/utils/urls.ts b/superset-frontend/cypress-base/cypress/utils/urls.ts index 9da074c6f2179..63fa6684d7e6f 100644 --- a/superset-frontend/cypress-base/cypress/utils/urls.ts +++ b/superset-frontend/cypress-base/cypress/utils/urls.ts @@ -26,4 +26,4 @@ export const TABBED_DASHBOARD = '/superset/dashboard/tabbed_dash/'; export const DATABASE_LIST = '/databaseview/list'; export const DATASET_LIST_PATH = 'tablemodelview/list'; export const ALERT_LIST = '/alert/list/'; -export const REPORT_LIST = '/report/list/'; \ No newline at end of file +export const REPORT_LIST = '/report/list/'; From 34ada5a0da26a9eb3bd93f7a11d64cbbde0de024 Mon Sep 17 00:00:00 2001 From: geido Date: Thu, 8 Sep 2022 18:55:44 +0300 Subject: [PATCH 25/31] Refactor nativeFilters tests --- .../dashboard/nativeFilters.test.ts | 1171 ++++++++--------- .../cypress/integration/dashboard/utils.ts | 80 +- .../FiltersConfigForm/DefaultValue.tsx | 4 +- 3 files changed, 557 insertions(+), 698 deletions(-) diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts index d9bd36025caf7..10c1fc88d6c5b 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts @@ -23,20 +23,16 @@ import { exploreView, dataTestChartName, } from 'cypress/support/directories'; -import { waitForChartLoad } from 'cypress/utils'; -import { DASHBOARD_LIST, CHART_LIST } from 'cypress/utils/urls'; +import { SAMPLE_DASHBOARD_1 } from 'cypress/utils/urls'; import { - addCountryCodeFilter, addCountryNameFilter, addParentFilterWithValue, - addRegionFilter, applyAdvancedTimeRangeFilterOnDashboard, applyNativeFilterValueWithIndex, cancelNativeFilterSettings, checkNativeFilterTooltip, clickOnAddFilterInModal, - closeDashboardToastMessage, collapseFilterOnLeftPanel, deleteNativeFilter, enterNativeFilterEditModal, @@ -52,705 +48,604 @@ import { validateFilterNameOnDashboard, testItems, WORLD_HEALTH_CHARTS, + interceptGet, + interceptCharts, + interceptDatasets, } from './utils'; -// TODO: fix flaky init logic and re-enable -const milliseconds = new Date().getTime(); -const dashboard = `Test Dashboard${milliseconds}`; +const SAMPLE_CHART = { name: 'Most Populated Countries', viz: 'table' }; -function setup() { - cy.preserveLogin(); - cy.copyDashboard("World Bank's Data", 'Cypress test Dashboard'); - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); - closeDashboardToastMessage(); -} - -describe('Nativefilters tests initial state required', () => { - beforeEach(() => { - setup(); - }); +function visitDashboard() { + interceptCharts(); + interceptGet(); + interceptDatasets(); - it('Verify that default value is respected after revisit', () => { - expandFilterOnLeftPanel(); - enterNativeFilterEditModal(); - addCountryNameFilter(); - inputNativeFilterDefaultValue(testItems.filterDefaultValue); - saveNativeFilterSettings(WORLD_HEALTH_CHARTS); - cy.get(nativeFilters.filterItem) - .contains(testItems.filterDefaultValue) - .should('be.visible'); - cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { - cy.contains(testItems.filterDefaultValue).should('be.visible'); - cy.contains(testItems.filterOtherCountry).should('not.exist'); - }); + cy.visit(SAMPLE_DASHBOARD_1); + cy.wait('@get'); + cy.wait('@getCharts'); + cy.wait('@getDatasets'); + cy.wait(500); +} - // reload dashboard - cy.reload(); - WORLD_HEALTH_CHARTS.forEach(waitForChartLoad); - cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { - cy.contains(testItems.filterDefaultValue).should('be.visible'); - cy.contains(testItems.filterOtherCountry).should('not.exist'); +function prepareDashboardFilter(filters: { name: string; column: string }[]) { + cy.request({ + method: 'GET', + url: `api/v1/dashboard/1-sample-dashboard`, + }).then(res => { + const { body } = res; + const dashboardId = body.result.id; + const allFilters: Record[] = []; + filters.forEach((f, i) => { + allFilters.push({ + id: `NATIVE_FILTER-fLH0pxFQ${i}`, + controlValues: { + enableEmptyFilter: false, + defaultToFirstItem: false, + multiSelect: true, + searchAllOptions: false, + inverseSelection: false, + }, + name: f.name, + filterType: 'filter_select', + targets: [ + { + datasetId: 2, + column: { name: f.column }, + }, + ], + defaultDataMask: { + extraFormData: {}, + filterState: {}, + ownState: {}, + }, + cascadeParentIds: [], + scope: { + rootPath: ['ROOT_ID'], + excluded: [], + }, + type: 'NATIVE_FILTER', + description: '', + chartsInScope: [6], + tabsInScope: [], + }); }); - validateFilterContentOnDashboard(testItems.filterDefaultValue); + if (dashboardId) { + const jsonMetadata = { + show_native_filters: true, + native_filter_configuration: allFilters, + timed_refresh_immune_slices: [], + expanded_slices: {}, + refresh_frequency: 0, + color_scheme: '', + label_colors: {}, + shared_label_colors: {}, + color_scheme_domain: [], + positions: { + DASHBOARD_VERSION_KEY: 'v2', + ROOT_ID: { type: 'ROOT', id: 'ROOT_ID', children: ['GRID_ID'] }, + GRID_ID: { + type: 'GRID', + id: 'GRID_ID', + children: ['ROW-0rHnUz4nMA'], + parents: ['ROOT_ID'], + }, + HEADER_ID: { + id: 'HEADER_ID', + type: 'HEADER', + meta: { text: '1 - Sample dashboard' }, + }, + 'CHART-DF6EfI55F-': { + type: 'CHART', + id: 'CHART-DF6EfI55F-', + children: [], + parents: ['ROOT_ID', 'GRID_ID', 'ROW-0rHnUz4nMA'], + meta: { + width: 4, + height: 50, + chartId: 6, + sliceName: 'Most Populated Countries', + }, + }, + 'ROW-0rHnUz4nMA': { + type: 'ROW', + id: 'ROW-0rHnUz4nMA', + children: ['CHART-DF6EfI55F-'], + parents: ['ROOT_ID', 'GRID_ID'], + meta: { background: 'BACKGROUND_TRANSPARENT' }, + }, + }, + default_filters: '{}', + filter_scopes: {}, + chart_configuration: {}, + }; + + return cy + .request({ + method: 'PUT', + url: `api/v1/dashboard/${dashboardId}`, + body: { + json_metadata: JSON.stringify(jsonMetadata), + }, + }) + .then(() => visitDashboard()); + } + return cy; }); +} - it('User can create parent filters using "Values are dependent on other filters"', () => { - enterNativeFilterEditModal(); - // Create parent filter 'region'. - addRegionFilter(); - // Create filter 'country_name' depend on region filter. - clickOnAddFilterInModal(); - addCountryNameFilter(); - cy.get(nativeFilters.filterConfigurationSections.displayedSection).within( - () => { - cy.contains('Values are dependent on other filters') - .should('be.visible') - .click(); - }, - ); - addParentFilterWithValue(0, testItems.topTenChart.filterColumnRegion); - saveNativeFilterSettings(WORLD_HEALTH_CHARTS); - [ - testItems.topTenChart.filterColumnRegion, - testItems.topTenChart.filterColumn, - ].forEach(it => { - cy.get(nativeFilters.filterFromDashboardView.filterName) - .contains(it) - .should('be.visible'); - }); - getNativeFilterPlaceholderWithIndex(1) - .invoke('text') - .should('equal', '214 options', { timeout: 20000 }); - // apply first filter value and validate 2nd filter is depden on 1st filter. - applyNativeFilterValueWithIndex(0, 'North America'); - getNativeFilterPlaceholderWithIndex(0).should('have.text', '3 options', { - timeout: 20000, - }); +function selectFilter(index: number) { + cy.get("[data-test='filter-title-container'] [draggable='true']") + .eq(index) + .click(); +} + +function closeFilterModal() { + cy.get('body').then($body => { + if ($body.find('[data-test="native-filter-modal-cancel-button"]').length) { + cy.getBySel('native-filter-modal-cancel-button').click(); + } }); +} - it('user can delete dependent filter', () => { - enterNativeFilterEditModal(); - addRegionFilter(); - clickOnAddFilterInModal(); - addCountryNameFilter(); - cy.get(nativeFilters.filterConfigurationSections.displayedSection).within( - () => { - cy.contains('Values are dependent on other filters') - .should('be.visible') - .click(); - }, - ); - addParentFilterWithValue(0, testItems.topTenChart.filterColumnRegion); - // remove year native filter to cause it disappears from parent filter input in global sales - cy.get(nativeFilters.modal.tabsList.removeTab) - .should('be.visible') - .first() - .click(); - // make sure you are seeing global sales filter which had parent filter - cy.get(nativeFilters.modal.tabsList.filterItemsContainer) - .children() - .last() - .click(); - // - cy.wait(1000); - cy.get(nativeFilters.filterConfigurationSections.displayedSection).within( - () => { - cy.contains('Values are dependent on other filters').should( - 'not.exist', - ); - }, - ); +describe('Native filters', () => { + beforeEach(() => { + cy.preserveLogin(); }); - it('User can create filter depend on 2 other filters', () => { - enterNativeFilterEditModal(); - // add first filter - addRegionFilter(); - // add second filter - clickOnAddFilterInModal(); - addCountryNameFilter(); - // add third filter - clickOnAddFilterInModal(); - addCountryCodeFilter(); - cy.wait(1000); - cy.get(nativeFilters.filterConfigurationSections.displayedSection).within( - () => { - cy.contains('Values are dependent on other filters') - .should('be.visible') - .click(); - cy.get(exploreView.controlPanel.addFieldValue).click(); - }, - ); - // add value to the first input - addParentFilterWithValue(0, testItems.topTenChart.filterColumnRegion); - // add value to the second input - addParentFilterWithValue(1, testItems.topTenChart.filterColumn); - saveNativeFilterSettings(WORLD_HEALTH_CHARTS); - // filters should be displayed in the left panel - [ - testItems.topTenChart.filterColumnRegion, - testItems.topTenChart.filterColumn, - testItems.topTenChart.filterColumnCountryCode, - ].forEach(it => { - validateFilterNameOnDashboard(it); + describe('Nativefilters tests initial state required', () => { + beforeEach(() => { + cy.createSampleDashboards(); }); - // initially first filter shows 39 options - getNativeFilterPlaceholderWithIndex(0).should('have.text', '7 options'); - // initially second filter shows 409 options - getNativeFilterPlaceholderWithIndex(1).should('have.text', '214 options'); - // verify third filter shows 409 options - getNativeFilterPlaceholderWithIndex(2).should('have.text', '214 options'); - - // apply first filter value - applyNativeFilterValueWithIndex(0, 'North America'); - - // verify second filter shows 409 options available still - getNativeFilterPlaceholderWithIndex(0).should('have.text', '214 options'); - - // verify second filter shows 69 options available still - getNativeFilterPlaceholderWithIndex(1).should('have.text', '3 options'); - - // apply second filter value - applyNativeFilterValueWithIndex(1, 'United States'); + it('Verify that default value is respected after revisit', () => { + prepareDashboardFilter([ + { name: 'country_name', column: 'country_name' }, + ]); + enterNativeFilterEditModal(); + inputNativeFilterDefaultValue(testItems.filterDefaultValue); + saveNativeFilterSettings([SAMPLE_CHART]); + cy.get(nativeFilters.filterItem) + .contains(testItems.filterDefaultValue) + .should('be.visible'); + cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { + cy.contains(testItems.filterDefaultValue).should('be.visible'); + cy.contains(testItems.filterOtherCountry).should('not.exist'); + }); - // verify number of available options for third filter - should be decreased to only one - getNativeFilterPlaceholderWithIndex(0).should('have.text', '1 option'); - }); + // reload dashboard + cy.reload(); + cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { + cy.contains(testItems.filterDefaultValue).should('be.visible'); + cy.contains(testItems.filterOtherCountry).should('not.exist'); + }); + validateFilterContentOnDashboard(testItems.filterDefaultValue); + }); - it('User can remove parent filters', () => { - enterNativeFilterEditModal(); - addRegionFilter(); - clickOnAddFilterInModal(); - addCountryNameFilter(); - cy.wait(1000); - // Select dependdent option and auto use platform for genre - cy.get(nativeFilters.filterConfigurationSections.displayedSection).within( - () => { - cy.contains('Values are dependent on other filters') - .should('be.visible') - .click(); - }, - ); - saveNativeFilterSettings(WORLD_HEALTH_CHARTS); - enterNativeFilterEditModal(); - cy.get(nativeFilters.modal.tabsList.removeTab) - .should('be.visible') - .first() - .click({ - force: true, + it('User can create parent filters using "Values are dependent on other filters"', () => { + prepareDashboardFilter([ + { name: 'region', column: 'region' }, + { name: 'country_name', column: 'country_name' }, + ]); + enterNativeFilterEditModal(); + selectFilter(1); + cy.get(nativeFilters.filterConfigurationSections.displayedSection).within( + () => { + cy.contains('Values are dependent on other filters') + .should('be.visible') + .click(); + }, + ); + addParentFilterWithValue(0, testItems.topTenChart.filterColumnRegion); + saveNativeFilterSettings([SAMPLE_CHART]); + [ + testItems.topTenChart.filterColumnRegion, + testItems.topTenChart.filterColumn, + ].forEach(it => { + cy.get(nativeFilters.filterFromDashboardView.filterName) + .contains(it) + .should('be.visible'); + }); + getNativeFilterPlaceholderWithIndex(1) + .invoke('text') + .should('equal', '214 options', { timeout: 20000 }); + // apply first filter value and validate 2nd filter is depden on 1st filter. + applyNativeFilterValueWithIndex(0, 'North America'); + getNativeFilterPlaceholderWithIndex(0).should('have.text', '3 options', { + timeout: 20000, }); - saveNativeFilterSettings(WORLD_HEALTH_CHARTS); - cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { - cy.contains(testItems.filterDefaultValue).should('be.visible'); - cy.contains(testItems.filterOtherCountry).should('be.visible'); }); - }); -}); -describe('Nativefilters initial state not required', () => { - beforeEach(() => { - setup(); - }); + it('user can delete dependent filter', () => { + prepareDashboardFilter([ + { name: 'region', column: 'region' }, + { name: 'country_name', column: 'country_name' }, + ]); + enterNativeFilterEditModal(); + selectFilter(1); + cy.get(nativeFilters.filterConfigurationSections.displayedSection).within( + () => { + cy.contains('Values are dependent on other filters') + .should('be.visible') + .click(); + }, + ); + addParentFilterWithValue(0, testItems.topTenChart.filterColumnRegion); + // remove year native filter to cause it disappears from parent filter input in global sales + cy.get(nativeFilters.modal.tabsList.removeTab) + .should('be.visible') + .first() + .click(); + // make sure you are seeing global sales filter which had parent filter + cy.get(nativeFilters.modal.tabsList.filterItemsContainer) + .children() + .last() + .click(); + // + cy.wait(1000); + cy.get(nativeFilters.filterConfigurationSections.displayedSection).within( + () => { + cy.contains('Values are dependent on other filters').should( + 'not.exist', + ); + }, + ); + }); - it('User can expand / retract native filter sidebar on a dashboard', () => { - cy.get(nativeFilters.addFilterButton.button).should('not.exist'); - expandFilterOnLeftPanel(); - cy.get(nativeFilters.filterFromDashboardView.createFilterButton).should( - 'be.visible', - ); - cy.get(nativeFilters.filterFromDashboardView.expand).should( - 'not.be.visible', - ); - collapseFilterOnLeftPanel(); - }); + it('User can create filter depend on 2 other filters', () => { + prepareDashboardFilter([ + { name: 'region', column: 'region' }, + { name: 'country_name', column: 'country_name' }, + { name: 'country_code', column: 'country_code' }, + ]); + enterNativeFilterEditModal(); + selectFilter(2); + cy.get(nativeFilters.filterConfigurationSections.displayedSection).within( + () => { + cy.contains('Values are dependent on other filters') + .should('be.visible') + .click(); + cy.get(exploreView.controlPanel.addFieldValue).click(); + }, + ); + // add value to the first input + addParentFilterWithValue(0, testItems.topTenChart.filterColumnRegion); + // add value to the second input + addParentFilterWithValue(1, testItems.topTenChart.filterColumn); + saveNativeFilterSettings([SAMPLE_CHART]); + // filters should be displayed in the left panel + [ + testItems.topTenChart.filterColumnRegion, + testItems.topTenChart.filterColumn, + testItems.topTenChart.filterColumnCountryCode, + ].forEach(it => { + validateFilterNameOnDashboard(it); + }); - it('User can enter filter edit pop-up by clicking on native filter edit icon', () => { - enterNativeFilterEditModal(); - }); + // initially first filter shows 39 options + getNativeFilterPlaceholderWithIndex(0).should('have.text', '7 options'); + // initially second filter shows 409 options + getNativeFilterPlaceholderWithIndex(1).should('have.text', '214 options'); + // verify third filter shows 409 options + getNativeFilterPlaceholderWithIndex(2).should('have.text', '214 options'); - it('User can delete a native filter', () => { - enterNativeFilterEditModal(); - cy.get(nativeFilters.filtersList.removeIcon).first().click(); - cy.contains('Restore Filter').should('not.exist', { timeout: 10000 }); - saveNativeFilterSettings(WORLD_HEALTH_CHARTS); - }); + // apply first filter value + applyNativeFilterValueWithIndex(0, 'North America'); - it('User can cancel creating a new filter', () => { - enterNativeFilterEditModal(); - cancelNativeFilterSettings(); - }); + // verify second filter shows 409 options available still + getNativeFilterPlaceholderWithIndex(0).should('have.text', '214 options'); - it('Verify setting options and tooltips for value filter', () => { - enterNativeFilterEditModal(); - cy.contains('Filter value is required').should('be.visible').click(); - checkNativeFilterTooltip(0, nativeFilterTooltips.defaultValue); - cy.get(nativeFilters.modal.container).should('be.visible'); - valueNativeFilterOptions.forEach(el => { - cy.contains(el); - }); - cy.contains('Values are dependent on other filters').should('not.exist'); - cy.get(nativeFilters.filterConfigurationSections.checkedCheckbox).contains( - 'Can select multiple values', - ); - checkNativeFilterTooltip(1, nativeFilterTooltips.required); - checkNativeFilterTooltip(2, nativeFilterTooltips.defaultToFirstItem); - checkNativeFilterTooltip(3, nativeFilterTooltips.searchAllFilterOptions); - checkNativeFilterTooltip(4, nativeFilterTooltips.inverseSelection); - clickOnAddFilterInModal(); - cy.contains('Values are dependent on other filters').should('exist'); - }); + // verify second filter shows 69 options available still + getNativeFilterPlaceholderWithIndex(1).should('have.text', '3 options'); - it("User can check 'Filter has default value'", () => { - enterNativeFilterEditModal(); - addCountryNameFilter(); - inputNativeFilterDefaultValue(testItems.filterDefaultValue); - }); + // apply second filter value + applyNativeFilterValueWithIndex(1, 'United States'); - it('User can add a new native filter', () => { - let filterKey: string; - const removeFirstChar = (search: string) => - search.split('').slice(1, search.length).join(''); - cy.location().then(loc => { - const queryParams = qs.parse(removeFirstChar(loc.search)); - filterKey = queryParams.native_filters_key as string; - expect(typeof filterKey).eq('string'); - }); - enterNativeFilterEditModal(); - addCountryNameFilter(); - saveNativeFilterSettings(WORLD_HEALTH_CHARTS); - cy.location().then(loc => { - const queryParams = qs.parse(removeFirstChar(loc.search)); - const newfilterKey = queryParams.native_filters_key; - expect(newfilterKey).eq(filterKey); + // verify number of available options for third filter - should be decreased to only one + getNativeFilterPlaceholderWithIndex(0).should('have.text', '1 option'); }); - cy.wait(3000); - cy.get(nativeFilters.modal.container).should('not.exist'); - }); - it('User can undo deleting a native filter', () => { - enterNativeFilterEditModal(); - addCountryCodeFilter(); - saveNativeFilterSettings(WORLD_HEALTH_CHARTS); - validateFilterNameOnDashboard( - testItems.topTenChart.filterColumnCountryCode, - ); - enterNativeFilterEditModal(); - cy.get(nativeFilters.filtersList.removeIcon).first().click(); - cy.get('[data-test="restore-filter-button"]').should('be.visible').click(); - cy.get(nativeFilters.modal.container) - .find(nativeFilters.filtersPanel.filterName) - .should( - 'have.attr', - 'value', - testItems.topTenChart.filterColumnCountryCode, + it('User can remove parent filters', () => { + prepareDashboardFilter([ + { name: 'region', column: 'region' }, + { name: 'country_name', column: 'country_name' }, + ]); + enterNativeFilterEditModal(); + selectFilter(1); + // Select dependdent option and auto use platform for genre + cy.get(nativeFilters.filterConfigurationSections.displayedSection).within( + () => { + cy.contains('Values are dependent on other filters') + .should('be.visible') + .click(); + }, ); - }); - - it('User can create a time grain filter', () => { - enterNativeFilterEditModal(); - fillNativeFilterForm( - testItems.filterType.timeGrain, - testItems.filterType.timeGrain, - testItems.datasetForNativeFilter, - ); - saveNativeFilterSettings(WORLD_HEALTH_CHARTS); - applyNativeFilterValueWithIndex(0, testItems.filterTimeGrain); - cy.get(nativeFilters.applyFilter).click(); - cy.url().then(u => { - const ur = new URL(u); - expect(ur.search).to.include('native_filters'); + saveNativeFilterSettings([SAMPLE_CHART]); + enterNativeFilterEditModal(); + cy.get(nativeFilters.modal.tabsList.removeTab) + .should('be.visible') + .first() + .click({ + force: true, + }); + saveNativeFilterSettings([SAMPLE_CHART]); + cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { + cy.contains(testItems.filterDefaultValue).should('be.visible'); + cy.contains(testItems.filterOtherCountry).should('be.visible'); + }); }); - validateFilterNameOnDashboard(testItems.filterType.timeGrain); - validateFilterContentOnDashboard(testItems.filterTimeGrain); }); - it.skip('User can create a time range filter', () => { - enterNativeFilterEditModal(); - fillNativeFilterForm( - testItems.filterType.timeRange, - testItems.filterType.timeRange, - ); - saveNativeFilterSettings(WORLD_HEALTH_CHARTS); - cy.get(dashboardView.salesDashboardSpecific.vehicleSalesFilterTimeRange) - .should('be.visible') - .click(); - applyAdvancedTimeRangeFilterOnDashboard('2005-12-17', '2006-12-17'); - cy.url().then(u => { - const ur = new URL(u); - expect(ur.search).to.include('native_filters'); + describe('Nativefilters basic interactions', () => { + before(() => { + cy.createSampleDashboards(); + visitDashboard(); }); - validateFilterNameOnDashboard(testItems.filterType.timeRange); - cy.get(nativeFilters.filterFromDashboardView.timeRangeFilterContent) - .contains('2005-12-17') - .should('be.visible'); - }); - it.skip('User can create a time column filter', () => { - enterNativeFilterEditModal(); - fillNativeFilterForm( - testItems.filterType.timeColumn, - testItems.filterType.timeColumn, - testItems.datasetForNativeFilter, - ); - saveNativeFilterSettings(WORLD_HEALTH_CHARTS); - cy.intercept(`/api/v1/chart/data?form_data=**`).as('chart'); - cy.get(nativeFilters.modal.container).should('not.exist'); - // assert that native filter is created - validateFilterNameOnDashboard(testItems.filterType.timeColumn); - applyNativeFilterValueWithIndex(0, testItems.topTenChart.filterColumnYear); - cy.get(nativeFilters.applyFilter).click({ force: true }); - cy.wait('@chart'); - validateFilterContentOnDashboard(testItems.topTenChart.filterColumnYear); - }); + beforeEach(() => { + closeFilterModal(); + }); - it('User can create a numerical range filter', () => { - enterNativeFilterEditModal(); - fillNativeFilterForm( - testItems.filterType.numerical, - testItems.filterNumericalColumn, - testItems.datasetForNativeFilter, - testItems.filterNumericalColumn, - ); - saveNativeFilterSettings(WORLD_HEALTH_CHARTS); - // assertions - cy.get(nativeFilters.slider.slider).should('be.visible').click('center'); - // cy.get(sqlLabView.tooltip).should('be.visible'); - cy.intercept(`/superset/explore_json/*`).as('slices'); - cy.get(nativeFilters.applyFilter).click(); - cy.wait('@slices'); - // assert that the url contains 'native_filters' in the url - cy.url().then(u => { - const ur = new URL(u); - expect(ur.search).to.include('native_filters'); - // assert that the start handle has a value - cy.get(nativeFilters.slider.startHandle) - .invoke('attr', 'aria-valuenow') - .should('exist'); - // assert that the end handle has a value - cy.get(nativeFilters.slider.endHandle) - .invoke('attr', 'aria-valuenow') - .should('exist'); - // assert slider text matches what we should have - cy.get(nativeFilters.slider.sliderText).should('have.text', '49'); + it('User can expand / retract native filter sidebar on a dashboard', () => { + cy.get(nativeFilters.addFilterButton.button).should('not.exist'); + expandFilterOnLeftPanel(); + cy.get(nativeFilters.filterFromDashboardView.createFilterButton).should( + 'be.visible', + ); + cy.get(nativeFilters.filterFromDashboardView.expand).should( + 'not.be.visible', + ); + collapseFilterOnLeftPanel(); }); - }); - it('User can undo deleting a native filter', () => { - enterNativeFilterEditModal(); - addCountryNameFilter(); - saveNativeFilterSettings(WORLD_HEALTH_CHARTS); - validateFilterNameOnDashboard(testItems.topTenChart.filterColumn); - enterNativeFilterEditModal(); - undoDeleteNativeFilter(); - }); + it('User can enter filter edit pop-up by clicking on native filter edit icon', () => { + enterNativeFilterEditModal(false); + }); - it('User can cancel changes in native filter', () => { - enterNativeFilterEditModal(); - fillNativeFilterForm( - testItems.filterType.value, - 'suffix', - testItems.datasetForNativeFilter, - ); - cancelNativeFilterSettings(); - enterNativeFilterEditModal(); - cy.get(nativeFilters.filtersList.removeIcon).first().click(); - cy.contains('You have removed this filter.').should('be.visible'); - saveNativeFilterSettings(WORLD_HEALTH_CHARTS); - }); + it('User can delete a native filter', () => { + enterNativeFilterEditModal(false); + cy.get(nativeFilters.filtersList.removeIcon).first().click(); + cy.contains('Restore Filter').should('not.exist', { timeout: 10000 }); + }); - it('User can create a value filter', () => { - enterNativeFilterEditModal(); - addCountryNameFilter(); - cy.get(nativeFilters.filtersPanel.filterTypeInput) - .find(nativeFilters.filtersPanel.filterTypeItem) - .should('have.text', testItems.filterType.value); - saveNativeFilterSettings(WORLD_HEALTH_CHARTS); - validateFilterNameOnDashboard(testItems.topTenChart.filterColumn); - }); + it('User can cancel creating a new filter', () => { + enterNativeFilterEditModal(false); + cancelNativeFilterSettings(); + }); - it('User can apply value filter with selected values', () => { - enterNativeFilterEditModal(); - addCountryNameFilter(); - saveNativeFilterSettings(WORLD_HEALTH_CHARTS); - applyNativeFilterValueWithIndex(0, testItems.filterDefaultValue); - cy.get(nativeFilters.applyFilter).click(); - cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { - cy.contains(testItems.filterDefaultValue).should('be.visible'); - cy.contains(testItems.filterOtherCountry).should('not.exist'); + it('Verify setting options and tooltips for value filter', () => { + enterNativeFilterEditModal(false); + cy.contains('Filter value is required').should('be.visible').click(); + checkNativeFilterTooltip(0, nativeFilterTooltips.defaultValue); + cy.get(nativeFilters.modal.container).should('be.visible'); + valueNativeFilterOptions.forEach(el => { + cy.contains(el); + }); + cy.contains('Values are dependent on other filters').should('not.exist'); + cy.get( + nativeFilters.filterConfigurationSections.checkedCheckbox, + ).contains('Can select multiple values'); + checkNativeFilterTooltip(1, nativeFilterTooltips.required); + checkNativeFilterTooltip(2, nativeFilterTooltips.defaultToFirstItem); + checkNativeFilterTooltip(3, nativeFilterTooltips.searchAllFilterOptions); + checkNativeFilterTooltip(4, nativeFilterTooltips.inverseSelection); + clickOnAddFilterInModal(); + cy.contains('Values are dependent on other filters').should('exist'); }); }); - it('User can stop filtering when filter is removed', () => { - enterNativeFilterEditModal(); - addCountryNameFilter(); - inputNativeFilterDefaultValue(testItems.filterDefaultValue); - saveNativeFilterSettings(WORLD_HEALTH_CHARTS); - cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { - cy.contains(testItems.filterDefaultValue).should('be.visible'); - cy.contains(testItems.filterOtherCountry).should('not.exist'); - }); - cy.get(nativeFilters.filterItem) - .contains(testItems.filterDefaultValue) - .should('be.visible'); - validateFilterNameOnDashboard(testItems.topTenChart.filterColumn); - enterNativeFilterEditModal(); - deleteNativeFilter(); - saveNativeFilterSettings(WORLD_HEALTH_CHARTS); - cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { - cy.contains(testItems.filterDefaultValue).should('be.visible'); - cy.contains(testItems.filterOtherCountry).should('be.visible'); + describe('Nativefilters initial state not required', () => { + beforeEach(() => { + cy.createSampleDashboards(); }); - }); -}); -describe.skip('Nativefilters', () => { - before(() => { - cy.login(); - cy.visit(DASHBOARD_LIST); - cy.get('[data-test="new-dropdown"]').click(); - cy.get('[data-test="menu-item-Dashboard"]').click({ force: true }); - cy.get('[data-test="editable-title-input"]') - .click() - .clear() - .type(`${dashboard}{enter}`); - cy.get('[data-test="header-save-button"]').click(); - cy.visit(CHART_LIST); - cy.get('[data-test="search-input"]').type('Treemap{enter}'); - cy.get('[data-test="Treemap-list-chart-title"]') - .should('be.visible', { timeout: 5000 }) - .click(); - cy.get('[data-test="edit-dashboard-button"]').click(); - cy.get('[data-test="save-chart-modal-select-dashboard-form"]') - .find('input[aria-label="Select a dashboard"]') - .type(`${dashboard}`, { force: true }); - cy.get('[data-test="btn-modal-save"]').click(); - }); - beforeEach(() => { - cy.login(); - cy.visit(DASHBOARD_LIST); - cy.get('[data-test="search-input"]').click().type(`${dashboard}{enter}`); - cy.contains('[data-test="cell-text"]', `${dashboard}`).click(); - }); + it("User can check 'Filter has default value'", () => { + prepareDashboardFilter([ + { name: 'country_name', column: 'country_name' }, + ]); + enterNativeFilterEditModal(); + inputNativeFilterDefaultValue(testItems.filterDefaultValue); + }); - it('should show filter bar and allow user to create filters ', () => { - cy.get('[data-test="filter-bar"]').should('be.visible'); - cy.get('[data-test="filter-bar__expand-button"]').click(); - cy.get('[data-test="filter-bar__create-filter"]').click(); - cy.get('.ant-modal').should('be.visible'); - - cy.get('.ant-modal') - .find('[data-test="filters-config-modal__name-input"]') - .click() - .type('Country name'); - - cy.get('.ant-modal') - .find('[data-test="filters-config-modal__datasource-input"]') - .click() - .type('wb_health_population'); - - cy.get( - '.ant-modal [data-test="filters-config-modal__datasource-input"] .Select__menu', - ) - .contains('wb_health_population') - .click(); - - // hack for unclickable country_name - cy.get('.ant-modal').find('[data-test="field-input"]').type('country_name'); - cy.get('.ant-modal') - .find('[data-test="field-input"]') - .type('{downarrow}{downarrow}{enter}'); - cy.get('[data-test="apply-changes-instantly-checkbox"]').check(); - cy.get('.ant-modal-footer') - .find('[data-test="native-filter-modal-save-button"]') - .should('be.visible') - .click(); - }); + it('User can add a new native filter', () => { + prepareDashboardFilter([]); - it('should show newly added filter in filter bar menu', () => { - cy.get('[data-test="filter-bar"]').should('be.visible'); - cy.get('[data-test="filter-control-name"]').should('be.visible'); - cy.get('[data-test="form-item-value"]').should('be.visible'); - }); - it('should filter dashboard with selected filter value', () => { - cy.get('[data-test="form-item-value"]').should('be.visible').click(); - cy.get('.ant-select-selection-search').type('Hong Kong{enter}'); - cy.get('[data-test="filter-bar__apply-button"]').click(); - cy.get('.treemap').within(() => { - cy.contains('HKG').should('be.visible'); - cy.contains('USA').should('not.exist'); - }); - }); - it('default value is respected after revisit', () => { - cy.get('[data-test="filter-bar__create-filter"]').click(); - cy.get('.ant-modal').should('be.visible'); - // TODO: replace with proper wait for filter to finish loading - cy.wait(1000); - cy.get('[data-test="default-input"]').click(); - cy.get('.ant-modal') - .find('[data-test="default-input"]') - .type('Sweden{enter}'); - cy.get('[data-test="native-filter-modal-save-button"]') - .should('be.visible') - .click(); - cy.visit(DASHBOARD_LIST); - cy.get('[data-test="search-input"]').click().type(`${dashboard}{enter}`); - cy.contains('[data-test="cell-text"]', `${dashboard}`).click(); - cy.get('.treemap').within(() => { - cy.contains('SWE').should('be.visible'); - cy.contains('USA').should('not.exist'); - }); - cy.contains('Sweden'); - }); - it('should allow for deleted filter restore', () => { - cy.get('[data-test="filter-bar__create-filter"]').click(); - cy.get('.ant-modal').should('be.visible'); - cy.get('.ant-tabs-nav-list').within(() => { - cy.get('.ant-tabs-tab-remove').click(); + let filterKey: string; + const removeFirstChar = (search: string) => + search.split('').slice(1, search.length).join(''); + cy.location().then(loc => { + const queryParams = qs.parse(removeFirstChar(loc.search)); + filterKey = queryParams.native_filters_key as string; + expect(typeof filterKey).eq('string'); + }); + enterNativeFilterEditModal(); + addCountryNameFilter(); + saveNativeFilterSettings([SAMPLE_CHART]); + cy.location().then(loc => { + const queryParams = qs.parse(removeFirstChar(loc.search)); + const newfilterKey = queryParams.native_filters_key; + expect(newfilterKey).eq(filterKey); + }); + cy.get(nativeFilters.modal.container).should('not.exist'); }); - cy.get('[data-test="undo-button"]').should('be.visible').click(); - cy.get('.ant-tabs-nav-list').within(() => { - cy.get('.ant-tabs-tab-remove').click(); + it('User can restore a deleted native filter', () => { + prepareDashboardFilter([ + { name: 'country_code', column: 'country_code' }, + ]); + enterNativeFilterEditModal(); + cy.get(nativeFilters.filtersList.removeIcon).first().click(); + cy.get('[data-test="restore-filter-button"]') + .should('be.visible') + .click(); + cy.get(nativeFilters.modal.container) + .find(nativeFilters.filtersPanel.filterName) + .should( + 'have.attr', + 'value', + testItems.topTenChart.filterColumnCountryCode, + ); }); - cy.get('[data-test="restore-filter-button"]').should('be.visible').click(); - }); - it('should stop filtering when filter is removed', () => { - cy.get('[data-test="filter-bar__create-filter"]').click(); - cy.get('.ant-modal').should('be.visible'); - cy.get('.ant-tabs-nav-list').within(() => { - cy.get('.ant-tabs-tab-remove').click(); - }); - cy.get('.ant-modal-footer') - .find('[data-test="native-filter-modal-save-button"]') - .should('be.visible') - .click(); - cy.get('.treemap').within(() => { - cy.contains('HKG').should('be.visible'); - cy.contains('USA').should('be.visible'); + it('User can create a time grain filter', () => { + prepareDashboardFilter([]); + enterNativeFilterEditModal(); + fillNativeFilterForm( + testItems.filterType.timeGrain, + testItems.filterType.timeGrain, + testItems.datasetForNativeFilter, + ); + saveNativeFilterSettings([SAMPLE_CHART]); + applyNativeFilterValueWithIndex(0, testItems.filterTimeGrain); + cy.get(nativeFilters.applyFilter).click(); + cy.url().then(u => { + const ur = new URL(u); + expect(ur.search).to.include('native_filters'); + }); + validateFilterNameOnDashboard(testItems.filterType.timeGrain); + validateFilterContentOnDashboard(testItems.filterTimeGrain); }); - }); - describe('Parent Filters', () => { - it('should allow for creating parent filters ', () => { - cy.get('[data-test="filter-bar"]').should('be.visible'); - cy.get('[data-test="filter-bar__expand-button"]').click(); - cy.get('[data-test="filter-bar__create-filter"]').click(); - cy.get('.ant-modal').should('be.visible'); - - cy.get('.ant-modal') - .find('[data-test="filters-config-modal__name-input"]') - .click() - .type('Country name'); - - cy.get('.ant-modal') - .find('[data-test="filters-config-modal__datasource-input"]') - .click() - .type('wb_health_population'); - - cy.get( - '.ant-modal [data-test="filters-config-modal__datasource-input"] .Select__menu', - ) - .contains('wb_health_population') - .click(); - // hack for unclickable country_name - cy.get('.ant-modal') - .find('[data-test="field-input"]') - .type('country_name'); - cy.get('.ant-modal') - .find('[data-test="field-input"]') - .type('{downarrow}{downarrow}{enter}'); - cy.get('[data-test="apply-changes-instantly-checkbox"]').check(); - cy.get('.ant-modal-footer') - .find('[data-test="native-filter-modal-save-button"]') + it.skip('User can create a time range filter', () => { + enterNativeFilterEditModal(); + fillNativeFilterForm( + testItems.filterType.timeRange, + testItems.filterType.timeRange, + ); + saveNativeFilterSettings(WORLD_HEALTH_CHARTS); + cy.get(dashboardView.salesDashboardSpecific.vehicleSalesFilterTimeRange) .should('be.visible') .click(); + applyAdvancedTimeRangeFilterOnDashboard('2005-12-17', '2006-12-17'); + cy.url().then(u => { + const ur = new URL(u); + expect(ur.search).to.include('native_filters'); + }); + validateFilterNameOnDashboard(testItems.filterType.timeRange); + cy.get(nativeFilters.filterFromDashboardView.timeRangeFilterContent) + .contains('2005-12-17') + .should('be.visible'); + }); - cy.get('[data-test="filter-bar__create-filter"]').click(); - cy.get('.ant-modal').first().should('be.visible'); - cy.get('[data-test=add-filter-button]').first().click(); - - cy.get('.ant-modal') - .find('[data-test="filters-config-modal__name-input"]') - .last() - .click() - .type('Region Name'); - - cy.get('.ant-modal') - .find('[data-test="filters-config-modal__datasource-input"]') - .last() - .click() - .type('wb_health_population'); + it.skip('User can create a time column filter', () => { + enterNativeFilterEditModal(); + fillNativeFilterForm( + testItems.filterType.timeColumn, + testItems.filterType.timeColumn, + testItems.datasetForNativeFilter, + ); + saveNativeFilterSettings(WORLD_HEALTH_CHARTS); + cy.intercept(`/api/v1/chart/data?form_data=**`).as('chart'); + cy.get(nativeFilters.modal.container).should('not.exist'); + // assert that native filter is created + validateFilterNameOnDashboard(testItems.filterType.timeColumn); + applyNativeFilterValueWithIndex( + 0, + testItems.topTenChart.filterColumnYear, + ); + cy.get(nativeFilters.applyFilter).click({ force: true }); + cy.wait('@chart'); + validateFilterContentOnDashboard(testItems.topTenChart.filterColumnYear); + }); - cy.get( - '.ant-modal [data-test="filters-config-modal__datasource-input"] .Select__menu', - ) - .last() - .contains('wb_health_population') - .click(); + it('User can create a numerical range filter', () => { + visitDashboard(); + enterNativeFilterEditModal(false); + fillNativeFilterForm( + testItems.filterType.numerical, + testItems.filterNumericalColumn, + testItems.datasetForNativeFilter, + testItems.filterNumericalColumn, + ); + saveNativeFilterSettings([]); + // assertions + cy.get(nativeFilters.slider.slider).should('be.visible').click('center'); + cy.get(nativeFilters.applyFilter).click(); + // assert that the url contains 'native_filters' in the url + cy.url().then(u => { + const ur = new URL(u); + expect(ur.search).to.include('native_filters'); + // assert that the start handle has a value + cy.get(nativeFilters.slider.startHandle) + .invoke('attr', 'aria-valuenow') + .should('exist'); + // assert that the end handle has a value + cy.get(nativeFilters.slider.endHandle) + .invoke('attr', 'aria-valuenow') + .should('exist'); + // assert slider text matches what we should have + cy.get(nativeFilters.slider.sliderText).should('have.text', '49'); + }); + }); - // hack for unclickable country_name - cy.get('.ant-modal') - .find('[data-test="field-input"]') - .last() - .type('region'); - cy.get('.ant-modal') - .find('[data-test="field-input"]') - .last() - .type('{downarrow}{downarrow}{downarrow}{downarrow}{enter}'); + it('User can undo deleting a native filter', () => { + prepareDashboardFilter([ + { name: 'country_name', column: 'country_name' }, + ]); + enterNativeFilterEditModal(); + undoDeleteNativeFilter(); + cy.get(nativeFilters.modal.container) + .find(nativeFilters.filtersPanel.filterName) + .should('have.attr', 'value', testItems.topTenChart.filterColumn); + }); - cy.get('[data-test="apply-changes-instantly-checkbox"]').last().check(); - cy.get('.ant-modal') - .find('[data-test="parent-filter-input"]') - .last() - .type('{downarrow}{enter}'); + it('User can cancel changes in native filter', () => { + visitDashboard(); + enterNativeFilterEditModal(false); + fillNativeFilterForm( + testItems.filterType.value, + 'suffix', + testItems.datasetForNativeFilter, + ); + cancelNativeFilterSettings(); + enterNativeFilterEditModal(); + cy.get(nativeFilters.filtersList.removeIcon).first().click(); + cy.contains('You have removed this filter.').should('be.visible'); + }); - cy.get('.ant-modal-footer') - .find('[data-test="native-filter-modal-save-button"]') - .first() - .should('be.visible') - .click(); - cy.get('[data-test="filter-icon"]').should('be.visible'); + it('User can create a value filter', () => { + visitDashboard(); + enterNativeFilterEditModal(false); + addCountryNameFilter(); + cy.get(nativeFilters.filtersPanel.filterTypeInput) + .find(nativeFilters.filtersPanel.filterTypeItem) + .should('have.text', testItems.filterType.value); + saveNativeFilterSettings([]); + validateFilterNameOnDashboard(testItems.topTenChart.filterColumn); }); - it('should parent filter be working', () => { - cy.get('.treemap').within(() => { - cy.contains('SMR').should('be.visible'); - cy.contains('Europe & Central Asia').should('be.visible'); - cy.contains('South Asia').should('be.visible'); - }); - cy.get('[data-test="form-item-value"]').should('be.visible').click(); - cy.get('.ant-popover-inner-content').within(() => { - cy.get('[data-test="form-item-value"]') - .should('be.visible') - .first() - .type('San Marino{enter}'); - cy.get('[data-test="form-item-value"]') - .should('be.visible') - .last() - .type('Europe & Central Asia{enter}'); - }); - cy.get('.treemap').within(() => { - cy.contains('SMR').should('be.visible'); - cy.contains('Europe & Central Asia').should('be.visible'); - cy.contains('South Asia').should('not.exist'); + it('User can apply value filter with selected values', () => { + prepareDashboardFilter([ + { name: 'country_name', column: 'country_name' }, + ]); + applyNativeFilterValueWithIndex(0, testItems.filterDefaultValue); + cy.get(nativeFilters.applyFilter).click(); + cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { + cy.contains(testItems.filterDefaultValue).should('be.visible'); + cy.contains(testItems.filterOtherCountry).should('not.exist'); }); }); - it('should stop filtering when parent filter is removed', () => { - cy.get('[data-test="filter-bar__create-filter"]').click(); - cy.get('.ant-modal').should('be.visible'); - cy.get('.ant-tabs-nav-list').within(() => { - cy.get('.ant-tabs-tab-remove').click({ multiple: true }); + it('User can stop filtering when filter is removed', () => { + prepareDashboardFilter([ + { name: 'country_name', column: 'country_name' }, + ]); + enterNativeFilterEditModal(); + inputNativeFilterDefaultValue(testItems.filterDefaultValue); + saveNativeFilterSettings([SAMPLE_CHART]); + cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { + cy.contains(testItems.filterDefaultValue).should('be.visible'); + cy.contains(testItems.filterOtherCountry).should('not.exist'); }); - cy.get('.ant-modal-footer') - .find('[data-test="native-filter-modal-save-button"]') - .should('be.visible') - .click(); - cy.get('.treemap').within(() => { - cy.contains('HKG').should('be.visible'); - cy.contains('USA').should('be.visible'); + cy.get(nativeFilters.filterItem) + .contains(testItems.filterDefaultValue) + .should('be.visible'); + validateFilterNameOnDashboard(testItems.topTenChart.filterColumn); + enterNativeFilterEditModal(); + deleteNativeFilter(); + saveNativeFilterSettings([SAMPLE_CHART]); + cy.get(dataTestChartName(testItems.topTenChart.name)).within(() => { + cy.contains(testItems.filterDefaultValue).should('be.visible'); + cy.contains(testItems.filterOtherCountry).should('be.visible'); }); }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts index 9c3ce8be0296c..f633cae9b2448 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/utils.ts @@ -18,7 +18,7 @@ */ import { dashboardView, nativeFilters } from 'cypress/support/directories'; -import { waitForChartLoad } from 'cypress/utils'; +import { ChartSpec, waitForChartLoad } from 'cypress/utils'; export const WORLD_HEALTH_CHARTS = [ { name: '% Rural', viz: 'world_map' }, @@ -31,7 +31,7 @@ export const WORLD_HEALTH_CHARTS = [ { name: 'Life Expectancy VS Rural %', viz: 'bubble' }, { name: 'Treemap', viz: 'treemap' }, { name: 'Box plot', viz: 'box_plot' }, -] as const; +] as ChartSpec[]; export const ECHARTS_CHARTS = [ { name: 'Number of Girls', viz: 'big_number_total' }, @@ -39,7 +39,7 @@ export const ECHARTS_CHARTS = [ { name: 'Box plot', viz: 'box_plot' }, { name: 'Genders', viz: 'pie' }, { name: 'Energy Force Layout', viz: 'graph_chart' }, -] as const; +] as ChartSpec[]; export const testItems = { dashboard: 'Cypress test Dashboard', @@ -144,6 +144,18 @@ export function interceptUnfav() { cy.intercept(`/superset/favstar/Dashboard/*/unselect/`).as('unselect'); } +export function interceptDataset() { + cy.intercept('GET', `/api/v1/dataset/*`).as('getDataset'); +} + +export function interceptCharts() { + cy.intercept('GET', `/api/v1/dashboard/*/charts`).as('getCharts'); +} + +export function interceptDatasets() { + cy.intercept('GET', `/api/v1/dashboard/*/datasets`).as('getDatasets'); +} + export function setFilter(filter: string, option: string) { interceptFiltering(); @@ -184,11 +196,15 @@ export function collapseFilterOnLeftPanel() { * @returns {None} * @summary helper for enter native filter edit modal ************************************************************************* */ -export function enterNativeFilterEditModal() { +export function enterNativeFilterEditModal(waitForDataset = true) { + interceptDataset(); cy.get(nativeFilters.filterFromDashboardView.createFilterButton).click({ force: true, }); cy.get(nativeFilters.modal.container).should('be.visible'); + if (waitForDataset) { + cy.wait('@getDataset'); + } } /** ************************************************************************ @@ -308,7 +324,7 @@ export function addParentFilterWithValue(index: number, value: string) { * @returns {None} * @summary helper for save native filters settings ************************************************************************* */ -export function saveNativeFilterSettings(charts: any) { +export function saveNativeFilterSettings(charts: ChartSpec[]) { cy.get(nativeFilters.modal.footer) .contains('Save') .should('be.visible') @@ -333,34 +349,10 @@ export function cancelNativeFilterSettings() { cy.get(nativeFilters.modal.footer) .find(nativeFilters.modal.yesCancelButton) .contains('cancel') - .should('be.visible') - .click(); + .click({ force: true }); cy.get(nativeFilters.modal.container).should('not.exist'); } -/** ************************************************************************ - * Close dashboard toast message - * @returns {None} - * @summary helper for close dashboard toast message in order to make test stable - ************************************************************************* */ -export function closeDashboardToastMessage() { - cy.get('body').then($body => { - if ($body.find(dashboardView.dashboardAlert.modal).length > 0) { - // evaluates as true if button exists at all - cy.get(dashboardView.dashboardAlert.modal).then($header => { - if ($header.is(':visible')) { - cy.get(dashboardView.dashboardAlert.closeButton).click({ - force: true, - }); - cy.get(dashboardView.dashboardAlert.closeButton).should('not.exist', { - timeout: 10000, - }); - } - }); - } - }); -} - /** ************************************************************************ * Validate filter name on dashboard * @param name: filter name to validate @@ -484,31 +476,3 @@ export function addCountryNameFilter() { testItems.topTenChart.filterColumn, ); } - -/** ************************************************************************ - * add filter for test column 'Region' - * @return {null} - * @summary helper for add filter for test column 'Region' - ************************************************************************* */ -export function addRegionFilter() { - fillNativeFilterForm( - testItems.filterType.value, - testItems.topTenChart.filterColumnRegion, - testItems.datasetForNativeFilter, - testItems.topTenChart.filterColumnRegion, - ); -} - -/** ************************************************************************ - * add filter for test column 'Country Code' - * @return {null} - * @summary helper for add filter for test column 'Country Code' - ************************************************************************* */ -export function addCountryCodeFilter() { - fillNativeFilterForm( - testItems.filterType.value, - testItems.topTenChart.filterColumnCountryCode, - testItems.datasetForNativeFilter, - testItems.topTenChart.filterColumnCountryCode, - ); -} diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DefaultValue.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DefaultValue.tsx index 07f785484d52d..e4ae521764fc9 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DefaultValue.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DefaultValue.tsx @@ -51,7 +51,7 @@ const DefaultValue: FC = ({ const formFilter = (form.getFieldValue('filters') || {})[filterId]; const queriesData = formFilter?.defaultValueQueriesData; const loading = hasDataset && queriesData === null; - const value = formFilter.defaultDataMask?.filterState?.value; + const value = formFilter?.defaultDataMask?.filterState?.value; const isMissingRequiredValue = hasDefaultValue && (value === null || value === undefined); return loading ? ( @@ -71,7 +71,7 @@ const DefaultValue: FC = ({ hooks={{ setDataMask }} enableNoResults={enableNoResults} filterState={{ - ...formFilter.defaultDataMask?.filterState, + ...formFilter?.defaultDataMask?.filterState, validateMessage: isMissingRequiredValue && t('Value is required'), validateStatus: isMissingRequiredValue && 'error', }} From ba1257c0463b3863e1b12e12b27c1bebc598acaa Mon Sep 17 00:00:00 2001 From: geido Date: Thu, 8 Sep 2022 18:58:26 +0300 Subject: [PATCH 26/31] Remove unused command --- .../cypress-base/cypress/support/index.d.ts | 4 -- .../cypress-base/cypress/support/index.ts | 42 ------------------- 2 files changed, 46 deletions(-) diff --git a/superset-frontend/cypress-base/cypress/support/index.d.ts b/superset-frontend/cypress-base/cypress/support/index.d.ts index cb22bc1b89598..b884c1c430bb5 100644 --- a/superset-frontend/cypress-base/cypress/support/index.d.ts +++ b/superset-frontend/cypress-base/cypress/support/index.d.ts @@ -72,10 +72,6 @@ declare namespace Cypress { */ createSampleDashboards(): void; createSampleCharts(): void; - copyDashboard( - originalDashboardName: string, - copyDashboardName: string, - ): void; /** * Delete diff --git a/superset-frontend/cypress-base/cypress/support/index.ts b/superset-frontend/cypress-base/cypress/support/index.ts index 77dfa2bcc87df..c0b90f14f515a 100644 --- a/superset-frontend/cypress-base/cypress/support/index.ts +++ b/superset-frontend/cypress-base/cypress/support/index.ts @@ -328,48 +328,6 @@ Cypress.Commands.add('getDashboards', () => .then(resp => resp.body.result), ); -Cypress.Commands.add( - 'copyDashboard', - (originalDashboardName, copyDashboardName) => - cy.getDashboards().then((sampleDashboards: any) => { - cy.deleteDashboardByName(copyDashboardName, false).then(() => { - const dashboard = sampleDashboards.find( - (d: any) => d.dashboard_title === originalDashboardName, - ); - const slugifiedTitle = copyDashboardName - .toLowerCase() - .replace(/ /g, '-'); - const body = new FormData(); - body.append( - 'data', - JSON.stringify({ - dashboard_title: copyDashboardName, - slug: slugifiedTitle, - duplicate_slices: false, - }), - ); - if (dashboard) { - cy.request({ - method: 'POST', - url: `superset/copy_dash/${dashboard.id}/`, - body, - headers: { - 'content-type': 'multipart/form-data', - Authorization: `Bearer ${TokenName}`, - }, - }).then(() => - cy.getDashboards().then((sampleDashboards: any) => { - const newDashboard = sampleDashboards.find( - (d: any) => d.dashboard_title === copyDashboardName, - ); - cy.visit(`/superset/dashboard/${newDashboard.id}/`); - }), - ); - } - }); - }), -); - Cypress.Commands.add('deleteChart', (id: number, failOnStatusCode = false) => cy .request({ From 7f864499083bfc7113c8a4282be7b09daf16e334 Mon Sep 17 00:00:00 2001 From: geido Date: Fri, 9 Sep 2022 15:02:45 +0300 Subject: [PATCH 27/31] Clean up --- .../cypress-base/cypress/fixtures/charts.json | 72 +++++++-------- .../cypress/fixtures/dashboards.json | 32 +++---- .../integration/chart_list/filter.test.ts | 8 +- .../integration/dashboard/editmode.test.ts | 2 +- .../integration/dashboard_list/filter.test.ts | 8 +- .../cypress-base/cypress/support/index.d.ts | 4 +- .../cypress-base/cypress/support/index.ts | 90 ++++++++++--------- 7 files changed, 110 insertions(+), 106 deletions(-) diff --git a/superset-frontend/cypress-base/cypress/fixtures/charts.json b/superset-frontend/cypress-base/cypress/fixtures/charts.json index b5a9bb8da89d9..6b342ee9a55ea 100644 --- a/superset-frontend/cypress-base/cypress/fixtures/charts.json +++ b/superset-frontend/cypress-base/cypress/fixtures/charts.json @@ -1,38 +1,38 @@ [ - { - "slice_name": "1 - Sample chart", - "description": "chart description", - "owners": [1], - "viz_type": "line", - "cache_timeout": 1000, - "datasource_id": 1, - "datasource_type": "table" - }, - { - "slice_name": "2 - Sample chart", - "description": "chart description", - "owners": [1], - "viz_type": "line", - "cache_timeout": 1000, - "datasource_id": 1, - "datasource_type": "table" - }, - { - "slice_name": "3 - Sample chart", - "description": "chart description", - "owners": [1], - "viz_type": "line", - "cache_timeout": 1000, - "datasource_id": 1, - "datasource_type": "table" - }, - { - "slice_name": "4 - Sample chart", - "description": "chart description", - "owners": [1], - "viz_type": "line", - "cache_timeout": 1000, - "datasource_id": 1, - "datasource_type": "table" - } + { + "slice_name": "1 - Sample chart", + "description": "chart description", + "owners": [1], + "viz_type": "line", + "cache_timeout": 1000, + "datasource_id": 1, + "datasource_type": "table" + }, + { + "slice_name": "2 - Sample chart", + "description": "chart description", + "owners": [1], + "viz_type": "line", + "cache_timeout": 1000, + "datasource_id": 1, + "datasource_type": "table" + }, + { + "slice_name": "3 - Sample chart", + "description": "chart description", + "owners": [1], + "viz_type": "line", + "cache_timeout": 1000, + "datasource_id": 1, + "datasource_type": "table" + }, + { + "slice_name": "4 - Sample chart", + "description": "chart description", + "owners": [1], + "viz_type": "line", + "cache_timeout": 1000, + "datasource_id": 1, + "datasource_type": "table" + } ] diff --git a/superset-frontend/cypress-base/cypress/fixtures/dashboards.json b/superset-frontend/cypress-base/cypress/fixtures/dashboards.json index cff35d04c9398..083d7647b9623 100644 --- a/superset-frontend/cypress-base/cypress/fixtures/dashboards.json +++ b/superset-frontend/cypress-base/cypress/fixtures/dashboards.json @@ -1,18 +1,18 @@ [ - { - "dashboard_title": "1 - Sample dashboard", - "slug": "1-sample-dashboard" - }, - { - "dashboard_title": "2 - Sample dashboard", - "slug": "2-sample-dashboard" - }, - { - "dashboard_title": "3 - Sample dashboard", - "slug": "3-sample-dashboard" - }, - { - "dashboard_title": "4 - Sample dashboard", - "slug": "4-sample-dashboard" - } + { + "dashboard_title": "1 - Sample dashboard", + "slug": "1-sample-dashboard" + }, + { + "dashboard_title": "2 - Sample dashboard", + "slug": "2-sample-dashboard" + }, + { + "dashboard_title": "3 - Sample dashboard", + "slug": "3-sample-dashboard" + }, + { + "dashboard_title": "4 - Sample dashboard", + "slug": "4-sample-dashboard" + } ] diff --git a/superset-frontend/cypress-base/cypress/integration/chart_list/filter.test.ts b/superset-frontend/cypress-base/cypress/integration/chart_list/filter.test.ts index dffbebd47214d..d925ce93c4817 100644 --- a/superset-frontend/cypress-base/cypress/integration/chart_list/filter.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/chart_list/filter.test.ts @@ -39,14 +39,14 @@ describe('Charts filters', () => { setFilter('Owner', 'alpha user'); cy.getBySel('styled-card').should('not.exist'); setFilter('Owner', 'admin user'); - cy.getBySel('styled-card').should('have.length', 20); + cy.getBySel('styled-card').should('exist'); }); it('should filter by created by correctly', () => { setFilter('Created by', 'alpha user'); cy.getBySel('styled-card').should('not.exist'); setFilter('Created by', 'admin user'); - cy.getBySel('styled-card').should('have.length', 20); + cy.getBySel('styled-card').should('exist'); }); it('should filter by viz type correctly', () => { @@ -73,14 +73,14 @@ describe('Charts filters', () => { setFilter('Owner', 'alpha user'); cy.getBySel('table-row').should('not.exist'); setFilter('Owner', 'admin user'); - cy.getBySel('table-row').should('have.length', 20); + cy.getBySel('table-row').should('exist'); }); it('should filter by created by correctly', () => { setFilter('Created by', 'alpha user'); cy.getBySel('table-row').should('not.exist'); setFilter('Created by', 'admin user'); - cy.getBySel('table-row').should('have.length', 20); + cy.getBySel('table-row').should('exist'); }); it('should filter by viz type correctly', () => { diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/editmode.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/editmode.test.ts index c4c05160c92a6..c7b5f312880ea 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/editmode.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/editmode.test.ts @@ -223,7 +223,7 @@ describe('Dashboard edit', () => { }); it('should remove added charts', () => { - dragComponent('% Rural'); + dragComponent('Pivot Table'); cy.getBySel('dashboard-component-chart-holder').should('have.length', 1); cy.getBySel('dashboard-delete-component-button').click(); cy.getBySel('dashboard-component-chart-holder').should('have.length', 0); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts index 8c70ff7a882dd..2949267b4306d 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard_list/filter.test.ts @@ -39,14 +39,14 @@ describe('Dashboards filters', () => { setFilter('Owner', 'alpha user'); cy.getBySel('styled-card').should('not.exist'); setFilter('Owner', 'admin user'); - cy.getBySel('styled-card').should('have.length', 1); + cy.getBySel('styled-card').should('exist'); }); it('should filter by created by correctly', () => { setFilter('Created by', 'alpha user'); cy.getBySel('styled-card').should('not.exist'); setFilter('Created by', 'admin user'); - cy.getBySel('styled-card').should('have.length', 1); + cy.getBySel('styled-card').should('exist'); }); it('should filter by published correctly', () => { @@ -66,14 +66,14 @@ describe('Dashboards filters', () => { setFilter('Owner', 'alpha user'); cy.getBySel('table-row').should('not.exist'); setFilter('Owner', 'admin user'); - cy.getBySel('table-row').should('have.length', 1); + cy.getBySel('table-row').should('exist'); }); it('should filter by created by correctly', () => { setFilter('Created by', 'alpha user'); cy.getBySel('table-row').should('not.exist'); setFilter('Created by', 'admin user'); - cy.getBySel('table-row').should('have.length', 1); + cy.getBySel('table-row').should('exist'); }); it('should filter by published correctly', () => { diff --git a/superset-frontend/cypress-base/cypress/support/index.d.ts b/superset-frontend/cypress-base/cypress/support/index.d.ts index b884c1c430bb5..c60580247e569 100644 --- a/superset-frontend/cypress-base/cypress/support/index.d.ts +++ b/superset-frontend/cypress-base/cypress/support/index.d.ts @@ -70,8 +70,8 @@ declare namespace Cypress { /** * Create */ - createSampleDashboards(): void; - createSampleCharts(): void; + createSampleDashboards(indexes?: number[]): void; + createSampleCharts(indexes?: number[]): void; /** * Delete diff --git a/superset-frontend/cypress-base/cypress/support/index.ts b/superset-frontend/cypress-base/cypress/support/index.ts index c0b90f14f515a..80a51fc409b5f 100644 --- a/superset-frontend/cypress-base/cypress/support/index.ts +++ b/superset-frontend/cypress-base/cypress/support/index.ts @@ -47,12 +47,12 @@ before(() => { }); Cypress.Commands.add('cleanDashboards', () => - cy.getDashboards().then((sampleDashboards: any) => { + cy.getDashboards().then((sampleDashboards?: Record[]) => { const deletableDashboards = []; for (let i = 0; i < DASHBOARD_FIXTURES.length; i += 1) { const fixture = DASHBOARD_FIXTURES[i]; - const isInDb = sampleDashboards.find( - (d: any) => d.dashboard_title === fixture.dashboard_title, + const isInDb = sampleDashboards?.find( + d => d.dashboard_title === fixture.dashboard_title, ); if (isInDb) { deletableDashboards.push(isInDb.id); @@ -78,12 +78,12 @@ Cypress.Commands.add('cleanDashboards', () => ); Cypress.Commands.add('cleanCharts', () => - cy.getCharts().then((sampleCharts: any) => { + cy.getCharts().then((sampleCharts?: Record[]) => { const deletableCharts = []; for (let i = 0; i < CHART_FIXTURES.length; i += 1) { const fixture = CHART_FIXTURES[i]; - const isInDb = sampleCharts.find( - (c: any) => c.slice_name === fixture.slice_name, + const isInDb = sampleCharts?.find( + c => c.slice_name === fixture.slice_name, ); if (isInDb) { deletableCharts.push(isInDb.id); @@ -237,46 +237,50 @@ Cypress.Commands.add( }, ); -Cypress.Commands.add('createSampleDashboards', () => +Cypress.Commands.add('createSampleDashboards', (indexes?: number[]) => cy.cleanDashboards().then(() => { for (let i = 0; i < DASHBOARD_FIXTURES.length; i += 1) { - cy.request({ - method: 'POST', - url: `/api/v1/dashboard/`, - body: DASHBOARD_FIXTURES[i], - failOnStatusCode: false, - headers: { - Cookie: `csrf_access_token=${window.localStorage.getItem( - 'access_token', - )}`, - 'Content-Type': 'application/json', - Authorization: `Bearer ${TokenName}`, - 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, - Referer: `${Cypress.config().baseUrl}/`, - }, - }); + if (indexes?.includes(i) || !indexes) { + cy.request({ + method: 'POST', + url: `/api/v1/dashboard/`, + body: DASHBOARD_FIXTURES[i], + failOnStatusCode: false, + headers: { + Cookie: `csrf_access_token=${window.localStorage.getItem( + 'access_token', + )}`, + 'Content-Type': 'application/json', + Authorization: `Bearer ${TokenName}`, + 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, + Referer: `${Cypress.config().baseUrl}/`, + }, + }); + } } }), ); -Cypress.Commands.add('createSampleCharts', () => +Cypress.Commands.add('createSampleCharts', (indexes?: number[]) => cy.cleanCharts().then(() => { for (let i = 0; i < CHART_FIXTURES.length; i += 1) { - cy.request({ - method: 'POST', - url: `/api/v1/chart/`, - body: CHART_FIXTURES[i], - failOnStatusCode: false, - headers: { - Cookie: `csrf_access_token=${window.localStorage.getItem( - 'access_token', - )}`, - 'Content-Type': 'application/json', - Authorization: `Bearer ${TokenName}`, - 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, - Referer: `${Cypress.config().baseUrl}/`, - }, - }); + if (indexes?.includes(i) || !indexes) { + cy.request({ + method: 'POST', + url: `/api/v1/chart/`, + body: CHART_FIXTURES[i], + failOnStatusCode: false, + headers: { + Cookie: `csrf_access_token=${window.localStorage.getItem( + 'access_token', + )}`, + 'Content-Type': 'application/json', + Authorization: `Bearer ${TokenName}`, + 'X-CSRFToken': `${window.localStorage.getItem('access_token')}`, + Referer: `${Cypress.config().baseUrl}/`, + }, + }); + } } }), ); @@ -284,9 +288,9 @@ Cypress.Commands.add('createSampleCharts', () => Cypress.Commands.add( 'deleteDashboardByName', (dashboardName: string, failOnStatusCode = false) => - cy.getDashboards().then((sampleDashboards: any) => { - const dashboard = sampleDashboards.find( - (d: any) => d.dashboard_title === dashboardName, + cy.getDashboards().then((sampleDashboards?: Record[]) => { + const dashboard = sampleDashboards?.find( + d => d.dashboard_title === dashboardName, ); if (dashboard) { cy.deleteDashboard(dashboard.id, failOnStatusCode); @@ -363,8 +367,8 @@ Cypress.Commands.add('getCharts', () => Cypress.Commands.add( 'deleteChartByName', (sliceName: string, failOnStatusCode = false) => - cy.getCharts().then((sampleCharts: any) => { - const chart = sampleCharts.find((c: any) => c.slice_name === sliceName); + cy.getCharts().then((sampleCharts?: Record[]) => { + const chart = sampleCharts?.find(c => c.slice_name === sliceName); if (chart) { cy.deleteChart(chart.id, failOnStatusCode); } From 1cb117a198489e265dc5d41450d09cdc1819a164 Mon Sep 17 00:00:00 2001 From: geido Date: Fri, 9 Sep 2022 15:46:23 +0300 Subject: [PATCH 28/31] Minor enhancements --- .../dashboard/nativeFilters.test.ts | 60 ++++++++++--------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts index 10c1fc88d6c5b..403faf1668e25 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts @@ -67,7 +67,9 @@ function visitDashboard() { cy.wait(500); } -function prepareDashboardFilter(filters: { name: string; column: string }[]) { +function prepareDashboardFilters( + filters: { name: string; column: string; datasetId: number }[], +) { cy.request({ method: 'GET', url: `api/v1/dashboard/1-sample-dashboard`, @@ -89,7 +91,7 @@ function prepareDashboardFilter(filters: { name: string; column: string }[]) { filterType: 'filter_select', targets: [ { - datasetId: 2, + datasetId: f.datasetId, column: { name: f.column }, }, ], @@ -198,8 +200,8 @@ describe('Native filters', () => { }); it('Verify that default value is respected after revisit', () => { - prepareDashboardFilter([ - { name: 'country_name', column: 'country_name' }, + prepareDashboardFilters([ + { name: 'country_name', column: 'country_name', datasetId: 2 }, ]); enterNativeFilterEditModal(); inputNativeFilterDefaultValue(testItems.filterDefaultValue); @@ -222,9 +224,9 @@ describe('Native filters', () => { }); it('User can create parent filters using "Values are dependent on other filters"', () => { - prepareDashboardFilter([ - { name: 'region', column: 'region' }, - { name: 'country_name', column: 'country_name' }, + prepareDashboardFilters([ + { name: 'region', column: 'region', datasetId: 2 }, + { name: 'country_name', column: 'country_name', datasetId: 2 }, ]); enterNativeFilterEditModal(); selectFilter(1); @@ -256,9 +258,9 @@ describe('Native filters', () => { }); it('user can delete dependent filter', () => { - prepareDashboardFilter([ - { name: 'region', column: 'region' }, - { name: 'country_name', column: 'country_name' }, + prepareDashboardFilters([ + { name: 'region', column: 'region', datasetId: 2 }, + { name: 'country_name', column: 'country_name', datasetId: 2 }, ]); enterNativeFilterEditModal(); selectFilter(1); @@ -292,10 +294,10 @@ describe('Native filters', () => { }); it('User can create filter depend on 2 other filters', () => { - prepareDashboardFilter([ - { name: 'region', column: 'region' }, - { name: 'country_name', column: 'country_name' }, - { name: 'country_code', column: 'country_code' }, + prepareDashboardFilters([ + { name: 'region', column: 'region', datasetId: 2 }, + { name: 'country_name', column: 'country_name', datasetId: 2 }, + { name: 'country_code', column: 'country_code', datasetId: 2 }, ]); enterNativeFilterEditModal(); selectFilter(2); @@ -345,9 +347,9 @@ describe('Native filters', () => { }); it('User can remove parent filters', () => { - prepareDashboardFilter([ - { name: 'region', column: 'region' }, - { name: 'country_name', column: 'country_name' }, + prepareDashboardFilters([ + { name: 'region', column: 'region', datasetId: 2 }, + { name: 'country_name', column: 'country_name', datasetId: 2 }, ]); enterNativeFilterEditModal(); selectFilter(1); @@ -439,15 +441,15 @@ describe('Native filters', () => { }); it("User can check 'Filter has default value'", () => { - prepareDashboardFilter([ - { name: 'country_name', column: 'country_name' }, + prepareDashboardFilters([ + { name: 'country_name', column: 'country_name', datasetId: 2 }, ]); enterNativeFilterEditModal(); inputNativeFilterDefaultValue(testItems.filterDefaultValue); }); it('User can add a new native filter', () => { - prepareDashboardFilter([]); + prepareDashboardFilters([]); let filterKey: string; const removeFirstChar = (search: string) => @@ -469,8 +471,8 @@ describe('Native filters', () => { }); it('User can restore a deleted native filter', () => { - prepareDashboardFilter([ - { name: 'country_code', column: 'country_code' }, + prepareDashboardFilters([ + { name: 'country_code', column: 'country_code', datasetId: 2 }, ]); enterNativeFilterEditModal(); cy.get(nativeFilters.filtersList.removeIcon).first().click(); @@ -487,7 +489,7 @@ describe('Native filters', () => { }); it('User can create a time grain filter', () => { - prepareDashboardFilter([]); + prepareDashboardFilters([]); enterNativeFilterEditModal(); fillNativeFilterForm( testItems.filterType.timeGrain, @@ -578,8 +580,8 @@ describe('Native filters', () => { }); it('User can undo deleting a native filter', () => { - prepareDashboardFilter([ - { name: 'country_name', column: 'country_name' }, + prepareDashboardFilters([ + { name: 'country_name', column: 'country_name', datasetId: 2 }, ]); enterNativeFilterEditModal(); undoDeleteNativeFilter(); @@ -614,8 +616,8 @@ describe('Native filters', () => { }); it('User can apply value filter with selected values', () => { - prepareDashboardFilter([ - { name: 'country_name', column: 'country_name' }, + prepareDashboardFilters([ + { name: 'country_name', column: 'country_name', datasetId: 2 }, ]); applyNativeFilterValueWithIndex(0, testItems.filterDefaultValue); cy.get(nativeFilters.applyFilter).click(); @@ -626,8 +628,8 @@ describe('Native filters', () => { }); it('User can stop filtering when filter is removed', () => { - prepareDashboardFilter([ - { name: 'country_name', column: 'country_name' }, + prepareDashboardFilters([ + { name: 'country_name', column: 'country_name', datasetId: 2 }, ]); enterNativeFilterEditModal(); inputNativeFilterDefaultValue(testItems.filterDefaultValue); From 9e2e3346a33e51250b9e48b56a0e4de7471993de Mon Sep 17 00:00:00 2001 From: geido Date: Mon, 12 Sep 2022 15:43:21 +0300 Subject: [PATCH 29/31] Add TODOs --- .../cypress/integration/alerts_and_reports/alerts.test.ts | 2 ++ .../cypress/integration/alerts_and_reports/reports.test.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alerts.test.ts b/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alerts.test.ts index 5135d653b1539..03af055a27ace 100644 --- a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alerts.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/alerts.test.ts @@ -37,5 +37,7 @@ describe('Alert list view', () => { cy.getBySel('sort-header').eq(6).contains('Owners'); cy.getBySel('sort-header').eq(7).contains('Modified'); cy.getBySel('sort-header').eq(8).contains('Active'); + // TODO Cypress won't recognize the Actions column + // cy.getBySel('sort-header').eq(9).contains('Actions'); }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/reports.test.ts b/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/reports.test.ts index 8080183eeb765..12fe43a165a4d 100644 --- a/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/reports.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/alerts_and_reports/reports.test.ts @@ -37,5 +37,7 @@ describe('Report list view', () => { cy.getBySel('sort-header').eq(6).contains('Owners'); cy.getBySel('sort-header').eq(7).contains('Modified'); cy.getBySel('sort-header').eq(8).contains('Active'); + // TODO Cypress won't recognize the Actions column + // cy.getBySel('sort-header').eq(9).contains('Actions'); }); }); From 24cee1417df925b99308f8a26d0973c6d62c36fc Mon Sep 17 00:00:00 2001 From: geido Date: Mon, 12 Sep 2022 16:07:14 +0300 Subject: [PATCH 30/31] Skip unused test --- .../new-chart-2022-09-09T14-22-31.728Z.jpg | Bin 0 -> 16879 bytes .../sqllab/_skip.sourcePanel.index.test.js | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 superset-frontend/cypress-base/cypress/downloads/new-chart-2022-09-09T14-22-31.728Z.jpg diff --git a/superset-frontend/cypress-base/cypress/downloads/new-chart-2022-09-09T14-22-31.728Z.jpg b/superset-frontend/cypress-base/cypress/downloads/new-chart-2022-09-09T14-22-31.728Z.jpg new file mode 100644 index 0000000000000000000000000000000000000000..81bcb35cff22523bdfe07eead3d58cc1ed817bbd GIT binary patch literal 16879 zcmeHu2|SeB|Nmo;R?DaqG9pHDQ$vWv3}q>Uu`eOniAY(yg)AXuC=xR$W{e?Q2;D+b zMA?NFWGPf*iOl?-=b7&J*8TUr_x@ks|N475ULNQ3Jm-8qpYu7}`+PnJvxoT#*r2C# zSO;KZ0{}Mg2VlNompQDhZEs|JROhe(7XHA#2>=u4F96`>?eAx-tF_I-(rO#@?)T*2 zbn4{q`Jem+`ObAg+yUT){7=6B-7DVX&ZnHfLNnm6zaJ%cR{j!{ z_cJxt2FqlDc^Q}Q@{Zr-1N~3>gJqha@=hoHp!`cPzu(I<0FnhINaHom-gp!6uLbzK z6*vVL1G<0~nEzjz{;;PH2>|xZ0szP5Ki)ZB2Y`x50NB*`$Gh!W0I)s+0Lq`8bntV4 zmEi=R>?ckDz^B^)u+|a)1ls_B&-!;o|ET*%U;LZ4ZUgIV1>5NZ{;{yW{eU*W&ITpu$qpq>4(Q3n$;rXV&Be_P|MKvz;^yJy;pSeodKE7p zl)&7Y)qHCp0%F3d%Fe~X!NteJ%>x(tpL#Iw1N^Jl7ufL}Y)F8epN)f`jad(ff@7Br zVCR5__P4~&!@c786cv>+ja^+CZ|5`Rsbm2qf9$(t6FcVr;satJpL_nzOOlpN!jmCj<2>L;`@c zFyeYpKIXxL5(T^r^n%x*TQ4nH??jbpM;1g&?-IJMO2jlgxVpm>F2MGSUph*>HRGPr z(8t09@tx12?6z9FKWOdfI-N2h&IAtSsB*fSp0G(mYDjvA_IHc^2Gx=W)P%xZB+FrS%Wg z_Ia%>lgF0Uq|7XN42j%3c<1!3x>7_WUs3Vt>W4vPo`ym7k%wd05$T2GMODnj&D4v0 zauP4{eI>CGO)dVMVUxtUekX>Nd%sl4?WpvFd+zgvs_)mCS(pCCQzRkA{^6kx9o(DV zvG9*A!LKD9>w~&KRH3HO!k6->%lf^jai5-TUn5PJz?H-;6GMWN3hP6xdivsB#=5NQ z)0Lg5xn~c4+?>21{pnPd zDT#{Gow4VeI&)SDMHfbQMl^VyP(n{ft~qdmhqKJ{X7TJ+Kwy;*Jk zTA|N`_t3p=G{@vQ;Q#vES>LpDj0wc^1;#Uw&qMGtq;CAIvx6nY)*3%sg*mhvnT@OU z5MN6(Ba@^)3{)`z!|@>EppsP2>4IMG3l@E=v39=|dLevu^wg#IuF~sM7fYpXPK#Kaby>`ch- zI?-!fjoxUH%94mi*N^6CWh5Gk&LrP(!9256G``50Md^D#ws$0n9?Me*^W5xT+DR%G3=$2*oHP{Q{ zG-vqMu*lVa!rtFr%dP@I6gIynSfx}2J>=s*SeO4@i+K1%H-{>jI!4qWBmyt&0(tu23Gte^AD0d`Rzwv;Q+$!3F6z3E zSC$l*z%{w`f?n~+l3eW&^RC0ZLy=kcoi_Co8rp=@w0iN zsGeSP$BXTwUnD&=9sN+Ux4K`tO?;z_y>4$2`aU4=)gT=!1J4OfXj;L8hIDL1$&~#Z zM4s5uLK1=(5qRcFow7!a;h_CQ6W#}|^&TPUNh_J;8o?yM$=XA%S(rIbXc>v;rpSbtcYQG0<3LNw}7&6phgvq(CK=;LmDu zeDb&{$;nw250e03uv1QP);K0I@`N23+D-w1>xBfgOmd5Ve!eC|8`#Jy257~^MM@vZ zgA1@j_LG6cvLrw|aiqZ0qv;rygr6*DKQv;cn?S3sbkoXgTA5A%eHT5ptJaH*b_>4N zbgNGEz_CSj>1SrXdC7~0P7Bve)2uB=i>Z-e!<-Ra^`-;vlI`TUpxj9@$#yD2uPi>I zM5(pne6y9Q_XWc^%Z3=Sc;O_A0-nm^t>j^kzK)vIsYOvgB#JmR#t^YcLo3Ro%aj&D zO!{T__-^FEs3d|JN;~46oW%5Cb$@i~U`{7vlSNf|RH+Q&xJy|_+TMUr=}fV`hKp*? zw{s2!clH;Y!r?%k%VLCks@7g3fgaR`=v!@W^jN9Q#a9r%+7~ukH6>r`Kv@rPBatsh zA|@2&pN!Qa6+Vp3DxC~Ye=FU#>hg`c<(I@D<7p;vv?RQj)OPPc@oa!pX%#}R$9Ibj zmWpeMWdck+v+4jS1|X+W%-q z{PU3!VBZk`($i%gM~2CQ{d?N(uRLF0+=cfS&M%3t4vc0zy2jvOxV_B!Ir%t}pJ5Vy zu*YQn$U6z>Ob2`xzaQSBmIyPd)a3msd8H|FFnmmHQ+!-_Zl- zm_S;f44cMJX+JZ`uU(7_MYO5R?m0hr&t>~og~h<{oZ!EqrFZInIkL>-U_YRCBLX_W za{S2@WJPQno2=hpe%cI);Pi&tf4y+6Ek`%~t(dcGU^3^I(e{!Z85zZ=LTeoBWW2dcox zjEB{mEajVlqdz56FkzpWz`>rnWQO393Jl@?S+_1E4!W?ql?k{=KrqVa=lyyTUYLR7 z!OFqM`#9c=tR7oZ@`%zc2`o3v(%5BGn^~SeHt@Wym&KCC3nMVxFGU4UI$^g5y9xUFty~rw zgBbF{2n@ITWX|JG);aNS{33q<#cz%f&^7aYBTn4?p@rOc0e1VCtFE~$&ZXsWU#Ksc693Ife6qy7ue%fLp3s{GK1m2LuiZKa!lmD#j1 zn=~O4fN5pXTiKg{mAwg^3I92SP~2i-t{uSLZZ)*lwOyvjJ?& zNQx-)!aJk-(3{=XS4&=#kcmoh6m+n%%aUAY6C5KmDwuTwf5y zv780dzl)am z&_#7_5*2Dsa9~V5| z**#eJs&tCxcup`RY>P^F@h>UL$wM!^g_uCVdp|h-#VQ^N7j6Kg;o=Ug!kWCb2iD%0 z>`B?_^^TG58$9`S2i*?_p=@x0BG%_D&LLO{1z1g)Z)ylowzT++SMV_b&>?T%-UNeH zuAk`iCoTr~_z^XFe`NST@K*TP!u~UrSj{$K_xaH@5yche^!}Lefp7vNmZhB*9HaZz zl7CYT8$VhNiaan7UN=U8&37J-_|_ zod|1p5h!)GSMbxWgA&tJS=JEEs}+u8iuMig0+P+RIwv5BswHP`(%rueewTA8WU z9HN+~bq%2Kx^0WUCOJ#EU+T)g#zcQId&N+z#Wj5jy&P~9(r z-QDW7j?<#W<1NMd-mnwi$1fX)_nt-CIe+hE{r}Pj$su1p=ay_WHHhF zcbQ--u-~Qr7IG2qgEy_DGWhughB4YB)^*D}e8x?CQvB4#QgJUtPvq^*OGY1+owjQ6 zxfm3roX-0Jd(;~D0bAYS`I=v_E#~B=fun|0dG*rb*_xn4E3CGiYEJZgnMqi3bM1}N zyqK?L6Fq!aXa%Fazd7!>l&?UlzX@ghZ@S|77oiRK_9-0V`4-Cn zfFBx>_WJu4_K3Xtes#?P7u&xLWk6SQWC$&u6xOX)C=`?nd8zVPkqveS2g_7)GV6NI zIfx;AB?oiMBiE1>A98$s_$pb5g?!-xe-nX%Pm?6L<5(dlFjVk;BUZWzG&1L(BTg&b z1OkVDbYXgBHm%I2zl-1gKQWs+LX>Apn1EQn!UlPtuhVZ2%yt%DunQBPskMI5w9MkeCD?oMuu z;oR9){iFoj4_&vZfx^R;2+gT1SWHC#-e;D|1n41?=5DTY#(4oQ!jXq^G5$IaNNr=6 z=SjxM>b5Sl`r#nPq#qJVCL>W9>mDsc8kA6JV70iE(L`OMZq64(sQubNqV^}{D~k6q zh6@$y_}Jm2Pm2iMNI4wG5gr8Jb=?A)llgRWIihYv&*hh+a(JuZ8g;(t{4smu#UtQ; z#1rW?t!qDlJt!b4q3v%$(<#d%ze6qZ3(oJ+b1o_`fBw8(7J*hub(y&P^i)9$G6|!r zMIGl2A{+CE@0B^?h$>D+Kf{_2#&(si{Y6~qsg;b<`6znyWrr88v_t3&fwdCIToH{4 zmA1|nx_r~{mqpyhwouU4JQpiMWBZrge22%wwp;gMc{|e8aAxvZVZ!X#!pX6=>5FCu z1M@{7pZ5aopFpgk2t!iM|wa9D_No z8-%wWucBkEr!kAKKwE35SC;xe*@Fw)MajBz)iB4{0q42_Sr?EHj~HvDbgIjA)SdOF zzwE4jaZ=otI-pNm?hJqbDF7w!>{XCUB%_{Ky1EABpr(=pE_GygGJ%T$Vrs|gTa?Db`QLc-BfgWwd;Yx4+Z? z-XrNrSS35M@qE)0-lyhe2n#yBoIa~C2ScQp(P^n}##r6lSyfsrVM3d1++^CCi>1k7 zswmlQZgPCvmC?A6d3A-C5e=0#<%HwiXv$%5i{#*p%=_c>f%lu%B$l&}y z$5-twla8nweyeFc)g_ufL3rvzh&y2Oj6!+ukU?*Ki zhFBz*@H^eux~d(E#lrKn?6&B4J08rChuU9R^d%IQnZ>HB-nrG;THt2dtc5%)bSClC z>-tO6+78Ic70uBA_y7>(GF^XR31 zx8D{-YxPp4&_n|Do+%kcRxhQw?cJyyFUD@{IV*hrohqkH@unx~TY~26-Bl2H>$?>y zyWDMt*G)m(e^^Iy4t~_DiqpGbqnbr3C*_*Q;Bm;RYts!4aqo5_VlU4t2P*f~r3MH4 zA|?a+vjR^B1;`WgK5X4ons&bYSA$4y)Poq2cz&@KItGvN3lbhSofUfp31KBs{rb#x zd8Y|TD-?oHNUuv2QM9cg7v0{=C!lUuc$~{#{-g1%ncS5R!(NkqqS6FcYS~qyW>MD> zqV;ZpOaT!*PEJYbxv52<1|;x6BmS>6~j@!+YEhnlXrm6eS} zVI2NpLb8S0q*gh(Xkb@PoQ2LZDj~lpZ*?;-mVw+ zI#!|F=*_af^am4timhv7mdN(u;J+dqywkB58by2&vah&HCrO~130yw4%{ae}v~yok z#ip1eIgbW(D%Asb$AuG%`eLf8t6Vuc^2mz;<|gf9hzwuhq8#mu{z0CuUQXF+U4;Yg zNVLK%GU&=MeeszmsKS1gyg3TOY(zh0q%zFaxpO+wUtjhJ@qURgK6%X0;-q_Q&13%e zA*V^zAB85gr~Mv82E4x*+CP|ME*BWEji>pJ@M*${iQH^6^oaDGTe_Eu$4mRPQ)iKt z{2P5!2i8VMM|UZ=MaN89cZTJG;?|YDDcjXy^qyQ_vMX+FVM1eYZOM3|ImBLdK3YkG;P%SM14Z7yw*VF7Xd<&gHn1vQ1c^2|Ef>x}P1OjVO{jbv z+8o!TDah-nDrmbox|?DWN(~r`TO!FnKC20`QCDRUDO7oLfjsJ_*@$^`i@!|lqldvZ z2~K^(^s*K|$t07Gyx?4?STl3j@o(o77bby7)7-_tEBYQqR(($oXLYwvGP!)!Z6X;s^aY0@Y^5P<7=Af z)`g~c+jrg>wHX*MjSC{@$38l2cRdnSd<5q6RaqENp*)b%!k{Z}pWn2~#5dCWR4u|(dYSDNSRJtT_r{m}gCtD9#Z3 zHqYJ4o55v<;@&L9Z*Pw0d+#BzCoN7`^2$<*2zg+{#kk9*&YNN|bVk!Tyl9ey=J9>)DUyBly7guxxvpuwmp3Es6@e8`OOD za7^VW?o~q+E#yo!`I0XBrin;&1@dLrRGD`NAik>=Q|=owmQr;Qf4|0LW`;araHzVr zdj96zp5VEv(c4p@nxODlyl}i>Hil@jO>yU@w$3C6jMs-?{4P^ddn=TvNT&0Cz2cd- zIB*ze9*rnf%Nuv4C@6|<3@|?}B&{T(GG$7ae1oCeq>^6--p`ATjay;@d_35hBLrLX zr&Ow!gMC+NvpnibpE@srgigSoPw+I)Q9>$;PgKrK`B1l&`QWX)Ys7N3aro0Ga!I|5 zS7I-_ChwDvWEW5|8zqHJ)Dr9m@S&($f;wm^p2HQjTRY!J3bb3s(q`z7jD@8%u4?O6 zU2fWi{XC%KXxH^z>}LF2+1Bb-`e0t*F>Z4wSO5Oa-l#mGMbUK^u(@sHt943BT@x^Q zV@;hw&n4B)TJpDx#XH@|9}BLN%Q)2;AcJ!NA<+yH{XQ7?G*~o9Wn)KPU1fWS*-RB8 z=hOJCv%#Vs_Et_%SDbE+(pD>zbY4rg`TDPkpE9b3qnJQbEx{B|S8Jb1D=M4yqvG(U zLP4QMea)&Saw4emc-|yietv76h(c3;C7Y3;>_YR(rj`#whuol^0Mi29`mD2T%CDXc zBBkcW&m~`%2`BPP)Jh7>KlH@=q|BEo;GJv=^;76{**R8?|LDny!Bh&o`o^NgU60Fs zu{E#wBT6q=7J)A=kQ1?0l;V>-CNCzL?{ksA7_Tfw`-)MTD#PRO^Ca&yy&QceAeR=i jTrqVPFl-N<`?TBuKbu#m|Av { +describe.skip('SqlLab datasource panel', () => { beforeEach(() => { cy.login(); cy.visit('/superset/sqllab'); @@ -26,7 +26,7 @@ describe('SqlLab datasource panel', () => { // TODO the test bellow is flaky, and has been disabled for the time being // (notice the `it.skip`) - it.skip('creates a table preview when a database, schema, and table are selected', () => { + it('creates a table preview when a database, schema, and table are selected', () => { cy.intercept('/superset/table/**').as('tableMetadata'); // it should have dropdowns to select database, schema, and table From 1318e886f54cf899058c5e0f4fc174b56dfd2676 Mon Sep 17 00:00:00 2001 From: geido Date: Mon, 12 Sep 2022 16:59:17 +0300 Subject: [PATCH 31/31] Clean up test data --- .../cypress-base/cypress/integration/explore/link.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/superset-frontend/cypress-base/cypress/integration/explore/link.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/link.test.ts index fb3445fc6366f..7a31d7cbb81f1 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/link.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/link.test.ts @@ -101,8 +101,8 @@ describe('Test explore links', () => { cy.request(apiURL('/api/v1/chart/', query)).then(response => { expect(response.body.count).equals(1); - cy.request('DELETE', `/api/v1/chart/${response.body.ids[0]}`); }); + cy.deleteChartByName(newChartName, true); }); }); @@ -183,5 +183,6 @@ describe('Test explore links', () => { cy.request(apiURL('/api/v1/dashboard/', query)).then(response => { expect(response.body.count).equals(1); }); + cy.deleteDashboardByName(dashboardTitle, true); }); });