import { type Page, type Locator } from '@playwright/test';

import { test, expect, type E2ESelectorGroups } from '@grafana/plugin-e2e';

import { getCell, getCellHeight, getColumnIdx, getSelectedFilterCount, waitForTableLoad } from './table-utils';

const DASHBOARD_UID = 'dcb9f5e9-8066-4397-889e-864b99555dbb';

test.use({ viewport: { width: 2000, height: 1080 } });

const disableAllTextWrap = async (loc: Page | Locator, selectors: E2ESelectorGroups) => {
  // disable text wrapping for all of the columns, since long text with links in them can push the links off the screen.
  const wrapTextToggle = loc.getByLabel('Wrap text');
  const count = await wrapTextToggle.count();

  for (let i = 0; i < count; i++) {
    const toggle = wrapTextToggle.nth(i);
    if ((await toggle.getAttribute('checked')) !== null) {
      await toggle.click({ force: true });
    }
  }
};

test.describe('Panels test: Table - Kitchen Sink', { tag: ['@panels', '@table'] }, () => {
  test('a11y', { tag: ['@a11y'] }, async ({ scanForA11yViolations, selectors, page }) => {
    await page.goto(selectors.pages.SoloPanel.url(`${DASHBOARD_UID}/panel-tests-table-kitchen-sink?orgId=1&panelId=1`));
    await expect(page.getByTestId(selectors.components.Panels.Panel.title('Table - Kitchen Sink'))).toBeVisible();
    await waitForTableLoad(page);
    const report = await scanForA11yViolations({
      options: {
        runOnly: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'best-practice'],
      },
    });
    expect(report).toHaveNoA11yViolations({ ignoredRules: ['page-has-heading-one', 'region', 'color-contrast'] });
  });

  test('Tests word wrap, hover overflow, max cell height, and cell inspect', async ({
    gotoDashboardPage,
    selectors,
    page,
  }) => {
    const dashboardPage = await gotoDashboardPage({
      uid: DASHBOARD_UID,
      queryParams: new URLSearchParams({ editPanel: '1' }),
    });

    await expect(
      dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('Table - Kitchen Sink'))
    ).toBeVisible();

    // to avoid a race condition when counting up , wait for react-data-grid to finish rendering.
    await waitForTableLoad(page);

    const table = page.locator('.rdg');
    const longTextColIdx = await getColumnIdx(table, 'Long Text');

    // text wrapping is enabled by default on this panel.
    await expect(getCellHeight(table, 1, longTextColIdx)).resolves.toBeGreaterThan(100);

    // set a max row height, watch the height decrease, then clear it to continue.
    const maxRowHeightInput = page.getByLabel('Max row height').last();
    await maxRowHeightInput.fill('80');
    await expect(async () => {
      await expect(getCellHeight(table, 1, longTextColIdx)).resolves.toBeLessThan(100);
    }).toPass();
    await maxRowHeightInput.clear();

    // toggle the lorem ipsum column's wrap text toggle and confirm that the height shrinks.
    await dashboardPage
      .getByGrafanaSelector(selectors.components.OptionsGroup.group('panel-options-override-12'))
      .getByLabel('Wrap text')
      .click({ force: true });
    await expect(getCellHeight(table, 1, longTextColIdx)).resolves.toBeLessThan(100);

    // test that hover overflow works.
    const loremIpsumCell = getCell(table, 1, longTextColIdx);
    await loremIpsumCell.scrollIntoViewIfNeeded();
    await loremIpsumCell.hover();
    await expect(getCellHeight(table, 1, longTextColIdx)).resolves.toBeGreaterThan(100);
    await getCell(table, 1, longTextColIdx + 1).hover();
    await expect(getCellHeight(table, 1, longTextColIdx)).resolves.toBeLessThan(100);

    // enable cell inspect, confirm that hover no longer triggers.
    await dashboardPage
      .getByGrafanaSelector(selectors.components.PanelEditor.OptionsPane.fieldLabel('Cell options Cell value inspect'))
      .first()
      .getByRole('switch', { name: 'Cell value inspect' })
      .click({ force: true });
    await loremIpsumCell.hover();
    await expect(getCellHeight(table, 1, longTextColIdx)).resolves.toBeLessThan(100);

    // click cell inspect, check that cell inspection pops open in the side as we'd expect.
    const loremIpsumText = await loremIpsumCell.textContent();
    expect(loremIpsumText).toBeDefined();
    await loremIpsumCell.getByLabel('Inspect value').click();
    await expect(page.getByRole('dialog').getByText(loremIpsumText!)).toBeVisible();
  });

  test('Tests visibility and display name via overrides', async ({ gotoDashboardPage, selectors, page }) => {
    const dashboardPage = await gotoDashboardPage({
      uid: DASHBOARD_UID,
      queryParams: new URLSearchParams({ editPanel: '1' }),
    });

    await expect(
      dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('Table - Kitchen Sink'))
    ).toBeVisible();

    const stateOverride = dashboardPage.getByGrafanaSelector(
      selectors.components.OptionsGroup.group('panel-options-override-11')
    );

    // confirm that "State" column is hidden by default.
    expect(page.getByRole('row').nth(0)).not.toContainText('State');
    // toggle the "State" column visibility via the override we set up in the kitchen sink panel.
    const hideStateColumnSwitch = stateOverride.locator('label').last();
    await hideStateColumnSwitch.click();
    expect(page.getByRole('row').nth(0)).toContainText('State');

    // now change the display name of the "State" column.
    const displayNameInput = stateOverride.locator('input[value="State"]').last();
    await displayNameInput.fill('State (renamed)');
    await displayNameInput.press('Enter');
    expect(page.getByRole('row').nth(0)).toContainText('State (renamed)');

    // toggle the "State" column visibility again to hide it again. this confirms that we avoid bugs related to
    // array lengths between the fields array and the column widths array.
    await hideStateColumnSwitch.click();
    expect(page.getByRole('row').nth(0)).not.toContainText('State');

    // since the previous assertion is just for the absence of text, let's also confirm that the table is
    // actually still on the page and that an error has not been throw.
    await waitForTableLoad(page);
  });

  // we test niche cases for sorting, filtering, pagination, etc. in a unit tests already.
  // we mainly want to test the happiest paths for these in e2es as well to check for integration
  // issues, but the unit tests can confirm that the internal logic works as expected much more quickly and thoroughly.
  // hashtag testing pyramid.
  test('Tests sorting by column', async ({ gotoDashboardPage, selectors, page }) => {
    const dashboardPage = await gotoDashboardPage({
      uid: DASHBOARD_UID,
      queryParams: new URLSearchParams({ editPanel: '1' }),
    });

    await expect(
      dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('Table - Kitchen Sink'))
    ).toBeVisible();

    // click the "State" column header to sort it.
    const table = page.locator('.rdg');
    const stateColumnHeader = getCell(table, 0, 1);

    await stateColumnHeader.getByText('Info').click();
    await expect(stateColumnHeader).toHaveAttribute('aria-sort', 'ascending');
    await expect(getCell(table, 1, 1)).toContainText('down'); // down or down fast

    await stateColumnHeader.getByText('Info').click();
    await expect(stateColumnHeader).toHaveAttribute('aria-sort', 'descending');
    await expect(getCell(table, 1, 1)).toContainText('up'); // up or up fast

    await stateColumnHeader.getByText('Info').click();
    await expect(stateColumnHeader).not.toHaveAttribute('aria-sort');
  });

  test('Tests filtering within a column', async ({ gotoDashboardPage, selectors, page }) => {
    const dashboardPage = await gotoDashboardPage({
      uid: DASHBOARD_UID,
      queryParams: new URLSearchParams({ editPanel: '1' }),
    });

    await expect(
      dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('Table - Kitchen Sink'))
    ).toBeVisible();

    await waitForTableLoad(page);

    const table = page.locator('.rdg');

    const infoColumnIdx = await getColumnIdx(table, 'Info');

    const stateColumnHeader = page.getByRole('columnheader').nth(infoColumnIdx);

    // get the first value in the "State" column, filter it out, then check that it went away.
    const firstStateValue = (await getCell(table, 1, infoColumnIdx).textContent())!;
    await stateColumnHeader.getByTestId(selectors.components.Panels.Visualization.TableNG.Filters.HeaderButton).click();
    const filterContainer = dashboardPage.getByGrafanaSelector(
      selectors.components.Panels.Visualization.TableNG.Filters.Container
    );

    await expect(filterContainer).toBeVisible();

    // select all, then click the first value to unselect it, filtering it out.
    await filterContainer.getByTestId(selectors.components.Panels.Visualization.TableNG.Filters.SelectAll).click();
    await filterContainer.getByTitle(firstStateValue, { exact: true }).locator('label').click();
    await filterContainer.getByRole('button', { name: 'Ok' }).click();

    // make sure the filter container closed when we clicked "Ok".
    await expect(filterContainer).not.toBeVisible();

    // did it actually filter out our value?
    await expect(getCell(table, 1, infoColumnIdx)).not.toHaveText(firstStateValue);
  });

  test('Tests pagination, row height adjustment', async ({ gotoDashboardPage, selectors, page }) => {
    const rowRe = /([\d]+) - ([\d]+) of ([\d]+) rows/;
    const getRowStatus = async (page: Page | Locator) => {
      const text = (await page.getByText(rowRe).textContent()) ?? '';
      const match = text.match(rowRe);
      return {
        start: parseInt(match?.[1] ?? '0', 10),
        end: parseInt(match?.[2] ?? '0', 10),
        total: parseInt(match?.[3] ?? '0', 10),
      };
    };

    const dashboardPage = await gotoDashboardPage({
      uid: DASHBOARD_UID,
      queryParams: new URLSearchParams({ editPanel: '1' }),
    });

    await expect(
      dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('Table - Kitchen Sink'))
    ).toBeVisible();

    await page
      .getByLabel(selectors.components.PanelEditor.OptionsPane.fieldLabel(`Enable pagination`), { exact: true })
      .click();

    // because of text wrapping, we're guaranteed to only be showing a single row when we enable pagination.
    await expect(page.getByText(/([\d]+) - ([\d]+) of ([\d]+) rows/)).toBeVisible();

    await disableAllTextWrap(page, selectors);

    // any number of rows that is not "1" is allowed here, we don't want to police the exact number of rows that
    // are rendered since there are tons of factors which could effect this. we do want to grab this number for comparison
    // in a second, though.
    const smallRowStatus = await getRowStatus(page);
    expect(smallRowStatus.end).toBeGreaterThan(1);
    expect(page.getByRole('grid').getByRole('row')).toHaveCount(smallRowStatus.end + 2); // +2 for header and footer rows

    // change cell height to Large
    await dashboardPage
      .getByGrafanaSelector(selectors.components.PanelEditor.OptionsPane.fieldLabel('Table Cell height'))
      .locator('input')
      .last()
      .click();
    const largeRowStatus = await getRowStatus(page);
    expect(largeRowStatus.end).toBeLessThan(smallRowStatus.end);
    expect(page.getByRole('grid').getByRole('row')).toHaveCount(largeRowStatus.end + 2); // +2 for header and footer rows

    // click a page over with the directional nav
    await page.getByLabel('next page').click();
    const nextPageStatus = await getRowStatus(page);
    expect(nextPageStatus.start).toBe(largeRowStatus.end + 1);
    expect(nextPageStatus.end).toBe(largeRowStatus.end * 2);
    expect(nextPageStatus.total).toBe(largeRowStatus.total);

    // click a page number
    await page.getByTestId('data-testid panel content').getByRole('navigation').getByText('4', { exact: true }).click();
    const fourthPageStatus = await getRowStatus(page);
    expect(fourthPageStatus.start).toBe(largeRowStatus.end * 3 + 1);
    expect(fourthPageStatus.end).toBe(largeRowStatus.end * 4);
    expect(fourthPageStatus.total).toBe(largeRowStatus.total);
  });

  test.skip('Tests DataLinks (single and multi) and actions', async ({ gotoDashboardPage, selectors, page }) => {
    const addDataLink = async (title: string, url: string) => {
      await dashboardPage
        .getByGrafanaSelector(
          selectors.components.PanelEditor.OptionsPane.fieldLabel('Data links and actions Data links')
        )
        .locator('button')
        .filter({ hasText: 'Add link' })
        .click();

      // DataLinks dialog has popped open - fill it in and add a global datalink.
      await expect(page.getByRole('dialog')).toBeVisible();
      await page.getByRole('dialog').locator('#link-title').fill(title);
      await page.getByRole('dialog').locator('#data-link-input [contenteditable="true"]').focus();
      await page.getByRole('dialog').locator('#data-link-input [contenteditable="true"]').fill(url);
      await page.getByRole('dialog').locator('#data-link-input [contenteditable="true"]').blur();
      await page.getByRole('dialog').locator('button[aria-disabled="false"]').filter({ hasText: 'Save' }).click();
      await expect(page.getByRole('dialog')).not.toBeVisible();
    };

    const dashboardPage = await gotoDashboardPage({
      uid: DASHBOARD_UID,
      queryParams: new URLSearchParams({ editPanel: '1' }),
    });

    await expect(
      dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('Table - Kitchen Sink'))
    ).toBeVisible();

    await disableAllTextWrap(page, selectors);

    const table = page.locator('.rdg');
    const infoColumnIdx = await getColumnIdx(table, 'Info');
    const pillColIdx = await getColumnIdx(table, 'Pills');
    const dataLinkColIdx = await getColumnIdx(table, 'Data Link');

    // Info column has a single DataLink by default.
    const infoCell = getCell(table, 1, infoColumnIdx);
    await expect(infoCell.locator('a')).toBeVisible();
    expect(infoCell.locator('a')).toHaveAttribute('href');
    expect(infoCell.locator('a')).not.toHaveAttribute('aria-haspopup');

    // now, add a DataLink to the whole table
    await addDataLink('Test link', 'https://grafana.com');

    // add a DataLink to the whole table, all cells will now have a single link.
    const colCount = await page.getByRole('row').nth(1).getByRole('gridcell').count();
    for (let colIdx = 0; colIdx < colCount; colIdx++) {
      // - pills column currently does not support DataLinks.
      // - we don't apply DataLinks to the DataLinks column itself, since they're rendered inside.
      if (colIdx === pillColIdx || colIdx === dataLinkColIdx) {
        continue;
      }

      const cell = getCell(table, 1, colIdx);
      await expect(cell.locator('a')).toBeVisible();
      expect(cell.locator('a')).toHaveAttribute('href');
      expect(cell.locator('a')).not.toHaveAttribute('aria-haspopup', 'menu');
    }

    const headerContainer = dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.headerContainer);

    // add another data link. now we'll check that the multi-link popups work.
    await addDataLink('Another test link', 'https://grafana.com/foo');

    // loop thru the columns, click the links, observe that the tooltip appears, and close the tooltip.
    for (let colIdx = 0; colIdx < colCount; colIdx++) {
      const cell = getCell(table, 1, colIdx);
      if (colIdx === infoColumnIdx) {
        // the Info column should still have its single link.
        expect(cell.locator('a')).not.toHaveAttribute('aria-haspopup', 'menu');
        continue;
      }

      // - pills column currently does not support DataLinks.
      // - we don't apply DataLinks to the DataLinks column itself, since they're rendered inside.
      if (colIdx === pillColIdx || colIdx === dataLinkColIdx) {
        continue;
      }

      await cell.locator('a').click({ force: true });
      await expect(page.getByTestId(selectors.components.DataLinksActionsTooltip.tooltipWrapper)).toBeVisible();

      await headerContainer.click(); // convenient just to click the header to close the tooltip.
      await expect(page.getByTestId(selectors.components.DataLinksActionsTooltip.tooltipWrapper)).not.toBeVisible();
    }

    // add an Action to the whole table and check that the action button is added to the tooltip.
    // TODO -- saving for another day.
  });

  test('Cross-filter: second filter popup only shows values reachable after first filter', async ({
    gotoDashboardPage,
    selectors,
    page,
  }) => {
    const dashboardPage = await gotoDashboardPage({
      uid: DASHBOARD_UID,
      queryParams: new URLSearchParams({ editPanel: '1' }),
    });

    await expect(
      dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('Table - Kitchen Sink'))
    ).toBeVisible();

    await waitForTableLoad(page);

    const table = page.locator('.rdg');

    const infoColumnIdx = await getColumnIdx(table, 'Info');
    const minColumnIdx = await getColumnIdx(table, 'Min');

    // --- Baseline: collect the full set of Min option titles from the Min filter popup ---
    const minHeader = page.getByRole('columnheader').nth(minColumnIdx);
    await minHeader.getByTestId(selectors.components.Panels.Visualization.TableNG.Filters.HeaderButton).click();
    const minFilterContainer = dashboardPage.getByGrafanaSelector(
      selectors.components.Panels.Visualization.TableNG.Filters.Container
    );
    await expect(minFilterContainer, 'filter popup for min is visible after click').toBeVisible();

    // Count all option rows in the Min filter popup before any cross-filter is applied.
    // The List component is virtualized so we can't rely on DOM element count — instead click
    // "Select all" (which operates on the full data array) and parse the "N selected" label.
    await minFilterContainer.getByTestId(selectors.components.Panels.Visualization.TableNG.Filters.SelectAll).click();
    const allMinOptionCount = await getSelectedFilterCount(minFilterContainer, selectors);

    // Close without applying
    await minFilterContainer.getByRole('button', { name: 'Cancel' }).click();
    await expect(minFilterContainer, 'filter popup for min is not visible after close').not.toBeVisible();

    // --- Sort by Info and confirm that the first value is not "up" to compare later in the test ---
    const infoHeader = page.getByRole('columnheader').nth(infoColumnIdx);
    await infoHeader.getByText('Info').click();
    await expect(infoHeader, 'info column header is sorted ascending after click').toHaveAttribute(
      'aria-sort',
      'ascending'
    );
    const firstInfoCell = getCell(table, 1, infoColumnIdx);
    expect(firstInfoCell, 'first info cell is not "up" after sorting').not.toHaveText('up');

    // --- Apply a filter on Info to only show "up" rows ---
    await infoHeader.getByTestId(selectors.components.Panels.Visualization.TableNG.Filters.HeaderButton).click();
    const infoFilterContainer = dashboardPage.getByGrafanaSelector(
      selectors.components.Panels.Visualization.TableNG.Filters.Container
    );
    await expect(infoFilterContainer, 'filter popup for info is visible after click').toBeVisible();
    await infoFilterContainer.getByTitle('up', { exact: true }).locator('label').click();
    await infoFilterContainer.getByRole('button', { name: 'Ok' }).click();
    await expect(infoFilterContainer).not.toBeVisible();

    // Table should now show only "up" rows
    await expect(firstInfoCell, 'first info cell is "up" after filtering').toHaveText('up');

    // --- Open the Min filter popup again; cross-filter should restrict the options ---
    await minHeader.getByTestId(selectors.components.Panels.Visualization.TableNG.Filters.HeaderButton).click();
    await expect(minFilterContainer, 'filter popup for min is visible after click').toBeVisible();

    await minFilterContainer.getByTestId(selectors.components.Panels.Visualization.TableNG.Filters.SelectAll).click();
    const crossFilteredMinOptionCount = await getSelectedFilterCount(minFilterContainer, selectors);

    // With Info filtered to "up" only, Min options must be a subset of (or equal to) the full set.
    // In practice the data has multiple Info values, so the Min option list should be smaller.
    expect(
      crossFilteredMinOptionCount,
      'cross-filtered min option count is less than all min option count'
    ).toBeLessThan(allMinOptionCount);

    // Close the filter popup
    await minFilterContainer.getByRole('button', { name: 'Cancel' }).click();
  });

  test('Tests tooltip interactions', async ({ gotoDashboardPage, selectors }) => {
    const dashboardPage = await gotoDashboardPage({
      uid: DASHBOARD_UID,
      queryParams: new URLSearchParams({ editPanel: '1' }),
    });

    await expect(
      dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('Table - Kitchen Sink'))
    ).toBeVisible();

    const firstCaret = dashboardPage
      .getByGrafanaSelector(selectors.components.Panels.Visualization.TableNG.Tooltip.Caret)
      .first();

    // test hovering over and blurring the caret, and whether the tooltip appears and disappears as expected.
    await firstCaret.hover();

    await expect(
      dashboardPage.getByGrafanaSelector(selectors.components.Panels.Visualization.TableNG.Tooltip.Wrapper)
    ).toBeVisible();

    await dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('Table - Kitchen Sink')).hover();

    await expect(
      dashboardPage.getByGrafanaSelector(selectors.components.Panels.Visualization.TableNG.Tooltip.Wrapper)
    ).not.toBeVisible();

    // when a pinned tooltip is open, clicking outside of it should close it.
    await firstCaret.click();

    await expect(
      dashboardPage.getByGrafanaSelector(selectors.components.Panels.Visualization.TableNG.Tooltip.Wrapper)
    ).toBeVisible();

    await dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('Table - Kitchen Sink')).click();

    await expect(
      dashboardPage.getByGrafanaSelector(selectors.components.Panels.Visualization.TableNG.Tooltip.Wrapper)
    ).not.toBeVisible();

    // when a pinned tooltip is open, clicking inside of it should NOT close it.
    await firstCaret.click();

    await expect(
      dashboardPage.getByGrafanaSelector(selectors.components.Panels.Visualization.TableNG.Tooltip.Wrapper)
    ).toBeVisible();

    const tooltip = dashboardPage.getByGrafanaSelector(
      selectors.components.Panels.Visualization.TableNG.Tooltip.Wrapper
    );
    await tooltip.click();

    await expect(
      dashboardPage.getByGrafanaSelector(selectors.components.Panels.Visualization.TableNG.Tooltip.Wrapper)
    ).toBeVisible();

    await dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('Table - Kitchen Sink')).click();

    await expect(
      dashboardPage.getByGrafanaSelector(selectors.components.Panels.Visualization.TableNG.Tooltip.Wrapper)
    ).not.toBeVisible();
  });

  test('Styling overrides with styling from field', async ({ gotoDashboardPage, selectors, page }) => {
    const dashboardPage = await gotoDashboardPage({
      uid: DASHBOARD_UID,
      queryParams: new URLSearchParams({ editPanel: '1' }),
    });

    await expect(
      dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('Table - Kitchen Sink'))
    ).toBeVisible();

    await waitForTableLoad(page);

    const table = page.locator('.rdg');

    const infoColumnIdx = await getColumnIdx(table, 'Info');
    const dataLinkColumnIdx = await getColumnIdx(table, 'Data Link');
    const stateColumnHeader = page.getByRole('columnheader').nth(infoColumnIdx);

    // filter to only "Up," which we have a style override on.
    await stateColumnHeader.getByTestId(selectors.components.Panels.Visualization.TableNG.Filters.HeaderButton).click();
    const filterContainer = dashboardPage.getByGrafanaSelector(
      selectors.components.Panels.Visualization.TableNG.Filters.Container
    );

    await expect(filterContainer).toBeVisible();

    await filterContainer.getByTitle('up', { exact: true }).locator('label').click();
    await filterContainer.getByRole('button', { name: 'Ok' }).click();

    const cell = getCell(table, 1, dataLinkColumnIdx);
    await expect(cell).toBeVisible();
    await expect(cell).toHaveCSS('text-decoration', /line-through/);

    // now filter out "up," and confirm that the style override isn't present.
    await stateColumnHeader.getByTestId(selectors.components.Panels.Visualization.TableNG.Filters.HeaderButton).click();
    await expect(filterContainer).toBeVisible();

    // select all, then click the first value to unselect it, filtering it out.
    await filterContainer.getByTestId(selectors.components.Panels.Visualization.TableNG.Filters.SelectAll).click();
    await filterContainer.getByTitle('up', { exact: true }).locator('label').click();
    await filterContainer.getByRole('button', { name: 'Ok' }).click();

    await expect(cell).toBeVisible();
    await expect(cell).not.toHaveCSS('text-decoration', /line-through/);
  });

  test('Empty Table panel', async ({ gotoDashboardPage, selectors }) => {
    const dashboardPage = await gotoDashboardPage({
      uid: DASHBOARD_UID,
      queryParams: new URLSearchParams({ editPanel: '3' }),
    });

    await expect(
      dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.PanelDataErrorMessage)
    ).toBeVisible();
    await expect(
      dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('Table - Kitchen Sink'))
    ).not.toBeVisible();
  });
});
