Files
carmanagement/apps/dashboard/src/middleware.test.ts
T
2026-06-10 00:40:19 -04:00

128 lines
4.9 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
const nextServer = vi.hoisted(() => {
const redirect = vi.fn((url: URL) => ({ kind: 'redirect', url: url.toString() }))
const next = vi.fn(() => ({ kind: 'next' }))
const MockNextResponse = vi.fn((body?: string, init?: { status?: number }) => ({
kind: 'response',
body,
status: init?.status,
})) as any
MockNextResponse.redirect = redirect
MockNextResponse.next = next
return { redirect, next, MockNextResponse }
})
vi.mock('next/server', () => ({
NextResponse: nextServer.MockNextResponse,
}))
function cloneableUrl(input: string): URL {
const url = new URL(input)
;(url as URL & { clone: () => URL }).clone = () => cloneableUrl(url.toString())
return url
}
function request(input: string, options: { token?: string; headers?: Record<string, string> } = {}) {
const headers = new Map(Object.entries(options.headers ?? {}).map(([key, value]) => [key.toLowerCase(), value]))
return {
nextUrl: cloneableUrl(input),
cookies: {
get: vi.fn((name: string) => (name === 'employee_session' && options.token ? { value: options.token } : undefined)),
},
headers: {
get: vi.fn((name: string) => headers.get(name.toLowerCase()) ?? null),
has: vi.fn((name: string) => headers.has(name.toLowerCase())),
},
}
}
async function loadMiddleware(marketplaceUrl = 'https://market.example.com') {
vi.resetModules()
process.env.NEXT_PUBLIC_MARKETPLACE_URL = marketplaceUrl
return import('./middleware')
}
beforeEach(() => {
nextServer.redirect.mockClear()
nextServer.next.mockClear()
})
afterEach(() => {
delete process.env.NEXT_PUBLIC_MARKETPLACE_URL
vi.resetModules()
})
describe('dashboard middleware', () => {
it('rejects middleware subrequest headers at the app layer', async () => {
const { default: middleware } = await loadMiddleware()
const response = middleware(request('https://workspace.example.com/dashboard', {
headers: { 'x-middleware-subrequest': 'middleware:middleware' },
}) as never)
expect(response).toEqual({ kind: 'response', body: 'Unsupported internal request header', status: 400 })
})
it('deduplicates accidental repeated /dashboard prefixes before auth handling', async () => {
const { default: middleware } = await loadMiddleware()
const response = middleware(request('https://workspace.example.com/dashboard/dashboard/fleet') as never)
expect(response).toEqual({ kind: 'redirect', url: 'https://workspace.example.com/dashboard/fleet' })
expect(nextServer.redirect).toHaveBeenCalledTimes(1)
expect(nextServer.next).not.toHaveBeenCalled()
})
it('redirects unauthenticated protected internal-host requests to dashboard sign-in on the resolved origin', async () => {
const { default: middleware } = await loadMiddleware('https://rentaldrivego.example')
const response = middleware(request('http://dashboard:3001/dashboard/team') as never)
expect(response).toEqual({ kind: 'redirect', url: 'https://rentaldrivego.example:3001/dashboard/sign-in?redirect=%2Fdashboard%2Fteam' })
})
it('uses trusted forwarded host/proto when building the dashboard sign-in redirect', async () => {
const { default: middleware } = await loadMiddleware('https://market.example.com')
const response = middleware(request('http://dashboard:3001/dashboard/billing', {
headers: {
'x-forwarded-host': 'workspace.customer.example',
'x-forwarded-proto': 'https',
},
}) as never)
expect(response).toEqual({ kind: 'redirect', url: 'https://workspace.customer.example:3001/dashboard/sign-in?redirect=%2Fdashboard%2Fbilling' })
})
it('ignores internal forwarded hosts when building the dashboard sign-in redirect', async () => {
const { default: middleware } = await loadMiddleware('https://market.example.com')
const response = middleware(request('http://dashboard:3001/dashboard/fleet', {
headers: {
'x-forwarded-host': 'api:4000',
'x-forwarded-proto': 'https',
},
}) as never)
expect(response).toEqual({ kind: 'redirect', url: 'https://market.example.com:3001/dashboard/sign-in?redirect=%2Fdashboard%2Ffleet' })
})
it('redirects signed-in users away from the sign-in page', async () => {
const { default: middleware } = await loadMiddleware()
const response = middleware(request('https://workspace.example.com/dashboard/sign-in?redirect=/dashboard/fleet', { token: 'employee-token' }) as never)
expect(response).toEqual({ kind: 'redirect', url: 'https://workspace.example.com/dashboard' })
})
it('allows public dashboard auth pages without a token', async () => {
const { default: middleware } = await loadMiddleware()
const response = middleware(request('https://workspace.example.com/dashboard/forgot-password') as never)
expect(response).toEqual({ kind: 'next' })
expect(nextServer.next).toHaveBeenCalledTimes(1)
})
})