Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…generator into develop
  • Loading branch information
rohanm-crest committed Nov 21, 2024
2 parents f47cbf1 + 50e18c6 commit d256182
Show file tree
Hide file tree
Showing 20 changed files with 262 additions and 34 deletions.
Binary file modified docs/images/inputs/Tabs_Output.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 35 additions & 0 deletions tests/ui/conftest.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
from typing import Any, Iterator

import pytest

from tests.ui.pages.account_page import AccountPage
from tests.ui.test_configuration_page_account_tab import _ACCOUNT_CONFIG
from pytest_splunk_addon_ui_smartx import utils as s_utils

from _pytest.assertion import truncate

truncate.DEFAULT_MAX_LINES = 9999
truncate.DEFAULT_MAX_CHARS = 9999


@pytest.fixture
Expand All @@ -13,3 +21,30 @@ def add_delete_account(ucc_smartx_rest_helper):
kwargs = _ACCOUNT_CONFIG
yield account.backend_conf.post_stanza(url, kwargs)
account.backend_conf.delete_all_stanzas()


@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_call(item: pytest.Item) -> Iterator[Any]:
"""
Implemented hook to:
- check browser logs for severe logs after each test run.
"""

yield

IGNORED = {
"appLogo.png - Failed to load resource: the server responded with a status of 404 (Not Found)",
}

browser_logs = s_utils.get_browser_logs(item.selenium_helper.browser)
severe_logs = [
log
for log in browser_logs
if log.level == s_utils.LogLevel.SEVERE
and not any(ignored in log.message for ignored in IGNORED)
]

