fluentui
fluentui copied to clipboard
Stress Test: add random tree
Current Behavior
Test cases are simple benchmarks.
New Behavior
This PR adds code for generating and rendering deep and broad DOM trees allowing us to better simulate a real application with a benchmarking tool.
Note: tree generation is "random" but done with a seedable RNG for repeatable results.
The core of this is RandomTree a class for generating trees with random breadth and depth. This class is generic with an API for generating specific trees. This PR adds a "selector tree" which builds of RandomTree to generate a tree with many selectors (CSS classes, data attributes, etc) as well as generate the selectors themselves.
RandomTree is UI library agnostic and can be used to generate trees for React, Web Components, vanilla DOM or any other library we care to investigate.
Building off RandomTree this PR adds three library-specific tree implementations. One for React, one for (vanilla) Web Components and one for vanilla DOM.
Related Issue(s)
This PR is a foundational piece taken from #24799 (that other PR was far too large).
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 d2431ef256926392b216555e343a8974c9caefbe:
| Sandbox | Source |
|---|---|
| @fluentui/react 8 starter | Configuration |
| @fluentui/react-components 9 starter | Configuration |
Perf Analysis (@fluentui/react-components)
No significant results to display.
All results
| Scenario | Render type | Master Ticks | PR Ticks | Iterations | Status |
|---|---|---|---|---|---|
| Avatar | mount | 1505 | 1486 | 5000 | |
| Button | mount | 1126 | 1102 | 5000 | |
| FluentProvider | mount | 1825 | 1782 | 5000 | |
| FluentProviderWithTheme | mount | 712 | 714 | 10 | |
| FluentProviderWithTheme | virtual-rerender | 673 | 672 | 10 | |
| FluentProviderWithTheme | virtual-rerender-with-unmount | 713 | 717 | 10 | |
| MakeStyles | mount | 2155 | 2176 | 50000 | |
| SpinButton | mount | 2913 | 2871 | 5000 |
Asset size changes
Size Auditor did not detect a change in bundle size for any component!
Baseline commit: 483f160617f1037e672fe74b8e52abfee9378517 (build)
📊 Bundle size report
Unchanged fixtures
| Package & Exports | Size (minified/GZIP) |
|---|---|
| global-context createContext |
533 B341 B |
| global-context createContextSelector |
554 B348 B |
| priority-overflow createOverflowManager |
2.936 kB1.212 kB |
| react-accordion Accordion (including children components) |
78.914 kB24.06 kB |
| react-alert Alert |
83.511 kB20.921 kB |
| react-avatar Avatar |
48.381 kB13.696 kB |
| react-avatar AvatarGroup |
14.95 kB5.989 kB |
| react-avatar AvatarGroupItem |
68.349 kB19.039 kB |
| react-badge Badge |
22.6 kB7.205 kB |
| react-badge CounterBadge |
23.503 kB7.497 kB |
| react-badge PresenceBadge |
24.05 kB7.067 kB |
| react-button Button |
36.119 kB9.647 kB |
| react-button CompoundButton |
43.144 kB10.86 kB |
| react-button MenuButton |
38.813 kB10.551 kB |
| react-button SplitButton |
46.228 kB11.933 kB |
| react-button ToggleButton |
51.888 kB11.127 kB |
| react-card Card - All |
67.002 kB19.261 kB |
| react-card Card |
62.684 kB18.177 kB |
| react-card CardFooter |
8.561 kB3.601 kB |
| react-card CardHeader |
9.604 kB3.94 kB |
| react-card CardPreview |
8.662 kB3.656 kB |
| react-combobox Combobox (including child components) |
74.636 kB24.186 kB |
| react-combobox Dropdown (including child components) |
74.236 kB24.086 kB |
| react-components react-components: Accordion, Button, FluentProvider, Image, Menu, Popover |
188.672 kB52.359 kB |
| react-components react-components: FluentProvider & webLightTheme |
33.394 kB11.007 kB |
| react-dialog Dialog (including children components) |
82.755 kB24.581 kB |
| react-divider Divider |
16.459 kB5.902 kB |
| react-image Image |
10.78 kB4.264 kB |
| react-input Input |
23.757 kB7.704 kB |
| react-label Label |
9.338 kB3.86 kB |
| react-link Link |
11.784 kB4.867 kB |
| react-menu Menu (including children components) |
116.572 kB35.778 kB |
| react-menu Menu (including selectable components) |
119.641 kB36.297 kB |
| react-overflow hooks only |
10.685 kB4.104 kB |
| react-popover Popover |
102.963 kB31.553 kB |
| react-portal Portal |
10.576 kB3.875 kB |
| react-portal-compat PortalCompatProvider |
5.851 kB1.964 kB |
| react-positioning usePositioning |
19.7 kB7.404 kB |
| react-provider FluentProvider |
15.755 kB5.883 kB |
| react-radio Radio |
35.56 kB11.929 kB |
| react-radio RadioGroup |
14.248 kB5.7 kB |
| react-select Select |
20.846 kB7.346 kB |
| react-slider Slider |
31.526 kB10.046 kB |
| react-spinbutton SpinButton |
44.102 kB12.425 kB |
| react-spinner Spinner |
19.977 kB6.438 kB |
| react-switch Switch |
32.097 kB10.27 kB |
| react-text Text - Default |
11.782 kB4.605 kB |
| react-text Text - Wrappers |
15.092 kB5.044 kB |
| react-textarea Textarea |
25.013 kB8.133 kB |
| react-theme Single theme token import |
69 B89 B |
| react-theme Teams: all themes |
29.65 kB6.444 kB |
| react-theme Teams: Light theme |
17.486 kB5.057 kB |
| react-tooltip Tooltip |
41.535 kB14.639 kB |
| react-utilities SSRProvider |
180 B159 B |
Perf Analysis (@fluentui/react-northstar)
Perf tests with no regressions
| Scenario | Current PR Ticks | Baseline Ticks | Ratio |
|---|---|---|---|
| AccordionMinimalPerf.default | 117 | 110 | 1.06:1 |
| ImageMinimalPerf.default | 320 | 303 | 1.06:1 |
| AlertMinimalPerf.default | 227 | 216 | 1.05:1 |
| FormMinimalPerf.default | 320 | 304 | 1.05:1 |
| SkeletonMinimalPerf.default | 292 | 278 | 1.05:1 |
| HeaderMinimalPerf.default | 299 | 288 | 1.04:1 |
| LayoutMinimalPerf.default | 292 | 282 | 1.04:1 |
| CardMinimalPerf.default | 438 | 424 | 1.03:1 |
| LabelMinimalPerf.default | 312 | 304 | 1.03:1 |
| ListCommonPerf.default | 526 | 512 | 1.03:1 |
| ReactionMinimalPerf.default | 304 | 294 | 1.03:1 |
| IconMinimalPerf.default | 546 | 529 | 1.03:1 |
| TableMinimalPerf.default | 332 | 323 | 1.03:1 |
| TextAreaMinimalPerf.default | 394 | 383 | 1.03:1 |
| AvatarMinimalPerf.default | 150 | 147 | 1.02:1 |
| RosterPerf.default | 1794 | 1759 | 1.02:1 |
| PopupMinimalPerf.default | 532 | 522 | 1.02:1 |
| ProviderMinimalPerf.default | 338 | 330 | 1.02:1 |
| SplitButtonMinimalPerf.default | 3656 | 3599 | 1.02:1 |
| AnimationMinimalPerf.default | 445 | 440 | 1.01:1 |
| BoxMinimalPerf.default | 280 | 276 | 1.01:1 |
| CheckboxMinimalPerf.default | 1726 | 1706 | 1.01:1 |
| DatepickerMinimalPerf.default | 4807 | 4779 | 1.01:1 |
| DialogMinimalPerf.default | 639 | 635 | 1.01:1 |
| EmbedMinimalPerf.default | 3026 | 2997 | 1.01:1 |
| ListMinimalPerf.default | 419 | 415 | 1.01:1 |
| MenuMinimalPerf.default | 702 | 692 | 1.01:1 |
| MenuButtonMinimalPerf.default | 1405 | 1386 | 1.01:1 |
| PortalMinimalPerf.default | 138 | 136 | 1.01:1 |
| RadioGroupMinimalPerf.default | 360 | 358 | 1.01:1 |
| StatusMinimalPerf.default | 552 | 546 | 1.01:1 |
| TableManyItemsPerf.default | 1555 | 1542 | 1.01:1 |
| TextMinimalPerf.default | 281 | 279 | 1.01:1 |
| TreeMinimalPerf.default | 670 | 661 | 1.01:1 |
| AttachmentMinimalPerf.default | 121 | 121 | 1:1 |
| ButtonOverridesMissPerf.default | 1085 | 1080 | 1:1 |
| CarouselMinimalPerf.default | 379 | 378 | 1:1 |
| DropdownMinimalPerf.default | 2233 | 2234 | 1:1 |
| HeaderSlotsPerf.default | 624 | 626 | 1:1 |
| InputMinimalPerf.default | 936 | 937 | 1:1 |
| LoaderMinimalPerf.default | 544 | 542 | 1:1 |
| ProviderMergeThemesPerf.default | 1062 | 1059 | 1:1 |
| SegmentMinimalPerf.default | 276 | 277 | 1:1 |
| SliderMinimalPerf.default | 1331 | 1326 | 1:1 |
| CustomToolbarPrototype.default | 2237 | 2236 | 1:1 |
| TreeWith60ListItems.default | 135 | 135 | 1:1 |
| VideoMinimalPerf.default | 596 | 595 | 1:1 |
| ButtonSlotsPerf.default | 447 | 452 | 0.99:1 |
| ChatDuplicateMessagesPerf.default | 231 | 233 | 0.99:1 |
| DividerMinimalPerf.default | 287 | 290 | 0.99:1 |
| DropdownManyItemsPerf.default | 544 | 548 | 0.99:1 |
| GridMinimalPerf.default | 269 | 271 | 0.99:1 |
| ItemLayoutMinimalPerf.default | 955 | 964 | 0.99:1 |
| ListNestedPerf.default | 447 | 450 | 0.99:1 |
| ToolbarMinimalPerf.default | 758 | 767 | 0.99:1 |
| TooltipMinimalPerf.default | 1947 | 1966 | 0.99:1 |
| ChatMinimalPerf.default | 595 | 606 | 0.98:1 |
| ChatWithPopoverPerf.default | 304 | 309 | 0.98:1 |
| ListWith60ListItems.default | 513 | 522 | 0.98:1 |
| RefMinimalPerf.default | 171 | 177 | 0.97:1 |
| AttachmentSlotsPerf.default | 865 | 897 | 0.96:1 |
| FlexMinimalPerf.default | 222 | 232 | 0.96:1 |
| ButtonMinimalPerf.default | 126 | 133 | 0.95:1 |
Perf Analysis (@fluentui/react)
No significant results to display.
All results
| Scenario | Render type | Master Ticks | PR Ticks | Iterations | Status |
|---|---|---|---|---|---|
| BaseButton | mount | 1204 | 1213 | 5000 | |
| Breadcrumb | mount | 2778 | 2823 | 1000 | |
| Checkbox | mount | 2619 | 2656 | 5000 | |
| CheckboxBase | mount | 2387 | 2370 | 5000 | |
| ChoiceGroup | mount | 4231 | 4311 | 5000 | |
| ComboBox | mount | 1188 | 1190 | 1000 | |
| CommandBar | mount | 9339 | 9322 | 1000 | |
| ContextualMenu | mount | 10418 | 10594 | 1000 | |
| DefaultButton | mount | 1358 | 1356 | 5000 | |
| DetailsRow | mount | 3367 | 3389 | 5000 | |
| DetailsRowFast | mount | 3386 | 3375 | 5000 | |
| DetailsRowNoStyles | mount | 3242 | 3290 | 5000 | |
| Dialog | mount | 2947 | 2989 | 1000 | |
| DocumentCardTitle | mount | 583 | 593 | 1000 | |
| Dropdown | mount | 3182 | 3161 | 5000 | |
| FocusTrapZone | mount | 1980 | 1955 | 5000 | |
| FocusZone | mount | 1947 | 1900 | 5000 | |
| GroupedList | mount | 48671 | 55056 | 2 | |
| GroupedList | virtual-rerender | 23479 | 23162 | 2 | |
| GroupedList | virtual-rerender-with-unmount | 83155 | 83107 | 2 | |
| GroupedListV2 | mount | 569 | 562 | 2 | |
| GroupedListV2 | virtual-rerender | 525 | 530 | 2 | |
| GroupedListV2 | virtual-rerender-with-unmount | 545 | 547 | 2 | |
| IconButton | mount | 1822 | 1801 | 5000 | |
| Label | mount | 753 | 748 | 5000 | |
| Layer | mount | 4104 | 4113 | 5000 | |
| Link | mount | 865 | 859 | 5000 | |
| MenuButton | mount | 1601 | 1613 | 5000 | |
| MessageBar | mount | 2345 | 2345 | 5000 | |
| Nav | mount | 3066 | 3079 | 1000 | |
| OverflowSet | mount | 1422 | 1395 | 5000 | |
| Panel | mount | 2472 | 2479 | 1000 | |
| Persona | mount | 1255 | 1277 | 1000 | |
| Pivot | mount | 1512 | 1542 | 1000 | |
| PrimaryButton | mount | 1470 | 1486 | 5000 | |
| Rating | mount | 6914 | 6990 | 5000 | |
| SearchBox | mount | 1489 | 1512 | 5000 | |
| Shimmer | mount | 2936 | 3005 | 5000 | |
| Slider | mount | 2080 | 2107 | 5000 | |
| SpinButton | mount | 4257 | 4275 | 5000 | |
| Spinner | mount | 839 | 827 | 5000 | |
| SplitButton | mount | 2874 | 2871 | 5000 | |
| Stack | mount | 887 | 892 | 5000 | |
| StackWithIntrinsicChildren | mount | 2265 | 2266 | 5000 | |
| StackWithTextChildren | mount | 4936 | 4963 | 5000 | |
| SwatchColorPicker | mount | 9448 | 9498 | 5000 | |
| TagPicker | mount | 2360 | 2364 | 5000 | |
| TeachingBubble | mount | 76488 | 75534 | 5000 | |
| Text | mount | 834 | 831 | 5000 | |
| TextField | mount | 1558 | 1560 | 5000 | |
| ThemeProvider | mount | 1435 | 1445 | 5000 | |
| ThemeProvider | virtual-rerender | 1143 | 1142 | 5000 | |
| ThemeProvider | virtual-rerender-with-unmount | 1993 | 2007 | 5000 | |
| Toggle | mount | 1149 | 1141 | 5000 | |
| buttonNative | mount | 536 | 526 | 5000 |
Looks good in general, except there are several very large files under src/fixtures. Is it necessary to add them to the repo? Can they just be randomly generated as needed instead?
Initially I had them generated on demand and since they all the randomness uses random-seedable under the hood the results are deterministic. However, when demoing this for some folks the consensus feedback was to add these fixtures to ensure we always used the same trees.
I was on the fence about following through on the change but I tested it out and while we now have these large fixture files in the repo the tests themselves run noticeably faster as they aren't re-computing the same tree over and over and just loading it instead. The tests already tend to be slow as they are run many times against many browsers so cutting down on test run time is nice.
I think we should keep the fixtures for now. While the files will likely change a bit as this app stabilizes its functionality they aren't going to change all the time.