chore: Dashboard cypress refactor (#11280)

* moved dashboard tests to use data-test attributes

* linter

* fix for unstable save test
This commit is contained in:
adam-stasiak-polidea 2020-10-20 06:36:20 +02:00 committed by GitHub
parent 9266f0a4a8
commit 55ae259b13
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 171 additions and 94 deletions

View File

@ -23,47 +23,81 @@ describe('Dashboard edit mode', () => {
cy.server(); cy.server();
cy.login(); cy.login();
cy.visit(WORLD_HEALTH_DASHBOARD); 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 // 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() .last()
.then($el => { .then($el => {
cy.wrap($el).invoke('show').click(); cy.wrap($el).invoke('show').click();
// box plot should be gone // 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(); cy.get('[data-test="dashboard-builder-component-pane-tabs-navigation"]')
.children()
// wait for tab-switching animation to complete .last()
cy.wait(1000); .click();
// find box plot is available from list // find box plot is available from list
cy.get('.tabs-components') cy.get('[data-test="dashboard-charts-filter-search-input"]').type(
.find('.chart-card-container') 'Box plot',
.contains('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', '.grid-row.background--transparent:last',
); );
// add back to dashboard // 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 // 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 // undo first step and expect deleted item
cy.get('.dashboard-header .undo-action').click().click(); 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 // no changes, can switch to view mode
cy.get('.dashboard-header .button-container') cy.get('[data-test="dashboard-edit-actions"]')
.contains('Discard Changes') .find('[data-test="discard-changes-button"]')
.should('be.visible')
.click(); .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');
});
}); });
}); });

View File

@ -38,27 +38,27 @@ describe('Dashboard add to favorite', () => {
it('should allow favor/unfavor', () => { it('should allow favor/unfavor', () => {
if (!isFavoriteDashboard) { if (!isFavoriteDashboard) {
cy.get('a.fave-unfave-icon') cy.get('[data-test="fave-unfave-icon"]')
.find('svg') .find('svg')
.should('have.attr', 'data-test', 'favorite-unselected'); .should('have.attr', 'data-test', 'favorite-unselected');
cy.get('a.fave-unfave-icon').trigger('click'); cy.get('[data-test="fave-unfave-icon"]').trigger('click');
cy.get('a.fave-unfave-icon') cy.get('[data-test="fave-unfave-icon"]')
.find('svg') .find('svg')
.should('have.attr', 'data-test', 'favorite-selected') .should('have.attr', 'data-test', 'favorite-selected')
.and('not.have.attr', 'data-test', 'favorite-unselected'); .and('not.have.attr', 'data-test', 'favorite-unselected');
} else { } else {
cy.get('a.fave-unfave-icon') cy.get('[data-test="fave-unfave-icon"]')
.find('svg') .find('svg')
.should('have.attr', 'data-test', 'favorite-unselected') .should('have.attr', 'data-test', 'favorite-unselected')
.and('not.have.attr', 'data-test', 'favorite-selected'); .and('not.have.attr', 'data-test', 'favorite-selected');
cy.get('a.fave-unfave-icon').trigger('click'); cy.get('[data-test="fave-unfave-icon"]').trigger('click');
cy.get('a.fave-unfave-icon') cy.get('[data-test="fave-unfave-icon"]')
.find('svg') .find('svg')
.should('have.attr', 'data-test', 'favorite-unselected') .should('have.attr', 'data-test', 'favorite-unselected')
.and('not.have.attr', 'data-test', 'favorite-selected'); .and('not.have.attr', 'data-test', 'favorite-selected');
} }
// reset to original fav state // reset to original fav state
cy.get('a.fave-unfave-icon').trigger('click'); cy.get('[data-test="fave-unfave-icon"]').trigger('click');
}); });
}); });

View File

@ -51,7 +51,9 @@ describe('Dashboard load', () => {
expect(responseBody).to.have.property('errors'); expect(responseBody).to.have.property('errors');
expect(responseBody.errors.length).to.eq(0); expect(responseBody.errors.length).to.eq(0);
const sliceId = responseBody.form_data.slice_id; 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');
}), }),
); );
}); });

View File

