-
Notifications
You must be signed in to change notification settings - Fork 22
Fixes #38958 - Add basic Leapp preupgrade report table to the new job invocation page #165
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
base: master
Are you sure you want to change the base?
Conversation
- Add PropTypes and defaultProps to mock components (Table, Pagination) - Fix React Hooks rules violation by moving hooks before early return - Fix camelcase linting for API properties (template_name, preupgrade_report_entries) - Simplify else-if structure to avoid lonely-if error - Fix consistent-return by explicitly returning undefined in early exit - Fix boolean attribute syntax (isEmbedded) - Remove trailing whitespace for prettier compliance 🤖 Generated with [Claude Code](https://claude.com/claude-code) Assisted-By: Claude <[email protected]>
adamlazik1
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haven't looked at the whole code yet but test failures are related and need to be addressed.
| } | ||
|
No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trailing whitespace here.
| } | |
| } |
131319a to
80017aa
Compare
| jest.mock('foremanReact/components/Pagination', () => ({ | ||
| __esModule: true, | ||
| default: ({ onChange, itemCount, page, perPage }) => ( | ||
| <div data-testid="pagination"> | ||
| <button onClick={() => onChange({ page: page + 1 })}>Next Page</button> | ||
| <button onClick={() => onChange({ perPage: 10 })}>Set 10</button> | ||
| <span> | ||
| {itemCount} items, page {page}, per page {perPage} | ||
| </span> | ||
| </div> | ||
| ), | ||
| })); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicating mocks ain't cool, Mr. C
Fixed multiple test issues: - Changed redux-thunk import from named to default export - Added proper mocks for I18n, Pagination, and Table components - Updated Table mock to handle childrenOutsideTbody and customEmptyState props - Updated snapshots for PreupgradeReportsList tests All 61 tests now passing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Generated-By: Claude <[email protected]>
e42f6c1 to
ba5ec56
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to mock foremanReact
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to mock anything from foremanReact?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems I still need to mock ForemanContext to avoid this.
● PreupgradeReportsList › encountered a declaration exception
TypeError: Cannot read properties of undefined (reading 'perPage')
20 | toggleSelectAll,
21 | }) => {
> 22 | const { perPage, perPageOptions } = useForemanSettings();
| ^
23 | const [pagination, setPagination] = useState({
24 | page: 1,
25 | per_page: perPage,
at PreupgradeReportsList (../foreman-leapp/webpack/components/PreupgradeReportsList/index.js:22:11)
at ReactShallowRenderer.apply [as render] (node_modules/enzyme-adapter-react-16/node_modules/react-test-renderer/cjs/react-test-renderer-shallow.development.js:829:32)
at renderElement (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:643:41)
at fn (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:707:46)
at withSetStateAllowed (node_modules/enzyme-adapter-utils/src/Utils.js:100:18)
at Object.render (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:707:39)
at new ShallowWrapper (node_modules/enzyme/src/ShallowWrapper.js:411:22)
at shallow (node_modules/enzyme/src/shallow.js:10:10)
at map (webpack/assets/javascripts/react_app/common/testHelpers.js:62:23)
at Array.map (<anonymous>)
at shallowRenderComponentWithFixtures (webpack/assets/javascripts/react_app/common/testHelpers.js:60:28)
at testComponentSnapshotsWithFixtures (webpack/assets/javascripts/react_app/common/testHelpers.js:71:3)
at Suite.<anonymous> (../foreman-leapp/webpack/components/PreupgradeReportsList/__tests__/PreupgradeReportsList.test.js:40:37)
at Object.<anonymous> (../foreman-leapp/webpack/components/PreupgradeReportsList/__tests__/PreupgradeReportsList.test.js:39:1)
Or is there an alternative to this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok this specific mock is not correct in foreman core and should be fixed to include all items, so for this I would use a mock
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
theforeman/foreman#10823
Added a full mock in core
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the test be updated to not use snapshots?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done-ish
| customToolbarItems={[ | ||
| <ToolbarItem key="pagination">{topPagination}</ToolbarItem>, | ||
| ]} | ||
| replacementResponse={combinedResponse} | ||
| searchable={false} | ||
| updateParamsByUrl={false} | ||
| > | ||
| <Table | ||
| ouiaId="leapp-report-table" | ||
| columns={columns} | ||
| isEmbedded | ||
| params={{ | ||
| page: pagination.page, | ||
| per_page: pagination.per_page, | ||
| perPage: pagination.per_page, | ||
| order: '', | ||
| }} | ||
| results={pagedEntries} | ||
| itemCount={entries.length} | ||
| url="" | ||
| isPending={status === STATUS.PENDING} | ||
| errorMessage={ | ||
| status === STATUS.ERROR && error?.message ? error.message : null | ||
| } | ||
| showCheckboxes={false} | ||
| refreshData={() => {}} | ||
| isDeleteable={false} | ||
| customEmptyState={ | ||
| status === STATUS.RESOLVED && entries.length === 0 | ||
| ? customEmptyState | ||
| : null | ||
| } | ||
| setParams={handleParamsChange} | ||
| bottomPagination={bottomPagination} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is the custom top and bottom Pagination needed? I tried to remove them and the table still works
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll have to defer to @kmalyjur
| setPagination(prev => ({ | ||
| ...prev, | ||
| page: newParams.page || prev.page, | ||
| per_page: newParams.perPage || newParams.per_page || prev.per_page, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure why, but newParams.per_page is the correct one while newParams.perPage gives the old value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I'm seeing is newParams.perPage always being undefined and newParams.per_page being correct. Thinking about it, I'm not sure where should newParams.perPage be coming from
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All per_page, except newParams.per_page should be perPage.
so
webpack/components/PreupgradeReports/PreupgradeReportsHelpers.js
export const entriesPage = (entries, pagination) => {
const offset = (pagination.page - 1) * pagination.perPage;
return entries.slice(offset, offset + pagination.perPage);
};webpack/components/PreupgradeReportsTable/index.js
const [pagination, setPagination] = useState({ page: 1, perPage: 5 });
...
perPage: newParams.per_page || prev.perPage,
...
params={{
page: pagination.page,
perPage: pagination.perPage,
order: '',
}}And bottomPagination={bottomPagination} is not needed
57bf4e2 to
e369a39
Compare
Replace snapshot-based testing with React Testing Library assertions that test actual component behavior: - Verify header columns render correctly - Test entry data (titles, hostnames) appears in the document - Check checkbox interactions call the correct handlers - Test selected state rendering - Verify pagination component is present Generated-By: Claude Code 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
| export const columns = { | ||
| title: { | ||
| title: __('Title'), | ||
| wrapper: () => null, | ||
| }, | ||
| host: { | ||
| title: __('Host'), | ||
| wrapper: () => null, | ||
| }, | ||
| risk_factor: { | ||
| title: __('Risk Factor'), | ||
| wrapper: () => null, | ||
| }, | ||
| has_remediation: { | ||
| title: __('Has Remediation?'), | ||
| wrapper: () => null, | ||
| }, | ||
| inhibitor: { | ||
| title: __('Inhibitor?'), | ||
| wrapper: () => null, | ||
| }, | ||
| }; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of this, and the tbody, I think it would be better to do:
const columns = {
title: {
title: __('Title'),
},
host: {
title: __('Host'),
wrapper: entry =>
entry.hostname || (reportData && reportData.hostname) || '-',
},
risk_factor: {
title: __('Risk Factor'),
wrapper: ({ severity }) => renderSeverityLabel(severity),
},
has_remediation: {
title: __('Has Remediation?'),
wrapper: entry =>
entry.detail && entry.detail.remediations ? __('Yes') : __('No'),
},
inhibitor: {
title: __('Inhibitor?'),
wrapper: entry =>
entry.flags && entry.flags.some(flag => flag === 'inhibitor') ? (
<Tooltip content={__('This issue inhibits the upgrade.')}>
<span>{__('Yes')}</span>
</Tooltip>
) : (
__('No')
),
},
};There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, but I had to drop the (reportData && reportData.hostname) part from host as that is state within PreupgradeReportsTable and I wasn't sure how to access that, if that's even possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
its possible to move conts columns into PreupgradeReportsTable
| } | ||
| setParams={handleParamsChange} | ||
| bottomPagination={bottomPagination} | ||
| childrenOutsideTbody |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This prop is for when the table has expendable rows
| <TableIndexPage | ||
| apiUrl="" | ||
| controller="preupgrade_reports" | ||
| customToolbarItems={[ | ||
| <ToolbarItem key="pagination">{topPagination}</ToolbarItem>, | ||
| ]} | ||
| replacementResponse={combinedResponse} | ||
| searchable={false} | ||
| updateParamsByUrl={false} | ||
| > |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TableIndexPage is not needed
| const customEmptyState = ( | ||
| <Tr ouiaId="leapp-table-empty"> | ||
| <Td colSpan={100}> | ||
| <EmptyState variant={EmptyStateVariant.sm}> | ||
| <EmptyStateHeader | ||
| titleText={<>{__('No issues found')}</>} | ||
| headingLevel="h5" | ||
| /> | ||
| <EmptyStateBody> | ||
| {__('The preupgrade report shows no issues.')} | ||
| </EmptyStateBody> | ||
| </EmptyState> | ||
| </Td> | ||
| </Tr> | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be just sent as a prop to the Table emptyMessage={__('The preupgrade report shows no issues.')}
- wrappers in columns instead of explicity tbody - no tableindexpage - no childrenOutsideTbody - no customEmptyState
1cf15c8 to
c7c4653
Compare
- use perPage over per_page whereever possible - drop custom bottom pagination & friends
c7c4653 to
2c260dd
Compare
| import { Table } from 'foremanReact/components/PF4/TableIndexPage/Table/Table'; | ||
| import { APIActions } from 'foremanReact/redux/API'; | ||
| import { entriesPage } from '../PreupgradeReports/PreupgradeReportsHelpers'; | ||
| import { STATUS, renderSeverityLabel } from './PreupgradeReportsTableConstants'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
STATUS should come from foreman core, and not re-defined here
| .leapp-report-section .table-title-section, | ||
| .leapp-report-section .table-toolbar-section { | ||
| padding-top: 0 !important; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This css is no longer needed as the css classes are not present anymore
| export const STATUS = { | ||
| PENDING: 'PENDING', | ||
| RESOLVED: 'RESOLVED', | ||
| ERROR: 'ERROR', | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be imported from core and not redefined
| export const STATUS = { | ||
| PENDING: 'PENDING', | ||
| RESOLVED: 'RESOLVED', | ||
| ERROR: 'ERROR', | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be imported from core and not redefined
- drop redefined STATUS constant - drop unused css - move rendering function out of constants
92b3a3b to
6a684d4
Compare
| const { perPage, perPageOptions } = useForemanSettings(); | ||
| const [pagination, setPagination] = useState({ | ||
| page: 1, | ||
| per_page: perPage, | ||
| perPage, | ||
| perPageOptions, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
perPageOptions seem to be non-standard (see theforeman/foreman#10823 (comment)), what if I dropped it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it will probably be undefined and can be removed, also I dont see it being used as a value anywhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for confirming, I just dropped it
TO-DO: Fix tests
#38951 needs to be merged for this PR
Before:

After:
