Files
grafana/e2e-playwright/various-suite/grafana-datasource-random-walk.spec.ts
Nathan Marrs 8263803e81 Grafana Data Source: Add random walk configuration options (#113009)
* Grafana: Add random walk configuration options to Grafana datasource

Add UI controls to configure random walk parameters (min, max, start value,
spread, noise, drop percent) to match TestData datasource functionality.

- Add RandomWalkEditor component with inline number inputs for all parameters
- Update GrafanaQuery type to include random walk configuration fields
- Update backend to parse and apply query parameters to RandomWalk function
- Configuration options match TestData datasource UX for consistency

* Grafana: Add series count support to random walk

Add ability to generate multiple random walk series in a single query
for complete parity with TestData datasource.

- Add seriesCount field to RandomWalkEditor
- Update backend to loop and generate multiple frames based on series count
- Default to 1 series if not specified for backward compatibility

* Grafana: Improve random walk editor UI with better organization and tooltips

Enhance the random walk configuration UI for better usability:

- Organize fields into two logical rows (core config vs fine-tuning)
- Add helpful tooltips to all fields explaining their purpose
- Increase label width to prevent text wrapping
- Group related fields visually for better comprehension

Row 1: Series count, Start value, Min, Max (basic shape and range)
Row 2: Spread, Noise, Drop % (randomness and variation controls)

This provides a cleaner, more intuitive experience compared to TestData's
single-row layout, making it easier for users to configure random walks.

* Grafana: Format RandomWalkEditor code

Apply consistent formatting to RandomWalkEditor component.

* Grafana: Add E2E tests for random walk configuration

Add comprehensive Playwright E2E tests to verify random walk functionality:

- Test that all configuration fields render correctly
- Test min/max value constraints
- Test multiple series generation
- Test spread and noise parameters
- Test drop percentage for simulating missing data
- Test that tooltips are present and functional

These tests ensure the random walk configuration works end-to-end from
UI input to data rendering in panels.

* Grafana: Fix E2E tests for random walk configuration

Fix Playwright test selectors and assertions to work reliably:

- Use specific element IDs to avoid selector conflicts
- Remove flaky dropPercent check from rendering test (covered separately)
- Simplify test assertions to focus on functional verification
- All 7 tests now passing consistently

Tests verify: field rendering, min/max constraints, series count,
spread/noise configuration, drop percentage, and tooltips.

* Grafana: Add advanced E2E tests for random walk

Add two additional tests for better coverage:

- Test configuration value persistence across interactions
- Test that series count actually generates the expected number of series

These tests verify deeper functionality beyond basic UI rendering,
ensuring the random walk feature works correctly end-to-end.

All 9 tests passing consistently (20.1s runtime).

* Grafana: Remove redundant Min/Max tooltips

Remove tooltips from Min and Max fields that just repeated the label text.
These fields are self-explanatory and don't need tooltip icons.

Keeps the UI cleaner while maintaining helpful tooltips on fields that
actually benefit from explanation (Series count, Start value, Spread,
Noise, Drop %).

* Grafana: Add CODEOWNERS entry for random walk E2E tests

Add codeowner assignment for the new grafana-datasource-random-walk.spec.ts
test file to @grafana/grafana-frontend-platform, matching the ownership of
the Grafana datasource code.

* Add dashboardTemplates feature toggle and put new changes behind this toggle to limit impact

* Grafana: Add unit tests for dashboardTemplates feature toggle

Add unit tests to verify RandomWalkEditor renders correctly based on
the dashboardTemplates feature toggle:

- Test that random walk editor renders when FF is enabled
- Test that random walk editor is hidden when FF is disabled

These tests ensure the feature toggle works as expected and prevents
the random walk configuration UI from appearing when the feature is disabled.

* revert previous codeowners change as not necessary

* Grafana: Remove redundant E2E test for feature flag disabled

Remove E2E test for dashboardTemplates feature flag disabled scenario
since it's already covered by unit tests and E2E environment can't
reliably control server-side feature flags.

Feature flag behavior is properly tested in QueryEditor.test.tsx unit tests.
E2E tests focus on functional validation when the feature is enabled.

* fix lint
2025-10-28 13:05:32 -07:00

221 lines
7.9 KiB
TypeScript

import { test as base, expect } from '@grafana/plugin-e2e';
// Note: Random walk configuration UI requires dashboardTemplates feature toggle to be enabled
const test = base.extend({});
test.use({
featureToggles: {
dashboardTemplates: true,
},
});
test.describe(
'Grafana datasource random walk',
{
tag: ['@grafana-datasource'],
},
() => {
test('should render random walk configuration fields', async ({ gotoDashboardPage, page, selectors }) => {
// Create new dashboard
const dashboardPage = await gotoDashboardPage({});
// Add new panel
await dashboardPage.addPanel();
// Wait for the first field to be visible (ensures query editor loaded)
await expect(page.locator('#randomWalk-seriesCount-A')).toBeVisible();
// Verify core configuration fields (row 1)
await expect(page.locator('#randomWalk-startValue-A')).toBeVisible();
await expect(page.locator('#randomWalk-min-A')).toBeVisible();
await expect(page.locator('#randomWalk-max-A')).toBeVisible();
// Verify fine-tuning fields (row 2)
await expect(page.locator('#randomWalk-spread-A')).toBeVisible();
await expect(page.locator('#randomWalk-noise-A')).toBeVisible();
// Drop percentage is tested separately in its own test
});
test('should configure min and max values and render constrained data', async ({
gotoDashboardPage,
page,
selectors,
}) => {
// Create new dashboard
const dashboardPage = await gotoDashboardPage({});
// Add new panel
await dashboardPage.addPanel();
// Configure random walk with min/max constraints using specific IDs
const minInput = page.locator('#randomWalk-min-A');
const maxInput = page.locator('#randomWalk-max-A');
await minInput.fill('10');
await maxInput.fill('50');
// Wait for the query to execute
await page.waitForTimeout(1000);
// Verify graph renders with a series
await expect(
dashboardPage.getByGrafanaSelector(selectors.components.VizLegend.seriesName('A-series'))
).toBeVisible();
});
test('should generate multiple series when series count is configured', async ({
gotoDashboardPage,
page,
selectors,
}) => {
// Create new dashboard
const dashboardPage = await gotoDashboardPage({});
// Add new panel
await dashboardPage.addPanel();
// Configure series count to 3 using role selector
const seriesCountInput = page.getByRole('spinbutton', { name: 'Series count' });
await seriesCountInput.fill('3');
// Wait for query to execute and check that we have series in the legend
await expect(
dashboardPage.getByGrafanaSelector(selectors.components.VizLegend.seriesName('A-series'))
).toBeVisible();
// Verify the input value is set correctly
await expect(seriesCountInput).toHaveValue('3');
});
test('should configure spread and noise parameters', async ({ gotoDashboardPage, page, selectors }) => {
// Create new dashboard
const dashboardPage = await gotoDashboardPage({});
// Add new panel
await dashboardPage.addPanel();
// Configure spread and noise using role selectors
const spreadInput = page.getByRole('spinbutton', { name: 'Spread' });
const noiseInput = page.getByRole('spinbutton', { name: 'Noise' });
const startValueInput = page.getByRole('spinbutton', { name: 'Start value' });
await startValueInput.fill('100');
await spreadInput.fill('5');
await noiseInput.fill('2');
// Verify graph renders
await expect(
dashboardPage.getByGrafanaSelector(selectors.components.VizLegend.seriesName('A-series'))
).toBeVisible();
});
test('should configure drop percentage for missing data', async ({ gotoDashboardPage, page, selectors }) => {
// Create new dashboard
const dashboardPage = await gotoDashboardPage({});
// Add new panel
await dashboardPage.addPanel();
// Configure drop percentage using role selector
const dropInput = page.getByRole('spinbutton', { name: 'Drop (%)' });
await dropInput.fill('20');
// Verify graph still renders even with dropped points
await expect(
dashboardPage.getByGrafanaSelector(selectors.components.VizLegend.seriesName('A-series'))
).toBeVisible();
});
test('should show tooltips on configuration fields', async ({ gotoDashboardPage, page }) => {
// Create new dashboard
const dashboardPage = await gotoDashboardPage({});
// Add new panel
await dashboardPage.addPanel();
// Verify the Spread field has a tooltip by hovering near its label
const spreadInput = page.locator('#randomWalk-spread-A');
await expect(spreadInput).toBeVisible();
// The tooltip is part of the InlineField component
// Just verify we can interact with the field (tooltip rendering is handled by the component)
await spreadInput.hover();
// Verify the field is configured correctly with tooltip text in the DOM
const spreadLabel = page.getByText('Spread').first();
await expect(spreadLabel).toBeVisible();
});
test('should maintain configuration values when switching between queries', async ({
gotoDashboardPage,
page,
selectors,
}) => {
// Create new dashboard
const dashboardPage = await gotoDashboardPage({});
// Add new panel
await dashboardPage.addPanel();
// Configure multiple random walk parameters
await page.locator('#randomWalk-seriesCount-A').fill('2');
await page.locator('#randomWalk-startValue-A').fill('75');
await page.locator('#randomWalk-min-A').fill('20');
await page.locator('#randomWalk-max-A').fill('90');
await page.locator('#randomWalk-spread-A').fill('3');
await page.locator('#randomWalk-noise-A').fill('1.5');
// Wait for query to execute
await page.waitForTimeout(500);
// Verify all values are set correctly
await expect(page.locator('#randomWalk-seriesCount-A')).toHaveValue('2');
await expect(page.locator('#randomWalk-startValue-A')).toHaveValue('75');
await expect(page.locator('#randomWalk-min-A')).toHaveValue('20');
await expect(page.locator('#randomWalk-max-A')).toHaveValue('90');
await expect(page.locator('#randomWalk-spread-A')).toHaveValue('3');
await expect(page.locator('#randomWalk-noise-A')).toHaveValue('1.5');
// Verify graph renders with the configured data
await expect(
dashboardPage.getByGrafanaSelector(selectors.components.VizLegend.seriesName('A-series'))
).toBeVisible();
});
test('should verify series count actually generates multiple series', async ({
gotoDashboardPage,
page,
selectors,
}) => {
// Create new dashboard
const dashboardPage = await gotoDashboardPage({});
// Add new panel
await dashboardPage.addPanel();
// Set series count to 1 first and verify
await page.locator('#randomWalk-seriesCount-A').fill('1');
await page.waitForTimeout(500);
// Check legend - with 1 series we should see only A-series
await expect(
dashboardPage.getByGrafanaSelector(selectors.components.VizLegend.seriesName('A-series'))
).toBeVisible();
// Now set series count to 3
await page.locator('#randomWalk-seriesCount-A').fill('3');
await page.waitForTimeout(1000);
// With multiple series, they should all render
// The backend generates multiple frames which should show in the panel
// We can verify by checking the panel has data (legend shows A-series)
await expect(
dashboardPage.getByGrafanaSelector(selectors.components.VizLegend.seriesName('A-series'))
).toBeVisible();
// Verify the configuration is set
await expect(page.locator('#randomWalk-seriesCount-A')).toHaveValue('3');
});
}
);