UNPKG

@cipherstash/nextjs

Version:

Nextjs package for use with @cipherstash/protect

160 lines (130 loc) 4.7 kB
import { type NextRequest, NextResponse } from 'next/server' // cts.test.ts import { afterEach, describe, expect, it, vi } from 'vitest' // --------------------------------------------- // 1) Mock next/headers before importing it // --------------------------------------------- vi.mock('next/headers', () => ({ cookies: vi.fn(), // We'll override in tests with mockReturnValueOnce(...) })) // --------------------------------------------- // 2) Mock logger before importing it // --------------------------------------------- vi.mock('../../utils/logger', () => ({ logger: { debug: vi.fn(), error: vi.fn(), info: vi.fn(), warn: vi.fn(), }, })) // --------------------------------------------- // 3) Prepare your spies for partial mocking // (must be declared before vi.mock("../src/")) // --------------------------------------------- const mockReset = vi.fn() const mockSetCtsToken = vi.fn() // --------------------------------------------- // 4) Partial-mock ../src/ BEFORE importing // anything from that module // --------------------------------------------- vi.mock('../src/', async () => { // Re-import actual code so that only certain exports are overridden const actual = await vi.importActual<typeof import('../src/')>('../src/') return { ...actual, resetCtsToken: mockReset, setCtsToken: mockSetCtsToken, } }) // --------------------------------------------- // 5) Now import after the mock is declared // --------------------------------------------- import { cookies } from 'next/headers' import { logger } from '../../utils/logger' import { CS_COOKIE_NAME, type CtsToken, getCtsToken, protectMiddleware, resetCtsToken, } from '../src/' describe('getCtsToken', () => { afterEach(() => { vi.clearAllMocks() }) it('should return the parsed token if the cookie is present', async () => { const mockCookieValue: CtsToken = { accessToken: 'fake_token', expiry: 999999, } ;(cookies as unknown as vi.Mock).mockReturnValueOnce({ get: vi.fn().mockReturnValue({ value: JSON.stringify(mockCookieValue) }), }) const token = await getCtsToken() expect(token).toEqual(mockCookieValue) expect(logger.debug).not.toHaveBeenCalledWith( 'No CipherStash session cookie found in the request.', ) }) it('should return null if the cookie is not present', async () => { ;(cookies as unknown as vi.Mock).mockReturnValueOnce({ get: vi.fn().mockReturnValue(undefined), }) const token = await getCtsToken() expect(token).toBeNull() expect(logger.debug).toHaveBeenCalledWith( 'No CipherStash session cookie found in the request.', ) }) }) describe('resetCtsToken', () => { afterEach(() => { vi.clearAllMocks() }) it('should delete the token cookie on the provided NextResponse', () => { const response = NextResponse.next() const mockDelete = vi.spyOn(response.cookies, 'delete') const updatedResponse = resetCtsToken(response) expect(mockDelete).toHaveBeenCalledWith(CS_COOKIE_NAME) expect(updatedResponse).toBe(response) }) it('should create a new NextResponse if none is provided', () => { const response = resetCtsToken() expect(response).toBeInstanceOf(NextResponse) // Confirm the cookie is cleared expect(response.cookies.get(CS_COOKIE_NAME)?.value).toBe('') }) }) describe('protectMiddleware', () => { afterEach(() => { vi.clearAllMocks() }) function createMockRequest(hasCookie: boolean) { return { cookies: { has: vi.fn().mockReturnValue(hasCookie) }, } as unknown as NextRequest } it('should call setCtsToken if oidcToken is provided and there is no session cookie', async () => { const mockOidcToken = 'valid_token' const mockReq = createMockRequest(false) await protectMiddleware(mockOidcToken, mockReq) expect(mockSetCtsToken).toHaveBeenCalledWith(mockOidcToken) }) it('should reset the cts token if oidcToken is not provided but cookie is present', async () => { const mockReq = createMockRequest(true) await protectMiddleware('', mockReq) expect(logger.debug).toHaveBeenCalledWith( 'The JWT token was undefined, so the CipherStash session was reset.', ) expect(mockReset).toHaveBeenCalled() }) it('should return NextResponse.next() if none of the conditions are met', async () => { const mockReq = createMockRequest(false) const response = await protectMiddleware('', mockReq) expect(response).toBeInstanceOf(NextResponse) expect(logger.debug).toHaveBeenCalledWith( 'The JWT token was undefined, so the CipherStash session was not set.', ) }) })