Skip to content
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

Add conformance test for event callback typing: consistent-callback-type #30200

Closed
wants to merge 9 commits into from

Conversation

YuanboXue-Amber
Copy link
Contributor

@YuanboXue-Amber YuanboXue-Amber commented Jan 3, 2024

Background:

We agreed on new event type for v9 callbacks.

Below types will be exported from react-utilities as helpers:

export type EventData<Type extends string, TEvent> =
  | { type: undefined; event: React.SyntheticEvent | Event }
  | { type: Type; event: TEvent };

export type EventHandler<TData extends EventData<string, unknown>> = (
  ev: React.SyntheticEvent | Event,
  data: TData,
) => void;

And they will be used for typing callbacks:

type MyComponentElement = HTMLElement;

type OnSomeEventData = (
  | EventData<'click', React.MouseEvent<MyComponentElement>>
  | EventData<'focus', React.FocusEvent<MyComponentElement>>
) & {
  open: boolean;
};

type SomeProps = {
  onSomeEvent?: EventHandler<OnSomeEventData>;
};

detailed proposal: https://github.com/microsoft/fluentui/blob/master/rfcs/react-components/convergence/event-handlers-event-type.md

This PR does:

  1. export the helper types as mentioned above
  2. deprecate existing conformance test for event typing:
    • rename consistent-callback-args -> consistent-callback-args-legacy
    • disable consistent-callback-args-legacy in create component template
  3. add new conformance test for new type: consistent-callback-type, disable this test for existing callbacks.

@fabricteam
Copy link
Collaborator

fabricteam commented Jan 3, 2024

📊 Bundle size report

