Skip to content
Merged
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
@@ -0,0 +1,4 @@
Significance: patch
Type: changed

Dashboard: Show the no-results message in the Post views, Author performance, Video views and Store performance charts for a period with no data, instead of a flat zero line.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { getDefaultQueryParams, queryClient } from '@jetpack-premium-analytics/data';
import { render, screen } from '@testing-library/react';
import apiFetch from '@wordpress/api-fetch';
import type { ReactNode } from 'react';
/**
* Internal dependencies
*/
Expand All @@ -18,6 +19,7 @@ jest.mock( '@jetpack-premium-analytics/widgets-toolkit', () => ( {
MetricTabsChart: ( {
metrics,
chartType,
empty,
}: {
metrics: {
key: string;
Expand All @@ -27,6 +29,7 @@ jest.mock( '@jetpack-premium-analytics/widgets-toolkit', () => ( {
countLabel?: ( count: number ) => string;
}[];
chartType?: string;
empty?: ReactNode;
} ) => (
<div
data-testid="metric-tabs-chart"
Expand All @@ -40,7 +43,9 @@ jest.mock( '@jetpack-premium-analytics/widgets-toolkit', () => ( {
dates: metric.current.map( point => point.date.toISOString().slice( 0, 10 ) ),
} ) )
) }
/>
>
{ empty }
</div>
),
} ) );

Expand Down Expand Up @@ -200,6 +205,19 @@ describe( 'AuthorPerformanceWidget', () => {
);
} );

it( 'shows the no-results message in the chart for a window without views', async () => {
mockApiFetch.mockResolvedValue( {
...TOP_AUTHORS_DAYS,
days: { '2026-07-02': TOP_AUTHORS_DAYS.days[ '2026-07-02' ] },
} );

render( <AuthorPerformanceWidget attributes={ { reportParams: WINDOW_PARAMS } } /> );

await expect(
screen.findByText( 'We couldn’t find results for this time period.' )
).resolves.toBeInTheDocument();
} );

