-
Notifications
You must be signed in to change notification settings - Fork 145
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
feat(react 18): upgrade to react 18. #7336
base: main
Are you sure you want to change the base?
feat(react 18): upgrade to react 18. #7336
Conversation
Merging latest changes
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.
Please update the details for each type of change we did in PR description. Overall PR looks good but provided few nit pick comments. Please check for other similar changes.
src/tests/end-to-end/tests/details-view/fast-pass-report.test.ts
Outdated
Show resolved
Hide resolved
src/tests/unit/tests/DetailsView/components/assessment-instance-table.test.tsx
Outdated
Show resolved
Hide resolved
src/tests/unit/tests/DetailsView/components/assessment-instance-table.test.tsx
Outdated
Show resolved
Hide resolved
src/tests/unit/tests/DetailsView/components/details-view-command-bar.test.tsx
Outdated
Show resolved
Hide resolved
src/tests/unit/tests/DetailsView/no-content-available-view-renderer.test.tsx
Outdated
Show resolved
Hide resolved
src/tests/unit/tests/popup/components/launch-panel-header.test.tsx
Outdated
Show resolved
Hide resolved
src/tests/unit/tests/DetailsView/no-content-available-view-renderer.test.tsx
Show resolved
Hide resolved
src/tests/unit/tests/popup/components/diagnostic-view-toggle.test.tsx
Outdated
Show resolved
Hide resolved
src/tests/unit/tests/popup/components/diagnostic-view-toggle.test.tsx
Outdated
Show resolved
Hide resolved
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 PR is a huge effort! Well done, team! I have some questions about changes, mostly in tests.
.../unit/tests/DetailsView/components/__snapshots__/auto-detected-failures-dialog.test.tsx.snap
Outdated
Show resolved
Hide resolved
src/tests/unit/tests/DetailsView/components/__snapshots__/next-requirement-button.test.tsx.snap
Outdated
Show resolved
Hide resolved
src/tests/unit/tests/DetailsView/components/save-assessment-button.test.tsx
Outdated
Show resolved
Hide resolved
src/tests/unit/tests/DetailsView/components/save-assessment-button.test.tsx
Show resolved
Hide resolved
src/tests/unit/tests/debug-tools/components/stores-tree.test.tsx
Outdated
Show resolved
Hide resolved
…akeshsh/accessibility-insights-web into v-rakeshsh/react18-migration
src/tests/unit/tests/DetailsView/components/save-assessment-button.test.tsx
Show resolved
Hide resolved
src/tests/unit/tests/popup/components/diagnostic-view-toggle.test.tsx
Outdated
Show resolved
Hide resolved
|
||
const renderMock: any = Mock.ofType<typeof createRoot>(); | ||
createRootMock | ||
.setup(r => r(It.isAny())) |
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 don't see this change in the code.
src/tests/unit/tests/DetailsView/components/save-assessment-button.test.tsx
Outdated
Show resolved
Hide resolved
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.
The props snapshots need a snapshot name ("Dialog props"
) passed in:
it.each(isOpenOptions)('with open %p', isOpen => {
props.isOpen = isOpen;
onlyIncludeHtmlService();
const renderResult = render(<ExportDialog {...props} />);
expectMockedComponentPropsToMatchSnapshots([Dialog], 'Dialog props');
expect(renderResult.asFragment()).toMatchSnapshot();
});
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
src/tests/unit/tests/DetailsView/components/invalid-load-assessment-dialog.test.tsx
Outdated
Show resolved
Hide resolved
src/tests/unit/tests/DetailsView/components/issue-filing-dialog.test.tsx
Outdated
Show resolved
Hide resolved
src/tests/unit/tests/DetailsView/components/save-assessment-button.test.tsx
Show resolved
Hide resolved
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 test also needs to mock (Icon as any).type
in order to not have the generic Memo
in the snapshot
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.
With this change i.e mockReactComponents([(Icon as any).type])
also mockReactComponent((Icon as any).type, 'Icon')
Snapshot is not changing generic Memo
, it is still there in the snapshot. Even if we try to do mockReactComponent(Icon, 'Icon')
it gives error as mock-Icon is not a mockable component. Please add a jest.mock call for this component before using this component in the test function.
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.
Okay! I figured out a solution for this. React.memo
is the thing determining the name so we can mock that function and adjust the output:
jest.mock('react', () => {
const original = jest.requireActual('react');
return {
...original,
memo: jest.fn().mockImplementation((component, compare) => {
const elementType = original.memo(component, compare);
if (elementType.type && elementType.type.render) {
if (elementType.type.render.displayName) {
elementType.type.name = elementType.type.render.displayName;
}
}
return elementType;
}),
};
});
We don't need to mock Icon.type
anymore either.
src/tests/unit/tests/common/components/__snapshots__/telemetry-permission-dialog.test.tsx.snap
Outdated
Show resolved
Hide resolved
act(() => { | ||
getMockComponentCall(StartOverDialog, 3)[0].dismissDialog(); | ||
}); | ||
fireEvent.click(startOverMenuButton); |
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.
we shouldn't need a fireEvent
call after the dismissDialog
call for the button to be focused. dismissDialog
should send focus to the button.
@@ -119,10 +123,13 @@ describe('FailureInstancePanelControlTest', () => { | |||
const props = createPropsWithType(CapturedInstanceActionType.CREATE); | |||
|
|||
const renderResult = render(<FailureInstancePanelControl {...props} />); | |||
renderResult.rerender(<FailureInstancePanelControl {...props} />); |
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 this rerender necessary?
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.
Okay! I figured out a solution for this. React.memo
is the thing determining the name so we can mock that function and adjust the output:
jest.mock('react', () => {
const original = jest.requireActual('react');
return {
...original,
memo: jest.fn().mockImplementation((component, compare) => {
const elementType = original.memo(component, compare);
if (elementType.type && elementType.type.render) {
if (elementType.type.render.displayName) {
elementType.type.name = elementType.type.render.displayName;
}
}
return elementType;
}),
};
});
We don't need to mock Icon.type
anymore either.
const component = new TestDiagnosticViewToggle(props); | ||
component.isFocused = true; | ||
render(component.render()); | ||
expect(component.isFocused).toBeTruthy(); | ||
getMockComponentClassPropsForCall(VisualizationToggle).onBlur(); | ||
expect(component.isFocused).toBeFalsy(); |
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 thought of a way to do this without adding to or even using our test class:
const component = new TestDiagnosticViewToggle(props); | |
component.isFocused = true; | |
render(component.render()); | |
expect(component.isFocused).toBeTruthy(); | |
getMockComponentClassPropsForCall(VisualizationToggle).onBlur(); | |
expect(component.isFocused).toBeFalsy(); | |
const component = new DiagnosticViewToggle(props); | |
render(component.render()); | |
component.componentDidMount(); | |
const setState = jest.spyOn(component, 'setState'); | |
getMockComponentClassPropsForCall(VisualizationToggle).onBlur(); | |
expect(setState).toHaveBeenCalledWith({ isFocused: false }); |
@@ -122,6 +110,14 @@ describe('SaveAssessmentButton', () => { | |||
Times.atLeastOnce(), | |||
); | |||
}); | |||
it('dialog is hidden (dismissed) when "got it" button is clicked', async () => { |
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 test is still failing. I dug into it and there's some thing bizarre going on, potentially because of Fluent or React. I added console.log
calls after each place I expected Dialog.render
to have been called again and accessed (Dialog as any).render.mock.calls
and found that after the link click in the beforeEach
block, there's a mysterious third Dialog.render
call with empty props. I put that link click inside of an act(() =>)
call and added more logging and found:
console.log
after link click inside of act [
[
{
hidden: true,
onDismiss: [Function (anonymous)],
dialogContentProps: [Object],
modalProps: [Object],
children: [Array]
},
null
]
]
at log (src/tests/unit/tests/DetailsView/components/save-assessment-button.test.tsx:95:29)
console.error
Warning: contextType was defined as an instance property on CustomizedPrimaryButton. Use a static property to define contextType instead.
at CustomizedPrimaryButton
at mock-StackItem
at StackItem
at div
at div
at ResultComponent (eval at _createMockFunction (C:\repos\accessibility-insights-web\node_modules\jest-mock\build\index.js:566:31), Stack:3:61)
at span
at div
at div
at DialogFooterBase (C:\repos\accessibility-insights-web\node_modules\@fluentui\react\lib-commonjs\components\src\components\Dialog\DialogFooter.base.tsx:12:5)
at mockConstructor (C:\repos\accessibility-insights-web\node_modules\jest-mock\build\index.js:148:19)
at div
at div
at div
at DialogContentBase (C:\repos\accessibility-insights-web\node_modules\@fluentui\react\lib-commonjs\components\src\components\Dialog\DialogContent.base.tsx:27:5)
at WithResponsiveMode (C:\repos\accessibility-insights-web\node_modules\@fluentui\react\lib-commonjs\utilities\src\utilities\decorators\withResponsiveMode.tsx:85:7)
at C:\repos\accessibility-insights-web\node_modules\@fluentui\utilities\src\styled.tsx:99:26
at div
at div
at C:\repos\accessibility-insights-web\node_modules\@fluentui\react\lib-commonjs\components\src\components\FocusTrapZone\FocusTrapZone.tsx:66:22
at div
at div
at C:\repos\accessibility-insights-web\node_modules\@fluentui\react\lib-commonjs\components\src\components\Popup\Popup.tsx:149:24
at div
at FocusRectsProvider (C:\repos\accessibility-insights-web\node_modules\@fluentui\utilities\src\FocusRectsProvider.tsx:17:43)
at C:\repos\accessibility-insights-web\node_modules\@fluentui\react\lib-commonjs\components\src\components\Fabric\Fabric.base.tsx:38:77
at C:\repos\accessibility-insights-web\node_modules\@fluentui\utilities\src\styled.tsx:99:26
at FocusRectsProvider (C:\repos\accessibility-insights-web\node_modules\@fluentui\utilities\src\FocusRectsProvider.tsx:17:43)
at span
at C:\repos\accessibility-insights-web\node_modules\@fluentui\react\lib-commonjs\components\src\components\Layer\Layer.base.tsx:50:45
at C:\repos\accessibility-insights-web\node_modules\@fluentui\utilities\src\styled.tsx:99:26
at C:\repos\accessibility-insights-web\node_modules\@fluentui\react\lib-commonjs\components\src\components\Modal\Modal.base.tsx:134:27
at C:\repos\accessibility-insights-web\node_modules\@fluentui\utilities\src\styled.tsx:99:26
at DialogBase (C:\repos\accessibility-insights-web\node_modules\@fluentui\react\lib-commonjs\components\src\components\Dialog\Dialog.base.tsx:42:5)
at WithResponsiveMode (C:\repos\accessibility-insights-web\node_modules\@fluentui\react\lib-commonjs\utilities\src\utilities\decorators\withResponsiveMode.tsx:85:7)
at mockConstructor (C:\repos\accessibility-insights-web\node_modules\jest-mock\build\index.js:148:19)
at C:\repos\accessibility-insights-web\src\DetailsView\components\save-assessment-button.tsx:27:89
console.log
after link click outside of act [
[
{
hidden: true,
onDismiss: [Function (anonymous)],
dialogContentProps: [Object],
modalProps: [Object],
children: [Array]
},
null
],
[
{
hidden: false,
onDismiss: [Function (anonymous)],
dialogContentProps: [Object],
modalProps: [Object],
children: [Array]
},
null
],
[]
]
at Object.log (src/tests/unit/tests/DetailsView/components/save-assessment-button.test.tsx:100:25)
console.log
after got it click [
[
{
hidden: true,
onDismiss: [Function (anonymous)],
dialogContentProps: [Object],
modalProps: [Object],
children: [Array]
},
null
],
[
{
hidden: false,
onDismiss: [Function (anonymous)],
dialogContentProps: [Object],
modalProps: [Object],
children: [Array]
},
null
],
[],
[
{
hidden: true,
onDismiss: [Function (anonymous)],
dialogContentProps: [Object],
modalProps: [Object],
children: [Array]
},
null
]
]
at Object.log (src/tests/unit/tests/DetailsView/components/save-assessment-button.test.tsx:127:25)
which suggests that the additional Dialog.render
call is potentially happening after the fireEvent
when resolving useEffect
hooks. but I have no idea where this extra third render call is coming from or why beyond that. any ideas?
Changing the expect
call to look at the fourth render will cause the test to pass, but I want to understand where the third render is coming from.
issueFilingSettingsContainer.onPropertyUpdateCallback(payload); | ||
act(() => { | ||
issueFilingSettingsContainer.onPropertyUpdateCallback(payload); | ||
}); | ||
|
||
expect(renderResult.asFragment()).toMatchSnapshot(); | ||
expectMockedComponentPropsToMatchSnapshots([Dialog]); |
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.
expectMockedComponentPropsToMatchSnapshots([Dialog]); | |
expectMockedComponentPropsToMatchSnapshots([Dialog], 'Dialog props'); |
issueFilingSettingsContainer.onPropertyUpdateCallback(payload); | ||
act(() => { | ||
issueFilingSettingsContainer.onPropertyUpdateCallback(payload); | ||
}); | ||
|
||
expect(renderResult.asFragment()).toMatchSnapshot(); | ||
expectMockedComponentPropsToMatchSnapshots([Dialog]); |
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.
expectMockedComponentPropsToMatchSnapshots([Dialog]); | |
expectMockedComponentPropsToMatchSnapshots([Dialog], 'Dialog props'); |
issueFilingSettingsContainer.onSelectedServiceChange(payload); | ||
act(() => { | ||
issueFilingSettingsContainer.onSelectedServiceChange(payload); | ||
}); | ||
|
||
expect(renderResult.asFragment()).toMatchSnapshot(); | ||
expectMockedComponentPropsToMatchSnapshots([Dialog]); |
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.
expectMockedComponentPropsToMatchSnapshots([Dialog]); | |
expectMockedComponentPropsToMatchSnapshots([Dialog], 'Dialog props'); |
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 can't make a suggestion for the final call of expectMockedComponentPropsToMatchSnapshots([Dialog]);
(in the 'componentDidUpdate %s'
test) because there isn't edited code near enough to it, but that one also needs to be updated with snapshotName
.
@@ -142,7 +142,7 @@ export class DiagnosticViewToggle extends React.Component< | |||
} | |||
}; | |||
|
|||
private onBlurHandler = (): void => { | |||
protected onBlurHandler = (): void => { |
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.
we shouldn't need this anymore with the suggested changes to the test
Details
This feature updates below packages.
1. Notable changes for react, react-dom:
Motivation: React 18 introduces a new root API which provides better ergonomics for managing roots. The new root API also enables the new concurrent renderer, which allows you to opt-into concurrent features.
In V16, we had below to render the component:
import { render } from 'react-dom';
const container = document.getElementById('app');
render(, container);
import { createRoot } from 'react-dom/client';
const container = document.getElementById('app');
const root = createRoot(container); // createRoot(container!) if you use TypeScript
root.render();
2. Notable changes for @types-react and @types-react-dom:
Motivation: The new types are safer and catch issues that used to be ignored by the type checker. The most notable change is that the children prop now needs to be listed explicitly when defining props
WrappedComponent: React.ComponentType
,
WrappedComponent: React.ComponentType<React.PropsWithChildren
>,
Approach for type changes: So this Type changes are added using automation script https://github.com/eps1lon/types-react-codemod. This automation script is suggested in react18 migration document.
>.
3. Notable changes for @testing-library/react:
4. Notable changes for @fluentui/react from v8.x.x to v8.118.1
5. Notable changes for react-helmet-async:
For example:
export const GuidanceTitle = NamedFC<GuidanceTitleProps>('GuidanceTitle', ({ name }) => { const titleValue =
Guidance for ${name} - ${productName}; return ( <> <Helmet> <title>{titleValue}</title> </Helmet> <h1>{name}</h1> </> ); });
6. Along with above
using of mockReactComponents in global and inside test case using of useOriginalComponents to get the props using getMockComponentClassPropsForCall which was wrong logically is fixed to use any one approach.
Context
This PR includes all changes required for migration of AI web from react16 to react18.
It includes test cases fixes.
It includes lint issues fixes.
Pull request checklist
yarn fastpass
yarn test
)<rootDir>/test-results/unit/coverage
fix:
,chore:
,feat(feature-name):
,refactor:
). SeeCONTRIBUTING.md
.