@samitouri / QOS-React / commits / a637084320

DevTools: Add Jest snapshot serializer for number formatting (#23139)

Numbers in JavaScript can have precision issues due to how they are encoded. This shows up in snapshot tests sometimes with values like 0.0009999999999999992, which makes the tests hard to read and visually diff. This PR adds a new snapshot serializers which clamps numbers at 3 decimal points (e.g. the above number 0.0009999999999999992 is serialized as 0.001). This new serializer does not impact non-numeric values, integers, and special numbers like NaN and Infinity.

Brian Vaughn committed Jan 20, 2022 at 15:52 UTC a63708432082d480d422b0c93de5403611d9ce38
10 files changed +57 -30
packages/react-devtools-shared/src/__tests__/__serializers__/dehydratedValueSerializer.js renamed
packages/react-devtools-shared/src/__tests__/__serializers__/hookSerializer.js renamed
packages/react-devtools-shared/src/__tests__/__serializers__/inspectedElementSerializer.js renamed
packages/react-devtools-shared/src/__tests__/__serializers__/numberToFixedSerializer.js new
+24
@@ -0,0 +1,24 @@
1 +const MAX_DECIMAL_PLACES = 3;
2 +
3 +// test() is part of Jest's serializer API
4 +export function test(maybeNumber) {
5 + return (
6 + typeof maybeNumber === 'number' &&
7 + Number.isFinite(maybeNumber) &&
8 + !Number.isInteger(maybeNumber) &&
9 + !Number.isNaN(maybeNumber)
10 + );
11 +}
12 +
13 +// print() is part of Jest's serializer API
14 +export function print(number, serialize, indent) {
15 + const string = number.toString();
16 + const pieces = string.split('.');
17 + if (pieces.length === 2) {
18 + if (pieces[1].length > MAX_DECIMAL_PLACES) {
19 + return number.toFixed(MAX_DECIMAL_PLACES);
20 + }
21 + }
22 +
23 + return string;
24 +}
packages/react-devtools-shared/src/__tests__/__serializers__/storeSerializer.js renamed
packages/react-devtools-shared/src/__tests__/__serializers__/treeContextStateSerializer.js renamed
packages/react-devtools-shared/src/__tests__/preprocessData-test.js
+23 -23
@@ -439,7 +439,7 @@ describe('Timeline profiler', () => {
439 Object {
440 "batchUID": 0,
441 "depth": 0,
442 - "duration": 0.004999999999999999,
442 + "duration": 0.005,
443 "lanes": Array [
444 9,
445 ],
@@ -459,7 +459,7 @@ describe('Timeline profiler', () => {
459 Object {
460 "batchUID": 0,
461 "depth": 0,
462 - "duration": 0.002999999999999999,
462 + "duration": 0.003,
463 "lanes": Array [
464 9,
465 ],
@@ -469,7 +469,7 @@ describe('Timeline profiler', () => {
469 Object {
470 "batchUID": 0,
471 "depth": 1,
472 - "duration": 0.0010000000000000009,
472 + "duration": 0.001,
473 "lanes": Array [
474 9,
475 ],
@@ -529,7 +529,7 @@ describe('Timeline profiler', () => {
529 Object {
530 "batchUID": 0,
531 "depth": 0,
532 - "duration": 0.004999999999999999,
532 + "duration": 0.005,
533 "lanes": Array [
534 9,
535 ],
@@ -549,7 +549,7 @@ describe('Timeline profiler', () => {
549 Object {
550 "batchUID": 0,
551 "depth": 0,
552 - "duration": 0.002999999999999999,
552 + "duration": 0.003,
553 "lanes": Array [
554 9,
555 ],
@@ -559,7 +559,7 @@ describe('Timeline profiler', () => {
559 Object {
560 "batchUID": 0,
561 "depth": 1,
562 - "duration": 0.0010000000000000009,
562 + "duration": 0.001,
563 "lanes": Array [
564 9,
565 ],
@@ -656,7 +656,7 @@ describe('Timeline profiler', () => {
656 Object {
657 "batchUID": 0,
658 "depth": 1,
659 - "duration": 0.0009999999999999992,
659 + "duration": 0.001,
660 "lanes": Array [
661 0,
662 ],
@@ -748,7 +748,7 @@ describe('Timeline profiler', () => {
748 Object {
749 "batchUID": 0,
750 "depth": 1,
751 - "duration": 0.0009999999999999992,
751 + "duration": 0.001,
752 "lanes": Array [
753 0,
754 ],
@@ -865,7 +865,7 @@ describe('Timeline profiler', () => {
865 Object {
866 "batchUID": 0,
867 "depth": 1,
868 - "duration": 0.0009999999999999992,
868 + "duration": 0.001,
869 "lanes": Array [
870 4,
871 ],
@@ -887,7 +887,7 @@ describe('Timeline profiler', () => {
887 Object {
888 "batchUID": 1,
889 "depth": 0,
890 - "duration": 0.012000000000000004,
890 + "duration": 0.012,
891 "lanes": Array [
892 4,
893 ],
@@ -897,7 +897,7 @@ describe('Timeline profiler', () => {
897 Object {
898 "batchUID": 1,
899 "depth": 0,
900 - "duration": 0.0030000000000000027,
900 + "duration": 0.003,
901 "lanes": Array [
902 4,
903 ],
@@ -907,7 +907,7 @@ describe('Timeline profiler', () => {
907 Object {
908 "batchUID": 1,
909 "depth": 0,
910 - "duration": 0.008000000000000004,
910 + "duration": 0.008,
911 "lanes": Array [
912 4,
913 ],
@@ -917,7 +917,7 @@ describe('Timeline profiler', () => {
917 Object {
918 "batchUID": 1,
919 "depth": 1,
920 - "duration": 0.0010000000000000009,
920 + "duration": 0.001,
921 "lanes": Array [
922 4,
923 ],
@@ -927,7 +927,7 @@ describe('Timeline profiler', () => {
927 Object {
928 "batchUID": 1,
929 "depth": 0,
930 - "duration": 0.0029999999999999957,
930 + "duration": 0.003,
931 "lanes": Array [
932 4,
933 ],
@@ -946,21 +946,21 @@ describe('Timeline profiler', () => {
946 },
947 Object {
948 "componentName": "App",
949 - "duration": 0.0020000000000000018,
949 + "duration": 0.002,
950 "timestamp": 0.018,
951 "type": "passive-effect-mount",
952 "warning": null,
953 },
954 Object {
955 "componentName": "App",
956 - "duration": 0.0010000000000000009,
956 + "duration": 0.001,
957 "timestamp": 0.023,
958 "type": "render",
959 "warning": null,
960 },
961 Object {
962 "componentName": "App",
963 - "duration": 0.0010000000000000009,
963 + "duration": 0.001,
964 "timestamp": 0.036,
965 "type": "passive-effect-mount",
966 "warning": null,
@@ -1052,7 +1052,7 @@ describe('Timeline profiler', () => {
1052 Object {
1053 "batchUID": 0,
1054 "depth": 1,
1055 - "duration": 0.0009999999999999992,
1055 + "duration": 0.001,
1056 "lanes": Array [
1057 4,
1058 ],
@@ -1072,7 +1072,7 @@ describe('Timeline profiler', () => {
1072 Object {
1073 "batchUID": 1,
1074 "depth": 0,
1075 - "duration": 0.012000000000000004,
1075 + "duration": 0.012,
1076 "lanes": Array [
1077 4,
1078 ],
@@ -1082,7 +1082,7 @@ describe('Timeline profiler', () => {
1082 Object {
1083 "batchUID": 1,
1084 "depth": 0,
1085 - "duration": 0.0030000000000000027,
1085 + "duration": 0.003,
1086 "lanes": Array [
1087 4,
1088 ],
@@ -1092,7 +1092,7 @@ describe('Timeline profiler', () => {
1092 Object {
1093 "batchUID": 1,
1094 "depth": 0,
1095 - "duration": 0.008000000000000004,
1095 + "duration": 0.008,
1096 "lanes": Array [
1097 4,
1098 ],
@@ -1102,7 +1102,7 @@ describe('Timeline profiler', () => {
1102 Object {
1103 "batchUID": 1,
1104 "depth": 1,
1105 - "duration": 0.0010000000000000009,
1105 + "duration": 0.001,
1106 "lanes": Array [
1107 4,
1108 ],
@@ -1112,7 +1112,7 @@ describe('Timeline profiler', () => {
1112 Object {
1113 "batchUID": 1,
1114 "depth": 0,
1115 - "duration": 0.0029999999999999957,
1115 + "duration": 0.003,
1116 "lanes": Array [
1117 4,
1118 ],
packages/react-devtools-shared/src/__tests__/storeStressSync-test.js
+1 -1
@@ -28,7 +28,7 @@ describe('StoreStress (Legacy Mode)', () => {
28 act = utils.act;
29 legacyRender = utils.legacyRender;
30
31 - print = require('./storeSerializer').print;
31 + print = require('./__serializers__/storeSerializer').print;
32 });
33
34 // This is a stress test for the tree mount/update/unmount traversal.
packages/react-devtools-shared/src/__tests__/storeStressTestConcurrent-test.js
+1 -1
@@ -28,7 +28,7 @@ describe('StoreStressConcurrent', () => {
28 // this helper with the real thing.
29 actAsync = require('./utils').actAsync;
30
31 - print = require('./storeSerializer').print;
31 + print = require('./__serializers__/storeSerializer').print;
32 });
33
34 // TODO: Remove this in favor of @gate pragma
scripts/jest/config.build-devtools.js
+8 -5
@@ -62,19 +62,22 @@ module.exports = Object.assign({}, baseConfig, {
62 testRegex: 'packages/react-devtools-shared/.+/__tests__/[^]+.test.js$',
63 snapshotSerializers: [
64 require.resolve(
65 - '../../packages/react-devtools-shared/src/__tests__/dehydratedValueSerializer.js'
65 + '../../packages/react-devtools-shared/src/__tests__/__serializers__/dehydratedValueSerializer.js'
66 ),
67 require.resolve(
68 - '../../packages/react-devtools-shared/src/__tests__/hookSerializer.js'
68 + '../../packages/react-devtools-shared/src/__tests__/__serializers__/hookSerializer.js'
69 ),
70 require.resolve(
71 - '../../packages/react-devtools-shared/src/__tests__/inspectedElementSerializer.js'
71 + '../../packages/react-devtools-shared/src/__tests__/__serializers__/inspectedElementSerializer.js'
72 ),
73 require.resolve(
74 - '../../packages/react-devtools-shared/src/__tests__/storeSerializer.js'
74 + '../../packages/react-devtools-shared/src/__tests__/__serializers__/storeSerializer.js'
75 ),
76 require.resolve(
77 - '../../packages/react-devtools-shared/src/__tests__/treeContextStateSerializer.js'
77 + '../../packages/react-devtools-shared/src/__tests__/__serializers__/treeContextStateSerializer.js'
78 + ),
79 + require.resolve(
80 + '../../packages/react-devtools-shared/src/__tests__/__serializers__/numberToFixedSerializer.js'
81 ),
82 ],
83 setupFiles: [