urlState.test.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /* @vitest-environment node */
  2. import { describe, it, expect } from "vitest";
  3. import {
  4. SEARCH_SCOPE,
  5. parseBranchesCsv,
  6. serializeBranchesCsv,
  7. parseSearchUrlState,
  8. serializeSearchUrlState,
  9. } from "./urlState.js";
  10. describe("lib/frontend/search/urlState", () => {
  11. describe("parseBranchesCsv / serializeBranchesCsv", () => {
  12. it("parses CSV into a unique, trimmed list", () => {
  13. expect(parseBranchesCsv(" NL06, NL20 ,NL06,, ")).toEqual([
  14. "NL06",
  15. "NL20",
  16. ]);
  17. });
  18. it("serializes branches into CSV with stable order and dedupe", () => {
  19. expect(serializeBranchesCsv(["NL20", " NL06 ", "NL20"])).toBe(
  20. "NL20,NL06"
  21. );
  22. });
  23. it("returns null when serializing empty branches", () => {
  24. expect(serializeBranchesCsv([])).toBe(null);
  25. expect(serializeBranchesCsv(null)).toBe(null);
  26. });
  27. });
  28. describe("parseSearchUrlState", () => {
  29. it("defaults to SINGLE with routeBranch when no params are present", () => {
  30. const sp = new URLSearchParams();
  31. const state = parseSearchUrlState(sp, { routeBranch: "NL01" });
  32. expect(state).toEqual({
  33. q: null,
  34. scope: SEARCH_SCOPE.SINGLE,
  35. branch: "NL01",
  36. branches: [],
  37. from: null,
  38. to: null,
  39. });
  40. });
  41. it("parses SINGLE with explicit branch param", () => {
  42. const sp = new URLSearchParams({ q: " test ", branch: "NL02" });
  43. const state = parseSearchUrlState(sp, { routeBranch: "NL01" });
  44. expect(state.scope).toBe(SEARCH_SCOPE.SINGLE);
  45. expect(state.q).toBe("test");
  46. expect(state.branch).toBe("NL02");
  47. expect(state.branches).toEqual([]);
  48. });
  49. it("parses ALL when scope=all is set (highest precedence)", () => {
  50. const sp = new URLSearchParams({
  51. q: "x",
  52. scope: "all",
  53. branch: "NL01",
  54. branches: "NL06,NL20",
  55. });
  56. const state = parseSearchUrlState(sp, { routeBranch: "NL99" });
  57. expect(state).toEqual({
  58. q: "x",
  59. scope: SEARCH_SCOPE.ALL,
  60. branch: null,
  61. branches: [],
  62. from: null,
  63. to: null,
  64. });
  65. });
  66. it("parses MULTI when scope=multi is set", () => {
  67. const sp = new URLSearchParams({
  68. q: " reifen ",
  69. scope: "multi",
  70. branches: "NL06, NL20, NL06",
  71. });
  72. const state = parseSearchUrlState(sp, { routeBranch: "NL01" });
  73. expect(state.scope).toBe(SEARCH_SCOPE.MULTI);
  74. expect(state.q).toBe("reifen");
  75. expect(state.branch).toBe(null);
  76. expect(state.branches).toEqual(["NL06", "NL20"]);
  77. });
  78. it("parses MULTI when branches=... is present even without scope", () => {
  79. const sp = new URLSearchParams({
  80. q: "x",
  81. branches: "NL06,NL20",
  82. });
  83. const state = parseSearchUrlState(sp, { routeBranch: "NL01" });
  84. expect(state.scope).toBe(SEARCH_SCOPE.MULTI);
  85. expect(state.branches).toEqual(["NL06", "NL20"]);
  86. });
  87. it("keeps from/to when provided", () => {
  88. const sp = new URLSearchParams({
  89. q: "x",
  90. branch: "NL01",
  91. from: "2025-12-01",
  92. to: "2025-12-31",
  93. });
  94. const state = parseSearchUrlState(sp, { routeBranch: "NL01" });
  95. expect(state.from).toBe("2025-12-01");
  96. expect(state.to).toBe("2025-12-31");
  97. });
  98. });
  99. describe("serializeSearchUrlState", () => {
  100. it("serializes SINGLE as q + branch (no scope param)", () => {
  101. const qs = serializeSearchUrlState({
  102. q: "bridgestone",
  103. scope: SEARCH_SCOPE.SINGLE,
  104. branch: "NL01",
  105. });
  106. expect(qs).toBe("q=bridgestone&branch=NL01");
  107. });
  108. it("serializes MULTI as q + scope=multi + branches", () => {
  109. const qs = serializeSearchUrlState({
  110. q: "reifen",
  111. scope: SEARCH_SCOPE.MULTI,
  112. branches: ["NL06", "NL20"],
  113. });
  114. expect(qs).toBe("q=reifen&scope=multi&branches=NL06%2CNL20");
  115. });
  116. it("serializes ALL as q + scope=all", () => {
  117. const qs = serializeSearchUrlState({
  118. q: "x",
  119. scope: SEARCH_SCOPE.ALL,
  120. });
  121. expect(qs).toBe("q=x&scope=all");
  122. });
  123. it("includes from/to when present (future-proof for RHL-025)", () => {
  124. const qs = serializeSearchUrlState({
  125. q: "x",
  126. scope: SEARCH_SCOPE.SINGLE,
  127. branch: "NL01",
  128. from: "2025-12-01",
  129. to: "2025-12-31",
  130. });
  131. expect(qs).toBe("q=x&branch=NL01&from=2025-12-01&to=2025-12-31");
  132. });
  133. });
  134. });