if severe_logs:
log_msg = [f"{log.level}: {log.source} - {log.message}" for log in severe_logs]
msg = "Severe logs found in browser console logs: \n" + "\n".join(log_msg)
pytest.fail(msg, pytrace=True)
1 change: 1 addition & 0 deletions ui/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ module.exports = {
// https://typescript-eslint.io/rules/no-use-before-define/#how-to-use
'no-use-before-define': 'off',
'@typescript-eslint/no-use-before-define': ['error', { variables: false }],
'jest/expect-expect': 'error',
},
root: true,
};
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,9 @@ it('should fetch options from API when endpointUrl is provided', async () => {
/>
);
await userEvent.click(screen.getByRole('combobox'));
await screen.findByRole('option', { name: firstEntry.content.testLabel });
expect(
await screen.findByRole('option', { name: firstEntry.content.testLabel })
).toBeInTheDocument();

const secondEntry = mockedEntries[1];
rerender(
Expand All @@ -217,17 +219,23 @@ it('should fetch options from API when endpointUrl is provided', async () => {
/>
);
await userEvent.click(screen.getByRole('combobox'));
await screen.findByRole('option', { name: secondEntry.content.testLabel });
expect(
await screen.findByRole('option', { name: secondEntry.content.testLabel })
).toBeInTheDocument();

const thirdEntry = mockedEntries[2];
rerender(
<SingleInputComponent {...baseProps} dependencyValues={{ name: true, region: false }} />
);
await userEvent.click(screen.getByRole('combobox'));
await screen.findByRole('option', { name: thirdEntry.content.testLabel });
expect(
await screen.findByRole('option', { name: thirdEntry.content.testLabel })
).toBeInTheDocument();

const fourthEntry = mockedEntries[3];
rerender(<SingleInputComponent {...baseProps} dependencyValues={{ name: 0, region: 0 }} />);
await userEvent.click(screen.getByRole('combobox'));
await screen.findByRole('option', { name: fourthEntry.content.testLabel });
expect(
await screen.findByRole('option', { name: fourthEntry.content.testLabel })
).toBeInTheDocument();
});
21 changes: 17 additions & 4 deletions ui/src/components/table/TableHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React from 'react';
import PropTypes from 'prop-types';
import Select from '@splunk/react-ui/Select';
import Paginator from '@splunk/react-ui/Paginator';
import { Typography } from '@splunk/react-ui/Typography';

import styled from 'styled-components';
import { _ } from '@splunk/ui-utils/i18n';

Expand Down Expand Up @@ -71,13 +73,24 @@ function TableHeader({
);
};

const getInputCountStatus = () => {
const enabledRowCount = allFilteredData.filter((item) => !item.disabled).length;
const showCountStatus = `(${enabledRowCount} of ${totalElement} enabled)`;

return (
<Typography as="span" className="inputNumber">
{totalElement}
{totalElement > 1 ? _(` ${itemLabel}s`) : _(` ${itemLabel}`)}
&nbsp;
{page === PAGE_INPUT && totalElement >= pageSize ? showCountStatus : null}
</Typography>
);
};

return (
<TableHeaderWrapper>
<div>
<span className="inputNumber">
{totalElement}
{totalElement > 1 ? _(` ${itemLabel}s`) : _(` ${itemLabel}`)}
</span>
{getInputCountStatus()}
{page === PAGE_INPUT ? (
<TableSelectBoxWrapper>
<Select
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion ui/src/components/table/stories/configMockups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export const SIMPLE_NAME_TABLE_MOCK_DATA = {

export const getSimpleConfig = () => {
const configCp = JSON.parse(JSON.stringify(SIMPLE_NAME_TABLE_MOCK_DATA));
return configCp;
return configCp as GlobalConfig;
};

export const TABLE_CONFIG_WITH_MAPPING = {
Expand Down
172 changes: 172 additions & 0 deletions ui/src/components/table/tests/TableExpansionRow.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import { render, screen, waitFor, waitForElementToBeRemoved, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { http, HttpResponse } from 'msw';
import { BrowserRouter } from 'react-router-dom';
import TableWrapper, { ITableWrapperProps } from '../TableWrapper';
import { server } from '../../../mocks/server';
import { TableContextProvider } from '../../../context/TableContext';
import { setUnifiedConfig } from '../../../util/util';
import { getSimpleConfig } from '../stories/configMockups';
import { getMockServerResponseForInput } from '../../../mocks/server-response';
import { GlobalConfig } from '../../../types/globalConfig/globalConfig';
import { getBuildDirPath } from '../../../util/script';
import mockCustomInputRow from '../../../../../tests/testdata/test_addons/package_global_config_everything/package/appserver/static/js/build/custom/custom_input_row';

const inputName = 'example_input_one';
const interval = 7766;
const updatedInterval = 7788;

const props = {
page: 'inputs',
serviceName: inputName,
handleRequestModalOpen: jest.fn(),
handleOpenPageStyleDialog: jest.fn(),
} satisfies ITableWrapperProps;

const baseConfig = getSimpleConfig();
const customRowFileName = 'CustomInputRow';

function setup() {
jest.mock(`${getBuildDirPath()}/custom/${customRowFileName}.js`, () => mockCustomInputRow, {
virtual: true,
});

const headers = [
{
label: 'Name',
field: 'name',
},
{
label: 'Interval',
field: 'interval',
},
];
setUnifiedConfig({
...baseConfig,
pages: {
...baseConfig.pages,
inputs: {
title: inputName,
services: [
{
title: inputName,
name: inputName,
entity: [
{
label: 'Name',
field: 'name',
type: 'text',
},
{
label: 'Interval',
field: 'interval',
type: 'text',
},
],
},
],
table: {
actions: ['edit'],
header: headers,
moreInfo: headers,
customRow: {
src: customRowFileName,
type: 'external',
},
},
},
},
} satisfies GlobalConfig);

server.use(
http.get(`/servicesNS/nobody/-/splunk_ta_uccexample_${inputName}`, () =>
HttpResponse.json(
getMockServerResponseForInput([
{
name: inputName,
content: {
interval,
},
},
])
)
)
);

render(
<TableContextProvider>
<TableWrapper {...props} />
</TableContextProvider>,
{ wrapper: BrowserRouter }
);
}

async function expectIntervalInExpandedRow(inputRow: HTMLElement, expectedInterval: number) {
const arrow = within(inputRow).getByRole('cell', { name: /expandable/i });
const isExpanded = arrow.getAttribute('aria-expanded');
if (isExpanded === 'false') {
await userEvent.click(arrow);
}
await waitFor(() => expect(arrow.getAttribute('aria-expanded')).not.toBe('false'));
const loading = screen.queryByText('Loading...');
if (loading) {
await waitForElementToBeRemoved(loading);
}

const allDefinitions = screen.getAllByRole('definition').map((el) => el.textContent);

expect(allDefinitions).toContain(`${expectedInterval} sec`);
}

it.failing('should update custom Expansion Row when Input has changed', async () => {
setup();
const inputRow = await screen.findByRole('row', { name: `row-${inputName}` });

// simulate the server response for the post request
server.use(
http.post(
`/servicesNS/nobody/-/splunk_ta_uccexample_${inputName}/${inputName}`,
async ({ request }) => {
const formData = await request.formData();
const formDataObject: Record<string, string> = {};
formData.forEach((value, key) => {
if (typeof value === 'string') {
formDataObject[key] = value;
}
});
return HttpResponse.json(
getMockServerResponseForInput([
{
name: inputName,
content: formDataObject,
},
])
);
}
)
);

await expectIntervalInExpandedRow(
await screen.findByRole('row', { name: `row-${inputName}` }),
interval
);

await userEvent.click(within(inputRow).getByRole('button', { name: /edit/i }));
const dialog = await screen.findByRole('dialog');

const textBoxes = within(dialog).getAllByRole('textbox');
expect(textBoxes).toHaveLength(2);
const intervalInput = textBoxes[1];
expect(intervalInput).toHaveValue(interval.toString());
await userEvent.clear(intervalInput);
await userEvent.type(intervalInput, updatedInterval.toString());
await userEvent.click(screen.getByRole('button', { name: /update/i }));

await screen.findByRole('cell', { name: updatedInterval.toString() });

await expectIntervalInExpandedRow(
await screen.findByRole('row', { name: `row-${inputName}` }),
updatedInterval
);
});
1 change: 0 additions & 1 deletion ui/src/components/table/tests/TableWrapper.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,6 @@ it('Check inputs count is visible', async () => {
handleOpenPageStyleDialog,
displayActionBtnAllRows: false,
} satisfies ITableWrapperProps;

server.use(
http.get('/servicesNS/nobody/-/splunk_ta_uccexample_example_input_one', () =>
HttpResponse.json(MockRowDataForStatusCount)
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit d256182

Please sign in to comment.