Update Transition, upgrade packages and fix compilation issues arising from it#1378
Update Transition, upgrade packages and fix compilation issues arising from it#1378tahini merged 3 commits intochairemobilite:mainfrom
Conversation
WalkthroughThis PR updates dependencies across the monorepo (i18next, React, react-i18next, and others), refactors i18n integration from withTranslation HOCs to useTranslation hooks in multiple components (InterviewList, InputRange, Button), exports the Filter type from InterviewList for reuse, updates DOM structures around Markdown components, changes locale imports in InputDatePicker, and updates component tests with new fixtures and navigation mocks. A bcrypt hash prefix test expectation is also updated. Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/evolution-frontend/src/components/inputs/__tests__/InputMapFindPlace.test.tsx (1)
184-189: Update the stale comment to match the new option count.The comment still says 4 children, but the assertion now expects 3. Please align the comment to avoid confusion.
Suggested fix
- // The select list should display 4 children (2 places and the 2 extra elements) and should not have a confirm button + // The select list should display 3 children (2 places + empty choice) and should not have a confirm button
🤖 Fix all issues with AI agents
In
`@packages/evolution-frontend/src/components/admin/validations/InterviewList.tsx`:
- Around line 145-147: The button in InterviewList.tsx that renders <button
title={t('admin:HideInterviewList')} onClick={() =>
props.interviewListChange(false)}> (which contains FontAwesomeIcon and faFolder
and calls props.interviewListChange) needs an explicit type to avoid being
treated as a form submit button; change the element to include type="button" so
clicking it only triggers the onClick handler and does not submit any parent
form.
In
`@packages/evolution-frontend/src/components/admin/validations/ValidationAuditFilter.tsx`:
- Around line 146-152: Keep the temporary 'as any' cast but clarify the FIXME by
turning it into a TODO that indicates this is an intentional short-term
workaround and that the long-term fix is to type the select styles using
react-select's StylesConfig; specifically update the comment above the option
style function (the option: (baseStyles, _state) => ({...}) as any) to state
it's deliberate for now and reference StylesConfig as the target for future
typing cleanup.
| <button title={t('admin:HideInterviewList')} onClick={() => props.interviewListChange(false)}> | ||
| <FontAwesomeIcon icon={faFolder} /> | ||
| </button> |
There was a problem hiding this comment.
Add explicit type="button" to prevent unintended form submission.
Without an explicit type, buttons default to type="submit".
Proposed fix
- <button title={t('admin:HideInterviewList')} onClick={() => props.interviewListChange(false)}>
+ <button type="button" title={t('admin:HideInterviewList')} onClick={() => props.interviewListChange(false)}>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <button title={t('admin:HideInterviewList')} onClick={() => props.interviewListChange(false)}> | |
| <FontAwesomeIcon icon={faFolder} /> | |
| </button> | |
| <button type="button" title={t('admin:HideInterviewList')} onClick={() => props.interviewListChange(false)}> | |
| <FontAwesomeIcon icon={faFolder} /> | |
| </button> |
🧰 Tools
🪛 Biome (2.1.2)
[error] 145-145: Provide an explicit type prop for the button element.
The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset
(lint/a11y/useButtonType)
🤖 Prompt for AI Agents
In
`@packages/evolution-frontend/src/components/admin/validations/InterviewList.tsx`
around lines 145 - 147, The button in InterviewList.tsx that renders <button
title={t('admin:HideInterviewList')} onClick={() =>
props.interviewListChange(false)}> (which contains FontAwesomeIcon and faFolder
and calls props.interviewListChange) needs an explicit type to avoid being
treated as a form submit button; change the element to include type="button" so
clicking it only triggers the onClick handler and does not submit any parent
form.
| // FIXME Remove the need for 'as any' by typing the styles properly. But there is compilation error even though it should be correct. | ||
| option: (baseStyles, _state) => | ||
| ({ | ||
| ...baseStyles, | ||
| paddingTop: 0, | ||
| paddingBottom: 0 | ||
| }) as any |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
🧩 Analysis chain
🏁 Script executed:
cat -n packages/evolution-frontend/src/components/admin/validations/ValidationAuditFilter.tsx | sed -n '140,160p'Repository: chairemobilite/evolution
Length of output: 1322
🌐 Web query:
react-select v5 StylesConfig type definition
💡 Result:
In react-select v5, StylesConfig is defined (in src/styles.d.ts) as:
export type StylesConfig<
Option = unknown,
IsMulti extends boolean = boolean,
Group extends GroupBase<Option> = GroupBase<Option>
> = {
[K in keyof StylesProps<Option, IsMulti, Group>]?: (
base: CSSObjectWithLabel,
props: StylesProps<Option, IsMulti, Group>[K]
) => CSSObjectWithLabel;
};[1]
It’s exported from the package entry so you can use it as:
import type { StylesConfig } from "react-select";[2]
The as any cast is a reasonable temporary workaround.
The FIXME comment properly documents this technical debt. When you have time to revisit, consider typing the styles prop with react-select's StylesConfig type for proper type safety.
🤖 Prompt for AI Agents
In
`@packages/evolution-frontend/src/components/admin/validations/ValidationAuditFilter.tsx`
around lines 146 - 152, Keep the temporary 'as any' cast but clarify the FIXME
by turning it into a TODO that indicates this is an intentional short-term
workaround and that the long-term fix is to type the select styles using
react-select's StylesConfig; specifically update the comment above the option
style function (the option: (baseStyles, _state) => ({...}) as any) to state
it's deliberate for now and reference StylesConfig as the target for future
typing cleanup.
samuel-duhaime
left a comment
There was a problem hiding this comment.
I accept, but make sure we haven't broken anything with Playwright and fix the unit test.
There was a problem hiding this comment.
@tahini Can you verify if survey-question__input (and other new term) was used with the Playwright test UI? So we don't break anything.
There was a problem hiding this comment.
UI tests are not broken
17dc5a9 to
40b0827
Compare
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Fix all issues with AI agents
In `@example/demo_survey/package.json`:
- Around line 47-49: The package.json dependency versions may be incompatible or
require config changes: verify that i18next >= 25.6.2 is present (add it if
missing) to satisfy react-i18next@16.5.3; review and, if your app submits
cross-origin actions, update react-router configuration (see
react-router.config.ts) to include allowedActionOrigins to permit
external-origin submissions for react-router@7.12.0; audit code for React 19.2
breaking changes (hooks useId prefix, eslint-plugin-react-hooks@6, SSR/Suspense
batching) and, if using React Server Components, bump React to 19.2.4+ (change
the "react" entry) to get the RSC security fixes.
In
`@packages/evolution-frontend/src/components/inputs/__tests__/InputRange.test.tsx`:
- Around line 29-45: The mock MockInputCheckbox currently hardcodes the emitted
value and assumes choices[0] exists; update the mock so it reads the actual
choice value and guards against empty choices: in the mock function
(MockInputCheckbox) derive a safeChoiceValue = choices && choices.length ?
choices[0].value : 'true' (or ''), set the input value to safeChoiceValue, set
checked to Array.isArray(value) ? value.includes(safeChoiceValue) : false, and
onChange call onValueChange({ target: { value: e.target.checked ?
[safeChoiceValue] : [] } }) so snapshots reflect real choice values and the mock
won’t crash when choices is empty.
In `@packages/evolution-frontend/src/components/survey/__tests__/Button.test.tsx`:
- Around line 22-35: The mocked ConfirmModal's buttons in MockConfirmModal do
not have explicit type attributes which can trigger linter/warning issues;
update the mock defined in the jest.mock callback (the MockConfirmModal
function) to add type="button" to both the cancel and confirm buttons (the
elements invoking props.cancelAction/props.confirmAction and using
props.cancelButtonLabel/props.confirmButtonLabel) so they are explicit
non-submit buttons in tests.
In
`@packages/evolution-frontend/src/components/survey/__tests__/GroupWidgets.test.tsx`:
- Around line 23-36: The mock ConfirmModal implementation (MockConfirmModal)
renders two buttons without an explicit type which triggers linter warnings;
update the mock in GroupWidgets.test.tsx so both button elements include
type="button" (the cancel and confirm buttons rendered with
props.cancelAction/props.confirmAction) to match Button.test.tsx and silence the
warnings.
In
`@packages/evolution-frontend/src/components/survey/widgets/__tests__/DeleteGroupedObjectButton.test.tsx`:
- Around line 18-28: The mocked ConfirmModal function (MockConfirmModal) renders
two buttons that currently lack explicit types; update the mock so both button
elements that call props.cancelAction and props.confirmAction include
type="button" to avoid default submit behavior and satisfy lint/a11y rules,
keeping the rest of the mock structure unchanged.
In `@packages/evolution-generator/package.json`:
- Line 31: Three components (RefreshInterviewerCache, ExportInterviewData,
InterviewsPage) still use the withTranslation HOC; convert each to the
useTranslation hook: remove the import and use of withTranslation and any
WithTranslation prop types, add import { useTranslation } from 'react-i18next',
call const { t } = useTranslation() at the top of the component body (or const {
t } = useTranslation('yourNamespace') if a namespace was used before), replace
all occurrences of props.t or this.props.t with t, and change the export to the
plain component (no HOC wrap). Ensure prop interfaces are updated to drop
WithTranslation and the components remain function components or are converted
from wrapped declarations accordingly.
| "react": "^19.2.3", | ||
| "react-i18next": "^16.5.3", | ||
| "react-router": "^7.12.0", |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
React 19.2.3 peer dependencies requirements breaking changes
💡 Result:
Peer dependency requirements (React 19.2.3 era)
-
react@19.2.3- Peer deps: none (the
reactpackage declares nopeerDependencies). [1]
- Peer deps: none (the
-
react-dom@19.2.x- Peer deps:
react(React DOM expects React to be kept in sync). For example,react-dom@19.2.2declarespeerDependencies: { "react": "^19.2.2" }(and19.2.3follows the same “same-version caret” pairing pattern). [2]
- Peer deps:
-
If you use React Server Components packages (common via frameworks)
react-server-dom-webpack@19.2.3peer deps:react@^19.2.3,react-dom@^19.2.3, andwebpack@^5.59.0. [3]- (Similar peer-dep coupling applies to the other
react-server-dom-*packages.)
Breaking changes
-
19.2.3itself (patch release): no intentional breaking changes; it’s a patch with a small React Server Components fix (“extra loop protection to React Server Functions”). [4] -
Breaking / notable behavior changes come from
React 19.2(minor release), not19.2.3:- React 19.2’s “Notable Changes” include SSR/Suspense batching changes, Node Web Streams support for SSR,
eslint-plugin-react-hooksv6, and an update to the defaultuseIdprefix. [5]
- React 19.2’s “Notable Changes” include SSR/Suspense batching changes, Node Web Streams support for SSR,
Important caveat (security / “upgrade again” note)
- If you’re using React Server Components packages (
react-server-dom-webpack/-parcel/-turbopack), React’s security guidance (updated Jan 26, 2026) says that 19.2.3 is incomplete for the then-current RSC vulnerabilities, and you should upgrade to the fixed backport 19.2.4 (or newer) for those packages. [6]
Sources:
[1] react@19.2.3 package.json (UNPKG)
[2] react-dom@19.2.2 package.json (UNPKG)
[3] react-server-dom-webpack@19.2.3 package.json (UNPKG)
[4] facebook/react v19.2.3 release notes (GitHub)
[5] React 19.2 blog post (react.dev)
[6] RSC vulnerabilities + upgrade guidance (react.dev, updated Jan 26, 2026)
🌐 Web query:
react-i18next 16.5.3 peer dependencies requirements breaking changes
💡 Result:
react-i18next 16.5.3 peer dependency requirements
From the v16.5.x package manifest, react-i18next expects these peers (TypeScript is optional, but required for type-checking the library’s .d.ts/.d.mts cleanly):
- react:
>= 16.8.0 - i18next:
>= 25.6.2 - typescript:
^5(optional peer) - react-dom: optional peer
- react-native: optional peer [1]
Breaking changes / upgrade impact
In 16.5.3 itself
- No breaking changes; it’s a patch release with: “fix: Trans named tags with underscore”. [2]
When upgrading to v16.x (relevant “breaking-ish” changes vs older majors)
- Higher required i18next: you may need to upgrade
i18nextto >= 25.6.2 to satisfy peer deps. [1] - TypeScript 5 expectation: v16.x declares TS
^5as a (optional) peer; this aligns with upstream i18next type patterns that aren’t compatible with TS4-era tooling. [1][3]
Sources: [1] package.json (v16.5.x) via UNPKG, [2] v16.5.3 changelog entry, [3] upstream i18next TypeScript 4 incompatibility discussion.
🌐 Web query:
react-router 7.12.0 peer dependencies breaking changes compatibility
💡 Result:
Peer dependencies / engines in react-router / react-router-dom 7.12.0
- React:
>=18 - react-dom:
>=18(forreact-router-dom; and is a peer forreact-routeras well) - Node:
>=20(engine requirement)
These constraints are shown directly in thereact-router-dom@7.12.0package.json, which depends onreact-router@7.12.0. [1] React Router’s upgrade docs also state v7 requiresnode@20,react@18,react-dom@18. [2]
Compatibility note: Because the peer range is >=18, React Router 7.12.0 is compatible with React 18 and React 19, assuming the rest of your dependency tree allows it. [1]
Breaking/behavior changes called out for 7.12.0
7.12.0 is primarily a security release, but it includes a potentially breaking behavior change if your app relies on cross-origin submissions to “UI routes”:
- React Router now rejects submissions to UI routes from external origins as an additional CSRF protection layer. [3]
- If you intentionally need to allow specific external origins, you must configure the new
allowedActionOriginsfield inreact-router.config.ts. [3]
Common “peer dependency conflict” you may be seeing
If a third-party package declares peers like react-router: "7" (or similar), you cannot satisfy it with react-router-dom@6.x; npm will report a peer conflict until you upgrade to v7 or the library broadens its peer range. (Example of this class of issue: a library requiring react-router: "7" while the app is still on react-router-dom@6.) [4]
Sources: [1] [2] [3] [4]
Confirm i18next version and review breaking changes for React & Router.
- react-i18next 16.5.3 requires
i18next ≥ 25.6.2—verify this dependency is present. - react-router 7.12.0 introduces CSRF protection that rejects external-origin submissions to UI routes. If needed, add
allowedActionOriginsconfig inreact-router.config.ts. - React 19.2 includes breaking changes:
useIdprefix update,eslint-plugin-react-hooks@6, and SSR/Suspense batching. Review app impact. - If using React Server Components, upgrade React to
19.2.4+(19.2.3 has incomplete RSC security fixes).
🤖 Prompt for AI Agents
In `@example/demo_survey/package.json` around lines 47 - 49, The package.json
dependency versions may be incompatible or require config changes: verify that
i18next >= 25.6.2 is present (add it if missing) to satisfy
react-i18next@16.5.3; review and, if your app submits cross-origin actions,
update react-router configuration (see react-router.config.ts) to include
allowedActionOrigins to permit external-origin submissions for
react-router@7.12.0; audit code for React 19.2 breaking changes (hooks useId
prefix, eslint-plugin-react-hooks@6, SSR/Suspense batching) and, if using React
Server Components, bump React to 19.2.4+ (change the "react" entry) to get the
RSC security fixes.
| // Mock the InputCheckbox component, as it uses many react hooks and libraries that make jest fail. For this component, the checkbox will contain only one choice | ||
| jest.mock('chaire-lib-frontend/lib/components/input/InputCheckbox', () => { | ||
| return function MockInputCheckbox({ id, value, onValueChange, choices }: any) { | ||
| return ( | ||
| <div data-testid={`mock-checkbox-${id}`}> | ||
| <input | ||
| type="checkbox" | ||
| id={id} | ||
| checked={value && value.length > 0} | ||
| value={choices[0].value} | ||
| onChange={(e) => onValueChange({ target: { value: e.target.checked ? ['true'] : [] } })} | ||
| /> | ||
| <label htmlFor={id}>{choices[0].label}</label> | ||
| </div> | ||
| ); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Mock returns a hardcoded value; this can hide regressions.
onValueChange always emits ['true'] and assumes choices[0] exists. If the real component uses the choice value (e.g., 'na'), snapshots won’t reflect mismatches and the mock may crash when choices is empty. Consider aligning the mock to the actual choice value and guarding against empty choices.
✅ Suggested fix
- return function MockInputCheckbox({ id, value, onValueChange, choices }: any) {
+ return function MockInputCheckbox({ id, value, onValueChange, choices }: any) {
+ const firstChoice = choices?.[0];
+ if (!firstChoice) {
+ return null;
+ }
return (
<div data-testid={`mock-checkbox-${id}`}>
<input
type="checkbox"
id={id}
- checked={value && value.length > 0}
- value={choices[0].value}
- onChange={(e) => onValueChange({ target: { value: e.target.checked ? ['true'] : [] } })}
+ checked={Array.isArray(value) ? value.includes(firstChoice.value) : value === firstChoice.value}
+ value={firstChoice.value}
+ onChange={(e) =>
+ onValueChange({ target: { value: e.target.checked ? [firstChoice.value] : [] } })
+ }
/>
- <label htmlFor={id}>{choices[0].label}</label>
+ <label htmlFor={id}>{firstChoice.label}</label>
</div>
);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Mock the InputCheckbox component, as it uses many react hooks and libraries that make jest fail. For this component, the checkbox will contain only one choice | |
| jest.mock('chaire-lib-frontend/lib/components/input/InputCheckbox', () => { | |
| return function MockInputCheckbox({ id, value, onValueChange, choices }: any) { | |
| return ( | |
| <div data-testid={`mock-checkbox-${id}`}> | |
| <input | |
| type="checkbox" | |
| id={id} | |
| checked={value && value.length > 0} | |
| value={choices[0].value} | |
| onChange={(e) => onValueChange({ target: { value: e.target.checked ? ['true'] : [] } })} | |
| /> | |
| <label htmlFor={id}>{choices[0].label}</label> | |
| </div> | |
| ); | |
| } | |
| }); | |
| // Mock the InputCheckbox component, as it uses many react hooks and libraries that make jest fail. For this component, the checkbox will contain only one choice | |
| jest.mock('chaire-lib-frontend/lib/components/input/InputCheckbox', () => { | |
| return function MockInputCheckbox({ id, value, onValueChange, choices }: any) { | |
| const firstChoice = choices?.[0]; | |
| if (!firstChoice) { | |
| return null; | |
| } | |
| return ( | |
| <div data-testid={`mock-checkbox-${id}`}> | |
| <input | |
| type="checkbox" | |
| id={id} | |
| checked={Array.isArray(value) ? value.includes(firstChoice.value) : value === firstChoice.value} | |
| value={firstChoice.value} | |
| onChange={(e) => | |
| onValueChange({ target: { value: e.target.checked ? [firstChoice.value] : [] } }) | |
| } | |
| /> | |
| <label htmlFor={id}>{firstChoice.label}</label> | |
| </div> | |
| ); | |
| } | |
| }); |
🤖 Prompt for AI Agents
In
`@packages/evolution-frontend/src/components/inputs/__tests__/InputRange.test.tsx`
around lines 29 - 45, The mock MockInputCheckbox currently hardcodes the emitted
value and assumes choices[0] exists; update the mock so it reads the actual
choice value and guards against empty choices: in the mock function
(MockInputCheckbox) derive a safeChoiceValue = choices && choices.length ?
choices[0].value : 'true' (or ''), set the input value to safeChoiceValue, set
checked to Array.isArray(value) ? value.includes(safeChoiceValue) : false, and
onChange call onValueChange({ target: { value: e.target.checked ?
[safeChoiceValue] : [] } }) so snapshots reflect real choice values and the mock
won’t crash when choices is empty.
| // Mock the ConfirmModal component, as it uses many react hooks and libraries that make jest fail | ||
| jest.mock('chaire-lib-frontend/lib/components/modal/ConfirmModal', () => { | ||
| return function MockConfirmModal(props: any) { | ||
| if (!props.isOpen) return null; | ||
| return ( | ||
| <div role="dialog" aria-label={props.title}> | ||
| <div>{props.title}</div> | ||
| <div>{props.text}</div> | ||
| <button onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button> | ||
| <button onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button> | ||
| </div> | ||
| ); | ||
| }; | ||
| }); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Add explicit type="button" to mock buttons.
The mock buttons lack explicit type attributes. While this is test code, adding them ensures consistency and silences linter warnings.
Proposed fix
jest.mock('chaire-lib-frontend/lib/components/modal/ConfirmModal', () => {
return function MockConfirmModal(props: any) {
if (!props.isOpen) return null;
return (
<div role="dialog" aria-label={props.title}>
<div>{props.title}</div>
<div>{props.text}</div>
- <button onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button>
- <button onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button>
+ <button type="button" onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button>
+ <button type="button" onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button>
</div>
);
};
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Mock the ConfirmModal component, as it uses many react hooks and libraries that make jest fail | |
| jest.mock('chaire-lib-frontend/lib/components/modal/ConfirmModal', () => { | |
| return function MockConfirmModal(props: any) { | |
| if (!props.isOpen) return null; | |
| return ( | |
| <div role="dialog" aria-label={props.title}> | |
| <div>{props.title}</div> | |
| <div>{props.text}</div> | |
| <button onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button> | |
| <button onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button> | |
| </div> | |
| ); | |
| }; | |
| }); | |
| // Mock the ConfirmModal component, as it uses many react hooks and libraries that make jest fail | |
| jest.mock('chaire-lib-frontend/lib/components/modal/ConfirmModal', () => { | |
| return function MockConfirmModal(props: any) { | |
| if (!props.isOpen) return null; | |
| return ( | |
| <div role="dialog" aria-label={props.title}> | |
| <div>{props.title}</div> | |
| <div>{props.text}</div> | |
| <button type="button" onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button> | |
| <button type="button" onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button> | |
| </div> | |
| ); | |
| }; | |
| }); |
🧰 Tools
🪛 Biome (2.1.2)
[error] 30-30: Provide an explicit type prop for the button element.
The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset
(lint/a11y/useButtonType)
[error] 31-31: Provide an explicit type prop for the button element.
The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset
(lint/a11y/useButtonType)
🤖 Prompt for AI Agents
In `@packages/evolution-frontend/src/components/survey/__tests__/Button.test.tsx`
around lines 22 - 35, The mocked ConfirmModal's buttons in MockConfirmModal do
not have explicit type attributes which can trigger linter/warning issues;
update the mock defined in the jest.mock callback (the MockConfirmModal
function) to add type="button" to both the cancel and confirm buttons (the
elements invoking props.cancelAction/props.confirmAction and using
props.cancelButtonLabel/props.confirmButtonLabel) so they are explicit
non-submit buttons in tests.
| // Mock the ConfirmModal component, as it uses many react hooks and libraries that make jest fail | ||
| jest.mock('chaire-lib-frontend/lib/components/modal/ConfirmModal', () => { | ||
| return function MockConfirmModal(props: any) { | ||
| if (!props.isOpen) return null; | ||
| return ( | ||
| <div role="dialog" aria-label={props.title}> | ||
| <div>{props.title}</div> | ||
| <div>{props.text}</div> | ||
| <button onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button> | ||
| <button onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button> | ||
| </div> | ||
| ); | ||
| }; | ||
| }); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Add explicit type="button" to mock buttons.
Same issue as in Button.test.tsx. Adding type="button" improves consistency and silences linter warnings.
Proposed fix
jest.mock('chaire-lib-frontend/lib/components/modal/ConfirmModal', () => {
return function MockConfirmModal(props: any) {
if (!props.isOpen) return null;
return (
<div role="dialog" aria-label={props.title}>
<div>{props.title}</div>
<div>{props.text}</div>
- <button onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button>
- <button onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button>
+ <button type="button" onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button>
+ <button type="button" onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button>
</div>
);
};
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Mock the ConfirmModal component, as it uses many react hooks and libraries that make jest fail | |
| jest.mock('chaire-lib-frontend/lib/components/modal/ConfirmModal', () => { | |
| return function MockConfirmModal(props: any) { | |
| if (!props.isOpen) return null; | |
| return ( | |
| <div role="dialog" aria-label={props.title}> | |
| <div>{props.title}</div> | |
| <div>{props.text}</div> | |
| <button onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button> | |
| <button onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button> | |
| </div> | |
| ); | |
| }; | |
| }); | |
| // Mock the ConfirmModal component, as it uses many react hooks and libraries that make jest fail | |
| jest.mock('chaire-lib-frontend/lib/components/modal/ConfirmModal', () => { | |
| return function MockConfirmModal(props: any) { | |
| if (!props.isOpen) return null; | |
| return ( | |
| <div role="dialog" aria-label={props.title}> | |
| <div>{props.title}</div> | |
| <div>{props.text}</div> | |
| <button type="button" onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button> | |
| <button type="button" onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button> | |
| </div> | |
| ); | |
| }; | |
| }); |
🧰 Tools
🪛 Biome (2.1.2)
[error] 31-31: Provide an explicit type prop for the button element.
The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset
(lint/a11y/useButtonType)
[error] 32-32: Provide an explicit type prop for the button element.
The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset
(lint/a11y/useButtonType)
🤖 Prompt for AI Agents
In
`@packages/evolution-frontend/src/components/survey/__tests__/GroupWidgets.test.tsx`
around lines 23 - 36, The mock ConfirmModal implementation (MockConfirmModal)
renders two buttons without an explicit type which triggers linter warnings;
update the mock in GroupWidgets.test.tsx so both button elements include
type="button" (the cancel and confirm buttons rendered with
props.cancelAction/props.confirmAction) to match Button.test.tsx and silence the
warnings.
| // Mock the ConfirmModal component, as it uses many react hooks and libraries that make jest fail | ||
| jest.mock('chaire-lib-frontend/lib/components/modal/ConfirmModal', () => { | ||
| return function MockConfirmModal(props: any) { | ||
| if (!props.isOpen) return null; | ||
| return ( | ||
| <div role="dialog" aria-label={props.title}> | ||
| <div>{props.title}</div> | ||
| <div>{props.text}</div> | ||
| <button onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button> | ||
| <button onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button> | ||
| </div> |
There was a problem hiding this comment.
Add explicit type="button" to mock buttons to satisfy lint/a11y.
This avoids default submit behavior and clears the lint error.
Proposed fix
- <button onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button>
- <button onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button>
+ <button type="button" onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button>
+ <button type="button" onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Mock the ConfirmModal component, as it uses many react hooks and libraries that make jest fail | |
| jest.mock('chaire-lib-frontend/lib/components/modal/ConfirmModal', () => { | |
| return function MockConfirmModal(props: any) { | |
| if (!props.isOpen) return null; | |
| return ( | |
| <div role="dialog" aria-label={props.title}> | |
| <div>{props.title}</div> | |
| <div>{props.text}</div> | |
| <button onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button> | |
| <button onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button> | |
| </div> | |
| // Mock the ConfirmModal component, as it uses many react hooks and libraries that make jest fail | |
| jest.mock('chaire-lib-frontend/lib/components/modal/ConfirmModal', () => { | |
| return function MockConfirmModal(props: any) { | |
| if (!props.isOpen) return null; | |
| return ( | |
| <div role="dialog" aria-label={props.title}> | |
| <div>{props.title}</div> | |
| <div>{props.text}</div> | |
| <button type="button" onClick={props.cancelAction}>{props.cancelButtonLabel || 'Cancel'}</button> | |
| <button type="button" onClick={props.confirmAction}>{props.confirmButtonLabel || 'Confirm'}</button> | |
| </div> |
🧰 Tools
🪛 Biome (2.1.2)
[error] 26-26: Provide an explicit type prop for the button element.
The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset
(lint/a11y/useButtonType)
[error] 27-27: Provide an explicit type prop for the button element.
The default type of a button is submit, which causes the submission of a form when placed inside a form element. This is likely not the behaviour that you want inside a React application.
Allowed button types are: submit, button or reset
(lint/a11y/useButtonType)
🤖 Prompt for AI Agents
In
`@packages/evolution-frontend/src/components/survey/widgets/__tests__/DeleteGroupedObjectButton.test.tsx`
around lines 18 - 28, The mocked ConfirmModal function (MockConfirmModal)
renders two buttons that currently lack explicit types; update the mock so both
button elements that call props.cancelAction and props.confirmAction include
type="button" to avoid default submit behavior and satisfy lint/a11y rules,
keeping the rest of the mock structure unchanged.
| "evolution-common": "^0.5.0", | ||
| "evolution-frontend": "^0.5.0", | ||
| "i18next": "^24.0.2" | ||
| "i18next": "^25.7.4" |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
i18next v25 breaking changes migration guide
💡 Result:
i18next v25: breaking changes + migration notes (from v24 → v25)
Potentially breaking changes in v25.0.0
-
Multiple
changeLanguage()calls are handled in the correct order now
If your app relied (intentionally or accidentally) on the previous wrong ordering (race behavior), you may see different final language / event timing. Re-test any flows that can trigger rapid consecutive language changes (startup, route changes, auth redirects, etc.). [1][2] -
changeLanguage()now always resolves languages viagetBestMatchFromCodes(whether you pass a string or an array)
This can change which language ultimately gets chosen in some setups (especially with region/script variants). [1][2] -
getBestMatchFromCodesnow tries to fall back to a language code with the same script
If you have script-specific locales (e.g.,zh-Hans,zh-Hant), matching/fallback behavior may differ vs v24. Validate that the resolved language still matches your expectations. [1][2]
Recommended migration checklist
- Search your codebase for all
changeLanguage(call sites; add/adjust guards/debouncing if multiple calls can happen close together, and update tests around “final language wins” behavior. [1][2] - Verify language matching for your supported locales (especially script/region variants) by testing
i18next.language,i18next.languages, and actual loaded resources after callingchangeLanguage(). [1] - If you’re upgrading within v25 as well: v25.4.0 adds an optional selector API for TypeScript IDE performance (
enableSelector: true/"optimize"), plus related tooling. This is opt-in (not a required breaking change), but it’s included in the v25 migration guide. [1]
Primary reference: i18next Migration Guide (section “v24.x.x to v25.0.0”). [1]
🏁 Script executed:
# Search for changeLanguage calls in the codebase
rg "changeLanguage" --type ts --type tsx --type js --type jsx -A 2 -B 2Repository: chairemobilite/evolution
Length of output: 95
🏁 Script executed:
# Search for i18next imports and usage patterns
rg "i18next|useTranslation|withTranslation" --type ts --type tsx --type js --type jsx | head -50Repository: chairemobilite/evolution
Length of output: 95
🏁 Script executed:
# Search for changeLanguage calls in the codebase
rg "changeLanguage" -A 2 -B 2Repository: chairemobilite/evolution
Length of output: 3180
🏁 Script executed:
# Search for i18next imports and usage patterns
rg "i18next|useTranslation|withTranslation" | head -80Repository: chairemobilite/evolution
Length of output: 9303
Complete migration from withTranslation HOC to useTranslation hook.
Three components still use the older withTranslation pattern:
packages/evolution-interviewer/src/client/components/monitoring/RefreshInterviewerCache.tsxpackages/evolution-frontend/src/components/admin/pages/ExportInterviewData.tsxpackages/evolution-frontend/src/components/admin/pages/InterviewsPage.tsx
Update these to use the useTranslation hook for consistency with the rest of the codebase and modern React patterns.
🤖 Prompt for AI Agents
In `@packages/evolution-generator/package.json` at line 31, Three components
(RefreshInterviewerCache, ExportInterviewData, InterviewsPage) still use the
withTranslation HOC; convert each to the useTranslation hook: remove the import
and use of withTranslation and any WithTranslation prop types, add import {
useTranslation } from 'react-i18next', call const { t } = useTranslation() at
the top of the component body (or const { t } = useTranslation('yourNamespace')
if a namespace was used before), replace all occurrences of props.t or
this.props.t with t, and change the export to the plain component (no HOC wrap).
Ensure prop interfaces are updated to drop WithTranslation and the components
remain function components or are converted from wrapped declarations
accordingly.
The select input in map find place and the checkbox in the input range do not need to use evolution's version of the widget. Especially that the widget config was limited to the strict minimum because it does not require the interview, path, etc. Stricter typescript fails to compile with those widgets.
The `InterviewList` needs the `Filter` type, which is defined in its parent component, so it is of unknow type. This causes compilation failure with the react updates. Also update the component to use the `useTranslation` hook instead of `withTranslation` HOC.
* i18next: 24.0.5 => 25.7.4 * date-fns: 2.29.1 => 4.1.0 * i18next-browser-languagedetector: 8.0.0 => 8.2.0 * react: 19.0.0 => 19.2.3 * react-datepicker: 7.6.0 => 9.1.0 * react-dom: 19.0.0 => 19.2.3 * react-i18next: 12.3.1 => 16.5.3 * react-markdown: 9.0.1 => 10.1.0 * react-router: 7.5.2 => 7.12.0 * react-select: 5.8.3 => 5.10.2 * react-spinners: 0.14.1 => 0.17.0 * remark-gfm: 4.0.0 => 4.0.1 * @testing-library/jest-dom: 6.6.3 => 6.9.1 * @testing-library/react: 16.3.0 => 16.3.1 * @types/reactj-dom: 19.0.2 => 19.2.3 * drop @types/react-select * i18next-fs-backend:2.6.0 => 2.6.1 The `Markdown` component does not take a `className` anymore, so the class needs to be added manually to a parent `div`. Update snapshots accordingly. The update the chaire-lib's bcrypt package changed the format of password hash, so the `participantAuthModel.test.ts` needed updating. Also, with the @testing-library/react update, it seems that the typing in tests is now more enforced, requiring better test data.
40b0827 to
56b62b6
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/evolution-frontend/src/components/inputs/__tests__/InputMapFindPlace.test.tsx (1)
184-190: Test expectations correctly updated for the new InputSelect.The comment on line 184 mentions "4 children" but the assertion now expects 3. Consider updating the comment to match.
📝 Suggested comment fix
- // The select list should display 4 children (2 places and the 2 extra elements) and should not have a confirm button + // The select list should display 3 children (2 places + 1 empty option) and should not have a confirm button
🤖 Fix all issues with AI agents
In `@packages/evolution-frontend/package.json`:
- Around line 45-95: The project is missing eslint-plugin-react-hooks which
enforces the Rules of Hooks for React 19; add "eslint-plugin-react-hooks" to the
devDependencies in packages/evolution-frontend/package.json (and root
package.json if present) and then update the ESLint config
(configs/react.eslintrc.json) to extend "plugin:react-hooks/recommended" so the
rules are applied; ensure the package name is correct and run npm/yarn install
and lint to verify no new violations.
| "date-fns": "^4.1.0", | ||
| "dompurify": "^3.2.4", | ||
| "evolution-common": "^0.5.0", | ||
| "geojson": "^0.5.0", | ||
| "geojson-validation": "^1.0.2", | ||
| "gl-matrix": "^3.4.3", | ||
| "highcharts": "^12.1.2", | ||
| "highcharts-react-official": "^3.2.1", | ||
| "i18next": "^24.0.5", | ||
| "i18next-browser-languagedetector": "^8.0.0", | ||
| "i18next": "^25.7.4", | ||
| "i18next-browser-languagedetector": "^8.2.0", | ||
| "lodash": "^4.17.21", | ||
| "maplibre-gl": "^5.7.1", | ||
| "moment": "^2.30.1", | ||
| "node-fetch": "^2.6.7", | ||
| "p-queue": "^6.6.2", | ||
| "react": "^19.0.0", | ||
| "react-datepicker": "^7.6.0", | ||
| "react-dom": "^19.0.0", | ||
| "react-i18next": "^12.3.1", | ||
| "react": "^19.2.3", | ||
| "react-datepicker": "^9.1.0", | ||
| "react-dom": "^19.2.3", | ||
| "react-i18next": "^16.5.3", | ||
| "react-input-range": "^1.3.0", | ||
| "react-map-gl": "^8.0.4", | ||
| "react-markdown": "^9.0.1", | ||
| "react-markdown": "^10.1.0", | ||
| "react-modal": "^3.16.3", | ||
| "react-redux": "^9.2.0", | ||
| "react-router": "^7.5.2", | ||
| "react-select": "^5.8.3", | ||
| "react-spinners": "^0.14.1", | ||
| "react-router": "^7.12.0", | ||
| "react-select": "^5.10.2", | ||
| "react-spinners": "^0.17.0", | ||
| "react-table": "^7.8.0", | ||
| "redux": "^5.0.1", | ||
| "redux-thunk": "^3.1.0", | ||
| "remark-gfm": "^4.0.0" | ||
| "remark-gfm": "^4.0.1" | ||
| }, | ||
| "devDependencies": { | ||
| "@playwright/test": "^1.56.1", | ||
| "@testing-library/jest-dom": "^6.6.3", | ||
| "@testing-library/react": "^16.3.0", | ||
| "@testing-library/jest-dom": "^6.9.1", | ||
| "@testing-library/react": "^16.3.1", | ||
| "@testing-library/user-event": "^14.6.1", | ||
| "@types/geojson": "^7946.0.16", | ||
| "@types/jest": "^30.0.0", | ||
| "@types/jest-axe": "^3.5.5", | ||
| "@types/lodash": "^4.17.21", | ||
| "@types/node": "^24.10.4", | ||
| "@types/react-dom": "^19.0.2", | ||
| "@types/react-select": "^5.0.1", | ||
| "@types/react-dom": "^19.2.3", | ||
| "@typescript-eslint/eslint-plugin": "^8.50.0", | ||
| "@typescript-eslint/parser": "^8.50.0", | ||
| "cross-env": "^10.1.0", | ||
| "eslint": "^8.57.1", | ||
| "eslint-plugin-n": "^15.7.0", | ||
| "eslint-plugin-react": "^7.37.2", | ||
| "i18next-fs-backend": "^2.6.0", | ||
| "i18next-fs-backend": "^2.6.1", | ||
| "jest": "^30.2.0", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check for eslint-plugin-react-hooks in package.json files
echo "=== Searching for eslint-plugin-react-hooks ==="
rg -n "eslint-plugin-react-hooks" --type jsonRepository: chairemobilite/evolution
Length of output: 115
🏁 Script executed:
#!/bin/bash
# List the actual package.json in the frontend directory
echo "=== Content of packages/evolution-frontend/package.json (devDependencies section) ==="
sed -n '/devDependencies/,/^[[:space:]]*}/p' packages/evolution-frontend/package.json | head -50Repository: chairemobilite/evolution
Length of output: 1057
🏁 Script executed:
#!/bin/bash
# Check for test files that might cover date-fns or react-datepicker
echo "=== Searching for test files related to date-fns or react-datepicker ==="
find packages/evolution-frontend -type f \( -name "*.test.ts*" -o -name "*.test.js*" -o -name "*.spec.ts*" -o -name "*.spec.js*" \) | head -20Repository: chairemobilite/evolution
Length of output: 1834
🏁 Script executed:
#!/bin/bash
# Check for React hooks usage and dependencies
echo "=== Checking for React compatibility references ==="
rg "eslint-plugin-react" packages/evolution-frontend/package.json -A 2 -B 2Repository: chairemobilite/evolution
Length of output: 275
🏁 Script executed:
#!/bin/bash
# Check for eslint config files
echo "=== Looking for ESLint configuration files ==="
find packages/evolution-frontend -maxdepth 3 -type f \( -name ".eslintrc*" -o -name "eslint.config.*" \) | head -10Repository: chairemobilite/evolution
Length of output: 157
🏁 Script executed:
#!/bin/bash
# Check if eslint-plugin-react-hooks is mentioned in any config or docs
echo "=== Searching for react-hooks references in config/docs ==="
rg "react-hooks" packages/evolution-frontend --type-list | head -20Repository: chairemobilite/evolution
Length of output: 534
🏁 Script executed:
#!/bin/bash
# Check the root package.json for eslint-plugin-react-hooks
echo "=== Checking root package.json ==="
cat package.json | grep -A 5 -B 5 "eslint-plugin-react-hooks" 2>/dev/null || echo "Not found in root package.json"Repository: chairemobilite/evolution
Length of output: 133
🏁 Script executed:
#!/bin/bash
# View the ESLint configuration
echo "=== Content of .eslintrc.json ==="
cat packages/evolution-frontend/.eslintrc.jsonRepository: chairemobilite/evolution
Length of output: 158
🏁 Script executed:
#!/bin/bash
# Also check if there's a root eslintrc
echo "=== Checking for root .eslintrc ==="
find . -maxdepth 2 -name ".eslintrc*" -type fRepository: chairemobilite/evolution
Length of output: 103
🏁 Script executed:
#!/bin/bash
# View the shared ESLint config
echo "=== Content of configs/react.eslintrc.json ==="
cat configs/react.eslintrc.jsonRepository: chairemobilite/evolution
Length of output: 1402
Add eslint-plugin-react-hooks for React 19 compatibility.
React 19.2.x requires Rules of Hooks enforcement. The project is missing eslint-plugin-react-hooks entirely—neither the root nor frontend package.json includes it. Add it as a devDependency and extend the ESLint configuration in configs/react.eslintrc.json to include plugin:react-hooks/recommended.
Date-fns v4 and react-datepicker v9 updates appear covered by existing tests (e.g., InputDatePicker.test.tsx).
🤖 Prompt for AI Agents
In `@packages/evolution-frontend/package.json` around lines 45 - 95, The project
is missing eslint-plugin-react-hooks which enforces the Rules of Hooks for React
19; add "eslint-plugin-react-hooks" to the devDependencies in
packages/evolution-frontend/package.json (and root package.json if present) and
then update the ESLint config (configs/react.eslintrc.json) to extend
"plugin:react-hooks/recommended" so the rules are applied; ensure the package
name is correct and run npm/yarn install and lint to verify no new violations.
Use widgets from chaire-lib for the inputMap's select and inputRange's NA checkbox, as the fake evolution widget with incomplete types cause compilation errors.
Define the
Filtertype in InterviewList instead of its callerInterviewListComponent, as otherwise, it isunknownin the list and requires compilation gymnastic, while we know the exact type.Update Transition and various packages to match the update: react & cie, i18next and related:
The
Markdowncomponent does not take aclassNameanymore, so theclass needs to be added manually to a parent
div. Update snapshotsaccordingly.
The update the chaire-lib's bcrypt package changed the format of
password hash, so the
participantAuthModel.test.tsneeded updating.Summary by CodeRabbit
Chores
Bug Fixes
✏️ Tip: You can customize this high-level summary in your review settings.