admin login fixed.
Build & Push / Pipeline Tests (push) Failing after 1m34s
Build & Push / Build & Push Docker Image (push) Has been skipped
Test / Type Check (all packages) (push) Successful in 56s
Test / API Unit Tests (push) Successful in 1m8s
Test / Homepage Unit Tests (push) Successful in 47s
Test / Carplace Unit Tests (push) Successful in 43s
Test / Admin Unit Tests (push) Successful in 46s
Test / Dashboard Unit Tests (push) Failing after 43s
Test / API Integration Tests (push) Successful in 1m8s
Build & Push / Pipeline Tests (push) Failing after 1m34s
Build & Push / Build & Push Docker Image (push) Has been skipped
Test / Type Check (all packages) (push) Successful in 56s
Test / API Unit Tests (push) Successful in 1m8s
Test / Homepage Unit Tests (push) Successful in 47s
Test / Carplace Unit Tests (push) Successful in 43s
Test / Admin Unit Tests (push) Successful in 46s
Test / Dashboard Unit Tests (push) Failing after 43s
Test / API Integration Tests (push) Successful in 1m8s
This commit is contained in:
@@ -16,7 +16,8 @@ vi.mock('../../lib/redis', () => ({
|
||||
|
||||
import request from 'supertest'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { createApp } from '../../app'
|
||||
import { createApp, isCorsOriginAllowed } from '../../app'
|
||||
import { isTrustedBrowserOrigin } from '../../middleware/csrf'
|
||||
|
||||
const app = createApp()
|
||||
|
||||
@@ -87,6 +88,13 @@ describe('API foundation integration', () => {
|
||||
expect(res.headers['access-control-allow-credentials']).toBe('true')
|
||||
})
|
||||
|
||||
it('trusts private LAN app origins during local development only on known app ports', () => {
|
||||
expect(isCorsOriginAllowed('http://192.168.3.3:3000')).toBe(true)
|
||||
expect(isTrustedBrowserOrigin('http://192.168.3.3:3000')).toBe(true)
|
||||
expect(isCorsOriginAllowed('http://192.168.3.3:8080')).toBe(false)
|
||||
expect(isTrustedBrowserOrigin('http://192.168.3.3:8080')).toBe(false)
|
||||
})
|
||||
|
||||
it('blocks legacy anonymous access to customer identity document storage paths', async () => {
|
||||
const res = await request(app).get('/storage/companies/company_1/customers/customer_1/passport.jpg')
|
||||
|
||||
|
||||
@@ -149,4 +149,35 @@ describe('auth middleware API boundaries', () => {
|
||||
expect(res.body).toEqual({ data: { data: [{ id: 'company_1' }], pagination: { page: 1 } } })
|
||||
expect(adminService.listCompanies).toHaveBeenCalledWith({ page: 1, pageSize: 20 })
|
||||
})
|
||||
|
||||
it('clears any employee session when admin login succeeds', async () => {
|
||||
vi.mocked(adminService.login).mockResolvedValue({
|
||||
token: 'admin-jwt',
|
||||
admin: { id: 'admin_1', email: 'admin@example.test', role: 'SUPER_ADMIN' },
|
||||
} as never)
|
||||
|
||||
const res = await request(app)
|
||||
.post('/api/v1/admin/auth/login')
|
||||
.send({ email: 'admin@example.test', password: 'valid-password' })
|
||||
|
||||
expect(res.status).toBe(200)
|
||||
expect(res.headers['set-cookie']).toEqual(expect.arrayContaining([
|
||||
expect.stringMatching(/^employee_session=;/),
|
||||
expect.stringMatching(/^admin_session=/),
|
||||
]))
|
||||
})
|
||||
|
||||
it('clears any employee session when admin credentials require 2FA', async () => {
|
||||
vi.mocked(adminService.login).mockResolvedValue({ totpRequired: true } as never)
|
||||
|
||||
const res = await request(app)
|
||||
.post('/api/v1/admin/auth/login')
|
||||
.send({ email: 'admin@example.test', password: 'valid-password' })
|
||||
|
||||
expect(res.status).toBe(401)
|
||||
expect(res.body.error).toBe('totp_required')
|
||||
expect(res.headers['set-cookie']).toEqual(expect.arrayContaining([
|
||||
expect.stringMatching(/^employee_session=;/),
|
||||
]))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -95,6 +95,19 @@ describe('employee, notification, and carplace API validation contracts', () =>
|
||||
expect(employeeService.login).toHaveBeenCalledWith({ email: 'agent@example.test', password: 'valid-password' })
|
||||
})
|
||||
|
||||
it('clears any admin session when employee login succeeds', async () => {
|
||||
const res = await request(app).post('/api/v1/auth/employee/login').send({
|
||||
email: 'agent@example.test',
|
||||
password: 'valid-password',
|
||||
})
|
||||
|
||||
expect(res.status).toBe(200)
|
||||
expect(res.headers['set-cookie']).toEqual(expect.arrayContaining([
|
||||
expect.stringMatching(/^admin_session=;/),
|
||||
expect.stringMatching(/^employee_session=/),
|
||||
]))
|
||||
})
|
||||
|
||||
it('rejects empty employee reset tokens before service execution', async () => {
|
||||
const res = await request(app).post('/api/v1/auth/employee/reset-password').send({ token: '', password: 'new-password' })
|
||||
|
||||
|
||||
@@ -3,8 +3,10 @@ import { createApp } from '../../app'
|
||||
import {
|
||||
authHeader,
|
||||
createAdminUser,
|
||||
createCompanyNotification,
|
||||
createCompanyWithEmployee,
|
||||
createRenter,
|
||||
createRenterNotification,
|
||||
signAdminToken,
|
||||
} from '../helpers/fixtures'
|
||||
|
||||
@@ -17,6 +19,7 @@ describe('Admin API', () => {
|
||||
let viewerToken: string
|
||||
let adminId: string
|
||||
let companyId: string
|
||||
let employeeId: string
|
||||
|
||||
beforeAll(async () => {
|
||||
const admin = await createAdminUser({
|
||||
@@ -56,8 +59,9 @@ describe('Admin API', () => {
|
||||
})
|
||||
viewerToken = signAdminToken(viewerAdmin.id)
|
||||
|
||||
const { company } = await createCompanyWithEmployee()
|
||||
const { company, employee } = await createCompanyWithEmployee()
|
||||
companyId = company.id
|
||||
employeeId = employee.id
|
||||
await createRenter()
|
||||
})
|
||||
|
||||
@@ -126,6 +130,41 @@ describe('Admin API', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /api/v1/admin/notifications', () => {
|
||||
it('returns employee and renter notification deliveries in the platform log', async () => {
|
||||
const renter = await createRenter()
|
||||
const employeeNotification = await createCompanyNotification(companyId, employeeId, {
|
||||
title: 'Employee audit notification',
|
||||
})
|
||||
const renterNotification = await createRenterNotification(renter.id, {
|
||||
companyId,
|
||||
title: 'Renter audit notification',
|
||||
})
|
||||
|
||||
const res = await request(app)
|
||||
.get('/api/v1/admin/notifications?pageSize=100')
|
||||
.set(authHeader(protectedAdminToken))
|
||||
|
||||
expect(res.status).toBe(200)
|
||||
expect(res.body.data.data).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
notificationId: employeeNotification.notificationEventId,
|
||||
recipientType: 'EMPLOYEE',
|
||||
employeeId,
|
||||
title: 'Employee audit notification',
|
||||
}),
|
||||
expect.objectContaining({
|
||||
notificationId: renterNotification.notificationEventId,
|
||||
recipientType: 'RENTER',
|
||||
renterId: renter.id,
|
||||
title: 'Renter audit notification',
|
||||
}),
|
||||
]),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /api/v1/admin/metrics', () => {
|
||||
it('returns 403 for VIEWER role', async () => {
|
||||
const res = await request(app)
|
||||
@@ -173,6 +212,9 @@ describe('Admin API', () => {
|
||||
expect(res.status).toBe(200)
|
||||
expect(res.body.data.id).toBe(billingAccountId)
|
||||
expect(res.body.data.company.id).toBe(companyId)
|
||||
expect(res.body.data.openBalance).toEqual(expect.any(Number))
|
||||
expect(res.body.data.paidBalance).toEqual(expect.any(Number))
|
||||
expect(res.body.data.creditBalance).toEqual(expect.any(Number))
|
||||
expect(Array.isArray(res.body.data.invoices)).toBe(true)
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user