mirror of
https://github.com/SigNoz/signoz.git
synced 2026-10-17 07:30:45 +01:00
Compare commits
3 Commits
ci/e2e-pul
...
feat/saved
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d6fb4c3ca | ||
|
|
bbf1855269 | ||
|
|
f156b7cc0a |
@@ -300,20 +300,17 @@ describe('PrivateRoute', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should redirect /logs-save-views to /logs/saved-views', () => {
|
||||
renderPrivateRoute({ initialRoute: '/logs-save-views' });
|
||||
it.each([
|
||||
['/logs-save-views', ROUTES.LOGS_EXPLORER],
|
||||
['/traces-save-views', ROUTES.TRACES_EXPLORER],
|
||||
[ROUTES.LOGS_SAVE_VIEWS, ROUTES.LOGS_EXPLORER],
|
||||
[ROUTES.TRACES_SAVE_VIEWS, ROUTES.TRACES_EXPLORER],
|
||||
[ROUTES.METRICS_EXPLORER_VIEWS, ROUTES.METRICS_EXPLORER_EXPLORER],
|
||||
[ROUTES.METER_EXPLORER_VIEWS, ROUTES.METER_EXPLORER],
|
||||
])('should redirect the old views route %s to %s', (from, to) => {
|
||||
renderPrivateRoute({ initialRoute: from });
|
||||
|
||||
expect(screen.getByTestId('location-display')).toHaveTextContent(
|
||||
'/logs/saved-views',
|
||||
);
|
||||
});
|
||||
|
||||
it('should redirect /traces-save-views to /traces/saved-views', () => {
|
||||
renderPrivateRoute({ initialRoute: '/traces-save-views' });
|
||||
|
||||
expect(screen.getByTestId('location-display')).toHaveTextContent(
|
||||
'/traces/saved-views',
|
||||
);
|
||||
expect(screen.getByTestId('location-display').textContent).toBe(to);
|
||||
});
|
||||
|
||||
it('should redirect /settings/access-tokens to /settings/service-accounts', () => {
|
||||
@@ -1635,11 +1632,6 @@ describe('PrivateRoute', () => {
|
||||
['LIST_LICENSES', ROUTES.LIST_LICENSES, USER_ROLES.EDITOR as ROLES],
|
||||
['ONBOARDING', ROUTES.ONBOARDING, USER_ROLES.VIEWER as ROLES],
|
||||
['APPLICATION', ROUTES.APPLICATION, USER_ROLES.ANONYMOUS as ROLES],
|
||||
[
|
||||
'METRICS_EXPLORER_VIEWS',
|
||||
ROUTES.METRICS_EXPLORER_VIEWS,
|
||||
USER_ROLES.ANONYMOUS as ROLES,
|
||||
],
|
||||
];
|
||||
|
||||
it.each(authzRouteRolePairs)(
|
||||
|
||||
@@ -513,8 +513,12 @@ export const LIST_LICENSES: AppRoutes = {
|
||||
export const oldNewRoutesMapping: Record<string, string> = {
|
||||
'/pipelines': '/logs/pipelines',
|
||||
'/logs-explorer': '/logs/logs-explorer',
|
||||
'/logs-save-views': '/logs/saved-views',
|
||||
'/traces-save-views': '/traces/saved-views',
|
||||
'/logs-save-views': '/logs/logs-explorer',
|
||||
'/traces-save-views': '/traces-explorer',
|
||||
'/logs/saved-views': '/logs/logs-explorer',
|
||||
'/traces/saved-views': '/traces-explorer',
|
||||
'/metrics-explorer/views': '/metrics-explorer/explorer',
|
||||
'/meter/explorer/views': '/meter/explorer',
|
||||
'/settings/access-tokens': '/settings/service-accounts',
|
||||
'/settings/api-keys': '/settings/service-accounts',
|
||||
'/messaging-queues': '/messaging-queues/overview',
|
||||
|
||||
@@ -14,6 +14,7 @@ import * as useQueryBuilderHooks from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import * as useHandleExplorerTabChangeHooks from 'hooks/useHandleExplorerTabChange';
|
||||
import * as appContextHooks from 'providers/App/App';
|
||||
import { ErrorModalProvider } from 'providers/ErrorModalProvider';
|
||||
import { PreferenceContextProvider } from 'providers/preferences/context/PreferenceContextProvider';
|
||||
import * as timezoneHooks from 'providers/Timezone';
|
||||
import store from 'store';
|
||||
import { LicenseEvent } from 'types/api/licensesV3/getActive';
|
||||
@@ -147,7 +148,9 @@ function renderExplorer(): void {
|
||||
<MemoryRouter>
|
||||
<Provider store={store}>
|
||||
<ErrorModalProvider>
|
||||
<Explorer />
|
||||
<PreferenceContextProvider>
|
||||
<Explorer />
|
||||
</PreferenceContextProvider>
|
||||
</ErrorModalProvider>
|
||||
</Provider>
|
||||
</MemoryRouter>
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
import getLocalStorageKey from 'api/browser/localstorage/get';
|
||||
import { LOCALSTORAGE } from 'constants/localStorage';
|
||||
import { useState } from 'react';
|
||||
|
||||
export function useSavedViewEnabled(): boolean {
|
||||
const [isEnabled] = useState(
|
||||
() => getLocalStorageKey(LOCALSTORAGE.SAVED_VIEW_ENABLED) === 'true',
|
||||
);
|
||||
|
||||
return isEnabled;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/**
|
||||
* AI-owned. Generated and maintained by the `signoz-page-story` skill.
|
||||
* Do not hand-edit: regenerate instead.
|
||||
*/
|
||||
|
||||
import ROUTES from 'constants/routes';
|
||||
import { rest } from 'msw';
|
||||
|
||||
import { countControl } from '@/storybook/controls/controls';
|
||||
import { defineStoryMocks } from '@/storybook/controls/defineStoryMocks';
|
||||
|
||||
import {
|
||||
logsSavedViewsResponse,
|
||||
SAVED_VIEW_MAX,
|
||||
SAVED_VIEWS_PAGE_SIZE,
|
||||
savedViewWriteResponse,
|
||||
} from './__story_mockdata__/savedViews';
|
||||
|
||||
const LIST = 'Views · list';
|
||||
|
||||
export const savedViewsMocks = defineStoryMocks({
|
||||
controls: {
|
||||
views: countControl('Saved views', {
|
||||
group: LIST,
|
||||
description: `The views the org saved for logs. Past ${SAVED_VIEWS_PAGE_SIZE} the table paginates.`,
|
||||
value: 4,
|
||||
max: SAVED_VIEW_MAX,
|
||||
}),
|
||||
},
|
||||
handlers: (values, response) => [
|
||||
rest.get(
|
||||
'http://localhost/api/v1/explorer/views',
|
||||
response.json(() => logsSavedViewsResponse(values.views)),
|
||||
),
|
||||
|
||||
rest.put(
|
||||
'http://localhost/api/v1/explorer/views/:viewId',
|
||||
response.json(savedViewWriteResponse),
|
||||
),
|
||||
|
||||
rest.delete(
|
||||
'http://localhost/api/v1/explorer/views/:viewId',
|
||||
response.json(savedViewWriteResponse),
|
||||
),
|
||||
],
|
||||
config: () => ({ route: ROUTES.LOGS_SAVE_VIEWS }),
|
||||
});
|
||||
@@ -1,88 +0,0 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react-vite';
|
||||
import { screen, userEvent, within } from 'storybook/test';
|
||||
|
||||
import { storyMocks } from '@/storybook/controls/defineStoryMocks';
|
||||
import type { PageStoryArgs } from '@/storybook/runtime/resolveStory';
|
||||
|
||||
import { savedViewsMocks } from './SavedViews.stories.mocks';
|
||||
|
||||
import LogsModulePage from '../../LogsModulePage';
|
||||
|
||||
type SavedViewsArgs = PageStoryArgs<typeof savedViewsMocks>;
|
||||
|
||||
const pageStory = storyMocks(savedViewsMocks, { layout: 'app' });
|
||||
|
||||
/**
|
||||
* Saved views on the logs explorer, and the actions the legacy editor role gates.
|
||||
*
|
||||
* Route: `/logs/saved-views`.
|
||||
*/
|
||||
const meta = {
|
||||
title: 'Pages/Logs/Saved Views',
|
||||
tags: ['role-gated', 'play'],
|
||||
component: LogsModulePage,
|
||||
...pageStory,
|
||||
parameters: { ...pageStory.parameters },
|
||||
} satisfies Meta<SavedViewsArgs>;
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<SavedViewsArgs>;
|
||||
|
||||
/** The page fetches before it renders a row, which outlasts the 1s default. */
|
||||
const untilLoaded = { timeout: 15_000 };
|
||||
|
||||
/** Row actions are per-view icons, so a story that opens one picks the first. */
|
||||
const openFirstAction = async (
|
||||
canvasElement: HTMLElement,
|
||||
testId: string,
|
||||
): Promise<void> => {
|
||||
const [action] = await within(canvasElement).findAllByTestId(
|
||||
testId,
|
||||
undefined,
|
||||
untilLoaded,
|
||||
);
|
||||
|
||||
await userEvent.click(action);
|
||||
};
|
||||
|
||||
/**
|
||||
* The views tab: every view the org saved for logs, who saved it and when, with
|
||||
* the colour the view picker shows it under.
|
||||
*/
|
||||
export const Default: Story = {};
|
||||
|
||||
/** A workspace where nobody has saved a view yet. */
|
||||
export const NoViews: Story = {
|
||||
args: { views: 0 },
|
||||
};
|
||||
|
||||
/** Enough views to paginate, which is the only place the second page shows up. */
|
||||
export const Paginated: Story = {
|
||||
args: { views: 8 },
|
||||
};
|
||||
|
||||
/** Renaming a view: its label and the colour the picker shows it under. */
|
||||
export const EditView: Story = {
|
||||
play: async ({ canvasElement }): Promise<void> => {
|
||||
await openFirstAction(canvasElement, 'edit-view');
|
||||
await screen.findByText('Edit view details', undefined, untilLoaded);
|
||||
},
|
||||
};
|
||||
|
||||
/** The confirmation a view has to pass before it is deleted. */
|
||||
export const DeleteView: Story = {
|
||||
play: async ({ canvasElement }): Promise<void> => {
|
||||
await openFirstAction(canvasElement, 'delete-view');
|
||||
await screen.findByText(
|
||||
/are you sure you want to delete/i,
|
||||
undefined,
|
||||
untilLoaded,
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
/** A viewer: the views are listed, none of them editable. */
|
||||
export const ViewerAccess: Story = {
|
||||
args: { access: 'viewer' },
|
||||
};
|
||||
@@ -64,6 +64,7 @@ import {
|
||||
metricTemporalityOf,
|
||||
metricTypeOf,
|
||||
metricsSavedViewsResponse,
|
||||
metricsSavedViewsV2Response,
|
||||
metricsStatsResponse,
|
||||
metricsTreemapResponse,
|
||||
REDUCTION_RULE_MAX,
|
||||
@@ -517,6 +518,11 @@ export const metricsMocks = defineStoryMocks({
|
||||
response.json(() => metricsSavedViewsResponse(values.savedViews)),
|
||||
),
|
||||
|
||||
rest.get(
|
||||
'http://localhost/api/v2/saved_views',
|
||||
response.json(() => metricsSavedViewsV2Response(values.savedViews)),
|
||||
),
|
||||
|
||||
rest.post(
|
||||
'http://localhost/api/v5/query_range',
|
||||
response.json(async (req) => {
|
||||
|
||||
@@ -16,6 +16,7 @@ import type {
|
||||
InspectMetrics200,
|
||||
ListMetricReductionRules200,
|
||||
ListMetrics200,
|
||||
ListSavedViews200,
|
||||
MetricreductionruletypesGettableReductionRuleDTO,
|
||||
MetricsexplorertypesStatDTO,
|
||||
MetricsexplorertypesTreemapEntryDTO,
|
||||
@@ -24,7 +25,12 @@ import {
|
||||
MetricreductionruletypesMatchTypeDTO,
|
||||
MetrictypesTemporalityDTO,
|
||||
MetrictypesTypeDTO,
|
||||
Querybuildertypesv5QueryBuilderQueryGithubComSigNozSignozPkgTypesQuerybuildertypesQuerybuildertypesv5MetricAggregationDTOSignal as MetricsSignal,
|
||||
Querybuildertypesv5QueryEnvelopeBuilderDTOType,
|
||||
Querybuildertypesv5RequestTypeDTO,
|
||||
SavedviewtypesPanelTypeDTO,
|
||||
SavedviewtypesSchemaVersionDTO,
|
||||
SavedviewtypesSourceDTO,
|
||||
} from 'api/generated/services/sigNoz.schemas';
|
||||
import { explorerView } from 'mocks-server/__mockdata__/explorer_views';
|
||||
import type { AllViewsProps, ViewProps } from 'types/api/saveViews/types';
|
||||
@@ -785,6 +791,33 @@ export const metricsSavedViewsResponse = (count: number): AllViewsProps => ({
|
||||
})),
|
||||
});
|
||||
|
||||
export const metricsSavedViewsV2Response = (
|
||||
count: number,
|
||||
): ListSavedViews200 => ({
|
||||
status: 'success',
|
||||
data: VIEW_NAMES.slice(0, count).map((displayName, index) => ({
|
||||
id: `storybook-metrics-view-${index + 1}`,
|
||||
name: `storybook-metrics-view-${index + 1}`,
|
||||
source: SavedviewtypesSourceDTO.metrics,
|
||||
schemaVersion: SavedviewtypesSchemaVersionDTO.v2,
|
||||
createdAt: '2026-08-20T09:00:00Z',
|
||||
createdBy: 'ada@signoz.io',
|
||||
updatedAt: '2026-08-20T09:00:00Z',
|
||||
updatedBy: 'ada@signoz.io',
|
||||
spec: {
|
||||
displayName,
|
||||
panelType: SavedviewtypesPanelTypeDTO.graph,
|
||||
requestType: Querybuildertypesv5RequestTypeDTO.time_series,
|
||||
queries: [
|
||||
{
|
||||
type: Querybuildertypesv5QueryEnvelopeBuilderDTOType.builder_query,
|
||||
spec: { name: 'A', signal: MetricsSignal.metrics },
|
||||
},
|
||||
],
|
||||
},
|
||||
})),
|
||||
});
|
||||
|
||||
const FIELD_KEYS = [
|
||||
'service.name',
|
||||
'deployment.environment',
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
import { server } from 'mocks-server/server';
|
||||
import { rest } from 'msw';
|
||||
import {
|
||||
act,
|
||||
cleanup,
|
||||
fireEvent,
|
||||
render,
|
||||
@@ -316,99 +315,17 @@ describe('TracesExplorer -', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('test for explorer options', async () => {
|
||||
const { getByText, getByTestId } = renderWithTracesExplorerRouter(
|
||||
<TracesExplorer />,
|
||||
['/traces-explorer/?panelType=list&selectedExplorerView=list'],
|
||||
);
|
||||
|
||||
// assert explorer options - action btns
|
||||
[
|
||||
'Save this view',
|
||||
'Create an Alert',
|
||||
'Add to Dashboard',
|
||||
'Select a view',
|
||||
].forEach((val) => expect(getByText(val)).toBeInTheDocument());
|
||||
|
||||
const hideExplorerOption = getByTestId('hide-toolbar');
|
||||
expect(hideExplorerOption).toBeInTheDocument();
|
||||
fireEvent.click(hideExplorerOption);
|
||||
|
||||
// explorer options should hide and show btn should be present
|
||||
await expect(
|
||||
screen.findByTestId('show-explorer-option'),
|
||||
).resolves.toBeInTheDocument();
|
||||
expect(screen.queryByTestId('hide-toolbar')).toBeNull();
|
||||
|
||||
// show explorer options
|
||||
const showExplorerOption = screen.getByTestId('show-explorer-option');
|
||||
expect(showExplorerOption).toBeInTheDocument();
|
||||
fireEvent.click(showExplorerOption);
|
||||
|
||||
// explorer options should show and hide btn should be present
|
||||
await expect(
|
||||
screen.findByTestId('hide-toolbar'),
|
||||
).resolves.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('select a view options - assert and save this view', async () => {
|
||||
const { container } = renderWithTracesExplorerRouter(<TracesExplorer />, [
|
||||
'/traces-explorer/?panelType=list&selectedExplorerView=list',
|
||||
]);
|
||||
|
||||
const viewSearchInput = await waitFor(() => {
|
||||
const el = container.querySelector(
|
||||
'.view-options .ant-select-selection-search-input',
|
||||
) as HTMLElement;
|
||||
expect(el).toBeInTheDocument();
|
||||
return el;
|
||||
});
|
||||
|
||||
fireEvent.mouseDown(viewSearchInput);
|
||||
|
||||
// The saved-views request has to land and re-render the dropdown before the
|
||||
// option exists; findByRole's 1s default is not enough on a loaded runner.
|
||||
await expect(
|
||||
screen.findByRole('option', { name: 'R-test panel' }, { timeout: 5000 }),
|
||||
).resolves.toBeInTheDocument();
|
||||
|
||||
// save this view
|
||||
fireEvent.click(await screen.findByText('Save this view'));
|
||||
|
||||
const saveViewModalInput = await screen.findByPlaceholderText(
|
||||
'e.g. External http method view',
|
||||
);
|
||||
expect(saveViewModalInput).toBeInTheDocument();
|
||||
|
||||
const saveViewModal = await waitFor(() => {
|
||||
const el = document.querySelector('.ant-modal-content') as HTMLElement;
|
||||
expect(el).toBeInTheDocument();
|
||||
return el;
|
||||
});
|
||||
|
||||
await act(async () =>
|
||||
fireEvent.change(saveViewModalInput, { target: { value: 'test view' } }),
|
||||
);
|
||||
|
||||
expect(saveViewModalInput).toHaveValue('test view');
|
||||
await act(async () => {
|
||||
fireEvent.click(within(saveViewModal).getByTestId('save-view-btn'));
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(successNotification).toHaveBeenCalledWith({
|
||||
message: 'View Saved Successfully',
|
||||
});
|
||||
});
|
||||
}, 15000);
|
||||
|
||||
it('create a dashboard btn assert', async () => {
|
||||
renderWithTracesExplorerRouter(<TracesExplorer />, [
|
||||
'/traces-explorer/?panelType=list&selectedExplorerView=list',
|
||||
]);
|
||||
|
||||
const createDashboardBtn = await screen.findByText('Add to Dashboard');
|
||||
expect(createDashboardBtn).toBeInTheDocument();
|
||||
const createDashboardBtn = await screen.findByTestId(
|
||||
'explorer-add-to-dashboard',
|
||||
);
|
||||
await waitFor(() =>
|
||||
expect(createDashboardBtn).not.toHaveAttribute('aria-disabled', 'true'),
|
||||
);
|
||||
fireEvent.click(createDashboardBtn);
|
||||
|
||||
const createDashboardModal = (await screen.findByRole(
|
||||
@@ -431,8 +348,10 @@ describe('TracesExplorer -', () => {
|
||||
'/traces-explorer/?panelType=list&selectedExplorerView=list',
|
||||
]);
|
||||
|
||||
const createAlertBtn = await screen.findByText('Create an Alert');
|
||||
expect(createAlertBtn).toBeInTheDocument();
|
||||
const createAlertBtn = await screen.findByTestId('explorer-create-alert');
|
||||
await waitFor(() =>
|
||||
expect(createAlertBtn).not.toHaveAttribute('aria-disabled', 'true'),
|
||||
);
|
||||
fireEvent.click(createAlertBtn);
|
||||
|
||||
expect(historyPush).toHaveBeenCalledWith(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react-vite';
|
||||
import ROUTES from 'constants/routes';
|
||||
import { toast } from '@signozhq/ui/sonner';
|
||||
import { screen, userEvent, waitFor } from 'storybook/test';
|
||||
import { screen, userEvent } from 'storybook/test';
|
||||
|
||||
import type { GlobalMockArgs } from '../globals';
|
||||
|
||||
@@ -14,10 +14,10 @@ function EmptyPage(): JSX.Element {
|
||||
const untilLoaded = { timeout: 10_000 };
|
||||
|
||||
/**
|
||||
* The strip along the foot of the shell, behind the `SAVED_VIEW_ENABLED` flag:
|
||||
* what the page puts on the left, the build version when it puts nothing, and
|
||||
* the shell's own Ask Noz and Support on the right. Support follows the chat
|
||||
* support the workspace has, the way the floating bubble it replaces did.
|
||||
* The strip along the foot of the shell: what the page puts on the left, the
|
||||
* build version when it puts nothing, and the shell's own Ask Noz and Support
|
||||
* on the right. Support follows the chat support the workspace has, the way
|
||||
* the floating bubble it replaces did.
|
||||
*
|
||||
* Route: every page inside the app shell; these stories use `/home`.
|
||||
*/
|
||||
@@ -78,38 +78,6 @@ export const Tooltips: Story = {
|
||||
args: { noz: true, support: 'pylon', tooltipsOpen: true },
|
||||
};
|
||||
|
||||
/**
|
||||
* The flag off, on a cloud trial without a card: no strip, and chat support is
|
||||
* the floating bubble in the corner.
|
||||
*/
|
||||
export const WithoutStrip: Story = {
|
||||
args: { bottomStrip: false, noz: true, support: 'add-card' },
|
||||
};
|
||||
|
||||
/** The Add Credit Card modal, opened from the floating bubble with the flag off. */
|
||||
export const WithoutStripAddCardModal: Story = {
|
||||
args: { bottomStrip: false, noz: true, support: 'add-card' },
|
||||
play: async (): Promise<void> => {
|
||||
// The bubble is an icon with no label or test id of its own.
|
||||
const bubble = await waitFor(() => {
|
||||
const found = document.querySelector<HTMLElement>(
|
||||
'.chat-support-gateway-btn',
|
||||
);
|
||||
|
||||
if (!found) {
|
||||
throw new Error('the floating support bubble never rendered');
|
||||
}
|
||||
|
||||
return found;
|
||||
}, untilLoaded);
|
||||
|
||||
await userEvent.click(bubble);
|
||||
await screen.findByRole('dialog', {
|
||||
name: /Add Credit Card for Chat Support/i,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
/** Raises a toast and waits for it, so the shot is taken with it on screen. */
|
||||
const raiseToast: NonNullable<Story['play']> = async () => {
|
||||
toast.success('Service account deleted');
|
||||
@@ -117,16 +85,10 @@ const raiseToast: NonNullable<Story['play']> = async () => {
|
||||
};
|
||||
|
||||
/**
|
||||
* A toast with the strip on. Sonner pins itself to the foot of the viewport, so
|
||||
* A toast above the strip. Sonner pins itself to the foot of the viewport, so
|
||||
* without an offset it lands on top of Ask Noz and Support.
|
||||
*/
|
||||
export const WithToast: Story = {
|
||||
args: { noz: true, support: 'pylon' },
|
||||
play: raiseToast,
|
||||
};
|
||||
|
||||
/** The same toast with the flag off, back at sonner's own inset from the viewport. */
|
||||
export const WithoutStripToast: Story = {
|
||||
args: { bottomStrip: false, noz: true, support: 'pylon' },
|
||||
play: raiseToast,
|
||||
};
|
||||
|
||||
2
tests/e2e/drivers/routing.ts
generated
2
tests/e2e/drivers/routing.ts
generated
@@ -34,7 +34,7 @@ export const PATH = {
|
||||
k8s: '/infrastructure-monitoring/kubernetes',
|
||||
login: '/login',
|
||||
metricsSummary: '/metrics-explorer/summary',
|
||||
metricsViews: '/metrics-explorer/views',
|
||||
metricsExplorer: '/metrics-explorer/explorer',
|
||||
roles: '/settings/roles',
|
||||
roleCreate: '/settings/roles/new',
|
||||
services: '/services',
|
||||
|
||||
@@ -11,13 +11,13 @@ test.describe('Routing — route matching', () => {
|
||||
await routing.goto(PATH.metricsSummary);
|
||||
await expect(routing.activeRouteTab(PATH.metricsSummary)).toBeVisible();
|
||||
|
||||
await routing.routeTab(PATH.metricsViews).click();
|
||||
await routing.waitForPath(PATH.metricsViews);
|
||||
await expect(routing.activeRouteTab(PATH.metricsViews)).toBeVisible();
|
||||
await routing.routeTab(PATH.metricsExplorer).click();
|
||||
await routing.waitForPath(PATH.metricsExplorer);
|
||||
await expect(routing.activeRouteTab(PATH.metricsExplorer)).toBeVisible();
|
||||
|
||||
await routing.reload();
|
||||
expect(routing.url().pathname).toBe(PATH.metricsViews);
|
||||
await expect(routing.activeRouteTab(PATH.metricsViews)).toBeVisible();
|
||||
expect(routing.url().pathname).toBe(PATH.metricsExplorer);
|
||||
await expect(routing.activeRouteTab(PATH.metricsExplorer)).toBeVisible();
|
||||
});
|
||||
|
||||
test('TC-10 a prefix-route deep link loads with the right tab selected', async ({
|
||||
|
||||
Reference in New Issue
Block a user