Add row repeat tests
This commit is contained in:
@@ -0,0 +1,573 @@
|
||||
import { test, expect } from '@grafana/plugin-e2e';
|
||||
|
||||
import V2DashWithRowRepeats from '../dashboards/V2DashWithRowRepeats.json';
|
||||
|
||||
import {
|
||||
verifyChanges,
|
||||
saveDashboard,
|
||||
importTestDashboard,
|
||||
goToEmbeddedPanel,
|
||||
groupIntoRow,
|
||||
checkRepeatedRowTitles,
|
||||
moveRow,
|
||||
getRowPosition,
|
||||
} from './utils';
|
||||
|
||||
const repeatTitleBase = 'Row - ';
|
||||
const newTitleBase = 'edited row rep - ';
|
||||
const repeatOptions = [1, 2, 3, 4];
|
||||
const getRepeatedPanelTitle = (row: number, panel: number) => `repeated-row-${row}-repeated-panel-${panel}`;
|
||||
|
||||
test.use({
|
||||
featureToggles: {
|
||||
kubernetesDashboards: true,
|
||||
dashboardNewLayouts: true,
|
||||
groupByVariable: true,
|
||||
},
|
||||
});
|
||||
|
||||
test.use({
|
||||
viewport: { width: 1920, height: 1080 },
|
||||
});
|
||||
|
||||
test.describe(
|
||||
'Repeats - Dashboard rows layout',
|
||||
{
|
||||
tag: ['@dashboards'],
|
||||
},
|
||||
() => {
|
||||
test('can enable row repeats', async ({ dashboardPage, selectors, page }) => {
|
||||
await importTestDashboard(page, selectors, 'Row layout repeats - add repeats');
|
||||
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.editButton).click();
|
||||
|
||||
await groupIntoRow(page, dashboardPage, selectors);
|
||||
|
||||
await dashboardPage
|
||||
.getByGrafanaSelector(selectors.components.PanelEditor.ElementEditPane.RowsLayout.titleInput)
|
||||
.fill(`${repeatTitleBase}$c1`);
|
||||
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(
|
||||
selectors.components.DashboardRow.title(`${repeatTitleBase}${repeatOptions.join(' + ')}`)
|
||||
)
|
||||
).toBeVisible();
|
||||
|
||||
const repeatOptionsGroup = dashboardPage.getByGrafanaSelector(
|
||||
selectors.components.OptionsGroup.group('dash-row-repeat')
|
||||
);
|
||||
|
||||
// expand repeat options dropdown
|
||||
await repeatOptionsGroup.click();
|
||||
// find repeat variable dropdown
|
||||
await repeatOptionsGroup.getByRole('combobox').click();
|
||||
await page.getByRole('option', { name: 'c1' }).click();
|
||||
|
||||
await checkRepeatedRowTitles(dashboardPage, selectors, repeatTitleBase, repeatOptions);
|
||||
|
||||
await saveDashboard(dashboardPage, page, selectors);
|
||||
await page.reload();
|
||||
|
||||
await checkRepeatedRowTitles(dashboardPage, selectors, repeatTitleBase, repeatOptions);
|
||||
});
|
||||
|
||||
test('can update tab repeats with variable change', async ({ dashboardPage, selectors, page }) => {
|
||||
await importTestDashboard(
|
||||
page,
|
||||
selectors,
|
||||
'Rows layout repeats - update on variable change',
|
||||
JSON.stringify(V2DashWithRowRepeats)
|
||||
);
|
||||
|
||||
const c4Var = dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.SubMenu.submenuItemLabels('c4'));
|
||||
await c4Var
|
||||
.locator('..')
|
||||
.getByTestId(selectors.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts(repeatOptions.join(',')))
|
||||
.click();
|
||||
// deselect last variable option
|
||||
await dashboardPage
|
||||
.getByGrafanaSelector(
|
||||
selectors.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts(`${repeatOptions.at(0)}`)
|
||||
)
|
||||
.click();
|
||||
await page.locator('body').click({ position: { x: 0, y: 0 } }); // blur select
|
||||
|
||||
// verify that repeats are present for last 3 values
|
||||
await checkRepeatedRowTitles(dashboardPage, selectors, repeatTitleBase, repeatOptions.slice(1, -1));
|
||||
// verify there is no repeat with first value
|
||||
expect(
|
||||
dashboardPage.getByGrafanaSelector(
|
||||
selectors.components.DashboardRow.title(`${repeatTitleBase}${repeatOptions.at(0)}`)
|
||||
)
|
||||
).toBeHidden();
|
||||
});
|
||||
|
||||
test('can update title for repeat rows in edit pane', async ({ dashboardPage, selectors, page }) => {
|
||||
await importTestDashboard(
|
||||
page,
|
||||
selectors,
|
||||
'Rows layout repeats - update through edit pane',
|
||||
JSON.stringify(V2DashWithRowRepeats)
|
||||
);
|
||||
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.editButton).click();
|
||||
// select first/original repeat row to activate edit pane
|
||||
await dashboardPage
|
||||
.getByGrafanaSelector(selectors.components.DashboardRow.title(`${repeatTitleBase}${repeatOptions.at(0)}`))
|
||||
.click();
|
||||
|
||||
const titleInput = dashboardPage.getByGrafanaSelector(
|
||||
selectors.components.PanelEditor.ElementEditPane.RowsLayout.titleInput
|
||||
);
|
||||
await titleInput.fill(`${newTitleBase}$c4`);
|
||||
await titleInput.blur();
|
||||
|
||||
await checkRepeatedRowTitles(dashboardPage, selectors, newTitleBase, repeatOptions);
|
||||
|
||||
await saveDashboard(dashboardPage, page, selectors);
|
||||
await page.reload();
|
||||
|
||||
await checkRepeatedRowTitles(dashboardPage, selectors, newTitleBase, repeatOptions);
|
||||
});
|
||||
|
||||
test('can update repeats after panel change', async ({ dashboardPage, selectors, page }) => {
|
||||
await importTestDashboard(
|
||||
page,
|
||||
selectors,
|
||||
'Row layout repeats - update repeats after panel change',
|
||||
JSON.stringify(V2DashWithRowRepeats)
|
||||
);
|
||||
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.editButton).click();
|
||||
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('single panel row 1')).click();
|
||||
|
||||
const panelTitleInput = dashboardPage.getByGrafanaSelector(
|
||||
selectors.components.PanelEditor.OptionsPane.fieldInput('Title')
|
||||
);
|
||||
await panelTitleInput.fill('single panel row $c4 edited');
|
||||
await panelTitleInput.blur();
|
||||
|
||||
// close first row to load the second row
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.DashboardRow.title(`${repeatTitleBase}1`)).click();
|
||||
|
||||
// verify edited panel title updated in repeated row
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('single panel row 2 edited'))
|
||||
).toBeVisible();
|
||||
|
||||
// reopen first row so collapse is not saved
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.DashboardRow.title(`${repeatTitleBase}1`)).click();
|
||||
|
||||
await saveDashboard(dashboardPage, page, selectors);
|
||||
await page.reload();
|
||||
|
||||
// close first row to load the second row
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.DashboardRow.title(`${repeatTitleBase}1`)).click();
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('single panel row 2 edited'))
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test('can update repeats after panel change in editor', async ({ dashboardPage, selectors, page }) => {
|
||||
await importTestDashboard(
|
||||
page,
|
||||
selectors,
|
||||
'Row layout repeats - update repeats after panel change in editor',
|
||||
JSON.stringify(V2DashWithRowRepeats)
|
||||
);
|
||||
|
||||
const editedSinglePanelName = (rowNumber: string) => `single panel row ${rowNumber} edited`;
|
||||
const panel = dashboardPage
|
||||
.getByGrafanaSelector(selectors.components.Panels.Panel.title('single panel row 1'))
|
||||
.first();
|
||||
await panel.hover();
|
||||
await page.keyboard.press('e');
|
||||
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.DashboardEditPaneSplitter.primaryBody)
|
||||
).toBeHidden(); // verifying that panel editor loaded
|
||||
|
||||
const panelTitleInput = dashboardPage.getByGrafanaSelector(
|
||||
selectors.components.PanelEditor.OptionsPane.fieldInput('Title')
|
||||
);
|
||||
await panelTitleInput.fill(editedSinglePanelName('$c4'));
|
||||
await panelTitleInput.blur();
|
||||
|
||||
// playwright too fast, verifying JSON diff that changes landed
|
||||
await verifyChanges(dashboardPage, page, selectors, editedSinglePanelName('$c4'));
|
||||
// verify panel title change in panel editor UI
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(editedSinglePanelName('1')))
|
||||
).toBeVisible();
|
||||
|
||||
await dashboardPage
|
||||
.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.backToDashboardButton)
|
||||
.click();
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.DashboardEditPaneSplitter.primaryBody)
|
||||
).toBeVisible(); // verifying that dashboard loaded
|
||||
|
||||
// close first row to make sure we are viewing second row
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.DashboardRow.title(`${repeatTitleBase}1`)).click();
|
||||
|
||||
// verify edited panel title updated in repeated row
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(editedSinglePanelName('2')))
|
||||
).toBeVisible();
|
||||
// open first row again so collapse is not saved
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.DashboardRow.title(`${repeatTitleBase}1`)).click();
|
||||
|
||||
await saveDashboard(dashboardPage, page, selectors);
|
||||
await page.reload();
|
||||
|
||||
// collapse row again so lazy loading loads 2nd row
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.DashboardRow.title(`${repeatTitleBase}1`)).click();
|
||||
|
||||
// verify edited panel title updated in repeated tab
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(editedSinglePanelName('2')))
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test('can hide add panel action in repeats', async ({ dashboardPage, selectors, page }) => {
|
||||
await importTestDashboard(
|
||||
page,
|
||||
selectors,
|
||||
'Row layout repeats - hide canvas add action in repeats',
|
||||
JSON.stringify(V2DashWithRowRepeats)
|
||||
);
|
||||
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.editButton).click();
|
||||
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.CanvasGridAddActions.addPanel)
|
||||
).toBeDefined();
|
||||
|
||||
// close first row to make sure second row is in viewport
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.DashboardRow.title(`${repeatTitleBase}1`)).click();
|
||||
|
||||
const secondRow = dashboardPage.getByGrafanaSelector(
|
||||
selectors.components.DashboardRow.wrapper(`${repeatTitleBase}2`)
|
||||
);
|
||||
await expect(secondRow.getByTestId(selectors.components.CanvasGridAddActions.addPanel)).toBeHidden();
|
||||
});
|
||||
|
||||
test('can move repeated rows', async ({ dashboardPage, selectors, page }) => {
|
||||
await importTestDashboard(
|
||||
page,
|
||||
selectors,
|
||||
'Row layout repeats - move repeated rows',
|
||||
JSON.stringify(V2DashWithRowRepeats)
|
||||
);
|
||||
const singleRowTitle = 'single row';
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.editButton).click();
|
||||
|
||||
// collapse rows and save
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.DashboardRow.title(`${repeatTitleBase}1`)).click();
|
||||
await saveDashboard(dashboardPage, page, selectors);
|
||||
await page.reload();
|
||||
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.editButton).click();
|
||||
await moveRow(dashboardPage, page, selectors, `${repeatTitleBase}1`, singleRowTitle);
|
||||
|
||||
const singleRow = await getRowPosition(dashboardPage, selectors, singleRowTitle);
|
||||
|
||||
const repeatedRow = await getRowPosition(dashboardPage, selectors, `${repeatTitleBase}1`);
|
||||
expect(singleRow?.y).toBeLessThan(repeatedRow?.y || 0);
|
||||
|
||||
await saveDashboard(dashboardPage, page, selectors);
|
||||
await page.reload();
|
||||
|
||||
for (let i = 1; i <= repeatOptions.length; i++) {
|
||||
const singleRow = await getRowPosition(dashboardPage, selectors, singleRowTitle);
|
||||
|
||||
// verify move by row position
|
||||
const repeatedRow = await getRowPosition(dashboardPage, selectors, `${repeatTitleBase}${i}`);
|
||||
expect(singleRow?.y).toBeLessThan(repeatedRow?.y || 0);
|
||||
}
|
||||
});
|
||||
|
||||
test('can view panels in repeated row', async ({ dashboardPage, selectors, page }) => {
|
||||
await importTestDashboard(
|
||||
page,
|
||||
selectors,
|
||||
'Row layout repeats - view panels in repeated rows',
|
||||
JSON.stringify(V2DashWithRowRepeats)
|
||||
);
|
||||
|
||||
// non repeated panel in repeated row
|
||||
await dashboardPage
|
||||
.getByGrafanaSelector(selectors.components.Panels.Panel.title('single panel row 1'))
|
||||
.first()
|
||||
.hover();
|
||||
await page.keyboard.press('v');
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(getRepeatedPanelTitle(1, 1)))
|
||||
).toBeHidden();
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('single panel row 1'))
|
||||
).toBeVisible();
|
||||
|
||||
await page.reload();
|
||||
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('single panel row 1'))
|
||||
).toBeVisible();
|
||||
|
||||
await page.keyboard.press('Escape');
|
||||
|
||||
// repeated panel in original row repeat
|
||||
await dashboardPage
|
||||
.getByGrafanaSelector(selectors.components.Panels.Panel.title(getRepeatedPanelTitle(1, 2)))
|
||||
.hover();
|
||||
await page.keyboard.press('v');
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(getRepeatedPanelTitle(1, 1)))
|
||||
).toBeHidden();
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(getRepeatedPanelTitle(1, 2)))
|
||||
).toBeVisible();
|
||||
|
||||
await page.reload();
|
||||
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(getRepeatedPanelTitle(1, 2)))
|
||||
).toBeVisible();
|
||||
|
||||
await page.keyboard.press('Escape');
|
||||
|
||||
// repeated panel in repeated row
|
||||
await dashboardPage
|
||||
.getByGrafanaSelector(selectors.components.Panels.Panel.title(getRepeatedPanelTitle(2, 2)))
|
||||
.hover();
|
||||
await page.keyboard.press('v');
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(getRepeatedPanelTitle(1, 2)))
|
||||
).toBeHidden();
|
||||
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(getRepeatedPanelTitle(2, 2)))
|
||||
).toBeVisible();
|
||||
|
||||
await page.reload();
|
||||
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(getRepeatedPanelTitle(2, 2)))
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test('can view embedded panels in repeated tab', async ({ dashboardPage, selectors, page }) => {
|
||||
await importTestDashboard(
|
||||
page,
|
||||
selectors,
|
||||
'Row layout repeats - view embedded panels in repeated rows',
|
||||
JSON.stringify(V2DashWithRowRepeats)
|
||||
);
|
||||
|
||||
const dashUrl = page.url();
|
||||
|
||||
// non repeated panel in repeated row
|
||||
// collapse row to make sure row 2 is in viewport
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.DashboardRow.title(`${repeatTitleBase}1`)).click();
|
||||
await dashboardPage
|
||||
.getByGrafanaSelector(selectors.components.Panels.Panel.title('single panel row 2'))
|
||||
.first()
|
||||
.hover();
|
||||
await page.keyboard.press('p+e');
|
||||
await goToEmbeddedPanel(page);
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('single panel row 2'))
|
||||
).toBeVisible();
|
||||
await page.goto(dashUrl);
|
||||
|
||||
// repeated panel in original row
|
||||
await dashboardPage
|
||||
.getByGrafanaSelector(selectors.components.Panels.Panel.title(getRepeatedPanelTitle(1, 2)))
|
||||
.hover();
|
||||
await page.keyboard.press('p+e');
|
||||
await goToEmbeddedPanel(page);
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(getRepeatedPanelTitle(1, 2)))
|
||||
).toBeVisible();
|
||||
await page.goto(dashUrl);
|
||||
|
||||
// repeated panel in repeated row
|
||||
await dashboardPage
|
||||
.getByGrafanaSelector(selectors.components.Panels.Panel.title(getRepeatedPanelTitle(2, 2)))
|
||||
.hover();
|
||||
await page.keyboard.press('p+e');
|
||||
await goToEmbeddedPanel(page);
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(getRepeatedPanelTitle(2, 2)))
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test('can remove repeats', async ({ dashboardPage, selectors, page }) => {
|
||||
await importTestDashboard(
|
||||
page,
|
||||
selectors,
|
||||
'Row layout repeats - remove row repeats',
|
||||
JSON.stringify(V2DashWithRowRepeats)
|
||||
);
|
||||
|
||||
// verify both repeated and single rows are present
|
||||
await checkRepeatedRowTitles(dashboardPage, selectors, repeatTitleBase, repeatOptions);
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.DashboardRow.title('single row'))
|
||||
).toBeVisible();
|
||||
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.editButton).click();
|
||||
|
||||
await dashboardPage
|
||||
.getByGrafanaSelector(selectors.components.DashboardRow.title(`${repeatTitleBase}${repeatOptions.at(0)}`))
|
||||
.click();
|
||||
|
||||
const repeatOptionsGroup = dashboardPage.getByGrafanaSelector(
|
||||
selectors.components.OptionsGroup.group('dash-row-repeat')
|
||||
);
|
||||
// expand repeat options dropdown
|
||||
await repeatOptionsGroup.click();
|
||||
// find repeat variable dropdown
|
||||
await repeatOptionsGroup.getByRole('combobox').click();
|
||||
await page.getByRole('option', { name: 'Disable repeating' }).click();
|
||||
|
||||
const nonRepeatedTitle = `${repeatTitleBase}${repeatOptions.join(' + ')}`;
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.DashboardRow.title(nonRepeatedTitle))
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(
|
||||
selectors.components.Panels.Panel.title(`single panel row ${repeatOptions.join(' + ')}`)
|
||||
)
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(
|
||||
selectors.components.DashboardRow.title(`${repeatTitleBase}${repeatOptions.at(1)}`)
|
||||
)
|
||||
).toBeHidden();
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(
|
||||
selectors.components.DashboardRow.title(`${repeatTitleBase}${repeatOptions.at(2)}`)
|
||||
)
|
||||
).toBeHidden();
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(
|
||||
selectors.components.DashboardRow.title(`${repeatTitleBase}${repeatOptions.at(3)}`)
|
||||
)
|
||||
).toBeHidden();
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(
|
||||
selectors.components.DashboardRow.title(`${repeatTitleBase}${repeatOptions.at(4)}`)
|
||||
)
|
||||
).toBeHidden();
|
||||
await saveDashboard(dashboardPage, page, selectors);
|
||||
await page.reload();
|
||||
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.DashboardRow.title(nonRepeatedTitle))
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(
|
||||
selectors.components.Panels.Panel.title(`single panel row ${repeatOptions.join(' + ')}`)
|
||||
)
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(
|
||||
selectors.components.DashboardRow.title(`${repeatTitleBase}${repeatOptions.at(1)}`)
|
||||
)
|
||||
).toBeHidden();
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(
|
||||
selectors.components.DashboardRow.title(`${repeatTitleBase}${repeatOptions.at(2)}`)
|
||||
)
|
||||
).toBeHidden();
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(
|
||||
selectors.components.DashboardRow.title(`${repeatTitleBase}${repeatOptions.at(3)}`)
|
||||
)
|
||||
).toBeHidden();
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(
|
||||
selectors.components.DashboardRow.title(`${repeatTitleBase}${repeatOptions.at(4)}`)
|
||||
)
|
||||
).toBeHidden();
|
||||
});
|
||||
test('can add tabs in repeated rows', async ({ dashboardPage, selectors, page }) => {
|
||||
await importTestDashboard(
|
||||
page,
|
||||
selectors,
|
||||
'Row layout repeats - remove row repeats',
|
||||
JSON.stringify(V2DashWithRowRepeats)
|
||||
);
|
||||
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.editButton).click();
|
||||
|
||||
// add a tab in first row
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.CanvasGridAddActions.groupPanels).first().click();
|
||||
await page.getByText('Group into tab').click();
|
||||
|
||||
await dashboardPage
|
||||
.getByGrafanaSelector(selectors.components.PanelEditor.ElementEditPane.TabsLayout.titleInput)
|
||||
.fill(`tab-row-$c4`);
|
||||
|
||||
await expect(dashboardPage.getByGrafanaSelector(selectors.components.Tab.title(`tab-row-1`))).toBeVisible();
|
||||
|
||||
await saveDashboard(dashboardPage, page, selectors);
|
||||
await page.reload();
|
||||
|
||||
await expect(dashboardPage.getByGrafanaSelector(selectors.components.Tab.title(`tab-row-1`))).toBeVisible();
|
||||
await expect(dashboardPage.getByGrafanaSelector(selectors.components.Tab.title(`tab-row-2`))).toBeVisible();
|
||||
});
|
||||
test('can add repeat tabs in repeated rows', async ({ dashboardPage, selectors, page }) => {
|
||||
const tabRepeatTitle = (tabNo: number, rowNo: number) => `tab-${tabNo}-row-${rowNo}`;
|
||||
await importTestDashboard(
|
||||
page,
|
||||
selectors,
|
||||
'Row layout repeats - remove row repeats',
|
||||
JSON.stringify(V2DashWithRowRepeats)
|
||||
);
|
||||
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.editButton).click();
|
||||
|
||||
// add a tab in first row
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.CanvasGridAddActions.groupPanels).first().click();
|
||||
await page.getByText('Group into tab').click();
|
||||
|
||||
await dashboardPage
|
||||
.getByGrafanaSelector(selectors.components.PanelEditor.ElementEditPane.TabsLayout.titleInput)
|
||||
.fill(`tab-$c1-row-$c4`);
|
||||
|
||||
const repeatOptionsGroup = dashboardPage.getByGrafanaSelector(
|
||||
selectors.components.OptionsGroup.group('repeat-options')
|
||||
);
|
||||
// expand repeat options dropdown
|
||||
await repeatOptionsGroup.getByRole('button').first().click();
|
||||
// find repeat variable dropdown
|
||||
await repeatOptionsGroup.getByRole('combobox').click();
|
||||
await page.getByRole('option', { name: 'c1' }).click();
|
||||
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Tab.title(tabRepeatTitle(1, 1)))
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Tab.title(tabRepeatTitle(2, 1)))
|
||||
).toBeVisible();
|
||||
await saveDashboard(dashboardPage, page, selectors);
|
||||
await page.reload();
|
||||
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Tab.title(tabRepeatTitle(1, 1)))
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Tab.title(tabRepeatTitle(2, 1)))
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Tab.title(tabRepeatTitle(1, 2)))
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.Tab.title(tabRepeatTitle(2, 2)))
|
||||
).toBeVisible();
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -312,7 +312,7 @@ test.describe(
|
||||
await importTestDashboard(
|
||||
page,
|
||||
selectors,
|
||||
'Auto-grid repeats - move repeated panels 2',
|
||||
'Auto-grid repeats - view repeated panels 2',
|
||||
JSON.stringify(testV2DashWithRepeats)
|
||||
);
|
||||
|
||||
|
||||
@@ -211,11 +211,43 @@ export async function moveTab(
|
||||
await page.mouse.up();
|
||||
}
|
||||
|
||||
export async function moveRow(
|
||||
dashboardPage: DashboardPage,
|
||||
page: Page,
|
||||
selectors: E2ESelectorGroups,
|
||||
sourceRow: string,
|
||||
targetRow: string
|
||||
) {
|
||||
// Get target panel position
|
||||
const targetRowElement = dashboardPage
|
||||
.getByGrafanaSelector(selectors.components.DashboardRow.title(targetRow))
|
||||
.first();
|
||||
|
||||
// Get source panel element
|
||||
const sourceRowElement = dashboardPage
|
||||
.getByGrafanaSelector(selectors.components.DashboardRow.title(sourceRow))
|
||||
.first();
|
||||
|
||||
const targetBox = await targetRowElement.boundingBox();
|
||||
|
||||
// Perform drag and drop (dragTo() did not work in this case)
|
||||
await sourceRowElement.hover();
|
||||
await page.mouse.down();
|
||||
// move to adjusted target position (relative to top left)
|
||||
await page.mouse.move(targetBox?.x || 0, (targetBox?.y || 0) + (targetBox?.height || 0), { steps: 5 });
|
||||
await page.mouse.up();
|
||||
}
|
||||
|
||||
export async function groupIntoTab(page: Page, dashboardPage: DashboardPage, selectors: E2ESelectorGroups) {
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.CanvasGridAddActions.groupPanels).click();
|
||||
await page.getByText('Group into tab').click();
|
||||
}
|
||||
|
||||
export async function groupIntoRow(page: Page, dashboardPage: DashboardPage, selectors: E2ESelectorGroups) {
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.CanvasGridAddActions.groupPanels).click();
|
||||
await page.getByText('Group into row').click();
|
||||
}
|
||||
|
||||
export async function checkRepeatedTabTitles(
|
||||
dashboardPage: DashboardPage,
|
||||
selectors: E2ESelectorGroups,
|
||||
@@ -232,3 +264,23 @@ export async function getTabPosition(dashboardPage: DashboardPage, selectors: E2
|
||||
const boundingBox = await tab.boundingBox();
|
||||
return boundingBox;
|
||||
}
|
||||
|
||||
export async function getRowPosition(dashboardPage: DashboardPage, selectors: E2ESelectorGroups, rowTitle: string) {
|
||||
const row = dashboardPage.getByGrafanaSelector(selectors.components.DashboardRow.title(rowTitle)).first();
|
||||
const boundingBox = await row.boundingBox();
|
||||
return boundingBox;
|
||||
}
|
||||
|
||||
export async function checkRepeatedRowTitles(
|
||||
dashboardPage: DashboardPage,
|
||||
selectors: E2ESelectorGroups,
|
||||
title: string,
|
||||
options: Array<string | number>
|
||||
) {
|
||||
for (const option of options) {
|
||||
await expect(
|
||||
dashboardPage.getByGrafanaSelector(selectors.components.DashboardRow.title(`${title}${option}`))
|
||||
).toBeVisible();
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.DashboardRow.title(`${title}${option}`)).click();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,502 @@
|
||||
{
|
||||
"apiVersion": "dashboard.grafana.app/v2beta1",
|
||||
"kind": "Dashboard",
|
||||
"metadata": {
|
||||
"name": "ad8l8fz",
|
||||
"namespace": "default",
|
||||
"uid": "fLb2na54K8NZHvn8LfWGL1jhZh03Hy0xpV1KzMYgAXEX",
|
||||
"resourceVersion": "1",
|
||||
"generation": 2,
|
||||
"creationTimestamp": "2025-11-25T15:52:42Z",
|
||||
"labels": {
|
||||
"grafana.app/deprecatedInternalID": "20"
|
||||
},
|
||||
"annotations": {
|
||||
"grafana.app/createdBy": "user:aerwo725ot62od",
|
||||
"grafana.app/updatedBy": "user:aerwo725ot62od",
|
||||
"grafana.app/updatedTimestamp": "2025-11-25T15:52:42Z",
|
||||
"grafana.app/folder": ""
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"annotations": [
|
||||
{
|
||||
"kind": "AnnotationQuery",
|
||||
"spec": {
|
||||
"builtIn": true,
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"query": {
|
||||
"datasource": {
|
||||
"name": "-- Grafana --"
|
||||
},
|
||||
"group": "grafana",
|
||||
"kind": "DataQuery",
|
||||
"spec": {},
|
||||
"version": "v0"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"cursorSync": "Off",
|
||||
"description": "",
|
||||
"editable": true,
|
||||
"elements": {
|
||||
"panel-1": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"hidden": false,
|
||||
"query": {
|
||||
"group": "",
|
||||
"kind": "DataQuery",
|
||||
"spec": {},
|
||||
"version": "v0"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
}
|
||||
],
|
||||
"queryOptions": {},
|
||||
"transformations": []
|
||||
}
|
||||
},
|
||||
"description": "",
|
||||
"id": 4,
|
||||
"links": [],
|
||||
"title": "repeated-row-$c4-repeated-panel-$c3",
|
||||
"vizConfig": {
|
||||
"group": "timeseries",
|
||||
"kind": "VizConfig",
|
||||
"spec": {
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisBorderShow": false,
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"barWidthFactor": 0.6,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"insertNulls": false,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"showValues": false,
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"hideZeros": false,
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
}
|
||||
},
|
||||
"version": "12.4.0-pre"
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel-2": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"hidden": false,
|
||||
"query": {
|
||||
"group": "",
|
||||
"kind": "DataQuery",
|
||||
"spec": {},
|
||||
"version": "v0"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
}
|
||||
],
|
||||
"queryOptions": {},
|
||||
"transformations": []
|
||||
}
|
||||
},
|
||||
"description": "",
|
||||
"id": 2,
|
||||
"links": [],
|
||||
"title": "single panel row $c4",
|
||||
"vizConfig": {
|
||||
"group": "timeseries",
|
||||
"kind": "VizConfig",
|
||||
"spec": {
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisBorderShow": false,
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"barWidthFactor": 0.6,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"insertNulls": false,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"showValues": false,
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"hideZeros": false,
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
}
|
||||
},
|
||||
"version": "12.4.0-pre"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
"kind": "RowsLayout",
|
||||
"spec": {
|
||||
"rows": [
|
||||
{
|
||||
"kind": "RowsLayoutRow",
|
||||
"spec": {
|
||||
"collapse": false,
|
||||
"layout": {
|
||||
"kind": "GridLayout",
|
||||
"spec": {
|
||||
"items": [
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-1"
|
||||
},
|
||||
"height": 10,
|
||||
"repeat": {
|
||||
"direction": "h",
|
||||
"mode": "variable",
|
||||
"value": "c3"
|
||||
},
|
||||
"width": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-2"
|
||||
},
|
||||
"height": 8,
|
||||
"width": 12,
|
||||
"x": 0,
|
||||
"y": 10
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"repeat": {
|
||||
"mode": "variable",
|
||||
"value": "c4"
|
||||
},
|
||||
"title": "Row - $c4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "RowsLayoutRow",
|
||||
"spec": {
|
||||
"collapse": false,
|
||||
"layout": {
|
||||
"kind": "AutoGridLayout",
|
||||
"spec": {
|
||||
"columnWidthMode": "standard",
|
||||
"items": [],
|
||||
"maxColumnCount": 3,
|
||||
"rowHeightMode": "standard"
|
||||
}
|
||||
},
|
||||
"title": "single row"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"preload": false,
|
||||
"tags": [],
|
||||
"timeSettings": {
|
||||
"autoRefresh": "",
|
||||
"autoRefreshIntervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"],
|
||||
"fiscalYearStartMonth": 0,
|
||||
"from": "now-6h",
|
||||
"hideTimepicker": false,
|
||||
"timezone": "browser",
|
||||
"to": "now"
|
||||
},
|
||||
"title": "test-e2e-repeats",
|
||||
"variables": [
|
||||
{
|
||||
"kind": "CustomVariable",
|
||||
"spec": {
|
||||
"allowCustomValue": true,
|
||||
"current": {
|
||||
"text": ["1", "2", "3", "4"],
|
||||
"value": ["1", "2", "3", "4"]
|
||||
},
|
||||
"hide": "dontHide",
|
||||
"includeAll": true,
|
||||
"multi": true,
|
||||
"name": "c1",
|
||||
"options": [
|
||||
{
|
||||
"selected": true,
|
||||
"text": "1",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"selected": true,
|
||||
"text": "2",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"selected": true,
|
||||
"text": "3",
|
||||
"value": "3"
|
||||
},
|
||||
{
|
||||
"selected": true,
|
||||
"text": "4",
|
||||
"value": "4"
|
||||
}
|
||||
],
|
||||
"query": "1,2,3,4",
|
||||
"skipUrlSync": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "CustomVariable",
|
||||
"spec": {
|
||||
"allowCustomValue": true,
|
||||
"current": {
|
||||
"text": ["A", "B", "C", "D"],
|
||||
"value": ["A", "B", "C", "D"]
|
||||
},
|
||||
"hide": "dontHide",
|
||||
"includeAll": true,
|
||||
"multi": true,
|
||||
"name": "c2",
|
||||
"options": [
|
||||
{
|
||||
"selected": true,
|
||||
"text": "A",
|
||||
"value": "A"
|
||||
},
|
||||
{
|
||||
"selected": true,
|
||||
"text": "B",
|
||||
"value": "B"
|
||||
},
|
||||
{
|
||||
"selected": true,
|
||||
"text": "C",
|
||||
"value": "C"
|
||||
},
|
||||
{
|
||||
"selected": true,
|
||||
"text": "D",
|
||||
"value": "D"
|
||||
}
|
||||
],
|
||||
"query": "A,B,C,D",
|
||||
"skipUrlSync": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "CustomVariable",
|
||||
"spec": {
|
||||
"allowCustomValue": true,
|
||||
"current": {
|
||||
"text": ["1", "2", "3", "4"],
|
||||
"value": ["1", "2", "3", "4"]
|
||||
},
|
||||
"hide": "dontHide",
|
||||
"includeAll": false,
|
||||
"multi": true,
|
||||
"name": "c3",
|
||||
"options": [
|
||||
{
|
||||
"selected": true,
|
||||
"text": "1",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"selected": true,
|
||||
"text": "2",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"selected": true,
|
||||
"text": "3",
|
||||
"value": "3"
|
||||
},
|
||||
{
|
||||
"selected": true,
|
||||
"text": "4",
|
||||
"value": "4"
|
||||
}
|
||||
],
|
||||
"query": "1, 2, 3, 4",
|
||||
"skipUrlSync": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "CustomVariable",
|
||||
"spec": {
|
||||
"allowCustomValue": true,
|
||||
"current": {
|
||||
"text": ["1", "2", "3", "4"],
|
||||
"value": ["1", "2", "3", "4"]
|
||||
},
|
||||
"hide": "dontHide",
|
||||
"includeAll": false,
|
||||
"multi": true,
|
||||
"name": "c4",
|
||||
"options": [
|
||||
{
|
||||
"selected": true,
|
||||
"text": "1",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"selected": true,
|
||||
"text": "2",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"selected": true,
|
||||
"text": "3",
|
||||
"value": "3"
|
||||
},
|
||||
{
|
||||
"selected": true,
|
||||
"text": "4",
|
||||
"value": "4"
|
||||
}
|
||||
],
|
||||
"query": "1, 2, 3, 4",
|
||||
"skipUrlSync": false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
Reference in New Issue
Block a user