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 ab4d8db7bf..c628837ebb 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 @@ -23,47 +23,81 @@ describe('Dashboard edit mode', () => { cy.server(); cy.login(); cy.visit(WORLD_HEALTH_DASHBOARD); - cy.get('.dashboard-header [data-test=edit-alt]').click(); + cy.get('[data-test="dashboard-header"]') + .find('[data-test=edit-alt]') + .click(); }); - xit('remove, and add chart flow', () => { + it('remove, and add chart flow', () => { // wait for box plot to appear - cy.get('.grid-container .box_plot'); + cy.get('[data-test="grid-container"]').find('.box_plot', { + timeout: 10000, + }); + const elementsCount = 10; - cy.get('.fa.fa-trash') + 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('.grid-container .box_plot').should('not.exist'); + cy.get('[data-test="grid-container"]') + .find('.box_plot') + .should('not.be.visible'); }); - cy.get('.tabs-components .nav-tabs li a').contains('Charts').click(); - - // wait for tab-switching animation to complete - cy.wait(1000); + cy.get('[data-test="dashboard-builder-component-pane-tabs-navigation"]') + .children() + .last() + .click(); // find box plot is available from list - cy.get('.tabs-components') - .find('.chart-card-container') - .contains('Box plot'); + cy.get('[data-test="dashboard-charts-filter-search-input"]').type( + 'Box plot', + ); + cy.get('[data-test="card-title"]').should('have.length', 1); - drag('.chart-card', 'Box plot').to( + drag('[data-test="card-title"]', 'Box plot').to( '.grid-row.background--transparent:last', ); // add back to dashboard - cy.get('.grid-container .box_plot').should('be.exist'); + cy.get('[data-test="grid-container"]') + .find('.box_plot') + .should('be.visible'); // should show Save changes button - cy.get('.dashboard-header .button-container').contains('Save'); + cy.get('[data-test="header-save-button"]').should('be.visible'); - // undo 2 steps - cy.get('.dashboard-header .undo-action').click().click(); + // 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.be.visible'); + + // 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('.dashboard-header .button-container') - .contains('Discard Changes') + cy.get('[data-test="dashboard-edit-actions"]') + .find('[data-test="discard-changes-button"]') + .should('be.visible') .click(); + cy.get('[data-test="dashboard-header"]').within(() => { + cy.get('[data-test="dashboard-edit-actions"]').should('not.be.visible'); + cy.get('[data-test="edit-alt"]').should('be.visible'); + }); }); }); 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 7d66a0b9df..3a6ffcd332 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 @@ -38,27 +38,27 @@ describe('Dashboard add to favorite', () => { it('should allow favor/unfavor', () => { if (!isFavoriteDashboard) { - cy.get('a.fave-unfave-icon') + cy.get('[data-test="fave-unfave-icon"]') .find('svg') .should('have.attr', 'data-test', 'favorite-unselected'); - cy.get('a.fave-unfave-icon').trigger('click'); - cy.get('a.fave-unfave-icon') + cy.get('[data-test="fave-unfave-icon"]').trigger('click'); + cy.get('[data-test="fave-unfave-icon"]') .find('svg') .should('have.attr', 'data-test', 'favorite-selected') .and('not.have.attr', 'data-test', 'favorite-unselected'); } else { - cy.get('a.fave-unfave-icon') + cy.get('[data-test="fave-unfave-icon"]') .find('svg') .should('have.attr', 'data-test', 'favorite-unselected') .and('not.have.attr', 'data-test', 'favorite-selected'); - cy.get('a.fave-unfave-icon').trigger('click'); - cy.get('a.fave-unfave-icon') + cy.get('[data-test="fave-unfave-icon"]').trigger('click'); + cy.get('[data-test="fave-unfave-icon"]') .find('svg') .should('have.attr', 'data-test', 'favorite-unselected') .and('not.have.attr', 'data-test', 'favorite-selected'); } // reset to original fav state - cy.get('a.fave-unfave-icon').trigger('click'); + cy.get('[data-test="fave-unfave-icon"]').trigger('click'); }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/load.test.js b/superset-frontend/cypress-base/cypress/integration/dashboard/load.test.js index 6e33eb5dec..7b46ffa0b2 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/load.test.js +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/load.test.js @@ -51,7 +51,9 @@ describe('Dashboard load', () => { expect(responseBody).to.have.property('errors'); expect(responseBody.errors.length).to.eq(0); const sliceId = responseBody.form_data.slice_id; - cy.get(`#chart-id-${sliceId}`).should('be.visible'); + cy.get('[data-test="grid-content"]') + .find(`#chart-id-${sliceId}`) + .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 4f8fb84fb5..929f9e65a8 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/markdown.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/markdown.test.ts @@ -30,27 +30,35 @@ describe('Dashboard edit markdown', () => { cy.get('script').then(nodes => { numScripts = nodes.length; }); - cy.get('.dashboard-header [data-test=edit-alt]').click(); + cy.get('[data-test="dashboard-header"]') + .find('[data-test="edit-alt"]') + .click(); cy.get('script').then(nodes => { // load 5 new script chunks for css editor expect(nodes.length).to.greaterThan(numScripts); numScripts = nodes.length; }); - + cy.get('[data-test="grid-row-background--transparent"]') + .first() + .as('component-background-first'); // add new markdown component - drag('.new-component', 'Markdown').to( - '.grid-row.background--transparent:first', + drag('[data-test="new-component"]', 'Markdown').to( + '@component-background-first', ); cy.get('script').then(nodes => { // load more scripts for markdown editor expect(nodes.length).to.greaterThan(numScripts); numScripts = nodes.length; }); - - cy.contains('h3', '✨Markdown').click(); - cy.get('.ace_content').contains( - 'Click here to edit [markdown](https://bit.ly/1dQOfRK)', - ); + cy.get('[data-test="dashboard-markdown-editor"]') + .should( + 'have.text', + '✨Markdown✨Markdown✨MarkdownClick here to edit markdown', + ) + .click(); + cy.get('[data-test="dashboard-component-chart-holder"]') + .find('.ace_content') + .contains('Click here to edit [markdown](https://bit.ly/1dQOfRK)'); // entering edit mode does not add new scripts // (though scripts may still be removed by others) @@ -58,7 +66,9 @@ describe('Dashboard edit markdown', () => { expect(nodes.length).to.most(numScripts); }); - cy.get('.grid-row.background--transparent:first').click('right'); - cy.get('.ace_content').should('not.exist'); + cy.get('@component-background-first').click('right'); + cy.get('[data-test="dashboard-component-chart-holder"]') + .find('.ace_content') + .should('not.be.visible'); }); }); 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 811e7c0767..6b7ff92406 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/save.test.js +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/save.test.js @@ -34,9 +34,11 @@ describe('Dashboard save action', () => { cy.route('POST', `/superset/copy_dash/${dashboardId}/`).as('copyRequest'); }); - cy.get('#save-dash-split-button').trigger('click', { force: true }); - cy.contains('Save as').trigger('click', { force: true }); - cy.get('.modal-footer').contains('Save').trigger('click', { force: true }); + cy.get('[data-test="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, + }); }); it('should save as new dashboard', () => { @@ -50,21 +52,32 @@ describe('Dashboard save action', () => { it('should save/overwrite dashboard', () => { // should have box_plot chart - cy.get('.grid-container .box_plot', { timeout: 5000 }); // wait for 5 secs + cy.get('[data-test="grid-row-background--transparent"]').within(() => { + cy.get('.box_plot', { timeout: 10000 }).should('be.visible'); + }); // remove box_plot chart from dashboard - cy.get('.dashboard-header [data-test=edit-alt]').click(); - cy.get('.fa.fa-trash').last().trigger('click', { force: true }); - cy.get('.grid-container .box_plot').should('not.exist'); + cy.get('[data-test="edit-alt"]').click({ timeout: 5000 }); + cy.get('[data-test="dashboard-delete-component-button"]') + .should('be.visible', { timeout: 10000 }) + .last() + .trigger('click'); + cy.get('[data-test="grid-container"]') + .find('.box_plot') + .should('not.be.visible'); cy.route('POST', '/superset/save_dash/**/').as('saveRequest'); - cy.get('.dashboard-header') + cy.get('[data-test="dashboard-header"]') + .find('[data-test="header-save-button"]') .contains('Save') .trigger('click', { force: true }); - // go back to view mode cy.wait('@saveRequest'); - cy.get('.dashboard-header [data-test=edit-alt]').click(); - cy.get('.grid-container .box_plot').should('not.exist'); + cy.get('[data-test="dashboard-header"]') + .find('[data-test="edit-alt"]') + .click(); + cy.get('[data-test="grid-container"]') + .find('.box_plot', { timeout: 20000 }) + .should('not.be.visible'); }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/tabs.test.js b/superset-frontend/cypress-base/cypress/integration/dashboard/tabs.test.js index 94b0bb0ccd..a842264be2 100644 --- a/superset-frontend/cypress-base/cypress/integration/dashboard/tabs.test.js +++ b/superset-frontend/cypress-base/cypress/integration/dashboard/tabs.test.js @@ -95,46 +95,60 @@ describe('Dashboard tabs', () => { cy.wait('@filterRequest'); cy.wait('@treemapRequest'); - cy.get('.dashboard-component-tabs') + cy.get('[data-test="dashboard-component-tabs"]') .first() - .find('ul.nav.nav-tabs li') - .as('tabs'); + .find('[data-test="nav-list"]') + .children() + .as('top-level-tabs'); - cy.get('@tabs').first().click().should('have.class', 'active'); - cy.get('@tabs').last().should('not.have.class', 'active'); + cy.get('@top-level-tabs').first().click().should('have.class', 'active'); + cy.get('@top-level-tabs').last().should('not.have.class', 'active'); - cy.get('@tabs').last().click().should('have.class', 'active'); - cy.get('@tabs').first().should('not.have.class', 'active'); + cy.get('@top-level-tabs').last().click().should('have.class', 'active'); + cy.get('@top-level-tabs').first().should('not.have.class', 'active'); }); it('should load charts when tab is visible', () => { // landing in first tab, should see 2 charts cy.wait('@filterRequest'); - cy.get('.grid-container .filter_box').should('be.exist'); + cy.get('[data-test="grid-container"]') + .find('.filter_box') + .should('be.visible'); cy.wait('@treemapRequest'); - cy.get('.grid-container .treemap').should('be.exist'); - cy.get('.grid-container .box_plot').should('not.be.exist'); - cy.get('.grid-container .line').should('not.be.exist'); + cy.get('[data-test="grid-container"]') + .find('.treemap') + .should('be.visible'); + cy.get('[data-test="grid-container"]') + .find('.box_plot') + .should('not.be.visible'); + cy.get('[data-test="grid-container"]') + .find('.line') + .should('not.be.visible'); // click row level tab, see 1 more chart - cy.get('.tab-content ul.nav.nav-tabs li') + cy.get('[data-test="dashboard-component-tabs"]') .last() - .find('.editable-title input') - .click(); + .find('[data-test="nav-list"]') + .children() + .as('row-level-tabs'); + + cy.get('@row-level-tabs').last().click(); + cy.wait('@linechartRequest'); - cy.get('.grid-container .line').should('be.exist'); + cy.get('[data-test="grid-container"]').find('.line').should('be.visible'); // click top level tab, see 1 more chart handleException(); - cy.get('.dashboard-component-tabs') + cy.get('[data-test="dashboard-component-tabs"]') .first() - .find('ul.nav.nav-tabs li') - .last() - .find('.editable-title input') - .click(); + .find('[data-test="nav-list"]') + .children() + .as('top-level-tabs'); + + cy.get('@top-level-tabs').last().click(); // should exist a visible box_plot element - cy.get('.grid-container .box_plot'); + cy.get('[data-test="grid-container"]').find('.box_plot'); }); it('should send new queries when tab becomes visible', () => { @@ -162,7 +176,13 @@ describe('Dashboard tabs', () => { }); // click row level tab, send 1 more query - cy.get('.tab-content ul.nav.nav-tabs li').last().click(); + cy.get('[data-test="dashboard-component-tabs"]') + .last() + .find('[data-test="nav-list"]') + .children() + .as('row-level-tabs'); + cy.get('@row-level-tabs').last().click(); + cy.wait('@linechartRequest').then(xhr => { const requestFormData = xhr.request.body; const requestParams = JSON.parse(requestFormData.get('form_data')); @@ -174,13 +194,13 @@ describe('Dashboard tabs', () => { }); // click top level tab, send 1 more query - handleException(); - cy.get('.dashboard-component-tabs') + cy.get('[data-test="dashboard-component-tabs"]') .first() - .find('ul.nav.nav-tabs li') - .last() - .find('.editable-title input') - .click(); + .find('[data-test="nav-list"]') + .children() + .as('top-level-tabs'); + + cy.get('@top-level-tabs').last().click(); cy.wait('@boxplotRequest').then(xhr => { const requestFormData = xhr.request.body; @@ -193,15 +213,10 @@ describe('Dashboard tabs', () => { }); // navigate to filter and clear filter - cy.get('.dashboard-component-tabs') - .first() - .find('ul.nav.nav-tabs li') - .first() - .click(); - cy.get('.tab-content ul.nav.nav-tabs li') - .first() - .should('be.visible') - .click(); + cy.get('@top-level-tabs').first().click(); + + cy.get('@top-level-tabs').first().click(); + cy.get('.Select__clear-indicator').click(); // trigger 1 new query diff --git a/superset-frontend/src/dashboard/components/BuilderComponentPane.jsx b/superset-frontend/src/dashboard/components/BuilderComponentPane.jsx index 87545f8924..df18290b84 100644 --- a/superset-frontend/src/dashboard/components/BuilderComponentPane.jsx +++ b/superset-frontend/src/dashboard/components/BuilderComponentPane.jsx @@ -50,7 +50,7 @@ class BuilderComponentPane extends React.PureComponent { diff --git a/superset-frontend/src/dashboard/components/SaveModal.jsx b/superset-frontend/src/dashboard/components/SaveModal.jsx index 40b29c2955..e3a85b5bbe 100644 --- a/superset-frontend/src/dashboard/components/SaveModal.jsx +++ b/superset-frontend/src/dashboard/components/SaveModal.jsx @@ -197,7 +197,7 @@ class SaveModal extends React.PureComponent { modalFooter={