Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cypress test - dashboard create/archive #3565

Merged
merged 20 commits into from
Mar 14, 2019
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .circleci/Dockerfile.cypress
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ FROM cypress/browsers:chrome67
ENV APP /usr/src/app
WORKDIR $APP

RUN npm install --no-save puppeteer@1.10.0 cypress@^3.1.5 @percy/cypress@^0.2.3 atob@2.1.2 > /dev/null
COPY package.json $APP/package.json
RUN npm run cypress:install > /dev/null

COPY cypress $APP/cypress
COPY cypress.json $APP/cypress.json
Expand Down
2 changes: 1 addition & 1 deletion client/app/components/app-header/app-header.html
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@

<!-- Add New Button -->
<div class="btn-group navbar-btn navbar-left btn__new hidden-xs" uib-dropdown is-open="status.isopen">
<button id="create-button" type="button" class="btn btn-primary btn--create" uib-dropdown-toggle ng-disabled="disabled">
<button id="create-button" data-test="CreateButton" type="button" class="btn btn-primary btn--create" uib-dropdown-toggle ng-disabled="disabled">
Create <span class="caret caret--nav"></span>
</button>
<ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="create-button">
Expand Down
32 changes: 17 additions & 15 deletions client/app/components/dashboards/edit-dashboard-dialog.html
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
<div class="modal-header">
<button type="button" class="close" ng-click="$ctrl.dismiss()" ng-disabled="$ctrl.saveInProgress" aria-hidden="true">&times;</button>
<h4 class="modal-title">New Dashboard</h4>
</div>
<div class="modal-body" ng-if="$ctrl.policy.isCreateDashboardEnabled()">
<p>
<input type="text" class="form-control" placeholder="Dashboard Name" ng-model="$ctrl.dashboard.name" autofocus ng-keyup="$event.keyCode === 13 && $ctrl.saveDashboard()">
</p>
</div>
<div class="modal-footer" ng-if="$ctrl.policy.isCreateDashboardEnabled()">
<button type="button" class="btn btn-default" ng-disabled="$ctrl.saveInProgress" ng-click="$ctrl.dismiss()">Close</button>
<button type="button" class="btn btn-primary" ng-disabled="$ctrl.saveInProgress || !$ctrl.isFormValid()" ng-click="$ctrl.saveDashboard()">Save</button>
</div>
<div data-test="EditDashboardDialog">
<div class="modal-header">
<button type="button" class="close" ng-click="$ctrl.dismiss()" ng-disabled="$ctrl.saveInProgress" aria-hidden="true">&times;</button>
<h4 class="modal-title">New Dashboard</h4>
</div>
<div class="modal-body" ng-if="$ctrl.policy.isCreateDashboardEnabled()">
<p>
<input type="text" class="form-control" placeholder="Dashboard Name" ng-model="$ctrl.dashboard.name" autofocus ng-keyup="$event.keyCode === 13 && $ctrl.saveDashboard()">
</p>
</div>
<div class="modal-footer" ng-if="$ctrl.policy.isCreateDashboardEnabled()">
<button type="button" class="btn btn-default" ng-disabled="$ctrl.saveInProgress" ng-click="$ctrl.dismiss()">Close</button>
<button type="button" class="btn btn-primary" ng-disabled="$ctrl.saveInProgress || !$ctrl.isFormValid()" ng-click="$ctrl.saveDashboard()" data-test="DashboardSaveButton">Save</button>
</div>

