@veltra/sheet 2.0.1 → 2.1.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 (211) hide show
  1. package/dist/index.d.ts +4 -26
  2. package/dist/index.js +3 -23
  3. package/dist/tools/builtin.js +279 -8
  4. package/dist/tools/context.d.ts +54 -11
  5. package/dist/tools/context.js +28 -5
  6. package/dist/tools/download.js +68 -0
  7. package/dist/tools/export.worker.d.ts +16 -0
  8. package/dist/tools/export.worker.js +29 -0
  9. package/dist/tools/registry.d.ts +7 -4
  10. package/dist/tools/registry.js +1 -3
  11. package/dist/types/index.d.ts +1 -0
  12. package/dist/types/sheet.d.ts +6 -5
  13. package/dist/vue/formula-bar.js +393 -0
  14. package/dist/vue/formula-suggest-list.js +66 -0
  15. package/dist/vue/import-file.js +140 -0
  16. package/dist/vue/insert-count-menu-item.js +68 -0
  17. package/dist/vue/insert-image.js +79 -0
  18. package/dist/vue/popup-helpers.js +73 -0
  19. package/dist/vue/popups/border-popup.js +75 -0
  20. package/dist/vue/popups/border-preset-glyph.js +106 -0
  21. package/dist/vue/popups/export-popup.js +51 -0
  22. package/dist/vue/popups/fill-color-popup.js +37 -0
  23. package/dist/vue/popups/find-popup.js +113 -0
  24. package/dist/vue/popups/font-color-popup.js +37 -0
  25. package/dist/vue/popups/font-size-popup.js +63 -0
  26. package/dist/vue/popups/import.worker.d.ts +21 -0
  27. package/dist/vue/popups/import.worker.js +41 -0
  28. package/dist/vue/popups/insert-image-popup.js +38 -0
  29. package/dist/vue/sheet-context-menu.js +200 -0
  30. package/dist/vue/sheet-tabs.js +162 -0
  31. package/dist/vue/sheet-toolbar.js +106 -0
  32. package/dist/vue/sheet.js +144 -164
  33. package/dist/vue/style.d.ts +11 -1
  34. package/dist/vue/style.js +10 -0
  35. package/dist/vue/style2.css +564 -3
  36. package/dist/vue/use-find-replace.js +161 -0
  37. package/dist/vue/use-formula-ref-select.js +37 -0
  38. package/dist/vue/use-formula-suggest.js +126 -0
  39. package/dist/vue/use-sheet-grid.js +180 -0
  40. package/dist/vue/use-sheet-state.js +122 -0
  41. package/dist/vue/use-sheet-tabs-bar.js +90 -0
  42. package/dist/vue/use-tool-groups.js +42 -0
  43. package/dist/vue/use-tool-popup.js +123 -0
  44. package/dist/vue/use-toolbar-scroll.js +72 -0
  45. package/package.json +12 -7
  46. package/src/env.d.ts +11 -0
  47. package/src/index.ts +203 -14
  48. package/src/tools/__test__/builtin.test.ts +208 -66
  49. package/src/tools/__test__/context.test.ts +62 -2
  50. package/src/tools/builtin.ts +350 -6
  51. package/src/tools/context.ts +89 -11
  52. package/src/tools/download.ts +82 -0
  53. package/src/tools/export.worker.ts +61 -0
  54. package/src/tools/registry.ts +16 -1
  55. package/src/types/index.ts +6 -0
  56. package/src/types/sheet.ts +5 -3
  57. package/src/vue/__test__/formula-bar.test.ts +455 -0
  58. package/src/vue/__test__/import-file.test.ts +183 -0
  59. package/src/vue/__test__/insert-count-menu-item.test.ts +123 -0
  60. package/src/vue/__test__/insert-image-popup.test.ts +89 -0
  61. package/src/vue/__test__/insert-image.test.ts +100 -0
  62. package/src/vue/__test__/sheet-component.test.ts +716 -27
  63. package/src/vue/__test__/sheet-context-menu.test.ts +206 -0
  64. package/src/vue/__test__/use-formula-ref-select.test.ts +35 -0
  65. package/src/vue/__test__/use-formula-suggest.test.ts +83 -0
  66. package/src/vue/formula-bar.vue +473 -0
  67. package/src/vue/formula-suggest-list.vue +64 -0
  68. package/src/vue/import-file.ts +173 -0
  69. package/src/vue/insert-count-menu-item.vue +69 -0
  70. package/src/vue/insert-image.ts +90 -0
  71. package/src/vue/parsing.ts +11 -0
  72. package/src/vue/popup-helpers.ts +50 -0
  73. package/src/vue/popups/border-popup.vue +93 -0
  74. package/src/vue/popups/border-preset-glyph.vue +111 -0
  75. package/src/vue/popups/export-popup.vue +52 -0
  76. package/src/vue/popups/fill-color-popup.vue +39 -0
  77. package/src/vue/popups/find-popup.vue +111 -0
  78. package/src/vue/popups/font-color-popup.vue +39 -0
  79. package/src/vue/popups/font-size-popup.vue +52 -0
  80. package/src/vue/popups/import.worker.ts +66 -0
  81. package/src/vue/popups/insert-image-popup.vue +39 -0
  82. package/src/vue/sheet-context-menu.ts +229 -0
  83. package/src/vue/sheet-tabs.vue +162 -0
  84. package/src/vue/sheet-toolbar.vue +91 -0
  85. package/src/vue/sheet.vue +161 -186
  86. package/src/vue/style.scss +646 -3
  87. package/src/vue/style.ts +11 -0
  88. package/src/vue/use-find-replace.ts +200 -0
  89. package/src/vue/use-formula-ref-select.ts +34 -0
  90. package/src/vue/use-formula-suggest.ts +150 -0
  91. package/src/vue/use-sheet-grid.ts +243 -0
  92. package/src/vue/use-sheet-state.ts +161 -0
  93. package/src/vue/use-sheet-tabs-bar.ts +115 -0
  94. package/src/vue/use-tool-groups.ts +61 -0
  95. package/src/vue/use-tool-popup.ts +150 -0
  96. package/src/vue/use-toolbar-scroll.ts +95 -0
  97. package/dist/core/address.d.ts +0 -60
  98. package/dist/core/address.js +0 -142
  99. package/dist/core/address.js.map +0 -1
  100. package/dist/core/cell-store.d.ts +0 -61
  101. package/dist/core/cell-store.js +0 -135
  102. package/dist/core/cell-store.js.map +0 -1
  103. package/dist/core/command/default-registry.d.ts +0 -10
  104. package/dist/core/command/default-registry.js +0 -18
  105. package/dist/core/command/default-registry.js.map +0 -1
  106. package/dist/core/command/history.d.ts +0 -64
  107. package/dist/core/command/history.js +0 -127
  108. package/dist/core/command/history.js.map +0 -1
  109. package/dist/core/command/merge-cells.d.ts +0 -21
  110. package/dist/core/command/merge-cells.js +0 -74
  111. package/dist/core/command/merge-cells.js.map +0 -1
  112. package/dist/core/command/registry.d.ts +0 -17
  113. package/dist/core/command/registry.js +0 -26
  114. package/dist/core/command/registry.js.map +0 -1
  115. package/dist/core/command/set-cell-formula.d.ts +0 -17
  116. package/dist/core/command/set-cell-formula.js +0 -29
  117. package/dist/core/command/set-cell-formula.js.map +0 -1
  118. package/dist/core/command/set-cell-value.d.ts +0 -22
  119. package/dist/core/command/set-cell-value.js +0 -35
  120. package/dist/core/command/set-cell-value.js.map +0 -1
  121. package/dist/core/command/types.d.ts +0 -68
  122. package/dist/core/events.js +0 -29
  123. package/dist/core/events.js.map +0 -1
  124. package/dist/core/fill.d.ts +0 -34
  125. package/dist/core/fill.js +0 -320
  126. package/dist/core/fill.js.map +0 -1
  127. package/dist/core/formula/ast.d.ts +0 -58
  128. package/dist/core/formula/ast.js +0 -38
  129. package/dist/core/formula/ast.js.map +0 -1
  130. package/dist/core/formula/dependency-graph.d.ts +0 -70
  131. package/dist/core/formula/dependency-graph.js +0 -269
  132. package/dist/core/formula/dependency-graph.js.map +0 -1
  133. package/dist/core/formula/errors.d.ts +0 -25
  134. package/dist/core/formula/errors.js +0 -36
  135. package/dist/core/formula/errors.js.map +0 -1
  136. package/dist/core/formula/evaluator.d.ts +0 -41
  137. package/dist/core/formula/evaluator.js +0 -154
  138. package/dist/core/formula/evaluator.js.map +0 -1
  139. package/dist/core/formula/functions.d.ts +0 -30
  140. package/dist/core/formula/functions.js +0 -209
  141. package/dist/core/formula/functions.js.map +0 -1
  142. package/dist/core/formula/parser.d.ts +0 -7
  143. package/dist/core/formula/parser.js +0 -208
  144. package/dist/core/formula/parser.js.map +0 -1
  145. package/dist/core/formula/tokenizer.d.ts +0 -37
  146. package/dist/core/formula/tokenizer.js +0 -146
  147. package/dist/core/formula/tokenizer.js.map +0 -1
  148. package/dist/core/merge-manager.d.ts +0 -64
  149. package/dist/core/merge-manager.js +0 -111
  150. package/dist/core/merge-manager.js.map +0 -1
  151. package/dist/core/selection.d.ts +0 -31
  152. package/dist/core/selection.js +0 -62
  153. package/dist/core/selection.js.map +0 -1
  154. package/dist/core/sheet.d.ts +0 -116
  155. package/dist/core/sheet.js +0 -224
  156. package/dist/core/sheet.js.map +0 -1
  157. package/dist/core/workbook.d.ts +0 -43
  158. package/dist/core/workbook.js +0 -77
  159. package/dist/core/workbook.js.map +0 -1
  160. package/dist/grid/sheet-grid.d.ts +0 -81
  161. package/dist/grid/sheet-grid.js +0 -331
  162. package/dist/grid/sheet-grid.js.map +0 -1
  163. package/dist/grid/vtable-theme.js +0 -80
  164. package/dist/grid/vtable-theme.js.map +0 -1
  165. package/dist/tools/builtin.js.map +0 -1
  166. package/dist/tools/context.js.map +0 -1
  167. package/dist/tools/registry.js.map +0 -1
  168. package/dist/vue/index.d.ts +0 -2
  169. package/dist/vue/sheet.js.map +0 -1
  170. package/dist/vue/sheet.vue.d.ts +0 -24
  171. package/src/core/__test__/address.test.ts +0 -113
  172. package/src/core/__test__/cell-store.test.ts +0 -97
  173. package/src/core/__test__/command.test.ts +0 -377
  174. package/src/core/__test__/fill.test.ts +0 -140
  175. package/src/core/__test__/formula-adversarial.test.ts +0 -265
  176. package/src/core/__test__/formula-engine.test.ts +0 -470
  177. package/src/core/__test__/formula-functions.test.ts +0 -178
  178. package/src/core/__test__/formula-parser.test.ts +0 -160
  179. package/src/core/__test__/history.test.ts +0 -225
  180. package/src/core/__test__/merge-manager.test.ts +0 -106
  181. package/src/core/__test__/sheet.test.ts +0 -142
  182. package/src/core/address.ts +0 -166
  183. package/src/core/cell-store.ts +0 -173
  184. package/src/core/command/default-registry.ts +0 -15
  185. package/src/core/command/history.ts +0 -167
  186. package/src/core/command/index.ts +0 -7
  187. package/src/core/command/merge-cells.ts +0 -74
  188. package/src/core/command/registry.ts +0 -30
  189. package/src/core/command/set-cell-formula.ts +0 -29
  190. package/src/core/command/set-cell-value.ts +0 -38
  191. package/src/core/command/types.ts +0 -73
  192. package/src/core/events.ts +0 -37
  193. package/src/core/fill.ts +0 -314
  194. package/src/core/formula/ast.ts +0 -66
  195. package/src/core/formula/dependency-graph.ts +0 -329
  196. package/src/core/formula/errors.ts +0 -41
  197. package/src/core/formula/evaluator.ts +0 -219
  198. package/src/core/formula/functions.ts +0 -266
  199. package/src/core/formula/index.ts +0 -7
  200. package/src/core/formula/parser.ts +0 -198
  201. package/src/core/formula/tokenizer.ts +0 -160
  202. package/src/core/merge-manager.ts +0 -158
  203. package/src/core/selection.ts +0 -66
  204. package/src/core/sheet.ts +0 -282
  205. package/src/core/workbook.ts +0 -99
  206. package/src/grid/__test__/canvas-mock.ts +0 -49
  207. package/src/grid/__test__/setup.ts +0 -3
  208. package/src/grid/__test__/sheet-grid-formula.test.ts +0 -140
  209. package/src/grid/__test__/sheet-grid.test.ts +0 -275
  210. package/src/grid/sheet-grid.ts +0 -407
  211. package/src/grid/vtable-theme.ts +0 -61
