session.test.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. import { describe, it, expect, vi, beforeEach } from "vitest";
  2. // Mock next/headers to provide a simple in-memory cookie store
  3. vi.mock("next/headers", () => {
  4. let store = new Map();
  5. return {
  6. cookies() {
  7. return {
  8. get(name) {
  9. const entry = store.get(name);
  10. if (!entry) return undefined;
  11. return { name, value: entry.value };
  12. },
  13. set(name, value, options) {
  14. store.set(name, { value, options });
  15. },
  16. };
  17. },
  18. __cookieStore: {
  19. clear() {
  20. store = new Map();
  21. },
  22. dump() {
  23. return store;
  24. },
  25. },
  26. };
  27. });
  28. // Import after the mock so the module under test uses the mocked cookies()
  29. import {
  30. createSession,
  31. getSession,
  32. destroySession,
  33. SESSION_COOKIE_NAME,
  34. SESSION_MAX_AGE_SECONDS,
  35. } from "./session";
  36. import { __cookieStore } from "next/headers";
  37. describe("auth session utilities", () => {
  38. beforeEach(() => {
  39. __cookieStore.clear();
  40. process.env.SESSION_SECRET = "x".repeat(64);
  41. process.env.NODE_ENV = "test";
  42. });
  43. it("creates a session cookie with a signed JWT", async () => {
  44. const jwt = await createSession({
  45. userId: "user123",
  46. role: "branch",
  47. branchId: "NL01",
  48. });
  49. expect(typeof jwt).toBe("string");
  50. expect(jwt.length).toBeGreaterThan(10);
  51. const store = __cookieStore.dump();
  52. const cookie = store.get(SESSION_COOKIE_NAME);
  53. expect(cookie).toBeDefined();
  54. expect(cookie.value).toBe(jwt);
  55. expect(cookie.options).toMatchObject({
  56. httpOnly: true,
  57. secure: false, // NODE_ENV = "test"
  58. sameSite: "lax",
  59. path: "/",
  60. maxAge: SESSION_MAX_AGE_SECONDS,
  61. });
  62. });
  63. it("reads a valid session from cookie", async () => {
  64. await createSession({
  65. userId: "user456",
  66. role: "admin",
  67. branchId: null,
  68. });
  69. const session = await getSession();
  70. expect(session).toEqual({
  71. userId: "user456",
  72. role: "admin",
  73. branchId: null,
  74. });
  75. });
  76. it("returns null when no session cookie is present", async () => {
  77. const session = await getSession();
  78. expect(session).toBeNull();
  79. });
  80. it("returns null and clears cookie when token is invalid", async () => {
  81. // Manually set an invalid JWT value
  82. const store = __cookieStore.dump();
  83. store.set(SESSION_COOKIE_NAME, {
  84. value: "not-a-valid-jwt",
  85. options: {
  86. httpOnly: true,
  87. secure: false,
  88. sameSite: "lax",
  89. path: "/",
  90. maxAge: SESSION_MAX_AGE_SECONDS,
  91. },
  92. });
  93. const session = await getSession();
  94. expect(session).toBeNull();
  95. const updatedStore = __cookieStore.dump();
  96. const cookie = updatedStore.get(SESSION_COOKIE_NAME);
  97. expect(cookie).toBeDefined();
  98. expect(cookie.value).toBe("");
  99. expect(cookie.options.maxAge).toBe(0);
  100. });
  101. it("destroySession clears the session cookie when it exists", async () => {
  102. await createSession({
  103. userId: "user789",
  104. role: "branch",
  105. branchId: "NL02",
  106. });
  107. await destroySession();
  108. const store = __cookieStore.dump();
  109. const cookie = store.get(SESSION_COOKIE_NAME);
  110. expect(cookie).toBeDefined();
  111. expect(cookie.value).toBe("");
  112. expect(cookie.options.maxAge).toBe(0);
  113. });
  114. it("destroySession sets an empty cookie even if none existed before", async () => {
  115. await destroySession();
  116. const store = __cookieStore.dump();
  117. const cookie = store.get(SESSION_COOKIE_NAME);
  118. expect(cookie).toBeDefined();
  119. expect(cookie.value).toBe("");
  120. expect(cookie.options.maxAge).toBe(0);
  121. });
  122. });