mirror of https://github.com/grafana/grafana
e2e: creates a separate package for selectors (#23858)
* Initial commit * Chore: fixes after merge * Chore: removes todos * Chore: uncomment test * Chore: adds missing externals to rollup config * Refactor: selectors is master for everything * Docs: updates Docs * Chore: adds e2e-selectors to publishpull/23931/head
parent
9ac7263e66
commit
b09b49fb37
@ -0,0 +1,2 @@ |
|||||||
|
|
||||||
|
|
@ -0,0 +1,3 @@ |
|||||||
|
# Grafana End-to-End Test Selectors library |
||||||
|
|
||||||
|
> **@grafana/e2e-selectors is currently in ALPHA**. Core API is unstable and can be a subject of breaking changes! |
@ -0,0 +1,3 @@ |
|||||||
|
{ |
||||||
|
"extends": "../../api-extractor.json" |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
'use strict'; |
||||||
|
|
||||||
|
if (process.env.NODE_ENV === 'production') { |
||||||
|
module.exports = require('./index.production.js'); |
||||||
|
} else { |
||||||
|
module.exports = require('./index.development.js'); |
||||||
|
} |
@ -0,0 +1,50 @@ |
|||||||
|
{ |
||||||
|
"author": "Grafana Labs", |
||||||
|
"license": "Apache-2.0", |
||||||
|
"name": "@grafana/e2e-selectors", |
||||||
|
"version": "7.0.0-pre.0", |
||||||
|
"description": "Grafana End-to-End Test Selectors Library", |
||||||
|
"keywords": [ |
||||||
|
"cli", |
||||||
|
"grafana", |
||||||
|
"e2e", |
||||||
|
"typescript" |
||||||
|
], |
||||||
|
"repository": { |
||||||
|
"type": "git", |
||||||
|
"url": "http://github.com/grafana/grafana.git", |
||||||
|
"directory": "packages/grafana-e2e-selectors" |
||||||
|
}, |
||||||
|
"main": "src/index.ts", |
||||||
|
"scripts": { |
||||||
|
"build": "grafana-toolkit package:build --scope=e2e-selectors", |
||||||
|
"bundle": "rollup -c rollup.config.ts", |
||||||
|
"clean": "rimraf ./dist ./compiled", |
||||||
|
"docsExtract": "mkdir -p ../../reports/docs && api-extractor run 2>&1 | tee ../../reports/docs/$(basename $(pwd)).log", |
||||||
|
"lint": "eslint src/ --ext=.js,.ts,.tsx", |
||||||
|
"typecheck": "tsc --noEmit" |
||||||
|
}, |
||||||
|
"devDependencies": { |
||||||
|
"@types/node": "13.7.7", |
||||||
|
"@rollup/plugin-commonjs": "11.0.2", |
||||||
|
"@rollup/plugin-node-resolve": "7.1.1", |
||||||
|
"@types/rollup-plugin-visualizer": "2.6.0", |
||||||
|
"@types/systemjs": "^0.20.6", |
||||||
|
"pretty-format": "25.1.0", |
||||||
|
"rollup": "2.0.6", |
||||||
|
"rollup-plugin-sourcemaps": "0.5.0", |
||||||
|
"rollup-plugin-terser": "5.3.0", |
||||||
|
"rollup-plugin-typescript2": "0.26.0", |
||||||
|
"rollup-plugin-visualizer": "3.3.1", |
||||||
|
"ts-loader": "6.2.1", |
||||||
|
"ts-node": "8.8.1" |
||||||
|
}, |
||||||
|
"types": "src/index.ts", |
||||||
|
"dependencies": { |
||||||
|
"@grafana/tsconfig": "^1.0.0-rc1", |
||||||
|
"commander": "5.0.0", |
||||||
|
"execa": "4.0.0", |
||||||
|
"typescript": "3.7.5", |
||||||
|
"yaml": "^1.8.3" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
import resolve from '@rollup/plugin-node-resolve'; |
||||||
|
import sourceMaps from 'rollup-plugin-sourcemaps'; |
||||||
|
import { terser } from 'rollup-plugin-terser'; |
||||||
|
|
||||||
|
const pkg = require('./package.json'); |
||||||
|
|
||||||
|
const libraryName = pkg.name; |
||||||
|
|
||||||
|
const buildCjsPackage = ({ env }) => { |
||||||
|
return { |
||||||
|
input: `compiled/index.js`, |
||||||
|
output: [ |
||||||
|
{ |
||||||
|
file: `dist/index.${env}.js`, |
||||||
|
name: libraryName, |
||||||
|
format: 'cjs', |
||||||
|
sourcemap: true, |
||||||
|
exports: 'named', |
||||||
|
globals: {}, |
||||||
|
}, |
||||||
|
], |
||||||
|
plugins: [resolve(), sourceMaps(), env === 'production' && terser()], |
||||||
|
}; |
||||||
|
}; |
||||||
|
export default [buildCjsPackage({ env: 'development' }), buildCjsPackage({ env: 'production' })]; |
@ -0,0 +1,7 @@ |
|||||||
|
/** |
||||||
|
* A library containing the different design components of the Grafana ecosystem. |
||||||
|
* |
||||||
|
* @packageDocumentation |
||||||
|
*/ |
||||||
|
export * from './selectors'; |
||||||
|
export * from './types'; |
@ -0,0 +1,108 @@ |
|||||||
|
import { Pages } from './pages'; |
||||||
|
|
||||||
|
export const Components = { |
||||||
|
DataSource: { |
||||||
|
TestData: { |
||||||
|
QueryTab: { |
||||||
|
scenarioSelect: 'Test Data Query scenario select', |
||||||
|
max: 'TestData max', |
||||||
|
min: 'TestData min', |
||||||
|
noise: 'TestData noise', |
||||||
|
seriesCount: 'TestData series count', |
||||||
|
spread: 'TestData spread', |
||||||
|
startValue: 'TestData start value', |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
Panels: { |
||||||
|
Panel: { |
||||||
|
title: (title: string) => `Panel header title item ${title}`, |
||||||
|
headerItems: (item: string) => `Panel header item ${item}`, |
||||||
|
}, |
||||||
|
Visualization: { |
||||||
|
Graph: { |
||||||
|
VisualizationTab: { |
||||||
|
legendSection: 'Legend section', |
||||||
|
}, |
||||||
|
Legend: { |
||||||
|
legendItemAlias: (name: string) => `gpl alias ${name}`, |
||||||
|
showLegendSwitch: 'gpl show legend', |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
Drawer: { |
||||||
|
General: { |
||||||
|
title: (title: string) => `Drawer title ${title}`, |
||||||
|
expand: 'Drawer expand', |
||||||
|
contract: 'Drawer contract', |
||||||
|
close: 'Drawer close', |
||||||
|
rcContentWrapper: () => '.drawer-content-wrapper', |
||||||
|
}, |
||||||
|
}, |
||||||
|
PanelEditor: { |
||||||
|
General: { |
||||||
|
content: 'Panel editor content', |
||||||
|
}, |
||||||
|
OptionsPane: { |
||||||
|
content: 'Panel editor option pane content', |
||||||
|
close: Pages.Dashboard.Toolbar.toolbarItems('Close options pane'), |
||||||
|
open: Pages.Dashboard.Toolbar.toolbarItems('Open options pane'), |
||||||
|
select: 'Panel editor option pane select', |
||||||
|
}, |
||||||
|
// not sure about the naming *DataPane*
|
||||||
|
DataPane: { |
||||||
|
content: 'Panel editor data pane content', |
||||||
|
}, |
||||||
|
}, |
||||||
|
PanelInspector: { |
||||||
|
Data: { |
||||||
|
content: 'Panel inspector Data content', |
||||||
|
}, |
||||||
|
Stats: { |
||||||
|
content: 'Panel inspector Stats content', |
||||||
|
}, |
||||||
|
Json: { |
||||||
|
content: 'Panel inspector Json content', |
||||||
|
}, |
||||||
|
Query: { |
||||||
|
content: 'Panel inspector Query content', |
||||||
|
}, |
||||||
|
}, |
||||||
|
Tab: { |
||||||
|
title: (title: string) => `Tab ${title}`, |
||||||
|
active: () => '[class*="-activeTabStyle"]', |
||||||
|
}, |
||||||
|
QueryTab: { |
||||||
|
content: 'Query editor tab content', |
||||||
|
queryInspectorButton: 'Query inspector button', |
||||||
|
}, |
||||||
|
AlertTab: { |
||||||
|
content: 'Alert editor tab content', |
||||||
|
}, |
||||||
|
TransformTab: { |
||||||
|
content: 'Transform editor tab content', |
||||||
|
}, |
||||||
|
QueryEditorToolbarItem: { |
||||||
|
button: (title: string) => `QueryEditor toolbar item button ${title}`, |
||||||
|
}, |
||||||
|
BackButton: { |
||||||
|
backArrow: 'Go Back button', |
||||||
|
}, |
||||||
|
OptionsGroup: { |
||||||
|
toggle: (title: string) => `Options group ${title}`, |
||||||
|
}, |
||||||
|
PluginVisualization: { |
||||||
|
item: (title: string) => `Plugin visualization item ${title}`, |
||||||
|
current: () => '[class*="-currentVisualizationItem"]', |
||||||
|
}, |
||||||
|
Select: { |
||||||
|
option: 'Select option', |
||||||
|
}, |
||||||
|
FieldConfigEditor: { |
||||||
|
content: 'Field config editor content', |
||||||
|
}, |
||||||
|
OverridesConfigEditor: { |
||||||
|
content: 'Field overrides editor content', |
||||||
|
}, |
||||||
|
}; |
@ -0,0 +1,8 @@ |
|||||||
|
import { Pages } from './pages'; |
||||||
|
import { Components } from './components'; |
||||||
|
import { E2ESelectors } from '../types'; |
||||||
|
|
||||||
|
export const selectors: { pages: E2ESelectors<typeof Pages>; components: E2ESelectors<typeof Components> } = { |
||||||
|
pages: Pages, |
||||||
|
components: Components, |
||||||
|
}; |
@ -0,0 +1,121 @@ |
|||||||
|
export const Pages = { |
||||||
|
Login: { |
||||||
|
url: '/login', |
||||||
|
username: 'Username input field', |
||||||
|
password: 'Password input field', |
||||||
|
submit: 'Login button', |
||||||
|
skip: 'Skip change password button', |
||||||
|
}, |
||||||
|
DataSource: { |
||||||
|
name: 'Data source settings page name input field', |
||||||
|
delete: 'Data source settings page Delete button', |
||||||
|
saveAndTest: 'Data source settings page Save and Test button', |
||||||
|
alert: 'Data source settings page Alert', |
||||||
|
alertMessage: 'Data source settings page Alert message', |
||||||
|
}, |
||||||
|
DataSources: { |
||||||
|
url: '/datasources', |
||||||
|
dataSources: (dataSourceName: string) => `Data source list item ${dataSourceName}`, |
||||||
|
}, |
||||||
|
AddDataSource: { |
||||||
|
url: '/datasources/new', |
||||||
|
dataSourcePlugins: (pluginName: string) => `Data source plugin item ${pluginName}`, |
||||||
|
}, |
||||||
|
ConfirmModal: { |
||||||
|
delete: 'Confirm Modal Danger Button', |
||||||
|
}, |
||||||
|
AddDashboard: { |
||||||
|
url: '/dashboard/new', |
||||||
|
addNewPanel: 'Add new panel', |
||||||
|
}, |
||||||
|
Dashboard: { |
||||||
|
url: (uid: string) => `/d/${uid}`, |
||||||
|
Toolbar: { |
||||||
|
toolbarItems: (button: string) => `Dashboard navigation bar button ${button}`, |
||||||
|
navBar: () => '.navbar', |
||||||
|
}, |
||||||
|
SubMenu: { |
||||||
|
submenuItem: 'Dashboard template variables submenu item', |
||||||
|
submenuItemLabels: (item: string) => `Dashboard template variables submenu Label ${item}`, |
||||||
|
submenuItemValueDropDownValueLinkTexts: (item: string) => |
||||||
|
`Dashboard template variables Variable Value DropDown value link text ${item}`, |
||||||
|
submenuItemValueDropDownDropDown: 'Dashboard template variables Variable Value DropDown DropDown', |
||||||
|
submenuItemValueDropDownOptionTexts: (item: string) => |
||||||
|
`Dashboard template variables Variable Value DropDown option text ${item}`, |
||||||
|
}, |
||||||
|
Settings: { |
||||||
|
General: { |
||||||
|
deleteDashBoard: 'Dashboard settings page delete dashboard button', |
||||||
|
sectionItems: (item: string) => `Dashboard settings section item ${item}`, |
||||||
|
saveDashBoard: 'Dashboard settings aside actions Save button', |
||||||
|
saveAsDashBoard: 'Dashboard settings aside actions Save As button', |
||||||
|
}, |
||||||
|
Variables: { |
||||||
|
List: { |
||||||
|
addVariableCTA: 'Call to action button Add variable', |
||||||
|
newButton: 'Variable editor New variable button', |
||||||
|
table: 'Variable editor Table', |
||||||
|
tableRowNameFields: (variableName: string) => `Variable editor Table Name field ${variableName}`, |
||||||
|
tableRowDefinitionFields: (variableName: string) => `Variable editor Table Definition field ${variableName}`, |
||||||
|
tableRowArrowUpButtons: (variableName: string) => `Variable editor Table ArrowUp button ${variableName}`, |
||||||
|
tableRowArrowDownButtons: (variableName: string) => `Variable editor Table ArrowDown button ${variableName}`, |
||||||
|
tableRowDuplicateButtons: (variableName: string) => `Variable editor Table Duplicate button ${variableName}`, |
||||||
|
tableRowRemoveButtons: (variableName: string) => `Variable editor Table Remove button ${variableName}`, |
||||||
|
}, |
||||||
|
Edit: { |
||||||
|
General: { |
||||||
|
headerLink: 'Variable editor Header link', |
||||||
|
modeLabelNew: 'Variable editor Header mode New', |
||||||
|
modeLabelEdit: 'Variable editor Header mode Edit', |
||||||
|
generalNameInput: 'Variable editor Form Name field', |
||||||
|
generalTypeSelect: 'Variable editor Form Type select', |
||||||
|
generalLabelInput: 'Variable editor Form Label field', |
||||||
|
generalHideSelect: 'Variable editor Form Hide select', |
||||||
|
selectionOptionsMultiSwitch: 'Variable editor Form Multi switch', |
||||||
|
selectionOptionsIncludeAllSwitch: 'Variable editor Form IncludeAll switch', |
||||||
|
selectionOptionsCustomAllInput: 'Variable editor Form IncludeAll field', |
||||||
|
previewOfValuesOption: 'Variable editor Preview of Values option', |
||||||
|
addButton: 'Variable editor Add button', |
||||||
|
updateButton: 'Variable editor Update button', |
||||||
|
}, |
||||||
|
QueryVariable: { |
||||||
|
queryOptionsDataSourceSelect: 'Variable editor Form Query DataSource select', |
||||||
|
queryOptionsRefreshSelect: 'Variable editor Form Query Refresh select', |
||||||
|
queryOptionsRegExInput: 'Variable editor Form Query RegEx field', |
||||||
|
queryOptionsSortSelect: 'Variable editor Form Query Sort select', |
||||||
|
queryOptionsQueryInput: 'Variable editor Form Default Variable Query Editor textarea', |
||||||
|
valueGroupsTagsEnabledSwitch: 'Variable editor Form Query UseTags switch', |
||||||
|
valueGroupsTagsTagsQueryInput: 'Variable editor Form Query TagsQuery field', |
||||||
|
valueGroupsTagsTagsValuesQueryInput: 'Variable editor Form Query TagsValuesQuery field', |
||||||
|
}, |
||||||
|
ConstantVariable: { |
||||||
|
constantOptionsQueryInput: 'Variable editor Form Constant Query field', |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
Dashboards: { |
||||||
|
url: '/dashboards', |
||||||
|
dashboards: (title: string) => `Dashboard search item ${title}`, |
||||||
|
}, |
||||||
|
SaveDashboardAsModal: { |
||||||
|
newName: 'Save dashboard title field', |
||||||
|
save: 'Save dashboard button', |
||||||
|
}, |
||||||
|
SaveDashboardModal: { |
||||||
|
save: 'Dashboard settings Save Dashboard Modal Save button', |
||||||
|
saveVariables: 'Dashboard settings Save Dashboard Modal Save variables checkbox', |
||||||
|
saveTimerange: 'Dashboard settings Save Dashboard Modal Save timerange checkbox', |
||||||
|
}, |
||||||
|
SharePanelModal: { |
||||||
|
linkToRenderedImage: 'Link to rendered image', |
||||||
|
}, |
||||||
|
Explore: { |
||||||
|
url: '/explore', |
||||||
|
General: { |
||||||
|
container: 'Explore', |
||||||
|
runButton: 'Run button', |
||||||
|
}, |
||||||
|
}, |
||||||
|
}; |
@ -0,0 +1 @@ |
|||||||
|
export * from './selectors'; |
@ -0,0 +1,15 @@ |
|||||||
|
export type StringSelector = string; |
||||||
|
export type FunctionSelector = (id: string) => string; |
||||||
|
export type CssSelector = () => string; |
||||||
|
|
||||||
|
export interface Selectors { |
||||||
|
[key: string]: StringSelector | FunctionSelector | CssSelector | UrlSelector | Selectors; |
||||||
|
} |
||||||
|
|
||||||
|
export type E2ESelectors<S extends Selectors> = { |
||||||
|
[P in keyof S]: S[P]; |
||||||
|
}; |
||||||
|
|
||||||
|
export interface UrlSelector extends Selectors { |
||||||
|
url: string | FunctionSelector; |
||||||
|
} |
@ -0,0 +1,4 @@ |
|||||||
|
{ |
||||||
|
"exclude": ["dist", "node_modules", "**/*.test.ts*"], |
||||||
|
"extends": "./tsconfig.json" |
||||||
|
} |
@ -0,0 +1,11 @@ |
|||||||
|
{ |
||||||
|
"compilerOptions": { |
||||||
|
"declarationDir": "dist", |
||||||
|
"outDir": "compiled", |
||||||
|
"rootDirs": ["."], |
||||||
|
"typeRoots": ["node_modules/@types"] |
||||||
|
}, |
||||||
|
"exclude": ["dist", "node_modules"], |
||||||
|
"extends": "@grafana/tsconfig", |
||||||
|
"include": ["src/**/*.ts"] |
||||||
|
} |
@ -1,129 +0,0 @@ |
|||||||
import { TestData } from '../pages/testdata'; |
|
||||||
import { Panel } from '../pages/panel'; |
|
||||||
import { Graph } from '../pages/graph'; |
|
||||||
import { componentFactory } from '../support'; |
|
||||||
import { Dashboard } from '../pages/dashboard'; |
|
||||||
|
|
||||||
export const Components = { |
|
||||||
DataSource: { |
|
||||||
TestData, |
|
||||||
}, |
|
||||||
Panels: { |
|
||||||
Panel, |
|
||||||
Visualization: { |
|
||||||
Graph, |
|
||||||
}, |
|
||||||
}, |
|
||||||
Drawer: { |
|
||||||
General: componentFactory({ |
|
||||||
selectors: { |
|
||||||
title: (title: string) => `Drawer title ${title}`, |
|
||||||
expand: 'Drawer expand', |
|
||||||
contract: 'Drawer contract', |
|
||||||
close: 'Drawer close', |
|
||||||
rcContentWrapper: () => '.drawer-content-wrapper', |
|
||||||
}, |
|
||||||
}), |
|
||||||
}, |
|
||||||
PanelEditor: { |
|
||||||
General: componentFactory({ |
|
||||||
selectors: { |
|
||||||
content: 'Panel editor content', |
|
||||||
}, |
|
||||||
}), |
|
||||||
OptionsPane: componentFactory({ |
|
||||||
selectors: { |
|
||||||
content: 'Panel editor option pane content', |
|
||||||
close: Dashboard.selectors.toolbarItems('Close options pane'), |
|
||||||
open: Dashboard.selectors.toolbarItems('Open options pane'), |
|
||||||
select: 'Panel editor option pane select', |
|
||||||
}, |
|
||||||
}), |
|
||||||
// not sure about the naming *DataPane*
|
|
||||||
DataPane: componentFactory({ |
|
||||||
selectors: { |
|
||||||
content: 'Panel editor data pane content', |
|
||||||
}, |
|
||||||
}), |
|
||||||
}, |
|
||||||
PanelInspector: { |
|
||||||
Data: componentFactory({ |
|
||||||
selectors: { |
|
||||||
content: 'Panel inspector Data content', |
|
||||||
}, |
|
||||||
}), |
|
||||||
Stats: componentFactory({ |
|
||||||
selectors: { |
|
||||||
content: 'Panel inspector Stats content', |
|
||||||
}, |
|
||||||
}), |
|
||||||
Json: componentFactory({ |
|
||||||
selectors: { |
|
||||||
content: 'Panel inspector Json content', |
|
||||||
}, |
|
||||||
}), |
|
||||||
Query: componentFactory({ |
|
||||||
selectors: { |
|
||||||
content: 'Panel inspector Query content', |
|
||||||
}, |
|
||||||
}), |
|
||||||
}, |
|
||||||
Tab: componentFactory({ |
|
||||||
selectors: { |
|
||||||
title: (title: string) => `Tab ${title}`, |
|
||||||
active: () => '[class*="-activeTabStyle"]', |
|
||||||
}, |
|
||||||
}), |
|
||||||
QueryTab: componentFactory({ |
|
||||||
selectors: { |
|
||||||
content: 'Query editor tab content', |
|
||||||
queryInspectorButton: 'Query inspector button', |
|
||||||
}, |
|
||||||
}), |
|
||||||
AlertTab: componentFactory({ |
|
||||||
selectors: { |
|
||||||
content: 'Alert editor tab content', |
|
||||||
}, |
|
||||||
}), |
|
||||||
TransformTab: componentFactory({ |
|
||||||
selectors: { |
|
||||||
content: 'Transform editor tab content', |
|
||||||
}, |
|
||||||
}), |
|
||||||
QueryEditorToolbarItem: componentFactory({ |
|
||||||
selectors: { |
|
||||||
button: (title: string) => `QueryEditor toolbar item button ${title}`, |
|
||||||
}, |
|
||||||
}), |
|
||||||
BackButton: componentFactory({ |
|
||||||
selectors: { |
|
||||||
backArrow: 'Go Back button', |
|
||||||
}, |
|
||||||
}), |
|
||||||
OptionsGroup: componentFactory({ |
|
||||||
selectors: { |
|
||||||
toggle: (title: string) => `Options group ${title}`, |
|
||||||
}, |
|
||||||
}), |
|
||||||
PluginVisualization: componentFactory({ |
|
||||||
selectors: { |
|
||||||
item: (title: string) => `Plugin visualization item ${title}`, |
|
||||||
current: () => '[class*="-currentVisualizationItem"]', |
|
||||||
}, |
|
||||||
}), |
|
||||||
Select: componentFactory({ |
|
||||||
selectors: { |
|
||||||
option: 'Select option', |
|
||||||
}, |
|
||||||
}), |
|
||||||
FieldConfigEditor: componentFactory({ |
|
||||||
selectors: { |
|
||||||
content: 'Field config editor content', |
|
||||||
}, |
|
||||||
}), |
|
||||||
OverridesConfigEditor: componentFactory({ |
|
||||||
selectors: { |
|
||||||
content: 'Field overrides editor content', |
|
||||||
}, |
|
||||||
}), |
|
||||||
}; |
|
@ -1,28 +0,0 @@ |
|||||||
// @ts-nocheck
|
|
||||||
// importing the e2e package in Grafana will cause transpile errors because
|
|
||||||
// Cypress is an unknown type. Adding the Cypress types would overwrite all jest test types like
|
|
||||||
// toBe, toEqual and so forth. That's why this file is not type checked and will be so until we
|
|
||||||
// can solve the above mentioned issue with Cypress/Jest.
|
|
||||||
import { e2eScenario, ScenarioArguments } from './support/scenario'; |
|
||||||
import { Pages } from './pages'; |
|
||||||
import { Components } from './components'; |
|
||||||
import { Flows } from './flows'; |
|
||||||
import { getScenarioContext, setScenarioContext } from './support/scenarioContext'; |
|
||||||
|
|
||||||
export type SelectorFunction = (text?: string) => Cypress.Chainable<JQuery<HTMLElement>>; |
|
||||||
export type VisitFunction = (args?: string) => Cypress.Chainable<Window>; |
|
||||||
|
|
||||||
const e2eObject = { |
|
||||||
env: (args: string) => Cypress.env(args), |
|
||||||
config: () => Cypress.config(), |
|
||||||
blobToBase64String: (blob: any) => Cypress.Blob.blobToBase64String(blob), |
|
||||||
imgSrcToBlob: (url: string) => Cypress.Blob.imgSrcToBlob(url), |
|
||||||
scenario: (args: ScenarioArguments) => e2eScenario(args), |
|
||||||
pages: Pages, |
|
||||||
components: Components, |
|
||||||
flows: Flows, |
|
||||||
getScenarioContext, |
|
||||||
setScenarioContext, |
|
||||||
}; |
|
||||||
|
|
||||||
export const e2e: (() => Cypress.cy) & typeof e2eObject = Object.assign(() => cy, e2eObject); |
|
@ -1,8 +0,0 @@ |
|||||||
import { pageFactory } from '../support'; |
|
||||||
|
|
||||||
export const AddDashboard = pageFactory({ |
|
||||||
url: '/dashboard/new', |
|
||||||
selectors: { |
|
||||||
addNewPanel: 'Add new panel', |
|
||||||
}, |
|
||||||
}); |
|
@ -1,8 +0,0 @@ |
|||||||
import { pageFactory } from '../support'; |
|
||||||
|
|
||||||
export const AddDataSource = pageFactory({ |
|
||||||
url: '/datasources/new', |
|
||||||
selectors: { |
|
||||||
dataSourcePlugins: (pluginName: string) => `Data source plugin item ${pluginName}`, |
|
||||||
}, |
|
||||||
}); |
|
@ -1,8 +0,0 @@ |
|||||||
import { pageFactory } from '../support'; |
|
||||||
|
|
||||||
export const ConfirmModal = pageFactory({ |
|
||||||
url: '', |
|
||||||
selectors: { |
|
||||||
delete: 'Confirm Modal Danger Button', |
|
||||||
}, |
|
||||||
}); |
|
@ -1,9 +0,0 @@ |
|||||||
import { pageFactory } from '../support'; |
|
||||||
|
|
||||||
export const Dashboard = pageFactory({ |
|
||||||
url: (uid: string) => `/d/${uid}`, |
|
||||||
selectors: { |
|
||||||
toolbarItems: (button: string) => `Dashboard navigation bar button ${button}`, |
|
||||||
navBar: () => '.navbar', |
|
||||||
}, |
|
||||||
}); |
|
@ -1,11 +0,0 @@ |
|||||||
import { pageFactory } from '../support'; |
|
||||||
|
|
||||||
export const DashboardSettings = pageFactory({ |
|
||||||
url: '', |
|
||||||
selectors: { |
|
||||||
deleteDashBoard: 'Dashboard settings page delete dashboard button', |
|
||||||
sectionItems: (item: string) => `Dashboard settings section item ${item}`, |
|
||||||
saveDashBoard: 'Dashboard settings aside actions Save button', |
|
||||||
saveAsDashBoard: 'Dashboard settings aside actions Save As button', |
|
||||||
}, |
|
||||||
}); |
|
@ -1,8 +0,0 @@ |
|||||||
import { pageFactory } from '../support'; |
|
||||||
|
|
||||||
export const Dashboards = pageFactory({ |
|
||||||
url: '/dashboards', |
|
||||||
selectors: { |
|
||||||
dashboards: (title: string) => `Dashboard search item ${title}`, |
|
||||||
}, |
|
||||||
}); |
|
@ -1,12 +0,0 @@ |
|||||||
import { pageFactory } from '../support'; |
|
||||||
|
|
||||||
export const DataSource = pageFactory({ |
|
||||||
url: '', |
|
||||||
selectors: { |
|
||||||
name: 'Data source settings page name input field', |
|
||||||
delete: 'Data source settings page Delete button', |
|
||||||
saveAndTest: 'Data source settings page Save and Test button', |
|
||||||
alert: 'Data source settings page Alert', |
|
||||||
alertMessage: 'Data source settings page Alert message', |
|
||||||
}, |
|
||||||
}); |
|
@ -1,8 +0,0 @@ |
|||||||
import { pageFactory } from '../support'; |
|
||||||
|
|
||||||
export const DataSources = pageFactory({ |
|
||||||
url: '/datasources', |
|
||||||
selectors: { |
|
||||||
dataSources: (dataSourceName: string) => `Data source list item ${dataSourceName}`, |
|
||||||
}, |
|
||||||
}); |
|
@ -1,9 +0,0 @@ |
|||||||
import { pageFactory } from '../support'; |
|
||||||
|
|
||||||
export const Explore = pageFactory({ |
|
||||||
url: '/explore', |
|
||||||
selectors: { |
|
||||||
container: 'Explore', |
|
||||||
runButton: 'Run button', |
|
||||||
}, |
|
||||||
}); |
|
@ -1,13 +0,0 @@ |
|||||||
import { VisualizationTab } from './visualizationTab'; |
|
||||||
import { pageFactory } from '../../support'; |
|
||||||
|
|
||||||
export const Graph = { |
|
||||||
VisualizationTab, |
|
||||||
Legend: pageFactory({ |
|
||||||
url: '', |
|
||||||
selectors: { |
|
||||||
legendItemAlias: (name: string) => `gpl alias ${name}`, |
|
||||||
showLegendSwitch: 'gpl show legend', |
|
||||||
}, |
|
||||||
}), |
|
||||||
}; |
|
@ -1,11 +0,0 @@ |
|||||||
import { pageFactory } from '../../support'; |
|
||||||
|
|
||||||
export const VisualizationTab = pageFactory({ |
|
||||||
url: '', |
|
||||||
selectors: { |
|
||||||
xAxisSection: 'X-Axis section', |
|
||||||
axesSection: 'Axes section', |
|
||||||
legendSection: 'Legend section', |
|
||||||
displaySection: 'Display section', |
|
||||||
}, |
|
||||||
}); |
|
@ -1,47 +0,0 @@ |
|||||||
import { Login } from './login'; |
|
||||||
import { AddDataSource } from './addDataSource'; |
|
||||||
import { DataSource } from './datasource'; |
|
||||||
import { DataSources } from './datasources'; |
|
||||||
import { ConfirmModal } from './confirmModal'; |
|
||||||
import { AddDashboard } from './addDashboard'; |
|
||||||
import { Dashboard } from './dashboard'; |
|
||||||
import { SaveDashboardAsModal } from './saveDashboardAsModal'; |
|
||||||
import { Dashboards } from './dashboards'; |
|
||||||
import { DashboardSettings } from './dashboardSettings'; |
|
||||||
import { Explore } from './explore'; |
|
||||||
import { SaveDashboardModal } from './saveDashboardModal'; |
|
||||||
import { SharePanelModal } from './sharePanelModal'; |
|
||||||
import { ConstantVariable, QueryVariable, VariableGeneral, Variables, VariablesSubMenu } from './variables'; |
|
||||||
|
|
||||||
export const Pages = { |
|
||||||
Login, |
|
||||||
DataSource, |
|
||||||
DataSources, |
|
||||||
AddDataSource, |
|
||||||
ConfirmModal, |
|
||||||
AddDashboard, |
|
||||||
Dashboard: { |
|
||||||
visit: (uid: string) => Dashboard.visit(uid), |
|
||||||
Toolbar: Dashboard, |
|
||||||
SubMenu: VariablesSubMenu, |
|
||||||
Settings: { |
|
||||||
General: DashboardSettings, |
|
||||||
Variables: { |
|
||||||
List: Variables, |
|
||||||
Edit: { |
|
||||||
General: VariableGeneral, |
|
||||||
QueryVariable: QueryVariable, |
|
||||||
ConstantVariable: ConstantVariable, |
|
||||||
}, |
|
||||||
}, |
|
||||||
}, |
|
||||||
}, |
|
||||||
Dashboards, |
|
||||||
SaveDashboardAsModal, |
|
||||||
SaveDashboardModal, |
|
||||||
SharePanelModal, |
|
||||||
Explore: { |
|
||||||
visit: () => Explore.visit(), |
|
||||||
General: Explore, |
|
||||||
}, |
|
||||||
}; |
|
@ -1,11 +0,0 @@ |
|||||||
import { pageFactory } from '../support'; |
|
||||||
|
|
||||||
export const Login = pageFactory({ |
|
||||||
url: '/login', |
|
||||||
selectors: { |
|
||||||
username: 'Username input field', |
|
||||||
password: 'Password input field', |
|
||||||
submit: 'Login button', |
|
||||||
skip: 'Skip change password button', |
|
||||||
}, |
|
||||||
}); |
|
@ -1,9 +0,0 @@ |
|||||||
import { pageFactory } from '../support'; |
|
||||||
|
|
||||||
export const Panel = pageFactory({ |
|
||||||
url: '', |
|
||||||
selectors: { |
|
||||||
title: (title: string) => `Panel header title item ${title}`, |
|
||||||
headerItems: (item: string) => `Panel header item ${item}`, |
|
||||||
}, |
|
||||||
}); |
|
@ -1,9 +0,0 @@ |
|||||||
import { pageFactory } from '../support'; |
|
||||||
|
|
||||||
export const SaveDashboardAsModal = pageFactory({ |
|
||||||
url: '', |
|
||||||
selectors: { |
|
||||||
newName: 'Save dashboard title field', |
|
||||||
save: 'Save dashboard button', |
|
||||||
}, |
|
||||||
}); |
|
@ -1,10 +0,0 @@ |
|||||||
import { pageFactory } from '../support'; |
|
||||||
|
|
||||||
export const SaveDashboardModal = pageFactory({ |
|
||||||
url: '', |
|
||||||
selectors: { |
|
||||||
save: 'Dashboard settings Save Dashboard Modal Save button', |
|
||||||
saveVariables: 'Dashboard settings Save Dashboard Modal Save variables checkbox', |
|
||||||
saveTimerange: 'Dashboard settings Save Dashboard Modal Save timerange checkbox', |
|
||||||
}, |
|
||||||
}); |
|
@ -1,8 +0,0 @@ |
|||||||
import { pageFactory } from '../support'; |
|
||||||
|
|
||||||
export const SharePanelModal = pageFactory({ |
|
||||||
url: '', |
|
||||||
selectors: { |
|
||||||
linkToRenderedImage: 'Link to rendered image', |
|
||||||
}, |
|
||||||
}); |
|
@ -1,5 +0,0 @@ |
|||||||
import { QueryTab } from './queryTab'; |
|
||||||
|
|
||||||
export const TestData = { |
|
||||||
QueryTab, |
|
||||||
}; |
|
@ -1,13 +0,0 @@ |
|||||||
import { componentFactory } from '../../support'; |
|
||||||
|
|
||||||
export const QueryTab = componentFactory({ |
|
||||||
selectors: { |
|
||||||
scenarioSelect: 'Test Data Query scenario select', |
|
||||||
max: 'TestData max', |
|
||||||
min: 'TestData min', |
|
||||||
noise: 'TestData noise', |
|
||||||
seriesCount: 'TestData series count', |
|
||||||
spread: 'TestData spread', |
|
||||||
startValue: 'TestData start value', |
|
||||||
}, |
|
||||||
}); |
|
@ -1,69 +0,0 @@ |
|||||||
import { pageFactory } from '../support'; |
|
||||||
|
|
||||||
export const Variables = pageFactory({ |
|
||||||
url: '', |
|
||||||
selectors: { |
|
||||||
addVariableCTA: 'Call to action button Add variable', |
|
||||||
newButton: 'Variable editor New variable button', |
|
||||||
table: 'Variable editor Table', |
|
||||||
tableRowNameFields: (variableName: string) => `Variable editor Table Name field ${variableName}`, |
|
||||||
tableRowDefinitionFields: (variableName: string) => `Variable editor Table Definition field ${variableName}`, |
|
||||||
tableRowArrowUpButtons: (variableName: string) => `Variable editor Table ArrowUp button ${variableName}`, |
|
||||||
tableRowArrowDownButtons: (variableName: string) => `Variable editor Table ArrowDown button ${variableName}`, |
|
||||||
tableRowDuplicateButtons: (variableName: string) => `Variable editor Table Duplicate button ${variableName}`, |
|
||||||
tableRowRemoveButtons: (variableName: string) => `Variable editor Table Remove button ${variableName}`, |
|
||||||
}, |
|
||||||
}); |
|
||||||
|
|
||||||
export const VariablesSubMenu = pageFactory({ |
|
||||||
url: '', |
|
||||||
selectors: { |
|
||||||
submenuItem: 'Dashboard template variables submenu item', |
|
||||||
submenuItemLabels: (item: string) => `Dashboard template variables submenu Label ${item}`, |
|
||||||
submenuItemValueDropDownValueLinkTexts: (item: string) => |
|
||||||
`Dashboard template variables Variable Value DropDown value link text ${item}`, |
|
||||||
submenuItemValueDropDownDropDown: 'Dashboard template variables Variable Value DropDown DropDown', |
|
||||||
submenuItemValueDropDownOptionTexts: (item: string) => |
|
||||||
`Dashboard template variables Variable Value DropDown option text ${item}`, |
|
||||||
}, |
|
||||||
}); |
|
||||||
|
|
||||||
export const VariableGeneral = pageFactory({ |
|
||||||
url: '', |
|
||||||
selectors: { |
|
||||||
headerLink: 'Variable editor Header link', |
|
||||||
modeLabelNew: 'Variable editor Header mode New', |
|
||||||
modeLabelEdit: 'Variable editor Header mode Edit', |
|
||||||
generalNameInput: 'Variable editor Form Name field', |
|
||||||
generalTypeSelect: 'Variable editor Form Type select', |
|
||||||
generalLabelInput: 'Variable editor Form Label field', |
|
||||||
generalHideSelect: 'Variable editor Form Hide select', |
|
||||||
selectionOptionsMultiSwitch: 'Variable editor Form Multi switch', |
|
||||||
selectionOptionsIncludeAllSwitch: 'Variable editor Form IncludeAll switch', |
|
||||||
selectionOptionsCustomAllInput: 'Variable editor Form IncludeAll field', |
|
||||||
previewOfValuesOption: 'Variable editor Preview of Values option', |
|
||||||
addButton: 'Variable editor Add button', |
|
||||||
updateButton: 'Variable editor Update button', |
|
||||||
}, |
|
||||||
}); |
|
||||||
|
|
||||||
export const QueryVariable = pageFactory({ |
|
||||||
url: '', |
|
||||||
selectors: { |
|
||||||
queryOptionsDataSourceSelect: 'Variable editor Form Query DataSource select', |
|
||||||
queryOptionsRefreshSelect: 'Variable editor Form Query Refresh select', |
|
||||||
queryOptionsRegExInput: 'Variable editor Form Query RegEx field', |
|
||||||
queryOptionsSortSelect: 'Variable editor Form Query Sort select', |
|
||||||
queryOptionsQueryInput: 'Variable editor Form Default Variable Query Editor textarea', |
|
||||||
valueGroupsTagsEnabledSwitch: 'Variable editor Form Query UseTags switch', |
|
||||||
valueGroupsTagsTagsQueryInput: 'Variable editor Form Query TagsQuery field', |
|
||||||
valueGroupsTagsTagsValuesQueryInput: 'Variable editor Form Query TagsValuesQuery field', |
|
||||||
}, |
|
||||||
}); |
|
||||||
|
|
||||||
export const ConstantVariable = pageFactory({ |
|
||||||
url: '', |
|
||||||
selectors: { |
|
||||||
constantOptionsQueryInput: 'Variable editor Form Constant Query field', |
|
||||||
}, |
|
||||||
}); |
|
@ -1,76 +1,99 @@ |
|||||||
|
import { CssSelector, FunctionSelector, Selectors, StringSelector, UrlSelector } from '@grafana/e2e-selectors'; |
||||||
|
import { e2e } from '../index'; |
||||||
import { Selector } from './selector'; |
import { Selector } from './selector'; |
||||||
import { fromBaseUrl } from './url'; |
import { fromBaseUrl } from './url'; |
||||||
import { e2e } from '../index'; |
|
||||||
import { SelectorFunction, VisitFunction } from '../noTypeCheck'; |
|
||||||
|
|
||||||
export type Selectors = Record<string, string | Function>; |
export type VisitFunction = (args?: string) => Cypress.Chainable<Window>; |
||||||
export type SelectorFunctions<S> = { [P in keyof S]: SelectorFunction }; |
export type E2EVisit = { visit: VisitFunction }; |
||||||
|
export type E2EFunction = (text?: string) => Cypress.Chainable<JQuery<HTMLElement>>; |
||||||
|
|
||||||
export type Page<S> = SelectorFunctions<S> & { |
export type TypeSelectors<S> = S extends StringSelector |
||||||
selectors: S; |
? E2EFunction |
||||||
visit: VisitFunction; |
: S extends FunctionSelector |
||||||
|
? E2EFunction |
||||||
|
: S extends CssSelector |
||||||
|
? E2EFunction |
||||||
|
: S extends UrlSelector |
||||||
|
? E2EVisit & Omit<E2EFunctions<S>, 'url'> |
||||||
|
: S extends Record<any, any> |
||||||
|
? E2EFunctions<S> |
||||||
|
: S; |
||||||
|
|
||||||
|
export type E2EFunctions<S extends Selectors> = { |
||||||
|
[P in keyof S]: TypeSelectors<S[P]>; |
||||||
}; |
}; |
||||||
export interface PageFactoryArgs<S> { |
|
||||||
selectors: S; |
|
||||||
url?: string | Function; |
|
||||||
} |
|
||||||
|
|
||||||
export const pageFactory = <S extends Selectors>({ url, selectors }: PageFactoryArgs<S>): Page<S> => { |
|
||||||
const visit = (args?: string) => { |
|
||||||
if (!url) { |
|
||||||
return e2e().visit(''); |
|
||||||
} |
|
||||||
|
|
||||||
let parsedUrl = ''; |
export type E2EObjects<S extends Selectors> = E2EFunctions<S>; |
||||||
if (typeof url === 'string') { |
|
||||||
parsedUrl = fromBaseUrl(url); |
|
||||||
} |
|
||||||
|
|
||||||
if (typeof url === 'function' && args) { |
export type E2EFactoryArgs<S extends Selectors> = { selectors: S }; |
||||||
parsedUrl = fromBaseUrl(url(args)); |
|
||||||
} |
|
||||||
|
|
||||||
e2e().logToConsole('Visiting', parsedUrl); |
const processSelectors = <S extends Selectors>(e2eObjects: E2EFunctions<S>, selectors: S): E2EFunctions<S> => { |
||||||
return e2e().visit(parsedUrl); |
const logOutput = (data: any) => e2e().logToConsole('Retrieving Selector:', data); |
||||||
}; |
|
||||||
const pageObjects: SelectorFunctions<S> = {} as SelectorFunctions<S>; |
|
||||||
const keys = Object.keys(selectors); |
const keys = Object.keys(selectors); |
||||||
|
for (let index = 0; index < keys.length; index++) { |
||||||
keys.forEach(key => { |
const key = keys[index]; |
||||||
const value = selectors[key]; |
const value = selectors[key]; |
||||||
|
|
||||||
|
if (key === 'url') { |
||||||
|
// @ts-ignore
|
||||||
|
e2eObjects['visit'] = (args?: string) => { |
||||||
|
let parsedUrl = ''; |
||||||
|
if (typeof value === 'string') { |
||||||
|
parsedUrl = fromBaseUrl(value); |
||||||
|
} |
||||||
|
|
||||||
|
if (typeof value === 'function' && args) { |
||||||
|
parsedUrl = fromBaseUrl(value(args)); |
||||||
|
} |
||||||
|
|
||||||
|
e2e().logToConsole('Visiting', parsedUrl); |
||||||
|
return e2e().visit(parsedUrl); |
||||||
|
}; |
||||||
|
|
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
if (typeof value === 'string') { |
if (typeof value === 'string') { |
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
pageObjects[key] = () => { |
e2eObjects[key] = () => { |
||||||
e2e().logToConsole('Retrieving Selector:', value); |
logOutput(value); |
||||||
return e2e().get(Selector.fromAriaLabel(value)); |
return e2e().get(Selector.fromAriaLabel(value)); |
||||||
}; |
}; |
||||||
|
|
||||||
|
continue; |
||||||
} |
} |
||||||
|
|
||||||
if (typeof value === 'function') { |
if (typeof value === 'function') { |
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
pageObjects[key] = (text?: string) => { |
e2eObjects[key] = (text?: string) => { |
||||||
if (!text) { |
if (!text) { |
||||||
const selector = value(); |
const selector = value((undefined as unknown) as string); |
||||||
e2e().logToConsole('Retrieving Selector:', selector); |
|
||||||
|
logOutput(selector); |
||||||
return e2e().get(selector); |
return e2e().get(selector); |
||||||
} |
} |
||||||
|
|
||||||
const selector = value(text); |
const selector = value(text); |
||||||
e2e().logToConsole('Retrieving Selector:', selector); |
|
||||||
|
logOutput(selector); |
||||||
return e2e().get(Selector.fromAriaLabel(selector)); |
return e2e().get(Selector.fromAriaLabel(selector)); |
||||||
}; |
}; |
||||||
|
|
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
if (typeof value === 'object') { |
||||||
|
// @ts-ignore
|
||||||
|
e2eObjects[key] = processSelectors({}, value); |
||||||
} |
} |
||||||
}); |
} |
||||||
|
|
||||||
return { |
return e2eObjects; |
||||||
visit, |
|
||||||
...pageObjects, |
|
||||||
selectors, |
|
||||||
}; |
|
||||||
}; |
}; |
||||||
|
|
||||||
type Component<S> = Omit<Page<S>, 'visit'>; |
export const e2eFactory = <S extends Selectors>({ selectors }: E2EFactoryArgs<S>): E2EObjects<S> => { |
||||||
type ComponentFactoryArgs<S> = Omit<PageFactoryArgs<S>, 'url'>; |
const e2eObjects: E2EFunctions<S> = {} as E2EFunctions<S>; |
||||||
|
processSelectors(e2eObjects, selectors); |
||||||
|
|
||||||
export const componentFactory = <S extends Selectors>(args: ComponentFactoryArgs<S>): Component<S> => { |
return { ...e2eObjects }; |
||||||
const { visit, ...rest } = pageFactory(args); |
|
||||||
return rest; |
|
||||||
}; |
}; |
||||||
|
@ -1,6 +1,6 @@ |
|||||||
{ |
{ |
||||||
"extends": ["@grafana/eslint-config"], |
"extends": ["@grafana/eslint-config"], |
||||||
"rules": { |
"rules": { |
||||||
"no-restricted-imports": [2, "^@grafana/runtime.*", "^@grafana/ui.*"] |
"no-restricted-imports": [2, "^@grafana/runtime.*", "^@grafana/ui.*", "^@grafana/e2e.*"] |
||||||
} |
} |
||||||
} |
} |
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue