hevy-shared 1.0.960 → 1.0.962

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/.eslintignore +2 -0
  2. package/.eslintrc +21 -0
  3. package/.github/workflows/ci.yml +15 -0
  4. package/.github/workflows/npm-publish.yml +59 -0
  5. package/.github/workflows/pr-auto-assign.yml +15 -0
  6. package/.prettierrc.js +5 -0
  7. package/README.md +2 -17
  8. package/built/chat.d.ts +23 -25
  9. package/built/coachPlans.d.ts +1 -2
  10. package/built/coachPlans.js +2 -2
  11. package/built/filterExercises.d.ts +3 -19
  12. package/built/filterExercises.js +60 -72
  13. package/built/index.d.ts +304 -1140
  14. package/built/index.js +75 -269
  15. package/built/setIndicatorUtils.d.ts +3 -4
  16. package/built/setIndicatorUtils.js +1 -15
  17. package/built/tests/utils.test.js +0 -748
  18. package/built/tests/workoutVolume.test.js +49 -165
  19. package/built/units.d.ts +7 -14
  20. package/built/units.js +14 -24
  21. package/built/utils.d.ts +5 -192
  22. package/built/utils.js +85 -598
  23. package/built/websocket.d.ts +2 -14
  24. package/built/workoutVolume.d.ts +5 -24
  25. package/built/workoutVolume.js +34 -25
  26. package/jest.config.js +4 -0
  27. package/package.json +10 -32
  28. package/src/chat.ts +130 -0
  29. package/src/coachPlans.ts +57 -0
  30. package/src/constants.ts +14 -0
  31. package/src/filterExercises.ts +222 -0
  32. package/src/index.ts +1576 -0
  33. package/src/setIndicatorUtils.ts +137 -0
  34. package/src/tests/utils.test.ts +156 -0
  35. package/src/tests/workoutVolume.test.ts +93 -0
  36. package/src/units.ts +41 -0
  37. package/src/utils.ts +516 -0
  38. package/src/websocket.ts +36 -0
  39. package/src/workoutVolume.ts +175 -0
  40. package/tsconfig.json +70 -0
  41. package/built/API/APIClient.d.ts +0 -157
  42. package/built/API/APIClient.js +0 -381
  43. package/built/API/index.d.ts +0 -2
  44. package/built/API/index.js +0 -18
  45. package/built/API/types.d.ts +0 -38
  46. package/built/API/types.js +0 -18
  47. package/built/adjustEventTokens.d.ts +0 -16
  48. package/built/adjustEventTokens.js +0 -18
  49. package/built/adminPermissions.d.ts +0 -4
  50. package/built/adminPermissions.js +0 -22
  51. package/built/async.d.ts +0 -50
  52. package/built/async.js +0 -170
  53. package/built/cue.d.ts +0 -12
  54. package/built/cue.js +0 -22
  55. package/built/exerciseLocaleUtils.d.ts +0 -17
  56. package/built/exerciseLocaleUtils.js +0 -62
  57. package/built/hevyTrainer.d.ts +0 -250
  58. package/built/hevyTrainer.js +0 -676
  59. package/built/muscleHeatmaps.d.ts +0 -31
  60. package/built/muscleHeatmaps.js +0 -68
  61. package/built/muscleSplits.d.ts +0 -36
  62. package/built/muscleSplits.js +0 -100
  63. package/built/normalizedWorkoutUtils.d.ts +0 -88
  64. package/built/normalizedWorkoutUtils.js +0 -112
  65. package/built/notifications.d.ts +0 -215
  66. package/built/notifications.js +0 -9
  67. package/built/routineUtils.d.ts +0 -14
  68. package/built/routineUtils.js +0 -186
  69. package/built/schemas.d.ts +0 -6
  70. package/built/schemas.js +0 -12
  71. package/built/tests/async.test.d.ts +0 -1
  72. package/built/tests/async.test.js +0 -49
  73. package/built/tests/hevyTrainer.test.d.ts +0 -1
  74. package/built/tests/hevyTrainer.test.js +0 -1199
  75. package/built/tests/muscleSplit.test.d.ts +0 -1
  76. package/built/tests/muscleSplit.test.js +0 -153
  77. package/built/tests/routineUtils.test.d.ts +0 -1
  78. package/built/tests/routineUtils.test.js +0 -745
  79. package/built/tests/testUtils.d.ts +0 -85
  80. package/built/tests/testUtils.js +0 -319
  81. package/built/translations/index.d.ts +0 -2
  82. package/built/translations/index.js +0 -18
  83. package/built/translations/translationUtils.d.ts +0 -2
  84. package/built/translations/translationUtils.js +0 -61
  85. package/built/translations/types.d.ts +0 -8
  86. package/built/translations/types.js +0 -20
  87. package/built/typeUtils.d.ts +0 -70
  88. package/built/typeUtils.js +0 -55
@@ -1,9 +1,5 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const dayjs_1 = __importDefault(require("dayjs"));
7
3
  const utils_1 = require("../utils");
8
4
  describe('utils', () => {
9
5
  describe('isValidUsername', () => {
@@ -19,7 +15,6 @@ describe('utils', () => {
19
15
  expect((0, utils_1.isValidUsername)('desmond-mc')).toBe(false);
20
16
  expect((0, utils_1.isValidUsername)('.desmondmc')).toBe(false);
21
17
  expect((0, utils_1.isValidUsername)('thisusernameistolongg')).toBe(false);
22
- expect((0, utils_1.isValidUsername)('Desmond')).toBe(false);
23
18
  });
24
19
  });
25
20
  describe('isValidEmail', () => {
@@ -35,37 +30,16 @@ describe('utils', () => {
35
30
  });
36
31
  describe('isValidUrl', () => {
37
32
  it('returns true for valid url', () => {
38
- expect((0, utils_1.isValidWebUrl)('0-0.com')).toBe(true);
39
- expect((0, utils_1.isValidWebUrl)('0--0.com')).toBe(true);
40
- expect((0, utils_1.isValidWebUrl)('a.aa')).toBe(true);
41
- expect((0, utils_1.isValidWebUrl)('https://a.aa')).toBe(true);
42
- expect((0, utils_1.isValidWebUrl)('https://a.aa/')).toBe(true);
43
- expect((0, utils_1.isValidWebUrl)('w.a.aa')).toBe(true);
44
- expect((0, utils_1.isValidWebUrl)('https://w.a.aa')).toBe(true);
45
- expect((0, utils_1.isValidWebUrl)('https://w.a.aa/')).toBe(true);
46
33
  expect((0, utils_1.isValidWebUrl)('http://hevyapp.com')).toBe(true);
47
34
  expect((0, utils_1.isValidWebUrl)('hevyapp.com')).toBe(true);
48
35
  expect((0, utils_1.isValidWebUrl)('https://hevyapp.com')).toBe(true);
49
36
  expect((0, utils_1.isValidWebUrl)('hevyapp.com/')).toBe(true);
50
- expect((0, utils_1.isValidWebUrl)('https://hevyapp.com/')).toBe(true);
51
37
  expect((0, utils_1.isValidWebUrl)('hevyapp.com/about-us')).toBe(true);
52
38
  expect((0, utils_1.isValidWebUrl)('www.hevyapp.com')).toBe(true);
53
39
  expect((0, utils_1.isValidWebUrl)('something.xd')).toBe(true);
54
40
  expect((0, utils_1.isValidWebUrl)('my-cool.website')).toBe(true);
55
41
  });
56
42
  it('returns false for invalid url', () => {
57
- expect((0, utils_1.isValidWebUrl)('-.com')).toBe(false);
58
- expect((0, utils_1.isValidWebUrl)('0-.com')).toBe(false);
59
- expect((0, utils_1.isValidWebUrl)('-0.com')).toBe(false);
60
- expect((0, utils_1.isValidWebUrl)('a.a')).toBe(false);
61
- expect((0, utils_1.isValidWebUrl)('a..aa')).toBe(false);
62
- expect((0, utils_1.isValidWebUrl)('.a.aa')).toBe(false);
63
- expect((0, utils_1.isValidWebUrl)('..a.aa')).toBe(false);
64
- expect((0, utils_1.isValidWebUrl)('a.aa.')).toBe(false);
65
- expect((0, utils_1.isValidWebUrl)('hevyapp.com:1234')).toBe(false);
66
- expect((0, utils_1.isValidWebUrl)('hevyapp.com:1234/')).toBe(false);
67
- expect((0, utils_1.isValidWebUrl)('https://hevyapp.com:1234')).toBe(false);
68
- expect((0, utils_1.isValidWebUrl)('https://hevyapp.com:1234/')).toBe(false);
69
43
  expect((0, utils_1.isValidWebUrl)('asdasd')).toBe(false);
70
44
  expect((0, utils_1.isValidWebUrl)('ftp://hevyapp.com')).toBe(false);
71
45
  expect((0, utils_1.isValidWebUrl)('mailto://me@me.com')).toBe(false);
@@ -77,10 +51,6 @@ describe('utils', () => {
77
51
  expect((0, utils_1.isValidWebUrl)('This is my link')).toBe(false);
78
52
  expect((0, utils_1.isValidWebUrl)('my_impossible.website')).toBe(false);
79
53
  });
80
- it('returns false when the entire string is not a valid url', () => {
81
- expect((0, utils_1.isValidWebUrl)(' https://a.aa')).toBe(false);
82
- expect((0, utils_1.isValidWebUrl)('https://a.aa ')).toBe(false);
83
- });
84
54
  });
85
55
  describe('isValidPhoneNumber', () => {
86
56
  it('returns true for a valid phone number', () => {
@@ -98,76 +68,6 @@ describe('utils', () => {
98
68
  expect((0, utils_1.isValidPhoneNumber)('')).toBe(false);
99
69
  });
100
70
  });
101
- describe('isNumber', () => {
102
- it('returns true for a number', () => {
103
- expect((0, utils_1.isNumber)(1)).toBe(true);
104
- expect((0, utils_1.isNumber)(0)).toBe(true);
105
- expect((0, utils_1.isNumber)(100)).toBe(true);
106
- expect((0, utils_1.isNumber)(1000000000)).toBe(true);
107
- expect((0, utils_1.isNumber)(-1)).toBe(true);
108
- expect((0, utils_1.isNumber)(-100)).toBe(true);
109
- expect((0, utils_1.isNumber)(-1000000000.0)).toBe(true);
110
- expect((0, utils_1.isNumber)(9.0)).toBe(true);
111
- expect((0, utils_1.isNumber)(1.1)).toBe(true);
112
- expect((0, utils_1.isNumber)(0.1)).toBe(true);
113
- expect((0, utils_1.isNumber)(0.0000001)).toBe(true);
114
- expect((0, utils_1.isNumber)(0.111111)).toBe(true);
115
- expect((0, utils_1.isNumber)(100.1)).toBe(true);
116
- expect((0, utils_1.isNumber)(1000000000.1)).toBe(true);
117
- expect((0, utils_1.isNumber)(-1.1)).toBe(true);
118
- expect((0, utils_1.isNumber)((5 * 8) / 689)).toBe(true);
119
- expect((0, utils_1.isNumber)(Infinity)).toBe(true);
120
- expect((0, utils_1.isNumber)(-Infinity)).toBe(true);
121
- expect((0, utils_1.isNumber)(NaN)).toBe(true);
122
- });
123
- it('returns false for a non-number', () => {
124
- expect((0, utils_1.isNumber)('')).toBe(false);
125
- expect((0, utils_1.isNumber)('1')).toBe(false);
126
- expect((0, utils_1.isNumber)(null)).toBe(false);
127
- expect((0, utils_1.isNumber)(undefined)).toBe(false);
128
- expect((0, utils_1.isNumber)(false)).toBe(false);
129
- expect((0, utils_1.isNumber)(true)).toBe(false);
130
- expect((0, utils_1.isNumber)({})).toBe(false);
131
- expect((0, utils_1.isNumber)([])).toBe(false);
132
- expect((0, utils_1.isNumber)({ number: 8 })).toBe(false);
133
- expect((0, utils_1.isNumber)('1')).toBe(false);
134
- expect((0, utils_1.isNumber)('0')).toBe(false);
135
- expect((0, utils_1.isNumber)('100')).toBe(false);
136
- expect((0, utils_1.isNumber)('1000000000')).toBe(false);
137
- expect((0, utils_1.isNumber)('-1')).toBe(false);
138
- expect((0, utils_1.isNumber)('-100')).toBe(false);
139
- expect((0, utils_1.isNumber)('-1000000000.0')).toBe(false);
140
- expect((0, utils_1.isNumber)('9.0')).toBe(false);
141
- expect((0, utils_1.isNumber)('1.1')).toBe(false);
142
- expect((0, utils_1.isNumber)('0.1')).toBe(false);
143
- expect((0, utils_1.isNumber)('0.0000001')).toBe(false);
144
- expect((0, utils_1.isNumber)('0.111111')).toBe(false);
145
- expect((0, utils_1.isNumber)('100.1')).toBe(false);
146
- expect((0, utils_1.isNumber)('1000000000.1')).toBe(false);
147
- expect((0, utils_1.isNumber)('-1.1')).toBe(false);
148
- });
149
- });
150
- describe('isWholeNumber', () => {
151
- it('returns true for a whole number', () => {
152
- expect((0, utils_1.isWholeNumber)(1)).toBe(true);
153
- expect((0, utils_1.isWholeNumber)(0)).toBe(true);
154
- expect((0, utils_1.isWholeNumber)(100)).toBe(true);
155
- expect((0, utils_1.isWholeNumber)(1000000000)).toBe(true);
156
- expect((0, utils_1.isWholeNumber)(-1)).toBe(true);
157
- expect((0, utils_1.isWholeNumber)(-100)).toBe(true);
158
- expect((0, utils_1.isWholeNumber)(-1000000000.0)).toBe(true);
159
- expect((0, utils_1.isWholeNumber)(9.0)).toBe(true);
160
- });
161
- it('returns false for a non-whole number', () => {
162
- expect((0, utils_1.isWholeNumber)(1.1)).toBe(false);
163
- expect((0, utils_1.isWholeNumber)(0.1)).toBe(false);
164
- expect((0, utils_1.isWholeNumber)(0.0000001)).toBe(false);
165
- expect((0, utils_1.isWholeNumber)(0.111111)).toBe(false);
166
- expect((0, utils_1.isWholeNumber)(100.1)).toBe(false);
167
- expect((0, utils_1.isWholeNumber)(1000000000.1)).toBe(false);
168
- expect((0, utils_1.isWholeNumber)(-1.1)).toBe(false);
169
- });
170
- });
171
71
  describe('forceStringToNumber', () => {
172
72
  it('Takes any string and outputs a number. No matter what.', () => {
173
73
  expect((0, utils_1.forceStringToNumber)('10')).toBe(10);
@@ -198,143 +98,6 @@ describe('utils', () => {
198
98
  expect((0, utils_1.stringToNumber)('')).toBe(undefined);
199
99
  });
200
100
  });
201
- describe('findMapped', () => {
202
- it('Returns the first non-undefined value produced by transform function being applied to array elements', () => {
203
- expect((0, utils_1.findMapped)([1, 2, 3, 4, 5], (e) => (e >= 3 ? e * 10 : undefined))).toBe(30);
204
- expect((0, utils_1.findMapped)([1, 2, 3, 4, 5], (e) => (e >= 3 ? String(e) : undefined))).toBe('3');
205
- expect((0, utils_1.findMapped)(['a: element 001.', 'b: element 002.', 'c: element 003.'], (e) => { var _a; return (_a = e.match(/^c: [^0-9]*([0-9]+).*$/)) === null || _a === void 0 ? void 0 : _a[1]; })).toBe('003');
206
- });
207
- it('Returns `undefined` if no non-undefined value was produced by transform function being applied to array elements', () => {
208
- expect((0, utils_1.findMapped)([1, 2, 3, 4, 5], () => undefined)).toBeUndefined();
209
- expect((0, utils_1.findMapped)([], () => true)).toBeUndefined();
210
- expect((0, utils_1.findMapped)([], () => undefined)).toBeUndefined();
211
- });
212
- });
213
- describe('toFragmentedJSON', () => {
214
- it('converts any array into an array of JSON chunks with a maximum given length', () => {
215
- expect((0, utils_1.toFragmentedJSON)([
216
- { value: 'AAAAAAAAAAAAAAAA' },
217
- { value: 'BBBBBBBBBBBBBBBBBBBBB' },
218
- { value: 'CCCCCCCCCCCCCCCC' },
219
- ], 64)).toEqual([
220
- JSON.stringify([
221
- { value: 'AAAAAAAAAAAAAAAA' },
222
- { value: 'BBBBBBBBBBBBBBBBBBBBB' },
223
- ]),
224
- JSON.stringify([{ value: 'CCCCCCCCCCCCCCCC' }]),
225
- ]);
226
- expect((0, utils_1.toFragmentedJSON)([
227
- { value: 'AAAAAAAAAAAAAAAA' },
228
- { value: 'BBBBBBBBBBBBBBBBBBBBB' },
229
- { value: 'CCCCCCCCCCCCCCCC' },
230
- ], 35)).toEqual([
231
- JSON.stringify([{ value: 'AAAAAAAAAAAAAAAA' }]),
232
- JSON.stringify([{ value: 'BBBBBBBBBBBBBBBBBBBBB' }]),
233
- JSON.stringify([{ value: 'CCCCCCCCCCCCCCCC' }]),
234
- ]);
235
- expect(() => (0, utils_1.toFragmentedJSON)([
236
- { value: 'AAAAAAAAAAAAAAAA' },
237
- { value: 'BBBBBBBBBBBBBBBBBBBBB' },
238
- { value: 'CCCCCCCCCCCCCCCC' },
239
- ], 34)).toThrow();
240
- expect((0, utils_1.toFragmentedJSON)(['A', 'B', 'C'], 15)).toEqual([
241
- JSON.stringify(['A', 'B', 'C']),
242
- ]);
243
- expect((0, utils_1.toFragmentedJSON)(['A', 'B', 'C'], 10)).toEqual([
244
- JSON.stringify(['A', 'B']),
245
- JSON.stringify(['C']),
246
- ]);
247
- expect((0, utils_1.toFragmentedJSON)(['A', 'B', 'C'], 5)).toEqual([
248
- JSON.stringify(['A']),
249
- JSON.stringify(['B']),
250
- JSON.stringify(['C']),
251
- ]);
252
- expect(() => (0, utils_1.toFragmentedJSON)(['A', 'B', 'C'], 1)).toThrow();
253
- expect(() => (0, utils_1.toFragmentedJSON)(['A', 'B', 'C'], 0)).toThrow();
254
- expect((0, utils_1.toFragmentedJSON)([], 1)).toEqual([]);
255
- expect((0, utils_1.toFragmentedJSON)([], 0)).toEqual([]);
256
- });
257
- it('returns an empty array for an empty input array', () => {
258
- expect((0, utils_1.toFragmentedJSON)(['blah'], 100)).toEqual([
259
- JSON.stringify(['blah']),
260
- ]);
261
- expect((0, utils_1.toFragmentedJSON)([], 100)).toEqual([]);
262
- expect((0, utils_1.toFragmentedJSON)([], 100)).not.toEqual([JSON.stringify([])]);
263
- });
264
- });
265
- describe('getClosestDataPointBeforeTargetDate', () => {
266
- it('gets the closest data point before a target date, if such a data point exists, using a function to extract the date from the data points', () => {
267
- var _a, _b, _c, _d;
268
- expect((0, utils_1.getClosestDataPointBeforeTargetDate)([
269
- { id: 1, date: new Date('2023-01-01') },
270
- { id: 2, date: new Date('2023-04-01') },
271
- ], (item) => new Date(item.date), new Date('2023-03-15'))).toEqual({ id: 1, date: new Date('2023-01-01') });
272
- expect((_a = (0, utils_1.getClosestDataPointBeforeTargetDate)([{ key: 'abc', date: '2022-10-11' }], (item) => new Date(item.date), new Date('2022-12-21'))) === null || _a === void 0 ? void 0 : _a.key).toEqual('abc');
273
- expect((_b = (0, utils_1.getClosestDataPointBeforeTargetDate)([
274
- { key: 'wrong1', date: '2022-09-05' },
275
- { key: 'wrong2', date: '2022-09-06' },
276
- { key: 'wrong3', date: '2022-09-07' },
277
- { key: 'wrong4', date: '2022-09-08' },
278
- { key: 'closest', date: '2022-09-09' },
279
- { key: 'wrong5', date: '2022-09-11' },
280
- { key: 'wrong6', date: '2022-09-12' },
281
- { key: 'wrong7', date: '2022-09-13' },
282
- ], (item) => new Date(item.date), new Date('2022-09-10'))) === null || _b === void 0 ? void 0 : _b.key).toEqual('closest');
283
- expect((_c = (0, utils_1.getClosestDataPointBeforeTargetDate)([
284
- { key: 'wrong1', date: '2022-09-05' },
285
- { key: 'wrong2', date: '2022-09-06' },
286
- { key: 'wrong3', date: '2022-09-07' },
287
- { key: 'wrong4', date: '2022-09-08' },
288
- { key: 'wrong5', date: '2022-09-09' },
289
- { key: 'exact', date: '2022-09-10' },
290
- { key: 'wrong6', date: '2022-09-11' },
291
- { key: 'wrong7', date: '2022-09-12' },
292
- { key: 'wrong8', date: '2022-09-13' },
293
- ], (item) => new Date(item.date), new Date('2022-09-10'))) === null || _c === void 0 ? void 0 : _c.key).toEqual('exact');
294
- expect((_d = (0, utils_1.getClosestDataPointBeforeTargetDate)([{ key: 'abc', date: '2023-01-15' }], (item) => new Date(item.date), new Date('2022-12-21'))) === null || _d === void 0 ? void 0 : _d.key).toBeUndefined();
295
- });
296
- });
297
- describe('getClosestDataPointAroundTargetDate', () => {
298
- it('gets the closest data point to a target date, if such a data point exists, using a function to extract the date from the data points', () => {
299
- var _a, _b, _c, _d;
300
- expect((0, utils_1.getClosestDataPointAroundTargetDate)([
301
- { id: 1, date: new Date('2023-01-01') },
302
- { id: 2, date: new Date('2023-04-01') },
303
- ], (item) => new Date(item.date), new Date('2023-03-15'))).toEqual({ id: 2, date: new Date('2023-04-01') });
304
- // Test single point - should return it as closest
305
- expect((_a = (0, utils_1.getClosestDataPointAroundTargetDate)([{ key: 'abc', date: '2022-10-11' }], (item) => new Date(item.date), new Date('2022-12-21'))) === null || _a === void 0 ? void 0 : _a.key).toEqual('abc');
306
- // Test multiple points - should return closest by absolute difference
307
- expect((_b = (0, utils_1.getClosestDataPointAroundTargetDate)([
308
- { key: 'wrong1', date: '2022-09-05' },
309
- { key: 'wrong2', date: '2022-09-06' },
310
- { key: 'wrong3', date: '2022-09-07' },
311
- { key: 'wrong4', date: '2022-09-08' },
312
- { key: 'closest', date: '2022-09-09' }, // 1 day before
313
- { key: 'alsoClose', date: '2022-09-11' }, // 1 day after
314
- { key: 'wrong6', date: '2022-09-12' },
315
- { key: 'wrong7', date: '2022-09-13' },
316
- ], (item) => new Date(item.date), new Date('2022-09-10'))) === null || _b === void 0 ? void 0 : _b.key).toEqual('closest'); // Should pick the earlier date when equidistant
317
- // Test exact match
318
- expect((_c = (0, utils_1.getClosestDataPointAroundTargetDate)([
319
- { key: 'wrong1', date: '2022-09-05' },
320
- { key: 'wrong2', date: '2022-09-06' },
321
- { key: 'wrong3', date: '2022-09-07' },
322
- { key: 'wrong4', date: '2022-09-08' },
323
- { key: 'wrong5', date: '2022-09-09' },
324
- { key: 'exact', date: '2022-09-10' },
325
- { key: 'wrong6', date: '2022-09-11' },
326
- { key: 'wrong7', date: '2022-09-12' },
327
- ], (item) => new Date(item.date), new Date('2022-09-10'))) === null || _c === void 0 ? void 0 : _c.key).toEqual('exact');
328
- // Test empty array
329
- expect((0, utils_1.getClosestDataPointAroundTargetDate)([], (item) => new Date(item.date), new Date('2022-09-10'))).toBeUndefined();
330
- // Test closest when target is between two dates
331
- expect((_d = (0, utils_1.getClosestDataPointAroundTargetDate)([
332
- { key: 'further', date: '2022-09-08' },
333
- { key: 'closest', date: '2022-09-09' },
334
- { key: 'secondClosest', date: '2022-09-12' },
335
- ], (item) => new Date(item.date), new Date('2022-09-10'))) === null || _d === void 0 ? void 0 : _d.key).toEqual('closest');
336
- });
337
- });
338
101
  describe('removeAccents', () => {
339
102
  it('Takes an input string and returns a new string with accents removed', () => {
340
103
  expect((0, utils_1.removeAccents)('dog')).toBe('dog');
@@ -362,520 +125,9 @@ describe('utils', () => {
362
125
  expect((0, utils_1.isValidFormattedTime)('asdfg')).toBe(false);
363
126
  expect((0, utils_1.isValidFormattedTime)('0:00')).toBe(false);
364
127
  expect((0, utils_1.isValidFormattedTime)('0:00:01')).toBe(false);
365
- expect((0, utils_1.isValidFormattedTime)('2:10')).toBe(false);
366
128
  expect((0, utils_1.isValidFormattedTime)('99:99')).toBe(true);
367
129
  expect((0, utils_1.isValidFormattedTime)('00:01')).toBe(true);
368
130
  expect((0, utils_1.isValidFormattedTime)('10:00:01')).toBe(true);
369
131
  });
370
132
  });
371
- describe('formatDurationInput', () => {
372
- it('Returns a string in the format of NN:NN or NN:NN:NN', () => {
373
- expect((0, utils_1.formatDurationInput)('0')).toBe('');
374
- expect((0, utils_1.formatDurationInput)('1')).toBe('00:01');
375
- expect((0, utils_1.formatDurationInput)('60')).toBe(undefined);
376
- expect((0, utils_1.formatDurationInput)('61')).toBe(undefined);
377
- expect((0, utils_1.formatDurationInput)('99:99')).toBe('99:99');
378
- });
379
- });
380
- describe('getEstimatedExercisesDurationSeconds', () => {
381
- const testCases = [
382
- {
383
- exercises: [
384
- {
385
- exercise_type: 'duration',
386
- rest_seconds: 10,
387
- sets: [{ duration_seconds: 50, indicator: 'normal' }],
388
- },
389
- ],
390
- expectedDuration: 50 + 10,
391
- },
392
- {
393
- exercises: [
394
- {
395
- exercise_type: 'floors_duration',
396
- rest_seconds: 10,
397
- sets: [{ duration_seconds: 0, indicator: 'normal' }],
398
- },
399
- ],
400
- expectedDuration: 10,
401
- },
402
- {
403
- exercises: [
404
- {
405
- exercise_type: 'weight_duration',
406
- rest_seconds: null,
407
- sets: [{ duration_seconds: 30, indicator: 'normal' }],
408
- },
409
- ],
410
- expectedDuration: 30 + utils_1.ESTIMATED_REST_TIMER_DURATION,
411
- },
412
- {
413
- exercises: [
414
- {
415
- exercise_type: 'distance_duration',
416
- rest_seconds: 120,
417
- sets: [{ duration_seconds: 40, indicator: 'normal' }],
418
- },
419
- ],
420
- expectedDuration: 40 + 120,
421
- },
422
- {
423
- exercises: [
424
- {
425
- exercise_type: 'weight_duration',
426
- rest_seconds: 120,
427
- sets: [{ duration_seconds: null, indicator: 'normal' }],
428
- },
429
- ],
430
- expectedDuration: 120 + utils_1.ESTIMATED_SET_DURATION,
431
- },
432
- {
433
- exercises: [
434
- {
435
- exercise_type: 'duration',
436
- rest_seconds: 0,
437
- sets: [{ duration_seconds: null, indicator: 'normal' }],
438
- },
439
- ],
440
- expectedDuration: utils_1.ESTIMATED_SET_DURATION,
441
- },
442
- {
443
- exercises: [
444
- {
445
- exercise_type: 'reps_only',
446
- rest_seconds: 180,
447
- sets: [{ duration_seconds: null, indicator: 'normal' }],
448
- },
449
- {
450
- exercise_type: 'reps_only',
451
- rest_seconds: 180,
452
- sets: [
453
- {
454
- duration_seconds: 0,
455
- indicator: 'normal',
456
- },
457
- {
458
- duration_seconds: 0,
459
- indicator: 'normal',
460
- },
461
- {
462
- duration_seconds: 0,
463
- indicator: 'normal',
464
- },
465
- {
466
- duration_seconds: 0,
467
- indicator: 'normal',
468
- },
469
- ],
470
- },
471
- ],
472
- expectedDuration: (180 + utils_1.ESTIMATED_SET_DURATION) * 5,
473
- },
474
- {
475
- exercises: [
476
- {
477
- exercise_type: 'reps_only',
478
- rest_seconds: null,
479
- sets: [{ duration_seconds: null, indicator: 'normal' }],
480
- },
481
- {
482
- exercise_type: 'reps_only',
483
- rest_seconds: null,
484
- sets: [
485
- {
486
- duration_seconds: 0,
487
- indicator: 'normal',
488
- },
489
- {
490
- duration_seconds: 0,
491
- indicator: 'dropset',
492
- },
493
- {
494
- duration_seconds: 0,
495
- indicator: 'normal',
496
- },
497
- {
498
- duration_seconds: 0,
499
- indicator: 'dropset',
500
- },
501
- ],
502
- },
503
- ],
504
- expectedDuration: utils_1.ESTIMATED_REST_TIMER_DURATION * 3 + 5 * utils_1.ESTIMATED_SET_DURATION,
505
- },
506
- ];
507
- testCases.forEach((testCase) => {
508
- it(`getEstimatedExercisesDurationSeconds`, () => {
509
- expect((0, utils_1.getEstimatedExercisesDurationSeconds)(testCase)).toBe(testCase.expectedDuration);
510
- });
511
- });
512
- });
513
- describe('splitAtUsernamesAndLinks', () => {
514
- it('Takes a string and returns an array of FormatAtText', () => {
515
- const inputOutputs = [
516
- [
517
- 'No mentions in this',
518
- [{ format: 'none', text: 'No mentions in this' }],
519
- ],
520
- [
521
- 'Crazy workout with @guillemros',
522
- [
523
- { format: 'none', text: 'Crazy workout with ' },
524
- { format: '@', text: '@guillemros' },
525
- ],
526
- ],
527
- [
528
- '@himynameisivo and @guillemros are crazy!',
529
- [
530
- { format: '@', text: '@himynameisivo' },
531
- { format: 'none', text: ' and ' },
532
- { format: '@', text: '@guillemros' },
533
- { format: 'none', text: ' are crazy!' },
534
- ],
535
- ],
536
- [
537
- 'Worked out with @himynameisivo and @guillemros!',
538
- [
539
- { format: 'none', text: 'Worked out with ' },
540
- { format: '@', text: '@himynameisivo' },
541
- { format: 'none', text: ' and ' },
542
- { format: '@', text: '@guillemros' },
543
- { format: 'none', text: '!' },
544
- ],
545
- ],
546
- [
547
- '@himynameisivo @guillemros!',
548
- [
549
- { format: '@', text: '@himynameisivo' },
550
- { format: 'none', text: ' ' },
551
- { format: '@', text: '@guillemros' },
552
- { format: 'none', text: '!' },
553
- ],
554
- ],
555
- [
556
- '@12345 @123_123!',
557
- [
558
- { format: '@', text: '@12345' },
559
- { format: 'none', text: ' ' },
560
- { format: '@', text: '@123_123' },
561
- { format: 'none', text: '!' },
562
- ],
563
- ],
564
- [
565
- '@12345 www.google.com! hey',
566
- [
567
- { format: '@', text: '@12345' },
568
- { format: 'none', text: ' ' },
569
- { format: 'link', text: 'www.google.com' },
570
- { format: 'none', text: '! hey' },
571
- ],
572
- ],
573
- [
574
- 'hey www.google.com youtube.com https://example.com',
575
- [
576
- { format: 'none', text: 'hey ' },
577
- { format: 'link', text: 'www.google.com' },
578
- { format: 'none', text: ' ' },
579
- { format: 'link', text: 'youtube.com' },
580
- { format: 'none', text: ' ' },
581
- { format: 'link', text: 'https://example.com' },
582
- ],
583
- ],
584
- [
585
- 'hey Test - https://www.tiktok.com/@tylerpath/video/7471271437467405614 @test',
586
- [
587
- { format: 'none', text: 'hey Test - ' },
588
- {
589
- format: 'link',
590
- text: 'https://www.tiktok.com/@tylerpath/video/7471271437467405614',
591
- },
592
- { format: 'none', text: ' ' },
593
- { format: '@', text: '@test' },
594
- ],
595
- ],
596
- ];
597
- inputOutputs.forEach((i) => {
598
- expect((0, utils_1.splitAtUsernamesAndLinks)(i[0])).toEqual(i[1]);
599
- });
600
- });
601
- });
602
- describe('generateUserGroup', () => {
603
- it('generates a subsample or test group given a user id', () => {
604
- expect((0, utils_1.generateUserGroup)('0a83932f-c3d4-4cbb-acfc-db48c09a362d', 2)).toEqual({
605
- isSuccess: true,
606
- value: Number(BigInt('0xdb48c09a362d') % BigInt(2)),
607
- });
608
- expect((0, utils_1.generateUserGroup)('2B022B1F-93C7-4C8F-9677-9F3000B29D2A', 3)).toEqual({
609
- isSuccess: true,
610
- value: Number(BigInt('0x9f3000b29d2a') % BigInt(3)),
611
- });
612
- expect((0, utils_1.generateUserGroup)('7693699a-afe7-4DEC-D07E-9694d2de3920', 1000)).toEqual({
613
- isSuccess: true,
614
- value: Number(BigInt('0x9694d2de3920') % BigInt(1000)),
615
- });
616
- });
617
- it('fails when given an invalid input', () => {
618
- expect((0, utils_1.generateUserGroup)('c1abee8a-461a-414c-9a2f-f1ba120cb8c7', 1)).toEqual({
619
- isSuccess: false,
620
- error: 'invalid-number-of-groups',
621
- });
622
- expect((0, utils_1.generateUserGroup)('absolutely-no-UUID-to-be-found-here', 2)).toEqual({
623
- isSuccess: false,
624
- error: 'invalid-uuid',
625
- });
626
- expect((0, utils_1.generateUserGroup)('3187b48c-d9bd-11ef-a2ec-325096b39f47', 2)).toEqual({
627
- isSuccess: false,
628
- error: 'uuid-not-v4',
629
- });
630
- expect((0, utils_1.generateUserGroup)('baa45206-475e-4bf5-7a9d-a21fd3d6966d', 2)).toEqual({
631
- isSuccess: false,
632
- error: 'invalid-variant',
633
- });
634
- });
635
- });
636
- describe('validateYoutubeUrl', () => {
637
- it('returns true for valid YouTube URLs', () => {
638
- expect((0, utils_1.validateYoutubeUrl)('https://www.youtube.com/watch?v=dQw4w9WgXcQ')).toBe(true);
639
- expect((0, utils_1.validateYoutubeUrl)('https://youtube.com/watch?v=dQw4w9WgXcQ')).toBe(true);
640
- expect((0, utils_1.validateYoutubeUrl)('http://youtube.com/watch?v=dQw4w9WgXcQ')).toBe(true);
641
- expect((0, utils_1.validateYoutubeUrl)('youtube.com/watch?v=dQw4w9WgXcQ')).toBe(true);
642
- expect((0, utils_1.validateYoutubeUrl)('https://youtu.be/dQw4w9WgXcQ')).toBe(true);
643
- expect((0, utils_1.validateYoutubeUrl)('https://www.youtube.com/shorts/dQw4w9WgXcQ')).toBe(true);
644
- expect((0, utils_1.validateYoutubeUrl)('https://www.youtube.com/embed/dQw4w9WgXcQ')).toBe(true);
645
- expect((0, utils_1.validateYoutubeUrl)('https://www.youtube.com/v/dQw4w9WgXcQ')).toBe(true);
646
- expect((0, utils_1.validateYoutubeUrl)('https://youtube.com/shorts/dQw4w9WgXcQ')).toBe(true);
647
- expect((0, utils_1.validateYoutubeUrl)('https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=10s')).toBe(true);
648
- });
649
- it('returns false for invalid YouTube URLs', () => {
650
- expect((0, utils_1.validateYoutubeUrl)('https://www.notbyoutube.com/watch?v=dQw4w9WgXcQ')).toBe(false);
651
- expect((0, utils_1.validateYoutubeUrl)('https://www.youtube.org/watch?v=dQw4w9WgXcQ')).toBe(false);
652
- expect((0, utils_1.validateYoutubeUrl)('https://www.youtube.com/notWatch?v=dQw4w9WgXcQ')).toBe(false);
653
- expect((0, utils_1.validateYoutubeUrl)('https://www.youtube.com/watch?id=dQw4w9WgXcQ')).toBe(false);
654
- expect((0, utils_1.validateYoutubeUrl)('https://www.youtube.com/watch?v=short')).toBe(false); // Too short ID
655
- expect((0, utils_1.validateYoutubeUrl)('https://www.youtu.be/dQw4w9WgXcQ')).toBe(false); // Invalid domain
656
- expect((0, utils_1.validateYoutubeUrl)('https://www.vimeo.com/123456789')).toBe(false);
657
- expect((0, utils_1.validateYoutubeUrl)('')).toBe(false);
658
- expect((0, utils_1.validateYoutubeUrl)('not a url')).toBe(false);
659
- });
660
- });
661
- describe('getYoutubeVideoId', () => {
662
- it('extracts video ID from standard YouTube URLs', () => {
663
- expect((0, utils_1.getYoutubeVideoId)('https://www.youtube.com/watch?v=dQw4w9WgXcQ')).toBe('dQw4w9WgXcQ');
664
- expect((0, utils_1.getYoutubeVideoId)('https://youtube.com/watch?v=dQw4w9WgXcQ')).toBe('dQw4w9WgXcQ');
665
- expect((0, utils_1.getYoutubeVideoId)('http://www.youtube.com/watch?v=dQw4w9WgXcQ')).toBe('dQw4w9WgXcQ');
666
- expect((0, utils_1.getYoutubeVideoId)('youtube.com/watch?v=dQw4w9WgXcQ')).toBe('dQw4w9WgXcQ');
667
- expect((0, utils_1.getYoutubeVideoId)('https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=10s')).toBe('dQw4w9WgXcQ');
668
- expect((0, utils_1.getYoutubeVideoId)('https://youtu.be/dQw4w9WgXcQ')).toBe('dQw4w9WgXcQ');
669
- expect((0, utils_1.getYoutubeVideoId)('https://www.youtube.com/embed/dQw4w9WgXcQ')).toBe('dQw4w9WgXcQ');
670
- expect((0, utils_1.getYoutubeVideoId)('https://www.youtube.com/v/dQw4w9WgXcQ')).toBe('dQw4w9WgXcQ');
671
- });
672
- it('extracts video ID from YouTube Shorts URLs', () => {
673
- expect((0, utils_1.getYoutubeVideoId)('https://www.youtube.com/shorts/dQw4w9WgXcQ')).toBe('dQw4w9WgXcQ');
674
- expect((0, utils_1.getYoutubeVideoId)('https://youtube.com/shorts/dQw4w9WgXcQ')).toBe('dQw4w9WgXcQ');
675
- expect((0, utils_1.getYoutubeVideoId)('youtube.com/shorts/dQw4w9WgXcQ')).toBe('dQw4w9WgXcQ');
676
- expect((0, utils_1.getYoutubeVideoId)('https://www.youtube.com/shorts/dQw4w9WgXcQ?feature=share')).toBe('dQw4w9WgXcQ');
677
- });
678
- it('returns undefined for invalid YouTube URLs', () => {
679
- expect((0, utils_1.getYoutubeVideoId)('https://www.notYoutube.com/watch?v=dQw4w9WgXcQ')).toBeUndefined();
680
- expect((0, utils_1.getYoutubeVideoId)('https://www.youtube.org/watch?v=dQw4w9WgXcQ')).toBeUndefined();
681
- expect((0, utils_1.getYoutubeVideoId)('https://www.vimeo.com/123456789')).toBeUndefined();
682
- expect((0, utils_1.getYoutubeVideoId)('')).toBeUndefined();
683
- expect((0, utils_1.getYoutubeVideoId)('not a url')).toBeUndefined();
684
- });
685
- it('returns undefined for invalid video IDs', () => {
686
- expect((0, utils_1.getYoutubeVideoId)('https://www.youtube.com/watch?v=short')).toBeUndefined(); // ID too short
687
- expect((0, utils_1.getYoutubeVideoId)('https://www.youtube.com/shorts/short')).toBeUndefined(); // ID too short
688
- });
689
- it('extracts video ID from videos in playlists', () => {
690
- expect((0, utils_1.getYoutubeVideoId)('https://www.youtube.com/watch?v=dQw4w9WgXcQ&list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoS')).toBe('dQw4w9WgXcQ');
691
- expect((0, utils_1.getYoutubeVideoId)('https://www.youtube.com/watch?v=dQw4w9WgXcQ&list=PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoS&index=2')).toBe('dQw4w9WgXcQ');
692
- });
693
- it('extracts video ID from videos from channels', () => {
694
- expect((0, utils_1.getYoutubeVideoId)('https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=channel')).toBe('dQw4w9WgXcQ');
695
- expect((0, utils_1.getYoutubeVideoId)('https://www.youtube.com/watch?v=dQw4w9WgXcQ&ab_channel=RickAstleyVEVO')).toBe('dQw4w9WgXcQ');
696
- });
697
- });
698
- describe('calculateCurrentWeekStreak', () => {
699
- it("Doesn't include gaps in the streak count", () => {
700
- const workouts = [
701
- { start_time: (0, dayjs_1.default)('2025-11-05').unix() },
702
- { start_time: (0, dayjs_1.default)('2025-11-02').unix() },
703
- { start_time: (0, dayjs_1.default)('2025-10-31').unix() },
704
- { start_time: (0, dayjs_1.default)('2025-10-23').unix() },
705
- { start_time: (0, dayjs_1.default)('2025-10-10').unix() },
706
- ];
707
- const firstWeekday = 'sunday';
708
- const untilUnix = (0, dayjs_1.default)('2025-11-06').unix();
709
- expect((0, utils_1.calculateCurrentWeekStreak)(workouts, firstWeekday, untilUnix)).toBe(3);
710
- });
711
- it("Calculates a potentially non-zero streak when the user hasn't worked out this week yet", () => {
712
- const workouts = [
713
- { start_time: (0, dayjs_1.default)('2025-10-31').unix() },
714
- { start_time: (0, dayjs_1.default)('2025-10-23').unix() },
715
- { start_time: (0, dayjs_1.default)('2025-10-20').unix() },
716
- { start_time: (0, dayjs_1.default)('2025-10-14').unix() + 1 },
717
- { start_time: (0, dayjs_1.default)('2025-10-12').unix() },
718
- ];
719
- const firstWeekday = 'monday';
720
- const untilUnix = (0, dayjs_1.default)('2025-11-06').unix();
721
- expect((0, utils_1.calculateCurrentWeekStreak)(workouts, firstWeekday, untilUnix)).toBe(4);
722
- });
723
- it('Includes this week in the streak count if the user worked out this week', () => {
724
- const workouts = [
725
- { start_time: (0, dayjs_1.default)('2025-11-05').unix() },
726
- { start_time: (0, dayjs_1.default)('2025-10-31').unix() },
727
- { start_time: (0, dayjs_1.default)('2025-10-23').unix() },
728
- { start_time: (0, dayjs_1.default)('2025-10-20').unix() },
729
- { start_time: (0, dayjs_1.default)('2025-10-14').unix() },
730
- { start_time: (0, dayjs_1.default)('2025-10-07').unix() },
731
- ];
732
- const firstWeekday = 'monday';
733
- const untilUnix = (0, dayjs_1.default)('2025-11-06').unix();
734
- expect((0, utils_1.calculateCurrentWeekStreak)(workouts, firstWeekday, untilUnix)).toBe(5);
735
- });
736
- it("Returns 0 if the user hasn't worked out", () => {
737
- const workouts = [];
738
- const firstWeekday = 'friday';
739
- const untilUnix = (0, dayjs_1.default)('2025-10-10').unix();
740
- expect((0, utils_1.calculateCurrentWeekStreak)(workouts, firstWeekday, untilUnix)).toBe(0);
741
- });
742
- it('Returns 0 if the user has not worked out this week and last week', () => {
743
- const workouts = [
744
- { start_time: (0, dayjs_1.default)('2025-10-23').unix() },
745
- { start_time: (0, dayjs_1.default)('2025-10-20').unix() },
746
- { start_time: (0, dayjs_1.default)('2025-10-13').unix() },
747
- { start_time: (0, dayjs_1.default)('2025-10-07').unix() },
748
- ];
749
- const firstWeekday = 'sunday';
750
- const untilUnix = (0, dayjs_1.default)('2025-11-05').unix();
751
- expect((0, utils_1.calculateCurrentWeekStreak)(workouts, firstWeekday, untilUnix)).toBe(0);
752
- });
753
- });
754
- describe('formatSetValue', () => {
755
- const baseParams = {
756
- set: {
757
- weight_kg: 100,
758
- reps: 10,
759
- duration_seconds: 90,
760
- distance_meters: 1500,
761
- custom_metric: 15,
762
- },
763
- units: {
764
- weight: 'kg',
765
- distance: 'kilometers',
766
- },
767
- lokalizedLabels: {
768
- kg: 'kg',
769
- lbs: 'lbs',
770
- km: 'km',
771
- mi: 'mi',
772
- m: 'm',
773
- yd: 'yd',
774
- steps: 'Steps',
775
- floors: 'Floors',
776
- },
777
- };
778
- it('formats weight and reps for weight-based exercises', () => {
779
- expect((0, utils_1.formatSetValue)(Object.assign(Object.assign({}, baseParams), { exerciseType: 'weight_reps' }))).toBe('100 kg x 10');
780
- expect((0, utils_1.formatSetValue)(Object.assign(Object.assign({}, baseParams), { exerciseType: 'bodyweight_reps' }))).toBe('100 kg x 10');
781
- });
782
- it('formats assisted bodyweight reps with negative weight', () => {
783
- expect((0, utils_1.formatSetValue)(Object.assign(Object.assign({}, baseParams), { exerciseType: 'bodyweight_assisted_reps', set: Object.assign(Object.assign({}, baseParams.set), { weight_kg: 15, reps: 8 }) }))).toBe('-15 kg x 8');
784
- });
785
- it('formats reps-only exercises', () => {
786
- expect((0, utils_1.formatSetValue)(Object.assign(Object.assign({}, baseParams), { exerciseType: 'reps_only' }))).toBe('10');
787
- });
788
- it('formats distance with duration', () => {
789
- expect((0, utils_1.formatSetValue)(Object.assign(Object.assign({}, baseParams), { exerciseType: 'distance_duration' }))).toBe('1.5 km - 1min 30s');
790
- });
791
- it('formats duration-only exercises', () => {
792
- expect((0, utils_1.formatSetValue)(Object.assign(Object.assign({}, baseParams), { exerciseType: 'duration' }))).toBe('1min 30s');
793
- });
794
- it('formats short distance with weight', () => {
795
- expect((0, utils_1.formatSetValue)(Object.assign(Object.assign({}, baseParams), { exerciseType: 'short_distance_weight', set: Object.assign(Object.assign({}, baseParams.set), { distance_meters: 250 }) }))).toBe('100 kg - 250 m');
796
- });
797
- it('handles null reps as zero', () => {
798
- expect((0, utils_1.formatSetValue)(Object.assign(Object.assign({}, baseParams), { exerciseType: 'weight_reps', set: Object.assign(Object.assign({}, baseParams.set), { reps: null }) }))).toBe('100 kg x 0');
799
- });
800
- it('formats weight with duration', () => {
801
- expect((0, utils_1.formatSetValue)(Object.assign(Object.assign({}, baseParams), { exerciseType: 'weight_duration' }))).toBe('100 kg - 1min 30s');
802
- });
803
- it('formats weights in kg', () => {
804
- expect((0, utils_1.formatSetValue)({
805
- set: {
806
- weight_kg: 100,
807
- reps: 12,
808
- duration_seconds: null,
809
- distance_meters: null,
810
- custom_metric: null,
811
- },
812
- units: {
813
- weight: 'kg',
814
- distance: 'kilometers',
815
- },
816
- lokalizedLabels: {
817
- kg: 'kg',
818
- lbs: 'lbs',
819
- km: 'km',
820
- mi: 'mi',
821
- m: 'm',
822
- yd: 'yd',
823
- steps: 'Steps',
824
- floors: 'Floors',
825
- },
826
- exerciseType: 'weight_reps',
827
- })).toBe('100 kg x 12');
828
- });
829
- it('formats weights logged in lbs', () => {
830
- expect((0, utils_1.formatSetValue)({
831
- set: {
832
- weight_kg: 50,
833
- reps: 12,
834
- duration_seconds: null,
835
- distance_meters: null,
836
- custom_metric: null,
837
- },
838
- units: {
839
- weight: 'lbs',
840
- distance: 'kilometers',
841
- },
842
- lokalizedLabels: {
843
- kg: 'kg',
844
- lbs: 'lbs',
845
- km: 'km',
846
- mi: 'mi',
847
- m: 'm',
848
- yd: 'yd',
849
- steps: 'Steps',
850
- floors: 'Floors',
851
- },
852
- exerciseType: 'weight_reps',
853
- })).toBe('110.23 lbs x 12');
854
- });
855
- it('formats floors with duration', () => {
856
- expect((0, utils_1.formatSetValue)(Object.assign(Object.assign({}, baseParams), { exerciseType: 'floors_duration' }))).toBe('15 Floors - 1min 30s');
857
- });
858
- it('formats steps with duration', () => {
859
- expect((0, utils_1.formatSetValue)(Object.assign(Object.assign({}, baseParams), { exerciseType: 'steps_duration' }))).toBe('15 Steps - 1min 30s');
860
- });
861
- });
862
- describe('distance', () => {
863
- it('converts meters to kilometers and rounds to two decimals', () => {
864
- expect((0, utils_1.distance)(1555, 'kilometers')).toBe(1.56);
865
- });
866
- it('converts meters to miles and rounds to two decimals', () => {
867
- expect((0, utils_1.distance)(1000, 'miles')).toBe(0.62);
868
- });
869
- });
870
- describe('exerciseWeight', () => {
871
- it('returns rounded kg values for metric units', () => {
872
- expect((0, utils_1.exerciseWeight)(10.555, 'kg')).toBe(10.56);
873
- });
874
- it('converts kg to lbs and rounds to two decimals', () => {
875
- expect((0, utils_1.exerciseWeight)(100, 'lbs')).toBe(220.46);
876
- });
877
- it('rounds lbs values to two decimals', () => {
878
- expect((0, utils_1.exerciseWeight)(4.535, 'lbs')).toBe(10.0);
879
- });
880
- });
881
133
  });