Unchanged fixtures
Package & Exports Size (minified/GZIP)
global-context
createContext
510 B
328 B
global-context
createContextSelector
537 B
339 B
react-accordion
Accordion (including children components)
93.891 kB
28.677 kB
react-alert
Alert
83.737 kB
23.474 kB
react-avatar
Avatar
50.175 kB
15.944 kB
react-avatar
AvatarGroup
19.704 kB
7.796 kB
react-avatar
AvatarGroupItem
64.831 kB
20.274 kB
react-badge
Badge
26.905 kB
8.729 kB
react-badge
CounterBadge
27.806 kB
9.024 kB
react-badge
PresenceBadge
25.311 kB
9.306 kB
react-button
Button
39.513 kB
11.169 kB
react-button
CompoundButton
46.874 kB
12.661 kB
react-button
MenuButton
44.292 kB
12.542 kB
react-button
SplitButton
52.306 kB
14.134 kB
react-button
ToggleButton
56.559 kB
13.068 kB
react-calendar-compat
Calendar Compat
142.165 kB
37.153 kB
react-card
Card - All
94.583 kB
27.221 kB
react-card
Card
89.407 kB
25.71 kB
react-card
CardFooter
13.064 kB
5.385 kB
react-card
CardHeader
15.307 kB
6.143 kB
react-card
CardPreview
14.015 kB
5.752 kB
react-checkbox
Checkbox
34.746 kB
11.902 kB
react-combobox
Combobox (including child components)
95.436 kB
30.792 kB
react-combobox
Dropdown (including child components)
94.022 kB
30.47 kB
react-components
react-components: Button, FluentProvider & webLightTheme
69.901 kB
20.261 kB
react-components
react-components: Accordion, Button, FluentProvider, Image, Menu, Popover
210.164 kB
59.999 kB
react-components
react-components: FluentProvider & webLightTheme
42.388 kB
14.103 kB
react-datepicker-compat
DatePicker Compat
213.918 kB
60.021 kB
react-dialog
Dialog (including children components)
95.452 kB
28.456 kB
react-divider
Divider
20.82 kB
7.763 kB
react-field
Field
22.427 kB
8.573 kB
react-image
Image
15.736 kB
6.228 kB
react-infobutton
InfoButton
132.996 kB
41.838 kB
react-infobutton
InfoLabel
136.684 kB
42.979 kB
react-input
Input
26.887 kB
9.118 kB
react-jsx-runtime
Classic Pragma
1.057 kB
530 B
react-jsx-runtime
JSX Dev Runtime
3.783 kB
1.648 kB
react-jsx-runtime
JSX Runtime
4.377 kB
1.881 kB
react-label
Label
14.149 kB
5.759 kB
react-link
Link
17.082 kB
6.911 kB
react-menu
Menu (including children components)
142.349 kB
43.657 kB
react-menu
Menu (including selectable components)
145.035 kB
44.163 kB
react-message-bar
MessageBar (all components)
25.181 kB
9.039 kB
react-overflow
hooks only
12.837 kB
4.818 kB
react-persona
Persona
57.066 kB
17.821 kB
react-popover
Popover
121.19 kB
38.227 kB
react-portal
Portal
12.788 kB
4.67 kB
react-portal-compat
PortalCompatProvider
7.099 kB
2.385 kB
react-positioning
usePositioning
26.162 kB
9.465 kB
react-progress
ProgressBar
17.428 kB
6.898 kB
react-provider
FluentProvider
22.928 kB
8.472 kB
react-radio
Radio
32.042 kB
10.046 kB
react-radio
RadioGroup
15.345 kB
6.263 kB
react-select
Select
28.609 kB
10.205 kB
react-slider
Slider
39.15 kB
12.769 kB
react-spinbutton
SpinButton
36.774 kB
11.788 kB
react-spinner
Spinner
23.402 kB
8.467 kB
react-switch
Switch
34.23 kB
10.995 kB
react-table
DataGrid
156.347 kB
43.735 kB
react-table
Table (Primitives only)
43.899 kB
13.781 kB
react-table
Table as DataGrid
129.567 kB
35 kB
react-table
Table (Selection only)
74.744 kB
20.215 kB
react-table
Table (Sort only)
73.351 kB
19.806 kB
react-tags
InteractionTag
15.259 kB
6.058 kB
react-tags
Tag
29.982 kB
9.439 kB
react-tags
TagGroup
74.334 kB
22.284 kB
react-text
Text - Default
16.705 kB
6.569 kB
react-text
Text - Wrappers
19.878 kB
6.896 kB
react-textarea
Textarea
30.947 kB
10.476 kB
react-timepicker-compat
TimePicker
97.272 kB
32.257 kB
react-toast
Toast (including Toaster)
93.203 kB
28.026 kB
react-tooltip
Tooltip
53.63 kB
18.924 kB
react-utilities
SSRProvider
180 B
160 B
🤖 This report was generated against 300073896d3b7ab9a0556e5b1b886d46c99d2515

@fabricteam
Copy link
Collaborator

fabricteam commented Jan 3, 2024

Perf Analysis (@fluentui/react-components)

Scenario Render type Master Ticks PR Ticks Iterations Status
FluentProviderWithTheme virtual-rerender-with-unmount 79 72 10 Possible regression
All results

Scenario Render type Master Ticks PR Ticks Iterations Status
Avatar mount 639 614 5000
Button mount 293 296 5000
Field mount 1137 1129 5000
FluentProvider mount 704 717 5000
FluentProviderWithTheme mount 77 89 10
FluentProviderWithTheme virtual-rerender 62 60 10
FluentProviderWithTheme virtual-rerender-with-unmount 79 72 10 Possible regression
MakeStyles mount 879 902 50000
Persona mount 1796 1755 5000
SpinButton mount 1364 1377 5000

@fabricteam
Copy link
Collaborator

fabricteam commented Jan 3, 2024

Perf Analysis (@fluentui/react-northstar)

