mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Add OTel K8S e2e test for Ensemble (#206756)
This adds an e2e test for [the Ensemble workflow](https://github.com/elastic/ensemble/actions/workflows/nightly.yml) to cover stack installation part of the OTel K8S quickstart flow. Besides that I've replaced the retry logic for K8S EA and Auto Detect flow with a simple timeouts to workaround the missing data issue on the CTA pages (host details and k8s dashboard) after finishing the onboarding flow. I've also simplified assertions on the CTA pages.
This commit is contained in:
parent
cd71ca903b
commit
ad30ed8d69
11 changed files with 232 additions and 133 deletions
|
@ -36,6 +36,19 @@ test('Auto-detect logs and metrics', async ({ page, onboardingHomePage, autoDete
|
|||
fs.writeFileSync(outputPath, clipboardData);
|
||||
|
||||
await autoDetectFlowPage.assertReceivedDataIndicator();
|
||||
|
||||
/**
|
||||
* Host Details page sometime shows "No Data"
|
||||
* even when we've detected data during
|
||||
* the onboarding flow. This is most prominent
|
||||
* in a test script which click on the "Explore Data"
|
||||
* CTA immediately. Having a timeout before going
|
||||
* to the Host Details page "solves" the issue.
|
||||
* 2 minutes is generous and should be more then enough
|
||||
* for the data to propagate everywhere.
|
||||
*/
|
||||
await page.waitForTimeout(2 * 60000);
|
||||
|
||||
await autoDetectFlowPage.clickAutoDetectSystemIntegrationCTA();
|
||||
|
||||
/**
|
||||
|
@ -44,22 +57,5 @@ test('Auto-detect logs and metrics', async ({ page, onboardingHomePage, autoDete
|
|||
*/
|
||||
const hostDetailsPage = new HostDetailsPage(await page.waitForEvent('popup'));
|
||||
|
||||
/**
|
||||
* There is a glitch on the Hosts page where it can show "No data"
|
||||
* screen even though data is available and it can show it with a delay
|
||||
* after the Hosts page layout was loaded. This workaround waits for
|
||||
* the No Data screen to be visible, and if so - reloads the page.
|
||||
* If the No Data screen does not appear, the test can proceed normally.
|
||||
* Seems like some caching issue with the Hosts page.
|
||||
*/
|
||||
try {
|
||||
await hostDetailsPage.noData().waitFor({ state: 'visible', timeout: 10000 });
|
||||
await hostDetailsPage.page.waitForTimeout(2000);
|
||||
await hostDetailsPage.page.reload();
|
||||
} catch {
|
||||
/* Ignore if "No Data" screen never showed up */
|
||||
}
|
||||
|
||||
await hostDetailsPage.clickHostDetailsLogsTab();
|
||||
await hostDetailsPage.assertHostDetailsLogsStream();
|
||||
await hostDetailsPage.assertCpuPercentageNotEmpty();
|
||||
});
|
||||
|
|
|
@ -12,6 +12,8 @@ import { SpaceSelector } from '../pom/components/space_selector.component';
|
|||
import { KubernetesOverviewDashboardPage } from '../pom/pages/kubernetes_overview_dashboard.page';
|
||||
import { AutoDetectFlowPage } from '../pom/pages/auto_detect_flow.page';
|
||||
import { KubernetesEAFlowPage } from '../pom/pages/kubernetes_ea_flow.page';
|
||||
import { OtelKubernetesFlowPage } from '../pom/pages/otel_kubernetes_flow.page';
|
||||
import { OtelKubernetesOverviewDashboardPage } from '../pom/pages/otel_kubernetes_overview_dashboard.page';
|
||||
|
||||
export const test = base.extend<{
|
||||
headerBar: HeaderBar;
|
||||
|
@ -19,7 +21,9 @@ export const test = base.extend<{
|
|||
onboardingHomePage: OnboardingHomePage;
|
||||
autoDetectFlowPage: AutoDetectFlowPage;
|
||||
kubernetesEAFlowPage: KubernetesEAFlowPage;
|
||||
otelKubernetesFlowPage: OtelKubernetesFlowPage;
|
||||
kubernetesOverviewDashboardPage: KubernetesOverviewDashboardPage;
|
||||
otelKubernetesOverviewDashboardPage: OtelKubernetesOverviewDashboardPage;
|
||||
}>({
|
||||
headerBar: async ({ page }, use) => {
|
||||
await use(new HeaderBar(page));
|
||||
|
@ -41,7 +45,15 @@ export const test = base.extend<{
|
|||
await use(new KubernetesEAFlowPage(page));
|
||||
},
|
||||
|
||||
otelKubernetesFlowPage: async ({ page }, use) => {
|
||||
await use(new OtelKubernetesFlowPage(page));
|
||||
},
|
||||
|
||||
kubernetesOverviewDashboardPage: async ({ page }, use) => {
|
||||
await use(new KubernetesOverviewDashboardPage(page));
|
||||
},
|
||||
|
||||
otelKubernetesOverviewDashboardPage: async ({ page }, use) => {
|
||||
await use(new OtelKubernetesOverviewDashboardPage(page));
|
||||
},
|
||||
});
|
||||
|
|
|
@ -45,22 +45,19 @@ test('Kubernetes EA', async ({
|
|||
fs.writeFileSync(outputPath, clipboardData);
|
||||
|
||||
await kubernetesEAFlowPage.assertReceivedDataIndicatorKubernetes();
|
||||
await kubernetesEAFlowPage.clickKubernetesAgentCTA();
|
||||
|
||||
await kubernetesOverviewDashboardPage.openNodesInspector();
|
||||
/**
|
||||
* There might be a case that dashboard still does not show
|
||||
* the data even though it was ingested already. This usually
|
||||
* happens during in the test when navigation from the onboarding
|
||||
* happens during the test when navigation from the onboarding
|
||||
* flow to the dashboard happens almost immediately.
|
||||
* Waiting for a few seconds and reloading the page handles
|
||||
* this case and makes the test a bit more robust.
|
||||
* Having a timeout before going to the dashboard "solves"
|
||||
* the issue. 2 minutes is generous and should be more then enough
|
||||
* for the data to propagate everywhere.
|
||||
*/
|
||||
try {
|
||||
await kubernetesOverviewDashboardPage.assertNodesNoResultsNotVisible();
|
||||
} catch {
|
||||
await kubernetesOverviewDashboardPage.page.waitForTimeout(2000);
|
||||
await kubernetesOverviewDashboardPage.page.reload();
|
||||
}
|
||||
await kubernetesOverviewDashboardPage.assetNodesInspectorStatusTableCells();
|
||||
await page.waitForTimeout(2 * 60000);
|
||||
|
||||
await kubernetesEAFlowPage.clickKubernetesAgentCTA();
|
||||
|
||||
await kubernetesOverviewDashboardPage.assertNodesPanelNotEmpty();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { test } from './fixtures/base_page';
|
||||
import { assertEnv } from '../lib/assert_env';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto(`${process.env.KIBANA_BASE_URL}/app/observabilityOnboarding`);
|
||||
});
|
||||
|
||||
test('Otel Kubernetes', async ({
|
||||
page,
|
||||
onboardingHomePage,
|
||||
otelKubernetesFlowPage,
|
||||
otelKubernetesOverviewDashboardPage,
|
||||
}) => {
|
||||
assertEnv(process.env.ARTIFACTS_FOLDER, 'ARTIFACTS_FOLDER is not defined.');
|
||||
|
||||
const fileName = 'code_snippet_otel_kubernetes.sh';
|
||||
const outputPath = path.join(__dirname, '..', process.env.ARTIFACTS_FOLDER, fileName);
|
||||
|
||||
await onboardingHomePage.selectKubernetesUseCase();
|
||||
await onboardingHomePage.selectOtelKubernetesQuickstart();
|
||||
|
||||
await otelKubernetesFlowPage.copyHelmRepositorySnippetToClipboard();
|
||||
const helmRepoSnippet = (await page.evaluate('navigator.clipboard.readText()')) as string;
|
||||
|
||||
await otelKubernetesFlowPage.copyInstallStackSnippetToClipboard();
|
||||
const installStackSnippet = (await page.evaluate('navigator.clipboard.readText()')) as string;
|
||||
|
||||
const codeSnippet = `${helmRepoSnippet}\n${installStackSnippet}`;
|
||||
|
||||
/**
|
||||
* Ensemble story watches for the code snippet file
|
||||
* to be created and then executes it
|
||||
*/
|
||||
fs.writeFileSync(outputPath, codeSnippet);
|
||||
|
||||
/**
|
||||
* There is no explicit data ingest indication
|
||||
* in the flow, so we need to rely on a timeout.
|
||||
* 3 minutes should be enough for the stack to be
|
||||
* created and to start pushing data.
|
||||
*/
|
||||
await page.waitForTimeout(3 * 60000);
|
||||
|
||||
await otelKubernetesFlowPage.clickClusterOverviewDashboardCTA();
|
||||
await otelKubernetesOverviewDashboardPage.assertNodesPanelNotEmpty();
|
||||
});
|
|
@ -5,47 +5,46 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { expect, Page } from '@playwright/test';
|
||||
import { expect, type Page, type Locator } from '@playwright/test';
|
||||
|
||||
export class AutoDetectFlowPage {
|
||||
page: Page;
|
||||
|
||||
private readonly copyToClipboardButton: Locator;
|
||||
private readonly receivedDataIndicator: Locator;
|
||||
private readonly autoDetectSystemIntegrationActionLink: Locator;
|
||||
private readonly codeBlock: Locator;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
private readonly copyToClipboardButton = () =>
|
||||
this.page.getByTestId('observabilityOnboardingCopyToClipboardButton');
|
||||
|
||||
private readonly receivedDataIndicator = () =>
|
||||
this.page
|
||||
this.copyToClipboardButton = this.page.getByTestId(
|
||||
'observabilityOnboardingCopyToClipboardButton'
|
||||
);
|
||||
this.receivedDataIndicator = this.page
|
||||
.getByTestId('observabilityOnboardingAutoDetectPanelDataReceivedProgressIndicator')
|
||||
.getByText('Your data is ready to explore!');
|
||||
|
||||
private readonly autoDetectSystemIntegrationActionLink = () =>
|
||||
this.page.getByTestId(
|
||||
this.autoDetectSystemIntegrationActionLink = this.page.getByTestId(
|
||||
'observabilityOnboardingDataIngestStatusActionLink-inventory-host-details'
|
||||
);
|
||||
|
||||
private readonly codeBlock = () =>
|
||||
this.page.getByTestId('observabilityOnboardingAutoDetectPanelCodeSnippet');
|
||||
this.codeBlock = this.page.getByTestId('observabilityOnboardingAutoDetectPanelCodeSnippet');
|
||||
}
|
||||
|
||||
public async copyToClipboard() {
|
||||
await this.copyToClipboardButton().click();
|
||||
await this.copyToClipboardButton.click();
|
||||
}
|
||||
|
||||
public async assertVisibilityCodeBlock() {
|
||||
await expect(this.codeBlock(), 'Code block should be visible').toBeVisible();
|
||||
await expect(this.codeBlock, 'Code block should be visible').toBeVisible();
|
||||
}
|
||||
|
||||
public async assertReceivedDataIndicator() {
|
||||
await expect(
|
||||
this.receivedDataIndicator(),
|
||||
this.receivedDataIndicator,
|
||||
'Received data indicator should be visible'
|
||||
).toBeVisible();
|
||||
}
|
||||
|
||||
public async clickAutoDetectSystemIntegrationCTA() {
|
||||
await this.autoDetectSystemIntegrationActionLink().click();
|
||||
await this.autoDetectSystemIntegrationActionLink.click();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,34 +5,23 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { expect, Page } from '@playwright/test';
|
||||
import { expect, type Page, type Locator } from '@playwright/test';
|
||||
|
||||
export class HostDetailsPage {
|
||||
page: Page;
|
||||
|
||||
public readonly hostDetailsLogsTab = () => this.page.getByTestId('infraAssetDetailsLogsTab');
|
||||
|
||||
private readonly hostDetailsLogsStream = () => this.page.getByTestId('logStream');
|
||||
|
||||
public readonly noData = () => this.page.getByTestId('kbnNoDataPage');
|
||||
private readonly cpuPercentageValue: Locator;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
|
||||
this.cpuPercentageValue = this.page
|
||||
.getByTestId('infraAssetDetailsKPIcpuUsage')
|
||||
.locator('.echMetricText__value');
|
||||
}
|
||||
|
||||
public async clickHostDetailsLogsTab() {
|
||||
await this.hostDetailsLogsTab().click();
|
||||
}
|
||||
|
||||
public async assertHostDetailsLogsStream() {
|
||||
await expect(
|
||||
this.hostDetailsLogsStream(),
|
||||
'Host details log stream should be visible'
|
||||
/**
|
||||
* Using toBeAttached() instead of toBeVisible() because the element
|
||||
* we're selecting here has a bit weird layout with 0 height and
|
||||
* overflowing child elements. 0 height makes toBeVisible() fail.
|
||||
*/
|
||||
).toBeAttached();
|
||||
public async assertCpuPercentageNotEmpty() {
|
||||
await expect(this.cpuPercentageValue).toBeVisible();
|
||||
expect(await this.cpuPercentageValue.textContent()).toMatch(/\d+%$/);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,47 +5,47 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { expect, Page } from '@playwright/test';
|
||||
import { expect, type Page, type Locator } from '@playwright/test';
|
||||
|
||||
export class KubernetesEAFlowPage {
|
||||
page: Page;
|
||||
|
||||
private readonly receivedDataIndicatorKubernetes: Locator;
|
||||
private readonly kubernetesAgentExploreDataActionLink: Locator;
|
||||
private readonly codeBlock: Locator;
|
||||
private readonly copyToClipboardButton: Locator;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
private readonly receivedDataIndicatorKubernetes = () =>
|
||||
this.page
|
||||
this.receivedDataIndicatorKubernetes = this.page
|
||||
.getByTestId('observabilityOnboardingKubernetesPanelDataProgressIndicator')
|
||||
.getByText('We are monitoring your cluster');
|
||||
|
||||
private readonly kubernetesAgentExploreDataActionLink = () =>
|
||||
this.page.getByTestId(
|
||||
this.kubernetesAgentExploreDataActionLink = this.page.getByTestId(
|
||||
'observabilityOnboardingDataIngestStatusActionLink-kubernetes-f4dc26db-1b53-4ea2-a78b-1bfab8ea267c'
|
||||
);
|
||||
|
||||
private readonly codeBlock = () =>
|
||||
this.page.getByTestId('observabilityOnboardingKubernetesPanelCodeSnippet');
|
||||
|
||||
private readonly copyToClipboardButton = () =>
|
||||
this.page.getByTestId('observabilityOnboardingCopyToClipboardButton');
|
||||
this.codeBlock = this.page.getByTestId('observabilityOnboardingKubernetesPanelCodeSnippet');
|
||||
this.copyToClipboardButton = this.page.getByTestId(
|
||||
'observabilityOnboardingCopyToClipboardButton'
|
||||
);
|
||||
}
|
||||
|
||||
public async assertVisibilityCodeBlock() {
|
||||
await expect(this.codeBlock(), 'Code block should be visible').toBeVisible();
|
||||
await expect(this.codeBlock, 'Code block should be visible').toBeVisible();
|
||||
}
|
||||
|
||||
public async copyToClipboard() {
|
||||
await this.copyToClipboardButton().click();
|
||||
await this.copyToClipboardButton.click();
|
||||
}
|
||||
|
||||
public async assertReceivedDataIndicatorKubernetes() {
|
||||
await expect(
|
||||
this.receivedDataIndicatorKubernetes(),
|
||||
this.receivedDataIndicatorKubernetes,
|
||||
'Received data indicator should be visible'
|
||||
).toBeVisible();
|
||||
}
|
||||
|
||||
public async clickKubernetesAgentCTA() {
|
||||
await this.kubernetesAgentExploreDataActionLink().click();
|
||||
await this.kubernetesAgentExploreDataActionLink.click();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,44 +5,22 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { expect, Page } from '@playwright/test';
|
||||
import { expect, type Page, type Locator } from '@playwright/test';
|
||||
|
||||
export class KubernetesOverviewDashboardPage {
|
||||
page: Page;
|
||||
|
||||
private readonly nodesPanelChart: Locator;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
|
||||
this.nodesPanelChart = this.page
|
||||
.locator(`#panel-7116207b-48ce-4d93-9fbd-26d73af1c185`)
|
||||
.getByTestId('xyVisChart');
|
||||
}
|
||||
|
||||
private readonly nodesPanelHeader = () => this.page.getByTestId('embeddablePanelHeading-Nodes');
|
||||
|
||||
private readonly nodesInspectorButton = () =>
|
||||
this.page
|
||||
.getByTestId('embeddablePanelHoverActions-Nodes')
|
||||
.getByTestId('embeddablePanelAction-openInspector');
|
||||
|
||||
private readonly nodesInspectorTableNoResults = () =>
|
||||
this.page.getByTestId('inspectorTable').getByText('No items found');
|
||||
|
||||
private readonly nodesInspectorTableStatusTableCells = () =>
|
||||
this.page.getByTestId('inspectorTable').getByText('Status');
|
||||
|
||||
public async assertNodesNoResultsNotVisible() {
|
||||
await expect(
|
||||
this.nodesInspectorTableNoResults(),
|
||||
'Nodes "No results" message should not be visible'
|
||||
).toBeHidden();
|
||||
}
|
||||
|
||||
public async openNodesInspector() {
|
||||
await this.nodesPanelHeader().hover();
|
||||
await this.nodesInspectorButton().click();
|
||||
}
|
||||
|
||||
public async assetNodesInspectorStatusTableCells() {
|
||||
await expect(
|
||||
this.nodesInspectorTableStatusTableCells(),
|
||||
'Status table cell should exist'
|
||||
).toBeVisible();
|
||||
async assertNodesPanelNotEmpty() {
|
||||
await expect(this.nodesPanelChart).toBeVisible();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,40 +5,50 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { Page } from '@playwright/test';
|
||||
import type { Page, Locator } from '@playwright/test';
|
||||
|
||||
export class OnboardingHomePage {
|
||||
page: Page;
|
||||
|
||||
private readonly otelKubernetesQuickStartCard: Locator;
|
||||
private readonly useCaseKubernetes: Locator;
|
||||
private readonly kubernetesQuickStartCard: Locator;
|
||||
private readonly useCaseHost: Locator;
|
||||
private readonly autoDetectElasticAgent: Locator;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
|
||||
this.otelKubernetesQuickStartCard = this.page.getByTestId('integration-card:otel-kubernetes');
|
||||
this.useCaseKubernetes = this.page
|
||||
.getByTestId('observabilityOnboardingUseCaseCard-kubernetes')
|
||||
.getByRole('radio');
|
||||
this.kubernetesQuickStartCard = this.page.getByTestId(
|
||||
'integration-card:kubernetes-quick-start'
|
||||
);
|
||||
this.useCaseHost = this.page
|
||||
.getByTestId('observabilityOnboardingUseCaseCard-host')
|
||||
.getByRole('radio');
|
||||
this.autoDetectElasticAgent = this.page.getByTestId('integration-card:auto-detect-logs');
|
||||
}
|
||||
|
||||
private readonly useCaseKubernetes = () =>
|
||||
this.page.getByTestId('observabilityOnboardingUseCaseCard-kubernetes').getByRole('radio');
|
||||
|
||||
private readonly kubernetesQuickStartCard = () =>
|
||||
this.page.getByTestId('integration-card:kubernetes-quick-start');
|
||||
|
||||
private readonly useCaseHost = () =>
|
||||
this.page.getByTestId('observabilityOnboardingUseCaseCard-host').getByRole('radio');
|
||||
|
||||
private readonly autoDetectElasticAgent = () =>
|
||||
this.page.getByTestId('integration-card:auto-detect-logs');
|
||||
|
||||
public async selectHostUseCase() {
|
||||
await this.useCaseHost().click();
|
||||
await this.useCaseHost.click();
|
||||
}
|
||||
|
||||
public async selectKubernetesUseCase() {
|
||||
await this.useCaseKubernetes().click();
|
||||
await this.useCaseKubernetes.click();
|
||||
}
|
||||
|
||||
public async selectAutoDetectWithElasticAgent() {
|
||||
await this.autoDetectElasticAgent().click();
|
||||
await this.autoDetectElasticAgent.click();
|
||||
}
|
||||
|
||||
public async selectKubernetesQuickstart() {
|
||||
await this.kubernetesQuickStartCard().click();
|
||||
await this.kubernetesQuickStartCard.click();
|
||||
}
|
||||
|
||||
public async selectOtelKubernetesQuickstart() {
|
||||
await this.otelKubernetesQuickStartCard.click();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { Page } from '@playwright/test';
|
||||
|
||||
export class OtelKubernetesFlowPage {
|
||||
page: Page;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
public async copyHelmRepositorySnippetToClipboard() {
|
||||
await this.page
|
||||
.getByTestId('observabilityOnboardingOtelKubernetesPanelAddRepositoryCopyToClipboard')
|
||||
.click();
|
||||
}
|
||||
|
||||
public async copyInstallStackSnippetToClipboard() {
|
||||
await this.page
|
||||
.getByTestId('observabilityOnboardingOtelKubernetesPanelInstallStackCopyToClipboard')
|
||||
.click();
|
||||
}
|
||||
|
||||
public async clickClusterOverviewDashboardCTA() {
|
||||
await this.page
|
||||
.getByTestId(
|
||||
'observabilityOnboardingDataIngestStatusActionLink-kubernetes_otel-cluster-overview'
|
||||
)
|
||||
.click();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { expect, type Page, type Locator } from '@playwright/test';
|
||||
|
||||
export class OtelKubernetesOverviewDashboardPage {
|
||||
page: Page;
|
||||
|
||||
private readonly nodesPanelValue: Locator;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
|
||||
this.nodesPanelValue = this.page.locator(
|
||||
`#panel-6119419c-1899-4765-aed4-c050cde4c30a .echMetricText__value`
|
||||
);
|
||||
}
|
||||
|
||||
async assertNodesPanelNotEmpty() {
|
||||
await expect(this.nodesPanelValue).toBeVisible();
|
||||
expect(await this.nodesPanelValue.textContent()).toMatch(/\d+/);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue