@odoo/o-spreadsheet 14.0.0 → 14.0.1

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 (198) hide show
  1. package/.eslintrc.json +20 -0
  2. package/.husky/post-checkout +9 -0
  3. package/.husky/pre-commit +39 -0
  4. package/.prettierignore +1 -0
  5. package/astToFormula.patch +0 -0
  6. package/demo/data.js +255 -0
  7. package/demo/index.html +9 -0
  8. package/demo/libs/Chart.bundle.js +20755 -0
  9. package/demo/main.js +101 -0
  10. package/doc/readme.md +46 -0
  11. package/package.json +3 -17
  12. package/rollup.config.js +23 -0
  13. package/src/base_plugin.ts +102 -0
  14. package/src/components/autofill.ts +146 -0
  15. package/src/components/bottom_bar.ts +199 -0
  16. package/src/components/color_picker.ts +150 -0
  17. package/src/components/composer/autocomplete_dropdown.ts +135 -0
  18. package/src/components/composer/composer.ts +487 -0
  19. package/src/components/composer/content_editable_helper.ts +146 -0
  20. package/src/components/figures/chart.ts +70 -0
  21. package/src/components/figures/container.ts +268 -0
  22. package/src/components/figures/text_figure.ts +36 -0
  23. package/src/components/grid.ts +635 -0
  24. package/src/components/helpers/dom_helpers.ts +7 -0
  25. package/src/components/helpers/drag_and_drop.ts +17 -0
  26. package/src/components/icons.ts +36 -0
  27. package/src/components/index.ts +1 -0
  28. package/src/components/menu.ts +288 -0
  29. package/src/components/overlay.ts +457 -0
  30. package/src/components/scrollbar.ts +22 -0
  31. package/src/components/selection_input.ts +168 -0
  32. package/src/components/side_panel/cell_is_rule_editor.ts +169 -0
  33. package/src/components/side_panel/chart_panel.ts +104 -0
  34. package/src/components/side_panel/color_scale_rule_editor.ts +145 -0
  35. package/src/components/side_panel/conditional_formatting.ts +396 -0
  36. package/src/components/side_panel/side_panel.ts +127 -0
  37. package/src/components/side_panel/translations_terms.ts +45 -0
  38. package/src/components/spreadsheet.ts +198 -0
  39. package/src/components/top_bar.ts +535 -0
  40. package/src/constants.ts +26 -0
  41. package/src/data.ts +149 -0
  42. package/src/fonts.ts +41 -0
  43. package/src/formulas/compiler.ts +258 -0
  44. package/src/formulas/composer_tokenizer.ts +70 -0
  45. package/src/formulas/index.ts +15 -0
  46. package/src/formulas/normalize.ts +52 -0
  47. package/src/formulas/parser.ts +280 -0
  48. package/src/formulas/range_tokenizer.ts +97 -0
  49. package/src/formulas/tokenizer.ts +242 -0
  50. package/src/functions/arguments.ts +114 -0
  51. package/src/functions/dates.ts +302 -0
  52. package/src/functions/helpers.ts +592 -0
  53. package/src/functions/index.ts +52 -0
  54. package/src/functions/module_database.ts +282 -0
  55. package/src/functions/module_date.ts +743 -0
  56. package/src/functions/module_info.ts +69 -0
  57. package/src/functions/module_logical.ts +208 -0
  58. package/src/functions/module_lookup.ts +185 -0
  59. package/src/functions/module_math.ts +1252 -0
  60. package/src/functions/module_operators.ts +291 -0
  61. package/src/functions/module_statistical.ts +882 -0
  62. package/src/functions/module_text.ts +370 -0
  63. package/src/helpers/color.ts +30 -0
  64. package/src/helpers/coordinates.ts +71 -0
  65. package/src/helpers/grid_manipulation.ts +68 -0
  66. package/src/helpers/index.ts +7 -0
  67. package/src/helpers/misc.ts +76 -0
  68. package/src/helpers/numbers.ts +117 -0
  69. package/src/helpers/uuid.ts +19 -0
  70. package/src/helpers/zones.ts +263 -0
  71. package/src/history.ts +186 -0
  72. package/src/index.ts +84 -0
  73. package/src/model.ts +261 -0
  74. package/src/plugins/autofill.ts +412 -0
  75. package/src/plugins/chart.ts +404 -0
  76. package/src/plugins/clipboard.ts +461 -0
  77. package/src/plugins/conditional_format.ts +445 -0
  78. package/src/plugins/core.ts +1502 -0
  79. package/src/plugins/edition.ts +157 -0
  80. package/src/plugins/evaluation.ts +428 -0
  81. package/src/plugins/figures.ts +123 -0
  82. package/src/plugins/formatting.ts +630 -0
  83. package/src/plugins/highlight.ts +187 -0
  84. package/src/plugins/index.ts +32 -0
  85. package/src/plugins/merge.ts +524 -0
  86. package/src/plugins/renderer.ts +571 -0
  87. package/src/plugins/selection.ts +562 -0
  88. package/src/plugins/selection_inputs.ts +326 -0
  89. package/src/registries/autofill_modifiers.ts +76 -0
  90. package/src/registries/autofill_rules.ts +98 -0
  91. package/src/registries/figure_registry.ts +30 -0
  92. package/src/registries/index.ts +7 -0
  93. package/src/registries/menu_items_registry.ts +110 -0
  94. package/src/registries/menus/cell_menu_registry.ts +79 -0
  95. package/src/registries/menus/col_menu_registry.ts +63 -0
  96. package/src/registries/menus/index.ts +6 -0
  97. package/src/registries/menus/menu_items_actions.ts +425 -0
  98. package/src/registries/menus/row_menu_registry.ts +63 -0
  99. package/src/registries/menus/sheet_menu_registry.ts +75 -0
  100. package/src/registries/menus/topbar_menu_registry.ts +204 -0
  101. package/src/registries/side_panel_registry.ts +26 -0
  102. package/src/registries/topbar_component_registry.ts +12 -0
  103. package/src/registry.ts +51 -0
  104. package/src/translation.ts +44 -0
  105. package/src/types/autofill.ts +48 -0
  106. package/src/types/chart.ts +26 -0
  107. package/src/types/commands.ts +716 -0
  108. package/src/types/conditional_formatting.ts +124 -0
  109. package/src/types/env.ts +13 -0
  110. package/src/types/functions.ts +35 -0
  111. package/src/types/getters.ts +103 -0
  112. package/src/types/index.ts +20 -0
  113. package/src/types/misc.ts +143 -0
  114. package/src/types/rendering.ts +41 -0
  115. package/src/types/workbook_data.ts +62 -0
  116. package/tests/__mocks__/uuid.ts +7 -0
  117. package/tests/canvas.mock.ts +34 -0
  118. package/tests/components/__mocks__/content_editable_helper.ts +79 -0
  119. package/tests/components/__mocks__/scrollbar.ts +18 -0
  120. package/tests/components/__snapshots__/autocomplete_dropdown_test.ts.snap +29 -0
  121. package/tests/components/__snapshots__/bottom_bar_test.ts.snap +75 -0
  122. package/tests/components/__snapshots__/context_menu_test.ts.snap +88 -0
  123. package/tests/components/__snapshots__/grid_test.ts.snap +60 -0
  124. package/tests/components/__snapshots__/spreadsheet_test.ts.snap +455 -0
  125. package/tests/components/__snapshots__/top_bar_test.ts.snap +705 -0
  126. package/tests/components/autocomplete_dropdown_test.ts +315 -0
  127. package/tests/components/autofill_test.ts +167 -0
  128. package/tests/components/bottom_bar_test.ts +262 -0
  129. package/tests/components/chart_side_panel_test.ts +123 -0
  130. package/tests/components/composer_test.ts +400 -0
  131. package/tests/components/context_menu_test.ts +825 -0
  132. package/tests/components/grid_manipulation_test.ts +163 -0
  133. package/tests/components/grid_test.ts +581 -0
  134. package/tests/components/overlay_test.ts +541 -0
  135. package/tests/components/selection_input_test.ts +259 -0
  136. package/tests/components/side_panel_test.ts +148 -0
  137. package/tests/components/spreadsheet_test.ts +194 -0
  138. package/tests/components/top_bar_test.ts +427 -0
  139. package/tests/data_test.ts +175 -0
  140. package/tests/dom_helper.ts +42 -0
  141. package/tests/formulas/__snapshots__/compiler_test.ts.snap +302 -0
  142. package/tests/formulas/compiler_test.ts +266 -0
  143. package/tests/formulas/composer_tokenizer_test.ts +137 -0
  144. package/tests/formulas/expressions_test.ts +57 -0
  145. package/tests/formulas/formulas_test.ts +80 -0
  146. package/tests/formulas/normalize_test.ts +82 -0
  147. package/tests/formulas/parser_test.ts +224 -0
  148. package/tests/formulas/range_tokenizer_test.ts +187 -0
  149. package/tests/formulas/tokenizer_test.ts +164 -0
  150. package/tests/functions/arguments_test.ts +141 -0
  151. package/tests/functions/dates_test.ts +1081 -0
  152. package/tests/functions/functions_test.ts +53 -0
  153. package/tests/functions/helper_test.ts +98 -0
  154. package/tests/functions/module_database_test.ts +311 -0
  155. package/tests/functions/module_date_test.ts +941 -0
  156. package/tests/functions/module_info_test.ts +139 -0
  157. package/tests/functions/module_logical_test.ts +369 -0
  158. package/tests/functions/module_lookup_test.ts +541 -0
  159. package/tests/functions/module_math_test.ts +2482 -0
  160. package/tests/functions/module_operators_test.ts +955 -0
  161. package/tests/functions/module_statistical_test.ts +2014 -0
  162. package/tests/functions/module_text_test.ts +667 -0
  163. package/tests/helpers/coordinates_test.ts +25 -0
  164. package/tests/helpers/misc_test.ts +95 -0
  165. package/tests/helpers/numbers_test.ts +196 -0
  166. package/tests/helpers/zones_test.ts +97 -0
  167. package/tests/helpers.ts +384 -0
  168. package/tests/menu_items_registry_test.ts +540 -0
  169. package/tests/model/plugins/__snapshots__/chart_test.ts.snap +90 -0
  170. package/tests/model/plugins/chart_test.ts +562 -0
  171. package/tests/model_test.ts +82 -0
  172. package/tests/plugins/__snapshots__/conditional_formatting_test.ts.snap +131 -0
  173. package/tests/plugins/__snapshots__/renderer_test.ts.snap +371 -0
  174. package/tests/plugins/autofill_test.ts +457 -0
  175. package/tests/plugins/borders_test.ts +295 -0
  176. package/tests/plugins/clipboard_test.ts +1180 -0
  177. package/tests/plugins/conditional_formatting_test.ts +1253 -0
  178. package/tests/plugins/core_test.ts +614 -0
  179. package/tests/plugins/edition_test.ts +100 -0
  180. package/tests/plugins/evaluation_async_test.ts +332 -0
  181. package/tests/plugins/evaluation_dates_test.ts +79 -0
  182. package/tests/plugins/evaluation_test.ts +901 -0
  183. package/tests/plugins/figures_test.ts +327 -0
  184. package/tests/plugins/formatting_test.ts +391 -0
  185. package/tests/plugins/grid_manipulation_test.ts +1366 -0
  186. package/tests/plugins/highlight_test.ts +413 -0
  187. package/tests/plugins/history_test.ts +142 -0
  188. package/tests/plugins/import_export_test.ts +276 -0
  189. package/tests/plugins/merges_test.ts +490 -0
  190. package/tests/plugins/navigation_test.ts +181 -0
  191. package/tests/plugins/plugins/evaluation_test.ts +111 -0
  192. package/tests/plugins/renderer_test.ts +598 -0
  193. package/tests/plugins/resizing_test.ts +152 -0
  194. package/tests/plugins/selection_input_test.ts +409 -0
  195. package/tests/plugins/selection_test.ts +442 -0
  196. package/tests/plugins/sheets_test.ts +643 -0
  197. package/tests/plugins/style_test.ts +90 -0
  198. package/tsconfig.json +22 -0
@@ -0,0 +1,941 @@
1
+ import { parseDateTime } from "../../src/functions/dates";
2
+ import { evaluateCell, evaluateGrid } from "../helpers";
3
+
4
+ describe("date", () => {
5
+ //----------------------------------------------------------------------------
6
+ // DATE
7
+ //----------------------------------------------------------------------------
8
+
9
+ test("DATE: functional tests on cell arguments CHECK TIMEZONE IF FAILS", () => {
10
+ // prettier-ignore
11
+ const grid = {
12
+ // YEAR / MONTH / DAY
13
+ A2: "=DATE(B2 , C2 , D2 )",
14
+ A3: "=DATE(B3 , C3 , D3 )", C3: "1" , D3: "1",
15
+ A4: "=DATE(B4 , C4 , D4 )", B4: "2028" , C4: "12" , D4: "5",
16
+ // calculate numeric dates which fall outside of valid month or day ranges.
17
+ A6: "=DATE(B6 , C6 , D6 )", B6: "2028" , C6: "13" , D6: "5" ,
18
+ A7: "=DATE(B7 , C7 , D7 )", B7: "2028" , C7: "5" , D7: "87",
19
+ A8: "=DATE(B8 , C8 , D8 )", B8: "2028" , C8: "12" , D8: "5" ,
20
+ // truncate decimal values input into the function.
21
+ A10: "=DATE(B10, C10, D10)", B10: "2028" , C10: "12.9", D10: "5" ,
22
+ A11: "=DATE(B11, C11, D11)", B11: "2028" , C11: "12.9", D11: "5.6",
23
+ A12: "=DATE(B12, C12, D12)", B12: "2028.5", C12: "12.9", D12: "5.6",
24
+ // Between 0 and 1899, add value to 1900 to calculate the year.
25
+ A14: "=DATE(B14, C14, D14)", B14: "119" , C14: "12" , D14: "5",
26
+ A15: "=DATE(B15, C15, D15)", B15: "19" , C15: "12" , D15: "5",
27
+ A16: "=DATE(B16, C16, D16)", B16: "1850" , C16: "12" , D16: "5",
28
+ A17: "=DATE(B17, C17, D17)", B17: "1899" , C17: "12" , D17: "5",
29
+ A18: "=DATE(B18, C18, D18)", B18: "1900" , C18: "12" , D18: "5",
30
+ A19: "=DATE(B19, C19, D19)", B19: "12" ,
31
+ A20: "=DATE(B20, C20, D20)", B20: "1900" , C20: "-24" , D20: "5",
32
+ A21: "=DATE(B21, C21, D21)", B21: "2000" , C21: "-22" , D21: "5",
33
+ A22: "=DATE(B22, C22, D22)", B22: "1899" , C22: "-22" , D22: "5",
34
+ // For years less than 0 or greater than 10,000 return the #ERROR.
35
+ A24: "=DATE(B24, C24, D24)", B24: "-2020" , C24: "12" , D24: "5",
36
+ A25: "=DATE(B25, C25, D25)", B25: "9999" , C25: "12" , D25: "5",
37
+ A26: "=DATE(B26, C26, D26)", B26: "10000" , C26: "12" , D26: "5",
38
+ A27: "=DATE(B27, C27, D27)", B27: "-1" , C27: "12" , D27: "5",
39
+ A28: "=DATE(B28, C28, D28)", B28: "0" , C28: "12" , D28: "5",
40
+ A29: "=DATE(B29, C29, D29)", B29: "2000" , C29: "-12" , D29: "-5",
41
+ A30: "=DATE(B30, C30, D30)", B30: "0" , C30: "-12" , D30: "-5",
42
+ };
43
+
44
+ const gridResult = evaluateGrid(grid);
45
+ expect(gridResult.A2).toBe("#ERROR");
46
+ expect(gridResult.A3).toEqual(parseDateTime("1/1/1900"));
47
+ expect(gridResult.A4).toEqual(parseDateTime("12/5/2028"));
48
+ expect(gridResult.A6).toEqual(parseDateTime("1/5/2029"));
49
+ expect(gridResult.A7).toEqual(parseDateTime("7/26/2028"));
50
+ expect(gridResult.A8).toEqual(parseDateTime("12/5/2028"));
51
+ expect(gridResult.A10).toEqual(parseDateTime("12/5/2028"));
52
+ expect(gridResult.A11).toEqual(parseDateTime("12/5/2028"));
53
+ expect(gridResult.A12).toEqual(parseDateTime("12/5/2028"));
54
+ expect(gridResult.A14).toEqual(parseDateTime("12/5/2019"));
55
+ expect(gridResult.A15).toEqual(parseDateTime("12/5/1919"));
56
+ expect(gridResult.A16).toEqual(parseDateTime("12/5/3750"));
57
+ expect(gridResult.A17).toEqual(parseDateTime("12/5/3799"));
58
+ expect(gridResult.A18).toEqual(parseDateTime("12/5/1900"));
59
+ expect(gridResult.A19).toEqual(parseDateTime("11/30/1911"));
60
+ expect(gridResult.A20).toBe("#ERROR");
61
+ expect(gridResult.A21).toEqual(parseDateTime("2/5/1998"));
62
+ expect(gridResult.A22).toEqual(parseDateTime("2/5/3797"));
63
+ expect(gridResult.A24).toBe("#ERROR");
64
+ expect(gridResult.A25).toEqual(parseDateTime("12/5/9999"));
65
+ expect(gridResult.A26).toBe("#ERROR");
66
+ expect(gridResult.A27).toBe("#ERROR");
67
+ expect(gridResult.A28).toEqual(parseDateTime("12/5/1900"));
68
+ expect(gridResult.A29).toEqual(parseDateTime("11/25/1998"));
69
+ expect(gridResult.A30).toBe("#ERROR");
70
+ });
71
+
72
+ test("DATE: casting tests on cell arguments", () => {
73
+ // prettier-ignore
74
+ const grid = {
75
+ A33: "=DATE(B33, C33, D33)", B33: "2028", C33:"12", D33:'="5"' ,
76
+ A34: "=DATE(B34, C34, D34)", B34: "2028", C34:"12", D34:"TRUE" ,
77
+ A35: "=DATE(B35, C35, D35)", B35: "TRUE", C35:"12", D35:"TRUE" ,
78
+ A36: "=DATE(B36, C36, D36)", B36: '="5"', C36:"12", D36:"TRUE" ,
79
+ };
80
+
81
+ const gridResult = evaluateGrid(grid);
82
+ expect(gridResult.A33).toEqual(parseDateTime("12/5/2028"));
83
+ expect(gridResult.A34).toEqual(parseDateTime("12/1/2028"));
84
+ expect(gridResult.A35).toEqual(parseDateTime("12/1/1901"));
85
+ expect(gridResult.A36).toEqual(parseDateTime("12/1/1905"));
86
+ });
87
+
88
+ //----------------------------------------------------------------------------
89
+ // DATEVALUE
90
+ //----------------------------------------------------------------------------
91
+
92
+ test("DATEVALUE: functional tests on simple arguments", () => {
93
+ expect(evaluateCell("A1", { A1: "=DATEVALUE(40931)" })).toBe("#ERROR"); // @compatibility, retrun #VALUE! on Google Sheet
94
+ expect(evaluateCell("A1", { A1: "=DATEVALUE(1/23/2012)" })).toBe("#ERROR"); // @compatibility, retrun #VALUE! on Google Sheet
95
+ expect(evaluateCell("A1", { A1: '=DATEVALUE("1/23/2012")' })).toBe(40931);
96
+ expect(evaluateCell("A1", { A1: '=DATEVALUE("1/23/2012 8:10:30")' })).toBe(40931);
97
+ expect(evaluateCell("A1", { A1: '=DATEVALUE("2012/1/23")' })).toBe(40931);
98
+ expect(evaluateCell("A1", { A1: '=DATEVALUE("2012-1-23")' })).toBe(40931);
99
+ expect(evaluateCell("A1", { A1: '=DATEVALUE("1/23/2012")' })).toBe(40931);
100
+ expect(evaluateCell("A1", { A1: '=DATEVALUE("13/8/1999")' })).toBe("#ERROR"); // @compatibility, retrun #VALUE! on Google Sheet
101
+ });
102
+
103
+ test("DATEVALUE: functional tests on cell arguments", () => {
104
+ expect(evaluateCell("A1", { A1: "=DATEVALUE(A2)", A2: "36380" })).toBe("#ERROR"); // @compatibility, retrun #VALUE! on Google Sheet
105
+ expect(evaluateCell("A1", { A1: "=DATEVALUE(A2)", A2: "8/8/1999" })).toBe("#ERROR"); // @compatibility, retrun 8/8/1999 on Google Sheet
106
+ expect(evaluateCell("A1", { A1: "=DATEVALUE(A2)", A2: "13/8/1999" })).toBe("#ERROR"); // @compatibility, retrun #VALUE! on Google Sheet
107
+ });
108
+
109
+ //----------------------------------------------------------------------------
110
+ // DAY
111
+ //----------------------------------------------------------------------------
112
+
113
+ test("DAY: functional tests on simple arguments", () => {
114
+ expect(evaluateCell("A1", { A1: '=DAY("3/28/2017")' })).toBe(28);
115
+ expect(evaluateCell("A1", { A1: '=DAY("5/31/2012")' })).toBe(31);
116
+ expect(evaluateCell("A1", { A1: '=DAY("41060")' })).toBe(31);
117
+ expect(evaluateCell("A1", { A1: "=DAY(41060)" })).toBe(31);
118
+ });
119
+
120
+ test("DAY: functional tests on cell arguments", () => {
121
+ expect(evaluateCell("A1", { A1: "=DAY(A2)", A2: "5/31/2012" })).toBe(31);
122
+ expect(evaluateCell("A1", { A1: "=DAY(A2)", A2: "41060" })).toBe(31);
123
+ });
124
+
125
+ //----------------------------------------------------------------------------
126
+ // DAYS
127
+ //----------------------------------------------------------------------------
128
+
129
+ test("DAYS: functional tests on simple arguments", () => {
130
+ const grid = {
131
+ A1: '=DAYS("2/13/2015", "2/23/2014")',
132
+ A2: '=DAYS("7/15/2020", "7/16/2016")',
133
+ A3: '=DAYS("2/23/1234", "2/13/1245")',
134
+ A4: '=DAYS("7/17/2016", "7/16/2016")',
135
+ A5: '=DAYS("7/18/2016", "7/16/2016")',
136
+ A6: '=DAYS("7/16/2017", "7/16/2016")',
137
+ A7: '=DAYS("7/16/2020", "7/16/2019")',
138
+ };
139
+ const gridResult = evaluateGrid(grid);
140
+ expect(gridResult.A1).toBe(355);
141
+ expect(gridResult.A2).toBe(1460);
142
+ expect(gridResult.A3).toBe(-4008);
143
+ expect(gridResult.A4).toBe(1);
144
+ expect(gridResult.A5).toBe(2);
145
+ expect(gridResult.A6).toBe(365);
146
+ expect(gridResult.A7).toBe(366);
147
+ });
148
+
149
+ //----------------------------------------------------------------------------
150
+ // EDATE
151
+ //----------------------------------------------------------------------------
152
+
153
+ test("EDATE: functional tests on simple arguments", () => {
154
+ const grid = {
155
+ A1: '=EDATE("7/20/1969", 0)',
156
+ A2: '=EDATE("7/21/1969", 1)',
157
+ A3: '=EDATE("7/22/1969", -2)',
158
+ A4: '=EDATE("7/23/1969", -13)',
159
+ A5: '=EDATE("7/24/1969", 1234)',
160
+ A6: '=EDATE("7/21/1969", 1.9)',
161
+ };
162
+ const gridResult = evaluateGrid(grid);
163
+ expect(gridResult.A1).toEqual(parseDateTime("7/20/1969"));
164
+ expect(gridResult.A2).toEqual(parseDateTime("8/21/1969"));
165
+ expect(gridResult.A3).toEqual(parseDateTime("5/22/1969"));
166
+ expect(gridResult.A4).toEqual(parseDateTime("6/23/1968"));
167
+ expect(gridResult.A5).toEqual(parseDateTime("5/24/2072"));
168
+ expect(gridResult.A6).toEqual(parseDateTime("8/21/1969"));
169
+ });
170
+
171
+ test("EDATE: casting tests on cell arguments", () => {
172
+ const grid = {
173
+ A7: '=EDATE("7/21/1969", "1")',
174
+ A8: '=EDATE("7/21/1969", True)',
175
+ };
176
+ const gridResult = evaluateGrid(grid);
177
+ expect(gridResult.A7).toEqual(parseDateTime("8/21/1969"));
178
+ expect(gridResult.A8).toEqual(parseDateTime("8/21/1969"));
179
+ });
180
+
181
+ //----------------------------------------------------------------------------
182
+ // EOMONTH
183
+ //----------------------------------------------------------------------------
184
+
185
+ test("EOMONTH: functional tests on simple arguments", () => {
186
+ const grid = {
187
+ A1: '=EOMONTH("7/20/2020", 0)',
188
+ A2: '=EOMONTH("7/21/2020", 1)',
189
+ A3: '=EOMONTH("7/22/2020", -2)',
190
+ A4: '=EOMONTH("7/23/2020", -5)',
191
+ A5: '=EOMONTH("7/24/2020", 1234)',
192
+ A6: '=EOMONTH("7/25/2020", 1.9)',
193
+ };
194
+ const gridResult = evaluateGrid(grid);
195
+ expect(gridResult.A1).toEqual(parseDateTime("7/31/2020"));
196
+ expect(gridResult.A2).toEqual(parseDateTime("8/31/2020"));
197
+ expect(gridResult.A3).toEqual(parseDateTime("5/31/2020"));
198
+ expect(gridResult.A4).toEqual(parseDateTime("2/29/2020"));
199
+ expect(gridResult.A5).toEqual(parseDateTime("5/31/2123"));
200
+ expect(gridResult.A6).toEqual(parseDateTime("8/31/2020"));
201
+ });
202
+
203
+ test("EOMONTH: casting tests on cell arguments", () => {
204
+ const grid = {
205
+ A7: '=EOMONTH("7/21/1920", "1")',
206
+ A8: '=EOMONTH("7/21/2020", True)',
207
+ };
208
+ const gridResult = evaluateGrid(grid);
209
+ expect(gridResult.A7).toEqual(parseDateTime("8/31/1920"));
210
+ expect(gridResult.A8).toEqual(parseDateTime("8/31/2020"));
211
+ });
212
+
213
+ //----------------------------------------------------------------------------
214
+ // HOUR
215
+ //----------------------------------------------------------------------------
216
+
217
+ test("HOUR: functional tests on simple arguments", () => {
218
+ expect(evaluateCell("A1", { A1: '=HOUR("11:23:13")' })).toBe(11);
219
+ expect(evaluateCell("A1", { A1: '=HOUR("2020 12 12 23:40:12")' })).toBe(23);
220
+ expect(evaluateCell("A1", { A1: '=HOUR("3:00")' })).toBe(3);
221
+ expect(evaluateCell("A1", { A1: '=HOUR("2015 01 01")' })).toBe(0);
222
+ expect(evaluateCell("A1", { A1: "=HOUR(0.125)" })).toBe(3);
223
+ expect(evaluateCell("A1", { A1: "=HOUR(12345.125)" })).toBe(3);
224
+ });
225
+
226
+ test("HOUR: functional tests on cell arguments", () => {
227
+ expect(evaluateCell("A1", { A1: "=HOUR(A2)", A2: "11:23:13" })).toBe(11);
228
+ expect(evaluateCell("A1", { A1: "=HOUR(A2)", A2: "2020 12 12 23:40:12" })).toBe(23);
229
+ expect(evaluateCell("A1", { A1: "=HOUR(A2)", A2: "0.25" })).toBe(6);
230
+ expect(evaluateCell("A1", { A1: "=HOUR(A2)", A2: "54321.5" })).toBe(12);
231
+ });
232
+
233
+ //----------------------------------------------------------------------------
234
+ // ISOWEEKNUM
235
+ //----------------------------------------------------------------------------
236
+
237
+ test("ISOWEEKNUM: functional tests on cell arguments", () => {
238
+ expect(evaluateCell("A1", { A1: "=ISOWEEKNUM(A2)", A2: "1/1/2016" })).toBe(53);
239
+ expect(evaluateCell("A1", { A1: "=ISOWEEKNUM(A2)", A2: "1/3/2016" })).toBe(53);
240
+ expect(evaluateCell("A1", { A1: "=ISOWEEKNUM(A2)", A2: "1/4/2016" })).toBe(1);
241
+ expect(evaluateCell("A1", { A1: "=ISOWEEKNUM(A2)", A2: "1/1/2017" })).toBe(52);
242
+ expect(evaluateCell("A1", { A1: "=ISOWEEKNUM(A2)", A2: "1/2/2017" })).toBe(1);
243
+ expect(evaluateCell("A1", { A1: "=ISOWEEKNUM(A2)", A2: "1/1/2018" })).toBe(1);
244
+ expect(evaluateCell("A1", { A1: "=ISOWEEKNUM(A2)", A2: "1/7/2018" })).toBe(1);
245
+ expect(evaluateCell("A1", { A1: "=ISOWEEKNUM(A2)", A2: "1/8/2018" })).toBe(2);
246
+ expect(evaluateCell("A1", { A1: "=ISOWEEKNUM(A2)", A2: "1/1/2020" })).toBe(1);
247
+ expect(evaluateCell("A1", { A1: "=ISOWEEKNUM(A2)", A2: "1/5/2020" })).toBe(1);
248
+ expect(evaluateCell("A1", { A1: "=ISOWEEKNUM(A2)", A2: "1/6/2020" })).toBe(2);
249
+ expect(evaluateCell("A1", { A1: "=ISOWEEKNUM(A2)", A2: "1/1/2021" })).toBe(53);
250
+ expect(evaluateCell("A1", { A1: "=ISOWEEKNUM(A2)", A2: "1/3/2021" })).toBe(53);
251
+ expect(evaluateCell("A1", { A1: "=ISOWEEKNUM(A2)", A2: "1/4/2021" })).toBe(1);
252
+ });
253
+
254
+ //----------------------------------------------------------------------------
255
+ // MINUTE
256
+ //----------------------------------------------------------------------------
257
+
258
+ test("MINUTE: functional tests on simple arguments", () => {
259
+ expect(evaluateCell("A1", { A1: '=MINUTE("11:23:13")' })).toBe(23);
260
+ expect(evaluateCell("A1", { A1: '=MINUTE("2020 12 12 23:40:12")' })).toBe(40);
261
+ expect(evaluateCell("A1", { A1: '=MINUTE("0:21")' })).toBe(21);
262
+ expect(evaluateCell("A1", { A1: '=MINUTE("2015 01 01")' })).toBe(0);
263
+ expect(evaluateCell("A1", { A1: "=MINUTE(0.126)" })).toBe(1);
264
+ expect(evaluateCell("A1", { A1: "=MINUTE(12345.129)" })).toBe(5);
265
+ });
266
+
267
+ test("MINUTE: functional tests on cell arguments", () => {
268
+ expect(evaluateCell("A1", { A1: "=MINUTE(A2)", A2: "11:23:13" })).toBe(23);
269
+ expect(evaluateCell("A1", { A1: "=MINUTE(A2)", A2: "2020 12 12 23:40:12" })).toBe(40);
270
+ expect(evaluateCell("A1", { A1: "=MINUTE(A2)", A2: "0.2532" })).toBe(4);
271
+ expect(evaluateCell("A1", { A1: "=MINUTE(A2)", A2: "54321.789" })).toBe(56);
272
+ });
273
+
274
+ //----------------------------------------------------------------------------
275
+ // MONTH
276
+ //----------------------------------------------------------------------------
277
+
278
+ test("MONTH: functional tests on cell arguments", () => {
279
+ expect(evaluateCell("A1", { A1: "=MONTH(A2)", A2: "1/2/1954" })).toBe(1);
280
+ expect(evaluateCell("A1", { A1: "=MONTH(A2)", A2: "5/13/1954" })).toBe(5);
281
+ expect(evaluateCell("A1", { A1: "=MONTH(A2)", A2: "43964" })).toBe(5); // 43964 corespond to 5/13/195
282
+ expect(evaluateCell("A1", { A1: "=MONTH(A2)", A2: "0" })).toBe(12); // 0 corespond to 12/30/1899
283
+ expect(evaluateCell("A1", { A1: "=MONTH(A2)", A2: "1" })).toBe(12); // 1 corespond to 12/31/1899
284
+ expect(evaluateCell("A1", { A1: "=MONTH(A2)", A2: "2" })).toBe(1); // 2 corespond to 1/1/1900
285
+ expect(evaluateCell("A1", { A1: "=MONTH(A2)", A2: '="43964"' })).toBe(5);
286
+ expect(evaluateCell("A1", { A1: "=MONTH(A2)", A2: "TRUE" })).toBe(12);
287
+ });
288
+
289
+ //----------------------------------------------------------------------------
290
+ // NETWORKDAYS
291
+ //----------------------------------------------------------------------------
292
+
293
+ test("NETWORKDAYS: functional tests on cell arguments", () => {
294
+ // prettier-ignore
295
+ const grid = {
296
+ A1: "1/1/2013", A2: "1/21/2013", A3: "2/18/2013", A4: "5/27/2013",
297
+ A5: "1/21/2013", A6: "1/12/2013", A7: "Hello there", A8: "1/1/2015",
298
+
299
+ A15: "1/1/2013", B15: "2/1/2013", C15: "=NETWORKDAYS(A15,B15)",
300
+ A16: "1/1/2013", B16: "2/1/2013", C16: "=NETWORKDAYS(A16,B16,A1:A5)",
301
+ A17: "3/1/2013", B17: "7/1/2013", C17: '=NETWORKDAYS("3/1/2013","7/1/2013",A1:A5)',
302
+ A18: "2/1/2013", B18: "1/1/2013", C18: "=NETWORKDAYS(A18,B18)",
303
+ A19: "1/1/2013", B19: "1/2/2013", C19: "=NETWORKDAYS(A19,B19)",
304
+ A20: "1/1/2013", B20: "2/1/2013", C20: "=NETWORKDAYS(A20,B20,A1)",
305
+ A21: "1/1/2013", B21: "2/1/2013", C21: "=NETWORKDAYS(A21,B21,A1,A2)",
306
+ A22: "1/1/2013", B22: "2/1/2013", C22: "=NETWORKDAYS(A22,B22,A6:A7)",
307
+ A23: "1/1/2013", B23: "2/1/2013", C23: "=NETWORKDAYS(A23,B23,A6)",
308
+ A24: "1/1/2013", B24: "2/1/2013", C24: "=NETWORKDAYS(A24,B24,A8)",
309
+ };
310
+ const gridResult = evaluateGrid(grid);
311
+
312
+ expect(gridResult.C15).toBe(24);
313
+ expect(gridResult.C16).toBe(22);
314
+ expect(gridResult.C17).toBe(86);
315
+ expect(gridResult.C18).toBe(-24);
316
+ expect(gridResult.C19).toBe(2);
317
+ expect(gridResult.C20).toBe(23);
318
+ expect(gridResult.C21).toBe("#BAD_EXPR"); // @compatibility on Google Sheets, return #N/A
319
+ expect(gridResult.C22).toBe("#ERROR"); // @compatibility on Google Sheets, return #VALUE!
320
+ expect(gridResult.C23).toBe(24);
321
+ expect(gridResult.C24).toBe(24);
322
+ });
323
+
324
+ //----------------------------------------------------------------------------
325
+ // NETWORKDAYS.INTL
326
+ //----------------------------------------------------------------------------
327
+ test("NETWORKDAYS.INTL: functional tests on cell arguments, string method", () => {
328
+ // prettier-ignore
329
+ const grid = {
330
+ B2: "5/4/2020", C2: "5/17/2020", D2: "=NETWORKDAYS.INTL(B2, C2)",
331
+ B3: "5/4/2020", C3: "5/17/2020", D3: '=NETWORKDAYS.INTL(B3, C3, "0")',
332
+ B4: "5/4/2020", C4: "5/17/2020", D4: '=NETWORKDAYS.INTL(B4, C4, "00")',
333
+ B5: "5/4/2020", C5: "5/17/2020", D5: '=NETWORKDAYS.INTL(B5, C5, "000000")',
334
+ B6: "5/4/2020", C6: "5/17/2020", D6: '=NETWORKDAYS.INTL(B6, C6, "0000000")',
335
+ B7: "5/4/2020", C7: "5/17/2020", D7: '=NETWORKDAYS.INTL(B7, C7, "0000011")',
336
+ B8: "5/4/2020", C8: "5/17/2020", D8: '=NETWORKDAYS.INTL(B8, C8, "0000111")',
337
+ B9: "5/4/2020", C9: "5/17/2020", D9: '=NETWORKDAYS.INTL(B9, C9, "1000111")',
338
+ B10: "5/4/2020", C10: "5/17/2020", D10: '=NETWORKDAYS.INTL(B10, C10, "1110111")',
339
+ B11: "5/4/2020", C11: "5/17/2020", D11: '=NETWORKDAYS.INTL(B11, C11, "1111111")',
340
+ B12: "5/4/2020", C12: "5/17/2020", D12: '=NETWORKDAYS.INTL(B12, C12, "1000211")',
341
+ C13: "5/17/2020", D13: '=NETWORKDAYS.INTL(B13, C13, "0000000")',
342
+ B14: "5/4/2020", D14: '=NETWORKDAYS.INTL(B14, C14, "0000000")',
343
+
344
+ B75: "5/4/2020", C75: "5/17/2020", D75: '=NETWORKDAYS.INTL(B75, C75, "0000000")',
345
+ B76: "5/4/2020", C76: "5/8/2020" , D76: '=NETWORKDAYS.INTL(B76, C76, "0000011")',
346
+ B77: "5/9/2020", C77: "5/10/2020", D77: '=NETWORKDAYS.INTL(B77, C77, "0000011")',
347
+ B78: "5/4/2020", C78: "5/8/2020" , D78: '=NETWORKDAYS.INTL(B78, C78, "0000111")',
348
+ B79: "5/8/2020", C79: "5/10/2020", D79: '=NETWORKDAYS.INTL(B79, C79, "0000111")',
349
+ B80: "5/5/2020", C80: "5/7/2020" , D80: '=NETWORKDAYS.INTL(B80, C80, "1000111")',
350
+ B81: "5/8/2020", C81: "5/11/2020", D81: '=NETWORKDAYS.INTL(B81, C81, "1000111")',
351
+ B82: "5/7/2020", C82: "5/7/2020" , D82: '=NETWORKDAYS.INTL(B82, C82, "1110111")',
352
+ B83: "5/8/2020", C83: "5/12/2020", D83: '=NETWORKDAYS.INTL(B83, C83, "1110111")',
353
+
354
+ };
355
+ const gridResult = evaluateGrid(grid);
356
+ expect(gridResult.D2).toBe(10);
357
+ expect(gridResult.D3).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
358
+ expect(gridResult.D4).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
359
+ expect(gridResult.D5).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
360
+ expect(gridResult.D6).toBe(14);
361
+ expect(gridResult.D7).toBe(10);
362
+ expect(gridResult.D8).toBe(8);
363
+ expect(gridResult.D9).toBe(6);
364
+ expect(gridResult.D10).toBe(2);
365
+ expect(gridResult.D11).toBe(0); // @compatibility on Google Sheets, return #NUM!
366
+ expect(gridResult.D12).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
367
+ // To do:
368
+ //expect(gridResult.D13).toBe(43969);
369
+ //expect(gridResult.D14).toBe(-43956);
370
+
371
+ expect(gridResult.D75).toBe(14);
372
+ expect(gridResult.D76).toBe(5);
373
+ expect(gridResult.D77).toBe(0);
374
+ expect(gridResult.D78).toBe(4);
375
+ expect(gridResult.D79).toBe(0);
376
+ expect(gridResult.D80).toBe(3);
377
+ expect(gridResult.D81).toBe(0);
378
+ expect(gridResult.D82).toBe(1);
379
+ expect(gridResult.D83).toBe(0);
380
+ });
381
+
382
+ test("NETWORKDAYS.INTL: functional tests on cell arguments, number method", () => {
383
+ // prettier-ignore
384
+ const grid = {
385
+ B18: "5/4/2020", C18: "5/17/2020", D18: '=NETWORKDAYS.INTL(B18, C18, 0)',
386
+ B19: "5/9/2020", C19: "5/10/2020", D19: '=NETWORKDAYS.INTL(B19, C19, 1)',
387
+ B20: "5/10/2020", C20: "5/11/2020", D20: '=NETWORKDAYS.INTL(B20, C20, 1)',
388
+ B21: "5/10/2020", C21: "5/11/2020", D21: '=NETWORKDAYS.INTL(B21, C21, 2)',
389
+ B22: "5/11/2020", C22: "5/12/2020", D22: '=NETWORKDAYS.INTL(B22, C22, 2)',
390
+ B23: "5/11/2020", C23: "5/12/2020", D23: '=NETWORKDAYS.INTL(B23, C23, 3)',
391
+ B24: "5/12/2020", C24: "5/13/2020", D24: '=NETWORKDAYS.INTL(B24, C24, 3)',
392
+ B25: "5/12/2020", C25: "5/13/2020", D25: '=NETWORKDAYS.INTL(B25, C25, 4)',
393
+ B26: "5/13/2020", C26: "5/14/2020", D26: '=NETWORKDAYS.INTL(B26, C26, 4)',
394
+ B27: "5/13/2020", C27: "5/14/2020", D27: '=NETWORKDAYS.INTL(B27, C27, 5)',
395
+ B28: "5/14/2020", C28: "5/15/2020", D28: '=NETWORKDAYS.INTL(B28, C28, 5)',
396
+ B29: "5/14/2020", C29: "5/15/2020", D29: '=NETWORKDAYS.INTL(B29, C29, 6)',
397
+ B30: "5/15/2020", C30: "5/16/2020", D30: '=NETWORKDAYS.INTL(B30, C30, 6)',
398
+ B31: "5/15/2020", C31: "5/16/2020", D31: '=NETWORKDAYS.INTL(B31, C31, 7)',
399
+ B32: "5/16/2020", C32: "5/17/2020", D32: '=NETWORKDAYS.INTL(B32, C32, 7)',
400
+ B33: "5/16/2020", C33: "5/17/2020", D33: '=NETWORKDAYS.INTL(B33, C33, 8)',
401
+
402
+ B39: "5/4/2020", C39: "5/17/2020", D39: '=NETWORKDAYS.INTL(B39, C39, 10)',
403
+ B40: "5/9/2020", C40: "5/9/2020" , D40: '=NETWORKDAYS.INTL(B40, C40, 11)',
404
+ B41: "5/10/2020", C41: "5/10/2020", D41: '=NETWORKDAYS.INTL(B41, C41, 11)',
405
+ B42: "5/10/2020", C42: "5/10/2020", D42: '=NETWORKDAYS.INTL(B42, C42, 12)',
406
+ B43: "5/11/2020", C43: "5/11/2020", D43: '=NETWORKDAYS.INTL(B43, C43, 12)',
407
+ B44: "5/11/2020", C44: "5/11/2020", D44: '=NETWORKDAYS.INTL(B44, C44, 13)',
408
+ B45: "5/12/2020", C45: "5/12/2020", D45: '=NETWORKDAYS.INTL(B45, C45, 13)',
409
+ B46: "5/12/2020", C46: "5/12/2020", D46: '=NETWORKDAYS.INTL(B46, C46, 14)',
410
+ B47: "5/13/2020", C47: "5/13/2020", D47: '=NETWORKDAYS.INTL(B47, C47, 14)',
411
+ B48: "5/13/2020", C48: "5/13/2020", D48: '=NETWORKDAYS.INTL(B48, C48, 15)',
412
+ B49: "5/14/2020", C49: "5/14/2020", D49: '=NETWORKDAYS.INTL(B49, C49, 15)',
413
+ B50: "5/14/2020", C50: "5/14/2020", D50: '=NETWORKDAYS.INTL(B50, C50, 16)',
414
+ B51: "5/15/2020", C51: "5/15/2020", D51: '=NETWORKDAYS.INTL(B51, C51, 16)',
415
+ B52: "5/15/2020", C52: "5/15/2020", D52: '=NETWORKDAYS.INTL(B52, C52, 17)',
416
+ B53: "5/16/2020", C53: "5/16/2020", D53: '=NETWORKDAYS.INTL(B53, C53, 17)',
417
+ B54: "5/16/2020", C54: "5/16/2020", D54: '=NETWORKDAYS.INTL(B54, C54, 18)',
418
+ };
419
+ const gridResult = evaluateGrid(grid);
420
+ expect(gridResult.D18).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
421
+ expect(gridResult.D19).toBe(0);
422
+ expect(gridResult.D20).toBe(1);
423
+ expect(gridResult.D21).toBe(0);
424
+ expect(gridResult.D22).toBe(1);
425
+ expect(gridResult.D23).toBe(0);
426
+ expect(gridResult.D24).toBe(1);
427
+ expect(gridResult.D25).toBe(0);
428
+ expect(gridResult.D26).toBe(1);
429
+ expect(gridResult.D27).toBe(0);
430
+ expect(gridResult.D28).toBe(1);
431
+ expect(gridResult.D29).toBe(0);
432
+ expect(gridResult.D30).toBe(1);
433
+ expect(gridResult.D31).toBe(0);
434
+ expect(gridResult.D32).toBe(1);
435
+ expect(gridResult.D33).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
436
+
437
+ expect(gridResult.D39).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
438
+ expect(gridResult.D40).toBe(1);
439
+ expect(gridResult.D41).toBe(0);
440
+ expect(gridResult.D42).toBe(1);
441
+ expect(gridResult.D43).toBe(0);
442
+ expect(gridResult.D44).toBe(1);
443
+ expect(gridResult.D45).toBe(0);
444
+ expect(gridResult.D46).toBe(1);
445
+ expect(gridResult.D47).toBe(0);
446
+ expect(gridResult.D48).toBe(1);
447
+ expect(gridResult.D49).toBe(0);
448
+ expect(gridResult.D50).toBe(1);
449
+ expect(gridResult.D51).toBe(0);
450
+ expect(gridResult.D52).toBe(1);
451
+ expect(gridResult.D53).toBe(0);
452
+ expect(gridResult.D54).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
453
+ });
454
+
455
+ test("NETWORKDAYS.INTL: casting tests on cell arguments", () => {
456
+ // prettier-ignore
457
+ const grid = {
458
+ B68: "5/4/2020", C68: "5/17/2020", D68: '=NETWORKDAYS.INTL(B68, C68, 1110111)',
459
+ B69: "5/5/2020", C69: "5/18/2020", D69: '=NETWORKDAYS.INTL(B69, C69, "test")',
460
+ B70: "5/11/2020", C70: "5/12/2020", D70: '=NETWORKDAYS.INTL(B70, C70, "2")',
461
+ B71: "5/11/2020", C71: "5/12/2020", D71: '=NETWORKDAYS.INTL(B71, C71, A71)',
462
+ B72: "5/11/2020", C72: "5/17/2020", D72: '=NETWORKDAYS.INTL(B72, C72)',
463
+ };
464
+ const gridResult = evaluateGrid(grid);
465
+ expect(gridResult.D68).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
466
+ expect(gridResult.D69).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
467
+ expect(gridResult.D70).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
468
+ expect(gridResult.D71).toBe("#ERROR"); // @compatibility on Google Sheets, return #VALUE!
469
+ expect(gridResult.D72).toBe(5);
470
+ });
471
+
472
+ //----------------------------------------------------------------------------
473
+ // NOW
474
+ //----------------------------------------------------------------------------
475
+
476
+ const MockDate = require("mockdate");
477
+
478
+ test("NOW: functional tests on simple arguments", async () => {
479
+ MockDate.set(new Date(2042, 3, 2, 4, 7, 30, 999));
480
+ const now = evaluateCell("A1", { A1: "=NOW()" });
481
+ expect(now.value).toBe(51958.171875);
482
+ expect(now.format).toBe("m/d/yyyy hh:mm:ss");
483
+ expect(now.jsDate.getTime()).toBe(new Date(2042, 3, 2, 4, 7, 30).getTime());
484
+ MockDate.reset();
485
+ });
486
+
487
+ //----------------------------------------------------------------------------
488
+ // SECOND
489
+ //----------------------------------------------------------------------------
490
+
491
+ test("SECOND: functional tests on simple arguments", () => {
492
+ expect(evaluateCell("A1", { A1: '=SECOND("11:23:13")' })).toBe(13);
493
+ expect(evaluateCell("A1", { A1: '=SECOND("2020 12 12 23:40:12")' })).toBe(12);
494
+ expect(evaluateCell("A1", { A1: '=SECOND("0:21:42")' })).toBe(42);
495
+ expect(evaluateCell("A1", { A1: '=SECOND("2015 01 01")' })).toBe(0);
496
+ expect(evaluateCell("A1", { A1: "=SECOND(0.126)" })).toBe(26);
497
+ expect(evaluateCell("A1", { A1: "=SECOND(12345.129)" })).toBe(46);
498
+ });
499
+
500
+ test("SECOND: functional tests on cell arguments", () => {
501
+ expect(evaluateCell("A1", { A1: "=SECOND(A2)", A2: "11:23:13" })).toBe(13);
502
+ expect(evaluateCell("A1", { A1: "=SECOND(A2)", A2: "2020 12 12 23:40:12" })).toBe(12);
503
+ expect(evaluateCell("A1", { A1: "=SECOND(A2)", A2: "0.2532" })).toBe(36);
504
+ expect(evaluateCell("A1", { A1: "=SECOND(A2)", A2: "54321.789" })).toBe(10);
505
+ });
506
+
507
+ //----------------------------------------------------------------------------
508
+ // TIME
509
+ //----------------------------------------------------------------------------
510
+ test("TIME: functional tests on cell arguments", () => {
511
+ // prettier-ignore
512
+ const grid = {
513
+ A1: "=TIME(B1, C1, D1 )", B1: "9", C1: "11", D1: "31",
514
+ A2: "=TIME(B2, C2, D2 )", B2: "14", C2: "59", D2: "59",
515
+ A3: "=TIME(B3, C3, D3 )", B3: "26", C3: "0", D3: "0",
516
+ A4: "=TIME(B4, C4, D4 )", B4: "26", C4: "60", D4: "60",
517
+ A5: "=TIME(B5, C5, D5 )", B5: "13", C5: "61", D5: "20",
518
+ A6: "=TIME(B6, C6, D6 )", B6: "16", C6: "49", D6: "62",
519
+ A7: "=TIME(B7, C7, D7 )", B7: "26", C7: "61", D7: "62",
520
+ A8: "=TIME(B8, C8, D8 )", B8: "26", C8: "61", D8: "62",
521
+ A9: "=TIME(B9, C9, D9 )", B9: "14", C9: "59", D9: "-59",
522
+ A10: "=TIME(B10, C10, D10 )", B10: "14", C10: "-5", D10: "-59",
523
+ A11: "=TIME(B11, C11, D11 )", B11: "1", C11: "-61", D11: "-61",
524
+ };
525
+
526
+ const gridResult = evaluateGrid(grid);
527
+ expect(gridResult.A1).toEqual(parseDateTime("9:11:31 AM"));
528
+ expect(gridResult.A2).toEqual(parseDateTime("2:59:59 PM"));
529
+ expect(gridResult.A3).toEqual(parseDateTime("2:00:00 AM"));
530
+ expect(gridResult.A4).toEqual(parseDateTime("3:01:00 AM"));
531
+ expect(gridResult.A5).toEqual(parseDateTime("2:01:20 PM"));
532
+ expect(gridResult.A6).toEqual(parseDateTime("4:50:02 PM"));
533
+ expect(gridResult.A7).toEqual(parseDateTime("3:02:02 AM"));
534
+ expect(gridResult.A8).toEqual(parseDateTime("3:02:02 AM"));
535
+ expect(gridResult.A9).toEqual(parseDateTime("2:58:01 PM"));
536
+ expect(gridResult.A10).toEqual(parseDateTime("1:54:01 PM"));
537
+ expect(gridResult.A11).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
538
+ });
539
+
540
+ //----------------------------------------------------------------------------
541
+ // TIMEVALUE
542
+ //----------------------------------------------------------------------------
543
+
544
+ test("TIMEVALUE: functional tests on simple arguments", () => {
545
+ expect(evaluateCell("A1", { A1: "=TIMEVALUE(40931.5678)" })).toBe("#ERROR"); // @compatibility, retrun #VALUE! on Google Sheet
546
+ expect(evaluateCell("A1", { A1: "=TIMEVALUE(1/23/2012)" })).toBe("#ERROR"); // @compatibility, retrun #VALUE! on Google Sheet
547
+ expect(evaluateCell("A1", { A1: '=TIMEVALUE("1/23/2012")' })).toBe(0);
548
+ expect(evaluateCell("A1", { A1: '=TIMEVALUE("1/23/2012 12:09:00")' })).toBeCloseTo(0.50625, 5);
549
+ expect(evaluateCell("A1", { A1: '=TIMEVALUE("1899 10 08 18:00")' })).toBe(0.75);
550
+ });
551
+
552
+ test("TIMEVALUE: functional tests on cell arguments", () => {
553
+ expect(evaluateCell("A1", { A1: "=TIMEVALUE(A2)", A2: "36380.5678" })).toBe("#ERROR"); // @compatibility, retrun #VALUE! on Google Sheet
554
+ expect(evaluateCell("A1", { A1: "=TIMEVALUE(A2)", A2: "8/8/1999 12:09:00" })).toBe("#ERROR"); // @compatibility, retrun 8/8/1999 on Google Sheet
555
+ });
556
+
557
+ //----------------------------------------------------------------------------
558
+ // TODAY
559
+ //----------------------------------------------------------------------------
560
+
561
+ test("TODAY: functional tests on simple arguments", () => {
562
+ let timeNow = new Date();
563
+ timeNow.setHours(0);
564
+ timeNow.setMinutes(0);
565
+ timeNow.setSeconds(0);
566
+ timeNow.setMilliseconds(0);
567
+
568
+ const today = evaluateCell("A1", { A1: "=TODAY()" });
569
+ expect(today.jsDate.getTime()).toBeGreaterThanOrEqual(timeNow.getTime());
570
+ expect(today.jsDate.getTime()).toBeLessThanOrEqual(new Date().getTime());
571
+
572
+ expect(today.jsDate.getHours()).toBe(0);
573
+ expect(today.jsDate.getMinutes()).toBe(0);
574
+ expect(today.jsDate.getSeconds()).toBe(0);
575
+ expect(today.jsDate.getMilliseconds()).toBe(0);
576
+
577
+ expect(today.value - Math.abs(today.value)).toBe(0);
578
+ });
579
+
580
+ //----------------------------------------------------------------------------
581
+ // WEEKDAY
582
+ //----------------------------------------------------------------------------
583
+
584
+ test("WEEKDAY: functional tests on cell arguments, option 1", () => {
585
+ // prettier-ignore
586
+ const grid = {
587
+ A3: "1/1/2020", B3: "1", C3: "=WEEKDAY(A3,B3)",
588
+ A4: "1/2/2020", B4: "1", C4: "=WEEKDAY(A4,B4)",
589
+ A5: "1/3/2020", B5: "1", C5: "=WEEKDAY(A5,B5)",
590
+ A6: "1/4/2020", B6: "1", C6: "=WEEKDAY(A6,B6)",
591
+ A7: "1/5/2020", B7: "1", C7: "=WEEKDAY(A7,B7)",
592
+ A8: "1/6/2020", B8: "1", C8: "=WEEKDAY(A8,B8)",
593
+ A9: "1/7/2020", B9: "1", C9: "=WEEKDAY(A9,B9)",
594
+ };
595
+ const gridResult = evaluateGrid(grid);
596
+ expect(gridResult.C3).toBe(4);
597
+ expect(gridResult.C4).toBe(5);
598
+ expect(gridResult.C5).toBe(6);
599
+ expect(gridResult.C6).toBe(7);
600
+ expect(gridResult.C7).toBe(1);
601
+ expect(gridResult.C8).toBe(2);
602
+ expect(gridResult.C9).toBe(3);
603
+ });
604
+
605
+ test("WEEKDAY: functional tests on cell arguments, option 2", () => {
606
+ // prettier-ignore
607
+ const grid = {
608
+ A11: "1/1/2020", B11: "2", C11: "=WEEKDAY(A11,B11)",
609
+ A12: "1/2/2020", B12: "2", C12: "=WEEKDAY(A12,B12)",
610
+ A13: "1/3/2020", B13: "2", C13: "=WEEKDAY(A13,B13)",
611
+ A14: "1/4/2020", B14: "2", C14: "=WEEKDAY(A14,B14)",
612
+ A15: "1/5/2020", B15: "2", C15: "=WEEKDAY(A15,B15)",
613
+ A16: "1/6/2020", B16: "2", C16: "=WEEKDAY(A16,B16)",
614
+ A17: "1/7/2020", B17: "2", C17: "=WEEKDAY(A17,B17)",
615
+ };
616
+ const gridResult = evaluateGrid(grid);
617
+ expect(gridResult.C11).toBe(3);
618
+ expect(gridResult.C12).toBe(4);
619
+ expect(gridResult.C13).toBe(5);
620
+ expect(gridResult.C14).toBe(6);
621
+ expect(gridResult.C15).toBe(7);
622
+ expect(gridResult.C16).toBe(1);
623
+ expect(gridResult.C17).toBe(2);
624
+ });
625
+
626
+ test("WEEKDAY: functional tests on cell arguments, option 3", () => {
627
+ // prettier-ignore
628
+ const grid = {
629
+ A19: "1/1/2020", B19: "3", C19: "=WEEKDAY(A19,B19)",
630
+ A20: "1/2/2020", B20: "3", C20: "=WEEKDAY(A20,B20)",
631
+ A21: "1/3/2020", B21: "3", C21: "=WEEKDAY(A21,B21)",
632
+ A22: "1/4/2020", B22: "3", C22: "=WEEKDAY(A22,B22)",
633
+ A23: "1/5/2020", B23: "3", C23: "=WEEKDAY(A23,B23)",
634
+ A24: "1/6/2020", B24: "3", C24: "=WEEKDAY(A24,B24)",
635
+ A25: "1/7/2020", B25: "3", C25: "=WEEKDAY(A25,B25)",
636
+ };
637
+ const gridResult = evaluateGrid(grid);
638
+ expect(gridResult.C19).toBe(2);
639
+ expect(gridResult.C20).toBe(3);
640
+ expect(gridResult.C21).toBe(4);
641
+ expect(gridResult.C22).toBe(5);
642
+ expect(gridResult.C23).toBe(6);
643
+ expect(gridResult.C24).toBe(0);
644
+ expect(gridResult.C25).toBe(1);
645
+ });
646
+
647
+ //----------------------------------------------------------------------------
648
+ // WEEKNUM
649
+ //----------------------------------------------------------------------------
650
+
651
+ test("WEEKNUM: functional tests on cell arguments", () => {
652
+ // prettier-ignore
653
+ const grid = {
654
+ A11: "12/31/2019", B11: "1" , C11: "=WEEKNUM(A11, B11)",
655
+ A12: "1/1/2020" , B12: "1" , C12: "=WEEKNUM(A12, B12)",
656
+ A13: "1/4/2020" , B13: "1" , C13: "=WEEKNUM(A13, B13)",
657
+ A14: "1/5/2020" , B14: "1" , C14: "=WEEKNUM(A14, B14)",
658
+ A15: "12/31/2019", B15: "2" , C15: "=WEEKNUM(A15, B15)",
659
+ A16: "1/1/2020" , B16: "2" , C16: "=WEEKNUM(A16, B16)",
660
+ A17: "1/5/2020" , B17: "2" , C17: "=WEEKNUM(A17, B17)",
661
+ A18: "1/6/2020" , B18: "2" , C18: "=WEEKNUM(A18, B18)",
662
+ A19: "12/31/2019", B19: "11", C19: "=WEEKNUM(A19, B19)",
663
+ A20: "1/1/2020" , B20: "11", C20: "=WEEKNUM(A20, B20)",
664
+ A21: "1/5/2020" , B21: "11", C21: "=WEEKNUM(A21, B21)",
665
+ A22: "1/6/2020" , B22: "11", C22: "=WEEKNUM(A22, B22)",
666
+ A23: "12/31/2019", B23: "12", C23: "=WEEKNUM(A23, B23)",
667
+ A24: "1/1/2020" , B24: "12", C24: "=WEEKNUM(A24, B24)",
668
+ A25: "1/6/2020" , B25: "12", C25: "=WEEKNUM(A25, B25)",
669
+ A26: "1/7/2020" , B26: "12", C26: "=WEEKNUM(A26, B26)",
670
+ A27: "12/31/2019", B27: "13", C27: "=WEEKNUM(A27, B27)",
671
+ A28: "1/1/2020" , B28: "13", C28: "=WEEKNUM(A28, B28)",
672
+ A29: "1/7/2020" , B29: "13", C29: "=WEEKNUM(A29, B29)",
673
+ A30: "1/8/2020" , B30: "13", C30: "=WEEKNUM(A30, B30)",
674
+ A31: "12/31/2019", B31: "14", C31: "=WEEKNUM(A31, B31)",
675
+ A32: "1/1/2020" , B32: "14", C32: "=WEEKNUM(A32, B32)",
676
+ A33: "1/2/2020" , B33: "14", C33: "=WEEKNUM(A33, B33)",
677
+ A34: "12/31/2019", B34: "15", C34: "=WEEKNUM(A34, B34)",
678
+ A35: "1/1/2020" , B35: "15", C35: "=WEEKNUM(A35, B35)",
679
+ A36: "1/2/2020" , B36: "15", C36: "=WEEKNUM(A36, B36)",
680
+ A37: "1/3/2020" , B37: "15", C37: "=WEEKNUM(A37, B37)",
681
+ A38: "12/31/2019", B38: "16", C38: "=WEEKNUM(A38, B38)",
682
+ A39: "1/1/2020" , B39: "16", C39: "=WEEKNUM(A39, B39)",
683
+ A40: "1/3/2020" , B40: "16", C40: "=WEEKNUM(A40, B40)",
684
+ A41: "1/4/2020" , B41: "16", C41: "=WEEKNUM(A41, B41)",
685
+ A42: "12/31/2019", B42: "17", C42: "=WEEKNUM(A42, B42)",
686
+ A43: "1/1/2020" , B43: "17", C43: "=WEEKNUM(A43, B43)",
687
+ A44: "1/4/2020" , B44: "17", C44: "=WEEKNUM(A44, B44)",
688
+ A45: "1/5/2020" , B45: "17", C45: "=WEEKNUM(A45, B45)",
689
+ A46: "12/29/2019", B46: "21", C46: "=WEEKNUM(A46, B46)",
690
+ A47: "12/30/2019", B47: "21", C47: "=WEEKNUM(A47, B47)",
691
+ A48: "12/31/2019", B48: "21", C48: "=WEEKNUM(A48, B48)",
692
+ A49: "1/1/2020" , B49: "21", C49: "=WEEKNUM(A49, B49)",
693
+ A50: "1/5/2020" , B50: "21", C50: "=WEEKNUM(A50, B50)",
694
+ A51: "1/6/2020" , B51: "21", C51: "=WEEKNUM(A51, B51)",
695
+ A52: "1/1/2020" , B52: "18", C52: "=WEEKNUM(A52, B52)",
696
+ A53: "1/1/2020" , B53: "0" , C53: "=WEEKNUM(A53, B53)",
697
+ A54: "1/1/2020" , B54: "10", C54: "=WEEKNUM(A54, B54)",
698
+ };
699
+ const gridResult = evaluateGrid(grid);
700
+
701
+ expect(gridResult.C11).toBe(53);
702
+ expect(gridResult.C12).toBe(1);
703
+ expect(gridResult.C13).toBe(1);
704
+ expect(gridResult.C14).toBe(2);
705
+ expect(gridResult.C15).toBe(53);
706
+ expect(gridResult.C16).toBe(1);
707
+ expect(gridResult.C17).toBe(1);
708
+ expect(gridResult.C18).toBe(2);
709
+ expect(gridResult.C19).toBe(53);
710
+ expect(gridResult.C20).toBe(1);
711
+ expect(gridResult.C21).toBe(1);
712
+ expect(gridResult.C22).toBe(2);
713
+ expect(gridResult.C23).toBe(53);
714
+ expect(gridResult.C24).toBe(1);
715
+ expect(gridResult.C25).toBe(1);
716
+ expect(gridResult.C26).toBe(2);
717
+ expect(gridResult.C27).toBe(53);
718
+ expect(gridResult.C28).toBe(1);
719
+ expect(gridResult.C29).toBe(1);
720
+ expect(gridResult.C30).toBe(2);
721
+ expect(gridResult.C31).toBe(53);
722
+ expect(gridResult.C32).toBe(1);
723
+ expect(gridResult.C33).toBe(2);
724
+ expect(gridResult.C34).toBe(53);
725
+ expect(gridResult.C35).toBe(1);
726
+ expect(gridResult.C36).toBe(1);
727
+ expect(gridResult.C37).toBe(2);
728
+ expect(gridResult.C38).toBe(53);
729
+ expect(gridResult.C39).toBe(1);
730
+ expect(gridResult.C40).toBe(1);
731
+ expect(gridResult.C41).toBe(2);
732
+ expect(gridResult.C42).toBe(53);
733
+ expect(gridResult.C43).toBe(1);
734
+ expect(gridResult.C44).toBe(1);
735
+ expect(gridResult.C45).toBe(2);
736
+ expect(gridResult.C46).toBe(52);
737
+ expect(gridResult.C47).toBe(1);
738
+ expect(gridResult.C48).toBe(1);
739
+ expect(gridResult.C49).toBe(1);
740
+ expect(gridResult.C50).toBe(1);
741
+ expect(gridResult.C51).toBe(2);
742
+ expect(gridResult.C52).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
743
+ expect(gridResult.C53).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
744
+ expect(gridResult.C54).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
745
+ });
746
+
747
+ //----------------------------------------------------------------------------
748
+ // WORKDAY
749
+ //----------------------------------------------------------------------------
750
+
751
+ test("WORKDAY: functional tests on cell arguments", () => {
752
+ // prettier-ignore
753
+ const grid = {
754
+ A1: "1/1/2013" , A2: "1/21/2013", A3: "2/18/2013", A4: "5/27/2013",
755
+ A5: "1/21/2013", A6: "1/12/2013", A7: "1/2/2013" , A8: "12/31/2012",
756
+
757
+ A11: "1/1/2013", B11: "3" , C11: "=WORKDAY(A11, B11)",
758
+ A12: "1/1/2013", B12: "3" , C12: "=WORKDAY(A12, B12, A1)",
759
+ A13: "1/1/2013", B13: "3" , C13: '=WORKDAY(A13, B13, A7)',
760
+ A14: "3/1/2013", B14: "120", C14: "=WORKDAY(A14, B14)",
761
+ A15: "3/1/2013", B15: "120", C15: "=WORKDAY(A15, B15,A1: A6)",
762
+ A16: "2/1/2013", B16: "22" , C16: "=WORKDAY(A16, B16)",
763
+ A17: "1/1/2013", B17: "-3" , C17: "=WORKDAY(A17, B17)",
764
+ A18: "1/1/2013", B18: "-3" , C18: "=WORKDAY(A18, B18, A1)",
765
+ A19: "1/1/2013", B19: "-3" , C19: "=WORKDAY(A19, B19, A8)",
766
+ };
767
+ const gridResult = evaluateGrid(grid);
768
+
769
+ expect(gridResult.C11).toEqual(parseDateTime("1/4/2013"));
770
+ expect(gridResult.C12).toEqual(parseDateTime("1/4/2013"));
771
+ expect(gridResult.C13).toEqual(parseDateTime("1/7/2013"));
772
+ expect(gridResult.C14).toEqual(parseDateTime("8/16/2013"));
773
+ expect(gridResult.C15).toEqual(parseDateTime("8/19/2013"));
774
+ expect(gridResult.C16).toEqual(parseDateTime("3/5/2013"));
775
+ expect(gridResult.C17).toEqual(parseDateTime("12/27/2012"));
776
+ expect(gridResult.C18).toEqual(parseDateTime("12/27/2012"));
777
+ expect(gridResult.C19).toEqual(parseDateTime("12/26/2012"));
778
+ });
779
+
780
+ //----------------------------------------------------------------------------
781
+ // WORKDAY.INTL
782
+ //----------------------------------------------------------------------------
783
+ test("WORKDAY.INTL: functional tests on cell arguments, string method", () => {
784
+ // prettier-ignore
785
+ const grid = {
786
+ B2: "5/4/2020", C2: "4", D2: '=WORKDAY.INTL(B2, C2)',
787
+ B3: "5/4/2020", C3: "4", D3: '=WORKDAY.INTL(B3, C3, "0")',
788
+ B4: "5/4/2020", C4: "4", D4: '=WORKDAY.INTL(B4, C4, "00")',
789
+ B5: "5/4/2020", C5: "4", D5: '=WORKDAY.INTL(B5, C5, "000000")',
790
+ B6: "5/4/2020", C6: "4", D6: '=WORKDAY.INTL(B6, C6, "0000000")',
791
+ B7: "5/4/2020", C7: "4", D7: '=WORKDAY.INTL(B7, C7, "0000011")',
792
+ B8: "5/4/2020", C8: "4", D8: '=WORKDAY.INTL(B8, C8, "0000111")',
793
+ B9: "5/4/2020", C9: "4", D9: '=WORKDAY.INTL(B9, C9, "1000111")',
794
+ B10: "5/4/2020", C10: "4", D10: '=WORKDAY.INTL(B10, C10, "1110111")',
795
+ B11: "5/4/2020", C11: "4", D11: '=WORKDAY.INTL(B11, C11, "1111111")',
796
+ B12: "5/4/2020", C12: "4", D12: '=WORKDAY.INTL(B12, C12, "1000211")',
797
+ C13: "4", D13: '=WORKDAY.INTL(B13, C13, "0000000")',
798
+ B14: "5/4/2020", D14: '=WORKDAY.INTL(B14, C14, "0000000")',
799
+
800
+ B75: "5/4/2020", C75: "7" , D75: '=WORKDAY.INTL(B75, C75, "0000000")',
801
+ B76: "5/4/2020", C76: "-3", D76: '=WORKDAY.INTL(B76, C76, "0000011")',
802
+ B77: "5/9/2020", C77: "1" , D77: '=WORKDAY.INTL(B77, C77, "0000011")',
803
+ B78: "5/4/2020", C78: "-4", D78: '=WORKDAY.INTL(B78, C78, "0000111")',
804
+ B79: "5/8/2020", C79: "5" , D79: '=WORKDAY.INTL(B79, C79, "0000111")',
805
+ B80: "5/5/2020", C80: "-4", D80: '=WORKDAY.INTL(B80, C80, "1000111")',
806
+ B81: "5/8/2020", C81: "1" , D81: '=WORKDAY.INTL(B81, C81, "1000111")',
807
+ B82: "5/7/2020", C82: "-4", D82: '=WORKDAY.INTL(B82, C82, "1110111")',
808
+ B83: "5/8/2020", C83: "4" , D83: '=WORKDAY.INTL(B83, C83, "1110111")',
809
+ };
810
+
811
+ const gridResult = evaluateGrid(grid);
812
+ expect(gridResult.D2).toEqual(parseDateTime("5/8/2020")); // @compatibility on Google Sheets, return #VALUE!
813
+ expect(gridResult.D3).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
814
+ expect(gridResult.D4).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
815
+ expect(gridResult.D5).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
816
+ expect(gridResult.D6).toEqual(parseDateTime("5/8/2020"));
817
+ expect(gridResult.D7).toEqual(parseDateTime("5/8/2020"));
818
+ expect(gridResult.D8).toEqual(parseDateTime("5/11/2020"));
819
+ expect(gridResult.D9).toEqual(parseDateTime("5/12/2020"));
820
+ expect(gridResult.D10).toEqual(parseDateTime("5/28/2020"));
821
+ expect(gridResult.D11).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
822
+ expect(gridResult.D12).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
823
+ expect(gridResult.D13).toEqual(parseDateTime("1/3/1900"));
824
+ expect(gridResult.D14).toEqual(parseDateTime("5/4/2020"));
825
+
826
+ expect(gridResult.D75).toEqual(parseDateTime("5/11/2020"));
827
+ expect(gridResult.D76).toEqual(parseDateTime("4/29/2020"));
828
+ expect(gridResult.D77).toEqual(parseDateTime("5/11/2020"));
829
+ expect(gridResult.D78).toEqual(parseDateTime("4/27/2020"));
830
+ expect(gridResult.D79).toEqual(parseDateTime("5/18/2020"));
831
+ expect(gridResult.D80).toEqual(parseDateTime("4/23/2020"));
832
+ expect(gridResult.D81).toEqual(parseDateTime("5/12/2020"));
833
+ expect(gridResult.D82).toEqual(parseDateTime("4/9/2020"));
834
+ expect(gridResult.D83).toEqual(parseDateTime("6/4/2020"));
835
+ });
836
+
837
+ test("WORKDAY.INTL: functional tests on cell arguments, number method", () => {
838
+ // prettier-ignore
839
+ const grid = {
840
+ B18: "5/4/2020", C18: "1", D18: '=WORKDAY.INTL(B18, C18, 0)',
841
+ B19: "5/9/2020", C19: "1", D19: '=WORKDAY.INTL(B19, C19, 1)',
842
+ B20: "5/10/2020", C20: "1", D20: '=WORKDAY.INTL(B20, C20, 1)',
843
+ B21: "5/10/2020", C21: "1", D21: '=WORKDAY.INTL(B21, C21, 2)',
844
+ B22: "5/11/2020", C22: "1", D22: '=WORKDAY.INTL(B22, C22, 2)',
845
+ B23: "5/11/2020", C23: "1", D23: '=WORKDAY.INTL(B23, C23, 3)',
846
+ B24: "5/12/2020", C24: "1", D24: '=WORKDAY.INTL(B24, C24, 3)',
847
+ B25: "5/12/2020", C25: "1", D25: '=WORKDAY.INTL(B25, C25, 4)',
848
+ B26: "5/13/2020", C26: "1", D26: '=WORKDAY.INTL(B26, C26, 4)',
849
+ B27: "5/13/2020", C27: "1", D27: '=WORKDAY.INTL(B27, C27, 5)',
850
+ B28: "5/14/2020", C28: "1", D28: '=WORKDAY.INTL(B28, C28, 5)',
851
+ B29: "5/14/2020", C29: "1", D29: '=WORKDAY.INTL(B29, C29, 6)',
852
+ B30: "5/15/2020", C30: "1", D30: '=WORKDAY.INTL(B30, C30, 6)',
853
+ B31: "5/15/2020", C31: "1", D31: '=WORKDAY.INTL(B31, C31, 7)',
854
+ B32: "5/16/2020", C32: "1", D32: '=WORKDAY.INTL(B32, C32, 7)',
855
+ B33: "5/16/2020", C33: "1", D33: '=WORKDAY.INTL(B33, C33, 8)',
856
+
857
+ B39: "5/4/2020", C39: "1", D39: '=WORKDAY.INTL(B39, C39, 10)',
858
+ B40: "5/9/2020", C40: "1", D40: '=WORKDAY.INTL(B40, C40, 11)',
859
+ B41: "5/10/2020", C41: "1", D41: '=WORKDAY.INTL(B41, C41, 11)',
860
+ B42: "5/10/2020", C42: "1", D42: '=WORKDAY.INTL(B42, C42, 12)',
861
+ B43: "5/11/2020", C43: "1", D43: '=WORKDAY.INTL(B43, C43, 12)',
862
+ B44: "5/11/2020", C44: "1", D44: '=WORKDAY.INTL(B44, C44, 13)',
863
+ B45: "5/12/2020", C45: "1", D45: '=WORKDAY.INTL(B45, C45, 13)',
864
+ B46: "5/12/2020", C46: "1", D46: '=WORKDAY.INTL(B46, C46, 14)',
865
+ B47: "5/13/2020", C47: "1", D47: '=WORKDAY.INTL(B47, C47, 14)',
866
+ B48: "5/13/2020", C48: "1", D48: '=WORKDAY.INTL(B48, C48, 15)',
867
+ B49: "5/14/2020", C49: "1", D49: '=WORKDAY.INTL(B49, C49, 15)',
868
+ B50: "5/14/2020", C50: "1", D50: '=WORKDAY.INTL(B50, C50, 16)',
869
+ B51: "5/15/2020", C51: "1", D51: '=WORKDAY.INTL(B51, C51, 16)',
870
+ B52: "5/15/2020", C52: "1", D52: '=WORKDAY.INTL(B52, C52, 17)',
871
+ B53: "5/16/2020", C53: "1", D53: '=WORKDAY.INTL(B53, C53, 17)',
872
+ B54: "5/16/2020", C54: "1", D54: '=WORKDAY.INTL(B54, C54, 18)',
873
+ };
874
+ const gridResult = evaluateGrid(grid);
875
+ expect(gridResult.D18).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
876
+ expect(gridResult.D19).toEqual(parseDateTime("5/11/2020"));
877
+ expect(gridResult.D20).toEqual(parseDateTime("5/11/2020"));
878
+ expect(gridResult.D21).toEqual(parseDateTime("5/12/2020"));
879
+ expect(gridResult.D22).toEqual(parseDateTime("5/12/2020"));
880
+ expect(gridResult.D23).toEqual(parseDateTime("5/13/2020"));
881
+ expect(gridResult.D24).toEqual(parseDateTime("5/13/2020"));
882
+ expect(gridResult.D25).toEqual(parseDateTime("5/14/2020"));
883
+ expect(gridResult.D26).toEqual(parseDateTime("5/14/2020"));
884
+ expect(gridResult.D27).toEqual(parseDateTime("5/15/2020"));
885
+ expect(gridResult.D28).toEqual(parseDateTime("5/15/2020"));
886
+ expect(gridResult.D29).toEqual(parseDateTime("5/16/2020"));
887
+ expect(gridResult.D30).toEqual(parseDateTime("5/16/2020"));
888
+ expect(gridResult.D31).toEqual(parseDateTime("5/17/2020"));
889
+ expect(gridResult.D32).toEqual(parseDateTime("5/17/2020"));
890
+ expect(gridResult.D33).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
891
+
892
+ expect(gridResult.D39).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
893
+ expect(gridResult.D40).toEqual(parseDateTime("5/11/2020"));
894
+ expect(gridResult.D41).toEqual(parseDateTime("5/11/2020"));
895
+ expect(gridResult.D42).toEqual(parseDateTime("5/12/2020"));
896
+ expect(gridResult.D43).toEqual(parseDateTime("5/12/2020"));
897
+ expect(gridResult.D44).toEqual(parseDateTime("5/13/2020"));
898
+ expect(gridResult.D45).toEqual(parseDateTime("5/13/2020"));
899
+ expect(gridResult.D46).toEqual(parseDateTime("5/14/2020"));
900
+ expect(gridResult.D47).toEqual(parseDateTime("5/14/2020"));
901
+ expect(gridResult.D48).toEqual(parseDateTime("5/15/2020"));
902
+ expect(gridResult.D49).toEqual(parseDateTime("5/15/2020"));
903
+ expect(gridResult.D50).toEqual(parseDateTime("5/16/2020"));
904
+ expect(gridResult.D51).toEqual(parseDateTime("5/16/2020"));
905
+ expect(gridResult.D52).toEqual(parseDateTime("5/17/2020"));
906
+ expect(gridResult.D53).toEqual(parseDateTime("5/17/2020"));
907
+ expect(gridResult.D54).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
908
+ });
909
+
910
+ test("WORKDAY.INTL: casting tests on cell arguments", () => {
911
+ // prettier-ignore
912
+ const grid = {
913
+ B68: "5/4/2020", C68: "1", D68: '=WORKDAY.INTL(B68, C68, 1110111)',
914
+ B69: "5/5/2020", C69: "1", D69: '=WORKDAY.INTL(B69, C69, "test")',
915
+ B70: "5/11/2020", C70: "1", D70: '=WORKDAY.INTL(B70, C70, "2")',
916
+ B71: "5/11/2020", C71: "1", D71: '=WORKDAY.INTL(B71, C71, A71)',
917
+ B72: "5/11/2020", C72: "1", D72: '=WORKDAY.INTL(B72, C72)',
918
+ };
919
+ const gridResult = evaluateGrid(grid);
920
+ expect(gridResult.D68).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
921
+ expect(gridResult.D69).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
922
+ expect(gridResult.D70).toBe("#ERROR"); // @compatibility on Google Sheets, return #NUM!
923
+ expect(gridResult.D71).toBe("#ERROR"); // @compatibility on Google Sheets, return #VALUE!
924
+ expect(gridResult.D72).toEqual(parseDateTime("5/12/2020"));
925
+ });
926
+
927
+ //----------------------------------------------------------------------------
928
+ // YEAR
929
+ //----------------------------------------------------------------------------
930
+
931
+ test("YEAR: functional tests on cell arguments", () => {
932
+ expect(evaluateCell("A1", { A1: "=YEAR(A2)", A2: "5/13/1950" })).toBe(1950);
933
+ expect(evaluateCell("A1", { A1: "=YEAR(A2)", A2: "5/13/2020" })).toBe(2020);
934
+ expect(evaluateCell("A1", { A1: "=YEAR(A2)", A2: "43964" })).toBe(2020); // 43964 corespond to 5/13/2020
935
+ expect(evaluateCell("A1", { A1: "=YEAR(A2)", A2: "0" })).toBe(1899); // 0 corespond to 12/30/1899
936
+ expect(evaluateCell("A1", { A1: "=YEAR(A2)", A2: "1" })).toBe(1899); // 1 corespond to 12/31/1899
937
+ expect(evaluateCell("A1", { A1: "=YEAR(A2)", A2: "2" })).toBe(1900); // 2 corespond to 1/1/1900
938
+ expect(evaluateCell("A1", { A1: "=YEAR(A2)", A2: '="43964"' })).toBe(2020);
939
+ expect(evaluateCell("A1", { A1: "=YEAR(A2)", A2: "TRUE" })).toBe(1899);
940
+ });
941
+ });