@ -30,27 +30,35 @@ describe('Dashboard edit markdown', () => {
cy.get('script').then(nodes => { cy.get('script').then(nodes => {
numScripts = nodes.length; 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 => { cy.get('script').then(nodes => {
// load 5 new script chunks for css editor // load 5 new script chunks for css editor
expect(nodes.length).to.greaterThan(numScripts); expect(nodes.length).to.greaterThan(numScripts);
numScripts = nodes.length; numScripts = nodes.length;
}); });
cy.get('[data-test="grid-row-background--transparent"]')
.first()
.as('component-background-first');
// add new markdown component // add new markdown component
drag('.new-component', 'Markdown').to( drag('[data-test="new-component"]', 'Markdown').to(
'.grid-row.background--transparent:first', '@component-background-first',
); );
cy.get('script').then(nodes => { cy.get('script').then(nodes => {
// load more scripts for markdown editor // load more scripts for markdown editor
expect(nodes.length).to.greaterThan(numScripts); expect(nodes.length).to.greaterThan(numScripts);
numScripts = nodes.length; numScripts = nodes.length;
}); });
cy.get('[data-test="dashboard-markdown-editor"]')
cy.contains('h3', '✨Markdown').click(); .should(
cy.get('.ace_content').contains( 'have.text',
'Click here to edit [markdown](https://bit.ly/1dQOfRK)', '✨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 // entering edit mode does not add new scripts
// (though scripts may still be removed by others) // (though scripts may still be removed by others)
@ -58,7 +66,9 @@ describe('Dashboard edit markdown', () => {
expect(nodes.length).to.most(numScripts); expect(nodes.length).to.most(numScripts);
}); });
cy.get('.grid-row.background--transparent:first').click('right'); cy.get('@component-background-first').click('right');
cy.get('.ace_content').should('not.exist'); cy.get('[data-test="dashboard-component-chart-holder"]')
.find('.ace_content')
.should('not.be.visible');
}); });
}); });

View File

