searchApiInput.test.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /* @vitest-environment node */
  2. import { describe, it, expect } from "vitest";
  3. import { ApiClientError } from "@/lib/frontend/apiClient";
  4. import { SEARCH_SCOPE } from "@/lib/frontend/search/urlState";
  5. import { buildSearchApiInput } from "./searchApiInput.js";
  6. describe("lib/frontend/search/searchApiInput", () => {
  7. it("returns {input:null} when q is missing", () => {
  8. const { input, error } = buildSearchApiInput({
  9. urlState: {
  10. q: null,
  11. scope: SEARCH_SCOPE.SINGLE,
  12. branch: "NL01",
  13. branches: [],
  14. from: null,
  15. to: null,
  16. },
  17. routeBranch: "NL01",
  18. user: { role: "admin", branchId: null },
  19. });
  20. expect(input).toBe(null);
  21. expect(error).toBe(null);
  22. });
  23. it("branch users always use routeBranch (single) and ignore scope", () => {
  24. const { input, error } = buildSearchApiInput({
  25. urlState: {
  26. q: "x",
  27. scope: SEARCH_SCOPE.ALL,
  28. branch: "NL99",
  29. branches: ["NL06"],
  30. from: null,
  31. to: null,
  32. },
  33. routeBranch: "NL01",
  34. user: { role: "branch", branchId: "NL01" },
  35. });
  36. expect(error).toBe(null);
  37. expect(input).toEqual({ q: "x", limit: 100, branch: "NL01" });
  38. });
  39. it("admin-like: ALL uses scope=all (admin)", () => {
  40. const { input } = buildSearchApiInput({
  41. urlState: {
  42. q: "x",
  43. scope: SEARCH_SCOPE.ALL,
  44. branch: null,
  45. branches: [],
  46. from: null,
  47. to: null,
  48. },
  49. routeBranch: "NL01",
  50. user: { role: "admin", branchId: null },
  51. });
  52. expect(input).toEqual({ q: "x", limit: 100, scope: "all" });
  53. });
  54. it("admin-like: ALL uses scope=all (superadmin)", () => {
  55. const { input } = buildSearchApiInput({
  56. urlState: {
  57. q: "x",
  58. scope: SEARCH_SCOPE.ALL,
  59. branch: null,
  60. branches: [],
  61. from: null,
  62. to: null,
  63. },
  64. routeBranch: "NL01",
  65. user: { role: "superadmin", branchId: null },
  66. });
  67. expect(input).toEqual({ q: "x", limit: 100, scope: "all" });
  68. });
  69. it("admin-like: MULTI uses scope=multi + branches (dev)", () => {
  70. const { input, error } = buildSearchApiInput({
  71. urlState: {
  72. q: "x",
  73. scope: SEARCH_SCOPE.MULTI,
  74. branch: null,
  75. branches: ["NL06", "NL20"],
  76. from: null,
  77. to: null,
  78. },
  79. routeBranch: "NL01",
  80. user: { role: "dev", branchId: null },
  81. cursor: "abc",
  82. limit: 100,
  83. });
  84. expect(error).toBe(null);
  85. expect(input).toEqual({
  86. q: "x",
  87. limit: 100,
  88. cursor: "abc",
  89. scope: "multi",
  90. branches: ["NL06", "NL20"],
  91. });
  92. });
  93. it("admin-like: MULTI without branches is treated as not-ready (no error)", () => {
  94. const { input, error } = buildSearchApiInput({
  95. urlState: {
  96. q: "x",
  97. scope: SEARCH_SCOPE.MULTI,
  98. branch: null,
  99. branches: [],
  100. from: null,
  101. to: null,
  102. },
  103. routeBranch: "NL01",
  104. user: { role: "admin", branchId: null },
  105. });
  106. expect(input).toBe(null);
  107. expect(error).toBe(null);
  108. });
  109. it("admin-like: SINGLE uses routeBranch as branch param", () => {
  110. const { input } = buildSearchApiInput({
  111. urlState: {
  112. q: "x",
  113. scope: SEARCH_SCOPE.SINGLE,
  114. branch: "NL99",
  115. branches: [],
  116. from: null,
  117. to: null,
  118. },
  119. routeBranch: "NL01",
  120. user: { role: "admin", branchId: null },
  121. });
  122. expect(input).toEqual({ q: "x", limit: 100, branch: "NL01" });
  123. });
  124. it("includes from/to when valid", () => {
  125. const { input, error } = buildSearchApiInput({
  126. urlState: {
  127. q: "x",
  128. scope: SEARCH_SCOPE.SINGLE,
  129. branch: "NL01",
  130. branches: [],
  131. from: "2025-12-01",
  132. to: "2025-12-31",
  133. },
  134. routeBranch: "NL01",
  135. user: { role: "admin", branchId: null },
  136. });
  137. expect(error).toBe(null);
  138. expect(input).toEqual({
  139. q: "x",
  140. limit: 100,
  141. branch: "NL01",
  142. from: "2025-12-01",
  143. to: "2025-12-31",
  144. });
  145. });
  146. it("accepts from===to as a valid single-day search", () => {
  147. const { input, error } = buildSearchApiInput({
  148. urlState: {
  149. q: "x",
  150. scope: SEARCH_SCOPE.SINGLE,
  151. branch: "NL01",
  152. branches: [],
  153. from: "2025-12-01",
  154. to: "2025-12-01",
  155. },
  156. routeBranch: "NL01",
  157. user: { role: "admin", branchId: null },
  158. });
  159. expect(error).toBe(null);
  160. expect(input).toEqual({
  161. q: "x",
  162. limit: 100,
  163. branch: "NL01",
  164. from: "2025-12-01",
  165. to: "2025-12-01",
  166. });
  167. });
  168. it("returns a local validation error when from > to (no request should be sent)", () => {
  169. const { input, error } = buildSearchApiInput({
  170. urlState: {
  171. q: "x",
  172. scope: SEARCH_SCOPE.SINGLE,
  173. branch: "NL01",
  174. branches: [],
  175. from: "2025-12-31",
  176. to: "2025-12-01",
  177. },
  178. routeBranch: "NL01",
  179. user: { role: "admin", branchId: null },
  180. });
  181. expect(input).toBe(null);
  182. expect(error).toBeInstanceOf(ApiClientError);
  183. expect(error.code).toBe("VALIDATION_SEARCH_RANGE");
  184. });
  185. it("returns a local validation error for invalid date format", () => {
  186. const { input, error } = buildSearchApiInput({
  187. urlState: {
  188. q: "x",
  189. scope: SEARCH_SCOPE.SINGLE,
  190. branch: "NL01",
  191. branches: [],
  192. from: "2025/12/01",
  193. to: null,
  194. },
  195. routeBranch: "NL01",
  196. user: { role: "admin", branchId: null },
  197. });
  198. expect(input).toBe(null);
  199. expect(error).toBeInstanceOf(ApiClientError);
  200. expect(error.code).toBe("VALIDATION_SEARCH_DATE");
  201. });
  202. });