mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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 publish
This commit is contained in:
parent
9ac7263e66
commit
b09b49fb37
@ -26,7 +26,8 @@ All the integration tests are located at `e2e/suite<x>/specs`. The page objects
|
||||
Here is a good introduction to e2e best practices: https://martinfowler.com/bliki/PageObject.html.
|
||||
|
||||
- `Selector`: A unique identifier that is used from the e2e framework to retrieve an element from the Browser
|
||||
- `Page`: An abstraction for an object that contains one or more `Selectors`
|
||||
- `Page`: An abstraction for an object that contains one or more `Selectors` with `visit` function to navigate to the page.
|
||||
- `Component`: An abstraction for an object that contains one or more `Selectors` but without `visit` function
|
||||
- `Flow`: An abstraction that contains a sequence of actions on one or more `Pages` that can be reused and shared between tests
|
||||
|
||||
## Basic example
|
||||
@ -57,15 +58,13 @@ Now that we added the `aria-label` we suddenly get more information about this p
|
||||
The next step is to create a `Page` representation in our e2e test framework to glue the test with the real implementation using the `pageFactory` function. For that function we can supply a `url` and `selectors` like in the example below:
|
||||
|
||||
```typescript
|
||||
export const Login = pageFactory({
|
||||
export const Login = {
|
||||
url: "/login", // used when called from Login.visit()
|
||||
selectors: {
|
||||
username: "Username input field", // used when called from Login.username().type('Hello World')
|
||||
},
|
||||
});
|
||||
username: "Username input field", // used when called from Login.username().type('Hello World')
|
||||
};
|
||||
```
|
||||
|
||||
The next step is to add the `Login` page to the exported const `Pages` in `packages/grafana-e2e/src/pages/index.ts` so that it appears when we type `e2e.pages` in our IDE.
|
||||
The next step is to add the `Login` page to the exported const `Pages` in `packages/grafana-e2e-selectors/src/selectors/pages.ts` so that it appears when we type `e2e.pages` in our IDE.
|
||||
|
||||
```ecmascript 6
|
||||
export const Pages = {
|
||||
@ -81,15 +80,15 @@ Now that we have a `Page` called `Login` in our `Pages` const we can use that to
|
||||
|
||||
```jsx harmony
|
||||
<div>
|
||||
<input type="text" className="gf-form-input login-form-input" aria-label={e2e.pages.Login.selectors.username} />
|
||||
<input type="text" className="gf-form-input login-form-input" aria-label={selectors.pages.Login.username} />
|
||||
</div>
|
||||
```
|
||||
|
||||
The last step in our example is to use our `Login` page as part of a test. The `pageFactory` function we used before gives us two things:
|
||||
The last step in our example is to use our `Login` page as part of a test.
|
||||
|
||||
- The `url` property is used whenever we call the `visit` function and is equivalent to the Cypress function [cy.visit()](https://docs.cypress.io/api/commands/visit.html#Syntax).
|
||||
> Best practice after calling `visit` is to always call `should` on a selector to prevent flaky tests when you try to access an element that isn't ready. For more information, refer to [Commands vs. assertions](https://docs.cypress.io/guides/core-concepts/retry-ability.html#Commands-vs-assertions).
|
||||
- Any defined selector in the `selectors` property can be accessed from the `Login` page by invoking it. This is equivalent to the result of the Cypress function [cy.get(...)](https://docs.cypress.io/api/commands/get.html#Syntax).
|
||||
- Any defined selector can be accessed from the `Login` page by invoking it. This is equivalent to the result of the Cypress function [cy.get(...)](https://docs.cypress.io/api/commands/get.html#Syntax).
|
||||
|
||||
```ecmascript 6
|
||||
describe('Login test', () => {
|
||||
@ -123,17 +122,15 @@ Let's take a look at an example that uses the same `selector` for multiple items
|
||||
|
||||
Just as before in the basic example we'll start by creating a page abstraction using the `pageFactory` function:
|
||||
```typescript
|
||||
export const DataSources = pageFactory({
|
||||
export const DataSources = {
|
||||
url: '/datasources',
|
||||
selectors: {
|
||||
dataSources: (dataSourceName: string) => `Data source list item ${dataSourceName}`,
|
||||
},
|
||||
});
|
||||
dataSources: (dataSourceName: string) => `Data source list item ${dataSourceName}`,
|
||||
};
|
||||
````
|
||||
|
||||
You might have noticed that instead of a simple `string` as the `selector`, we're using a `function` that takes a string parameter as an argument and returns a formatted string using the argument.
|
||||
|
||||
Just as before we need to add the `DataSources` page to the exported const `Pages` in `packages/grafana-e2e/src/pages/index.ts`.
|
||||
Just as before we need to add the `DataSources` page to the exported const `Pages` in `packages/grafana-e2e-selectors/src/selectors/pages.ts`.
|
||||
|
||||
The next step is to use the `dataSources` selector function as in our example below:
|
||||
|
||||
@ -142,7 +139,7 @@ The next step is to use the `dataSources` selector function as in our example be
|
||||
{dataSources.map(dataSource => (
|
||||
<li className="card-item-wrapper" key={dataSource.id}>
|
||||
<a className="card-item" href={`datasources/edit/${dataSource.id}`}>
|
||||
<div className="card-item-name" aria-label={e2e.pages.DataSources.selectors.dataSources(dataSource.name)}>
|
||||
<div className="card-item-name" aria-label={selectors.pages.DataSources.dataSources(dataSource.name)}>
|
||||
{dataSource.name}
|
||||
</div>
|
||||
</a>
|
||||
|
@ -7,9 +7,7 @@ e2e.scenario({
|
||||
addScenarioDashBoard: true,
|
||||
skipScenario: false,
|
||||
scenario: () => {
|
||||
// @todo remove `@ts-ignore` when possible
|
||||
// @ts-ignore
|
||||
e2e.getScenarioContext().then(({ lastAddedDashboardUid }) => {
|
||||
e2e.getScenarioContext().then(({ lastAddedDashboardUid }: any) => {
|
||||
e2e.flows.openDashboard(lastAddedDashboardUid);
|
||||
});
|
||||
e2e.pages.Dashboard.Toolbar.toolbarItems('Add panel').click();
|
||||
|
@ -8,9 +8,7 @@ e2e.scenario({
|
||||
addScenarioDashBoard: true,
|
||||
skipScenario: false,
|
||||
scenario: () => {
|
||||
// @todo remove `@ts-ignore` when possible
|
||||
// @ts-ignore
|
||||
e2e.getScenarioContext().then(({ lastAddedDashboardUid }) => {
|
||||
e2e.getScenarioContext().then(({ lastAddedDashboardUid }: any) => {
|
||||
e2e.flows.openDashboard(lastAddedDashboardUid);
|
||||
});
|
||||
e2e.pages.Dashboard.Toolbar.toolbarItems('Dashboard settings').click();
|
||||
@ -253,9 +251,7 @@ const assertAdding3dependantQueryVariablesScenario = (queryVariables: QueryVaria
|
||||
for (let queryVariableIndex = 0; queryVariableIndex < queryVariables.length; queryVariableIndex++) {
|
||||
const { name, label, query, options, selectedOption } = queryVariables[queryVariableIndex];
|
||||
const asserts = queryVariables.slice(0, queryVariableIndex + 1);
|
||||
// @todo remove `@ts-ignore` when possible
|
||||
// @ts-ignore
|
||||
e2e.getScenarioContext().then(({ lastAddedDataSource }) => {
|
||||
e2e.getScenarioContext().then(({ lastAddedDataSource }: any) => {
|
||||
createQueryVariable({
|
||||
dataSourceName: lastAddedDataSource,
|
||||
name,
|
||||
|
2
packages/grafana-e2e-selectors/CHANGELOG.md
Normal file
2
packages/grafana-e2e-selectors/CHANGELOG.md
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
|
3
packages/grafana-e2e-selectors/README.md
Normal file
3
packages/grafana-e2e-selectors/README.md
Normal file
@ -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!
|
3
packages/grafana-e2e-selectors/api-extractor.json
Normal file
3
packages/grafana-e2e-selectors/api-extractor.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "../../api-extractor.json"
|
||||
}
|
7
packages/grafana-e2e-selectors/index.js
Normal file
7
packages/grafana-e2e-selectors/index.js
Normal file
@ -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');
|
||||
}
|
50
packages/grafana-e2e-selectors/package.json
Normal file
50
packages/grafana-e2e-selectors/package.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
25
packages/grafana-e2e-selectors/rollup.config.ts
Normal file
25
packages/grafana-e2e-selectors/rollup.config.ts
Normal file
@ -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' })];
|
7
packages/grafana-e2e-selectors/src/index.ts
Normal file
7
packages/grafana-e2e-selectors/src/index.ts
Normal file
@ -0,0 +1,7 @@
|
||||
/**
|
||||
* A library containing the different design components of the Grafana ecosystem.
|
||||
*
|
||||
* @packageDocumentation
|
||||
*/
|
||||
export * from './selectors';
|
||||
export * from './types';
|
108
packages/grafana-e2e-selectors/src/selectors/components.ts
Normal file
108
packages/grafana-e2e-selectors/src/selectors/components.ts
Normal file
@ -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',
|
||||
},
|
||||
};
|
8
packages/grafana-e2e-selectors/src/selectors/index.ts
Normal file
8
packages/grafana-e2e-selectors/src/selectors/index.ts
Normal file
@ -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,
|
||||
};
|
121
packages/grafana-e2e-selectors/src/selectors/pages.ts
Normal file
121
packages/grafana-e2e-selectors/src/selectors/pages.ts
Normal file
@ -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',
|
||||
},
|
||||
},
|
||||
};
|
1
packages/grafana-e2e-selectors/src/types/index.ts
Normal file
1
packages/grafana-e2e-selectors/src/types/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './selectors';
|
15
packages/grafana-e2e-selectors/src/types/selectors.ts
Normal file
15
packages/grafana-e2e-selectors/src/types/selectors.ts
Normal file
@ -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;
|
||||
}
|
4
packages/grafana-e2e-selectors/tsconfig.build.json
Normal file
4
packages/grafana-e2e-selectors/tsconfig.build.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"exclude": ["dist", "node_modules", "**/*.test.ts*"],
|
||||
"extends": "./tsconfig.json"
|
||||
}
|
11
packages/grafana-e2e-selectors/tsconfig.json
Normal file
11
packages/grafana-e2e-selectors/tsconfig.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"declarationDir": "dist",
|
||||
"outDir": "compiled",
|
||||
"rootDirs": ["."],
|
||||
"typeRoots": ["node_modules/@types"]
|
||||
},
|
||||
"exclude": ["dist", "node_modules"],
|
||||
"extends": "@grafana/tsconfig",
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
@ -31,7 +31,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cypress/webpack-preprocessor": "4.1.3",
|
||||
"@grafana/tsconfig": "^1.0.0-rc1",
|
||||
"@rollup/plugin-commonjs": "11.0.2",
|
||||
"@rollup/plugin-node-resolve": "7.1.1",
|
||||
"@types/node": "13.7.7",
|
||||
@ -43,19 +42,18 @@
|
||||
"rollup-plugin-typescript2": "0.26.0",
|
||||
"rollup-plugin-visualizer": "3.3.1",
|
||||
"ts-loader": "6.2.1",
|
||||
"typescript": "3.7.5",
|
||||
"ts-node": "8.8.1"
|
||||
},
|
||||
"types": "src/index.ts",
|
||||
"dependencies": {
|
||||
"@cypress/webpack-preprocessor": "4.1.1",
|
||||
"@grafana/tsconfig": "^1.0.0-rc1",
|
||||
"@grafana/e2e-selectors": "7.0.0-pre.0",
|
||||
"blink-diff": "1.0.13",
|
||||
"commander": "5.0.0",
|
||||
"cypress": "3.7.0",
|
||||
"execa": "4.0.0",
|
||||
"ts-loader": "6.2.1",
|
||||
"typescript": "3.7.2",
|
||||
"typescript": "3.7.5",
|
||||
"yaml": "^1.8.3"
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ const buildCjsPackage = ({ env }) => ({
|
||||
exports: 'named',
|
||||
globals: {},
|
||||
},
|
||||
external: ['@grafana/e2e-selectors'],
|
||||
plugins: [
|
||||
copy({
|
||||
flatten: false,
|
||||
|
@ -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',
|
||||
},
|
||||
}),
|
||||
};
|
@ -14,9 +14,7 @@ const DEFAULT_ADD_PANEL_CONFIG: AddPanelConfig = {
|
||||
export const addPanel = (config?: Partial<AddPanelConfig>) => {
|
||||
const { dataSourceName, queriesForm } = { ...DEFAULT_ADD_PANEL_CONFIG, ...config };
|
||||
|
||||
// @todo remove `@ts-ignore` when possible
|
||||
// @ts-ignore
|
||||
getScenarioContext().then(({ lastAddedDashboardUid }) => {
|
||||
getScenarioContext().then(({ lastAddedDashboardUid }: any) => {
|
||||
e2e.flows.openDashboard(lastAddedDashboardUid);
|
||||
e2e.pages.Dashboard.Toolbar.toolbarItems('Add panel').click();
|
||||
e2e.pages.AddDashboard.addNewPanel().click();
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { e2e } from '../noTypeCheck';
|
||||
import { e2e } from '../index';
|
||||
|
||||
export enum PanelMenuItems {
|
||||
Edit = 'Edit',
|
||||
|
@ -3,4 +3,24 @@
|
||||
*
|
||||
* @packageDocumentation
|
||||
*/
|
||||
export { e2e } from './noTypeCheck';
|
||||
import { e2eScenario, ScenarioArguments } from './support/scenario';
|
||||
import { Flows } from './flows';
|
||||
import { getScenarioContext, setScenarioContext } from './support/scenarioContext';
|
||||
import { e2eFactory } from './support';
|
||||
import { Pages } from '@grafana/e2e-selectors/src/selectors/pages';
|
||||
import { Components } from '@grafana/e2e-selectors/src/selectors/components';
|
||||
|
||||
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: e2eFactory({ selectors: Pages }),
|
||||
components: e2eFactory({ selectors: Components }),
|
||||
flows: Flows,
|
||||
getScenarioContext,
|
||||
setScenarioContext,
|
||||
};
|
||||
|
||||
export const e2e: (() => Cypress.cy) & typeof e2eObject = Object.assign(() => cy, e2eObject);
|
||||
|
@ -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',
|
||||
},
|
||||
});
|
@ -18,20 +18,10 @@ export const e2eScenario = ({
|
||||
addScenarioDataSource = false,
|
||||
addScenarioDashBoard = false,
|
||||
}: ScenarioArguments) => {
|
||||
// when we started to use import { e2e } from '@grafana/e2e'; in grafana/ui components
|
||||
// then type checking @grafana/run-time started to fail with
|
||||
// Cannot find name 'describe'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha`.
|
||||
// Haven't investigated deeper why this happens yet so adding ts-ignore as temporary solution
|
||||
// @todo remove `@ts-ignore` when possible
|
||||
// @ts-ignore
|
||||
describe(describeName, () => {
|
||||
if (skipScenario) {
|
||||
// @todo remove `@ts-ignore` when possible
|
||||
// @ts-ignore
|
||||
it.skip(itName, () => scenario());
|
||||
} else {
|
||||
// @todo remove `@ts-ignore` when possible
|
||||
// @ts-ignore
|
||||
beforeEach(() => {
|
||||
Flows.login('admin', 'admin');
|
||||
if (addScenarioDataSource) {
|
||||
@ -42,12 +32,8 @@ export const e2eScenario = ({
|
||||
}
|
||||
});
|
||||
|
||||
// @todo remove `@ts-ignore` when possible
|
||||
// @ts-ignore
|
||||
afterEach(() => {
|
||||
// @todo remove `@ts-ignore` when possible
|
||||
// @ts-ignore
|
||||
getScenarioContext().then(({ lastAddedDashboardUid, lastAddedDataSource }) => {
|
||||
getScenarioContext().then(({ lastAddedDashboardUid, lastAddedDataSource }: any) => {
|
||||
if (lastAddedDataSource) {
|
||||
Flows.deleteDataSource(lastAddedDataSource);
|
||||
}
|
||||
@ -58,8 +44,6 @@ export const e2eScenario = ({
|
||||
});
|
||||
});
|
||||
|
||||
// @todo remove `@ts-ignore` when possible
|
||||
// @ts-ignore
|
||||
it(itName, () => scenario());
|
||||
}
|
||||
});
|
||||
|
@ -1,76 +1,99 @@
|
||||
import { CssSelector, FunctionSelector, Selectors, StringSelector, UrlSelector } from '@grafana/e2e-selectors';
|
||||
import { e2e } from '../index';
|
||||
import { Selector } from './selector';
|
||||
import { fromBaseUrl } from './url';
|
||||
import { e2e } from '../index';
|
||||
import { SelectorFunction, VisitFunction } from '../noTypeCheck';
|
||||
|
||||
export type Selectors = Record<string, string | Function>;
|
||||
export type SelectorFunctions<S> = { [P in keyof S]: SelectorFunction };
|
||||
export type VisitFunction = (args?: string) => Cypress.Chainable<Window>;
|
||||
export type E2EVisit = { visit: VisitFunction };
|
||||
export type E2EFunction = (text?: string) => Cypress.Chainable<JQuery<HTMLElement>>;
|
||||
|
||||
export type Page<S> = SelectorFunctions<S> & {
|
||||
selectors: S;
|
||||
visit: VisitFunction;
|
||||
export type TypeSelectors<S> = S extends StringSelector
|
||||
? E2EFunction
|
||||
: 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('');
|
||||
}
|
||||
export type E2EObjects<S extends Selectors> = E2EFunctions<S>;
|
||||
|
||||
let parsedUrl = '';
|
||||
if (typeof url === 'string') {
|
||||
parsedUrl = fromBaseUrl(url);
|
||||
}
|
||||
export type E2EFactoryArgs<S extends Selectors> = { selectors: S };
|
||||
|
||||
if (typeof url === 'function' && args) {
|
||||
parsedUrl = fromBaseUrl(url(args));
|
||||
}
|
||||
|
||||
e2e().logToConsole('Visiting', parsedUrl);
|
||||
return e2e().visit(parsedUrl);
|
||||
};
|
||||
const pageObjects: SelectorFunctions<S> = {} as SelectorFunctions<S>;
|
||||
const processSelectors = <S extends Selectors>(e2eObjects: E2EFunctions<S>, selectors: S): E2EFunctions<S> => {
|
||||
const logOutput = (data: any) => e2e().logToConsole('Retrieving Selector:', data);
|
||||
const keys = Object.keys(selectors);
|
||||
|
||||
keys.forEach(key => {
|
||||
for (let index = 0; index < keys.length; index++) {
|
||||
const key = keys[index];
|
||||
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') {
|
||||
// @ts-ignore
|
||||
pageObjects[key] = () => {
|
||||
e2e().logToConsole('Retrieving Selector:', value);
|
||||
e2eObjects[key] = () => {
|
||||
logOutput(value);
|
||||
return e2e().get(Selector.fromAriaLabel(value));
|
||||
};
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (typeof value === 'function') {
|
||||
// @ts-ignore
|
||||
pageObjects[key] = (text?: string) => {
|
||||
e2eObjects[key] = (text?: string) => {
|
||||
if (!text) {
|
||||
const selector = value();
|
||||
e2e().logToConsole('Retrieving Selector:', selector);
|
||||
const selector = value((undefined as unknown) as string);
|
||||
|
||||
logOutput(selector);
|
||||
return e2e().get(selector);
|
||||
}
|
||||
|
||||
const selector = value(text);
|
||||
e2e().logToConsole('Retrieving Selector:', selector);
|
||||
|
||||
logOutput(selector);
|
||||
return e2e().get(Selector.fromAriaLabel(selector));
|
||||
};
|
||||
|
||||
continue;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
visit,
|
||||
...pageObjects,
|
||||
selectors,
|
||||
};
|
||||
if (typeof value === 'object') {
|
||||
// @ts-ignore
|
||||
e2eObjects[key] = processSelectors({}, value);
|
||||
}
|
||||
}
|
||||
|
||||
return e2eObjects;
|
||||
};
|
||||
|
||||
type Component<S> = Omit<Page<S>, 'visit'>;
|
||||
type ComponentFactoryArgs<S> = Omit<PageFactoryArgs<S>, 'url'>;
|
||||
export const e2eFactory = <S extends Selectors>({ selectors }: E2EFactoryArgs<S>): E2EObjects<S> => {
|
||||
const e2eObjects: E2EFunctions<S> = {} as E2EFunctions<S>;
|
||||
processSelectors(e2eObjects, selectors);
|
||||
|
||||
export const componentFactory = <S extends Selectors>(args: ComponentFactoryArgs<S>): Component<S> => {
|
||||
const { visit, ...rest } = pageFactory(args);
|
||||
return rest;
|
||||
return { ...e2eObjects };
|
||||
};
|
||||
|
@ -16,7 +16,7 @@ import { closeMilestoneTask } from './tasks/closeMilestone';
|
||||
import { pluginDevTask } from './tasks/plugin.dev';
|
||||
import { githubPublishTask } from './tasks/plugin.utils';
|
||||
import { pluginUpdateTask } from './tasks/plugin.update';
|
||||
import { ciBuildPluginTask, ciBuildPluginDocsTask, ciPackagePluginTask, ciPluginReportTask } from './tasks/plugin.ci';
|
||||
import { ciBuildPluginDocsTask, ciBuildPluginTask, ciPackagePluginTask, ciPluginReportTask } from './tasks/plugin.ci';
|
||||
import { buildPackageTask } from './tasks/package.build';
|
||||
import { pluginCreateTask } from './tasks/plugin.create';
|
||||
import { bundleManagedTask } from './tasks/plugin/bundle.managed';
|
||||
@ -41,7 +41,7 @@ export const run = (includeInternalScripts = false) => {
|
||||
|
||||
program
|
||||
.command('package:build')
|
||||
.option('-s, --scope <packages>', 'packages=[data|runtime|ui|toolkit]')
|
||||
.option('-s, --scope <packages>', 'packages=[data|runtime|ui|toolkit|e2e|e2e-selectors]')
|
||||
.description('Builds @grafana/* package to packages/grafana-*/dist')
|
||||
.action(async cmd => {
|
||||
await execTask(buildPackageTask)({
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"extends": ["@grafana/eslint-config"],
|
||||
"rules": {
|
||||
"no-restricted-imports": [2, "^@grafana/runtime.*", "^@grafana/ui.*"]
|
||||
"no-restricted-imports": [2, "^@grafana/runtime.*", "^@grafana/ui.*", "^@grafana/e2e.*"]
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
"dependencies": {
|
||||
"@emotion/core": "^10.0.27",
|
||||
"@grafana/data": "7.0.0-pre.0",
|
||||
"@grafana/e2e-selectors": "7.0.0-pre.0",
|
||||
"@grafana/slate-react": "0.22.9-grafana",
|
||||
"@grafana/tsconfig": "^1.0.0-rc1",
|
||||
"@iconscout/react-unicons": "^1.0.0",
|
||||
|
@ -24,7 +24,7 @@ const buildCjsPackage = ({ env }) => {
|
||||
},
|
||||
},
|
||||
],
|
||||
external: ['react', 'react-dom', '@grafana/data', 'moment'],
|
||||
external: ['react', 'react-dom', '@grafana/data', 'moment', '@grafana/e2e-selectors'],
|
||||
plugins: [
|
||||
commonjs({
|
||||
include: /node_modules/,
|
||||
|
@ -2,10 +2,11 @@ import React, { CSSProperties, FC, ReactNode, useState } from 'react';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
import RcDrawer from 'rc-drawer';
|
||||
import { css } from 'emotion';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import CustomScrollbar from '../CustomScrollbar/CustomScrollbar';
|
||||
import { IconButton } from '../IconButton/IconButton';
|
||||
import { stylesFactory, useTheme } from '../../themes';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
|
||||
export interface Props {
|
||||
children: ReactNode;
|
||||
@ -96,8 +97,8 @@ export const Drawer: FC<Props> = ({
|
||||
className={drawerStyles.drawer}
|
||||
aria-label={
|
||||
typeof title === 'string'
|
||||
? e2e.components.Drawer.General.selectors.title(title)
|
||||
: e2e.components.Drawer.General.selectors.title('no title')
|
||||
? selectors.components.Drawer.General.title(title)
|
||||
: selectors.components.Drawer.General.title('no title')
|
||||
}
|
||||
>
|
||||
{typeof title === 'string' && (
|
||||
@ -109,7 +110,7 @@ export const Drawer: FC<Props> = ({
|
||||
size="xl"
|
||||
onClick={() => setIsExpanded(true)}
|
||||
surface="header"
|
||||
aria-label={e2e.components.Drawer.General.selectors.expand}
|
||||
aria-label={selectors.components.Drawer.General.expand}
|
||||
/>
|
||||
)}
|
||||
{expandable && isExpanded && (
|
||||
@ -118,7 +119,7 @@ export const Drawer: FC<Props> = ({
|
||||
size="xl"
|
||||
onClick={() => setIsExpanded(false)}
|
||||
surface="header"
|
||||
aria-label={e2e.components.Drawer.General.selectors.contract}
|
||||
aria-label={selectors.components.Drawer.General.contract}
|
||||
/>
|
||||
)}
|
||||
<IconButton
|
||||
@ -126,7 +127,7 @@ export const Drawer: FC<Props> = ({
|
||||
size="xl"
|
||||
onClick={onClose}
|
||||
surface="header"
|
||||
aria-label={e2e.components.Drawer.General.selectors.close}
|
||||
aria-label={selectors.components.Drawer.General.close}
|
||||
/>
|
||||
</div>
|
||||
<div className={drawerStyles.titleWrapper}>
|
||||
|
@ -1,11 +1,12 @@
|
||||
import React, { FC } from 'react';
|
||||
import { css, cx } from 'emotion';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import { Icon } from '../Icon/Icon';
|
||||
import { IconName } from '../../types';
|
||||
import { stylesFactory, useTheme } from '../../themes';
|
||||
import { Counter } from './Counter';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
|
||||
export interface TabProps {
|
||||
label: string;
|
||||
@ -69,7 +70,7 @@ export const Tab: FC<TabProps> = ({ label, active, icon, onChangeTab, counter })
|
||||
<li
|
||||
className={cx(tabsStyles.tabItem, active && tabsStyles.activeStyle)}
|
||||
onClick={onChangeTab}
|
||||
aria-label={e2e.components.Tab.selectors.title(label)}
|
||||
aria-label={selectors.components.Tab.title(label)}
|
||||
>
|
||||
{icon && <Icon name={icon} />}
|
||||
{label}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { ButtonHTMLAttributes } from 'react';
|
||||
import { IconButton } from '@grafana/ui';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
export interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
surface: 'dashboard' | 'panel' | 'header';
|
||||
@ -14,7 +14,7 @@ export const BackButton: React.FC<Props> = ({ surface, onClick }) => {
|
||||
tooltipPlacement="bottom"
|
||||
size="xxl"
|
||||
surface={surface}
|
||||
aria-label={e2e.components.BackButton.selectors.backArrow}
|
||||
aria-label={selectors.components.BackButton.backArrow}
|
||||
onClick={onClick}
|
||||
/>
|
||||
);
|
||||
|
@ -1,9 +1,9 @@
|
||||
import React, { ChangeEvent, PureComponent, SyntheticEvent } from 'react';
|
||||
import { Tooltip } from '@grafana/ui';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
interface Props {
|
||||
onSubmit: (pw: string) => void;
|
||||
@ -117,7 +117,7 @@ export class ChangePassword extends PureComponent<Props, State> {
|
||||
placement="bottom"
|
||||
content="If you skip you will be prompted to change password next time you login."
|
||||
>
|
||||
<a className="btn btn-link" onClick={this.onSkip} aria-label={e2e.pages.Login.selectors.skip}>
|
||||
<a className="btn btn-link" onClick={this.onSkip} aria-label={selectors.pages.Login.skip}>
|
||||
Skip
|
||||
</a>
|
||||
</Tooltip>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { ChangeEvent, PureComponent, SyntheticEvent } from 'react';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import { FormModel } from './LoginCtrl';
|
||||
|
||||
@ -74,7 +74,7 @@ export class LoginForm extends PureComponent<Props, State> {
|
||||
className="gf-form-input login-form-input"
|
||||
required
|
||||
placeholder={this.props.loginHint}
|
||||
aria-label={e2e.pages.Login.selectors.username}
|
||||
aria-label={selectors.pages.Login.username}
|
||||
onChange={this.onChangeUsername}
|
||||
/>
|
||||
</div>
|
||||
@ -87,7 +87,7 @@ export class LoginForm extends PureComponent<Props, State> {
|
||||
ng-model="formModel.password"
|
||||
id="inputPassword"
|
||||
placeholder={this.props.passwordHint}
|
||||
aria-label={e2e.pages.Login.selectors.password}
|
||||
aria-label={selectors.pages.Login.password}
|
||||
onChange={this.onChangePassword}
|
||||
/>
|
||||
</div>
|
||||
@ -95,7 +95,7 @@ export class LoginForm extends PureComponent<Props, State> {
|
||||
{!this.props.isLoggingIn ? (
|
||||
<button
|
||||
type="submit"
|
||||
aria-label={e2e.pages.Login.selectors.submit}
|
||||
aria-label={selectors.pages.Login.submit}
|
||||
className={`btn btn-large p-x-2 ${this.state.valid ? 'btn-primary' : 'btn-inverse'}`}
|
||||
onClick={this.onSubmit}
|
||||
disabled={!this.state.valid}
|
||||
|
0
public/app/core/components/search/search_results.ts
Normal file
0
public/app/core/components/search/search_results.ts
Normal file
@ -5,7 +5,7 @@ import filter from 'lodash/filter';
|
||||
import find from 'lodash/find';
|
||||
import indexOf from 'lodash/indexOf';
|
||||
import map from 'lodash/map';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import coreModule from '../core_module';
|
||||
import { GrafanaRootScope } from 'app/routes/GrafanaCtrl';
|
||||
@ -27,13 +27,13 @@ export class ValueSelectDropdownCtrl {
|
||||
onUpdated: any;
|
||||
queryHasSearchFilter: boolean;
|
||||
debouncedQueryChanged: Function;
|
||||
selectors: typeof e2e.pages.Dashboard.SubMenu.selectors;
|
||||
selectors: typeof selectors.pages.Dashboard.SubMenu;
|
||||
|
||||
/** @ngInject */
|
||||
constructor(private $scope: IScope) {
|
||||
this.queryHasSearchFilter = this.variable ? containsSearchFilter(this.variable.query) : false;
|
||||
this.debouncedQueryChanged = debounce(this.queryChanged.bind(this), 200);
|
||||
this.selectors = e2e.pages.Dashboard.SubMenu.selectors;
|
||||
this.selectors = selectors.pages.Dashboard.SubMenu;
|
||||
}
|
||||
|
||||
show() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import coreModule from 'app/core/core_module';
|
||||
import appEvents from 'app/core/app_events';
|
||||
@ -103,7 +103,7 @@ export class UtilSrv {
|
||||
scope.yesText = payload.yesText || 'Yes';
|
||||
scope.noText = payload.noText || 'Cancel';
|
||||
scope.confirmTextValid = scope.confirmText ? false : true;
|
||||
scope.selectors = e2e.pages.ConfirmModal.selectors;
|
||||
scope.selectors = selectors.pages.ConfirmModal;
|
||||
|
||||
appEvents.emit(CoreEvents.showModal, {
|
||||
src: 'public/app/partials/confirm_modal.html',
|
||||
|
@ -2,8 +2,9 @@ import React, { PureComponent } from 'react';
|
||||
import { connect, MapDispatchToProps, MapStateToProps } from 'react-redux';
|
||||
import { css } from 'emotion';
|
||||
import { Alert, Button, IconName } from '@grafana/ui';
|
||||
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { AngularComponent, getAngularLoader, getDataSourceSrv } from '@grafana/runtime';
|
||||
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { getAlertingValidationMessage } from './getAlertingValidationMessage';
|
||||
|
||||
@ -18,7 +19,6 @@ import { TestRuleResult } from './TestRuleResult';
|
||||
import { AppNotificationSeverity, CoreEvents, StoreState } from 'app/types';
|
||||
import { updateLocation } from 'app/core/actions';
|
||||
import { PanelEditorTabId } from '../dashboard/components/PanelEditor/types';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
|
||||
interface OwnProps {
|
||||
dashboard: DashboardModel;
|
||||
@ -206,7 +206,7 @@ class UnConnectedAlertTab extends PureComponent<Props, State> {
|
||||
|
||||
return (
|
||||
<EditorTabBody toolbarItems={toolbarItems}>
|
||||
<div aria-label={e2e.components.AlertTab.selectors.content}>
|
||||
<div aria-label={selectors.components.AlertTab.content}>
|
||||
{alert && hasTransformations && (
|
||||
<Alert
|
||||
severity={AppNotificationSeverity.Error}
|
||||
|
@ -3,6 +3,7 @@ import React, { useMemo } from 'react';
|
||||
import _ from 'lodash';
|
||||
import { LocationUpdate } from '@grafana/runtime';
|
||||
import { Button, HorizontalGroup, IconButton, stylesFactory, useTheme } from '@grafana/ui';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { connect, MapDispatchToProps } from 'react-redux';
|
||||
// Utils
|
||||
import config from 'app/core/config';
|
||||
@ -13,7 +14,6 @@ import { addPanel } from 'app/features/dashboard/state/reducers';
|
||||
// Types
|
||||
import { DashboardModel, PanelModel } from '../../state';
|
||||
import { LS_PANEL_COPY_KEY } from 'app/core/constants';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { css, cx, keyframes } from 'emotion';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
import tinycolor from 'tinycolor2';
|
||||
@ -168,7 +168,7 @@ const AddPanelWidgetCreate: React.FC<AddPanelWidgetCreateProps> = ({ onCreate, o
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
<HorizontalGroup>
|
||||
<Button icon="plus" size="md" onClick={onCreate} aria-label={e2e.pages.AddDashboard.selectors.addNewPanel}>
|
||||
<Button icon="plus" size="md" onClick={onCreate} aria-label={selectors.pages.AddDashboard.addNewPanel}>
|
||||
Add new panel
|
||||
</Button>
|
||||
{copiedPanelPlugins.length === 1 && (
|
||||
|
@ -1,8 +1,8 @@
|
||||
// Libraries
|
||||
import React, { FunctionComponent } from 'react';
|
||||
// Components
|
||||
import { Tooltip, Icon, IconName, IconType, IconSize } from '@grafana/ui';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { Icon, IconName, IconSize, IconType, Tooltip } from '@grafana/ui';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
interface Props {
|
||||
icon?: IconName;
|
||||
@ -31,7 +31,7 @@ export const DashNavButton: FunctionComponent<Props> = ({
|
||||
<button
|
||||
className={`btn navbar-button navbar-button--${classSuffix}`}
|
||||
onClick={onClick}
|
||||
aria-label={e2e.pages.Dashboard.Toolbar.selectors.toolbarItems(tooltip)}
|
||||
aria-label={selectors.pages.Dashboard.Toolbar.toolbarItems(tooltip)}
|
||||
>
|
||||
{icon && <Icon name={icon} type={iconType} size={iconSize || 'lg'} />}
|
||||
{children}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import $ from 'jquery';
|
||||
import _ from 'lodash';
|
||||
import angular, { ILocationService, IScope } from 'angular';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import { appEvents, contextSrv, coreModule } from 'app/core/core';
|
||||
import { DashboardModel } from '../../state/DashboardModel';
|
||||
@ -24,7 +24,7 @@ export class SettingsCtrl {
|
||||
canDelete: boolean;
|
||||
sections: any[];
|
||||
hasUnsavedFolderChange: boolean;
|
||||
selectors: typeof e2e.pages.Dashboard.Settings.General.selectors;
|
||||
selectors: typeof selectors.pages.Dashboard.Settings.General;
|
||||
useAngularTemplating: boolean;
|
||||
|
||||
/** @ngInject */
|
||||
@ -59,7 +59,7 @@ export class SettingsCtrl {
|
||||
|
||||
appEvents.on(CoreEvents.dashboardSaved, this.onPostSave.bind(this), $scope);
|
||||
|
||||
this.selectors = e2e.pages.Dashboard.Settings.General.selectors;
|
||||
this.selectors = selectors.pages.Dashboard.Settings.General;
|
||||
this.useAngularTemplating = !getConfig().featureToggles.newVariables;
|
||||
}
|
||||
|
||||
|
@ -8,12 +8,13 @@ import {
|
||||
transformDataFrame,
|
||||
} from '@grafana/data';
|
||||
import { Button, Field, Icon, Select, Table } from '@grafana/ui';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
|
||||
import { getPanelInspectorStyles } from './styles';
|
||||
import { config } from 'app/core/config';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
import { saveAs } from 'file-saver';
|
||||
import { cx } from 'emotion';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
|
||||
interface Props {
|
||||
data: DataFrame[];
|
||||
@ -109,7 +110,7 @@ export class InspectDataTab extends PureComponent<Props, State> {
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={styles.dataTabContent} aria-label={e2e.components.PanelInspector.Data.selectors.content}>
|
||||
<div className={styles.dataTabContent} aria-label={selectors.components.PanelInspector.Data.content}>
|
||||
<div className={styles.toolbar}>
|
||||
<Field label="Transformer" className="flex-grow-1">
|
||||
<Select options={transformationOptions} value={transformId} onChange={this.onTransformationChange} />
|
||||
|
@ -2,10 +2,11 @@ import React, { PureComponent } from 'react';
|
||||
import { chain } from 'lodash';
|
||||
import { AppEvents, PanelData, SelectableValue } from '@grafana/data';
|
||||
import { Button, ClipboardButton, Field, JSONFormatter, Select, TextArea } from '@grafana/ui';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import { appEvents } from 'app/core/core';
|
||||
import { DashboardModel, PanelModel } from '../../state';
|
||||
import { getPanelInspectorStyles } from './styles';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
|
||||
enum ShowContent {
|
||||
PanelJSON = 'panel',
|
||||
@ -142,7 +143,7 @@ export class InspectJSONTab extends PureComponent<Props, State> {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles.toolbar} aria-label={e2e.components.PanelInspector.Json.selectors.content}>
|
||||
<div className={styles.toolbar} aria-label={selectors.components.PanelInspector.Json.content}>
|
||||
<Field label="Select source" className="flex-grow-1">
|
||||
<Select options={options} value={selected} onChange={this.onSelectChanged} />
|
||||
</Field>
|
||||
|
@ -7,6 +7,7 @@ import { QueryInspector } from './QueryInspector';
|
||||
|
||||
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
|
||||
import { CustomScrollbar, Drawer, JSONFormatter, TabContent } from '@grafana/ui';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { getDataSourceSrv, getLocationSrv } from '@grafana/runtime';
|
||||
import {
|
||||
DataFrame,
|
||||
@ -25,7 +26,6 @@ import { config } from 'app/core/config';
|
||||
import { getPanelInspectorStyles } from './styles';
|
||||
import { StoreState } from 'app/types';
|
||||
import { InspectDataTab } from './InspectDataTab';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
|
||||
interface OwnProps {
|
||||
dashboard: DashboardModel;
|
||||
@ -223,7 +223,7 @@ export class PanelInspectorUnconnected extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
return (
|
||||
<div aria-label={e2e.components.PanelInspector.Stats.selectors.content}>
|
||||
<div aria-label={selectors.components.PanelInspector.Stats.content}>
|
||||
{this.renderStatsTable('Stats', stats)}
|
||||
{this.renderStatsTable('Data source stats', dataStats)}
|
||||
</div>
|
||||
|
@ -1,12 +1,13 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Button, JSONFormatter, LoadingPlaceholder } from '@grafana/ui';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { AppEvents, PanelEvents } from '@grafana/data';
|
||||
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { CopyToClipboard } from 'app/core/components/CopyToClipboard/CopyToClipboard';
|
||||
import { Button, JSONFormatter, LoadingPlaceholder } from '@grafana/ui';
|
||||
import { CoreEvents } from 'app/types';
|
||||
import { AppEvents, PanelEvents } from '@grafana/data';
|
||||
import { PanelModel } from 'app/features/dashboard/state';
|
||||
import { getPanelInspectorStyles } from './styles';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
|
||||
interface DsQuery {
|
||||
isLoading: boolean;
|
||||
@ -189,7 +190,7 @@ export class QueryInspector extends PureComponent<Props, State> {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div aria-label={e2e.components.PanelInspector.Query.selectors.content}>
|
||||
<div aria-label={selectors.components.PanelInspector.Query.content}>
|
||||
<h3 className="section-heading">Query inspector</h3>
|
||||
<p className="small muted">
|
||||
Query inspector allows you to view raw request and response. To collect this data Grafana needs to issue a
|
||||
|
@ -13,7 +13,7 @@ import { getDataLinksVariableSuggestions } from '../../../panel/panellinks/link_
|
||||
import { OverrideEditor } from './OverrideEditor';
|
||||
import groupBy from 'lodash/groupBy';
|
||||
import { OptionsGroup } from './OptionsGroup';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
interface Props {
|
||||
plugin: PanelPlugin;
|
||||
@ -103,7 +103,7 @@ export const OverrideFieldConfigEditor: React.FC<Props> = props => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div aria-label={e2e.components.OverridesConfigEditor.selectors.content}>
|
||||
<div aria-label={selectors.components.OverridesConfigEditor.content}>
|
||||
{renderOverrides()}
|
||||
{renderAddOverride()}
|
||||
</div>
|
||||
@ -183,7 +183,7 @@ export const DefaultFieldConfigEditor: React.FC<Props> = ({ data, onChange, conf
|
||||
const groupedConfigs = groupBy(plugin.fieldConfigRegistry.list(), i => i.category && i.category[0]);
|
||||
|
||||
return (
|
||||
<div aria-label={e2e.components.FieldConfigEditor.selectors.content}>
|
||||
<div aria-label={selectors.components.FieldConfigEditor.content}>
|
||||
{Object.keys(groupedConfigs).map((k, i) => {
|
||||
const groupItemsCounter = countGroupItems(groupedConfigs[k], config);
|
||||
|
||||
|
@ -4,7 +4,7 @@ import { GrafanaTheme } from '@grafana/data';
|
||||
import { Icon, stylesFactory, useTheme } from '@grafana/ui';
|
||||
import { PANEL_EDITOR_UI_STATE_STORAGE_KEY } from './state/reducers';
|
||||
import { useLocalStorage } from 'react-use';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
export interface OptionsGroupProps {
|
||||
id: string;
|
||||
@ -101,7 +101,7 @@ const CollapsibleSection: FC<Omit<OptionsGroupProps, 'persistMe'>> = ({
|
||||
<div
|
||||
className={styles.header}
|
||||
onClick={() => toggleExpand(!isExpanded)}
|
||||
aria-label={e2e.components.OptionsGroup.selectors.toggle(id)}
|
||||
aria-label={selectors.components.OptionsGroup.toggle(id)}
|
||||
>
|
||||
<div className={cx(styles.toggle, 'editor-options-group-toggle')}>
|
||||
<Icon name={isExpanded ? 'angle-down' : 'angle-right'} />
|
||||
|
@ -8,7 +8,7 @@ import { css } from 'emotion';
|
||||
import { PanelOptionsTab } from './PanelOptionsTab';
|
||||
import { DashNavButton } from 'app/features/dashboard/components/DashNav/DashNavButton';
|
||||
import { usePanelLatestData } from './usePanelLatestData';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
interface Props {
|
||||
plugin: PanelPlugin;
|
||||
@ -81,7 +81,7 @@ export const OptionsPaneContent: React.FC<Props> = ({
|
||||
const showMainTab = activeTab === 'options' || plugin.meta.skipDataQuery;
|
||||
|
||||
return (
|
||||
<div className={styles.panelOptionsPane} aria-label={e2e.components.PanelEditor.OptionsPane.selectors.content}>
|
||||
<div className={styles.panelOptionsPane} aria-label={selectors.components.PanelEditor.OptionsPane.content}>
|
||||
{plugin && (
|
||||
<div className={styles.wrapper}>
|
||||
<TabsBar className={styles.tabsBar}>
|
||||
@ -185,7 +185,7 @@ export const TabsBarContent: React.FC<{
|
||||
return (
|
||||
<>
|
||||
{width < 352 ? (
|
||||
<div className="flex-grow-1" aria-label={e2e.components.PanelEditor.OptionsPane.selectors.select}>
|
||||
<div className="flex-grow-1" aria-label={selectors.components.PanelEditor.OptionsPane.select}>
|
||||
<Select
|
||||
options={tabs}
|
||||
value={active}
|
||||
|
@ -31,7 +31,7 @@ import { SubMenuItems } from 'app/features/dashboard/components/SubMenu/SubMenuI
|
||||
import { BackButton } from 'app/core/components/BackButton/BackButton';
|
||||
import { appEvents } from 'app/core/core';
|
||||
import { SaveDashboardModalProxy } from '../SaveDashboard/SaveDashboardModalProxy';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
interface OwnProps {
|
||||
dashboard: DashboardModel;
|
||||
@ -197,7 +197,7 @@ export class PanelEditorUnconnected extends PureComponent<Props> {
|
||||
onDragFinished={size => this.onDragFinished(Pane.Top, size)}
|
||||
>
|
||||
{this.renderPanel(styles)}
|
||||
<div className={styles.tabsWrapper} aria-label={e2e.components.PanelEditor.DataPane.selectors.content}>
|
||||
<div className={styles.tabsWrapper} aria-label={selectors.components.PanelEditor.DataPane.content}>
|
||||
<PanelEditorTabs panel={panel} dashboard={dashboard} tabs={tabs} onChangeTab={this.onChangeTab} data={data} />
|
||||
</div>
|
||||
</SplitPane>
|
||||
@ -332,7 +332,7 @@ export class PanelEditorUnconnected extends PureComponent<Props> {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper} aria-label={e2e.components.PanelEditor.General.selectors.content}>
|
||||
<div className={styles.wrapper} aria-label={selectors.components.PanelEditor.General.content}>
|
||||
{this.editorToolbar(styles)}
|
||||
<div className={styles.verticalSplitPanesWrapper}>
|
||||
{uiState.isPanelOptionsVisible ? this.renderWithOptionsPane(styles) : this.renderHorizontalSplit(styles)}
|
||||
|
@ -1,7 +1,8 @@
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import { Button, HorizontalGroup, TextArea, Form, Checkbox } from '@grafana/ui';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { Button, Checkbox, Form, HorizontalGroup, TextArea } from '@grafana/ui';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import { SaveDashboardFormProps } from '../types';
|
||||
|
||||
interface SaveDashboardFormDTO {
|
||||
@ -37,7 +38,7 @@ export const SaveDashboardForm: React.FC<SaveDashboardFormProps> = ({ dashboard,
|
||||
label="Save current time range as dashboard default"
|
||||
name="saveTimerange"
|
||||
ref={register}
|
||||
aria-label={e2e.pages.SaveDashboardModal.selectors.saveTimerange}
|
||||
aria-label={selectors.pages.SaveDashboardModal.saveTimerange}
|
||||
/>
|
||||
)}
|
||||
{hasVariableChanged && (
|
||||
@ -45,7 +46,7 @@ export const SaveDashboardForm: React.FC<SaveDashboardFormProps> = ({ dashboard,
|
||||
label="Save current variable values as dashboard default"
|
||||
name="saveVariables"
|
||||
ref={register}
|
||||
aria-label={e2e.pages.SaveDashboardModal.selectors.saveVariables}
|
||||
aria-label={selectors.pages.SaveDashboardModal.saveVariables}
|
||||
/>
|
||||
)}
|
||||
{(hasVariableChanged || hasTimeChanged) && <div className="gf-form-group" />}
|
||||
@ -54,7 +55,7 @@ export const SaveDashboardForm: React.FC<SaveDashboardFormProps> = ({ dashboard,
|
||||
</div>
|
||||
|
||||
<HorizontalGroup>
|
||||
<Button type="submit" aria-label={e2e.pages.SaveDashboardModal.selectors.save}>
|
||||
<Button type="submit" aria-label={selectors.pages.SaveDashboardModal.save}>
|
||||
Save
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={onCancel}>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
|
||||
import { LegacyForms, ClipboardButton, Icon, InfoBox } from '@grafana/ui';
|
||||
const { Select, Switch } = LegacyForms;
|
||||
import { SelectableValue, PanelModel, AppEvents } from '@grafana/data';
|
||||
@ -86,7 +86,7 @@ export class ShareLink extends PureComponent<Props, State> {
|
||||
render() {
|
||||
const { panel } = this.props;
|
||||
const { useCurrentTimeRange, includeTemplateVars, selectedTheme, shareUrl, imageUrl } = this.state;
|
||||
const selectors = e2e.pages.SharePanelModal.selectors;
|
||||
const selectors = e2eSelectors.pages.SharePanelModal;
|
||||
|
||||
return (
|
||||
<div className="share-modal-body">
|
||||
|
@ -1,6 +1,6 @@
|
||||
import angular, { ILocationService } from 'angular';
|
||||
import _ from 'lodash';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { VariableSrv } from 'app/features/templating/all';
|
||||
import { CoreEvents } from '../../../../types';
|
||||
|
||||
@ -9,7 +9,7 @@ export class SubMenuCtrl {
|
||||
variables: any;
|
||||
dashboard: any;
|
||||
submenuEnabled: boolean;
|
||||
selectors: typeof e2e.pages.Dashboard.SubMenu.selectors;
|
||||
selectors: typeof selectors.pages.Dashboard.SubMenu;
|
||||
|
||||
/** @ngInject */
|
||||
constructor(private variableSrv: VariableSrv, private $location: ILocationService) {
|
||||
@ -19,7 +19,7 @@ export class SubMenuCtrl {
|
||||
this.dashboard.events.on(CoreEvents.submenuVisibilityChanged, (enabled: boolean) => {
|
||||
this.submenuEnabled = enabled;
|
||||
});
|
||||
this.selectors = e2e.pages.Dashboard.SubMenu.selectors;
|
||||
this.selectors = selectors.pages.Dashboard.SubMenu;
|
||||
}
|
||||
|
||||
annotationStateChanged() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { FunctionComponent, useEffect, useState } from 'react';
|
||||
import { VariableHide, VariableModel } from '../../../templating/types';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { PickerRenderer } from '../../../variables/pickers/PickerRenderer';
|
||||
|
||||
interface Props {
|
||||
@ -24,7 +24,7 @@ export const SubMenuItems: FunctionComponent<Props> = ({ variables }) => {
|
||||
<div
|
||||
key={variable.id}
|
||||
className="submenu-item gf-form-inline"
|
||||
aria-label={e2e.pages.Dashboard.SubMenu.selectors.submenuItem}
|
||||
aria-label={selectors.pages.Dashboard.SubMenu.submenuItem}
|
||||
>
|
||||
<PickerRenderer variable={variable} />
|
||||
</div>
|
||||
|
@ -11,7 +11,7 @@ import {
|
||||
import { TransformationOperationRow } from './TransformationOperationRow';
|
||||
import { Card, CardProps } from '../../../../core/components/Card/Card';
|
||||
import { css } from 'emotion';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
interface Props {
|
||||
onChange: (transformations: DataTransformerConfig[]) => void;
|
||||
@ -145,7 +145,7 @@ export class TransformationsEditor extends React.PureComponent<Props> {
|
||||
return (
|
||||
<CustomScrollbar autoHeightMin="100%">
|
||||
<Container padding="md">
|
||||
<div aria-label={e2e.components.TransformTab.selectors.content}>
|
||||
<div aria-label={selectors.components.TransformTab.content}>
|
||||
{!hasTransformationsConfigured && this.renderNoAddedTransformsState()}
|
||||
{hasTransformationsConfigured && this.renderTransformationEditors()}
|
||||
{hasTransformationsConfigured && this.renderTransformationSelector()}
|
||||
|
@ -1,10 +1,10 @@
|
||||
import React, { Component } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { isEqual } from 'lodash';
|
||||
import { DataLink, ScopedVars, PanelMenuItem, PanelData, LoadingState, QueryResultMetaNotice } from '@grafana/data';
|
||||
import { DataLink, LoadingState, PanelData, PanelMenuItem, QueryResultMetaNotice, ScopedVars } from '@grafana/data';
|
||||
import { AngularComponent } from '@grafana/runtime';
|
||||
import { ClickOutsideWrapper, Tooltip, Icon } from '@grafana/ui';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { ClickOutsideWrapper, Icon, Tooltip } from '@grafana/ui';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import PanelHeaderCorner from './PanelHeaderCorner';
|
||||
import { PanelHeaderMenu } from './PanelHeaderMenu';
|
||||
@ -159,7 +159,7 @@ export class PanelHeader extends Component<Props, State> {
|
||||
className="panel-title-container"
|
||||
onClick={this.onMenuToggle}
|
||||
onMouseDown={this.onMouseDown}
|
||||
aria-label={e2e.components.Panels.Panel.selectors.title(title)}
|
||||
aria-label={selectors.components.Panels.Panel.title(title)}
|
||||
>
|
||||
<div className="panel-title">
|
||||
{Object.values(notices).map(this.renderNotice)}
|
||||
|
@ -2,7 +2,7 @@ import React, { FC } from 'react';
|
||||
import { css } from 'emotion';
|
||||
import { PanelMenuItem } from '@grafana/data';
|
||||
import { Icon, IconName, useTheme } from '@grafana/ui';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
interface Props {
|
||||
children: any;
|
||||
@ -30,7 +30,7 @@ export const PanelHeaderMenuItem: FC<Props & PanelMenuItem> = props => {
|
||||
<li className={isSubMenu ? 'dropdown-submenu' : undefined}>
|
||||
<a onClick={props.onClick} href={props.href}>
|
||||
{props.iconClassName && <Icon name={props.iconClassName as IconName} className={menuIconClassName} />}
|
||||
<span className="dropdown-item-text" aria-label={e2e.components.Panels.Panel.selectors.headerItems(props.text)}>
|
||||
<span className="dropdown-item-text" aria-label={selectors.components.Panels.Panel.headerItems(props.text)}>
|
||||
{props.text}
|
||||
{isSubMenu && <Icon name="angle-right" className={shortcutIconClassName} />}
|
||||
</span>
|
||||
|
@ -1,9 +1,8 @@
|
||||
// Libraries
|
||||
import React, { PureComponent } from 'react';
|
||||
// Components
|
||||
import { CustomScrollbar, Icon, IconName, PanelOptionsGroup } from '@grafana/ui';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import { FadeIn } from 'app/core/components/Animations/FadeIn';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
|
||||
interface Props {
|
||||
children: JSX.Element;
|
||||
@ -92,7 +91,7 @@ export class EditorTabBody extends PureComponent<Props, State> {
|
||||
className="btn navbar-button"
|
||||
onClick={onClick}
|
||||
disabled={view.disabled}
|
||||
aria-label={e2e.components.QueryEditorToolbarItem.selectors.button(view.title)}
|
||||
aria-label={selectors.components.QueryEditorToolbarItem.button(view.title)}
|
||||
>
|
||||
{view.icon && <Icon name={view.icon as IconName} />} {view.title}
|
||||
</button>
|
||||
|
@ -3,7 +3,7 @@ import React, { PureComponent } from 'react';
|
||||
// Components
|
||||
import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker';
|
||||
import { QueryOptions } from './QueryOptions';
|
||||
import { CustomScrollbar, stylesFactory, Button, HorizontalGroup, Modal } from '@grafana/ui';
|
||||
import { Button, CustomScrollbar, HorizontalGroup, Modal, stylesFactory } from '@grafana/ui';
|
||||
import { getLocationSrv } from '@grafana/runtime';
|
||||
import { QueryEditorRows } from './QueryEditorRows';
|
||||
// Services
|
||||
@ -20,7 +20,7 @@ import { Unsubscribable } from 'rxjs';
|
||||
import { DashboardQueryEditor, isSharedDashboardQuery } from 'app/plugins/datasource/dashboard';
|
||||
import { expressionDatasource, ExpressionDatasourceID } from 'app/features/expressions/ExpressionDatasource';
|
||||
import { css } from 'emotion';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
interface Props {
|
||||
panel: PanelModel;
|
||||
@ -178,7 +178,7 @@ export class QueriesTab extends PureComponent<Props, State> {
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={this.openQueryInspector}
|
||||
aria-label={e2e.components.QueryTab.selectors.queryInspectorButton}
|
||||
aria-label={selectors.components.QueryTab.queryInspectorButton}
|
||||
>
|
||||
Query inspector
|
||||
</Button>
|
||||
@ -245,7 +245,7 @@ export class QueriesTab extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
return (
|
||||
<div aria-label={e2e.components.QueryTab.selectors.content}>
|
||||
<div aria-label={selectors.components.QueryTab.content}>
|
||||
<QueryEditorRows
|
||||
queries={panel.targets}
|
||||
datasource={currentDS}
|
||||
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { GrafanaTheme, PanelPluginMeta } from '@grafana/data';
|
||||
import { stylesFactory, useTheme, styleMixins } from '@grafana/ui';
|
||||
import { css, cx } from 'emotion';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { PanelPluginBadge } from '../../plugins/PluginSignatureBadge';
|
||||
|
||||
interface Props {
|
||||
@ -22,7 +22,7 @@ const VizTypePickerPlugin: React.FC<Props> = ({ isCurrent, plugin, onClick, disa
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper} aria-label={e2e.components.PluginVisualization.selectors.item(plugin.name)}>
|
||||
<div className={styles.wrapper} aria-label={selectors.components.PluginVisualization.item(plugin.name)}>
|
||||
<div className={cssClass} onClick={disabled ? () => {} : onClick} title={plugin.name}>
|
||||
<div className={styles.bg} />
|
||||
<div className={styles.itemContent}>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { DataSourceSettings } from '@grafana/data';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
export interface Props {
|
||||
dataSource: DataSourceSettings;
|
||||
@ -20,7 +20,7 @@ export class DataSourcesListItem extends PureComponent<Props> {
|
||||
<img src={dataSource.typeLogoUrl} alt={dataSource.name} />
|
||||
</figure>
|
||||
<div className="card-item-details">
|
||||
<div className="card-item-name" aria-label={e2e.pages.DataSources.selectors.dataSources(dataSource.name)}>
|
||||
<div className="card-item-name" aria-label={selectors.pages.DataSources.dataSources(dataSource.name)}>
|
||||
{dataSource.name}
|
||||
{dataSource.isDefault && <span className="btn btn-secondary btn-small card-item-label">default</span>}
|
||||
</div>
|
||||
|
@ -2,8 +2,8 @@ import React, { FC, PureComponent } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import { DataSourcePluginMeta, NavModel } from '@grafana/data';
|
||||
import { List, LinkButton, Button } from '@grafana/ui';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { Button, LinkButton, List } from '@grafana/ui';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import Page from 'app/core/components/Page/Page';
|
||||
import { DataSourcePluginCategory, StoreState } from 'app/types';
|
||||
@ -126,7 +126,7 @@ const DataSourceTypeCard: FC<DataSourceTypeCardProps> = props => {
|
||||
<Card
|
||||
title={plugin.name}
|
||||
description={plugin.info.description}
|
||||
ariaLabel={e2e.pages.AddDataSource.selectors.dataSourcePlugins(plugin.name)}
|
||||
ariaLabel={selectors.pages.AddDataSource.dataSourcePlugins(plugin.name)}
|
||||
logoUrl={plugin.info.logos.small}
|
||||
actions={
|
||||
<>
|
||||
@ -154,7 +154,7 @@ const DataSourceTypeCard: FC<DataSourceTypeCardProps> = props => {
|
||||
}
|
||||
className={isPhantom && 'add-data-source-item--phantom'}
|
||||
onClick={onClick}
|
||||
aria-label={e2e.pages.AddDataSource.selectors.dataSourcePlugins(plugin.name)}
|
||||
aria-label={selectors.pages.AddDataSource.dataSourcePlugins(plugin.name)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -1,7 +1,8 @@
|
||||
import React, { FC } from 'react';
|
||||
import { InlineFormLabel, LegacyForms } from '@grafana/ui';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
const { Input, Switch } = LegacyForms;
|
||||
import { e2e } from '@grafana/e2e';
|
||||
|
||||
export interface Props {
|
||||
dataSourceName: string;
|
||||
@ -30,7 +31,7 @@ const BasicSettings: FC<Props> = ({ dataSourceName, isDefault, onDefaultChange,
|
||||
placeholder="Name"
|
||||
onChange={event => onNameChange(event.target.value)}
|
||||
required
|
||||
aria-label={e2e.pages.DataSource.selectors.name}
|
||||
aria-label={selectors.pages.DataSource.name}
|
||||
/>
|
||||
</div>
|
||||
<Switch
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { FC } from 'react';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import config from 'app/core/config';
|
||||
|
||||
@ -19,7 +19,7 @@ const ButtonRow: FC<Props> = ({ isReadOnly, onDelete, onSubmit, onTest }) => {
|
||||
className="btn btn-primary"
|
||||
disabled={isReadOnly}
|
||||
onClick={event => onSubmit(event)}
|
||||
aria-label={e2e.pages.DataSource.selectors.saveAndTest}
|
||||
aria-label={selectors.pages.DataSource.saveAndTest}
|
||||
>
|
||||
Save & Test
|
||||
</button>
|
||||
@ -34,7 +34,7 @@ const ButtonRow: FC<Props> = ({ isReadOnly, onDelete, onSubmit, onTest }) => {
|
||||
className="btn btn-danger"
|
||||
disabled={isReadOnly}
|
||||
onClick={onDelete}
|
||||
aria-label={e2e.pages.DataSource.selectors.delete}
|
||||
aria-label={selectors.pages.DataSource.delete}
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
|
@ -2,7 +2,8 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import isString from 'lodash/isString';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { Icon } from '@grafana/ui';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
// Components
|
||||
import Page from 'app/core/components/Page/Page';
|
||||
import { GenericDataSourcePlugin, PluginSettings } from './PluginSettings';
|
||||
@ -24,7 +25,6 @@ import { getRouteParamsId } from 'app/core/selectors/location';
|
||||
// Types
|
||||
import { CoreEvents, StoreState } from 'app/types/';
|
||||
import { DataSourcePluginMeta, DataSourceSettings, NavModel, UrlQueryMap } from '@grafana/data';
|
||||
import { Icon } from '@grafana/ui';
|
||||
import { getDataSourceLoadingNav } from '../state/navModel';
|
||||
import PluginStateinfo from 'app/features/plugins/PluginStateInfo';
|
||||
import { dataSourceLoaded, setDataSourceName, setIsDefault } from '../state/reducers';
|
||||
@ -204,12 +204,12 @@ export class DataSourceSettingsPage extends PureComponent<Props> {
|
||||
|
||||
<div className="gf-form-group">
|
||||
{testingStatus && testingStatus.message && (
|
||||
<div className={`alert-${testingStatus.status} alert`} aria-label={e2e.pages.DataSource.selectors.alert}>
|
||||
<div className={`alert-${testingStatus.status} alert`} aria-label={selectors.pages.DataSource.alert}>
|
||||
<div className="alert-icon">
|
||||
{testingStatus.status === 'error' ? <Icon name="exclamation-triangle" /> : <Icon name="check" />}
|
||||
</div>
|
||||
<div className="alert-body">
|
||||
<div className="alert-title" aria-label={e2e.pages.DataSource.selectors.alertMessage}>
|
||||
<div className="alert-title" aria-label={selectors.pages.DataSource.alertMessage}>
|
||||
{testingStatus.message}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,23 +1,34 @@
|
||||
// Libraries
|
||||
import React from 'react';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import { css, cx } from 'emotion';
|
||||
import { compose } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
import memoizeOne from 'memoize-one';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { ErrorBoundaryAlert, stylesFactory, withTheme } from '@grafana/ui';
|
||||
import {
|
||||
AbsoluteTimeRange,
|
||||
DataQuery,
|
||||
DataSourceApi,
|
||||
ExploreMode,
|
||||
GrafanaTheme,
|
||||
GraphSeriesXY,
|
||||
LoadingState,
|
||||
PanelData,
|
||||
RawTimeRange,
|
||||
TimeRange,
|
||||
TimeZone,
|
||||
} from '@grafana/data';
|
||||
|
||||
// Services & Utils
|
||||
import store from 'app/core/store';
|
||||
import config from 'app/core/config';
|
||||
|
||||
// Components
|
||||
import { ErrorBoundaryAlert, stylesFactory, withTheme } from '@grafana/ui';
|
||||
import LogsContainer from './LogsContainer';
|
||||
import QueryRows from './QueryRows';
|
||||
import TableContainer from './TableContainer';
|
||||
import RichHistoryContainer from './RichHistory/RichHistoryContainer';
|
||||
// Actions
|
||||
import {
|
||||
addQueryRow,
|
||||
changeSize,
|
||||
initializeExplore,
|
||||
modifyQueries,
|
||||
@ -25,23 +36,8 @@ import {
|
||||
scanStart,
|
||||
setQueries,
|
||||
toggleGraph,
|
||||
addQueryRow,
|
||||
updateTimeRange,
|
||||
} from './state/actions';
|
||||
// Types
|
||||
import {
|
||||
AbsoluteTimeRange,
|
||||
DataQuery,
|
||||
DataSourceApi,
|
||||
GraphSeriesXY,
|
||||
PanelData,
|
||||
RawTimeRange,
|
||||
TimeRange,
|
||||
TimeZone,
|
||||
LoadingState,
|
||||
ExploreMode,
|
||||
GrafanaTheme,
|
||||
} from '@grafana/data';
|
||||
|
||||
import { ExploreId, ExploreItemState, ExploreUIState, ExploreUpdateState, ExploreUrlState } from 'app/types/explore';
|
||||
import { StoreState } from 'app/types';
|
||||
@ -49,10 +45,10 @@ import {
|
||||
DEFAULT_RANGE,
|
||||
DEFAULT_UI_STATE,
|
||||
ensureQueries,
|
||||
getTimeRangeFromUrl,
|
||||
getTimeRange,
|
||||
lastUsedDatasourceKeyForOrgId,
|
||||
getFirstNonQueryRowSpecificError,
|
||||
getTimeRange,
|
||||
getTimeRangeFromUrl,
|
||||
lastUsedDatasourceKeyForOrgId,
|
||||
} from 'app/core/utils/explore';
|
||||
import { Emitter } from 'app/core/utils/emitter';
|
||||
import { ExploreToolbar } from './ExploreToolbar';
|
||||
@ -63,8 +59,6 @@ import { scanStopAction } from './state/actionTypes';
|
||||
import { ExploreGraphPanel } from './ExploreGraphPanel';
|
||||
import { TraceView } from './TraceView/TraceView';
|
||||
import { SecondaryActions } from './SecondaryActions';
|
||||
import { compose } from 'redux';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
|
||||
const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
return {
|
||||
@ -320,7 +314,7 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
|
||||
const queryError = getFirstNonQueryRowSpecificError(queryErrors);
|
||||
|
||||
return (
|
||||
<div className={exploreClass} ref={this.getRef} aria-label={e2e.pages.Explore.General.selectors.container}>
|
||||
<div className={exploreClass} ref={this.getRef} aria-label={selectors.pages.Explore.General.container}>
|
||||
<ExploreToolbar exploreId={exploreId} onChangeTime={this.onChangeTime} />
|
||||
{datasourceMissing ? this.renderEmptyState() : null}
|
||||
{datasourceInstance && (
|
||||
|
@ -1,9 +1,9 @@
|
||||
import React from 'react';
|
||||
import { RefreshPicker } from '@grafana/ui';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import memoizeOne from 'memoize-one';
|
||||
import { css } from 'emotion';
|
||||
import classNames from 'classnames';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
|
||||
import { ResponsiveButton } from './ResponsiveButton';
|
||||
|
||||
@ -43,7 +43,7 @@ export function RunButton(props: Props) {
|
||||
})}
|
||||
icon={loading ? 'fa fa-spinner' : 'sync'}
|
||||
iconClassName={loading && ' fa-spin run-icon'}
|
||||
aria-label={e2e.pages.Explore.General.selectors.runButton}
|
||||
aria-label={selectors.pages.Explore.General.runButton}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { FC, useCallback, CSSProperties } from 'react';
|
||||
import { css, cx } from 'emotion';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
|
||||
import { useTheme, TagList, styleMixins, stylesFactory } from '@grafana/ui';
|
||||
import { DashboardSectionItem, OnToggleChecked } from '../types';
|
||||
import { SearchCheckbox } from './SearchCheckbox';
|
||||
@ -15,7 +15,7 @@ export interface Props {
|
||||
style?: CSSProperties;
|
||||
}
|
||||
|
||||
const { selectors } = e2e.pages.Dashboards;
|
||||
const selectors = e2eSelectors.pages.Dashboards;
|
||||
|
||||
export const SearchItem: FC<Props> = ({ item, editable, onToggleChecked, onTagSelected, style }) => {
|
||||
const theme = useTheme();
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { VariableQueryProps } from 'app/types/plugins';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
export default class DefaultVariableQueryEditor extends PureComponent<VariableQueryProps, any> {
|
||||
constructor(props: VariableQueryProps) {
|
||||
@ -38,7 +38,7 @@ export default class DefaultVariableQueryEditor extends PureComponent<VariableQu
|
||||
onBlur={this.onBlur}
|
||||
placeholder="metric name or tags query"
|
||||
required
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.selectors.queryOptionsQueryInput}
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsQueryInput}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import _ from 'lodash';
|
||||
import { AppEvents } from '@grafana/data';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import coreModule from 'app/core/core_module';
|
||||
import { variableTypes } from './types';
|
||||
@ -60,10 +60,10 @@ export class VariableEditorCtrl {
|
||||
];
|
||||
|
||||
$scope.selectors = {
|
||||
...e2e.pages.Dashboard.Settings.Variables.List.selectors,
|
||||
...e2e.pages.Dashboard.Settings.Variables.Edit.General.selectors,
|
||||
...e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.selectors,
|
||||
...e2e.pages.Dashboard.Settings.Variables.Edit.ConstantVariable.selectors,
|
||||
...selectors.pages.Dashboard.Settings.Variables.List,
|
||||
...selectors.pages.Dashboard.Settings.Variables.Edit.General,
|
||||
...selectors.pages.Dashboard.Settings.Variables.Edit.QueryVariable,
|
||||
...selectors.pages.Dashboard.Settings.Variables.Edit.ConstantVariable,
|
||||
};
|
||||
|
||||
$scope.init = () => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { ChangeEvent, FocusEvent, PureComponent } from 'react';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import { ConstantVariableModel } from '../../templating/types';
|
||||
import { VariableEditorProps } from '../editor/types';
|
||||
@ -36,9 +36,7 @@ export class ConstantVariableEditor extends PureComponent<Props> {
|
||||
onChange={this.onChange}
|
||||
onBlur={this.onBlur}
|
||||
placeholder="your metric prefix"
|
||||
aria-label={
|
||||
e2e.pages.Dashboard.Settings.Variables.Edit.ConstantVariable.selectors.constantOptionsQueryInput
|
||||
}
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.ConstantVariable.constantOptionsQueryInput}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,11 +1,12 @@
|
||||
import React, { FunctionComponent, useCallback } from 'react';
|
||||
import { LegacyForms } from '@grafana/ui';
|
||||
const { Switch } = LegacyForms;
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import { VariableWithMultiSupport } from '../../templating/types';
|
||||
import { VariableEditorProps } from './types';
|
||||
import { VariableIdentifier, toVariableIdentifier } from '../state/types';
|
||||
import { toVariableIdentifier, VariableIdentifier } from '../state/types';
|
||||
|
||||
const { Switch } = LegacyForms;
|
||||
|
||||
export interface SelectionOptionsEditorProps<Model extends VariableWithMultiSupport = VariableWithMultiSupport>
|
||||
extends VariableEditorProps<Model> {
|
||||
@ -37,7 +38,7 @@ export const SelectionOptionsEditor: FunctionComponent<SelectionOptionsEditorPro
|
||||
<div className="section gf-form-group">
|
||||
<h5 className="section-heading">Selection Options</h5>
|
||||
<div className="section">
|
||||
<div aria-label={e2e.pages.Dashboard.Settings.Variables.Edit.General.selectors.selectionOptionsMultiSwitch}>
|
||||
<div aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsMultiSwitch}>
|
||||
<Switch
|
||||
label="Multi-value"
|
||||
labelClass="width-10"
|
||||
@ -46,9 +47,7 @@ export const SelectionOptionsEditor: FunctionComponent<SelectionOptionsEditorPro
|
||||
tooltip={'Enables multiple values to be selected at the same time'}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.Edit.General.selectors.selectionOptionsIncludeAllSwitch}
|
||||
>
|
||||
<div aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsIncludeAllSwitch}>
|
||||
<Switch
|
||||
label="Include All option"
|
||||
labelClass="width-10"
|
||||
@ -67,7 +66,7 @@ export const SelectionOptionsEditor: FunctionComponent<SelectionOptionsEditorPro
|
||||
value={props.variable.allValue ?? ''}
|
||||
onChange={onAllValueChanged}
|
||||
placeholder="blank = auto"
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.Edit.General.selectors.selectionOptionsCustomAllInput}
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.General.selectionOptionsCustomAllInput}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
@ -1,8 +1,9 @@
|
||||
import React, { MouseEvent, PureComponent } from 'react';
|
||||
import { Icon } from '@grafana/ui';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import { NEW_VARIABLE_ID, toVariableIdentifier, toVariablePayload, VariableIdentifier } from '../state/types';
|
||||
import { StoreState } from '../../../types';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { Icon } from '@grafana/ui';
|
||||
import { VariableEditorList } from './VariableEditorList';
|
||||
import { VariableEditorEditor } from './VariableEditorEditor';
|
||||
import { MapDispatchToProps, MapStateToProps } from 'react-redux';
|
||||
@ -69,7 +70,7 @@ class VariableEditorContainerUnconnected extends PureComponent<Props> {
|
||||
<h3 className="dashboard-settings__header">
|
||||
<a
|
||||
onClick={this.onChangeToListMode}
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.Edit.General.selectors.headerLink}
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.General.headerLink}
|
||||
>
|
||||
Variables
|
||||
</a>
|
||||
@ -77,7 +78,7 @@ class VariableEditorContainerUnconnected extends PureComponent<Props> {
|
||||
<span>
|
||||
<Icon
|
||||
name="angle-right"
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.Edit.General.selectors.modeLabelNew}
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.General.modeLabelNew}
|
||||
/>
|
||||
New
|
||||
</span>
|
||||
@ -86,7 +87,7 @@ class VariableEditorContainerUnconnected extends PureComponent<Props> {
|
||||
<span>
|
||||
<Icon
|
||||
name="angle-right"
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.Edit.General.selectors.modeLabelEdit}
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.General.modeLabelEdit}
|
||||
/>
|
||||
Edit
|
||||
</span>
|
||||
@ -99,7 +100,7 @@ class VariableEditorContainerUnconnected extends PureComponent<Props> {
|
||||
type="button"
|
||||
className="btn btn-primary"
|
||||
onClick={this.onNewVariable}
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.List.selectors.newButton}
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.List.newButton}
|
||||
>
|
||||
New
|
||||
</a>
|
||||
|
@ -2,7 +2,8 @@ import React, { ChangeEvent, FormEvent, PureComponent } from 'react';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import { AppEvents, VariableType } from '@grafana/data';
|
||||
import { InlineFormLabel } from '@grafana/ui';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import { variableAdapters } from '../adapters';
|
||||
import { NEW_VARIABLE_ID, toVariablePayload, VariableIdentifier } from '../state/types';
|
||||
import { VariableHide, VariableModel } from '../../templating/types';
|
||||
@ -129,7 +130,7 @@ export class VariableEditorEditorUnConnected extends PureComponent<Props> {
|
||||
required
|
||||
value={this.props.editor.name}
|
||||
onChange={this.onNameChange}
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.Edit.General.selectors.generalNameInput}
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.General.generalNameInput}
|
||||
/>
|
||||
</div>
|
||||
<div className="gf-form max-width-19">
|
||||
@ -141,7 +142,7 @@ export class VariableEditorEditorUnConnected extends PureComponent<Props> {
|
||||
className="gf-form-input"
|
||||
value={this.props.variable.type}
|
||||
onChange={this.onTypeChange}
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.Edit.General.selectors.generalTypeSelect}
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.General.generalTypeSelect}
|
||||
>
|
||||
{variableAdapters.list().map(({ id, name }) => (
|
||||
<option key={id} label={name} value={id}>
|
||||
@ -168,7 +169,7 @@ export class VariableEditorEditorUnConnected extends PureComponent<Props> {
|
||||
value={this.props.variable.label ?? ''}
|
||||
onChange={this.onLabelChange}
|
||||
placeholder="optional display name"
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.Edit.General.selectors.generalLabelInput}
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.General.generalLabelInput}
|
||||
/>
|
||||
</div>
|
||||
<div className="gf-form max-width-19">
|
||||
@ -178,7 +179,7 @@ export class VariableEditorEditorUnConnected extends PureComponent<Props> {
|
||||
className="gf-form-input"
|
||||
value={this.props.variable.hide}
|
||||
onChange={this.onHideChange}
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.Edit.General.selectors.generalHideSelect}
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.General.generalHideSelect}
|
||||
>
|
||||
<option label="" value={VariableHide.dontHide}>
|
||||
{''}
|
||||
@ -204,7 +205,7 @@ export class VariableEditorEditorUnConnected extends PureComponent<Props> {
|
||||
<button
|
||||
type="submit"
|
||||
className="btn btn-primary"
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.Edit.General.selectors.updateButton}
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.General.updateButton}
|
||||
>
|
||||
Update
|
||||
</button>
|
||||
@ -213,7 +214,7 @@ export class VariableEditorEditorUnConnected extends PureComponent<Props> {
|
||||
<button
|
||||
type="submit"
|
||||
className="btn btn-primary"
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.Edit.General.selectors.addButton}
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.General.addButton}
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
|
@ -1,9 +1,10 @@
|
||||
import React, { MouseEvent, PureComponent } from 'react';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { Icon } from '@grafana/ui';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import EmptyListCTA from '../../../core/components/EmptyListCTA/EmptyListCTA';
|
||||
import { QueryVariableModel, VariableModel } from '../../templating/types';
|
||||
import { toVariableIdentifier, VariableIdentifier } from '../state/types';
|
||||
import { Icon } from '@grafana/ui';
|
||||
|
||||
export interface Props {
|
||||
variables: VariableModel[];
|
||||
@ -72,7 +73,7 @@ export class VariableEditorList extends PureComponent<Props> {
|
||||
<div>
|
||||
<table
|
||||
className="filter-table filter-table--hover"
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.List.selectors.table}
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.List.table}
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
@ -90,7 +91,7 @@ export class VariableEditorList extends PureComponent<Props> {
|
||||
<span
|
||||
onClick={event => this.onEditClick(event, toVariableIdentifier(variable))}
|
||||
className="pointer template-variable"
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.List.selectors.tableRowNameFields(
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.List.tableRowNameFields(
|
||||
variable.name
|
||||
)}
|
||||
>
|
||||
@ -101,7 +102,7 @@ export class VariableEditorList extends PureComponent<Props> {
|
||||
style={{ maxWidth: '200px' }}
|
||||
onClick={event => this.onEditClick(event, toVariableIdentifier(variable))}
|
||||
className="pointer max-width"
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.List.selectors.tableRowDefinitionFields(
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.List.tableRowDefinitionFields(
|
||||
variable.name
|
||||
)}
|
||||
>
|
||||
@ -113,7 +114,7 @@ export class VariableEditorList extends PureComponent<Props> {
|
||||
<Icon
|
||||
onClick={event => this.onChangeVariableOrder(event, variable, MoveType.up)}
|
||||
name="arrow-up"
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.List.selectors.tableRowArrowUpButtons(
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.List.tableRowArrowUpButtons(
|
||||
variable.name
|
||||
)}
|
||||
/>
|
||||
@ -124,7 +125,7 @@ export class VariableEditorList extends PureComponent<Props> {
|
||||
<Icon
|
||||
onClick={event => this.onChangeVariableOrder(event, variable, MoveType.down)}
|
||||
name="arrow-down"
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.List.selectors.tableRowArrowDownButtons(
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.List.tableRowArrowDownButtons(
|
||||
variable.name
|
||||
)}
|
||||
/>
|
||||
@ -134,7 +135,7 @@ export class VariableEditorList extends PureComponent<Props> {
|
||||
<a
|
||||
onClick={event => this.onDuplicateVariable(event, toVariableIdentifier(variable))}
|
||||
className="btn btn-inverse btn-small"
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.List.selectors.tableRowDuplicateButtons(
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.List.tableRowDuplicateButtons(
|
||||
variable.name
|
||||
)}
|
||||
>
|
||||
@ -145,7 +146,7 @@ export class VariableEditorList extends PureComponent<Props> {
|
||||
<a
|
||||
onClick={event => this.onRemoveVariable(event, toVariableIdentifier(variable))}
|
||||
className="btn btn-danger btn-small"
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.List.selectors.tableRowRemoveButtons(
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.List.tableRowRemoveButtons(
|
||||
variable.name
|
||||
)}
|
||||
>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { VariableModel, VariableOption, VariableWithOptions } from '../../templating/types';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
export interface VariableValuesPreviewProps {
|
||||
variable: VariableModel;
|
||||
@ -30,7 +30,7 @@ export const VariableValuesPreview: React.FunctionComponent<VariableValuesPrevie
|
||||
<div className="gf-form" key={`${o.value}-${index}`}>
|
||||
<span
|
||||
className="gf-form-label"
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.Edit.General.selectors.previewOfValuesOption}
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.General.previewOfValuesOption}
|
||||
>
|
||||
{o.text}
|
||||
</span>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { FunctionComponent, useMemo } from 'react';
|
||||
import { VariableHide, VariableModel } from '../../templating/types';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { variableAdapters } from '../adapters';
|
||||
|
||||
interface Props {
|
||||
@ -20,7 +20,7 @@ export const PickerRenderer: FunctionComponent<Props> = props => {
|
||||
{props.variable.hide === VariableHide.dontHide && (
|
||||
<label
|
||||
className="gf-form-label gf-form-label--variable"
|
||||
aria-label={e2e.pages.Dashboard.SubMenu.selectors.submenuItemLabels(labelOrName)}
|
||||
aria-label={selectors.pages.Dashboard.SubMenu.submenuItemLabels(labelOrName)}
|
||||
>
|
||||
{labelOrName}
|
||||
</label>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { getTagColorsFromName, Icon } from '@grafana/ui';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import { VariableTag } from '../../../templating/types';
|
||||
|
||||
interface Props {
|
||||
@ -22,7 +23,7 @@ export class VariableLink extends PureComponent<Props> {
|
||||
<a
|
||||
onClick={this.onClick}
|
||||
className="variable-value-link"
|
||||
aria-label={e2e.pages.Dashboard.SubMenu.selectors.submenuItemValueDropDownValueLinkTexts(`${text}`)}
|
||||
aria-label={selectors.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts(`${text}`)}
|
||||
>
|
||||
{text}
|
||||
{tags.map(tag => {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { getTagColorsFromName, Tooltip, Icon } from '@grafana/ui';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { getTagColorsFromName, Icon, Tooltip } from '@grafana/ui';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import { VariableOption, VariableTag } from '../../../templating/types';
|
||||
|
||||
export interface Props {
|
||||
@ -42,7 +43,7 @@ export class VariableOptions extends PureComponent<Props> {
|
||||
return (
|
||||
<div
|
||||
className={`${multi ? 'variable-value-dropdown multi' : 'variable-value-dropdown single'}`}
|
||||
aria-label={e2e.pages.Dashboard.SubMenu.selectors.submenuItemValueDropDownDropDown}
|
||||
aria-label={selectors.pages.Dashboard.SubMenu.submenuItemValueDropDownDropDown}
|
||||
>
|
||||
<div className="variable-options-wrapper">
|
||||
<div className="variable-options-column">
|
||||
@ -95,7 +96,7 @@ export class VariableOptions extends PureComponent<Props> {
|
||||
return (
|
||||
<a key={`${option.value}`} className={highlightClass} onClick={this.onToggle(option)}>
|
||||
<span className="variable-option-icon"></span>
|
||||
<span aria-label={e2e.pages.Dashboard.SubMenu.selectors.submenuItemValueDropDownOptionTexts(`${option.text}`)}>
|
||||
<span aria-label={selectors.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts(`${option.text}`)}>
|
||||
{option.text}
|
||||
</span>
|
||||
</a>
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React, { ChangeEvent, PureComponent } from 'react';
|
||||
import { e2e } from '@grafana/e2e';
|
||||
import { InlineFormLabel, LegacyForms } from '@grafana/ui';
|
||||
const { Switch } = LegacyForms;
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
import templateSrv from '../../templating/template_srv';
|
||||
import { SelectionOptionsEditor } from '../editor/SelectionOptionsEditor';
|
||||
@ -16,6 +15,8 @@ import { connectWithStore } from '../../../core/utils/connectWithReduxStore';
|
||||
import { toVariableIdentifier } from '../state/types';
|
||||
import { changeVariableMultiValue } from '../state/actions';
|
||||
|
||||
const { Switch } = LegacyForms;
|
||||
|
||||
export interface OwnProps extends VariableEditorProps<QueryVariableModel> {}
|
||||
|
||||
interface ConnectedProps {
|
||||
@ -131,7 +132,7 @@ export class QueryVariableEditorUnConnected extends PureComponent<Props, State>
|
||||
onChange={this.onDataSourceChange}
|
||||
required
|
||||
aria-label={
|
||||
e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.selectors.queryOptionsDataSourceSelect
|
||||
selectors.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsDataSourceSelect
|
||||
}
|
||||
>
|
||||
{this.props.editor.extended?.dataSources.length &&
|
||||
@ -153,9 +154,7 @@ export class QueryVariableEditorUnConnected extends PureComponent<Props, State>
|
||||
className="gf-form-input"
|
||||
value={this.props.variable.refresh}
|
||||
onChange={this.onRefreshChange}
|
||||
aria-label={
|
||||
e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.selectors.queryOptionsRefreshSelect
|
||||
}
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsRefreshSelect}
|
||||
>
|
||||
<option label="Never" value={VariableRefresh.never}>
|
||||
Never
|
||||
@ -194,7 +193,7 @@ export class QueryVariableEditorUnConnected extends PureComponent<Props, State>
|
||||
value={this.state.regex ?? this.props.variable.regex}
|
||||
onChange={this.onRegExChange}
|
||||
onBlur={this.onRegExBlur}
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.selectors.queryOptionsRegExInput}
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsRegExInput}
|
||||
/>
|
||||
</div>
|
||||
<div className="gf-form max-width-21">
|
||||
@ -206,7 +205,7 @@ export class QueryVariableEditorUnConnected extends PureComponent<Props, State>
|
||||
className="gf-form-input"
|
||||
value={this.props.variable.sort}
|
||||
onChange={this.onSortChange}
|
||||
aria-label={e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.selectors.queryOptionsSortSelect}
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsSortSelect}
|
||||
>
|
||||
<option label="Disabled" value={VariableSort.disabled}>
|
||||
Disabled
|
||||
@ -249,9 +248,7 @@ export class QueryVariableEditorUnConnected extends PureComponent<Props, State>
|
||||
<div className="gf-form-group">
|
||||
<h5>Value groups/tags (Experimental feature)</h5>
|
||||
<div
|
||||
aria-label={
|
||||
e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.selectors.valueGroupsTagsEnabledSwitch
|
||||
}
|
||||
aria-label={selectors.pages.Dashboard.Settings.Variables.Edit.QueryVariable.valueGroupsTagsEnabledSwitch}
|
||||
>
|
||||
<Switch
|
||||
label="Enabled"
|
||||
@ -272,7 +269,7 @@ export class QueryVariableEditorUnConnected extends PureComponent<Props, State>
|
||||
onChange={this.onTagsQueryChange}
|
||||
onBlur={this.onTagsQueryBlur}
|
||||
aria-label={
|
||||
e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.selectors.valueGroupsTagsTagsQueryInput
|
||||
selectors.pages.Dashboard.Settings.Variables.Edit.QueryVariable.valueGroupsTagsTagsQueryInput
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
@ -286,8 +283,7 @@ export class QueryVariableEditorUnConnected extends PureComponent<Props, State>
|
||||
onChange={this.onTagValuesQueryChange}
|
||||
onBlur={this.onTagValuesQueryBlur}
|
||||
aria-label={
|
||||
e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.selectors
|
||||
.valueGroupsTagsTagsValuesQueryInput
|
||||
selectors.pages.Dashboard.Settings.Variables.Edit.QueryVariable.valueGroupsTagsTagsValuesQueryInput
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user