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

Checks catalog stories #1953

Merged
merged 3 commits into from
Oct 26, 2023
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
39 changes: 9 additions & 30 deletions assets/js/components/ChecksCatalog/ChecksCatalog.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
/* eslint-disable react/no-array-index-key */
import React, { useState, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import React, { useEffect, useState } from 'react';
import { groupBy } from 'lodash';

import { getCatalog } from '@state/selectors/catalog';
import { updateCatalog } from '@state/actions/catalog';
import {
providerData,
checkProviderExists,
} from '@components/ProviderLabel/ProviderLabel';
import { providerData } from '@components/ProviderLabel/ProviderLabel';
import PageHeader from '@components/PageHeader';
import Accordion from '@components/Accordion';
import CatalogContainer from './CatalogContainer';
Expand All @@ -22,27 +15,13 @@ const updatedProvider = {
...providerData,
};

const buildUpdateCatalogAction = (provider) => {
const payload = checkProviderExists(provider)
? { provider, target_type: 'cluster' }
: {};
return updateCatalog(payload);
};

// eslint-disable-next-line import/prefer-default-export
function ChecksCatalog() {
const dispatch = useDispatch();
function ChecksCatalog({ catalogData, catalogError, loading, updateCatalog }) {
const [selectedProvider, setProviderSelected] = useState(ALL_FILTER);

const {
data: catalogData,
error: catalogError,
loading,
} = useSelector(getCatalog());

useEffect(() => {
dispatch(buildUpdateCatalogAction(selectedProvider));
}, [dispatch, selectedProvider]);
updateCatalog(selectedProvider);
}, [selectedProvider]);

return (
<>
<div className="flex">
Expand All @@ -55,15 +34,15 @@ function ChecksCatalog() {
/>
</div>
<CatalogContainer
onRefresh={() => dispatch(buildUpdateCatalogAction(selectedProvider))}
onRefresh={() => updateCatalog(selectedProvider)}
isCatalogEmpty={catalogData.length === 0}
catalogError={catalogError}
loading={loading}
>
<div>
{Object.entries(groupBy(catalogData, 'group')).map(
([group, checks], idx) => (
<ul key={idx}>
([group, checks]) => (
<ul key={group}>
<Accordion
defaultOpen
className="check-group mb-4"
Expand Down
82 changes: 82 additions & 0 deletions assets/js/components/ChecksCatalog/ChecksCatalog.stories.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { faker } from '@faker-js/faker';

import { catalogCheckFactory } from '@lib/test-utils/factories';
import ChecksCatalog from './ChecksCatalog';

const groupName1 = faker.string.uuid();
const groupName2 = faker.string.uuid();
const groupName3 = faker.string.uuid();
const group1 = catalogCheckFactory.buildList(5, { group: groupName1 });
const group2 = catalogCheckFactory.buildList(5, { group: groupName2 });
const group3 = catalogCheckFactory.buildList(5, { group: groupName3 });
const catalogData = group1.concat(group2, group3);

function ContainerWrapper({ children }) {
return (
<div className="max-w-7xl mx-auto px-4 sm:px-6 md:px-8">{children}</div>
);
}

export default {
title: 'Layouts/ChecksCatalog',
component: ChecksCatalog,
argTypes: {
catalogData: {
control: 'object',
description: 'Catalog content',
},
catalogError: {
control: 'text',
description: 'Error message getting catalog data',
table: {
type: { summary: 'string' },
},
},
loading: {
control: { type: 'boolean' },
description: 'Catalog data is being loaded',
table: {
type: { summary: 'string' },
defaultValue: { summary: false },
},
},
updateCatalog: {
action: 'Update catalog',
description: 'Update catalog content',
},
},
decorators: [
(Story) => (
<MemoryRouter>
<Story />
</MemoryRouter>
),
],
render: (args) => (
<ContainerWrapper>
<ChecksCatalog {...args} />
</ContainerWrapper>
),
};

export const Default = {
args: {
catalogData,
},
};

export const Loading = {
args: {
...Default.args,
loading: true,
},
};

export const Error = {
args: {
...Default.args,
catalogError: 'Error loading catalog',
},
};
59 changes: 22 additions & 37 deletions assets/js/components/ChecksCatalog/ChecksCatalog.test.jsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
import React from 'react';

import { screen, within, act, waitFor } from '@testing-library/react';
import { screen, within, render } from '@testing-library/react';
import '@testing-library/jest-dom';
import userEvent from '@testing-library/user-event';

import { faker } from '@faker-js/faker';
import { withState, renderWithRouter } from '@lib/test-utils';
import { catalogCheckFactory } from '@lib/test-utils/factories';

import ChecksCatalog from './ChecksCatalog';

describe('ChecksCatalog ChecksCatalog component', () => {
it('should render the checks catalog with fetched data', async () => {
it('should render the checks catalog with fetched data', () => {
const groupName1 = faker.string.uuid();
const groupName2 = faker.string.uuid();
const group1 = catalogCheckFactory.buildList(5, { group: groupName1 });
const group2 = catalogCheckFactory.buildList(5, { group: groupName2 });
const catalogData = group1.concat(group2);

const initialState = {
catalog: { loading: false, data: [...group1, ...group2], error: null },
};
const [statefulCatalog, store] = withState(<ChecksCatalog />, initialState);
const mockUpdateCatalog = jest.fn();

await act(async () => renderWithRouter(statefulCatalog));
render(
<ChecksCatalog
catalogData={catalogData}
updateCatalog={mockUpdateCatalog}
/>
);

const groups = await waitFor(() => screen.getAllByRole('list'));
const groups = screen.getAllByRole('list');
expect(groups.length).toBe(2);

groups.forEach((group) => {
Expand All @@ -33,46 +35,29 @@ describe('ChecksCatalog ChecksCatalog component', () => {
expect(checks.length).toBe(5);
});

const actions = store.getActions();
const expectedActions = [
{
type: 'UPDATE_CATALOG',
payload: {},
},
];
expect(actions).toEqual(expectedActions);
expect(mockUpdateCatalog).toHaveBeenCalledWith('all');
});

it('should query the catalog with the correct provider', async () => {
const user = userEvent.setup();

const catalog = catalogCheckFactory.buildList(5);
const catalogData = catalogCheckFactory.buildList(5);
const mockUpdateCatalog = jest.fn();

const initialState = {
catalog: { loading: false, data: catalog, error: null },
};

const [statefulCatalog, store] = withState(<ChecksCatalog />, initialState);

await act(async () => renderWithRouter(statefulCatalog, store));
render(
<ChecksCatalog
catalogData={catalogData}
updateCatalog={mockUpdateCatalog}
/>
);

await user.click(screen.getByText('All'));

const providerFilter = screen.getByText('AWS');

await user.click(providerFilter);

const actions = store.getActions();
const expectedActions = [
{
type: 'UPDATE_CATALOG',
payload: {},
},
{
type: 'UPDATE_CATALOG',
payload: { provider: 'aws', target_type: 'cluster' },
},
];
expect(actions).toEqual(expectedActions);
expect(mockUpdateCatalog).toHaveBeenNthCalledWith(1, 'all');
expect(mockUpdateCatalog).toHaveBeenNthCalledWith(2, 'aws');
});
});
37 changes: 37 additions & 0 deletions assets/js/components/ChecksCatalog/ChecksCatalogPage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';

import { getCatalog } from '@state/selectors/catalog';
import { updateCatalog } from '@state/actions/catalog';
import { checkProviderExists } from '@components/ProviderLabel/ProviderLabel';
import ChecksCatalog from './ChecksCatalog';

const buildUpdateCatalogAction = (provider) => {
const payload = checkProviderExists(provider)
? { provider, target_type: 'cluster' }
: {};
return updateCatalog(payload);
};

function ChecksCatalogPage() {
const dispatch = useDispatch();

const {
data: catalogData,
error: catalogError,
loading,
} = useSelector(getCatalog());

return (
<ChecksCatalog
catalogData={catalogData}
catalogError={catalogError}
loading={loading}
updateCatalog={(selectedProvider) =>
dispatch(buildUpdateCatalogAction(selectedProvider))
}
/>
);
}

export default ChecksCatalogPage;
4 changes: 2 additions & 2 deletions assets/js/components/ChecksCatalog/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import ChecksCatalog from './ChecksCatalog';
import ChecksCatalogPage from './ChecksCatalogPage';

export default ChecksCatalog;
export default ChecksCatalogPage;
4 changes: 2 additions & 2 deletions assets/js/trento.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { ExecutionResultsPage } from '@components/ExecutionResults';
import SapSystemsOverviewPage from '@components/SapSystemsOverview';
import HostDetailsPage, { HostSettingsPage } from '@components/HostDetails';
import DatabasesOverviewPage from '@components/DatabasesOverview';
import ChecksCatalog from '@components/ChecksCatalog';
import ChecksCatalogPage from '@components/ChecksCatalog';
import NotFound from '@components/NotFound';
import SomethingWentWrong from '@components/SomethingWentWrong';
import SaptuneDetailsPage from '@components/SaptuneDetails';
Expand Down Expand Up @@ -75,7 +75,7 @@ function App() {
element={<SapSystemsOverviewPage />}
/>
<Route path="databases" element={<DatabasesOverviewPage />} />
<Route path="catalog" element={<ChecksCatalog />} />
<Route path="catalog" element={<ChecksCatalogPage />} />
<Route path="settings" element={<Settings />} />
<Route path="about" element={<AboutPage />} />
<Route path="hosts/:hostID" element={<HostDetailsPage />} />
Expand Down