<div class="modal-body" ng-if="!$ctrl.policy.isCreateDashboardEnabled()">
<edit-dashboard-dialog-disabled></edit-dashboard-dialog-disabled>
<div class="modal-body" ng-if="!$ctrl.policy.isCreateDashboardEnabled()">
<edit-dashboard-dialog-disabled></edit-dashboard-dialog-disabled>
</div>
ranbena marked this conversation as resolved.
Show resolved Hide resolved
</div>
56 changes: 28 additions & 28 deletions client/app/pages/dashboards/DashboardList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,35 +88,35 @@ class DashboardList extends React.Component {
/>
</Layout.Sidebar>
<Layout.Content>
{!controller.isLoaded && <LoadingState />}
{
controller.isLoaded && controller.isEmpty && (
<DashboardListEmptyState
page={controller.params.currentPage}
searchTerm={controller.searchTerm}
selectedTags={controller.selectedTags}
/>
)
}
{
controller.isLoaded && !controller.isEmpty && (
<div className="bg-white tiled table-responsive">
<ItemsTable
items={controller.pageItems}
columns={this.listColumns}
orderByField={controller.orderByField}
orderByReverse={controller.orderByReverse}
toggleSorting={controller.toggleSorting}
{controller.isLoaded ? (
<div data-test="DashboardLayoutContent">
{controller.isEmpty ? (
<DashboardListEmptyState
page={controller.params.currentPage}
searchTerm={controller.searchTerm}
selectedTags={controller.selectedTags}
/>
<Paginator
totalCount={controller.totalItemsCount}
itemsPerPage={controller.itemsPerPage}
page={controller.page}
onChange={page => controller.updatePagination({ page })}
/>
</div>
)
}
) : (
<div className="bg-white tiled table-responsive">
<ItemsTable
items={controller.pageItems}
columns={this.listColumns}
orderByField={controller.orderByField}
orderByReverse={controller.orderByReverse}
toggleSorting={controller.toggleSorting}
/>
<Paginator
totalCount={controller.totalItemsCount}
itemsPerPage={controller.itemsPerPage}
page={controller.page}
onChange={page => controller.updatePagination({ page })}
/>
</div>
)}
</div>
) : (
<LoadingState />
)}
ranbena marked this conversation as resolved.
Show resolved Hide resolved
</Layout.Content>
</Layout>
</div>
Expand Down
2 changes: 1 addition & 1 deletion client/app/pages/dashboards/dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ <h3>
</button>
</span>

<div class="btn-group hidden-print hidden-xs" role="group" ng-show="$ctrl.dashboard.canEdit()" uib-dropdown ng-if="!$ctrl.dashboard.is_archived && !$ctrl.layoutEditing">
<div class="btn-group hidden-print hidden-xs" role="group" ng-show="$ctrl.dashboard.canEdit()" uib-dropdown ng-if="!$ctrl.dashboard.is_archived && !$ctrl.layoutEditing" data-test="DashboardMoreMenu">
<button class="btn btn-default btn-sm dropdown-toggle" uib-dropdown-toggle>
<span class="zmdi zmdi-more"></span>
</button>
Expand Down
74 changes: 74 additions & 0 deletions cypress/integration/dashboard/dashboard_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
function archiveAllDashboards() {
cy.visit('/dashboards');

// archive all dashboards
cy.getByTestId('DashboardLayoutContent').then($wrapper => {
$wrapper.find('.table-main-title').each((_, { href }) => {
archiveDashboard(href);
});
});
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I would not reset dashboards, neither before nor after. But if you want to guarantee a clean state here it will be better to use requests in this case:

  cy.request('/api/dashboards').then((response) => {
    response.body.results.forEach((dashboard) => {
      cy.request('DELETE', `/api/dashboards/${dashboard.slug}`)
    });
  });

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally perfect.

But you're right, a better approach is just not to depend on clean state. I'll fix the code. 🙇

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OMG I'm in love with the code, now doesn't require clean slate:

  1. When creating a new dashboard, listening to api response and extracting slug.
  2. Slug then used as test hook.

💪

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When creating a new dashboard, listening to api response and extracting slug.

That was really cool 👌


function createNewDashboard(dashboardName) {
cy.visit('/dashboards');
cy.getByTestId('CreateButton').click();
cy.get('li[role="menuitem"]')
.contains('Dashboard')
.click();
cy.getByTestId('EditDashboardDialog').within(() => {
cy.getByTestId('DashboardSaveButton').should('be.disabled');
cy.get('input').type(dashboardName);
cy.getByTestId('DashboardSaveButton').click();
});
}

function archiveDashboard(url) {
if (url) {
cy.visit(url);
}

cy.getByTestId('DashboardMoreMenu')
.click()
.within(() => {
cy.get('li')
.contains('Archive')
.click();
});

cy.get('.btn-warning')
.contains('Archive')
.click();
cy.get('.label-tag-archived').should('exist');
}

describe('Dashboard', () => {
beforeEach(() => {
cy.login();
archiveAllDashboards();
});

afterEach(archiveAllDashboards);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cypress has some good points not to use the afterEach to reset state. You actually solved half of that by also using the beforeHook, but I wonder if it's really worth it to have this here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes great sense 👍


it('creates a new dashboard and archives it', () => {
// create new
createNewDashboard('Foo Bar');

// verify listed in dashboards
cy.visit('/dashboards');
cy.getByTestId('DashboardLayoutContent').within(() => {
cy.get('.table-main-title')
.contains('Foo Bar')
.should('exist')
.click();
});

// archive
archiveDashboard();

// verify not listed in dashboards
cy.visit('/dashboards');
cy.getByTestId('DashboardLayoutContent').within(() => {
cy.get('.table-main-title').should('not.exist');
});
});
});