Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/plugin-e2e/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,16 @@ import { DashboardPage } from './models/pages/DashboardPage';

// models
export { Components } from './models/Components';
export { ColorPicker } from './models/components/ColorPicker';
export { DataSourcePicker } from './models/components/DataSourcePicker';
export { MultiSelect } from './models/components/MultiSelect';
export { RadioGroup } from './models/components/RadioGroup';
export { ScopedComponent } from './models/components/ScopedComponent';
export { Select } from './models/components/Select';
export { Switch } from './models/components/Switch';
export { Panel } from './models/components/Panel';
export { TimeRange } from './models/components/TimeRange';
export { UnitPicker } from './models/components/UnitPicker';
export { AnnotationEditPage } from './models/pages/AnnotationEditPage';
export { AnnotationPage } from './models/pages/AnnotationPage';
export { DashboardPage } from './models/pages/DashboardPage';
Expand Down
20 changes: 20 additions & 0 deletions packages/plugin-e2e/src/models/Components.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { PluginTestCtx } from '../types';
import { ColorPicker } from './components/ColorPicker';
import { DataSourcePicker } from './components/DataSourcePicker';
import { MultiSelect } from './components/MultiSelect';
import { RadioGroup } from './components/RadioGroup';
import { Select } from './components/Select';
import { Switch } from './components/Switch';
import { TimeRange } from './components/TimeRange';
import { UnitPicker } from './components/UnitPicker';

/**
* Factory for components that are not attached to a specific page.
Expand All @@ -15,14 +21,28 @@ import { TimeRange } from './components/TimeRange';
* ```typescript
* await components.dataSourcePicker.set('prom');
* await components.dataSourcePicker.within(panel).set('prom');
* await components.select.within(fieldLabel).selectOption('Europe/Stockholm');
* await components.switch.within(fieldLabel).check();
* ```
*/
export class Components {
readonly dataSourcePicker: DataSourcePicker;
readonly timeRangePicker: TimeRange;
readonly select: Select;
readonly multiSelect: MultiSelect;
readonly switch: Switch;
readonly radioGroup: RadioGroup;
readonly unitPicker: UnitPicker;
readonly colorPicker: ColorPicker;

constructor(ctx: PluginTestCtx) {
this.dataSourcePicker = new DataSourcePicker(ctx);
this.timeRangePicker = new TimeRange(ctx);
this.select = new Select(ctx, Select.getContainer(ctx));
this.multiSelect = new MultiSelect(ctx, MultiSelect.getContainer(ctx));
this.switch = new Switch(ctx, Switch.getContainer(ctx));
this.radioGroup = new RadioGroup(ctx, RadioGroup.getContainer(ctx));
this.unitPicker = new UnitPicker(ctx, UnitPicker.getContainer(ctx));
this.colorPicker = new ColorPicker(ctx, ColorPicker.getContainer(ctx));
Comment on lines 29 to +46
}
}
9 changes: 9 additions & 0 deletions packages/plugin-e2e/src/models/components/ColorPicker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ export class ColorPicker extends ComponentBase {
super(ctx, element);
}

static getContainer(ctx: PluginTestCtx, root?: Locator): Locator {
const base = root ?? ctx.page;
return base.locator('[data-testid*="colorswatch"]');
}

within(root: Locator): ColorPicker {
return new ColorPicker(this.ctx, ColorPicker.getContainer(this.ctx, root));
}

