test(e2e): Bonitoo cypress tokens (#13895)
* added writeData command * better junit reporting * adding package-lock.json as per circle-ci hint * delinting * removed chainable .only. * removed commented line * starting onboarding test * onboarding assert * complete onboarding to quick start * additional onboarding tests * delinting * adding field requirements test * fixing merge conflicts * WIP - updating to new org ctx - stablizing * WIP - linting - stablizing * fixing merge conflicts * refactor onboarding test to leverage data-testid * fixing jstests with new data-testid attribs * resynch promql.go * refactor add last data-testid replacements onb test * replacing lost asserts * improving assert * passing in additional data-testid values * removing bin_gen.go from branch * starting tokens test * troubleshoot tokens test * WIP tokens test - clean up after troubleshoot * WIP - tokens tests * synching tokens test with clockface changes * updating testID in tokens test * re-enable all current tokens tests * linted tokens.test.ts * stablize beforeEach in tokens.testpull/13614/head
parent
7b2d76c77b
commit
e9ccde1d78
|
@ -0,0 +1,344 @@
|
|||
import {Organization} from '@influxdata/influx'
|
||||
|
||||
describe('tokens', () => {
|
||||
let authData: {description: string; status: boolean; id: string}[]
|
||||
let testTokens: {
|
||||
id: string
|
||||
description: string
|
||||
status: string
|
||||
permissions: object[]
|
||||
}[]
|
||||
|
||||
beforeEach(() => {
|
||||
cy.flush()
|
||||
|
||||
authData = []
|
||||
|
||||
cy.signin().then(({body}) => {
|
||||
const {
|
||||
org: {id},
|
||||
} = body
|
||||
cy.wrap(body.org).as('org')
|
||||
|
||||
testTokens = [
|
||||
{
|
||||
id: id,
|
||||
description: 'token test \u0950',
|
||||
status: 'active',
|
||||
permissions: [
|
||||
{action: 'write', resource: {type: 'views'}},
|
||||
{action: 'write', resource: {type: 'documents'}},
|
||||
{action: 'write', resource: {type: 'dashboards'}},
|
||||
{action: 'write', resource: {type: 'buckets'}},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: id,
|
||||
description: 'token test 02',
|
||||
status: 'inactive',
|
||||
permissions: [
|
||||
{action: 'write', resource: {type: 'views'}},
|
||||
{action: 'write', resource: {type: 'documents'}},
|
||||
{action: 'write', resource: {type: 'dashboards'}},
|
||||
{action: 'write', resource: {type: 'buckets'}},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: id,
|
||||
description: 'token test 03',
|
||||
status: 'inactive',
|
||||
permissions: [
|
||||
{action: 'read', resource: {type: 'views'}},
|
||||
{action: 'read', resource: {type: 'documents'}},
|
||||
{action: 'read', resource: {type: 'dashboards'}},
|
||||
{action: 'read', resource: {type: 'buckets'}},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
//check out array.reduce for the nested calls here
|
||||
cy.request('api/v2/authorizations').then(resp => {
|
||||
expect(resp.body).to.exist
|
||||
authData.push({
|
||||
description: resp.body.authorizations[0].description,
|
||||
status: resp.body.authorizations[0].status === 'active',
|
||||
id: resp.body.authorizations[0].id,
|
||||
})
|
||||
|
||||
testTokens.forEach(token => {
|
||||
cy.createToken(
|
||||
token.id,
|
||||
token.description,
|
||||
token.status,
|
||||
token.permissions
|
||||
).then(resp => {
|
||||
expect(resp.body).to.exist
|
||||
authData.push({
|
||||
description: resp.body.description,
|
||||
status: resp.body.status === 'active',
|
||||
id: resp.body.id,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
cy.fixture('routes').then(({orgs}) => {
|
||||
cy.visit(`${orgs}/${id}/tokens`)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('can list tokens', () => {
|
||||
cy.getByTestID('table-row').should('have.length', 4)
|
||||
cy.getByTestID('table-row').then(rows => {
|
||||
authData = authData.sort((a, b) =>
|
||||
// eslint-disable-next-line
|
||||
a.description < b.description ? -1 : a.description > b.description ? 1 : 0
|
||||
)
|
||||
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
cy.getByTestID('editable-name')
|
||||
.eq(i)
|
||||
.children('a')
|
||||
.children('span')
|
||||
.should('have.text', authData[i].description)
|
||||
|
||||
if (authData[i].status) {
|
||||
cy.getByTestID('slide-toggle')
|
||||
.eq(i)
|
||||
.should('have.class', 'active')
|
||||
} else {
|
||||
cy.getByTestID('slide-toggle')
|
||||
.eq(i)
|
||||
.should('not.have.class', 'active')
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('can filter tokens', () => {
|
||||
//basic filter
|
||||
cy.getByTestID('input-field--filter').type('test')
|
||||
cy.getByTestID('table-row').should('have.length', 3)
|
||||
|
||||
//clear filter
|
||||
cy.getByTestID('input-field--filter').clear()
|
||||
cy.getByTestID('table-row').should('have.length', 4)
|
||||
|
||||
//exotic filter
|
||||
cy.getByTestID('input-field--filter').type('\u0950')
|
||||
cy.getByTestID('table-row').should('have.length', 1)
|
||||
})
|
||||
|
||||
it('can change token activation status', () => {
|
||||
//toggle on
|
||||
cy.getByTestID('table-row')
|
||||
.contains('token test 02')
|
||||
.parents('[data-testid=table-row]')
|
||||
.within(() => {
|
||||
cy.getByTestID('slide-toggle')
|
||||
.click()
|
||||
.then(() => {
|
||||
//wait for backend to sync
|
||||
cy.wait(1000)
|
||||
|
||||
//check for status update on backend
|
||||
// @ts-ignore
|
||||
cy.request(
|
||||
'api/v2/authorizations/' +
|
||||
authData.find(function(item) {
|
||||
return item.description === 'token test 02'
|
||||
}).id
|
||||
).then(resp => {
|
||||
expect(resp.body.status).equals('active')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
cy.getByTestID('table-row')
|
||||
.contains('token test 02')
|
||||
.parents('[data-testid=table-row]')
|
||||
.within(() => {
|
||||
cy.getByTestID('slide-toggle').should('have.class', 'active')
|
||||
})
|
||||
|
||||
cy.getByTestID('table-row')
|
||||
.contains('token test 02')
|
||||
.parents('[data-testid=table-row]')
|
||||
.within(() => {
|
||||
cy.getByTestID('slide-toggle')
|
||||
.click()
|
||||
.then(() => {
|
||||
//wait for backend to sync
|
||||
cy.wait(1000)
|
||||
|
||||
//check for status update on backend
|
||||
// @ts-ignore
|
||||
cy.request(
|
||||
'api/v2/authorizations/' +
|
||||
authData.find(function(item) {
|
||||
return item.description === 'token test 02'
|
||||
}).id
|
||||
).then(resp => {
|
||||
expect(resp.body.status).equals('inactive')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
cy.getByTestID('table-row')
|
||||
.contains('token test 02')
|
||||
.parents('[data-testid=table-row]')
|
||||
.within(() => {
|
||||
cy.getByTestID('slide-toggle').should('not.have.class', 'active')
|
||||
})
|
||||
})
|
||||
|
||||
it('can delete a token', () => {
|
||||
cy.getByTestID('table-row').should('have.length', 4)
|
||||
|
||||
cy.getByTestID('table-row')
|
||||
.contains('token test 03')
|
||||
.parents('[data-testid=table-row]')
|
||||
.within(() => {
|
||||
cy.getByTestID('delete-button')
|
||||
.click()
|
||||
.then(() => {
|
||||
cy.getByTestID('confirmation-button').click({force: true})
|
||||
})
|
||||
})
|
||||
|
||||
cy.getByTestID('table-row').should('have.length', 3)
|
||||
|
||||
cy.getByTestID('table-row')
|
||||
.contains('token test 03')
|
||||
.should('not.exist')
|
||||
})
|
||||
|
||||
it('can generate a read/write token', () => {
|
||||
cy.getByTestID('table-row').should('have.length', 4)
|
||||
|
||||
//create some extra buckets for filters
|
||||
cy.get<Organization>('@org').then(({id, name}) => {
|
||||
cy.createBucket(id, name, 'Magna Carta').then(() => {
|
||||
cy.createBucket(id, name, 'Sicilsky Bull').then(() => {
|
||||
cy.createBucket(id, name, 'A la Carta')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// open overlay
|
||||
cy.getByTestID('dropdown-button--gen-token').click()
|
||||
cy.getByTestIDSubStr('dropdown--item').should('have.length', 2)
|
||||
cy.getByTestID('dropdown--item Read/Write Token').click()
|
||||
cy.getByTestID('overlay--container').should('be.visible')
|
||||
|
||||
//check cancel
|
||||
cy.getByTestID('button--cancel').click()
|
||||
cy.getByTestID('overlay--container').should('not.be.visible')
|
||||
cy.getByTestID('table-row').should('have.length', 4)
|
||||
|
||||
// open overlay - again
|
||||
cy.getByTestID('dropdown-button--gen-token').click()
|
||||
cy.getByTestIDSubStr('dropdown--item').should('have.length', 2)
|
||||
cy.getByTestID('dropdown--item Read/Write Token').click()
|
||||
cy.getByTestID('overlay--container').should('be.visible')
|
||||
|
||||
//Create a token //todo filters in this or seperate test
|
||||
cy.getByTestID('input-field--descr').type('Jeton 01')
|
||||
cy.getByTestID('builder-card--body')
|
||||
.eq(0)
|
||||
.within(() => {
|
||||
cy.getByTitle('Click to filter by Sicilsky Bull').click()
|
||||
cy.getByTitle('Click to filter by A la Carta').click()
|
||||
})
|
||||
cy.getByTestID('builder-card--body')
|
||||
.eq(1)
|
||||
.within(() => {
|
||||
cy.getByTitle('Click to filter by Sicilsky Bull').click()
|
||||
})
|
||||
|
||||
cy.getByTestID('button--save').click()
|
||||
cy.getByTestID('overlay--container').should('not.be.visible')
|
||||
|
||||
//Verify token
|
||||
cy.getByTestID('table-row')
|
||||
.should('have.length', 5)
|
||||
.contains('Jeton 01')
|
||||
.should('be.visible')
|
||||
cy.getByTestID('table-row')
|
||||
.contains('Jeton 01')
|
||||
.click()
|
||||
cy.getByTestID('overlay--container').should('be.visible')
|
||||
cy.getByTestID('overlay--header').should('contain', 'Jeton 01')
|
||||
cy.getByTestID('permissions-section').should('have.length', 2)
|
||||
|
||||
cy.getByTestID('permissions-section')
|
||||
.contains('buckets-Sicilsky Bull')
|
||||
.should('be.visible')
|
||||
cy.getByTestID('permissions-section')
|
||||
.contains('buckets-Sicilsky Bull')
|
||||
.parent()
|
||||
.parent()
|
||||
.within(() => {
|
||||
cy.getByTestID('permissions--item').should('have.length', 2)
|
||||
cy.getByTestID('permissions--item')
|
||||
.contains('write')
|
||||
.should('be.visible')
|
||||
cy.getByTestID('permissions--item')
|
||||
.contains('read')
|
||||
.should('be.visible')
|
||||
})
|
||||
|
||||
cy.getByTestID('permissions-section')
|
||||
.contains('buckets-A la Carta')
|
||||
.parent()
|
||||
.parent()
|
||||
.within(() => {
|
||||
cy.getByTestID('permissions--item').should('have.length', 1)
|
||||
cy.getByTestID('permissions--item')
|
||||
.contains('write')
|
||||
.should('not.be.visible')
|
||||
cy.getByTestID('permissions--item')
|
||||
.contains('read')
|
||||
.should('be.visible')
|
||||
})
|
||||
})
|
||||
|
||||
it('can view a token', () => {
|
||||
cy.getByTestID('table-row')
|
||||
.contains('token test \u0950')
|
||||
.click()
|
||||
|
||||
//title match
|
||||
cy.getByTestID('overlay--container').should('be.visible')
|
||||
cy.getByTestID('overlay--header').should('contain', 'token test \u0950')
|
||||
|
||||
//summary match
|
||||
cy.getByTestID('permissions-section').should('have.length', 4)
|
||||
cy.getByTestID('permissions-section')
|
||||
.contains('views')
|
||||
.should('be.visible')
|
||||
cy.getByTestID('permissions-section')
|
||||
.contains('documents')
|
||||
.should('be.visible')
|
||||
cy.getByTestID('permissions-section')
|
||||
.contains('dashboards')
|
||||
.should('be.visible')
|
||||
cy.getByTestID('permissions-section')
|
||||
.contains('buckets')
|
||||
.should('be.visible')
|
||||
|
||||
//copy to clipboard + notification
|
||||
cy.getByTestID('button-copy').click()
|
||||
cy.getByTestID('notification-success').should($msg => {
|
||||
expect($msg).to.contain('has been copied to clipboard')
|
||||
})
|
||||
//todo check system clipboard
|
||||
|
||||
//close button
|
||||
cy.getByTestID('overlay--header').within(() => {
|
||||
cy.get('button').click()
|
||||
})
|
||||
cy.getByTestID('overlay--container').should('not.be.visible')
|
||||
})
|
||||
})
|
|
@ -17,8 +17,10 @@ import {
|
|||
createScraper,
|
||||
fluxEqual,
|
||||
createTelegraf,
|
||||
createToken,
|
||||
createDashboardTemplate,
|
||||
writeData,
|
||||
getByTestIDSubStr,
|
||||
} from './support/commands'
|
||||
|
||||
declare global {
|
||||
|
@ -36,12 +38,14 @@ declare global {
|
|||
getByTestID: typeof getByTestID
|
||||
getByInputName: typeof getByInputName
|
||||
getByTitle: typeof getByTitle
|
||||
getByTestIDSubStr: typeof getByTestIDSubStr
|
||||
createAndAddLabel: typeof createAndAddLabel
|
||||
createLabel: typeof createLabel
|
||||
createBucket: typeof createBucket
|
||||
createScraper: typeof createScraper
|
||||
fluxEqual: typeof fluxEqual
|
||||
createTelegraf: typeof createTelegraf
|
||||
createToken: typeof createToken
|
||||
writeData: typeof writeData
|
||||
}
|
||||
}
|
||||
|
|
|
@ -237,6 +237,27 @@ export const createTelegraf = (
|
|||
})
|
||||
}
|
||||
|
||||
/*
|
||||
[{action: 'write', resource: {type: 'views'}},
|
||||
{action: 'write', resource: {type: 'documents'}},
|
||||
{action: 'write', resource: {type: 'dashboards'}},
|
||||
{action: 'write', resource: {type: 'buckets'}}]}
|
||||
*/
|
||||
|
||||
export const createToken = (
|
||||
orgId: string,
|
||||
description: string,
|
||||
status: string,
|
||||
permissions: object[]
|
||||
): Cypress.Chainable<Cypress.Response> => {
|
||||
return cy.request('POST', 'api/v2/authorizations', {
|
||||
orgID: orgId,
|
||||
description: description,
|
||||
status: status,
|
||||
permissions: permissions,
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: have to go through setup because we cannot create a user w/ a password via the user API
|
||||
export const setupUser = (): Cypress.Chainable<Cypress.Response> => {
|
||||
return cy.fixture('user').then(({username, password, org, bucket}) => {
|
||||
|
@ -274,12 +295,16 @@ export const getByTestID = (dataTest: string): Cypress.Chainable => {
|
|||
return cy.get(`[data-testid="${dataTest}"]`)
|
||||
}
|
||||
|
||||
export const getByTestIDSubStr = (dataTest: string): Cypress.Chainable => {
|
||||
return cy.get(`[data-testid*="${dataTest}"]`)
|
||||
}
|
||||
|
||||
export const getByInputName = (name: string): Cypress.Chainable => {
|
||||
return cy.get(`input[name=${name}]`)
|
||||
}
|
||||
|
||||
export const getByTitle = (name: string): Cypress.Chainable => {
|
||||
return cy.get(`[title=${name}]`)
|
||||
return cy.get(`[title="${name}"]`)
|
||||
}
|
||||
|
||||
// custom assertions
|
||||
|
@ -306,6 +331,7 @@ Cypress.Commands.add('fluxEqual', fluxEqual)
|
|||
Cypress.Commands.add('getByTestID', getByTestID)
|
||||
Cypress.Commands.add('getByInputName', getByInputName)
|
||||
Cypress.Commands.add('getByTitle', getByTitle)
|
||||
Cypress.Commands.add('getByTestIDSubStr', getByTestIDSubStr)
|
||||
|
||||
// auth flow
|
||||
Cypress.Commands.add('signin', signin)
|
||||
|
@ -335,6 +361,9 @@ Cypress.Commands.add('flush', flush)
|
|||
// tasks
|
||||
Cypress.Commands.add('createTask', createTask)
|
||||
|
||||
//Tokems
|
||||
Cypress.Commands.add('createToken', createToken)
|
||||
|
||||
// variables
|
||||
Cypress.Commands.add('createVariable', createVariable)
|
||||
|
||||
|
|
|
@ -96,6 +96,7 @@ class BucketsTokenOverlay extends PureComponent<Props, State> {
|
|||
placeholder="Describe this new token"
|
||||
value={description}
|
||||
onChange={this.handleInputChange}
|
||||
testID="input-field--descr"
|
||||
/>
|
||||
</Form.Element>
|
||||
<Form.Element label="">
|
||||
|
@ -143,6 +144,7 @@ class BucketsTokenOverlay extends PureComponent<Props, State> {
|
|||
text="Cancel"
|
||||
icon={IconFont.Remove}
|
||||
onClick={this.handleDismiss}
|
||||
testID="button--cancel"
|
||||
/>
|
||||
|
||||
<Button
|
||||
|
@ -150,6 +152,7 @@ class BucketsTokenOverlay extends PureComponent<Props, State> {
|
|||
icon={IconFont.Checkmark}
|
||||
color={ComponentColor.Success}
|
||||
type={ButtonType.Submit}
|
||||
testID="button--save"
|
||||
/>
|
||||
</ComponentSpacer>
|
||||
</ComponentSpacer>
|
||||
|
|
|
@ -26,6 +26,8 @@ export default class GenerateTokenDropdown extends PureComponent<Props> {
|
|||
buttonSize={ComponentSize.Small}
|
||||
widthPixels={160}
|
||||
onChange={this.handleSelect}
|
||||
testID="dropdown--gen-token"
|
||||
buttonTestID="dropdown-button--gen-token"
|
||||
>
|
||||
{this.optionItems}
|
||||
</Dropdown>
|
||||
|
|
|
@ -60,6 +60,7 @@ class TokensTab extends PureComponent<Props, State> {
|
|||
placeholder="Filter Tokens..."
|
||||
onChange={this.handleChangeSearchTerm}
|
||||
widthPixels={256}
|
||||
testID="input-field--filter"
|
||||
/>
|
||||
<GenerateTokenDropdown
|
||||
onSelectAllAccess={this.handleGenerateAllAccess}
|
||||
|
|
|
@ -45,6 +45,7 @@ class CopyButton extends PureComponent<Props> {
|
|||
titleText="Copy to Clipboard"
|
||||
text="Copy to Clipboard"
|
||||
onClick={this.handleClickCopy}
|
||||
testID="button-copy"
|
||||
/>
|
||||
</CopyToClipboard>
|
||||
)
|
||||
|
|
|
@ -51,7 +51,7 @@ class EditableName extends Component<Props, State> {
|
|||
const {name, onEditName, hrefValue, noNameString, testID} = this.props
|
||||
|
||||
return (
|
||||
<div className={this.className}>
|
||||
<div className={this.className} data-testid={testID}>
|
||||
<SpinnerContainer
|
||||
loading={this.state.loading}
|
||||
spinnerComponent={<TechnoSpinner diameterPixels={20} />}
|
||||
|
@ -63,7 +63,7 @@ class EditableName extends Component<Props, State> {
|
|||
<div
|
||||
className="editable-name--toggle"
|
||||
onClick={this.handleStartEditing}
|
||||
data-testid={testID}
|
||||
data-testid={testID + '--toggle'}
|
||||
>
|
||||
<span className="icon pencil" />
|
||||
</div>
|
||||
|
|
|
@ -12,6 +12,7 @@ import {IconFont} from 'src/clockface'
|
|||
interface Props {
|
||||
mode?: PermissionsWidgetMode
|
||||
id: string
|
||||
testID?: string
|
||||
label: string
|
||||
selected: PermissionsWidgetSelection
|
||||
onToggle?: (
|
||||
|
@ -22,10 +23,14 @@ interface Props {
|
|||
|
||||
class PermissionsWidgetItem extends Component<Props> {
|
||||
public render() {
|
||||
const {label} = this.props
|
||||
const {label, testID} = this.props
|
||||
|
||||
return (
|
||||
<li className={this.className} onClick={this.handleClick}>
|
||||
<li
|
||||
className={this.className}
|
||||
onClick={this.handleClick}
|
||||
data-testid={testID || 'permissions--item'}
|
||||
>
|
||||
{this.checkbox}
|
||||
<label className="permissions-widget--item-label">{label}</label>
|
||||
</li>
|
||||
|
|
|
@ -21,14 +21,18 @@ interface Props {
|
|||
title: string
|
||||
onSelectAll?: (sectionID: string) => void
|
||||
onDeselectAll?: (sectionID: string) => void
|
||||
testID?: string
|
||||
}
|
||||
|
||||
class PermissionsWidgetSection extends Component<Props> {
|
||||
public render() {
|
||||
const {title} = this.props
|
||||
const {title, testID} = this.props
|
||||
|
||||
return (
|
||||
<section className="permissions-widget--section">
|
||||
<section
|
||||
className="permissions-widget--section"
|
||||
data-testid={testID || 'permissions-section'}
|
||||
>
|
||||
<header className="permissions-widget--section-heading">
|
||||
<h3 className="permissions-widget--section-title">{title}</h3>
|
||||
{this.selectionButtons}
|
||||
|
|
Loading…
Reference in New Issue