Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: added trace views test #5519

Merged
merged 18 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from 14 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
62 changes: 62 additions & 0 deletions frontend/src/mocks-server/__mockdata__/explorer_views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,67 @@ export const explorerView = {
},
extraData: '{"color":"#00ffd0"}',
},
{
uuid: '8c4bf492-d54d-4ab2-a8d6-9c1563f46e1f',
name: 'R-test panel',
category: '',
createdAt: '2024-07-01T13:45:57.924686766Z',
createdBy: 'test-user-test',
updatedAt: '2024-07-01T13:48:31.032106578Z',
updatedBy: 'test-user-test',
sourcePage: 'traces',
tags: [''],
compositeQuery: {
builderQueries: {
A: {
queryName: 'A',
stepInterval: 60,
dataSource: 'traces',
aggregateOperator: 'noop',
aggregateAttribute: {
key: '',
dataType: '',
type: '',
isColumn: false,
isJSON: false,
},
filters: {
op: 'AND',
items: [
{
key: {
key: 'httpMethod',
dataType: 'string',
type: 'tag',
isColumn: true,
isJSON: false,
},
value: 'GET',
op: '=',
},
],
},
expression: 'A',
disabled: false,
limit: 0,
offset: 0,
pageSize: 0,
orderBy: [
{
columnName: 'timestamp',
order: 'desc',
},
],
reduceTo: 'avg',
timeAggregation: 'rate',
spaceAggregation: 'sum',
ShiftBy: 0,
},
},
panelType: 'list',
queryType: 'builder',
},
extraData: '{"color":"#AD7F58"}',
},
],
};
172 changes: 172 additions & 0 deletions frontend/src/pages/SaveView/__test__/SaveView.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable sonarjs/no-duplicate-string */
import ROUTES from 'constants/routes';
import { explorerView } from 'mocks-server/__mockdata__/explorer_views';
import { server } from 'mocks-server/server';
import { rest } from 'msw';
import { MemoryRouter, Route } from 'react-router-dom';
import { fireEvent, render, screen, waitFor, within } from 'tests/test-utils';

import SaveView from '..';

const handleExplorerTabChangeTest = jest.fn();
jest.mock('hooks/useHandleExplorerTabChange', () => ({
useHandleExplorerTabChange: () => ({
handleExplorerTabChange: handleExplorerTabChangeTest,
}),
}));

jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useLocation: jest.fn().mockReturnValue({
pathname: `${ROUTES.TRACES_SAVE_VIEWS}`,
}),
}));