async selectOption(rgbOrHex: string, options?: SelectOptionsType): Promise<void> {
await this.element.getByRole('button').click(options);
await this.getCustomTab().click(options);
Comment on lines +13 to 24
Expand Down
9 changes: 9 additions & 0 deletions packages/plugin-e2e/src/models/components/MultiSelect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ export class MultiSelect extends ComponentBase {
super(ctx, element);
}

static getContainer(ctx: PluginTestCtx, root?: Locator): Locator {
const base = root ?? ctx.page;
return base.locator('[class*="-grafana-select-value-container-multi"]');
}

within(root: Locator): MultiSelect {
return new MultiSelect(this.ctx, MultiSelect.getContainer(this.ctx, root));
}
Comment on lines +17 to +19

async selectOptions(values: string[], options?: SelectOptionsType): Promise<string[]> {
const menu = await openSelect(this, options);

Expand Down
12 changes: 12 additions & 0 deletions packages/plugin-e2e/src/models/components/RadioGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@ export class RadioGroup extends ComponentBase {
super(ctx, element);
}

static getContainer(ctx: PluginTestCtx, root?: Locator): Locator {
const base = root ?? ctx.page;
if (gte(ctx.grafanaVersion, '10.0.0')) {
return base.locator('[role="radiogroup"]');
}
return base.locator('div:has(> div > input[type="radio"][name^="radiogroup-"])');
}

within(root: Locator): RadioGroup {
return new RadioGroup(this.ctx, RadioGroup.getContainer(this.ctx, root));
}

async check(labelOrValue: string, options?: CheckOptionsType): Promise<void> {
if (gte(this.ctx.grafanaVersion, '10.2.0')) {
return this.element.getByLabel(labelOrValue, { exact: true }).check(options);
Expand Down
12 changes: 12 additions & 0 deletions packages/plugin-e2e/src/models/components/Select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@ export class Select extends ComponentBase {
super(ctx, element);
}

static getContainer(ctx: PluginTestCtx, root?: Locator): Locator {
const base = root ?? ctx.page;
// TODO: add data-testid branch for >= 13.1.0 once @grafana/e2e-selectors is updated
return base.locator(
'[class*="-grafana-select-value-container"]:not([class*="-grafana-select-value-container-multi"])'
);
Comment on lines +15 to +17
}

within(root: Locator): Select {
return new Select(this.ctx, Select.getContainer(this.ctx, root));
}

async selectOption(values: string, options?: SelectOptionsType): Promise<string> {
const menu = await openSelect(this, options);
// type into whichever input gained focus when the select opened - handles virtualized
Expand Down
12 changes: 12 additions & 0 deletions packages/plugin-e2e/src/models/components/Switch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ export class Switch extends ComponentBase {
this.group = group;
}

static getContainer(ctx: PluginTestCtx, root?: Locator): Locator {
const base = root ?? ctx.page;
if (gte(ctx.grafanaVersion, '12.0.0')) {
return base.locator('div:has(> input[type="checkbox"][role="switch"])');
}
return base.locator('div:has(> input[type="checkbox"] + label)');
}

within(root: Locator): Switch {
return new Switch(this.ctx, Switch.getContainer(this.ctx, root));
}

private static getElement(ctx: PluginTestCtx, group: Locator): Locator {
if (gte(ctx.grafanaVersion, '11.5.0')) {
return group.getByRole('switch');
Expand Down
9 changes: 9 additions & 0 deletions packages/plugin-e2e/src/models/components/UnitPicker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ export class UnitPicker extends ComponentBase {
super(ctx, element);
}

static getContainer(ctx: PluginTestCtx, root?: Locator): Locator {
const base = root ?? ctx.page;
return base.locator('div:has(> div > [data-testid="input-wrapper"] input[placeholder="Choose"])');
}

within(root: Locator): UnitPicker {
return new UnitPicker(this.ctx, UnitPicker.getContainer(this.ctx, root));
}

async selectOption(value: string, options?: SelectOptionsType): Promise<void> {
await this.element.getByRole('textbox').click();
const option = await this.getOption(value, options);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { expect, test } from '../../../src';

/**
* DataSourcePicker
*/

test('components.dataSourcePicker should set the data source', async ({
panelEditPage,
components,
Expand All @@ -22,6 +26,10 @@ test('components.dataSourcePicker.within should set the data source when scoped
await expect(panelEditPage.getQueryEditorRow('A').getByRole('textbox', { name: 'Query Text' })).toBeVisible();
});

/**
* TimeRangePicker
*/

test('components.timeRangePicker should set the time range', async ({
panelEditPage,
components,
Expand All @@ -45,3 +53,87 @@ test('components.timeRangePicker.within should set the time range when scoped to
const openButton = dashboardPage.getByGrafanaSelector(selectors.components.TimePicker.openButton).first();
await expect(openButton).toContainText('2020-01-01 00:00:00');
});

/**
* Select
*/

test('components.select.within should select a value in a single-value select', async ({
gotoPanelEditPage,
components,
selectors,
}) => {
const panelEdit = await gotoPanelEditPage({ dashboard: { uid: 'mxb-Jv4Vk' }, id: '5' });
const root = panelEdit.getByGrafanaSelector(
selectors.components.PanelEditor.OptionsPane.fieldLabel('Timezone Timezone')
);
await components.select.within(root).selectOption('Europe/Stockholm');
await expect(components.select.within(root)).toHaveSelected('Europe/Stockholm');
});

/**
* Switch
*/

test('components.switch.within should check a switch', async ({
gotoPanelEditPage,
components,
selectors,
}) => {
const panelEdit = await gotoPanelEditPage({ dashboard: { uid: 'mxb-Jv4Vk' }, id: '5' });
const root = panelEdit.getByGrafanaSelector(
selectors.components.PanelEditor.OptionsPane.fieldLabel('Clock Font monospace')
);
await components.switch.within(root).check();
await expect(components.switch.within(root)).toBeChecked();
});

/**
* RadioGroup
*/

test('components.radioGroup.within should check a radio option', async ({
gotoPanelEditPage,
components,
selectors,
}) => {
const panelEdit = await gotoPanelEditPage({ dashboard: { uid: 'mxb-Jv4Vk' }, id: '5' });
const root = panelEdit.getByGrafanaSelector(
selectors.components.PanelEditor.OptionsPane.fieldLabel('Clock Mode')
);
await components.radioGroup.within(root).check('Countdown');
await expect(components.radioGroup.within(root)).toHaveChecked('Countdown');
});

/**
* ColorPicker
*/

test('components.colorPicker.within should select a color', async ({
gotoPanelEditPage,
components,
selectors,
}) => {
const panelEdit = await gotoPanelEditPage({ dashboard: { uid: 'mxb-Jv4Vk' }, id: '3' });
const root = panelEdit.getByGrafanaSelector(
selectors.components.PanelEditor.OptionsPane.fieldLabel('Clock Background Color')
);
await components.colorPicker.within(root).selectOption('#73bf69');
await expect(components.colorPicker.within(root)).toHaveColor('#73bf69');
});

/**
* UnitPicker
*/

test('components.unitPicker.within should select a unit', async ({
gotoPanelEditPage,
components,
selectors,
}) => {
const panelEdit = await gotoPanelEditPage({ dashboard: { uid: 'be6sir7o1iccgb' }, id: '1' });
const root = panelEdit.getByGrafanaSelector(
selectors.components.PanelEditor.OptionsPane.fieldLabel('Standard options Unit')
);
await components.unitPicker.within(root).selectOption('Misc > Pixels');
});
Loading