diff --git a/ui/cypress/e2e/buckets.test.ts b/ui/cypress/e2e/buckets.test.ts index 304e869c88..d941a419da 100644 --- a/ui/cypress/e2e/buckets.test.ts +++ b/ui/cypress/e2e/buckets.test.ts @@ -22,17 +22,17 @@ describe('Buckets', () => { describe('from the org view', () => { it('can create a bucket', () => { const newBucket = '🅱️ucket' - cy.getByDataTest('table-row').should('have.length', 1) + cy.getByTestID('table-row').should('have.length', 1) cy.contains('Create').click() - cy.getByDataTest('overlay--container').within(() => { + cy.getByTestID('overlay--container').within(() => { cy.getByInputName('name').type(newBucket) cy.get('.button') .contains('Create') .click() }) - cy.getByDataTest('table-row') + cy.getByTestID('table-row') .should('have.length', 2) .and('contain', newBucket) }) @@ -44,14 +44,14 @@ describe('Buckets', () => { cy.contains(name).click() }) - cy.getByDataTest('retention-intervals').click() + cy.getByTestID('retention-intervals').click() cy.getByInputName('days').type('{uparrow}') cy.getByInputName('hours').type('{uparrow}') cy.getByInputName('minutes').type('{uparrow}') cy.getByInputName('seconds').type('{uparrow}') - cy.getByDataTest('overlay--container').within(() => { + cy.getByTestID('overlay--container').within(() => { cy.getByInputName('name') .clear() .type(newName) @@ -59,7 +59,7 @@ describe('Buckets', () => { cy.contains('Save').click() }) - cy.getByDataTest('table-row') + cy.getByTestID('table-row') .should('contain', '1 day') .and('contain', newName) }) diff --git a/ui/cypress/e2e/dashboards.test.ts b/ui/cypress/e2e/dashboards.test.ts deleted file mode 100644 index 2be4ca2946..0000000000 --- a/ui/cypress/e2e/dashboards.test.ts +++ /dev/null @@ -1,101 +0,0 @@ -import {Organization} from '@influxdata/influx' - -describe('Dashboards', () => { - beforeEach(() => { - cy.flush() - - cy.setupUser().then(({body}) => { - cy.wrap(body.org).as('org') - }) - - cy.get('@org').then(org => { - cy.signin(org.id) - }) - - cy.fixture('routes').then(({dashboards}) => { - cy.visit(dashboards) - }) - }) - - it('can create a dashboard from empty state', () => { - cy.get('.empty-state') - .contains('Create') - .click() - - cy.visit('/dashboards') - - cy.get('.index-list--row') - .its('length') - .should('be.eq', 1) - }) - - it('can create a dashboard from the header', () => { - cy.get('.page-header--container') - .contains('Create') - .click() - - cy.getByDataTest('dropdown--item New Dashboard').click() - - cy.visit('/dashboards') - - cy.get('.index-list--row') - .its('length') - .should('be.eq', 1) - }) - - it('can delete a dashboard', () => { - cy.get('@org').then(({id}) => { - cy.createDashboard(id) - cy.createDashboard(id) - }) - - cy.get('.index-list--row').then(rows => { - const numDashboards = rows.length - - cy.get('.button-danger') - .first() - .click() - - cy.contains('Confirm') - .first() - .click({force: true}) - - cy.get('.index-list--row') - .its('length') - .should('eq', numDashboards - 1) - }) - }) - - it('can edit a dashboards name', () => { - cy.get('@org').then(({id}) => { - cy.createDashboard(id).then(({body}) => { - cy.visit(`/dashboards/${body.id}`) - }) - }) - - const newName = 'new 🅱️ashboard' - - cy.get('.renamable-page-title--title').click() - cy.get('.input-field') - .type(newName) - .type('{enter}') - - cy.visit('/dashboards') - - cy.get('.index-list--row').should('contain', newName) - }) - - describe('Cells', () => { - it('can create a cell', () => { - cy.get('@org').then(({id}) => { - cy.createDashboard(id).then(({body}) => { - cy.visit(`/dashboards/${body.id}`) - }) - }) - - cy.getByDataTest('add-cell--button').click() - cy.getByDataTest('save-cell--button').click() - cy.getByDataTest('cell--view-empty').should('have.length', 1) - }) - }) -}) diff --git a/ui/cypress/e2e/dashboardsIndex.test.ts b/ui/cypress/e2e/dashboardsIndex.test.ts new file mode 100644 index 0000000000..76b2c33453 --- /dev/null +++ b/ui/cypress/e2e/dashboardsIndex.test.ts @@ -0,0 +1,91 @@ +import {Organization} from '@influxdata/influx' + +describe('Dashboards', () => { + beforeEach(() => { + cy.flush() + + cy.setupUser().then(({body}) => { + cy.wrap(body.org).as('org') + }) + + cy.get('@org').then(org => { + cy.signin(org.id) + }) + + cy.fixture('routes').then(({dashboards}) => { + cy.visit(dashboards) + }) + }) + + it('can create a dashboard from empty state', () => { + cy.getByTestID('empty-state') + .contains('Create') + .click() + + cy.visit('/dashboards') + + cy.getByTestID('resource-card') + .its('length') + .should('be.eq', 1) + }) + + it('can create a dashboard from the header', () => { + cy.get('.page-header--container') + .contains('Create') + .click() + + cy.getByTestID('dropdown--item New Dashboard').click() + + cy.visit('/dashboards') + + cy.getByTestID('resource-card') + .its('length') + .should('be.eq', 1) + }) + + it('can delete a dashboard', () => { + cy.get('@org').then(({id}) => { + cy.createDashboard(id) + cy.createDashboard(id) + }) + + cy.getByTestID('resource-card') + .its('length') + .should('eq', 2) + + cy.getByTestID('resource-card') + .first() + .trigger('mouseover') + .within(() => { + cy.getByTestID('context-delete-menu').click() + + cy.getByTestID('context-delete-dashboard').click() + }) + + cy.getByTestID('resource-card') + .its('length') + .should('eq', 1) + }) + + it('can edit a dashboards name', () => { + cy.get('@org').then(({id}) => { + cy.createDashboard(id) + }) + + const newName = 'new 🅱️ashboard' + + cy.getByTestID('resource-card').within(() => { + cy.getByTestID('dashboard-card--name').trigger('mouseover') + + cy.getByTestID('dashboard-card--name-button').click() + + cy.get('.input-field') + .type(newName) + .type('{enter}') + }) + + cy.visit('/dashboards') + + cy.getByTestID('resource-card').should('contain', newName) + }) +}) diff --git a/ui/cypress/e2e/dashboardsView.test.ts b/ui/cypress/e2e/dashboardsView.test.ts new file mode 100644 index 0000000000..7e0238d754 --- /dev/null +++ b/ui/cypress/e2e/dashboardsView.test.ts @@ -0,0 +1,50 @@ +import {Organization} from '@influxdata/influx' + +describe('Dashboard', () => { + beforeEach(() => { + cy.flush() + + cy.setupUser().then(({body}) => { + cy.wrap(body.org).as('org') + }) + + cy.get('@org').then(org => { + cy.signin(org.id) + }) + + cy.fixture('routes').then(({dashboards}) => { + cy.visit(dashboards) + }) + }) + + it('can edit a dashboards name', () => { + cy.get('@org').then(({id}) => { + cy.createDashboard(id).then(({body}) => { + cy.visit(`/dashboards/${body.id}`) + }) + }) + + const newName = 'new 🅱️ashboard' + + cy.get('.renamable-page-title--title').click() + cy.get('.input-field') + .type(newName) + .type('{enter}') + + cy.visit('/dashboards') + + cy.getByTestID('resource-card').should('contain', newName) + }) + + it('can create a cell', () => { + cy.get('@org').then(({id}) => { + cy.createDashboard(id).then(({body}) => { + cy.visit(`/dashboards/${body.id}`) + }) + }) + + cy.getByTestID('add-cell--button').click() + cy.getByTestID('save-cell--button').click() + cy.getByTestID('cell--view-empty').should('have.length', 1) + }) +}) diff --git a/ui/cypress/e2e/explorer.ts b/ui/cypress/e2e/explorer.test.ts similarity index 100% rename from ui/cypress/e2e/explorer.ts rename to ui/cypress/e2e/explorer.test.ts diff --git a/ui/cypress/e2e/login.ts b/ui/cypress/e2e/login.test.ts similarity index 80% rename from ui/cypress/e2e/login.ts rename to ui/cypress/e2e/login.test.ts index 9acd261f58..98e05ed07d 100644 --- a/ui/cypress/e2e/login.ts +++ b/ui/cypress/e2e/login.test.ts @@ -22,7 +22,7 @@ describe('The Login Page', () => { cy.getByInputName('password').type(user.password) cy.get('button[type=submit]').click() - cy.getByDataTest('nav').should('exist') + cy.getByTestID('nav').should('exist') }) describe('login failure', () => { @@ -30,14 +30,14 @@ describe('The Login Page', () => { cy.getByInputName('password').type(user.password) cy.get('button[type=submit]').click() - cy.getByDataTest('notification-error').should('exist') + cy.getByTestID('notification-error').should('exist') }) it('if password is not present', () => { cy.getByInputName('username').type(user.username) cy.get('button[type=submit]').click() - cy.getByDataTest('notification-error').should('exist') + cy.getByTestID('notification-error').should('exist') }) it('if username is incorrect', () => { @@ -45,7 +45,7 @@ describe('The Login Page', () => { cy.getByInputName('password').type(user.password) cy.get('button[type=submit]').click() - cy.getByDataTest('notification-error').should('exist') + cy.getByTestID('notification-error').should('exist') }) it('if password is incorrect', () => { @@ -53,7 +53,7 @@ describe('The Login Page', () => { cy.getByInputName('password').type('not-a-password') cy.get('button[type=submit]').click() - cy.getByDataTest('notification-error').should('exist') + cy.getByTestID('notification-error').should('exist') }) }) }) diff --git a/ui/cypress/e2e/orgs.ts b/ui/cypress/e2e/orgs.test.ts similarity index 87% rename from ui/cypress/e2e/orgs.ts rename to ui/cypress/e2e/orgs.test.ts index 7c07ff7b1b..53f57a29dd 100644 --- a/ui/cypress/e2e/orgs.ts +++ b/ui/cypress/e2e/orgs.test.ts @@ -16,14 +16,13 @@ describe('Orgs', () => { .its('length') .should('be.eq', 1) - cy.get('.page-header--right > .button') - .contains('Create') - .click() + cy.getByTestID('create-org-button').click() const orgName = '🅱️organization' - cy.getByInputName('name').type(orgName) - cy.getByTitle('Create').click() + cy.getByTestID('create-org-name-input').type(orgName) + + cy.getByTestID('create-org-submit-button').click() cy.get('.index-list--row') .should('contain', orgName) diff --git a/ui/cypress/e2e/tasks.test.ts b/ui/cypress/e2e/tasks.test.ts index ab5724348e..0362d7c356 100644 --- a/ui/cypress/e2e/tasks.test.ts +++ b/ui/cypress/e2e/tasks.test.ts @@ -22,7 +22,7 @@ describe('Tasks', () => { cy.getByInputName('interval').type('1d') cy.getByInputName('offset').type('20m') - cy.getByDataTest('flux-editor').within(() => { + cy.getByTestID('flux-editor').within(() => { cy.get('textarea').type( `from(bucket: "defbuck") |> range(start: -2m)`, @@ -32,7 +32,7 @@ describe('Tasks', () => { cy.contains('Save').click() - cy.getByDataTest('task-row') + cy.getByTestID('task-row') .should('have.length', 1) .and('contain', taskName) }) @@ -43,13 +43,13 @@ describe('Tasks', () => { cy.createTask(id) }) - cy.getByDataTest('task-row').should('have.length', 2) + cy.getByTestID('task-row').should('have.length', 2) - cy.getByDataTest('confirmation-button') + cy.getByTestID('confirmation-button') .first() .click({force: true}) - cy.getByDataTest('task-row').should('have.length', 1) + cy.getByTestID('task-row').should('have.length', 1) }) it('fails to create a task without a valid script', () => { @@ -61,12 +61,12 @@ describe('Tasks', () => { cy.getByInputName('interval').type('1d') cy.getByInputName('offset').type('20m') - cy.getByDataTest('flux-editor').within(() => { + cy.getByTestID('flux-editor').within(() => { cy.get('textarea').type('{}', {force: true}) }) cy.contains('Save').click() - cy.getByDataTest('notification-error').should('exist') + cy.getByTestID('notification-error').should('exist') }) }) diff --git a/ui/cypress/e2e/variables.test.ts b/ui/cypress/e2e/variables.test.ts index e8a1ae1747..fa676981c4 100644 --- a/ui/cypress/e2e/variables.test.ts +++ b/ui/cypress/e2e/variables.test.ts @@ -16,7 +16,7 @@ describe('Variables', () => { }) cy.getByInputName('name').type('Little Variable') - cy.getByDataTest('flux-editor').within(() => { + cy.getByTestID('flux-editor').within(() => { cy.get('textarea').type('filter(fn: (r) => r._field == "cpu")', { force: true, }) @@ -26,6 +26,6 @@ describe('Variables', () => { .contains('Create') .click() - cy.getByDataTest('variable-row').should('have.length', 1) + cy.getByTestID('variable-row').should('have.length', 1) }) }) diff --git a/ui/cypress/index.d.ts b/ui/cypress/index.d.ts index d16a4f0c8e..fb97b90824 100644 --- a/ui/cypress/index.d.ts +++ b/ui/cypress/index.d.ts @@ -6,7 +6,7 @@ import { createOrg, createSource, flush, - getByDataTest, + getByTestID, getByInputName, getByTitle, createTask, @@ -22,7 +22,7 @@ declare global { createDashboard: typeof createDashboard createOrg: typeof createOrg flush: typeof flush - getByDataTest: typeof getByDataTest + getByTestID: typeof getByTestID getByInputName: typeof getByInputName getByTitle: typeof getByTitle } diff --git a/ui/cypress/support/commands.ts b/ui/cypress/support/commands.ts index 6e9296fe98..252bf965c3 100644 --- a/ui/cypress/support/commands.ts +++ b/ui/cypress/support/commands.ts @@ -98,7 +98,7 @@ export const flush = () => { } // DOM node getters -export const getByDataTest = (dataTest: string): Cypress.Chainable => { +export const getByTestID = (dataTest: string): Cypress.Chainable => { return cy.get(`[data-testid="${dataTest}"]`) } @@ -111,7 +111,7 @@ export const getByTitle = (name: string): Cypress.Chainable => { } // getters -Cypress.Commands.add('getByDataTest', getByDataTest) +Cypress.Commands.add('getByTestID', getByTestID) Cypress.Commands.add('getByInputName', getByInputName) Cypress.Commands.add('getByTitle', getByTitle) diff --git a/ui/mocks/MockChild.tsx b/ui/mocks/MockChild.tsx index 62f5386009..624bf831c3 100644 --- a/ui/mocks/MockChild.tsx +++ b/ui/mocks/MockChild.tsx @@ -1,5 +1,5 @@ import React, {SFC} from 'react' -const MockChild: SFC = () =>
+const MockChild: SFC = () =>
export default MockChild diff --git a/ui/package-lock.json b/ui/package-lock.json index b6c8290d1b..02174c269b 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -10500,6 +10500,11 @@ "xml": "^1.0.0" } }, + "mocks": { + "version": "0.0.15", + "resolved": "https://registry.npmjs.org/mocks/-/mocks-0.0.15.tgz", + "integrity": "sha1-RmClzFn07Fbrk7/XLwg0+PxPoRw=" + }, "moment": { "version": "2.22.2", "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", diff --git a/ui/src/clockface/components/confirmation_button/ConfirmationButton.tsx b/ui/src/clockface/components/confirmation_button/ConfirmationButton.tsx index 063e049c6b..fd6ff62f10 100644 --- a/ui/src/clockface/components/confirmation_button/ConfirmationButton.tsx +++ b/ui/src/clockface/components/confirmation_button/ConfirmationButton.tsx @@ -91,7 +91,6 @@ class ConfirmationButton extends Component { />
{ wrapper.find(Button).simulate('click') - wrapper - .find({'data-test': 'confirmation-button--click-target'}) - .simulate('click') + wrapper.find({'data-testid': 'confirmation-button'}).simulate('click') expect(onConfirm.mock.results[0].value).toBe(returnValue) }) diff --git a/ui/src/clockface/components/confirmation_button/test/__snapshots__/ConfirmationButton.test.tsx.snap b/ui/src/clockface/components/confirmation_button/test/__snapshots__/ConfirmationButton.test.tsx.snap index eb253117e9..d609552a2c 100644 --- a/ui/src/clockface/components/confirmation_button/test/__snapshots__/ConfirmationButton.test.tsx.snap +++ b/ui/src/clockface/components/confirmation_button/test/__snapshots__/ConfirmationButton.test.tsx.snap @@ -44,7 +44,6 @@ exports[`ConfirmationButton interaction shows the tooltip when clicked 1`] = ` >
diff --git a/ui/src/clockface/components/context_menu/Context.tsx b/ui/src/clockface/components/context_menu/Context.tsx index 03420502a0..f4e28a0b59 100644 --- a/ui/src/clockface/components/context_menu/Context.tsx +++ b/ui/src/clockface/components/context_menu/Context.tsx @@ -55,7 +55,7 @@ class Context extends PureComponent { /> ) } else { - throw new Error('Expected children of type ') + return child } })}
diff --git a/ui/src/clockface/components/context_menu/ContextMenu.tsx b/ui/src/clockface/components/context_menu/ContextMenu.tsx index 8a25b4ed12..4e76c3f750 100644 --- a/ui/src/clockface/components/context_menu/ContextMenu.tsx +++ b/ui/src/clockface/components/context_menu/ContextMenu.tsx @@ -17,26 +17,32 @@ import { import {ErrorHandling} from 'src/shared/decorators/errors' -interface Props { +interface PassedProps { children: JSX.Element | JSX.Element[] icon: IconFont - text?: string - title - color?: ComponentColor - shape?: ButtonShape onBoostZIndex?: (boostZIndex: boolean) => void } +interface DefaultProps { + text?: string + color?: ComponentColor + shape?: ButtonShape + testID?: string +} + +type Props = PassedProps & DefaultProps + interface State { isExpanded: boolean } @ErrorHandling class ContextMenu extends Component { - public static defaultProps: Partial = { + public static defaultProps: DefaultProps = { color: ComponentColor.Primary, shape: ButtonShape.Square, text: '', + testID: 'context-menu', } constructor(props: Props) { @@ -48,7 +54,7 @@ class ContextMenu extends Component { } public render() { - const {icon, text, shape, color} = this.props + const {icon, text, shape, color, testID} = this.props return ( @@ -61,6 +67,7 @@ class ContextMenu extends Component { icon={icon} size={ComponentSize.ExtraSmall} color={color} + testID={testID} /> {this.menu}
diff --git a/ui/src/clockface/components/context_menu/ContextMenuItem.tsx b/ui/src/clockface/components/context_menu/ContextMenuItem.tsx index 4a0173b7ac..b3438c82f0 100644 --- a/ui/src/clockface/components/context_menu/ContextMenuItem.tsx +++ b/ui/src/clockface/components/context_menu/ContextMenuItem.tsx @@ -2,24 +2,36 @@ import React, {Component} from 'react' import classnames from 'classnames' -interface Props { +interface PassedProps { label: string - description?: string action: (value?: any) => void value?: any onCollapseMenu?: () => void disabled?: boolean } +interface DefaultProps { + description?: string + testID?: string +} + +type Props = PassedProps & DefaultProps + class ContextMenuItem extends Component { + public static defaultProps: DefaultProps = { + description: null, + testID: 'context-menu-item', + } + public render() { - const {label, disabled} = this.props + const {label, disabled, testID} = this.props return (