@ -34,9 +34,11 @@ describe('Dashboard save action', () => {
cy.route('POST', `/superset/copy_dash/${dashboardId}/`).as('copyRequest'); cy.route('POST', `/superset/copy_dash/${dashboardId}/`).as('copyRequest');
}); });
cy.get('#save-dash-split-button').trigger('click', { force: true }); cy.get('[data-test="more-horiz"]').trigger('click', { force: true });
cy.contains('Save as').trigger('click', { force: true }); cy.get('[data-test="save-as-menu-item"]').trigger('click', { force: true });
cy.get('.modal-footer').contains('Save').trigger('click', { force: true }); cy.get('[data-test="modal-save-dashboard-button"]').trigger('click', {
force: true,
});
}); });
it('should save as new dashboard', () => { it('should save as new dashboard', () => {
@ -50,21 +52,32 @@ describe('Dashboard save action', () => {
it('should save/overwrite dashboard', () => { it('should save/overwrite dashboard', () => {
// should have box_plot chart // 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 // remove box_plot chart from dashboard
cy.get('.dashboard-header [data-test=edit-alt]').click(); cy.get('[data-test="edit-alt"]').click({ timeout: 5000 });
cy.get('.fa.fa-trash').last().trigger('click', { force: true }); cy.get('[data-test="dashboard-delete-component-button"]')
cy.get('.grid-container .box_plot').should('not.exist'); .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.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') .contains('Save')
.trigger('click', { force: true }); .trigger('click', { force: true });
// go back to view mode // go back to view mode
cy.wait('@saveRequest'); cy.wait('@saveRequest');
cy.get('.dashboard-header [data-test=edit-alt]').click(); cy.get('[data-test="dashboard-header"]')
cy.get('.grid-container .box_plot').should('not.exist'); .find('[data-test="edit-alt"]')
.click();
cy.get('[data-test="grid-container"]')
.find('.box_plot', { timeout: 20000 })
.should('not.be.visible');
}); });
}); });

View File

@ -95,46 +95,60 @@ describe('Dashboard tabs', () => {
cy.wait('@filterRequest'); cy.wait('@filterRequest');
cy.wait('@treemapRequest'); cy.wait('@treemapRequest');
cy.get('.dashboard-component-tabs') cy.get('[data-test="dashboard-component-tabs"]')
.first() .first()
.find('ul.nav.nav-tabs li') .find('[data-test="nav-list"]')
.as('tabs'); .children()
.as('top-level-tabs');
cy.get('@tabs').first().click().should('have.class', 'active'); cy.get('@top-level-tabs').first().click().should('have.class', 'active');
cy.get('@tabs').last().should('not.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('@top-level-tabs').last().click().should('have.class', 'active');
cy.get('@tabs').first().should('not.have.class', 'active'); cy.get('@top-level-tabs').first().should('not.have.class', 'active');
}); });
it('should load charts when tab is visible', () => { it('should load charts when tab is visible', () => {
// landing in first tab, should see 2 charts // landing in first tab, should see 2 charts
cy.wait('@filterRequest'); 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.wait('@treemapRequest');
cy.get('.grid-container .treemap').should('be.exist'); cy.get('[data-test="grid-container"]')
cy.get('.grid-container .box_plot').should('not.be.exist'); .find('.treemap')
cy.get('.grid-container .line').should('not.be.exist'); .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 // 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() .last()
.find('.editable-title input') .find('[data-test="nav-list"]')
.click(); .children()
.as('row-level-tabs');
cy.get('@row-level-tabs').last().click();
cy.wait('@linechartRequest'); 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 // click top level tab, see 1 more chart
handleException(); handleException();
cy.get('.dashboard-component-tabs') cy.get('[data-test="dashboard-component-tabs"]')
.first() .first()
.find('ul.nav.nav-tabs li') .find('[data-test="nav-list"]')
.last() .children()
.find('.editable-title input') .as('top-level-tabs');
.click();
cy.get('@top-level-tabs').last().click();
// should exist a visible box_plot element // 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', () => { it('should send new queries when tab becomes visible', () => {
@ -162,7 +176,13 @@ describe('Dashboard tabs', () => {
}); });
// click row level tab, send 1 more query // 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 => { cy.wait('@linechartRequest').then(xhr => {
const requestFormData = xhr.request.body; const requestFormData = xhr.request.body;
const requestParams = JSON.parse(requestFormData.get('form_data')); const requestParams = JSON.parse(requestFormData.get('form_data'));
@ -174,13 +194,13 @@ describe('Dashboard tabs', () => {
}); });
// click top level tab, send 1 more query // click top level tab, send 1 more query
handleException(); cy.get('[data-test="dashboard-component-tabs"]')
cy.get('.dashboard-component-tabs')
.first() .first()
.find('ul.nav.nav-tabs li') .find('[data-test="nav-list"]')
.last() .children()
.find('.editable-title input') .as('top-level-tabs');
.click();
cy.get('@top-level-tabs').last().click();
cy.wait('@boxplotRequest').then(xhr => { cy.wait('@boxplotRequest').then(xhr => {
const requestFormData = xhr.request.body; const requestFormData = xhr.request.body;
@ -193,15 +213,10 @@ describe('Dashboard tabs', () => {
}); });
// navigate to filter and clear filter // navigate to filter and clear filter
cy.get('.dashboard-component-tabs') cy.get('@top-level-tabs').first().click();
.first()
.find('ul.nav.nav-tabs li') cy.get('@top-level-tabs').first().click();
.first()
.click();
cy.get('.tab-content ul.nav.nav-tabs li')
.first()
.should('be.visible')
.click();
cy.get('.Select__clear-indicator').click(); cy.get('.Select__clear-indicator').click();
// trigger 1 new query // trigger 1 new query

View File

@ -50,7 +50,7 @@ class BuilderComponentPane extends React.PureComponent {
<Tabs <Tabs
className="m-t-10 tabs-components" className="m-t-10 tabs-components"
id="tabs" id="tabs"
data-test="tabs-component" data-test="dashboard-builder-component-pane-tabs-navigation"
> >
<Tab eventKey={1} title={t('Components')}> <Tab eventKey={1} title={t('Components')}>
<NewTabs /> <NewTabs />

View File

@ -197,7 +197,7 @@ class SaveModal extends React.PureComponent {
modalFooter={ modalFooter={
<div> <div>
<Button <Button
data-test="save-modal-save-button" data-test="modal-save-dashboard-button"
buttonStyle="primary" buttonStyle="primary"
onClick={this.saveDashboard} onClick={this.saveDashboard}
> >

View File

@ -214,6 +214,7 @@ class SliceAdder extends React.Component {
className="search-input" className="search-input"
onChange={this.searchUpdated} onChange={this.searchUpdated}
onKeyPress={this.handleKeyPress} onKeyPress={this.handleKeyPress}
data-test="dashboard-charts-filter-search-input"
/> />
<DropdownButton <DropdownButton
title={`Sort by ${KEYS_TO_SORT[this.state.sortBy].label}`} title={`Sort by ${KEYS_TO_SORT[this.state.sortBy].label}`}

View File

@ -237,6 +237,7 @@ class ChartHolder extends React.Component {
> >
<div <div
ref={dragSourceRef} ref={dragSourceRef}
data-test="dashboard-component-chart-holder"
className={`dashboard-component dashboard-component-chart-holder ${ className={`dashboard-component dashboard-component-chart-holder ${
this.state.outlinedComponentId ? 'fade-in' : 'fade-out' this.state.outlinedComponentId ? 'fade-in' : 'fade-out'
} ${this.state.isFullSize ? 'full-size' : ''}`} } ${this.state.isFullSize ? 'full-size' : ''}`}
@ -270,10 +271,11 @@ class ChartHolder extends React.Component {
)} )}
{editMode && ( {editMode && (
<HoverMenu position="top"> <HoverMenu position="top">
<DeleteComponentButton <div data-test="dashboard-delete-component-button">
data-test="chart-delete-button" <DeleteComponentButton
onDelete={this.handleDeleteComponent} onDelete={this.handleDeleteComponent}
/> />
</div>
</HoverMenu> </HoverMenu>
)} )}
</div> </div>

View File

@ -172,7 +172,7 @@ function PropertiesModal({ slice, onHide, onSave }: InternalProps) {
</FormLabel> </FormLabel>
<FormControl <FormControl
name="name" name="name"
data-test="properties-name-input" data-test="properties-modal-name-input"
type="text" type="text"
bsSize="sm" bsSize="sm"
value={name} value={name}
@ -260,7 +260,7 @@ function PropertiesModal({ slice, onHide, onSave }: InternalProps) {
{t('Cancel')} {t('Cancel')}
</Button> </Button>
<Button <Button
data-test="properties-save-button" data-test="properties-modal-save-button"
type="submit" type="submit"
buttonSize="sm" buttonSize="sm"
buttonStyle="primary" buttonStyle="primary"