@dizzlkheinz/ynab-mcpb 0.18.3 → 0.19.0

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 (346) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/CLAUDE.md +87 -8
  3. package/bin/ynab-mcp-server.cjs +2 -2
  4. package/bin/ynab-mcp-server.js +3 -3
  5. package/biome.json +39 -0
  6. package/dist/bundle/index.cjs +67 -67
  7. package/dist/index.d.ts +1 -1
  8. package/dist/index.js +27 -27
  9. package/dist/server/YNABMCPServer.d.ts +3 -4
  10. package/dist/server/YNABMCPServer.js +111 -116
  11. package/dist/server/budgetResolver.d.ts +6 -5
  12. package/dist/server/budgetResolver.js +46 -36
  13. package/dist/server/cacheKeys.js +6 -6
  14. package/dist/server/cacheManager.js +14 -11
  15. package/dist/server/completions.d.ts +2 -2
  16. package/dist/server/completions.js +20 -15
  17. package/dist/server/config.d.ts +10 -5
  18. package/dist/server/config.js +24 -7
  19. package/dist/server/deltaCache.d.ts +2 -2
  20. package/dist/server/deltaCache.js +22 -16
  21. package/dist/server/deltaCache.merge.d.ts +2 -2
  22. package/dist/server/diagnostics.d.ts +4 -4
  23. package/dist/server/diagnostics.js +38 -32
  24. package/dist/server/errorHandler.d.ts +5 -12
  25. package/dist/server/errorHandler.js +219 -217
  26. package/dist/server/prompts.d.ts +2 -2
  27. package/dist/server/prompts.js +45 -45
  28. package/dist/server/rateLimiter.js +4 -4
  29. package/dist/server/requestLogger.d.ts +1 -1
  30. package/dist/server/requestLogger.js +40 -35
  31. package/dist/server/resources.d.ts +3 -3
  32. package/dist/server/resources.js +55 -52
  33. package/dist/server/responseFormatter.js +6 -6
  34. package/dist/server/securityMiddleware.d.ts +2 -2
  35. package/dist/server/securityMiddleware.js +22 -20
  36. package/dist/server/serverKnowledgeStore.js +1 -1
  37. package/dist/server/toolRegistry.d.ts +3 -3
  38. package/dist/server/toolRegistry.js +47 -40
  39. package/dist/tools/__tests__/deltaTestUtils.d.ts +3 -3
  40. package/dist/tools/__tests__/deltaTestUtils.js +2 -2
  41. package/dist/tools/accountTools.d.ts +9 -8
  42. package/dist/tools/accountTools.js +47 -47
  43. package/dist/tools/adapters.d.ts +13 -8
  44. package/dist/tools/adapters.js +21 -11
  45. package/dist/tools/budgetTools.d.ts +8 -7
  46. package/dist/tools/budgetTools.js +22 -22
  47. package/dist/tools/categoryTools.d.ts +9 -8
  48. package/dist/tools/categoryTools.js +68 -59
  49. package/dist/tools/compareTransactions/formatter.d.ts +3 -3
  50. package/dist/tools/compareTransactions/formatter.js +9 -9
  51. package/dist/tools/compareTransactions/index.d.ts +6 -6
  52. package/dist/tools/compareTransactions/index.js +58 -43
  53. package/dist/tools/compareTransactions/matcher.d.ts +1 -1
  54. package/dist/tools/compareTransactions/matcher.js +28 -15
  55. package/dist/tools/compareTransactions/parser.d.ts +2 -2
  56. package/dist/tools/compareTransactions/parser.js +144 -138
  57. package/dist/tools/compareTransactions/types.d.ts +4 -4
  58. package/dist/tools/compareTransactions.d.ts +1 -1
  59. package/dist/tools/compareTransactions.js +1 -1
  60. package/dist/tools/deltaFetcher.d.ts +2 -2
  61. package/dist/tools/deltaFetcher.js +16 -15
  62. package/dist/tools/deltaSupport.d.ts +4 -4
  63. package/dist/tools/deltaSupport.js +35 -41
  64. package/dist/tools/exportTransactions.d.ts +5 -4
  65. package/dist/tools/exportTransactions.js +61 -59
  66. package/dist/tools/monthTools.d.ts +7 -6
  67. package/dist/tools/monthTools.js +31 -29
  68. package/dist/tools/payeeTools.d.ts +7 -6
  69. package/dist/tools/payeeTools.js +28 -28
  70. package/dist/tools/reconcileAdapter.d.ts +2 -2
  71. package/dist/tools/reconcileAdapter.js +21 -11
  72. package/dist/tools/reconciliation/analyzer.d.ts +4 -4
  73. package/dist/tools/reconciliation/analyzer.js +136 -57
  74. package/dist/tools/reconciliation/csvParser.d.ts +3 -3
  75. package/dist/tools/reconciliation/csvParser.js +128 -104
  76. package/dist/tools/reconciliation/executor.d.ts +4 -4
  77. package/dist/tools/reconciliation/executor.js +148 -109
  78. package/dist/tools/reconciliation/index.d.ts +10 -10
  79. package/dist/tools/reconciliation/index.js +96 -83
  80. package/dist/tools/reconciliation/matcher.d.ts +3 -3
  81. package/dist/tools/reconciliation/matcher.js +17 -16
  82. package/dist/tools/reconciliation/payeeNormalizer.js +19 -8
  83. package/dist/tools/reconciliation/recommendationEngine.d.ts +1 -1
  84. package/dist/tools/reconciliation/recommendationEngine.js +40 -40
  85. package/dist/tools/reconciliation/reportFormatter.d.ts +2 -2
  86. package/dist/tools/reconciliation/reportFormatter.js +79 -54
  87. package/dist/tools/reconciliation/signDetector.d.ts +1 -1
  88. package/dist/tools/reconciliation/types.d.ts +19 -16
  89. package/dist/tools/reconciliation/ynabAdapter.d.ts +2 -2
  90. package/dist/tools/schemas/common.d.ts +1 -1
  91. package/dist/tools/schemas/common.js +1 -1
  92. package/dist/tools/schemas/outputs/accountOutputs.d.ts +1 -1
  93. package/dist/tools/schemas/outputs/accountOutputs.js +24 -18
  94. package/dist/tools/schemas/outputs/budgetOutputs.d.ts +1 -1
  95. package/dist/tools/schemas/outputs/budgetOutputs.js +14 -11
  96. package/dist/tools/schemas/outputs/categoryOutputs.d.ts +1 -1
  97. package/dist/tools/schemas/outputs/categoryOutputs.js +49 -29
  98. package/dist/tools/schemas/outputs/comparisonOutputs.d.ts +1 -1
  99. package/dist/tools/schemas/outputs/comparisonOutputs.js +12 -12
  100. package/dist/tools/schemas/outputs/index.d.ts +14 -14
  101. package/dist/tools/schemas/outputs/index.js +14 -14
  102. package/dist/tools/schemas/outputs/monthOutputs.d.ts +1 -1
  103. package/dist/tools/schemas/outputs/monthOutputs.js +56 -41
  104. package/dist/tools/schemas/outputs/payeeOutputs.d.ts +1 -1
  105. package/dist/tools/schemas/outputs/payeeOutputs.js +10 -10
  106. package/dist/tools/schemas/outputs/reconciliationOutputs.d.ts +2 -2
  107. package/dist/tools/schemas/outputs/reconciliationOutputs.js +45 -45
  108. package/dist/tools/schemas/outputs/transactionMutationOutputs.d.ts +1 -1
  109. package/dist/tools/schemas/outputs/transactionMutationOutputs.js +28 -22
  110. package/dist/tools/schemas/outputs/transactionOutputs.d.ts +1 -1
  111. package/dist/tools/schemas/outputs/transactionOutputs.js +43 -35
  112. package/dist/tools/schemas/outputs/utilityOutputs.d.ts +1 -1
  113. package/dist/tools/schemas/outputs/utilityOutputs.js +5 -3
  114. package/dist/tools/schemas/shared/commonOutputs.d.ts +1 -1
  115. package/dist/tools/schemas/shared/commonOutputs.js +15 -9
  116. package/dist/tools/transactionReadTools.d.ts +11 -0
  117. package/dist/tools/transactionReadTools.js +202 -0
  118. package/dist/tools/transactionSchemas.d.ts +309 -0
  119. package/dist/tools/transactionSchemas.js +235 -0
  120. package/dist/tools/transactionTools.d.ts +6 -302
  121. package/dist/tools/transactionTools.js +7 -2054
  122. package/dist/tools/transactionUtils.d.ts +31 -0
  123. package/dist/tools/transactionUtils.js +364 -0
  124. package/dist/tools/transactionWriteTools.d.ts +20 -0
  125. package/dist/tools/transactionWriteTools.js +1342 -0
  126. package/dist/tools/utilityTools.d.ts +5 -4
  127. package/dist/tools/utilityTools.js +11 -11
  128. package/dist/types/index.d.ts +7 -7
  129. package/dist/types/index.js +6 -6
  130. package/dist/types/reconciliation.d.ts +1 -1
  131. package/dist/types/toolRegistration.d.ts +14 -12
  132. package/dist/utils/amountUtils.js +1 -1
  133. package/dist/utils/dateUtils.js +4 -4
  134. package/dist/utils/errors.d.ts +3 -3
  135. package/dist/utils/errors.js +4 -4
  136. package/dist/utils/money.d.ts +2 -2
  137. package/dist/utils/money.js +8 -8
  138. package/dist/utils/validationError.d.ts +1 -1
  139. package/dist/utils/validationError.js +1 -1
  140. package/docs/assets/examples/reconciliation-with-recommendations.json +66 -66
  141. package/docs/assets/schemas/reconciliation-v2.json +360 -336
  142. package/docs/plans/2025-12-25-transaction-tools-refactor-design.md +211 -0
  143. package/docs/plans/2025-12-25-transaction-tools-refactor.md +905 -0
  144. package/esbuild.config.mjs +53 -50
  145. package/meta.json +12548 -12548
  146. package/package.json +98 -109
  147. package/scripts/analyze-bundle.mjs +33 -30
  148. package/scripts/create-pr-description.js +169 -120
  149. package/scripts/run-all-tests.js +205 -0
  150. package/scripts/run-domain-integration-tests.js +28 -18
  151. package/scripts/run-generate-mcpb.js +19 -17
  152. package/scripts/run-throttled-integration-tests.js +92 -83
  153. package/scripts/test-delta-params.mjs +149 -120
  154. package/scripts/test-recommendations.ts +36 -32
  155. package/scripts/tmpTransaction.ts +80 -43
  156. package/scripts/validate-env.js +98 -91
  157. package/scripts/verify-build.js +78 -76
  158. package/src/__tests__/comprehensive.integration.test.ts +1281 -1154
  159. package/src/__tests__/performance.test.ts +723 -671
  160. package/src/__tests__/setup.ts +442 -395
  161. package/src/__tests__/smoke.e2e.test.ts +41 -39
  162. package/src/__tests__/testRunner.ts +314 -295
  163. package/src/__tests__/testUtils.ts +456 -364
  164. package/src/__tests__/tools/reconciliation/csvParser.integration.test.ts +109 -107
  165. package/src/__tests__/tools/reconciliation/real-world.integration.test.ts +41 -41
  166. package/src/index.ts +68 -59
  167. package/src/server/CLAUDE.md +480 -0
  168. package/src/server/YNABMCPServer.ts +821 -794
  169. package/src/server/__tests__/YNABMCPServer.integration.test.ts +929 -893
  170. package/src/server/__tests__/YNABMCPServer.test.ts +903 -899
  171. package/src/server/__tests__/budgetResolver.test.ts +466 -423
  172. package/src/server/__tests__/cacheManager.test.ts +891 -874
  173. package/src/server/__tests__/completions.integration.test.ts +115 -106
  174. package/src/server/__tests__/completions.test.ts +334 -313
  175. package/src/server/__tests__/config.test.ts +98 -86
  176. package/src/server/__tests__/deltaCache.merge.test.ts +774 -703
  177. package/src/server/__tests__/deltaCache.swr.test.ts +198 -153
  178. package/src/server/__tests__/deltaCache.test.ts +946 -759
  179. package/src/server/__tests__/diagnostics.test.ts +825 -792
  180. package/src/server/__tests__/errorHandler.integration.test.ts +512 -462
  181. package/src/server/__tests__/errorHandler.test.ts +402 -397
  182. package/src/server/__tests__/prompts.test.ts +424 -347
  183. package/src/server/__tests__/rateLimiter.test.ts +313 -309
  184. package/src/server/__tests__/requestLogger.test.ts +443 -403
  185. package/src/server/__tests__/resources.template.test.ts +196 -185
  186. package/src/server/__tests__/resources.test.ts +294 -288
  187. package/src/server/__tests__/security.integration.test.ts +487 -421
  188. package/src/server/__tests__/securityMiddleware.test.ts +519 -444
  189. package/src/server/__tests__/server-startup.integration.test.ts +509 -490
  190. package/src/server/__tests__/serverKnowledgeStore.test.ts +174 -173
  191. package/src/server/__tests__/toolRegistration.test.ts +239 -210
  192. package/src/server/__tests__/toolRegistry.test.ts +907 -845
  193. package/src/server/budgetResolver.ts +221 -181
  194. package/src/server/cacheKeys.ts +6 -6
  195. package/src/server/cacheManager.ts +498 -484
  196. package/src/server/completions.ts +267 -243
  197. package/src/server/config.ts +35 -14
  198. package/src/server/deltaCache.merge.ts +146 -128
  199. package/src/server/deltaCache.ts +352 -309
  200. package/src/server/diagnostics.ts +257 -242
  201. package/src/server/errorHandler.ts +747 -744
  202. package/src/server/prompts.ts +181 -176
  203. package/src/server/rateLimiter.ts +131 -129
  204. package/src/server/requestLogger.ts +350 -322
  205. package/src/server/resources.ts +442 -374
  206. package/src/server/responseFormatter.ts +41 -37
  207. package/src/server/securityMiddleware.ts +223 -205
  208. package/src/server/serverKnowledgeStore.ts +67 -67
  209. package/src/server/toolRegistry.ts +508 -474
  210. package/src/tools/CLAUDE.md +604 -0
  211. package/src/tools/__tests__/accountTools.delta.integration.test.ts +128 -111
  212. package/src/tools/__tests__/accountTools.integration.test.ts +129 -111
  213. package/src/tools/__tests__/accountTools.test.ts +685 -638
  214. package/src/tools/__tests__/adapters.test.ts +142 -108
  215. package/src/tools/__tests__/budgetTools.delta.integration.test.ts +73 -73
  216. package/src/tools/__tests__/budgetTools.integration.test.ts +132 -124
  217. package/src/tools/__tests__/budgetTools.test.ts +442 -413
  218. package/src/tools/__tests__/categoryTools.delta.integration.test.ts +76 -68
  219. package/src/tools/__tests__/categoryTools.integration.test.ts +314 -288
  220. package/src/tools/__tests__/categoryTools.test.ts +656 -625
  221. package/src/tools/__tests__/compareTransactions/formatter.test.ts +535 -462
  222. package/src/tools/__tests__/compareTransactions/index.test.ts +378 -358
  223. package/src/tools/__tests__/compareTransactions/matcher.test.ts +497 -398
  224. package/src/tools/__tests__/compareTransactions/parser.test.ts +765 -747
  225. package/src/tools/__tests__/compareTransactions.test.ts +352 -332
  226. package/src/tools/__tests__/compareTransactions.window.test.ts +150 -146
  227. package/src/tools/__tests__/deltaFetcher.scheduled.integration.test.ts +69 -65
  228. package/src/tools/__tests__/deltaFetcher.test.ts +325 -265
  229. package/src/tools/__tests__/deltaSupport.test.ts +211 -184
  230. package/src/tools/__tests__/deltaTestUtils.ts +37 -33
  231. package/src/tools/__tests__/exportTransactions.test.ts +205 -200
  232. package/src/tools/__tests__/monthTools.delta.integration.test.ts +68 -68
  233. package/src/tools/__tests__/monthTools.integration.test.ts +178 -166
  234. package/src/tools/__tests__/monthTools.test.ts +561 -512
  235. package/src/tools/__tests__/payeeTools.delta.integration.test.ts +68 -68
  236. package/src/tools/__tests__/payeeTools.integration.test.ts +158 -142
  237. package/src/tools/__tests__/payeeTools.test.ts +486 -434
  238. package/src/tools/__tests__/transactionSchemas.test.ts +1204 -0
  239. package/src/tools/__tests__/transactionTools.integration.test.ts +875 -825
  240. package/src/tools/__tests__/transactionTools.test.ts +4923 -4366
  241. package/src/tools/__tests__/transactionUtils.test.ts +1016 -0
  242. package/src/tools/__tests__/utilityTools.integration.test.ts +32 -32
  243. package/src/tools/__tests__/utilityTools.test.ts +68 -58
  244. package/src/tools/accountTools.ts +293 -271
  245. package/src/tools/adapters.ts +120 -63
  246. package/src/tools/budgetTools.ts +121 -116
  247. package/src/tools/categoryTools.ts +379 -339
  248. package/src/tools/compareTransactions/formatter.ts +131 -119
  249. package/src/tools/compareTransactions/index.ts +249 -214
  250. package/src/tools/compareTransactions/matcher.ts +259 -209
  251. package/src/tools/compareTransactions/parser.ts +517 -487
  252. package/src/tools/compareTransactions/types.ts +38 -38
  253. package/src/tools/compareTransactions.ts +1 -1
  254. package/src/tools/deltaFetcher.ts +281 -260
  255. package/src/tools/deltaSupport.ts +264 -259
  256. package/src/tools/exportTransactions.ts +230 -218
  257. package/src/tools/monthTools.ts +180 -165
  258. package/src/tools/payeeTools.ts +152 -140
  259. package/src/tools/reconcileAdapter.ts +297 -246
  260. package/src/tools/reconciliation/CLAUDE.md +506 -0
  261. package/src/tools/reconciliation/__tests__/adapter.causes.test.ts +135 -112
  262. package/src/tools/reconciliation/__tests__/adapter.test.ts +249 -227
  263. package/src/tools/reconciliation/__tests__/analyzer.test.ts +408 -335
  264. package/src/tools/reconciliation/__tests__/csvParser.test.ts +71 -69
  265. package/src/tools/reconciliation/__tests__/executor.integration.test.ts +348 -323
  266. package/src/tools/reconciliation/__tests__/executor.progress.test.ts +503 -457
  267. package/src/tools/reconciliation/__tests__/executor.test.ts +898 -831
  268. package/src/tools/reconciliation/__tests__/matcher.test.ts +667 -663
  269. package/src/tools/reconciliation/__tests__/payeeNormalizer.test.ts +296 -276
  270. package/src/tools/reconciliation/__tests__/recommendationEngine.integration.test.ts +692 -624
  271. package/src/tools/reconciliation/__tests__/recommendationEngine.test.ts +1008 -986
  272. package/src/tools/reconciliation/__tests__/reconciliation.delta.integration.test.ts +187 -146
  273. package/src/tools/reconciliation/__tests__/reportFormatter.test.ts +583 -530
  274. package/src/tools/reconciliation/__tests__/scenarios/adapterCurrency.scenario.test.ts +75 -71
  275. package/src/tools/reconciliation/__tests__/scenarios/extremes.scenario.test.ts +70 -58
  276. package/src/tools/reconciliation/__tests__/scenarios/repeatAmount.scenario.test.ts +102 -88
  277. package/src/tools/reconciliation/__tests__/schemaUrl.test.ts +58 -43
  278. package/src/tools/reconciliation/__tests__/signDetector.test.ts +209 -206
  279. package/src/tools/reconciliation/__tests__/ynabAdapter.test.ts +66 -60
  280. package/src/tools/reconciliation/analyzer.ts +582 -406
  281. package/src/tools/reconciliation/csvParser.ts +656 -609
  282. package/src/tools/reconciliation/executor.ts +1290 -1128
  283. package/src/tools/reconciliation/index.ts +580 -528
  284. package/src/tools/reconciliation/matcher.ts +256 -240
  285. package/src/tools/reconciliation/payeeNormalizer.ts +92 -78
  286. package/src/tools/reconciliation/recommendationEngine.ts +357 -345
  287. package/src/tools/reconciliation/reportFormatter.ts +349 -276
  288. package/src/tools/reconciliation/signDetector.ts +89 -83
  289. package/src/tools/reconciliation/types.ts +164 -153
  290. package/src/tools/reconciliation/ynabAdapter.ts +17 -15
  291. package/src/tools/schemas/CLAUDE.md +546 -0
  292. package/src/tools/schemas/common.ts +1 -1
  293. package/src/tools/schemas/outputs/__tests__/accountOutputs.test.ts +410 -409
  294. package/src/tools/schemas/outputs/__tests__/budgetOutputs.test.ts +305 -299
  295. package/src/tools/schemas/outputs/__tests__/categoryOutputs.test.ts +431 -430
  296. package/src/tools/schemas/outputs/__tests__/comparisonOutputs.test.ts +510 -495
  297. package/src/tools/schemas/outputs/__tests__/dateValidation.test.ts +179 -153
  298. package/src/tools/schemas/outputs/__tests__/discrepancyDirection.test.ts +293 -254
  299. package/src/tools/schemas/outputs/__tests__/monthOutputs.test.ts +457 -457
  300. package/src/tools/schemas/outputs/__tests__/payeeOutputs.test.ts +362 -356
  301. package/src/tools/schemas/outputs/__tests__/reconciliationOutputs.test.ts +402 -399
  302. package/src/tools/schemas/outputs/__tests__/transactionMutationSchemas.test.ts +225 -211
  303. package/src/tools/schemas/outputs/__tests__/transactionOutputs.test.ts +457 -454
  304. package/src/tools/schemas/outputs/__tests__/utilityOutputs.test.ts +316 -315
  305. package/src/tools/schemas/outputs/accountOutputs.ts +40 -34
  306. package/src/tools/schemas/outputs/budgetOutputs.ts +24 -19
  307. package/src/tools/schemas/outputs/categoryOutputs.ts +76 -56
  308. package/src/tools/schemas/outputs/comparisonOutputs.ts +192 -169
  309. package/src/tools/schemas/outputs/index.ts +163 -163
  310. package/src/tools/schemas/outputs/monthOutputs.ts +95 -80
  311. package/src/tools/schemas/outputs/payeeOutputs.ts +18 -18
  312. package/src/tools/schemas/outputs/reconciliationOutputs.ts +386 -373
  313. package/src/tools/schemas/outputs/transactionMutationOutputs.ts +259 -231
  314. package/src/tools/schemas/outputs/transactionOutputs.ts +81 -71
  315. package/src/tools/schemas/outputs/utilityOutputs.ts +90 -84
  316. package/src/tools/schemas/shared/commonOutputs.ts +27 -19
  317. package/src/tools/toolCategories.ts +114 -114
  318. package/src/tools/transactionReadTools.ts +327 -0
  319. package/src/tools/transactionSchemas.ts +484 -0
  320. package/src/tools/transactionTools.ts +107 -2990
  321. package/src/tools/transactionUtils.ts +621 -0
  322. package/src/tools/transactionWriteTools.ts +2110 -0
  323. package/src/tools/utilityTools.ts +46 -41
  324. package/src/types/CLAUDE.md +477 -0
  325. package/src/types/__tests__/index.test.ts +51 -51
  326. package/src/types/index.ts +43 -39
  327. package/src/types/integration-tests.d.ts +26 -26
  328. package/src/types/reconciliation.ts +29 -29
  329. package/src/types/toolAnnotations.ts +30 -30
  330. package/src/types/toolRegistration.ts +43 -32
  331. package/src/utils/CLAUDE.md +508 -0
  332. package/src/utils/__tests__/dateUtils.test.ts +174 -168
  333. package/src/utils/__tests__/money.test.ts +193 -187
  334. package/src/utils/amountUtils.ts +5 -5
  335. package/src/utils/baseError.ts +5 -5
  336. package/src/utils/dateUtils.ts +29 -26
  337. package/src/utils/errors.ts +14 -14
  338. package/src/utils/money.ts +66 -52
  339. package/src/utils/validationError.ts +1 -1
  340. package/tsconfig.json +29 -29
  341. package/tsconfig.prod.json +16 -16
  342. package/vitest-reporters/split-json-reporter.ts +247 -204
  343. package/vitest.config.ts +99 -95
  344. package/.prettierignore +0 -10
  345. package/.prettierrc.json +0 -10
  346. package/eslint.config.js +0 -49