Perf tests with no regressions
Scenario Current PR Ticks Baseline Ticks Ratio
AvatarMinimalPerf.default 117 102 1.15:1
ChatDuplicateMessagesPerf.default 155 138 1.12:1
ButtonMinimalPerf.default 92 83 1.11:1
AccordionMinimalPerf.default 81 75 1.08:1
AlertMinimalPerf.default 159 148 1.07:1
CarouselMinimalPerf.default 265 249 1.06:1
RefMinimalPerf.default 112 106 1.06:1
VideoMinimalPerf.default 442 418 1.06:1
AttachmentMinimalPerf.default 85 81 1.05:1
ChatMinimalPerf.default 435 416 1.05:1
ImageMinimalPerf.default 229 219 1.05:1
ToolbarMinimalPerf.default 540 512 1.05:1
TreeWith60ListItems.default 82 78 1.05:1
ButtonSlotsPerf.default 324 313 1.04:1
DropdownManyItemsPerf.default 379 364 1.04:1
PopupMinimalPerf.default 353 341 1.04:1
ProviderMergeThemesPerf.default 650 624 1.04:1
TooltipMinimalPerf.default 1301 1245 1.04:1
AnimationMinimalPerf.default 292 283 1.03:1
HeaderSlotsPerf.default 475 461 1.03:1
MenuButtonMinimalPerf.default 952 920 1.03:1
TextAreaMinimalPerf.default 290 282 1.03:1
CheckboxMinimalPerf.default 1120 1097 1.02:1
LayoutMinimalPerf.default 205 201 1.02:1
MenuMinimalPerf.default 497 485 1.02:1
PortalMinimalPerf.default 87 85 1.02:1
SliderMinimalPerf.default 734 723 1.02:1
TextMinimalPerf.default 193 190 1.02:1
CardMinimalPerf.default 311 309 1.01:1
LoaderMinimalPerf.default 191 190 1.01:1
RosterPerf.default 1569 1553 1.01:1
SegmentMinimalPerf.default 188 186 1.01:1
SplitButtonMinimalPerf.default 2215 2200 1.01:1
StatusMinimalPerf.default 396 391 1.01:1
TableManyItemsPerf.default 1112 1101 1.01:1
TreeMinimalPerf.default 473 470 1.01:1
ChatWithPopoverPerf.default 191 191 1:1
EmbedMinimalPerf.default 1832 1823 1:1
InputMinimalPerf.default 539 537 1:1
ListMinimalPerf.default 306 307 1:1
ListNestedPerf.default 320 319 1:1
SkeletonMinimalPerf.default 196 196 1:1
AttachmentSlotsPerf.default 635 643 0.99:1
BoxMinimalPerf.default 186 188 0.99:1
DatepickerMinimalPerf.default 3431 3475 0.99:1
DialogMinimalPerf.default 434 439 0.99:1
DropdownMinimalPerf.default 1422 1433 0.99:1
ItemLayoutMinimalPerf.default 683 691 0.99:1
TableMinimalPerf.default 228 231 0.99:1
CustomToolbarPrototype.default 1441 1458 0.99:1
GridMinimalPerf.default 187 191 0.98:1
RadioGroupMinimalPerf.default 257 262 0.98:1
DividerMinimalPerf.default 201 208 0.97:1
FlexMinimalPerf.default 154 158 0.97:1
ListCommonPerf.default 388 400 0.97:1
ProviderMinimalPerf.default 193 199 0.97:1
IconMinimalPerf.default 377 387 0.97:1
ButtonOverridesMissPerf.default 652 679 0.96:1
FormMinimalPerf.default 218 226 0.96:1
HeaderMinimalPerf.default 201 209 0.96:1
ListWith60ListItems.default 356 369 0.96:1
ReactionMinimalPerf.default 203 214 0.95:1
LabelMinimalPerf.default 206 218 0.94:1

@fabricteam
Copy link
Collaborator

fabricteam commented Jan 3, 2024

🕵 fluentuiv8 No visual regressions between this PR and main

Copy link

codesandbox-ci bot commented Jan 3, 2024

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 9bfaadf:

Sandbox Source
@fluentui/react 8 starter Configuration
@fluentui/react-components 9 starter Configuration

@fabricteam
Copy link
Collaborator

fabricteam commented Jan 3, 2024

Perf Analysis (@fluentui/react)

No significant results to display.

All results

