Skip to content

Conversation

@kmalyjur
Copy link

@kmalyjur kmalyjur commented Dec 15, 2025

TO-DO: Fix tests

#38951 needs to be merged for this PR

Before:
image

After:
image

@kmalyjur kmalyjur changed the title Add basic Leapp preupgrade report table to the new job invocation page Fixes #38958 - Add basic Leapp preupgrade report table to the new job invocation page Dec 15, 2025
@kmalyjur kmalyjur added the breaks-robottelo Can be set via comment: /label breaks-robottelo label Dec 15, 2025
- 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]>
Copy link

@adamlazik1 adamlazik1 left a 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.

Comment on lines 4 to 5
}

No newline at end of file

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing whitespace here.

Suggested change
}
}

Comment on lines 14 to 25
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>
),
}));
Copy link
Contributor

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]>
Copy link
Member

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

Copy link
Contributor

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?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

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?

Copy link
Member

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

Copy link
Member

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

Copy link
Member

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?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done-ish

Comment on lines 174 to 207
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}
Copy link
Member

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

Copy link
Contributor

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,
Copy link
Member

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

Copy link
Contributor

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

Copy link
Member

@MariaAga MariaAga Jan 16, 2026

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

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]>
Comment on lines 18 to 50
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,
},
};

Copy link
Member

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')
        ),
    },
  };

Copy link
Contributor

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.

Copy link
Member

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
Copy link
Member

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

Comment on lines 171 to 180
<TableIndexPage
apiUrl=""
controller="preupgrade_reports"
customToolbarItems={[
<ToolbarItem key="pagination">{topPagination}</ToolbarItem>,
]}
replacementResponse={combinedResponse}
searchable={false}
updateParamsByUrl={false}
>
Copy link
Member

@MariaAga MariaAga Jan 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TableIndexPage is not needed

Comment on lines 148 to 162
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>
);
Copy link
Member

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
- use perPage over per_page whereever possible
- drop custom bottom pagination & friends
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';
Copy link
Member

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

Comment on lines 1 to 4
.leapp-report-section .table-title-section,
.leapp-report-section .table-toolbar-section {
padding-top: 0 !important;
}
Copy link
Member

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

Comment on lines 5 to 9
export const STATUS = {
PENDING: 'PENDING',
RESOLVED: 'RESOLVED',
ERROR: 'ERROR',
};
Copy link
Member

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

Comment on lines 5 to 9
export const STATUS = {
PENDING: 'PENDING',
RESOLVED: 'RESOLVED',
ERROR: 'ERROR',
};
Copy link
Member

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
Comment on lines 22 to 26
const { perPage, perPageOptions } = useForemanSettings();
const [pagination, setPagination] = useState({
page: 1,
per_page: perPage,
perPage,
perPageOptions,
Copy link
Contributor

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?

Copy link
Member

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

Copy link
Contributor

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaks-robottelo Can be set via comment: /label breaks-robottelo Waiting on contributor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants