fix architecture and write new tests

This commit is contained in:
root
2026-06-10 00:40:19 -04:00
parent 560da1cadf
commit 80a597bc10
377 changed files with 84020 additions and 1337 deletions
+47
View File
@@ -0,0 +1,47 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
afterEach(() => {
delete process.env.API_INTERNAL_URL
delete process.env.NEXT_PUBLIC_API_URL
vi.restoreAllMocks()
Reflect.deleteProperty(globalThis, 'fetch')
vi.resetModules()
})
describe('adminFetch', () => {
it('requests through the server API base and returns the data envelope', async () => {
process.env.API_INTERNAL_URL = 'http://internal-api/api/v1'
const fetchMock = vi.fn(async () => ({
ok: true,
json: async () => ({ data: { companies: [] } }),
}))
Object.defineProperty(globalThis, 'fetch', { configurable: true, value: fetchMock })
const { adminFetch } = await import('./api')
await expect(adminFetch('/admin/companies', 'admin-token')).resolves.toEqual({ companies: [] })
expect(fetchMock).toHaveBeenCalledWith('http://internal-api/api/v1/admin/companies', {
cache: 'no-store',
credentials: 'include',
})
})
it('omits authorization when no token is supplied', async () => {
delete process.env.API_INTERNAL_URL
const fetchMock = vi.fn(async () => ({ ok: true, json: async () => ({ data: { ok: true } }) }))
Object.defineProperty(globalThis, 'fetch', { configurable: true, value: fetchMock })
const { adminFetch } = await import('./api')
await adminFetch('/public')
expect((fetchMock as any).mock.calls[0]?.[1]).toEqual({ cache: 'no-store', credentials: 'include' })
})
it('throws the API message from failed responses', async () => {
const fetchMock = vi.fn(async () => ({ ok: false, json: async () => ({ message: 'Admin only' }) }))
Object.defineProperty(globalThis, 'fetch', { configurable: true, value: fetchMock })
const { adminFetch } = await import('./api')
await expect(adminFetch('/admin/menu')).rejects.toThrow('Admin only')
})
})
+2 -2
View File
@@ -3,10 +3,10 @@ export const ADMIN_API_BASE =
? (process.env.API_INTERNAL_URL ?? process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:4000/api/v1')
: (process.env.NEXT_PUBLIC_API_URL ?? '/admin/api/v1')
export async function adminFetch<T>(path: string, token?: string): Promise<T> {
export async function adminFetch<T>(path: string, _token?: string): Promise<T> {
const res = await fetch(`${ADMIN_API_BASE}${path}`, {
cache: 'no-store',
headers: token ? { Authorization: `Bearer ${token}` } : undefined,
credentials: 'include',
})
const json = await res.json()
if (!res.ok) throw new Error(json?.message ?? 'Request failed')
+38
View File
@@ -0,0 +1,38 @@
import { afterEach, describe, expect, it } from 'vitest'
import { resolveBrowserAppUrl, resolveServerAppUrl } from './appUrls'
function installWindow(hostname: string, protocol = 'https:') {
Object.defineProperty(globalThis, 'window', {
configurable: true,
value: { location: { hostname, protocol } },
})
}
afterEach(() => {
Reflect.deleteProperty(globalThis, 'window')
})
describe('admin app URL resolution', () => {
it('keeps server fallback unchanged without a browser window', () => {
expect(resolveBrowserAppUrl('http://localhost:3002/admin')).toBe('http://localhost:3002/admin')
})
it('removes trailing slash for localhost browser fallbacks', () => {
installWindow('127.0.0.1')
expect(resolveBrowserAppUrl('http://localhost:3002/admin/')).toBe('http://localhost:3002/admin')
})
it('rewrites fallback origin to the current browser host in production', () => {
installWindow('admin.rentaldrivego.ma')
expect(resolveBrowserAppUrl('http://localhost:3002/admin')).toBe('https://admin.rentaldrivego.ma/admin')
})
it('resolves server app URLs from forwarded host and protocol', () => {
expect(resolveServerAppUrl('http://localhost:3002/admin', 'admin.example.com', 'https')).toBe('https://admin.example.com:3002/admin')
})
it('falls back when host is missing or the fallback is not parseable', () => {
expect(resolveServerAppUrl('http://localhost:3002/admin', null)).toBe('http://localhost:3002/admin')
expect(resolveServerAppUrl('/admin', 'admin.example.com')).toBe('/admin')
})
})