Scenario Render type Master Ticks PR Ticks Iterations Status
BaseButton mount 618 651 5000
Breadcrumb mount 1733 1689 1000
Checkbox mount 1693 1684 5000
CheckboxBase mount 1474 1467 5000
ChoiceGroup mount 2890 2871 5000
ComboBox mount 655 642 1000
CommandBar mount 6234 6274 1000
ContextualMenu mount 13107 14183 1000
DefaultButton mount 764 743 5000
DetailsRow mount 2185 2155 5000
DetailsRowFast mount 2145 2178 5000
DetailsRowNoStyles mount 1986 1973 5000
Dialog mount 2787 2657 1000
DocumentCardTitle mount 234 232 1000
Dropdown mount 1966 1945 5000
FocusTrapZone mount 1122 1131 5000
FocusZone mount 1041 1082 5000
GroupedList mount 41859 41554 2
GroupedList virtual-rerender 17889 19962 2
GroupedList virtual-rerender-with-unmount 51199 50961 2
GroupedListV2 mount 229 240 2
GroupedListV2 virtual-rerender 216 215 2
GroupedListV2 virtual-rerender-with-unmount 232 238 2
IconButton mount 1097 1101 5000
Label mount 327 336 5000
Layer mount 2767 2683 5000
Link mount 398 388 5000
MenuButton mount 904 922 5000
MessageBar mount 21461 21549 5000
Nav mount 1921 1946 1000
OverflowSet mount 780 780 5000
Panel mount 1805 1733 1000
Persona mount 737 739 1000
Pivot mount 884 866 1000
PrimaryButton mount 843 845 5000
Rating mount 4589 4577 5000
SearchBox mount 917 923 5000
Shimmer mount 1911 1839 5000
Slider mount 1329 1308 5000
SpinButton mount 2901 2779 5000
Spinner mount 391 384 5000
SplitButton mount 1877 1857 5000
Stack mount 413 411 5000
StackWithIntrinsicChildren mount 862 847 5000
StackWithTextChildren mount 2564 2579 5000
SwatchColorPicker mount 6193 6170 5000
TagPicker mount 1474 1495 5000
Text mount 380 369 5000
TextField mount 926 917 5000
ThemeProvider mount 819 824 5000
ThemeProvider virtual-rerender 592 577 5000
ThemeProvider virtual-rerender-with-unmount 1284 1273 5000
Toggle mount 616 616 5000
buttonNative mount 191 195 5000

@fabricteam
Copy link
Collaborator

fabricteam commented Jan 3, 2024

🕵 FluentUIV0 No visual regressions between this PR and main

Copy link

size-auditor bot commented Jan 3, 2024

Asset size changes

Size Auditor did not detect a change in bundle size for any component!

Baseline commit: 300073896d3b7ab9a0556e5b1b886d46c99d2515 (build)

@fabricteam
Copy link
Collaborator

fabricteam commented Jan 3, 2024

🕵 fluentuiv9 No visual regressions between this PR and main

@@ -0,0 +1,104 @@
import * as ts from 'typescript';
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is copy-pasted from the deleted part in getCallbackArguments. I don't understand it enough to make any change :/

Copy link
Contributor

@Hotell Hotell left a comment

Choose a reason for hiding this comment

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

It would be good idea to actually dissect these changes into multiple PRs for sake of granularity.

Regarding the conformance implementation:

can we remove consistent-callback-args from conformance defaults instead ?

  • removing all disabled definition for that check + adding that check only where it is actually used ( which based on this PR is focus zone/react v8 only ? )
  • no renaming churn needed
  • marking it as @deprecated