@@ -1,470 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest'
2
-
3
- import { parseRange, type CellAddress } from '../address'
4
- import { Sheet } from '../sheet'
5
- import { Workbook } from '../workbook'
6
-
7
- const A1 = { row: 0, col: 0 }
8
- const B1 = { row: 0, col: 1 }
9
- const C1 = { row: 0, col: 2 }
10
- const D1 = { row: 0, col: 3 }
11
-
12
- describe('依赖重算', () => {
13
- it('改 A1 → 依赖它的 =A1*2 重算', () => {
14
- const sheet = new Sheet()
15
- sheet.setCellValue(A1, 3)
16
- sheet.setCellFormula(B1, '=A1*2')
17
- expect(sheet.getCellData(B1)).toMatchObject({ v: 6 })
18
-
19
- sheet.setCellValue(A1, 10)
20
- expect(sheet.getCellData(B1)).toMatchObject({ v: 20 })
21
- })
22
-
23
- it('间接依赖按拓扑序重算:A1 → B1(=A1*2) → C1(=B1+1)', () => {
24
- const sheet = new Sheet()
25
- sheet.setCellValue(A1, 1)
26
- sheet.setCellFormula(B1, '=A1*2')
27
- sheet.setCellFormula(C1, '=B1+1')
28
- expect(sheet.getCellData(C1)).toMatchObject({ v: 3 })
29
-
30
- sheet.setCellValue(A1, 5)
31
- // 若顺序错误(C1 先于 B1 重算)会拿到旧 B1 的 2+1=3
32
- expect(sheet.getCellData(B1)).toMatchObject({ v: 10 })
33
- expect(sheet.getCellData(C1)).toMatchObject({ v: 11 })
34
- })
35
-
36
- it('菱形依赖(D1=B1+C1,B1/C1 同依赖 A1)只算一次且结果正确', () => {
37
- const sheet = new Sheet()
38
- sheet.setCellValue(A1, 2)
39
- sheet.setCellFormula(B1, '=A1*2')
40
- sheet.setCellFormula(C1, '=A1*3')
41
- sheet.setCellFormula(D1, '=B1+C1')
42
- expect(sheet.getCellData(D1)).toMatchObject({ v: 10 })
43
-
44
- sheet.setCellValue(A1, 4)
45
- expect(sheet.getCellData(D1)).toMatchObject({ v: 20 })
46
- })
47
-
48
- it('连续改值,每次重算结果一致', () => {
49
- const sheet = new Sheet()
50
- sheet.setCellFormula(B1, '=A1*2')
51
- sheet.setCellFormula(C1, '=B1+1')
52
- for (const [input, b, c] of [
53
- [1, 2, 3],
54
- [2, 4, 5],
55
- [3, 6, 7],
56
- [2, 4, 5],
57
- [0, 0, 1]
58
- ] as const) {
59
- sheet.setCellValue(A1, input)
60
- expect(sheet.getCellData(B1)).toMatchObject({ v: b })
61
- expect(sheet.getCellData(C1)).toMatchObject({ v: c })
62
- }
63
- })
64
-
65
- it('重算收敛时值未变的格不产生派生变更(不触发 cell-change)', () => {
66
- const sheet = new Sheet()
67
- sheet.setCellFormula(B1, '=A1*0+1')
68
- expect(sheet.getCellData(B1)).toMatchObject({ v: 1 })
69
-
70
- const handler = vi.fn()
71
- sheet.on('cell-change', handler)
72
- sheet.setCellValue(A1, 99)
73
- // 只有 A1 自身变更;B1 收敛(恒为 1)不应有事件
74
- expect(handler).toHaveBeenCalledTimes(1)
75
- expect(handler).toHaveBeenCalledWith({ addr: A1 })
76
- })
77
- })
78
-
79
- describe('循环引用', () => {
80
- it('A1==B1+1, B1==A1+1 → 双格 #CYCLE!;打破循环自动恢复', () => {
81
- const sheet = new Sheet()
82
- sheet.setCellFormula(A1, '=B1+1')
83
- sheet.setCellFormula(B1, '=A1+1')
84
- expect(sheet.getCellData(A1)).toMatchObject({ v: '#CYCLE!', t: 'e' })
85
- expect(sheet.getCellData(B1)).toMatchObject({ v: '#CYCLE!', t: 'e' })
86
-
87
- // 打破循环:B1 改为常量 → A1 恢复
88
- sheet.setCellValue(B1, 5)
89
- expect(sheet.getCellData(A1)).toMatchObject({ v: 6, t: 'n' })
90
- expect(sheet.getCellData(B1)).toMatchObject({ v: 5 })
91
- })
92
-
93
- it('环外格引用环上格 → 错误传播(自身不入环)', () => {
94
- const sheet = new Sheet()
95
- sheet.setCellFormula(A1, '=B1+1')
96
- sheet.setCellFormula(B1, '=A1+1')
97
- sheet.setCellFormula(C1, '=A1*2')
98
- expect(sheet.getCellData(C1)).toMatchObject({ v: '#CYCLE!', t: 'e' })
99
-
100
- // 打破循环后环外格一并恢复
101
- sheet.setCellValue(B1, 2)
102
- expect(sheet.getCellData(A1)).toMatchObject({ v: 3 })
103
- expect(sheet.getCellData(C1)).toMatchObject({ v: 6 })
104
- })
105
-
106
- it('自引用 A1==A1+1 → #CYCLE!,改常量后恢复', () => {
107
- const sheet = new Sheet()
108
- sheet.setCellFormula(A1, '=A1+1')
109
- expect(sheet.getCellData(A1)).toMatchObject({ v: '#CYCLE!', t: 'e' })
110
-
111
- sheet.setCellValue(A1, 10)
112
- expect(sheet.getCellData(A1)).toMatchObject({ v: 10 })
113
- })
114
-
115
- it('跨表循环:Sheet1!A1 ↔ Sheet2!B1 → 双格 #CYCLE!,打破后恢复', () => {
116
- const workbook = new Workbook()
117
- const sheet1 = workbook.activeSheet
118
- const sheet2 = workbook.addSheet('Sheet2')
119
- sheet1.setCellFormula(A1, '=Sheet2!B1+1')
120
- sheet2.setCellFormula(B1, '=Sheet1!A1+1')
121
- expect(sheet1.getCellData(A1)).toMatchObject({ v: '#CYCLE!', t: 'e' })
122
- expect(sheet2.getCellData(B1)).toMatchObject({ v: '#CYCLE!', t: 'e' })
123
-
124
- sheet2.setCellValue(B1, 3)
125
- expect(sheet1.getCellData(A1)).toMatchObject({ v: 4 })
126
- })
127
-
128
- it('循环期间其它无关变更不影响环状态', () => {
129
- const sheet = new Sheet()
130
- sheet.setCellFormula(A1, '=B1+1')
131
- sheet.setCellFormula(B1, '=A1+D1')
132
- sheet.setCellFormula(C1, '=A1+1')
133
- // A1 → B1 → A1 成环(D1 是环上引用);C1 环外
134
- expect(sheet.getCellData(A1)).toMatchObject({ v: '#CYCLE!' })
135
- expect(sheet.getCellData(B1)).toMatchObject({ v: '#CYCLE!' })
136
- expect(sheet.getCellData(C1)).toMatchObject({ v: '#CYCLE!' })
137
-
138
- // 改 D1(环的输入)→ 重算后仍是环
139
- sheet.setCellValue(D1, 10)
140
- expect(sheet.getCellData(A1)).toMatchObject({ v: '#CYCLE!' })
141
- expect(sheet.getCellData(B1)).toMatchObject({ v: '#CYCLE!' })
142
- })
143
- })
144
-
145
- describe('跨表引用', () => {
146
- it('Sheet2 值变更 → Sheet1 引用格实时重算;undo 一并还原', () => {
147
- const workbook = new Workbook()
148
- const sheet1 = workbook.activeSheet
149
- const sheet2 = workbook.addSheet('Sheet2')
150
- sheet2.setCellValue(A1, 10)
151
- sheet1.setCellFormula(B1, '=Sheet2!A1*2')
152
- expect(sheet1.getCellData(B1)).toMatchObject({ v: 20 })
153
-
154
- sheet2.setCellValue(A1, 7)
155
- expect(sheet1.getCellData(B1)).toMatchObject({ v: 14 })
156
-
157
- // 变更发生在 Sheet2,单次 undo 同时还原 Sheet2 源格与 Sheet1 派生格
158
- expect(sheet2.undo()).toBe(true)
159
- expect(sheet2.getCellData(A1)).toMatchObject({ v: 10 })
160
- expect(sheet1.getCellData(B1)).toMatchObject({ v: 20 })
161
- })
162
-
163
- it('引用不存在的 sheet → #REF!', () => {
164
- const sheet = new Sheet()
165
- sheet.setCellFormula(A1, '=Nope!B2')
166
- expect(sheet.getCellData(A1)).toMatchObject({ v: '#REF!', t: 'e' })
167
- sheet.setCellFormula(B1, "=SUM('No Sheet'!A1:B2)")
168
- expect(sheet.getCellData(B1)).toMatchObject({ v: '#REF!', t: 'e' })
169
- })
170
-
171
- it("跨表区域:'S2'!A1:B2 聚合", () => {
172
- const workbook = new Workbook()
173
- const sheet1 = workbook.activeSheet
174
- const s2 = workbook.addSheet('S2')
175
- s2.setCellValue(A1, 1)
176
- s2.setCellValue({ row: 1, col: 1 }, 2)
177
- sheet1.setCellFormula(A1, "=SUM('S2'!A1:B2)")
178
- expect(sheet1.getCellData(A1)).toMatchObject({ v: 3 })
179
-
180
- // 区域内空格变更也触发重算
181
- s2.setCellValue({ row: 0, col: 1 }, 10)
182
- expect(sheet1.getCellData(A1)).toMatchObject({ v: 13 })
183
- })
184
-
185
- it('删除被引用的 sheet:缓存仍旧值,下次重算 → #REF!(已知限制行为)', () => {
186
- const workbook = new Workbook()
187
- const sheet1 = workbook.activeSheet
188
- const sheet2 = workbook.addSheet('Sheet2')
189
- sheet2.setCellValue(A1, 10)
190
- sheet1.setCellFormula(B1, '=Sheet2!A1+D1')
191
- sheet1.setCellValue(D1, 1)
192
- expect(sheet1.getCellData(B1)).toMatchObject({ v: 11 })
193
-
194
- workbook.removeSheet('Sheet2')
195
- expect(workbook.formulaGraph.getSheet('Sheet2')).toBeUndefined()
196
- // 删除本身不触发重算(已知限制):缓存仍旧值
197
- expect(sheet1.getCellData(B1)).toMatchObject({ v: 11 })
198
- // 任意触发源变更 → 重算时表已不存在 → #REF!
199
- sheet1.setCellValue(D1, 2)
200
- expect(sheet1.getCellData(B1)).toMatchObject({ v: '#REF!', t: 'e' })
201
- })
202
- })
203
-
204
- describe('错误值体系', () => {
205
- it('三类错误:除零 #DIV/0!、类型错误 #VALUE!、未知函数 #NAME?', () => {
206
- const sheet = new Sheet()
207
- sheet.setCellFormula(A1, '=1/0')
208
- expect(sheet.getCellData(A1)).toMatchObject({ v: '#DIV/0!', t: 'e' })
209
- sheet.setCellFormula(B1, '=1+"abc"')
210
- expect(sheet.getCellData(B1)).toMatchObject({ v: '#VALUE!', t: 'e' })
211
- sheet.setCellFormula(C1, '=NOSUCHFN(1)')
212
- expect(sheet.getCellData(C1)).toMatchObject({ v: '#NAME?', t: 'e' })
213
- })
214
-
215
- it('0 作除数与 0 的负幂 → #DIV/0!;非法幂 → #VALUE!', () => {
216
- const sheet = new Sheet()
217
- sheet.setCellFormula(A1, '=0/0')
218
- expect(sheet.getCellData(A1)).toMatchObject({ v: '#DIV/0!' })
219
- sheet.setCellFormula(B1, '=0^-1')
220
- expect(sheet.getCellData(B1)).toMatchObject({ v: '#DIV/0!' })
221
- sheet.setCellFormula(C1, '=(-1)^0.5')
222
- expect(sheet.getCellData(C1)).toMatchObject({ v: '#VALUE!' })
223
- })
224
-
225
- it('错误沿依赖链传播,源修复后恢复', () => {
226
- const sheet = new Sheet()
227
- sheet.setCellFormula(A1, '=1/0')
228
- sheet.setCellFormula(B1, '=A1*2')
229
- sheet.setCellFormula(C1, '=B1+1')
230
- expect(sheet.getCellData(B1)).toMatchObject({ v: '#DIV/0!' })
231
- expect(sheet.getCellData(C1)).toMatchObject({ v: '#DIV/0!' })
232
-
233
- sheet.setCellValue(A1, 5)
234
- expect(sheet.getCellData(B1)).toMatchObject({ v: 10 })
235
- expect(sheet.getCellData(C1)).toMatchObject({ v: 11 })
236
- })
237
-
238
- it('区域直接作为公式结果 → #VALUE!', () => {
239
- const sheet = new Sheet()
240
- sheet.setCellValue(A1, 1)
241
- sheet.setCellFormula(B1, '=A1:A3')
242
- expect(sheet.getCellData(B1)).toMatchObject({ v: '#VALUE!', t: 'e' })
243
- })
244
- })
245
-
246
- describe('undo/redo 集成', () => {
247
- it('改值波及 10 格公式链 → 单次 undo 全部还原', () => {
248
- const sheet = new Sheet()
249
- sheet.setCellValue(A1, 1)
250
- // B1..K1 共 10 格链:B1=A1+1, C1=B1+1, …
251
- const chain: CellAddress[] = []
252
- for (let col = 1; col <= 10; col++) {
253
- const prev = { row: 0, col: col - 1 }
254
- const addr = { row: 0, col }
255
- sheet.setCellFormula(addr, `=${String.fromCharCode(64 + col)}1+1`)
256
- chain.push(addr)
257
- }
258
- expect(sheet.getCellData(chain[9]!)).toMatchObject({ v: 11 })
259
- sheet.history.clear()
260
-
261
- sheet.setCellValue(A1, 100)
262
- expect(sheet.getCellData(chain[9]!)).toMatchObject({ v: 110 })
263
- // 源变更 + 10 格派生 = 一个 undo 单元
264
- expect(sheet.history.undoSize).toBe(1)
265
-
266
- expect(sheet.undo()).toBe(true)
267
- expect(sheet.getCellData(A1)).toMatchObject({ v: 1 })
268
- for (const [i, addr] of chain.entries()) {
269
- expect(sheet.getCellData(addr)).toMatchObject({ v: i + 2 })
270
- }
271
-
272
- expect(sheet.redo()).toBe(true)
273
- expect(sheet.getCellData(chain[9]!)).toMatchObject({ v: 110 })
274
- })
275
-
276
- it('undo 公式输入:公式、缓存与波及变更一步还原', () => {
277
- const sheet = new Sheet()
278
- sheet.setCellValue(A1, 5)
279
- sheet.setCellFormula(B1, '=A1*2')
280
- sheet.setCellFormula(C1, '=B1+1')
281
- sheet.history.clear()
282
-
283
- sheet.setCellFormula(D1, '=C1*10')
284
- expect(sheet.getCellData(D1)).toMatchObject({ v: 110 })
285
-
286
- sheet.undo()
287
- expect(sheet.getCellData(D1)).toBeUndefined()
288
-
289
- sheet.redo()
290
- expect(sheet.getCellData(D1)).toMatchObject({ f: 'C1*10', v: 110 })
291
- })
292
-
293
- it('undo 公式删除 → 依赖图复原,再次改值照常重算', () => {
294
- const sheet = new Sheet()
295
- sheet.setCellValue(A1, 5)
296
- sheet.setCellFormula(B1, '=A1*2')
297
- sheet.setCellFormula(C1, '=B1+1')
298
- const nodesBefore = sheet.formulaGraph.nodeCount
299
-
300
- // 删除 B1 的公式(写常量覆盖)→ C1 按 B1 新值重算
301
- sheet.setCellValue(B1, 0)
302
- expect(sheet.getCellData(B1)).toMatchObject({ v: 0 })
303
- expect(sheet.getCellData(C1)).toMatchObject({ v: 1 })
304
- expect(sheet.formulaGraph.nodeCount).toBe(nodesBefore - 1)
305
-
306
- // undo 删除 → 公式、缓存、派生值、图节点全部复原
307
- sheet.undo()
308
- expect(sheet.getCellData(B1)).toMatchObject({ f: 'A1*2', v: 10 })
309
- expect(sheet.getCellData(C1)).toMatchObject({ v: 11 })
310
- expect(sheet.formulaGraph.nodeCount).toBe(nodesBefore)
311
-
312
- // 图确实复原:再改 A1 仍触发 B1/C1 重算
313
- sheet.setCellValue(A1, 7)
314
- expect(sheet.getCellData(B1)).toMatchObject({ v: 14 })
315
- expect(sheet.getCellData(C1)).toMatchObject({ v: 15 })
316
- })
317
- })
318
-
319
- describe('公式与合并单元格(对抗场景)', () => {
320
- it('引用合并格:锚点有值、被覆盖格按空(原始存储语义)', () => {
321
- const sheet = new Sheet()
322
- sheet.setCellValue({ row: 1, col: 1 }, 10) // B2
323
- sheet.mergeCells(parseRange('B2:C3')!)
324
-
325
- sheet.setCellFormula(D1, '=B2')
326
- expect(sheet.getCellData(D1)).toMatchObject({ v: 10 })
327
- // C3 是被覆盖格 → 空 → 0
328
- sheet.setCellFormula({ row: 0, col: 4 }, '=C3+1')
329
- expect(sheet.getCellData({ row: 0, col: 4 })).toMatchObject({ v: 1 })
330
- // 区域含合并:只锚点计数一次
331
- sheet.setCellFormula({ row: 0, col: 5 }, '=SUM(B2:C3)')
332
- expect(sheet.getCellData({ row: 0, col: 5 })).toMatchObject({ v: 10 })
333
- })
334
-
335
- it('公式格作为合并锚点:合并后公式保留且继续重算', () => {
336
- const sheet = new Sheet()
337
- sheet.setCellValue(A1, 5)
338
- sheet.setCellFormula({ row: 1, col: 1 }, '=A1+1') // B2
339
- sheet.mergeCells(parseRange('B2:C3')!)
340
-
341
- expect(sheet.getCellData({ row: 1, col: 1 })).toMatchObject({ f: 'A1+1', v: 6 })
342
- sheet.setCellValue(A1, 7)
343
- expect(sheet.getCellData({ row: 1, col: 1 })).toMatchObject({ v: 8 })
344
- })
345
-
346
- it('被覆盖格上的公式被合并清除:节点移除 + 依赖者重算', () => {
347
- const sheet = new Sheet()
348
- sheet.setCellValue({ row: 1, col: 1 }, 10) // B2 锚点
349
- sheet.setCellFormula({ row: 2, col: 2 }, '=B2+1') // C3 将被覆盖
350
- sheet.setCellFormula(D1, '=C3*2')
351
- expect(sheet.getCellData(D1)).toMatchObject({ v: 22 })
352
- const nodesBefore = sheet.formulaGraph.nodeCount
353
-
354
- sheet.mergeCells(parseRange('B2:C3')!)
355
- // C3 数据被清空 → 公式节点移除;D1 按 C3 空值重算
356
- expect(sheet.getCellData({ row: 2, col: 2 })).toBeUndefined()
357
- expect(sheet.formulaGraph.nodeCount).toBe(nodesBefore - 1)
358
- expect(sheet.getCellData(D1)).toMatchObject({ v: 0 })
359
-
360
- // undo 合并 → C3 公式恢复,D1 回到 22
361
- sheet.undo()
362
- expect(sheet.getCellData({ row: 2, col: 2 })).toMatchObject({ f: 'B2+1', v: 11 })
363
- expect(sheet.getCellData(D1)).toMatchObject({ v: 22 })
364
- })
365
- })
366
-
367
- describe('公式生命周期(对抗场景)', () => {
368
- it('删除公式后依赖图清理:原依赖格改动不再触发重算', () => {
369
- const sheet = new Sheet()
370
- sheet.setCellValue(A1, 5)
371
- sheet.setCellFormula(B1, '=A1*2')
372
- sheet.setCellFormula(C1, '=B1+1')
373
- expect(sheet.formulaGraph.nodeCount).toBe(2)
374
-
375
- // 清空 B1(删除公式)→ C1 按空值重算
376
- sheet.setCellValue(B1, null)
377
- expect(sheet.getCellData(B1)).toBeUndefined()
378
- expect(sheet.getCellData(C1)).toMatchObject({ v: 1 })
379
- expect(sheet.formulaGraph.nodeCount).toBe(1)
380
-
381
- // A1 改动不再有任何依赖者
382
- const handler = vi.fn()
383
- sheet.on('cell-change', handler)
384
- sheet.setCellValue(A1, 99)
385
- expect(handler).toHaveBeenCalledTimes(1)
386
- expect(sheet.getCellData(C1)).toMatchObject({ v: 1 })
387
- })
388
-
389
- it('公式改公式:依赖边切换(旧依赖不再触发,新依赖生效)', () => {
390
- const sheet = new Sheet()
391
- sheet.setCellValue(A1, 1)
392
- sheet.setCellValue(B1, 10)
393
- sheet.setCellFormula(C1, '=A1+1')
394
- expect(sheet.getCellData(C1)).toMatchObject({ v: 2 })
395
-
396
- sheet.setCellFormula(C1, '=B1+1')
397
- expect(sheet.getCellData(C1)).toMatchObject({ v: 11 })
398
-
399
- // 旧依赖 A1 改动不再影响 C1
400
- sheet.setCellValue(A1, 100)
401
- expect(sheet.getCellData(C1)).toMatchObject({ v: 11 })
402
- // 新依赖 B1 生效
403
- sheet.setCellValue(B1, 20)
404
- expect(sheet.getCellData(C1)).toMatchObject({ v: 21 })
405
- })
406
-
407
- it('同公式重复输入 = 无操作(不入历史)', () => {
408
- const sheet = new Sheet()
409
- sheet.setCellValue(A1, 1)
410
- sheet.setCellFormula(B1, '=A1*2')
411
- const depth = sheet.history.undoSize
412
-
413
- sheet.setCellFormula(B1, '=A1*2')
414
- expect(sheet.history.undoSize).toBe(depth)
415
- expect(sheet.getCellData(B1)).toMatchObject({ v: 2 })
416
- })
417
-
418
- it("'=' 单独输入 = 清除单元格", () => {
419
- const sheet = new Sheet()
420
- sheet.setCellValue(A1, 5)
421
- sheet.setCellValue(A1, '=')
422
- expect(sheet.getCellData(A1)).toBeUndefined()
423
- // 空格输入 '=' 也是无操作
424
- expect(sheet.canUndo).toBe(true) // 仍有上面两条历史
425
- sheet.setCellValue(B1, '=')
426
- expect(sheet.getCellData(B1)).toBeUndefined()
427
- })
428
-
429
- it('A1:A1 单格区域', () => {
430
- const sheet = new Sheet()
431
- sheet.setCellValue(A1, 42)
432
- sheet.setCellFormula(B1, '=SUM(A1:A1)')
433
- expect(sheet.getCellData(B1)).toMatchObject({ v: 42 })
434
- })
435
-
436
- it('公式引用空区域 → SUM 为 0、COUNT 为 0、AVERAGE #DIV/0!', () => {
437
- const sheet = new Sheet()
438
- sheet.setCellFormula(A1, '=SUM(D1:E9)')
439
- sheet.setCellFormula(B1, '=COUNT(D1:E9)')
440
- sheet.setCellFormula(C1, '=AVERAGE(D1:E9)')
441
- expect(sheet.getCellData(A1)).toMatchObject({ v: 0 })
442
- expect(sheet.getCellData(B1)).toMatchObject({ v: 0 })
443
- expect(sheet.getCellData(C1)).toMatchObject({ v: '#DIV/0!' })
444
- })
445
-
446
- it('批量写入(粘贴场景):重算派生并入同一 undo 单元', () => {
447
- const sheet = new Sheet()
448
- sheet.setCellFormula(C1, '=A1+B1')
449
- sheet.history.clear()
450
-
451
- sheet.setCells([
452
- { addr: A1, data: { v: 1, t: 'n' } },
453
- { addr: B1, data: { v: 2, t: 'n' } }
454
- ])
455
- expect(sheet.getCellData(C1)).toMatchObject({ v: 3 })
456
- expect(sheet.history.undoSize).toBe(1)
457
-
458
- sheet.undo()
459
- expect(sheet.getCellData(A1)).toBeUndefined()
460
- expect(sheet.getCellData(B1)).toBeUndefined()
461
- expect(sheet.getCellData(C1)).toMatchObject({ v: 0 })
462
- })
463
-
464
- it('setCell 直接写带 f 的 CellData 同样走重算', () => {
465
- const sheet = new Sheet()
466
- sheet.setCellValue(A1, 6)
467
- sheet.setCell(B1, { f: 'A1*2' })
468
- expect(sheet.getCellData(B1)).toMatchObject({ f: 'A1*2', v: 12, t: 'n' })
469
- })
470
- })
@@ -1,178 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
-
3
- import type { CellAddress } from '../address'
4
- import { Sheet } from '../sheet'
5
-
6
- const A1 = { row: 0, col: 0 }
7
-
8
- /** 写入公式并读回计算缓存值 */
9
- function calcValue(sheet: Sheet, formula: string, addr: CellAddress = { row: 20, col: 20 }) {
10
- sheet.setCellFormula(addr, formula)
11
- return sheet.getCellData(addr)
12
- }
13
-
14
- describe('函数集:SUM / AVERAGE / MAX / MIN', () => {
15
- it('SUM:直接参数求和、数字文本强转、非法文本 #VALUE!', () => {
16
- const sheet = new Sheet()
17
- expect(calcValue(sheet, '=SUM(1,2,3)')).toMatchObject({ v: 6 })
18
- expect(calcValue(sheet, '=SUM("5",3)')).toMatchObject({ v: 8 })
19
- expect(calcValue(sheet, '=SUM("abc")')).toMatchObject({ v: '#VALUE!', t: 'e' })
20
- })
21
-
22
- it('SUM:区域内文本/布尔忽略,空格按 0', () => {
23
- const sheet = new Sheet()
24
- sheet.setCellValue(A1, 2)
25
- sheet.setCellValue({ row: 1, col: 0 }, 'text')
26
- sheet.setCellValue({ row: 2, col: 0 }, true)
27
- expect(calcValue(sheet, '=SUM(A1:A5)')).toMatchObject({ v: 2 })
28
- // 全空区域 → 0
29
- expect(calcValue(sheet, '=SUM(C1:C9)')).toMatchObject({ v: 0 })
30
- })
31
-
32
- it('AVERAGE:均值;无数字 → #DIV/0!', () => {
33
- const sheet = new Sheet()
34
- expect(calcValue(sheet, '=AVERAGE(2,4)')).toMatchObject({ v: 3 })
35
- expect(calcValue(sheet, '=AVERAGE(C1:C9)')).toMatchObject({ v: '#DIV/0!', t: 'e' })
36
- sheet.setCellValue(A1, 2)
37
- sheet.setCellValue({ row: 1, col: 0 }, 'text')
38
- // 区域内文本忽略,只按数字格求均值
39
- expect(calcValue(sheet, '=AVERAGE(A1:A2)')).toMatchObject({ v: 2 })
40
- })
41
-
42
- it('MAX / MIN:极值;无数字 → 0', () => {
43
- const sheet = new Sheet()
44
- expect(calcValue(sheet, '=MAX(1,9,3)')).toMatchObject({ v: 9 })
45
- expect(calcValue(sheet, '=MIN(1,-9,3)')).toMatchObject({ v: -9 })
46
- expect(calcValue(sheet, '=MAX(C1:C9)')).toMatchObject({ v: 0 })
47
- expect(calcValue(sheet, '=MIN(C1:C9)')).toMatchObject({ v: 0 })
48
- })
49
- })
50
-
51
- describe('函数集:COUNT / COUNTA', () => {
52
- it('COUNT 只数数字(区域内文本/空格不计;直接参数可强转即计)', () => {
53
- const sheet = new Sheet()
54
- sheet.setCellValue(A1, 1)
55
- sheet.setCellValue({ row: 1, col: 0 }, 'text')
56
- sheet.setCellValue({ row: 2, col: 0 }, true)
57
- expect(calcValue(sheet, '=COUNT(A1:A5)')).toMatchObject({ v: 1 })
58
- expect(calcValue(sheet, '=COUNT(1,"x","5",TRUE)')).toMatchObject({ v: 3 })
59
- })
60
-
61
- it('COUNTA 数非空(文本/布尔/空串结果都计,空格不计)', () => {
62
- const sheet = new Sheet()
63
- sheet.setCellValue(A1, 1)
64
- sheet.setCellValue({ row: 1, col: 0 }, 'text')
65
- sheet.setCellValue({ row: 2, col: 0 }, true)
66
- expect(calcValue(sheet, '=COUNTA(A1:A5)')).toMatchObject({ v: 3 })
67
- })
68
- })
69
-
70
- describe('函数集:IF / AND / OR / NOT', () => {
71
- it('IF:分支选择;缺省 else → FALSE;条件非法 → #VALUE!', () => {
72
- const sheet = new Sheet()
73
- expect(calcValue(sheet, '=IF(1>0,"y","n")')).toMatchObject({ v: 'y' })
74
- expect(calcValue(sheet, '=IF(0,1,2)')).toMatchObject({ v: 2 })
75
- expect(calcValue(sheet, '=IF(1=1,7)')).toMatchObject({ v: 7 })
76
- expect(calcValue(sheet, '=IF(0,7)')).toMatchObject({ v: false, t: 'b' })
77
- expect(calcValue(sheet, '=IF("abc",1,2)')).toMatchObject({ v: '#VALUE!', t: 'e' })
78
- })
79
-
80
- it('IF 惰性求值:未选分支的除零不产生错误', () => {
81
- const sheet = new Sheet()
82
- expect(calcValue(sheet, '=IF(FALSE,1/0,2)')).toMatchObject({ v: 2 })
83
- expect(calcValue(sheet, '=IF(TRUE,1,1/0)')).toMatchObject({ v: 1 })
84
- // 条件本身是错误则传播
85
- expect(calcValue(sheet, '=IF(1/0,1,2)')).toMatchObject({ v: '#DIV/0!', t: 'e' })
86
- })
87
-
88
- it('AND / OR / NOT:布尔逻辑与强转', () => {
89
- const sheet = new Sheet()
90
- expect(calcValue(sheet, '=AND(1,TRUE)')).toMatchObject({ v: true })
91
- expect(calcValue(sheet, '=AND(1,0)')).toMatchObject({ v: false })
92
- expect(calcValue(sheet, '=OR(0,FALSE)')).toMatchObject({ v: false })
93
- expect(calcValue(sheet, '=OR(0,1)')).toMatchObject({ v: true })
94
- expect(calcValue(sheet, '=NOT(0)')).toMatchObject({ v: true })
95
- expect(calcValue(sheet, '=NOT(TRUE)')).toMatchObject({ v: false })
96
- // 无有效操作数 / 非法文本 → #VALUE!
97
- expect(calcValue(sheet, '=AND(C1:C9)')).toMatchObject({ v: '#VALUE!', t: 'e' })
98
- expect(calcValue(sheet, '=OR("x")')).toMatchObject({ v: '#VALUE!', t: 'e' })
99
- expect(calcValue(sheet, '=NOT("x")')).toMatchObject({ v: '#VALUE!', t: 'e' })
100
- // 区域内只取布尔格
101
- sheet.setCellValue(A1, true)
102
- sheet.setCellValue({ row: 1, col: 0 }, 5)
103
- expect(calcValue(sheet, '=AND(A1:A2)')).toMatchObject({ v: true })
104
- })
105
- })
106
-
107
- describe('函数集:ROUND / ABS / CONCATENATE', () => {
108
- it('ROUND:精度、负数位数、远离零取整', () => {
109
- const sheet = new Sheet()
110
- expect(calcValue(sheet, '=ROUND(3.14159,2)')).toMatchObject({ v: 3.14 })
111
- expect(calcValue(sheet, '=ROUND(2.5,0)')).toMatchObject({ v: 3 })
112
- expect(calcValue(sheet, '=ROUND(-2.5,0)')).toMatchObject({ v: -3 })
113
- expect(calcValue(sheet, '=ROUND(1234.567,-2)')).toMatchObject({ v: 1200 })
114
- // 浮点表示误差补偿(2.675 实际存储为 2.67499…)
115
- expect(calcValue(sheet, '=ROUND(2.675,2)')).toMatchObject({ v: 2.68 })
116
- })
117
-
118
- it('ABS:绝对值;非法参数 → #VALUE!', () => {
119
- const sheet = new Sheet()
120
- expect(calcValue(sheet, '=ABS(-3)')).toMatchObject({ v: 3 })
121
- expect(calcValue(sheet, '=ABS("x")')).toMatchObject({ v: '#VALUE!', t: 'e' })
122
- })
123
-
124
- it('CONCATENATE:文本拼接(数字/布尔强转,区域展开,空格按空串)', () => {
125
- const sheet = new Sheet()
126
- expect(calcValue(sheet, '=CONCATENATE("a",1,TRUE)')).toMatchObject({ v: 'a1TRUE' })
127
- sheet.setCellValue(A1, 'x')
128
- sheet.setCellValue({ row: 2, col: 0 }, 'z')
129
- // A2 为空格 → 空串
130
- expect(calcValue(sheet, '=CONCATENATE(A1:A3)')).toMatchObject({ v: 'xz' })
131
- })
132
- })
133
-
134
- describe('函数集:通用语义', () => {
135
- it('嵌套函数与多层括号', () => {
136
- const sheet = new Sheet()
137
- sheet.setCellValue(A1, 1)
138
- sheet.setCellValue({ row: 1, col: 0 }, 2)
139
- sheet.setCellValue({ row: 2, col: 0 }, 3)
140
- sheet.setCellValue({ row: 0, col: 1 }, 8)
141
- sheet.setCellValue({ row: 0, col: 2 }, 4)
142
- expect(calcValue(sheet, '=SUM(A1:A3, MAX(B1, MIN(C1, 10))) * 2')).toMatchObject({ v: 28 })
143
- expect(calcValue(sheet, '=((1+2)*(3+4))/(7-2)')).toMatchObject({ v: 4.2 })
144
- })
145
-
146
- it('参数个数非法 → #VALUE!;未知函数 → #NAME?', () => {
147
- const sheet = new Sheet()
148
- expect(calcValue(sheet, '=IF(1)')).toMatchObject({ v: '#VALUE!', t: 'e' })
149
- expect(calcValue(sheet, '=ROUND(1)')).toMatchObject({ v: '#VALUE!', t: 'e' })
150
- expect(calcValue(sheet, '=ABS(1,2)')).toMatchObject({ v: '#VALUE!', t: 'e' })
151
- expect(calcValue(sheet, '=SUM()')).toMatchObject({ v: '#VALUE!', t: 'e' })
152
- expect(calcValue(sheet, '=NOSUCHFN(1)')).toMatchObject({ v: '#NAME?', t: 'e' })
153
- })
154
-
155
- it('函数名大小写不敏感', () => {
156
- const sheet = new Sheet()
157
- expect(calcValue(sheet, '=sum(1,2)')).toMatchObject({ v: 3 })
158
- expect(calcValue(sheet, '=If(1,2,3)')).toMatchObject({ v: 2 })
159
- })
160
-
161
- it('区域内错误值传播', () => {
162
- const sheet = new Sheet()
163
- sheet.setCellFormula(A1, '=1/0')
164
- sheet.setCellValue({ row: 1, col: 0 }, 5)
165
- expect(calcValue(sheet, '=SUM(A1:A2)')).toMatchObject({ v: '#DIV/0!', t: 'e' })
166
- })
167
-
168
- it('稀疏性:大区域内只有少量格参与迭代', () => {
169
- const sheet = new Sheet()
170
- sheet.setCellValue(A1, 1)
171
- sheet.setCellValue({ row: 9999, col: 0 }, 2)
172
- // A1:A10000 只有 2 个真实格;结果与迭代规模无关
173
- expect(sheet.store.size).toBe(2)
174
- expect(calcValue(sheet, '=SUM(A1:A10000)')).toMatchObject({ v: 3 })
175
- expect(calcValue(sheet, '=COUNT(A1:A10000)')).toMatchObject({ v: 2 })
176
- expect(calcValue(sheet, '=AVERAGE(A1:A10000)')).toMatchObject({ v: 1.5 })
177
- })
178
- })