@grafana/plugin-e2e 1.14.6 → 1.15.0-canary.1272.059bc30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +37 -0
- package/dist/index.js +8 -0
- package/dist/matchers/toBeChecked.d.ts +6 -0
- package/dist/matchers/toBeChecked.js +28 -0
- package/dist/matchers/toHaveChecked.d.ts +5 -0
- package/dist/matchers/toHaveChecked.js +21 -0
- package/dist/matchers/toHaveColor.d.ts +5 -0
- package/dist/matchers/toHaveColor.js +21 -0
- package/dist/matchers/toHaveSelected.d.ts +6 -0
- package/dist/matchers/toHaveSelected.js +91 -0
- package/dist/models/components/ColorPicker.d.ts +9 -0
- package/dist/models/components/ColorPicker.js +29 -0
- package/dist/models/components/ComponentBase.d.ts +10 -0
- package/dist/models/components/ComponentBase.js +18 -0
- package/dist/models/components/MultiSelect.d.ts +8 -0
- package/dist/models/components/MultiSelect.js +17 -0
- package/dist/models/components/PanelEditOptionsGroup.d.ts +24 -0
- package/dist/models/components/PanelEditOptionsGroup.js +57 -0
- package/dist/models/components/RadioGroup.d.ts +8 -0
- package/dist/models/components/RadioGroup.js +17 -0
- package/dist/models/components/Select.d.ts +10 -0
- package/dist/models/components/Select.js +39 -0
- package/dist/models/components/Switch.d.ts +12 -0
- package/dist/models/components/Switch.js +36 -0
- package/dist/models/components/UnitPicker.d.ts +9 -0
- package/dist/models/components/UnitPicker.js +27 -0
- package/dist/models/components/types.d.ts +3 -0
- package/dist/models/components/types.js +2 -0
- package/dist/models/pages/GrafanaPage.js +2 -5
- package/dist/models/pages/PanelEditPage.d.ts +8 -0
- package/dist/models/pages/PanelEditPage.js +22 -1
- package/dist/models/utils.d.ts +2 -0
- package/dist/models/utils.js +8 -0
- package/dist/selectors/versionedConstants.d.ts +13 -0
- package/dist/selectors/versionedConstants.js +13 -0
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
|
+
import { Locator } from '@playwright/test';
|
|
1
2
|
import { AlertPageOptions, AlertVariant, ContainTextOptions, PluginFixture, PluginOptions } from './types';
|
|
2
3
|
import { GrafanaPage } from './models/pages/GrafanaPage';
|
|
3
4
|
import { VariableEditPage } from './models/pages/VariableEditPage';
|
|
5
|
+
import { toHaveSelected } from './matchers/toHaveSelected';
|
|
6
|
+
import { Select } from './models/components/Select';
|
|
7
|
+
import { Switch } from './models/components/Switch';
|
|
8
|
+
import { toBeChecked } from './matchers/toBeChecked';
|
|
9
|
+
import { RadioGroup } from './models/components/RadioGroup';
|
|
10
|
+
import { toHaveChecked } from './matchers/toHaveChecked';
|
|
11
|
+
import { MultiSelect } from './models/components/MultiSelect';
|
|
12
|
+
import { toHaveColor } from './matchers/toHaveColor';
|
|
13
|
+
import { ColorPicker } from './models/components/ColorPicker';
|
|
4
14
|
export { DataSourcePicker } from './models/components/DataSourcePicker';
|
|
5
15
|
export { Panel } from './models/components/Panel';
|
|
6
16
|
export { TimeRange } from './models/components/TimeRange';
|
|
@@ -41,6 +51,10 @@ export declare const expect: import("@playwright/test").Expect<{
|
|
|
41
51
|
pass: boolean;
|
|
42
52
|
actual: undefined;
|
|
43
53
|
}>;
|
|
54
|
+
toHaveSelected: typeof toHaveSelected;
|
|
55
|
+
toBeChecked: typeof toBeChecked;
|
|
56
|
+
toHaveChecked: typeof toHaveChecked;
|
|
57
|
+
toHaveColor: typeof toHaveColor;
|
|
44
58
|
}>;
|
|
45
59
|
export { selectors } from '@playwright/test';
|
|
46
60
|
declare global {
|
|
@@ -70,6 +84,29 @@ declare global {
|
|
|
70
84
|
* Asserts that a GrafanaPage contains an alert with the specified severity. Use the options to specify the timeout and to filter the alerts.
|
|
71
85
|
*/
|
|
72
86
|
toHaveAlert(this: Matchers<unknown, GrafanaPage>, severity: AlertVariant, options?: AlertPageOptions): Promise<R>;
|
|
87
|
+
/**
|
|
88
|
+
* Asserts that a Selector has the specified value selected
|
|
89
|
+
*/
|
|
90
|
+
toHaveSelected(select: Select | MultiSelect, value: string | RegExp | string[] | RegExp[], options?: ContainTextOptions): Promise<R>;
|
|
91
|
+
/**
|
|
92
|
+
* Asserts that a Switch is on or off (on by default)
|
|
93
|
+
*/
|
|
94
|
+
toBeChecked(target: Switch | Locator, options?: {
|
|
95
|
+
on?: boolean;
|
|
96
|
+
timeout?: number;
|
|
97
|
+
}): Promise<R>;
|
|
98
|
+
/**
|
|
99
|
+
* Asserts that a Radio has expected value selected
|
|
100
|
+
*/
|
|
101
|
+
toHaveChecked(radioGroup: RadioGroup, expected: string, options?: {
|
|
102
|
+
timeout?: number;
|
|
103
|
+
}): Promise<R>;
|
|
104
|
+
/**
|
|
105
|
+
* Asserts that a color picker has expected color selected
|
|
106
|
+
*/
|
|
107
|
+
toHaveColor(colorPicker: ColorPicker, rgbOrHex: string, options?: {
|
|
108
|
+
timeout?: number;
|
|
109
|
+
}): Promise<R>;
|
|
73
110
|
}
|
|
74
111
|
}
|
|
75
112
|
}
|
package/dist/index.js
CHANGED
|
@@ -48,6 +48,10 @@ const toDisplayPreviews_1 = require("./matchers/toDisplayPreviews");
|
|
|
48
48
|
const toBeOK_1 = require("./matchers/toBeOK");
|
|
49
49
|
const variablePage_1 = require("./fixtures/variablePage");
|
|
50
50
|
const gotoVariablePage_1 = require("./fixtures/commands/gotoVariablePage");
|
|
51
|
+
const toHaveSelected_1 = require("./matchers/toHaveSelected");
|
|
52
|
+
const toBeChecked_1 = require("./matchers/toBeChecked");
|
|
53
|
+
const toHaveChecked_1 = require("./matchers/toHaveChecked");
|
|
54
|
+
const toHaveColor_1 = require("./matchers/toHaveColor");
|
|
51
55
|
// models
|
|
52
56
|
var DataSourcePicker_1 = require("./models/components/DataSourcePicker");
|
|
53
57
|
Object.defineProperty(exports, "DataSourcePicker", { enumerable: true, get: function () { return DataSourcePicker_1.DataSourcePicker; } });
|
|
@@ -116,6 +120,10 @@ exports.expect = test_1.expect.extend({
|
|
|
116
120
|
toHaveAlert: toHaveAlert_1.toHaveAlert,
|
|
117
121
|
toDisplayPreviews: toDisplayPreviews_1.toDisplayPreviews,
|
|
118
122
|
toBeOK: toBeOK_1.toBeOK,
|
|
123
|
+
toHaveSelected: toHaveSelected_1.toHaveSelected,
|
|
124
|
+
toBeChecked: toBeChecked_1.toBeChecked,
|
|
125
|
+
toHaveChecked: toHaveChecked_1.toHaveChecked,
|
|
126
|
+
toHaveColor: toHaveColor_1.toHaveColor,
|
|
119
127
|
});
|
|
120
128
|
var test_2 = require("@playwright/test");
|
|
121
129
|
Object.defineProperty(exports, "selectors", { enumerable: true, get: function () { return test_2.selectors; } });
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toBeChecked = toBeChecked;
|
|
4
|
+
const test_1 = require("@playwright/test");
|
|
5
|
+
const utils_1 = require("./utils");
|
|
6
|
+
const Switch_1 = require("../models/components/Switch");
|
|
7
|
+
async function toBeChecked(target, options) {
|
|
8
|
+
const expected = options?.checked ?? true;
|
|
9
|
+
try {
|
|
10
|
+
if (target instanceof Switch_1.Switch) {
|
|
11
|
+
await (0, test_1.expect)(target.locator()).toBeChecked({ ...options, checked: expected });
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
await (0, test_1.expect)(target).toBeChecked(options);
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
pass: true,
|
|
18
|
+
expected,
|
|
19
|
+
message: () => `Value successfully selected`,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
return {
|
|
24
|
+
message: () => (0, utils_1.getMessage)(expected.toString(), err instanceof Error ? err.toString() : 'Unknown error'),
|
|
25
|
+
pass: false,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toHaveChecked = toHaveChecked;
|
|
4
|
+
const test_1 = require("@playwright/test");
|
|
5
|
+
const utils_1 = require("./utils");
|
|
6
|
+
async function toHaveChecked(radioGroup, expected, options) {
|
|
7
|
+
try {
|
|
8
|
+
await (0, test_1.expect)(radioGroup.locator().getByLabel(expected)).toBeChecked(options);
|
|
9
|
+
return {
|
|
10
|
+
pass: true,
|
|
11
|
+
expected,
|
|
12
|
+
message: () => `Value successfully selected`,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
return {
|
|
17
|
+
message: () => (0, utils_1.getMessage)(expected.toString(), err instanceof Error ? err.toString() : 'Unknown error'),
|
|
18
|
+
pass: false,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toHaveColor = toHaveColor;
|
|
4
|
+
const test_1 = require("@playwright/test");
|
|
5
|
+
const utils_1 = require("./utils");
|
|
6
|
+
async function toHaveColor(colorPicker, rgbOrHex, options) {
|
|
7
|
+
try {
|
|
8
|
+
await (0, test_1.expect)(colorPicker.locator().getByRole('textbox')).toHaveValue(rgbOrHex, options);
|
|
9
|
+
return {
|
|
10
|
+
pass: true,
|
|
11
|
+
expected: rgbOrHex,
|
|
12
|
+
message: () => `Value successfully selected`,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
return {
|
|
17
|
+
message: () => (0, utils_1.getMessage)(rgbOrHex, err instanceof Error ? err.toString() : 'Unknown error'),
|
|
18
|
+
pass: false,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { MatcherReturnType } from '@playwright/test';
|
|
2
|
+
import { ContainTextOptions } from '../types';
|
|
3
|
+
import { Select } from '../models/components/Select';
|
|
4
|
+
import { MultiSelect } from '../models/components/MultiSelect';
|
|
5
|
+
import { UnitPicker } from '../models/components/UnitPicker';
|
|
6
|
+
export declare function toHaveSelected(target: Select | MultiSelect | UnitPicker, value: string | RegExp | string[] | RegExp[], options?: ContainTextOptions): Promise<MatcherReturnType>;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toHaveSelected = toHaveSelected;
|
|
4
|
+
const test_1 = require("@playwright/test");
|
|
5
|
+
const utils_1 = require("./utils");
|
|
6
|
+
const Select_1 = require("../models/components/Select");
|
|
7
|
+
const MultiSelect_1 = require("../models/components/MultiSelect");
|
|
8
|
+
const UnitPicker_1 = require("../models/components/UnitPicker");
|
|
9
|
+
async function toHaveSelected(target, value, options) {
|
|
10
|
+
if (target instanceof MultiSelect_1.MultiSelect) {
|
|
11
|
+
if (Array.isArray(value)) {
|
|
12
|
+
return expectMultiSelectToBe(target, value);
|
|
13
|
+
}
|
|
14
|
+
return expectMultiSelectToBe(target, [value]);
|
|
15
|
+
}
|
|
16
|
+
if (target instanceof Select_1.Select) {
|
|
17
|
+
if (Array.isArray(value)) {
|
|
18
|
+
throw new Error(`Select only support a single value to be selected. You are asserting that multiple values have been selected: "${value}"`);
|
|
19
|
+
}
|
|
20
|
+
return expectSelectToBe(target, value, options);
|
|
21
|
+
}
|
|
22
|
+
if (target instanceof UnitPicker_1.UnitPicker) {
|
|
23
|
+
if (Array.isArray(value)) {
|
|
24
|
+
throw new Error(`UnitPicker only support a single value to be selected. You are asserting that multiple values have been selected: "${value}"`);
|
|
25
|
+
}
|
|
26
|
+
return expectUnitPickerToBe(target, value, options);
|
|
27
|
+
}
|
|
28
|
+
throw Error('Unsupported parameters passed to "toBeSelected"');
|
|
29
|
+
}
|
|
30
|
+
async function expectSelectToBe(select, value, options) {
|
|
31
|
+
let actual = '';
|
|
32
|
+
try {
|
|
33
|
+
actual = await select.locator(select.ctx.selectors.constants.Select.singleValueContainer('')).innerText(options);
|
|
34
|
+
(0, test_1.expect)(actual).toMatch(value);
|
|
35
|
+
return {
|
|
36
|
+
pass: true,
|
|
37
|
+
actual: actual,
|
|
38
|
+
expected: value,
|
|
39
|
+
message: () => `Value successfully selected`,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
return {
|
|
44
|
+
message: () => (0, utils_1.getMessage)(value.toString(), err instanceof Error ? err.toString() : 'Unknown error'),
|
|
45
|
+
pass: false,
|
|
46
|
+
actual,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function expectMultiSelectToBe(select, values) {
|
|
51
|
+
let actual = '';
|
|
52
|
+
try {
|
|
53
|
+
const actual = await select.locator(select.ctx.selectors.constants.Select.multiValueContainer('')).allInnerTexts();
|
|
54
|
+
(0, test_1.expect)(actual).toMatchObject(values);
|
|
55
|
+
return {
|
|
56
|
+
pass: true,
|
|
57
|
+
actual: actual,
|
|
58
|
+
expected: values,
|
|
59
|
+
message: () => `Values successfully selected`,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
return {
|
|
64
|
+
message: () => (0, utils_1.getMessage)(values.join(', '), err instanceof Error ? err.toString() : 'Unknown error'),
|
|
65
|
+
pass: false,
|
|
66
|
+
actual,
|
|
67
|
+
expected: values,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async function expectUnitPickerToBe(unitPicker, value, options) {
|
|
72
|
+
let actual = '';
|
|
73
|
+
try {
|
|
74
|
+
const input = unitPicker.locator().getByRole('textbox');
|
|
75
|
+
actual = await input.inputValue(options);
|
|
76
|
+
await (0, test_1.expect)(input).toHaveValue(value);
|
|
77
|
+
return {
|
|
78
|
+
pass: true,
|
|
79
|
+
actual: actual,
|
|
80
|
+
expected: value,
|
|
81
|
+
message: () => `Value successfully selected`,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
return {
|
|
86
|
+
message: () => (0, utils_1.getMessage)(value.toString(), err instanceof Error ? err.toString() : 'Unknown error'),
|
|
87
|
+
pass: false,
|
|
88
|
+
actual,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Locator } from '@playwright/test';
|
|
2
|
+
import { PluginTestCtx } from '../../types';
|
|
3
|
+
import { ComponentBase } from './ComponentBase';
|
|
4
|
+
import { SelectOptionsType } from './types';
|
|
5
|
+
export declare class ColorPicker extends ComponentBase {
|
|
6
|
+
constructor(ctx: PluginTestCtx, element: Locator);
|
|
7
|
+
selectOption(rgbOrHex: string, options?: SelectOptionsType): Promise<void>;
|
|
8
|
+
private getContainer;
|
|
9
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ColorPicker = void 0;
|
|
4
|
+
const ComponentBase_1 = require("./ComponentBase");
|
|
5
|
+
const semver_1 = require("semver");
|
|
6
|
+
const utils_1 = require("../utils");
|
|
7
|
+
class ColorPicker extends ComponentBase_1.ComponentBase {
|
|
8
|
+
constructor(ctx, element) {
|
|
9
|
+
super(ctx, element);
|
|
10
|
+
}
|
|
11
|
+
async selectOption(rgbOrHex, options) {
|
|
12
|
+
await this.element.getByRole('button').click(options);
|
|
13
|
+
await this.getContainer().getByRole('button', { name: 'Custom', exact: true }).click(options);
|
|
14
|
+
const colorInput = this.getContainer().getByTestId('input-wrapper').getByRole('textbox');
|
|
15
|
+
await colorInput.hover(options);
|
|
16
|
+
await colorInput.fill(rgbOrHex, options);
|
|
17
|
+
}
|
|
18
|
+
getContainer() {
|
|
19
|
+
const { grafanaVersion, page, selectors } = this.ctx;
|
|
20
|
+
if ((0, semver_1.gte)(grafanaVersion, '11.4.1')) {
|
|
21
|
+
return page.locator((0, utils_1.resolveGrafanaSelector)(selectors.components.Portal.container));
|
|
22
|
+
}
|
|
23
|
+
if ((0, semver_1.gte)(grafanaVersion, '8.7.0')) {
|
|
24
|
+
return page.locator('#grafana-portal-container');
|
|
25
|
+
}
|
|
26
|
+
return page.locator('body > div').last();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.ColorPicker = ColorPicker;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Locator } from '@playwright/test';
|
|
2
|
+
import { PluginTestCtx } from '../../types';
|
|
3
|
+
type LocatorParams = Parameters<Locator['locator']>;
|
|
4
|
+
export declare abstract class ComponentBase {
|
|
5
|
+
readonly ctx: PluginTestCtx;
|
|
6
|
+
protected readonly element: Locator;
|
|
7
|
+
constructor(ctx: PluginTestCtx, element: Locator);
|
|
8
|
+
locator(selectorOrLocator?: LocatorParams[0], options?: LocatorParams[1]): Locator;
|
|
9
|
+
}
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ComponentBase = void 0;
|
|
4
|
+
class ComponentBase {
|
|
5
|
+
ctx;
|
|
6
|
+
element;
|
|
7
|
+
constructor(ctx, element) {
|
|
8
|
+
this.ctx = ctx;
|
|
9
|
+
this.element = element;
|
|
10
|
+
}
|
|
11
|
+
locator(selectorOrLocator, options) {
|
|
12
|
+
if (!selectorOrLocator) {
|
|
13
|
+
return this.element;
|
|
14
|
+
}
|
|
15
|
+
return this.element.locator(selectorOrLocator, options);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.ComponentBase = ComponentBase;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Locator } from '@playwright/test';
|
|
2
|
+
import { ComponentBase } from './ComponentBase';
|
|
3
|
+
import { SelectOptionsType } from './types';
|
|
4
|
+
import { PluginTestCtx } from '../../types';
|
|
5
|
+
export declare class MultiSelect extends ComponentBase {
|
|
6
|
+
constructor(ctx: PluginTestCtx, element: Locator);
|
|
7
|
+
selectOptions(values: string[], options?: SelectOptionsType): Promise<string[]>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MultiSelect = void 0;
|
|
4
|
+
const Select_1 = require("./Select");
|
|
5
|
+
const ComponentBase_1 = require("./ComponentBase");
|
|
6
|
+
class MultiSelect extends ComponentBase_1.ComponentBase {
|
|
7
|
+
constructor(ctx, element) {
|
|
8
|
+
super(ctx, element);
|
|
9
|
+
}
|
|
10
|
+
async selectOptions(values, options) {
|
|
11
|
+
const menu = await (0, Select_1.openSelect)(this, options);
|
|
12
|
+
return Promise.all(values.map((value) => {
|
|
13
|
+
return (0, Select_1.selectByValueOrLabel)(value, menu, this.ctx, options);
|
|
14
|
+
}));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.MultiSelect = MultiSelect;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Locator } from '@playwright/test';
|
|
2
|
+
import { PluginTestCtx } from '../../types';
|
|
3
|
+
import { ColorPicker } from './ColorPicker';
|
|
4
|
+
import { UnitPicker } from './UnitPicker';
|
|
5
|
+
import { Select } from './Select';
|
|
6
|
+
import { MultiSelect } from './MultiSelect';
|
|
7
|
+
import { Switch } from './Switch';
|
|
8
|
+
import { RadioGroup } from './RadioGroup';
|
|
9
|
+
export declare class PanelEditOptionsGroup {
|
|
10
|
+
private ctx;
|
|
11
|
+
readonly element: Locator;
|
|
12
|
+
private groupLabel;
|
|
13
|
+
constructor(ctx: PluginTestCtx, element: Locator, groupLabel: string);
|
|
14
|
+
getRadioGroup(label: string): RadioGroup;
|
|
15
|
+
getSwitch(label: string): Switch;
|
|
16
|
+
getTextInput(label: string): Locator;
|
|
17
|
+
getNumberInput(label: string): Locator;
|
|
18
|
+
getSliderInput(label: string): Locator;
|
|
19
|
+
getSelect(label: string): Select;
|
|
20
|
+
getMultiSelect(label: string): MultiSelect;
|
|
21
|
+
getColorPicker(label: string): ColorPicker;
|
|
22
|
+
getUnitPicker(label: string): UnitPicker;
|
|
23
|
+
private getByLabel;
|
|
24
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PanelEditOptionsGroup = void 0;
|
|
4
|
+
const ColorPicker_1 = require("./ColorPicker");
|
|
5
|
+
const UnitPicker_1 = require("./UnitPicker");
|
|
6
|
+
const Select_1 = require("./Select");
|
|
7
|
+
const MultiSelect_1 = require("./MultiSelect");
|
|
8
|
+
const Switch_1 = require("./Switch");
|
|
9
|
+
const semver_1 = require("semver");
|
|
10
|
+
const RadioGroup_1 = require("./RadioGroup");
|
|
11
|
+
class PanelEditOptionsGroup {
|
|
12
|
+
ctx;
|
|
13
|
+
element;
|
|
14
|
+
groupLabel;
|
|
15
|
+
constructor(ctx, element, groupLabel) {
|
|
16
|
+
this.ctx = ctx;
|
|
17
|
+
this.element = element;
|
|
18
|
+
this.groupLabel = groupLabel;
|
|
19
|
+
}
|
|
20
|
+
getRadioGroup(label) {
|
|
21
|
+
if ((0, semver_1.gte)(this.ctx.grafanaVersion, '10.2.0')) {
|
|
22
|
+
return new RadioGroup_1.RadioGroup(this.ctx, this.getByLabel(label).getByRole('radiogroup'));
|
|
23
|
+
}
|
|
24
|
+
return new RadioGroup_1.RadioGroup(this.ctx, this.getByLabel(label));
|
|
25
|
+
}
|
|
26
|
+
getSwitch(label) {
|
|
27
|
+
return new Switch_1.Switch(this.ctx, this.getByLabel(label));
|
|
28
|
+
}
|
|
29
|
+
getTextInput(label) {
|
|
30
|
+
return this.getByLabel(label).getByRole('textbox');
|
|
31
|
+
}
|
|
32
|
+
getNumberInput(label) {
|
|
33
|
+
return this.getByLabel(label).getByRole('spinbutton');
|
|
34
|
+
}
|
|
35
|
+
getSliderInput(label) {
|
|
36
|
+
if ((0, semver_1.gte)(this.ctx.grafanaVersion, '9.1.0')) {
|
|
37
|
+
return this.getNumberInput(label);
|
|
38
|
+
}
|
|
39
|
+
return this.getByLabel(label).getByRole('textbox');
|
|
40
|
+
}
|
|
41
|
+
getSelect(label) {
|
|
42
|
+
return new Select_1.Select(this.ctx, this.getByLabel(label));
|
|
43
|
+
}
|
|
44
|
+
getMultiSelect(label) {
|
|
45
|
+
return new MultiSelect_1.MultiSelect(this.ctx, this.getByLabel(label));
|
|
46
|
+
}
|
|
47
|
+
getColorPicker(label) {
|
|
48
|
+
return new ColorPicker_1.ColorPicker(this.ctx, this.getByLabel(label));
|
|
49
|
+
}
|
|
50
|
+
getUnitPicker(label) {
|
|
51
|
+
return new UnitPicker_1.UnitPicker(this.ctx, this.getByLabel(label));
|
|
52
|
+
}
|
|
53
|
+
getByLabel(optionLabel) {
|
|
54
|
+
return this.element.getByLabel(`${this.groupLabel} ${optionLabel} field property editor`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.PanelEditOptionsGroup = PanelEditOptionsGroup;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Locator } from '@playwright/test';
|
|
2
|
+
import { ComponentBase } from './ComponentBase';
|
|
3
|
+
import { CheckOptionsType } from './types';
|
|
4
|
+
import { PluginTestCtx } from '../../types';
|
|
5
|
+
export declare class RadioGroup extends ComponentBase {
|
|
6
|
+
constructor(ctx: PluginTestCtx, element: Locator);
|
|
7
|
+
check(labelOrValue: string, options?: CheckOptionsType): Promise<void>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RadioGroup = void 0;
|
|
4
|
+
const ComponentBase_1 = require("./ComponentBase");
|
|
5
|
+
const semver_1 = require("semver");
|
|
6
|
+
class RadioGroup extends ComponentBase_1.ComponentBase {
|
|
7
|
+
constructor(ctx, element) {
|
|
8
|
+
super(ctx, element);
|
|
9
|
+
}
|
|
10
|
+
async check(labelOrValue, options) {
|
|
11
|
+
if ((0, semver_1.gte)(this.ctx.grafanaVersion, '10.2.0')) {
|
|
12
|
+
return this.element.getByLabel(labelOrValue, { exact: true }).check(options);
|
|
13
|
+
}
|
|
14
|
+
return this.element.getByText(labelOrValue, { exact: true }).check(options);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.RadioGroup = RadioGroup;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Locator } from '@playwright/test';
|
|
2
|
+
import { ComponentBase } from './ComponentBase';
|
|
3
|
+
import { SelectOptionsType } from './types';
|
|
4
|
+
import { PluginTestCtx } from '../../types';
|
|
5
|
+
export declare class Select extends ComponentBase {
|
|
6
|
+
constructor(ctx: PluginTestCtx, element: Locator);
|
|
7
|
+
selectOption(values: string, options?: SelectOptionsType): Promise<string>;
|
|
8
|
+
}
|
|
9
|
+
export declare function openSelect(component: ComponentBase, options?: SelectOptionsType): Promise<Locator>;
|
|
10
|
+
export declare function selectByValueOrLabel(labelOrValue: string, menu: Locator, ctx: PluginTestCtx, options?: SelectOptionsType): Promise<string>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Select = void 0;
|
|
4
|
+
exports.openSelect = openSelect;
|
|
5
|
+
exports.selectByValueOrLabel = selectByValueOrLabel;
|
|
6
|
+
const ComponentBase_1 = require("./ComponentBase");
|
|
7
|
+
const semver_1 = require("semver");
|
|
8
|
+
const utils_1 = require("../utils");
|
|
9
|
+
class Select extends ComponentBase_1.ComponentBase {
|
|
10
|
+
constructor(ctx, element) {
|
|
11
|
+
super(ctx, element);
|
|
12
|
+
}
|
|
13
|
+
async selectOption(values, options) {
|
|
14
|
+
const menu = await openSelect(this, options);
|
|
15
|
+
return selectByValueOrLabel(values, menu, this.ctx, options);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.Select = Select;
|
|
19
|
+
async function openSelect(component, options) {
|
|
20
|
+
const element = component.locator();
|
|
21
|
+
const selectors = component.ctx.selectors;
|
|
22
|
+
await element.getByRole('combobox').click(options);
|
|
23
|
+
return element.page().locator((0, utils_1.resolveGrafanaSelector)(selectors.components.Select.menu));
|
|
24
|
+
}
|
|
25
|
+
async function selectByValueOrLabel(labelOrValue, menu, ctx, options) {
|
|
26
|
+
const option = getOption(menu, ctx).getByText(labelOrValue, { exact: true });
|
|
27
|
+
const value = await option.textContent(options);
|
|
28
|
+
await option.click(options);
|
|
29
|
+
if (!value) {
|
|
30
|
+
throw new Error(`Could not select option: "${labelOrValue}"`);
|
|
31
|
+
}
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
function getOption(menu, ctx) {
|
|
35
|
+
if ((0, semver_1.gte)(ctx.grafanaVersion, '11.0.0')) {
|
|
36
|
+
return menu.getByRole('option');
|
|
37
|
+
}
|
|
38
|
+
return menu.getByLabel('Select option');
|
|
39
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Locator } from '@playwright/test';
|
|
2
|
+
import { ComponentBase } from './ComponentBase';
|
|
3
|
+
import { CheckOptionsType } from './types';
|
|
4
|
+
import { PluginTestCtx } from '../../types';
|
|
5
|
+
export declare class Switch extends ComponentBase {
|
|
6
|
+
private group;
|
|
7
|
+
constructor(ctx: PluginTestCtx, group: Locator);
|
|
8
|
+
private static getElement;
|
|
9
|
+
check(options?: CheckOptionsType): Promise<void>;
|
|
10
|
+
uncheck(options?: CheckOptionsType): Promise<void>;
|
|
11
|
+
private getSwitch;
|
|
12
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Switch = void 0;
|
|
4
|
+
const ComponentBase_1 = require("./ComponentBase");
|
|
5
|
+
const semver_1 = require("semver");
|
|
6
|
+
class Switch extends ComponentBase_1.ComponentBase {
|
|
7
|
+
group;
|
|
8
|
+
constructor(ctx, group) {
|
|
9
|
+
super(ctx, Switch.getElement(ctx, group));
|
|
10
|
+
this.group = group;
|
|
11
|
+
}
|
|
12
|
+
static getElement(ctx, group) {
|
|
13
|
+
if ((0, semver_1.gte)(ctx.grafanaVersion, '11.5.0')) {
|
|
14
|
+
return group.getByRole('switch');
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
return group.getByRole('checkbox');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async check(options) {
|
|
21
|
+
const target = await this.getSwitch(options);
|
|
22
|
+
return target.check({ force: true, ...options });
|
|
23
|
+
}
|
|
24
|
+
async uncheck(options) {
|
|
25
|
+
const target = await this.getSwitch(options);
|
|
26
|
+
return target.uncheck({ force: true, ...options });
|
|
27
|
+
}
|
|
28
|
+
async getSwitch(options) {
|
|
29
|
+
if ((0, semver_1.lt)(this.ctx.grafanaVersion, '11.3.0')) {
|
|
30
|
+
const id = await this.element.getAttribute('id', options);
|
|
31
|
+
return this.group.locator(`label[for='${id}']`);
|
|
32
|
+
}
|
|
33
|
+
return this.element;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.Switch = Switch;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Locator } from '@playwright/test';
|
|
2
|
+
import { PluginTestCtx } from '../../types';
|
|
3
|
+
import { SelectOptionsType } from './types';
|
|
4
|
+
import { ComponentBase } from './ComponentBase';
|
|
5
|
+
export declare class UnitPicker extends ComponentBase {
|
|
6
|
+
constructor(ctx: PluginTestCtx, element: Locator);
|
|
7
|
+
selectOption(value: string, options?: SelectOptionsType): Promise<void>;
|
|
8
|
+
private getOption;
|
|
9
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UnitPicker = void 0;
|
|
4
|
+
const ComponentBase_1 = require("./ComponentBase");
|
|
5
|
+
class UnitPicker extends ComponentBase_1.ComponentBase {
|
|
6
|
+
constructor(ctx, element) {
|
|
7
|
+
super(ctx, element);
|
|
8
|
+
}
|
|
9
|
+
async selectOption(value, options) {
|
|
10
|
+
await this.element.getByRole('textbox').click();
|
|
11
|
+
const option = await this.getOption(value, options);
|
|
12
|
+
await option.click(options);
|
|
13
|
+
}
|
|
14
|
+
async getOption(selector, options) {
|
|
15
|
+
const steps = selector.split('>').map((step) => step.trim());
|
|
16
|
+
const container = this.ctx.page.locator(this.ctx.selectors.constants.Cascader.menu(''));
|
|
17
|
+
if (steps.length === 0) {
|
|
18
|
+
throw new Error(`Could not find options from passed selector: ${selector}`);
|
|
19
|
+
}
|
|
20
|
+
const last = steps.pop();
|
|
21
|
+
for (const step of steps) {
|
|
22
|
+
await container.getByTitle(step, { exact: true }).click(options);
|
|
23
|
+
}
|
|
24
|
+
return container.getByRole('menuitemcheckbox', { exact: true, name: last });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.UnitPicker = UnitPicker;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.GrafanaPage = void 0;
|
|
4
|
+
const utils_1 = require("../utils");
|
|
4
5
|
/**
|
|
5
6
|
* Base class for all Grafana pages.
|
|
6
7
|
*
|
|
@@ -29,11 +30,7 @@ class GrafanaPage {
|
|
|
29
30
|
* An E2E selector is a string that identifies a specific element in the Grafana UI. The element referencing the E2E selector use the data-testid or aria-label attribute.
|
|
30
31
|
*/
|
|
31
32
|
getByGrafanaSelector(selector, options) {
|
|
32
|
-
|
|
33
|
-
if (selector.startsWith('data-testid')) {
|
|
34
|
-
return (options?.root || this.ctx.page).locator(`[data-testid${startsWith}="${selector}"]`);
|
|
35
|
-
}
|
|
36
|
-
return (options?.root || this.ctx.page).locator(`[aria-label${startsWith}="${selector}"]`);
|
|
33
|
+
return (options?.root ?? this.ctx.page).locator((0, utils_1.resolveGrafanaSelector)(selector, options));
|
|
37
34
|
}
|
|
38
35
|
/**
|
|
39
36
|
* Mocks the response of the datasource query call
|
|
@@ -5,6 +5,7 @@ import { GrafanaPage } from './GrafanaPage';
|
|
|
5
5
|
import { TimeRange } from '../components/TimeRange';
|
|
6
6
|
import { Panel } from '../components/Panel';
|
|
7
7
|
import { DashboardPage } from './DashboardPage';
|
|
8
|
+
import { PanelEditOptionsGroup } from '../components/PanelEditOptionsGroup';
|
|
8
9
|
export declare class PanelEditPage extends GrafanaPage {
|
|
9
10
|
readonly ctx: PluginTestCtx;
|
|
10
11
|
readonly args: DashboardEditViewArgs<string>;
|
|
@@ -63,4 +64,11 @@ export declare class PanelEditPage extends GrafanaPage {
|
|
|
63
64
|
})
|
|
64
65
|
*/
|
|
65
66
|
refreshPanel(options?: RequestOptions): Promise<Response>;
|
|
67
|
+
/** Return page object for the panel edit options group with the given label */
|
|
68
|
+
getCustomOptions(label: string): PanelEditOptionsGroup;
|
|
69
|
+
getStandardOptions(): PanelEditOptionsGroup;
|
|
70
|
+
getValueMappingOptions(): PanelEditOptionsGroup;
|
|
71
|
+
getDataLinksOptions(): PanelEditOptionsGroup;
|
|
72
|
+
getThresholdsOptions(): PanelEditOptionsGroup;
|
|
73
|
+
private getOptionsGroupLocator;
|
|
66
74
|
}
|
|
@@ -32,6 +32,7 @@ const TimeRange_1 = require("../components/TimeRange");
|
|
|
32
32
|
const Panel_1 = require("../components/Panel");
|
|
33
33
|
const utils_1 = require("../utils");
|
|
34
34
|
const DashboardPage_1 = require("./DashboardPage");
|
|
35
|
+
const PanelEditOptionsGroup_1 = require("../components/PanelEditOptionsGroup");
|
|
35
36
|
class PanelEditPage extends GrafanaPage_1.GrafanaPage {
|
|
36
37
|
ctx;
|
|
37
38
|
args;
|
|
@@ -99,7 +100,6 @@ class PanelEditPage extends GrafanaPage_1.GrafanaPage {
|
|
|
99
100
|
* Sets the visualization for the panel. This method will open the visualization picker, select the given visualization
|
|
100
101
|
*/
|
|
101
102
|
async setVisualization(visualization) {
|
|
102
|
-
// toggle options pane if panel edit is not visible
|
|
103
103
|
const showPanelEditElement = this.getByGrafanaSelector('Show options pane');
|
|
104
104
|
const showPanelEditElementCount = await showPanelEditElement.count();
|
|
105
105
|
if (showPanelEditElementCount > 0) {
|
|
@@ -178,5 +178,26 @@ class PanelEditPage extends GrafanaPage_1.GrafanaPage {
|
|
|
178
178
|
await refreshPanelButton.click();
|
|
179
179
|
return responsePromise;
|
|
180
180
|
}
|
|
181
|
+
/** Return page object for the panel edit options group with the given label */
|
|
182
|
+
getCustomOptions(label) {
|
|
183
|
+
const locator = this.getOptionsGroupLocator(label);
|
|
184
|
+
return new PanelEditOptionsGroup_1.PanelEditOptionsGroup(this.ctx, locator, label);
|
|
185
|
+
}
|
|
186
|
+
getStandardOptions() {
|
|
187
|
+
return this.getCustomOptions('Standard options');
|
|
188
|
+
}
|
|
189
|
+
getValueMappingOptions() {
|
|
190
|
+
return this.getCustomOptions('Value mappings');
|
|
191
|
+
}
|
|
192
|
+
getDataLinksOptions() {
|
|
193
|
+
return this.getCustomOptions('Data links');
|
|
194
|
+
}
|
|
195
|
+
getThresholdsOptions() {
|
|
196
|
+
return this.getCustomOptions('Thresholds');
|
|
197
|
+
}
|
|
198
|
+
getOptionsGroupLocator(label) {
|
|
199
|
+
const { selectors } = this.ctx;
|
|
200
|
+
return this.getByGrafanaSelector(selectors.components.OptionsGroup.group(label));
|
|
201
|
+
}
|
|
181
202
|
}
|
|
182
203
|
exports.PanelEditPage = PanelEditPage;
|
package/dist/models/utils.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Page } from '@playwright/test';
|
|
2
|
+
import { getByGrafanaSelectorOptions } from '../types';
|
|
2
3
|
export declare const radioButtonSetChecked: (page: Page, label: string, checked: boolean, options?: {
|
|
3
4
|
exact?: boolean;
|
|
4
5
|
}) => Promise<void>;
|
|
6
|
+
export declare function resolveGrafanaSelector(selector: string, options?: Omit<getByGrafanaSelectorOptions, 'root'>): string;
|
package/dist/models/utils.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.radioButtonSetChecked = void 0;
|
|
4
|
+
exports.resolveGrafanaSelector = resolveGrafanaSelector;
|
|
4
5
|
const radioButtonSetChecked = async (page, label, checked, options) => {
|
|
5
6
|
try {
|
|
6
7
|
await page.getByLabel(label, options).setChecked(checked, { timeout: 1000 });
|
|
@@ -10,3 +11,10 @@ const radioButtonSetChecked = async (page, label, checked, options) => {
|
|
|
10
11
|
}
|
|
11
12
|
};
|
|
12
13
|
exports.radioButtonSetChecked = radioButtonSetChecked;
|
|
14
|
+
function resolveGrafanaSelector(selector, options) {
|
|
15
|
+
const startsWith = options?.startsWith ? '^' : '';
|
|
16
|
+
if (selector.startsWith('data-testid')) {
|
|
17
|
+
return `[data-testid${startsWith}="${selector}"]`;
|
|
18
|
+
}
|
|
19
|
+
return `[aria-label${startsWith}="${selector}"]`;
|
|
20
|
+
}
|
|
@@ -5,5 +5,18 @@ export declare const versionedConstants: {
|
|
|
5
5
|
"8.0.0": string;
|
|
6
6
|
};
|
|
7
7
|
};
|
|
8
|
+
Select: {
|
|
9
|
+
singleValueContainer: {
|
|
10
|
+
"8.0.0": () => string;
|
|
11
|
+
};
|
|
12
|
+
multiValueContainer: {
|
|
13
|
+
"8.0.0": () => string;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
Cascader: {
|
|
17
|
+
menu: {
|
|
18
|
+
"8.0.0": () => string;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
8
21
|
};
|
|
9
22
|
export type VersionedConstants = typeof versionedConstants;
|
|
@@ -9,4 +9,17 @@ exports.versionedConstants = {
|
|
|
9
9
|
[minGrafanaVersion_1.MIN_GRAFANA_VERSION]: 'Add panel button',
|
|
10
10
|
},
|
|
11
11
|
},
|
|
12
|
+
Select: {
|
|
13
|
+
singleValueContainer: {
|
|
14
|
+
[minGrafanaVersion_1.MIN_GRAFANA_VERSION]: () => 'div[class*="-grafana-select-value-container"] > div[class*="-singleValue"]',
|
|
15
|
+
},
|
|
16
|
+
multiValueContainer: {
|
|
17
|
+
[minGrafanaVersion_1.MIN_GRAFANA_VERSION]: () => 'div[class*="-grafana-select-multi-value-container"] > div',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
Cascader: {
|
|
21
|
+
menu: {
|
|
22
|
+
[minGrafanaVersion_1.MIN_GRAFANA_VERSION]: () => 'div[class="rc-cascader-menus"]',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
12
25
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grafana/plugin-e2e",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.0-canary.1272.059bc30.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -57,5 +57,5 @@
|
|
|
57
57
|
"start": "cls || clear"
|
|
58
58
|
}
|
|
59
59
|
},
|
|
60
|
-
"gitHead": "
|
|
60
|
+
"gitHead": "059bc3077b626742df226a7a19afa22277d0653c"
|
|
61
61
|
}
|