influxdb/ui/cypress/e2e/dashboardsView.test.ts

456 lines
15 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

import {Organization, AppState} from '../../src/types'
describe('Dashboard', () => {
beforeEach(() => {
cy.flush()
cy.signin().then(({body}) => {
cy.wrap(body.org).as('org')
})
cy.fixture('routes').then(({orgs}) => {
cy.get('@org').then(({id: orgID}: Organization) => {
cy.visit(`${orgs}/${orgID}/dashboards`)
})
})
})
it("can edit a dashboard's name", () => {
cy.get('@org').then(({id: orgID}: Organization) => {
cy.createDashboard(orgID).then(({body}) => {
cy.fixture('routes').then(({orgs}) => {
cy.visit(`${orgs}/${orgID}/dashboards/${body.id}`)
})
})
})
const newName = 'new 🅱ashboard'
cy.get('.renamable-page-title').click()
cy.get('.cf-input-field')
.type(newName)
.type('{enter}')
cy.fixture('routes').then(({orgs}) => {
cy.get('@org').then(({id: orgID}: Organization) => {
cy.visit(`${orgs}/${orgID}/dashboards`)
})
})
cy.getByTestID('dashboard-card').should('contain', newName)
})
it('can create a cell', () => {
cy.get('@org').then(({id: orgID}: Organization) => {
cy.createDashboard(orgID).then(({body}) => {
cy.fixture('routes').then(({orgs}) => {
cy.visit(`${orgs}/${orgID}/dashboards/${body.id}`)
})
})
})
cy.getByTestID('add-cell--button').click()
cy.getByTestID('save-cell--button').click()
cy.getByTestID('cell--view-empty').should('have.length', 1)
})
// fix for https://github.com/influxdata/influxdb/issues/15239
it('retains the cell content after canceling an edit to the cell', () => {
cy.get('@org').then(({id: orgID}: Organization) => {
cy.createDashboard(orgID).then(({body}) => {
cy.fixture('routes').then(({orgs}) => {
cy.visit(`${orgs}/${orgID}/dashboards/${body.id}`)
})
})
})
// Add an empty celly cell
cy.getByTestID('add-cell--button').click()
cy.getByTestID('save-cell--button').click()
cy.getByTestID('cell--view-empty').should('be.visible')
cy.getByTestID('cell--view-empty')
.invoke('text')
.then(cellContent => {
// cellContent is yielded as a cutesy phrase from src/shared/copy/cell
// open Cell Editor Overlay
cy.getByTestID('cell-context--toggle').click()
cy.getByTestID('cell-context--configure').click()
// Cancel edit
cy.getByTestID('cancel-cell-edit--button').click()
// Cell content should remain
cy.getByTestID('cell--view-empty').contains(cellContent)
})
})
const getSelectedVariable = (contextID: string, index?: number) => win => {
const state = win.store.getState() as AppState
const defaultVarOrder = state.resources.variables.allIDs
const defaultVarDawg =
state.resources.variables.byID[defaultVarOrder[index]] || {}
const filledVarDawg =
(state.resources.variables.values[contextID] || {values: {}}).values[
defaultVarOrder[index]
] || {}
const hydratedVarDawg = {
...defaultVarDawg,
...filledVarDawg,
}
if (hydratedVarDawg.arguments.type === 'map') {
if (!hydratedVarDawg.selected) {
hydratedVarDawg.selected = [
Object.keys(hydratedVarDawg.arguments.values)[0],
]
}
return hydratedVarDawg.arguments.values[hydratedVarDawg.selected[0]]
}
if (!hydratedVarDawg.selected) {
hydratedVarDawg.selected = [hydratedVarDawg.arguments.values[0]]
}
return hydratedVarDawg.selected[0]
}
it('can manage variable state with a lot of pointing and clicking', () => {
cy.get('@org').then(({id: orgID}: Organization) => {
cy.createDashboard(orgID).then(({body: dashboard}) => {
cy.createCSVVariable(orgID)
cy.createQueryVariable(orgID)
cy.createMapVariable(orgID).then(() => {
cy.fixture('routes').then(({orgs}) => {
cy.visit(`${orgs}/${orgID}/dashboards/${dashboard.id}`)
})
// add cell with variable in its query
cy.getByTestID('add-cell--button').click()
cy.getByTestID('switch-to-script-editor').should('be.visible')
cy.getByTestID('switch-to-script-editor').click()
cy.getByTestID('toolbar-tab').click()
// check to see if the default timeRange variables are available
cy.get('.flux-toolbar--list-item').contains('timeRangeStart')
cy.get('.flux-toolbar--list-item').contains('timeRangeStop')
cy.get('.flux-toolbar--list-item')
.first()
.within(() => {
cy.get('.cf-button').click()
})
cy.getByTestID('flux-editor')
.should('be.visible')
.click()
.focused()
.type(' ')
cy.get('.flux-toolbar--list-item')
.eq(2)
.within(() => {
cy.get('.cf-button').click()
})
cy.getByTestID('save-cell--button').click()
// TESTING CSV VARIABLE
// selected value in dashboard is 1st value
cy.getByTestID('variable-dropdown')
.eq(0)
.should('contain', 'c1')
cy.window()
.pipe(getSelectedVariable(dashboard.id, 0))
.should('equal', 'c1')
// sanity check on the url before beginning
cy.location('search').should('eq', '?lower=now%28%29%20-%201h')
// select 3rd value in dashboard
cy.getByTestID('variable-dropdown--button')
.eq(0)
.click()
cy.get(`#c3`).click()
// selected value in dashboard is 3rd value
cy.getByTestID('variable-dropdown')
.eq(0)
.should('contain', 'c3')
cy.window()
.pipe(getSelectedVariable(dashboard.id, 0))
.should('equal', 'c3')
// and that it updates the variable in the URL
cy.location('search').should(
'eq',
'?lower=now%28%29%20-%201h&vars%5BCSVVariable%5D=c3'
)
// select 2nd value in dashboard
cy.getByTestID('variable-dropdown--button')
.eq(0)
.click()
cy.get(`#c2`).click()
// and that it updates the variable in the URL without breaking stuff
cy.location('search').should(
'eq',
'?lower=now%28%29%20-%201h&vars%5BCSVVariable%5D=c2'
)
// open CEO
cy.getByTestID('cell-context--toggle').click()
cy.getByTestID('cell-context--configure').click()
// selected value in cell context is 2nd value
cy.window()
.pipe(getSelectedVariable(dashboard.id, 0))
.should('equal', 'c2')
cy.getByTestID('toolbar-tab').click()
cy.get('.flux-toolbar--list-item')
.first()
.trigger('mouseover')
// toggle the variable dropdown in the VEO cell dashboard
cy.getByTestID('toolbar-popover--contents').within(() => {
cy.getByTestID('variable-dropdown--button').click()
// select 1st value in cell
cy.getByTestID('variable-dropdown--item')
.first()
.click()
})
// save cell
cy.getByTestID('save-cell--button').click()
// selected value in cell context is 1st value
cy.window()
.pipe(getSelectedVariable(dashboard.id, 0))
.should('equal', 'c1')
// selected value in dashboard is 1st value
cy.getByTestID('variable-dropdown').should('contain', 'c1')
cy.window()
.pipe(getSelectedVariable(dashboard.id, 0))
.should('equal', 'c1')
// TESTING MAP VARIABLE
// selected value in dashboard is 1st value
cy.getByTestID('variable-dropdown')
.eq(1)
.should('contain', 'k1')
cy.window()
.pipe(getSelectedVariable(dashboard.id, 2))
.should('equal', 'v1')
// select 2nd value in dashboard
cy.getByTestID('variable-dropdown--button')
.eq(1)
.click()
cy.get(`#k2`).click()
// selected value in dashboard is 2nd value
cy.getByTestID('variable-dropdown')
.eq(1)
.should('contain', 'k2')
cy.window()
.pipe(getSelectedVariable(dashboard.id, 2))
.should('equal', 'v2')
// open CEO
cy.getByTestID('cell-context--toggle').click()
cy.getByTestID('cell-context--configure').click()
cy.getByTestID('toolbar-tab').should('be.visible')
// selected value in cell context is 2nd value
cy.window()
.pipe(getSelectedVariable(dashboard.id, 2))
.should('equal', 'v2')
cy.getByTestID('toolbar-tab').click()
cy.get('.flux-toolbar--list-item')
.eq(2)
.trigger('mouseover')
// toggle the variable dropdown in the VEO cell dashboard
cy.getByTestID('toolbar-popover--contents').within(() => {
cy.getByTestID('variable-dropdown--button').click()
// select 1st value in cell
cy.getByTestID('variable-dropdown--item')
.first()
.click()
})
// save cell
cy.getByTestID('save-cell--button').click()
// selected value in cell context is 1st value
cy.window()
.pipe(getSelectedVariable(dashboard.id, 2))
.should('equal', 'v1')
// selected value in dashboard is 1st value
cy.getByTestID('variable-dropdown').should('contain', 'k1')
cy.window()
.pipe(getSelectedVariable(dashboard.id, 2))
.should('equal', 'v1')
})
})
})
})
/*\
built to approximate an instance with docker metrics,
operating with the variables:
depbuck:
from(bucket: v.buckets)
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "docker_container_cpu")
|> keep(columns: ["container_name"])
|> rename(columns: {"container_name": "_value"})
|> last()
|> group()
buckets:
buckets()
|> filter(fn: (r) => r.name !~ /^_/)
|> rename(columns: {name: "_value"})
|> keep(columns: ["_value"])
and a dashboard built of :
cell one:
from(bucket: v.buckets)
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "docker_container_cpu")
|> filter(fn: (r) => r["_field"] == "usage_percent")
cell two:
from(bucket: v.buckets)
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "docker_container_cpu")
|> filter(fn: (r) => r["_field"] == "usage_percent")
|> filter(fn: (r) => r["container_name"] == v.depbuck)
with only 4 api queries being sent to fulfill it all
\*/
it('can load dependent queries without much fuss', () => {
cy.get('@org').then(({id: orgID}: Organization) => {
cy.createDashboard(orgID).then(({body: dashboard}) => {
const now = Date.now()
cy.writeData([
`test,container_name=cool dopeness=12 ${now - 1000}000000`,
`test,container_name=beans dopeness=18 ${now - 1200}000000`,
`test,container_name=cool dopeness=14 ${now - 1400}000000`,
`test,container_name=beans dopeness=10 ${now - 1600}000000`,
])
cy.createCSVVariable(orgID, 'static', ['beans', 'defbuck'])
cy.createQueryVariable(
orgID,
'dependent',
`from(bucket: v.static)
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "test")
|> keep(columns: ["container_name"])
|> rename(columns: {"container_name": "_value"})
|> last()
|> group()`
)
cy.fixture('routes').then(({orgs}) => {
cy.visit(`${orgs}/${orgID}/dashboards/${dashboard.id}`)
})
})
})
cy.getByTestID('add-cell--button').click()
cy.getByTestID('switch-to-script-editor').should('be.visible')
cy.getByTestID('switch-to-script-editor').click()
cy.getByTestID('toolbar-tab').click()
cy
.getByTestID('flux-editor')
.should('be.visible')
.click()
.focused().type(`from(bucket: v.static)
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "test")
|> filter(fn: (r) => r["_field"] == "dopeness")
|> filter(fn: (r) => r["container_name"] == v.dependent)`)
cy.getByTestID('save-cell--button').click()
// the default bucket selection should have no results
cy.getByTestID('variable-dropdown')
.eq(0)
.should('contain', 'beans')
// and cause the rest to exist in loading states
cy.getByTestID('variable-dropdown')
.eq(1)
.should('contain', 'Loading')
cy.getByTestID('cell--view-empty')
// But selecting a nonempty bucket should load some data
cy.getByTestID('variable-dropdown--button')
.eq(0)
.click()
cy.get(`#defbuck`).click()
// default select the first result
cy.getByTestID('variable-dropdown')
.eq(1)
.should('contain', 'beans')
// and also load the second result
cy.getByTestID('variable-dropdown--button')
.eq(1)
.click()
cy.get(`#cool`).click()
})
it('can create a view through the API', () => {
cy.get('@org').then(({id: orgID}: Organization) => {
cy.createDashWithViewAndVar(orgID).then(() => {
cy.fixture('routes').then(({orgs}) => {
cy.visit(`${orgs}/${orgID}/dashboards`)
cy.getByTestID('dashboard-card--name').click()
cy.get('.cell--view').should('have.length', 1)
})
})
})
})
it("Should return empty table parameters when query hasn't been submitted", () => {
cy.get('@org').then(({id: orgID}: Organization) => {
cy.createDashboard(orgID).then(({body}) => {
cy.fixture('routes').then(({orgs}) => {
cy.visit(`${orgs}/${orgID}/dashboards/${body.id}`)
})
})
})
cy.getByTestID('add-cell--button')
.click()
.then(() => {
cy.get('.view-options').should('not.exist')
cy.getByTestID('cog-cell--button')
.should('have.length', 1)
.click()
// should toggle the view options
cy.get('.view-options').should('exist')
cy.getByTestID('dropdown--button')
.contains('Graph')
.click()
.then(() => {
cy.getByTestID('view-type--table')
.contains('Table')
.should('have.length', 1)
.click()
cy.getByTestID('empty-state--text')
.contains('This query returned no columns')
.should('exist')
})
})
})
})