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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { AnalyticsChart as AnalyticsChartType, BarChart as BarChartType, TimeSer

type Props = {
chartData: AnalyticsChartType;
testId?: string;
};

const TableWrapper = styled.div`
Expand Down Expand Up @@ -139,9 +140,15 @@ type StackedBarChartProps = {
stackedBarChartData: any[];
allSegmentLabels: string[];
segmentColors: string[];
testId?: string;
};

const StackedBarChartWithTooltip = ({ stackedBarChartData, allSegmentLabels, segmentColors }: StackedBarChartProps) => {
const StackedBarChartWithTooltip = ({
stackedBarChartData,
allSegmentLabels,
segmentColors,
testId,
}: StackedBarChartProps) => {
const theme = useTheme();
const { tooltipData, tooltipLeft, tooltipTop, showTooltip, hideTooltip } = useTooltip<{
label: string;
Expand Down Expand Up @@ -276,7 +283,7 @@ const StackedBarChartWithTooltip = ({ stackedBarChartData, allSegmentLabels, seg
);

return (
<ChartWithLegendContainer>
<ChartWithLegendContainer data-testid={testId}>
<ChartArea ref={setContainerRefs}>
<ParentSize>
{({ width, height }) =>
Expand Down Expand Up @@ -391,6 +398,7 @@ const StackedBarChartWithTooltip = ({ stackedBarChartData, allSegmentLabels, seg
return (
<LegendItem
key={segmentLabel}
data-testid={`analytics-entity-type-${segmentLabel.toLowerCase()}`}
$isSelected={isSelected}
onClick={() => handleLegendClick(segmentLabel)}
>
Expand All @@ -405,7 +413,7 @@ const StackedBarChartWithTooltip = ({ stackedBarChartData, allSegmentLabels, seg
);
};

export const AnalyticsChart = ({ chartData }: Props) => {
export const AnalyticsChart = ({ chartData, testId }: Props) => {
const theme = useTheme();
const isTable = chartData.__typename === 'TableChart';

Expand Down Expand Up @@ -513,6 +521,7 @@ export const AnalyticsChart = ({ chartData }: Props) => {
stackedBarChartData={stackedBarChartData}
allSegmentLabels={allSegmentLabels}
segmentColors={segmentColors}
testId={testId}
/>
)}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ export const AnalyticsPage = () => {
<ChartGroup
chartGroup={{ ...chartGroup, title: t('dataLandscapeSummary') }}
key={chartGroup.title}
testId="analytics-landscape-summary"
/>
))}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,20 @@ const ChartCol = styled(Col)`

type Props = {
chartGroup: AnalyticsChartGroup;
testId?: string;
};

export const ChartGroup = ({ chartGroup }: Props) => {
export const ChartGroup = ({ chartGroup, testId }: Props) => {
return (
<Container>
<Container data-testid={testId}>
{chartGroup.title?.length > 0 && <PageTitle title={chartGroup.title} variant="sectionHeader" />}
<Row gutter={[16, 16]}>
{chartGroup.charts.map((chart) => (
<ChartCol key={chart.title} sm={24} md={24} lg={8} xl={8}>
<AnalyticsChart chartData={chart} />
<AnalyticsChart
chartData={chart}
testId={`analytics-${chart.title?.toLowerCase().replace(/\s+/g, '-')}`}
/>
</ChartCol>
))}
</Row>
Expand Down
100 changes: 100 additions & 0 deletions e2e-test/ui/playwright/pages/analytics.page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import type { Page, Locator } from '@playwright/test';
import { expect } from '@playwright/test';
import { BasePage } from './base.page';
import type { DataHubLogger } from '../utils/logger';
import { TIMEOUTS, LOAD_STATES } from '../utils/constants';

/**
* Analytics page object — semantic methods for core workflows.
*
* Methods combine related operations (navigation + verification) to reduce redundancy.
*/
export class AnalyticsPage extends BasePage {
private readonly entityHeader: Locator;
private readonly landscapeSummarySection: Locator;
private readonly tabViewsChart: Locator;

constructor(
readonly page: Page,
protected readonly logger?: DataHubLogger,
protected readonly logDir?: string,
) {
super(page, logger, logDir);
this.entityHeader = this.page.getByTestId('entity-header-test-id');
this.landscapeSummarySection = this.page.getByTestId('analytics-landscape-summary');
this.tabViewsChart = this.page.getByTestId('analytics-tab-views-by-entity-type-(past-week)');
}

// Helper selectors for dynamic elements
private getTabSelector(tabName: string): Locator {
return this.page.getByRole('tab', { name: tabName });
}

private getLegendItemSelector(tabName: string): Locator {
return this.page.getByTestId(`analytics-entity-type-${tabName.toLowerCase()}`);
}

/**
* Navigate to chart and wait for load.
*/
async goToChart(urn: string): Promise<void> {
this.logger?.step('navigate to chart', { urn });
await this.navigate(`/chart/${urn}`);
await this.page.waitForLoadState(LOAD_STATES.NETWORKIDLE);
}

/**
* Navigate to analytics page and wait for load.
*/
async goToAnalytics(): Promise<void> {
this.logger?.step('navigate to analytics', {});
await this.navigate('/analytics');
await this.page.waitForLoadState(LOAD_STATES.NETWORKIDLE);
}

/**
* Verify chart title is visible in entity header.
*/
async verifyChartTitle(title: string): Promise<void> {
this.logger?.step('verify chart title', { title });
await expect(this.entityHeader.getByText(title)).toBeVisible({ timeout: TIMEOUTS.MEDIUM });
}

/**
* Verify Data Landscape Summary section is visible.
*/
async verifyLandscapeSummaryVisible(): Promise<void> {
this.logger?.step('verify landscape summary visible', {});
await expect(this.landscapeSummarySection).toBeVisible({ timeout: TIMEOUTS.SHORT });
}

/**
* Click on entity tab (e.g., Dashboards, Summary) and wait for content to load.
*/
async clickTab(tabName: string): Promise<void> {
this.logger?.step('click tab', { tabName });
const tab = this.getTabSelector(tabName);
await expect(tab).toBeVisible();
await tab.click();
// Wait for tab content to load after click
await this.page.waitForLoadState(LOAD_STATES.NETWORKIDLE);
}

/**
* Verify Tab Views chart is visible and scroll into viewport if needed.
*/
async verifyTabViewsChartVisible(): Promise<void> {
this.logger?.step('verify Tab Views chart visible', {});
await expect(this.tabViewsChart).toBeVisible({ timeout: TIMEOUTS.LONG });
await this.tabViewsChart.scrollIntoViewIfNeeded();
}

/**
* Verify tab interaction appears in chart legend (indicates tab click was tracked).
*/
async verifyTabInteractionTracked(tabName: string): Promise<void> {
this.logger?.step('verify tab interaction tracked', { tabName });
const legendItem = this.getLegendItemSelector(tabName);
await expect(legendItem).toBeVisible({ timeout: TIMEOUTS.SHORT });
}
}
41 changes: 41 additions & 0 deletions e2e-test/ui/playwright/tests/analytics/analytics.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Analytics Tests — Verify that user interactions (tab clicks) are tracked and visible in analytics.
*
* Core Behavior:
* - User opens a chart and clicks a tab (Dashboards)
* - This interaction is tracked by the system
* - Analytics page shows the tracked "dashboards" interaction in the Tab Views chart
*
* Test Data:
* Uses global Playwright test data (test-data/data.json):
* - Chart: urn:li:chart:(looker,playwright_baz1) — "Baz Chart 1"
* - Pre-seeded in all test environments
*/

import { test } from '../../fixtures/base-test';
import { AnalyticsPage } from '../../pages/analytics.page';

test.describe('Analytics', () => {
let analyticsPage: AnalyticsPage;

test.beforeEach(async ({ logger, logDir, page }) => {
analyticsPage = new AnalyticsPage(page, logger, logDir);
});

test('can view analytics dashboard with Data Landscape Summary', async () => {
await analyticsPage.goToAnalytics();
await analyticsPage.verifyLandscapeSummaryVisible();
});

test('can track tab interactions and see them in analytics', async () => {
const chartUrn = 'urn:li:chart:(looker,playwright_baz1)';
const chartTitle = 'Baz Chart 1';

await analyticsPage.goToChart(chartUrn);
await analyticsPage.verifyChartTitle(chartTitle);
await analyticsPage.clickTab('Dashboards');
await analyticsPage.goToAnalytics();
await analyticsPage.verifyTabViewsChartVisible();
await analyticsPage.verifyTabInteractionTracked('dashboards');
});
});
Loading