@@ -0,0 +1,7 @@
{
"type": "minor",
Copy link
Member

Choose a reason for hiding this comment

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

As you renaming consistent-callback-args, it should be a major bump (as it's a breaking change).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

react-conformance is on version 0.x.x. I think minor here is for breaking change.

@YuanboXue-Amber YuanboXue-Amber requested a review from a team as a code owner January 10, 2024 12:22
@YuanboXue-Amber
Copy link
Contributor Author

It would be good idea to actually dissect these changes into multiple PRs for sake of granularity.

Regarding the conformance implementation:

can we remove consistent-callback-args from conformance defaults instead ?

  • removing all disabled definition for that check + adding that check only where it is actually used ( which based on this PR is focus zone/react v8 only ? )
  • no renaming churn needed
  • marking it as @deprecated

@Hotell I'm in favor of removing consistent-callback-args. But it is also in use by most of the v9 components, and I would like to keep it this way.
WDYT if I export a const deprecatedTests: TestObject = {"consistent-callback-args": testFunction } object from react-conformance, and add it to all the existing v9 test, for example in packages/react-components/react-button/src/testing/isConformant.ts. I can do this in a separate PR

'consistent-callback-args-legacy': {
ignoreProps: ['onActiveElementChanged', 'onBeforeFocus', 'onFocusNotification', 'onFocus'],
},
'consistent-callback-type': {
Copy link
Contributor

Choose a reason for hiding this comment

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

why is this being added to v8 package ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because we want to disable the new consistent-callback-type for v8.
If you meant consistent-callback-args-legacy, the git diff is not very smart there, it was already in v8.

Copy link
Contributor

Choose a reason for hiding this comment

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

no I meant the new callback-type.

it should be disabled in root isConformant definition rather than configured for ignoring specific handlers
image

disabledTests: ['make-styles-overrides-win', 'consistent-callback-args-legacy'],
testOptions: {
'consistent-callback-type': {
ignoreProps: ['onToggle'],
Copy link
Contributor

Choose a reason for hiding this comment

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

why are some handlers being ignored ? what's the plan here , will it be fixed in a follow up PR ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The plan is to enable the new type EventHandler only for new v9 components, or newly added event callback props. Because we can't break the type of the existing props.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The existing callbacks will be verified by the legacy test consistent-callback-args-legacy.
The newly added callbacks will be verified by consistent-callback-type

Copy link
Contributor

Choose a reason for hiding this comment

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

so existing v9 packages (this one in particular), doesnt contain any old callback types ?

@Hotell
Copy link
Contributor

Hotell commented Jan 10, 2024

@Hotell I'm in favor of removing consistent-callback-args. But it is also in use by most of the v9 components, and I would like to keep it this way.

Gotcha, my assumption was based on this PR changes, havent checked all v9 packages.

WDYT if I export a const deprecatedTests: TestObject = {"consistent-callback-args": testFunction } object from react-conformance, and add it to all the existing v9 test, for example in packages/react-components/react-button/src/testing/isConformant.ts. I can do this in a separate PR

It's bit unfortunated that we keep extending react-conformance even we know we wanna get rid of it because its architecture limitations and performance bottlenecks. I'm wondering if you could add this new functionality as an eslint rule which is what conformance will be migrated to in future ?

Lets't not expand public API surface of this package because the reasons mentioned.

I propose following (for the old test case rule):

  • keeping the old test name as is
  • adding @deprecation jsdoc
image

Comment on lines +11 to +14
disabledTests: ['make-styles-overrides-win', 'consistent-callback-args-legacy'],
testOptions: {
'consistent-callback-type': {
ignoreProps: ['onToggle'],
Copy link
Contributor

Choose a reason for hiding this comment

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

The way these conformance tests are set up seems like a configuration headache. It's confusing when the -legacy version should be enabled. It's also not obvious why some props are being ignored, and when/if new props should be ignored as well.

IMO we should keep a single consistent-callback-args check: don't split it into two tests that have to be enabled/disabled in different scenarios. The test could be configured to check legacy callbacks against the legacy pattern (rather than simply ignored).

E.g.

Suggested change
disabledTests: ['make-styles-overrides-win', 'consistent-callback-args-legacy'],
testOptions: {
'consistent-callback-type': {
ignoreProps: ['onToggle'],
disabledTests: ['make-styles-overrides-win'],
testOptions: {
'consistent-callback-args': {
legacyCallbacks: ['onToggle'],

The config option could be named legacyCallbacks_doNotAddNewPropsHere or something, to make it even clearer.

@YuanboXue-Amber
Copy link
Contributor Author

Hi @Hotell and @behowell, I created a lint rule instead of conformance test since we have the goal of moving all conformance test to lint rule: #30293 - appreciate a review there 🙏
And I deprecated the current consistent-callback-args test in #30301

@Hotell
Copy link
Contributor

Hotell commented Jan 17, 2024

I guess we can close this one ?

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

Successfully merging this pull request may close these issues.

6 participants