describe('SaveView', () => {
it('should render the SaveView component', async () => {
render(<SaveView />);
expect(await screen.findByText('Table View')).toBeInTheDocument();

const savedViews = screen.getAllByRole('row');
expect(savedViews).toHaveLength(2);

// assert row 1
expect(
within(document.querySelector('.view-tag') as HTMLElement).getByText('T'),
).toBeInTheDocument();
expect(screen.getByText('test-user-1')).toBeInTheDocument();

// assert row 2
expect(screen.getByText('R-test panel')).toBeInTheDocument();
expect(screen.getByText('test-user-test')).toBeInTheDocument();
});

it('explorer icon should take the user to the related explorer page', async () => {
render(
<MemoryRouter initialEntries={[ROUTES.TRACES_SAVE_VIEWS]}>
<Route path={ROUTES.TRACES_SAVE_VIEWS}>
<SaveView />
</Route>
</MemoryRouter>,
);

expect(await screen.findByText('Table View')).toBeInTheDocument();

const explorerIcon = await screen.findAllByTestId('go-to-explorer');
expect(explorerIcon[0]).toBeInTheDocument();

// Simulate click on explorer icon
fireEvent.click(explorerIcon[0]);

await waitFor(() =>
expect(handleExplorerTabChangeTest).toHaveBeenCalledWith(
expect.anything(),
expect.anything(),
'/traces-explorer', // Asserts the third argument is '/traces-explorer'
),
);
});

it('should render the SaveView component with a search input', async () => {
render(<SaveView />);
const searchInput = screen.getByPlaceholderText('Search for views...');
expect(await screen.findByText('Table View')).toBeInTheDocument();

expect(searchInput).toBeInTheDocument();

// search for 'R-test panel'
searchInput.focus();
(searchInput as HTMLInputElement).setSelectionRange(
0,
(searchInput as HTMLInputElement).value.length,
);

fireEvent.change(searchInput, { target: { value: 'R-test panel' } });
expect(searchInput).toHaveValue('R-test panel');
searchInput.blur();

expect(await screen.findByText('R-test panel')).toBeInTheDocument();

// Table View should not be present now
const savedViews = screen.getAllByRole('row');
expect(savedViews).toHaveLength(1);
});

it('should be able to edit name of view', async () => {
server.use(
rest.put(
'http://localhost/api/v1/explorer/views/test-uuid-1',
// eslint-disable-next-line no-return-assign
(_req, res, ctx) =>
res(
ctx.status(200),
ctx.json({
...explorerView,
data: [
...explorerView.data,
(explorerView.data[0].name = 'New Table View'),
],
}),
),
),
);
render(<SaveView />);

const editButton = await screen.findAllByTestId('edit-view');
fireEvent.click(editButton[0]);

const viewName = await screen.findByTestId('view-name');
expect(viewName).toBeInTheDocument();
expect(viewName).toHaveValue('Table View');

const newViewName = 'New Table View';
fireEvent.change(viewName, { target: { value: newViewName } });
expect(viewName).toHaveValue(newViewName);

const saveButton = await screen.findByTestId('save-view');
fireEvent.click(saveButton);

await waitFor(() =>
expect(screen.getByText(newViewName)).toBeInTheDocument(),
);
});

it('should be able to delete a view', async () => {
server.use(
rest.delete(
'http://localhost/api/v1/explorer/views/test-uuid-1',
(_req, res, ctx) => res(ctx.status(200), ctx.json({ status: 'success' })),
),
);

render(<SaveView />);

const deleteButton = await screen.findAllByTestId('delete-view');
fireEvent.click(deleteButton[0]);

expect(await screen.findByText('delete_confirm_message')).toBeInTheDocument();

const confirmButton = await screen.findByTestId('confirm-delete');
fireEvent.click(confirmButton);

await waitFor(() => expect(screen.queryByText('Table View')).toBeNull());
});

it('should render empty state', async () => {
server.use(
rest.get('http://localhost/api/v1/explorer/views', (_req, res, ctx) =>
res(
ctx.status(200),
ctx.json({
status: 'success',
data: [],
}),
),
),
);
render(<SaveView />);

expect(screen.getByText('No data')).toBeInTheDocument();
});
});
11 changes: 10 additions & 1 deletion frontend/src/pages/SaveView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -263,13 +263,19 @@ function SaveView(): JSX.Element {
<PenLine
size={14}
className={isEditDeleteSupported ? '' : 'hidden'}
data-testid="edit-view"
onClick={(): void => handleEditModelOpen(view, bgColor)}
/>
<Compass size={14} onClick={(): void => handleRedirectQuery(view)} />
<Compass
size={14}
onClick={(): void => handleRedirectQuery(view)}
data-testid="go-to-explorer"
/>
<Trash2
size={14}
className={isEditDeleteSupported ? '' : 'hidden'}
color={Color.BG_CHERRY_500}
data-testid="delete-view"
onClick={(): void => handleDeleteModelOpen(view.uuid, view.name)}
/>
</div>
Expand Down Expand Up @@ -347,6 +353,7 @@ function SaveView(): JSX.Element {
onClick={onDeleteHandler}
className="delete-btn"
disabled={isDeleteLoading}
data-testid="confirm-delete"
>
Delete view
</Button>,
Expand All @@ -371,6 +378,7 @@ function SaveView(): JSX.Element {
icon={<Check size={16} color={Color.BG_VANILLA_100} />}
onClick={onUpdateQueryHandler}
disabled={isViewUpdating}
data-testid="save-view"
>
Save changes
</Button>,
Expand All @@ -385,6 +393,7 @@ function SaveView(): JSX.Element {
<Input
placeholder="e.g. Crash landing view"
value={newViewName}
data-testid="view-name"
onChange={(e): void => setNewViewName(e.target.value)}
/>
</div>
Expand Down
Loading