it( 'renders the scopeless empty state and makes no request without an author scope', async () => {
render( <AuthorPerformanceWidget attributes={ { reportParams: DEFAULT_PARAMS } } /> );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { STATS_CHART_BUCKET_PERIODS, toAuthorId } from '@jetpack-premium-analytics/data';
import { reports } from '@jetpack-premium-analytics/icons';
import {
ChartEmptyState,
MetricTabsChart,
MetricTabsChartSkeleton,
WidgetRoot,
Expand Down Expand Up @@ -97,6 +98,7 @@ function AuthorPerformanceInner( { chartType }: AuthorPerformanceInnerProps ) {
metrics={ metricTabs }
dataFormat={ DATA_FORMAT }
chartType={ chartType }
empty={ <ChartEmptyState /> }
/>
</WidgetState>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { getDefaultQueryParams, queryClient } from '@jetpack-premium-analytics/d
import { render, screen } from '@testing-library/react';
import apiFetch from '@wordpress/api-fetch';
import { getSettings, setSettings } from '@wordpress/date';
import type { ReactNode } from 'react';
/**
* Internal dependencies
*/
Expand All @@ -19,6 +20,7 @@ jest.mock( '@jetpack-premium-analytics/widgets-toolkit', () => ( {
MetricTabsChart: ( {
metrics,
chartType,
empty,
}: {
metrics: {
key: string;
Expand All @@ -29,6 +31,7 @@ jest.mock( '@jetpack-premium-analytics/widgets-toolkit', () => ( {
dataFormat?: { type: string };
}[];
chartType?: string;
empty?: ReactNode;
} ) => (
<div
data-testid="metric-tabs-chart"
Expand All @@ -45,7 +48,9 @@ jest.mock( '@jetpack-premium-analytics/widgets-toolkit', () => ( {
days: metric.current.map( point => point.date.getDate() ),
} ) )
) }
/>
>
{ empty }
</div>
),
} ) );

Expand Down Expand Up @@ -200,6 +205,16 @@ describe( 'PostViewsWidget', () => {
expect( mockApiFetch ).toHaveBeenCalledTimes( 1 );
} );

it( 'shows the no-results message in the chart for a window without views', async () => {
mockApiFetch.mockResolvedValue( { data: [] } );

render( <PostViewsWidget attributes={ { reportParams: WINDOW_PARAMS } } /> );

await expect(
screen.findByText( 'We couldn’t find results for this time period.' )
).resolves.toBeInTheDocument();
} );

it( 'renders the scopeless empty state and makes no request without a post scope', async () => {
render( <PostViewsWidget attributes={ {} } /> );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { STATS_CHART_BUCKET_PERIODS, toPostId } from '@jetpack-premium-analytics/data';
import { reports } from '@jetpack-premium-analytics/icons';
import {
ChartEmptyState,
MetricTabsChart,
MetricTabsChartSkeleton,
WidgetRoot,
Expand Down Expand Up @@ -97,6 +98,7 @@ function PostViewsInner( { chartType }: PostViewsInnerProps ) {
metrics={ metricTabs }
dataFormat={ DATA_FORMAT }
chartType={ chartType }
empty={ <ChartEmptyState /> }
/>
</WidgetState>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* External dependencies
*/
import { render, screen } from '@testing-library/react';
import type { ReactNode } from 'react';
/**
* Internal dependencies
*/
import StorePerformanceRender from '../render';

const mockEmptyReport = {
primary: { data: { summary: {}, data: [] } },
comparison: { data: { summary: {}, data: [] } },
timezone: 'UTC',
isLoading: false,
isFetching: false,
isError: false,
hasData: false,
refetch: jest.fn(),
};

jest.mock( '@jetpack-premium-analytics/data', () => ( {
...jest.requireActual( '@jetpack-premium-analytics/data' ),
useReportOrders: () => mockEmptyReport,
useReportVisitors: () => mockEmptyReport,
useReportConversionRate: () => mockEmptyReport,
useReportCustomersByDate: () => mockEmptyReport,
} ) );

// The chart itself is visx SVG rendering, outside this widget's concern.
jest.mock( '@jetpack-premium-analytics/widgets-toolkit', () => ( {
...jest.requireActual( '@jetpack-premium-analytics/widgets-toolkit' ),
MetricTabsChart: ( { empty }: { empty?: ReactNode } ) => (
<div data-testid="metric-tabs-chart">{ empty }</div>
),
} ) );

// WidgetRoot reads URL search params as a fallback for report params; outside
// a matched route the real hook warns and throws.
jest.mock( '@wordpress/route', () => jest.requireActual( '../../test-utils' ).mockWordPressRoute );

describe( 'StorePerformanceRender', () => {
it( 'shows the no-results message in the chart for a store without orders or visits', () => {
render( <StorePerformanceRender attributes={ {} } /> );

expect(
screen.getByText( 'We couldn’t find results for this time period.' )
).toBeInTheDocument();
} );
} );
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from '@jetpack-premium-analytics/data';
import {
BOOKINGS_FILTER,
ChartEmptyState,
MetricTabsChart,
MetricTabsChartSkeleton,
WidgetRoot,
Expand Down Expand Up @@ -361,6 +362,7 @@ function StorePerformanceContent() {
metrics={ metricTabs }
dataFormat={ DEFAULT_DATA_FORMAT }
groupLabel={ __( 'Store metric', 'jetpack-premium-analytics-pkg' ) }
empty={ <ChartEmptyState /> }
/>
</WidgetState>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { getDefaultQueryParams, queryClient } from '@jetpack-premium-analytics/data';
import { render, screen } from '@testing-library/react';
import apiFetch from '@wordpress/api-fetch';
import type { ReactNode } from 'react';
/**
* Internal dependencies
*/
Expand All @@ -18,6 +19,7 @@ jest.mock( '@jetpack-premium-analytics/widgets-toolkit', () => ( {
MetricTabsChart: ( {
metrics,
chartType,
empty,
}: {
metrics: {
key: string;
Expand All @@ -28,6 +30,7 @@ jest.mock( '@jetpack-premium-analytics/widgets-toolkit', () => ( {
dataFormat?: { type: string };
}[];
chartType?: string;
empty?: ReactNode;
} ) => (
<div
data-testid="metric-tabs-chart"
Expand All @@ -44,7 +47,9 @@ jest.mock( '@jetpack-premium-analytics/widgets-toolkit', () => ( {
days: metric.current.map( point => point.date.getDate() ),
} ) )
) }
/>
>
{ empty }
</div>
),
} ) );

Expand Down Expand Up @@ -321,6 +326,16 @@ describe( 'VideoDetailViewsPerformanceWidget', () => {
expect( metrics[ 0 ].value ).toBe( 12 );
} );

it( 'shows the no-results message in the chart for a window without views', async () => {
mockApiFetch.mockImplementation( respondByWindow( {} ) );

render( <VideoDetailViewsPerformanceWidget attributes={ { reportParams: WINDOW_PARAMS } } /> );

await expect(
screen.findByText( 'We couldn’t find results for this time period.' )
).resolves.toBeInTheDocument();
} );

it( 'renders the scopeless empty state and makes no request without a video scope', async () => {
render( <VideoDetailViewsPerformanceWidget attributes={ {} } /> );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/
import { STATS_CHART_BUCKET_PERIODS, toPostId } from '@jetpack-premium-analytics/data';
import {
ChartEmptyState,
MetricTabsChart,
MetricTabsChartSkeleton,
WidgetRoot,
Expand Down Expand Up @@ -81,6 +82,7 @@ function VideoDetailViewsPerformanceInner( { chartType }: VideoDetailViewsPerfor
dataFormat={ COUNT_FORMAT }
chartType={ chartType }
groupLabel={ groupLabel }
empty={ <ChartEmptyState /> }
/>
</WidgetState>
</div>
Expand Down
Loading