@@ -1,340 +1,413 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import { analyzeReconciliation } from '../analyzer.js';
3
- import type { Transaction as YNABAPITransaction } from 'ynab';
4
- import * as csvParser from '../csvParser.js';
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import type { Transaction as YNABAPITransaction } from "ynab";
3
+ import { analyzeReconciliation } from "../analyzer.js";
4
+ import * as csvParser from "../csvParser.js";
5
5
 
6
6
  // Mock the parser module
7
- vi.mock('../csvParser.js', () => ({
8
- parseCSV: vi.fn(),
7
+ vi.mock("../csvParser.js", () => ({
8
+ parseCSV: vi.fn(),
9
9
  }));
10
10
 
11
- describe('analyzer', () => {
12
- beforeEach(() => {
13
- vi.clearAllMocks();
14
- });
15
-
16
- describe('analyzeReconciliation', () => {
17
- it('should perform full analysis and return structured results', () => {
18
- // Mock CSV parsing
19
- vi.mocked(csvParser.parseCSV).mockReturnValue({
20
- transactions: [
21
- {
22
- id: 'b1',
23
- date: '2025-10-15',
24
- amount: -45230, // milliunits
25
- payee: 'Shell Gas',
26
- memo: '',
27
- sourceRow: 1,
28
- raw: { date: '10/15/2025', amount: '-45.23', description: 'Shell Gas' },
29
- },
30
- {
31
- id: 'b2',
32
- date: '2025-10-16',
33
- amount: -100000, // milliunits
34
- payee: 'Netflix',
35
- memo: '',
36
- sourceRow: 2,
37
- raw: { date: '10/16/2025', amount: '-100.00', description: 'Netflix' },
38
- },
39
- ],
40
- meta: {
41
- detectedDelimiter: ',',
42
- detectedColumns: ['Date', 'Amount', 'Description'],
43
- totalRows: 2,
44
- validRows: 2,
45
- skippedRows: 0,
46
- },
47
- errors: [],
48
- warnings: [],
49
- });
50
-
51
- const ynabTxns: YNABAPITransaction[] = [
52
- {
53
- id: 'y1',
54
- date: '2025-10-15',
55
- amount: -45230,
56
- payee_name: 'Shell',
57
- category_name: 'Auto: Gas',
58
- cleared: 'uncleared' as const,
59
- approved: true,
60
- } as YNABAPITransaction,
61
- {
62
- id: 'y2',
63
- date: '2025-10-16',
64
- amount: -100000,
65
- payee_name: 'Netflix',
66
- category_name: 'Entertainment',
67
- cleared: 'uncleared' as const,
68
- approved: true,
69
- } as YNABAPITransaction,
70
- ];
71
-
72
- const result = analyzeReconciliation(
73
- 'csv content',
74
- undefined,
75
- ynabTxns,
76
- -145.23, // Target balance
77
- );
78
-
79
- expect(result.success).toBe(true);
80
- expect(result.phase).toBe('analysis');
81
- expect(result.summary).toBeDefined();
82
- expect(result.auto_matches).toBeDefined();
83
- expect(result.suggested_matches).toBeDefined();
84
- expect(result.unmatched_bank).toBeDefined();
85
- expect(result.unmatched_ynab).toBeDefined();
86
- expect(result.balance_info).toBeDefined();
87
- expect(result.next_steps).toBeDefined();
88
-
89
- // Verify auto-matches (exact matches)
90
- expect(result.auto_matches.length).toBe(2);
91
- });
92
-
93
- it('should categorize high-confidence matches as auto-matches', () => {
94
- vi.mocked(csvParser.parseCSV).mockReturnValue({
95
- transactions: [
96
- {
97
- id: 'b1',
98
- date: '2025-10-15',
99
- amount: -50000,
100
- payee: 'Coffee Shop',
101
- memo: '',
102
- sourceRow: 1,
103
- raw: {} as any,
104
- },
105
- ],
106
- meta: {
107
- detectedDelimiter: ',',
108
- detectedColumns: [],
109
- totalRows: 1,
110
- validRows: 1,
111
- skippedRows: 0,
112
- },
113
- errors: [],
114
- warnings: [],
115
- });
116
-
117
- const ynabTxns: YNABAPITransaction[] = [
118
- {
119
- id: 'y1',
120
- date: '2025-10-15',
121
- amount: -50000,
122
- payee_name: 'Coffee Shop',
123
- category_name: 'Dining',
124
- cleared: 'uncleared' as const,
125
- approved: true,
126
- } as YNABAPITransaction,
127
- ];
128
-
129
- const result = analyzeReconciliation('csv', undefined, ynabTxns, -50.0);
130
-
131
- expect(result.auto_matches.length).toBeGreaterThan(0);
132
- expect(result.auto_matches[0].confidence).toBe('high');
133
- });
134
-
135
- it('should categorize medium-confidence matches as suggested', () => {
136
- vi.mocked(csvParser.parseCSV).mockReturnValue({
137
- transactions: [
138
- {
139
- id: 'b1',
140
- date: '2025-10-15',
141
- amount: -50000,
142
- payee: 'Generic Store',
143
- memo: '',
144
- sourceRow: 1,
145
- raw: {} as any,
146
- },
147
- ],
148
- meta: {
149
- detectedDelimiter: ',',
150
- detectedColumns: [],
151
- totalRows: 1,
152
- validRows: 1,
153
- skippedRows: 0,
154
- },
155
- errors: [],
156
- warnings: [],
157
- });
158
-
159
- const ynabTxns: YNABAPITransaction[] = [
160
- {
161
- id: 'y1',
162
- date: '2025-10-18', // 3 days difference - date score drops
163
- amount: -50000,
164
- payee_name: 'Amazon Prime', // Fuzzy match
165
- category_name: 'Shopping',
166
- cleared: 'uncleared' as const,
167
- approved: true,
168
- } as YNABAPITransaction,
169
- ];
170
-
171
- const result = analyzeReconciliation('csv', undefined, ynabTxns, -50.0);
172
-
173
- // Should be suggested (medium)
174
- expect(result.suggested_matches.length).toBeGreaterThan(0);
175
- expect(result.suggested_matches[0].confidence).toBe('medium');
176
- });
177
-
178
- it('should identify unmatched bank transactions', () => {
179
- vi.mocked(csvParser.parseCSV).mockReturnValue({
180
- transactions: [
181
- {
182
- id: 'b1',
183
- date: '2025-10-15',
184
- amount: -15990,
185
- payee: 'New Store',
186
- memo: '',
187
- sourceRow: 1,
188
- raw: {} as any,
189
- },
190
- ],
191
- meta: {
192
- detectedDelimiter: ',',
193
- detectedColumns: [],
194
- totalRows: 1,
195
- validRows: 1,
196
- skippedRows: 0,
197
- },
198
- errors: [],
199
- warnings: [],
200
- });
201
-
202
- const ynabTxns: YNABAPITransaction[] = [];
203
-
204
- const result = analyzeReconciliation('csv', undefined, ynabTxns, 0);
205
-
206
- expect(result.unmatched_bank.length).toBe(1);
207
- expect(result.unmatched_bank[0].payee).toBe('New Store');
208
- });
209
-
210
- it('should identify unmatched YNAB transactions', () => {
211
- vi.mocked(csvParser.parseCSV).mockReturnValue({
212
- transactions: [],
213
- meta: {
214
- detectedDelimiter: ',',
215
- detectedColumns: [],
216
- totalRows: 0,
217
- validRows: 0,
218
- skippedRows: 0,
219
- },
220
- errors: [],
221
- warnings: [],
222
- });
223
-
224
- const ynabTxns: YNABAPITransaction[] = [
225
- {
226
- id: 'y1',
227
- date: '2025-10-15',
228
- amount: -50000,
229
- payee_name: 'Restaurant',
230
- category_name: 'Dining',
231
- cleared: 'uncleared' as const,
232
- approved: true,
233
- } as YNABAPITransaction,
234
- ];
235
-
236
- const result = analyzeReconciliation('csv', undefined, ynabTxns, 0);
237
-
238
- expect(result.unmatched_ynab.length).toBe(1);
239
- expect(result.unmatched_ynab[0].payee).toBe('Restaurant');
240
- });
241
-
242
- it('should calculate balance information correctly', () => {
243
- vi.mocked(csvParser.parseCSV).mockReturnValue({
244
- transactions: [],
245
- meta: {
246
- detectedDelimiter: ',',
247
- detectedColumns: [],
248
- totalRows: 0,
249
- validRows: 0,
250
- skippedRows: 0,
251
- },
252
- errors: [],
253
- warnings: [],
254
- });
255
-
256
- const ynabTxns: YNABAPITransaction[] = [
257
- {
258
- id: 'y1',
259
- date: '2025-10-15',
260
- amount: -50000, // -$50.00 cleared
261
- payee_name: 'Store',
262
- category_name: 'Shopping',
263
- cleared: 'cleared' as const,
264
- approved: true,
265
- } as YNABAPITransaction,
266
- {
267
- id: 'y2',
268
- date: '2025-10-16',
269
- amount: -30000, // -$30.00 uncleared
270
- payee_name: 'Restaurant',
271
- category_name: 'Dining',
272
- cleared: 'uncleared' as const,
273
- approved: true,
274
- } as YNABAPITransaction,
275
- ];
276
-
277
- const result = analyzeReconciliation('csv', undefined, ynabTxns, -50.0);
278
-
279
- expect(result.balance_info.current_cleared.value).toBe(-50.0);
280
- expect(result.balance_info.current_uncleared.value).toBe(-30.0);
281
- expect(result.balance_info.current_total.value).toBe(-80.0);
282
- expect(result.balance_info.target_statement.value).toBe(-50.0);
283
- expect(result.balance_info.discrepancy.value).toBe(0);
284
- expect(result.balance_info.on_track).toBe(true);
285
- });
286
-
287
- it('should generate appropriate summary', () => {
288
- vi.mocked(csvParser.parseCSV).mockReturnValue({
289
- transactions: [
290
- {
291
- id: 'b1',
292
- date: '2025-10-15',
293
- amount: -50000,
294
- payee: 'Store',
295
- memo: '',
296
- sourceRow: 1,
297
- raw: {} as any,
298
- },
299
- {
300
- id: 'b2',
301
- date: '2025-10-20',
302
- amount: -30000,
303
- payee: 'Restaurant',
304
- memo: '',
305
- sourceRow: 2,
306
- raw: {} as any,
307
- },
308
- ],
309
- meta: {
310
- detectedDelimiter: ',',
311
- detectedColumns: [],
312
- totalRows: 2,
313
- validRows: 2,
314
- skippedRows: 0,
315
- },
316
- errors: [],
317
- warnings: [],
318
- });
319
-
320
- const ynabTxns: YNABAPITransaction[] = [
321
- {
322
- id: 'y1',
323
- date: '2025-10-15',
324
- amount: -50000,
325
- payee_name: 'Store',
326
- category_name: 'Shopping',
327
- cleared: 'uncleared' as const,
328
- approved: true,
329
- } as YNABAPITransaction,
330
- ];
331
-
332
- const result = analyzeReconciliation('csv', undefined, ynabTxns, -80.0);
333
-
334
- expect(result.summary.bank_transactions_count).toBe(2);
335
- expect(result.summary.ynab_transactions_count).toBe(1);
336
- expect(result.summary.statement_date_range).toContain('2025-10-15');
337
- expect(result.summary.statement_date_range).toContain('2025-10-20');
338
- });
339
- });
11
+ describe("analyzer", () => {
12
+ beforeEach(() => {
13
+ vi.clearAllMocks();
14
+ });
15
+
16
+ describe("analyzeReconciliation", () => {
17
+ it("should perform full analysis and return structured results", () => {
18
+ // Mock CSV parsing
19
+ vi.mocked(csvParser.parseCSV).mockReturnValue({
20
+ transactions: [
21
+ {
22
+ id: "b1",
23
+ date: "2025-10-15",
24
+ amount: -45230, // milliunits
25
+ payee: "Shell Gas",
26
+ memo: "",
27
+ sourceRow: 1,
28
+ raw: {
29
+ date: "10/15/2025",
30
+ amount: "-45.23",
31
+ description: "Shell Gas",
32
+ },
33
+ },
34
+ {
35
+ id: "b2",
36
+ date: "2025-10-16",
37
+ amount: -100000, // milliunits
38
+ payee: "Netflix",
39
+ memo: "",
40
+ sourceRow: 2,
41
+ raw: {
42
+ date: "10/16/2025",
43
+ amount: "-100.00",
44
+ description: "Netflix",
45
+ },
46
+ },
47
+ ],
48
+ meta: {
49
+ detectedDelimiter: ",",
50
+ detectedColumns: ["Date", "Amount", "Description"],
51
+ totalRows: 2,
52
+ validRows: 2,
53
+ skippedRows: 0,
54
+ },
55
+ errors: [],
56
+ warnings: [],
57
+ });
58
+
59
+ const ynabTxns: YNABAPITransaction[] = [
60
+ {
61
+ id: "y1",
62
+ date: "2025-10-15",
63
+ amount: -45230,
64
+ payee_name: "Shell",
65
+ category_name: "Auto: Gas",
66
+ cleared: "uncleared" as const,
67
+ approved: true,
68
+ } as YNABAPITransaction,
69
+ {
70
+ id: "y2",
71
+ date: "2025-10-16",
72
+ amount: -100000,
73
+ payee_name: "Netflix",
74
+ category_name: "Entertainment",
75
+ cleared: "uncleared" as const,
76
+ approved: true,
77
+ } as YNABAPITransaction,
78
+ ];
79
+
80
+ const result = analyzeReconciliation(
81
+ "csv content",
82
+ undefined,
83
+ ynabTxns,
84
+ -145.23, // Target balance
85
+ );
86
+
87
+ expect(result.success).toBe(true);
88
+ expect(result.phase).toBe("analysis");
89
+ expect(result.summary).toBeDefined();
90
+ expect(result.auto_matches).toBeDefined();
91
+ expect(result.suggested_matches).toBeDefined();
92
+ expect(result.unmatched_bank).toBeDefined();
93
+ expect(result.unmatched_ynab).toBeDefined();
94
+ expect(result.balance_info).toBeDefined();
95
+ expect(result.next_steps).toBeDefined();
96
+
97
+ // Verify auto-matches (exact matches)
98
+ expect(result.auto_matches.length).toBe(2);
99
+ });
100
+
101
+ it("should categorize high-confidence matches as auto-matches", () => {
102
+ vi.mocked(csvParser.parseCSV).mockReturnValue({
103
+ transactions: [
104
+ {
105
+ id: "b1",
106
+ date: "2025-10-15",
107
+ amount: -50000,
108
+ payee: "Coffee Shop",
109
+ memo: "",
110
+ sourceRow: 1,
111
+ raw: {} as any,
112
+ },
113
+ ],
114
+ meta: {
115
+ detectedDelimiter: ",",
116
+ detectedColumns: [],
117
+ totalRows: 1,
118
+ validRows: 1,
119
+ skippedRows: 0,
120
+ },
121
+ errors: [],
122
+ warnings: [],
123
+ });
124
+
125
+ const ynabTxns: YNABAPITransaction[] = [
126
+ {
127
+ id: "y1",
128
+ date: "2025-10-15",
129
+ amount: -50000,
130
+ payee_name: "Coffee Shop",
131
+ category_name: "Dining",
132
+ cleared: "uncleared" as const,
133
+ approved: true,
134
+ } as YNABAPITransaction,
135
+ ];
136
+
137
+ const result = analyzeReconciliation("csv", undefined, ynabTxns, -50.0);
138
+
139
+ expect(result.auto_matches.length).toBeGreaterThan(0);
140
+ expect(result.auto_matches[0].confidence).toBe("high");
141
+ });
142
+
143
+ it("should categorize medium-confidence matches as suggested", () => {
144
+ vi.mocked(csvParser.parseCSV).mockReturnValue({
145
+ transactions: [
146
+ {
147
+ id: "b1",
148
+ date: "2025-10-15",
149
+ amount: -50000,
150
+ payee: "Generic Store",
151
+ memo: "",
152
+ sourceRow: 1,
153
+ raw: {} as any,
154
+ },
155
+ ],
156
+ meta: {
157
+ detectedDelimiter: ",",
158
+ detectedColumns: [],
159
+ totalRows: 1,
160
+ validRows: 1,
161
+ skippedRows: 0,
162
+ },
163
+ errors: [],
164
+ warnings: [],
165
+ });
166
+
167
+ const ynabTxns: YNABAPITransaction[] = [
168
+ {
169
+ id: "y1",
170
+ date: "2025-10-18", // 3 days difference - date score drops
171
+ amount: -50000,
172
+ payee_name: "Amazon Prime", // Fuzzy match
173
+ category_name: "Shopping",
174
+ cleared: "uncleared" as const,
175
+ approved: true,
176
+ } as YNABAPITransaction,
177
+ ];
178
+
179
+ const result = analyzeReconciliation("csv", undefined, ynabTxns, -50.0);
180
+
181
+ // Should be suggested (medium)
182
+ expect(result.suggested_matches.length).toBeGreaterThan(0);
183
+ expect(result.suggested_matches[0].confidence).toBe("medium");
184
+ });
185
+
186
+ it("should identify unmatched bank transactions", () => {
187
+ vi.mocked(csvParser.parseCSV).mockReturnValue({
188
+ transactions: [
189
+ {
190
+ id: "b1",
191
+ date: "2025-10-15",
192
+ amount: -15990,
193
+ payee: "New Store",
194
+ memo: "",
195
+ sourceRow: 1,
196
+ raw: {} as any,
197
+ },
198
+ ],
199
+ meta: {
200
+ detectedDelimiter: ",",
201
+ detectedColumns: [],
202
+ totalRows: 1,
203
+ validRows: 1,
204
+ skippedRows: 0,
205
+ },
206
+ errors: [],
207
+ warnings: [],
208
+ });
209
+
210
+ const ynabTxns: YNABAPITransaction[] = [];
211
+
212
+ const result = analyzeReconciliation("csv", undefined, ynabTxns, 0);
213
+
214
+ expect(result.unmatched_bank.length).toBe(1);
215
+ expect(result.unmatched_bank[0].payee).toBe("New Store");
216
+ });
217
+
218
+ it("should identify unmatched YNAB transactions", () => {
219
+ vi.mocked(csvParser.parseCSV).mockReturnValue({
220
+ transactions: [],
221
+ meta: {
222
+ detectedDelimiter: ",",
223
+ detectedColumns: [],
224
+ totalRows: 0,
225
+ validRows: 0,
226
+ skippedRows: 0,
227
+ },
228
+ errors: [],
229
+ warnings: [],
230
+ });
231
+
232
+ const ynabTxns: YNABAPITransaction[] = [
233
+ {
234
+ id: "y1",
235
+ date: "2025-10-15",
236
+ amount: -50000,
237
+ payee_name: "Restaurant",
238
+ category_name: "Dining",
239
+ cleared: "uncleared" as const,
240
+ approved: true,
241
+ } as YNABAPITransaction,
242
+ ];
243
+
244
+ const result = analyzeReconciliation("csv", undefined, ynabTxns, 0);
245
+
246
+ expect(result.unmatched_ynab.length).toBe(1);
247
+ expect(result.unmatched_ynab[0].payee).toBe("Restaurant");
248
+ });
249
+
250
+ it("should calculate balance information correctly", () => {
251
+ vi.mocked(csvParser.parseCSV).mockReturnValue({
252
+ transactions: [],
253
+ meta: {
254
+ detectedDelimiter: ",",
255
+ detectedColumns: [],
256
+ totalRows: 0,
257
+ validRows: 0,
258
+ skippedRows: 0,
259
+ },
260
+ errors: [],
261
+ warnings: [],
262
+ });
263
+
264
+ const ynabTxns: YNABAPITransaction[] = [
265
+ {
266
+ id: "y1",
267
+ date: "2025-10-15",
268
+ amount: -50000, // -$50.00 cleared
269
+ payee_name: "Store",
270
+ category_name: "Shopping",
271
+ cleared: "cleared" as const,
272
+ approved: true,
273
+ } as YNABAPITransaction,
274
+ {
275
+ id: "y2",
276
+ date: "2025-10-16",
277
+ amount: -30000, // -$30.00 uncleared
278
+ payee_name: "Restaurant",
279
+ category_name: "Dining",
280
+ cleared: "uncleared" as const,
281
+ approved: true,
282
+ } as YNABAPITransaction,
283
+ ];
284
+
285
+ const result = analyzeReconciliation("csv", undefined, ynabTxns, -50.0);
286
+
287
+ expect(result.balance_info.current_cleared.value).toBe(-50.0);
288
+ expect(result.balance_info.current_uncleared.value).toBe(-30.0);
289
+ expect(result.balance_info.current_total.value).toBe(-80.0);
290
+ expect(result.balance_info.target_statement.value).toBe(-50.0);
291
+ expect(result.balance_info.discrepancy.value).toBe(0);
292
+ expect(result.balance_info.on_track).toBe(true);
293
+ });
294
+
295
+ it("should generate appropriate summary", () => {
296
+ vi.mocked(csvParser.parseCSV).mockReturnValue({
297
+ transactions: [
298
+ {
299
+ id: "b1",
300
+ date: "2025-10-15",
301
+ amount: -50000,
302
+ payee: "Store",
303
+ memo: "",
304
+ sourceRow: 1,
305
+ raw: {} as any,
306
+ },
307
+ {
308
+ id: "b2",
309
+ date: "2025-10-20",
310
+ amount: -30000,
311
+ payee: "Restaurant",
312
+ memo: "",
313
+ sourceRow: 2,
314
+ raw: {} as any,
315
+ },
316
+ ],
317
+ meta: {
318
+ detectedDelimiter: ",",
319
+ detectedColumns: [],
320
+ totalRows: 2,
321
+ validRows: 2,
322
+ skippedRows: 0,
323
+ },
324
+ errors: [],
325
+ warnings: [],
326
+ });
327
+
328
+ const ynabTxns: YNABAPITransaction[] = [
329
+ {
330
+ id: "y1",
331
+ date: "2025-10-15",
332
+ amount: -50000,
333
+ payee_name: "Store",
334
+ category_name: "Shopping",
335
+ cleared: "uncleared" as const,
336
+ approved: true,
337
+ } as YNABAPITransaction,
338
+ ];
339
+
340
+ const result = analyzeReconciliation("csv", undefined, ynabTxns, -80.0);
341
+
342
+ expect(result.summary.bank_transactions_count).toBe(2);
343
+ expect(result.summary.ynab_transactions_count).toBe(1);
344
+ expect(result.summary.statement_date_range).toContain("2025-10-15");
345
+ expect(result.summary.statement_date_range).toContain("2025-10-20");
346
+ });
347
+
348
+ it("should not flag transactions outside statement period as missing from bank", () => {
349
+ // Regression test for date range filtering bug
350
+ // Previously, ALL YNAB transactions were compared against bank CSV,
351
+ // causing transactions outside the statement period to be incorrectly
352
+ // flagged as "missing from bank"
353
+ vi.mocked(csvParser.parseCSV).mockReturnValue({
354
+ transactions: [
355
+ {
356
+ id: "b1",
357
+ date: "2025-01-15",
358
+ amount: -50000,
359
+ payee: "Grocery Store",
360
+ memo: "",
361
+ sourceRow: 1,
362
+ raw: {} as any,
363
+ },
364
+ ],
365
+ meta: {
366
+ detectedDelimiter: ",",
367
+ detectedColumns: [],
368
+ totalRows: 1,
369
+ validRows: 1,
370
+ skippedRows: 0,
371
+ },
372
+ errors: [],
373
+ warnings: [],
374
+ });
375
+
376
+ const ynabTxns: YNABAPITransaction[] = [
377
+ // Transaction OUTSIDE statement period (December, before January statement)
378
+ {
379
+ id: "y-outside",
380
+ date: "2024-12-20",
381
+ amount: -30000,
382
+ payee_name: "Old Transaction",
383
+ category_name: "Shopping",
384
+ cleared: "cleared" as const,
385
+ approved: true,
386
+ } as YNABAPITransaction,
387
+ // Transaction INSIDE statement period
388
+ {
389
+ id: "y-inside",
390
+ date: "2025-01-15",
391
+ amount: -50000,
392
+ payee_name: "Grocery Store",
393
+ category_name: "Groceries",
394
+ cleared: "uncleared" as const,
395
+ approved: true,
396
+ } as YNABAPITransaction,
397
+ ];
398
+
399
+ const result = analyzeReconciliation("csv", undefined, ynabTxns, -50.0);
400
+
401
+ // The outside-range transaction should be in ynab_outside_date_range, not unmatched_ynab
402
+ expect(result.ynab_outside_date_range).toHaveLength(1);
403
+ expect(result.ynab_outside_date_range[0]?.id).toBe("y-outside");
404
+
405
+ // The summary should reflect the correct counts
406
+ expect(result.summary.ynab_in_range_count).toBe(1);
407
+ expect(result.summary.ynab_outside_range_count).toBe(1);
408
+
409
+ // The inside-range transaction should match and not be in unmatched
410
+ expect(result.unmatched_ynab).toHaveLength(0);
411
+ });
412
+ });
340
413
  });