fix(tests): enhance fetch mocks and type safety in settings and audit tests
Docker / build (push) Failing after 30s

Updated fetch mocks in settings and audit test files to improve type safety by specifying the fetch type. Adjusted handling of mock call parameters to ensure proper access to request options. This enhances test reliability and clarity in error handling scenarios.
This commit is contained in:
Denozordec
2026-08-02 19:52:18 +07:00
parent 0177f5d539
commit c14cf3953e
6 changed files with 36 additions and 40 deletions
+8 -6
View File
@@ -46,7 +46,9 @@ describe('audit dual-write', () => {
})
it('fire-and-forgets portal ingest with vps action key', async () => {
const fetchMock = vi.fn(async () => new Response(JSON.stringify({ accepted: 1, duplicates: 0 })))
const fetchMock = vi.fn<typeof fetch>(
async () => new Response(JSON.stringify({ accepted: 1, duplicates: 0 })),
)
vi.stubGlobal('fetch', fetchMock)
auditCreate(
@@ -63,15 +65,15 @@ describe('audit dual-write', () => {
await vi.waitFor(() => expect(fetchMock).toHaveBeenCalledTimes(1))
const [url, init] = fetchMock.mock.calls[0] as [string, RequestInit]
const [url, init] = fetchMock.mock.calls[0]!
expect(url).toBe('http://portal.test/api/v1/ingest/audit')
expect(init.method).toBe('POST')
expect(init.headers).toMatchObject({
expect(init?.method).toBe('POST')
expect(init?.headers).toMatchObject({
Authorization: 'Bearer test-ingest-secret',
'Content-Type': 'application/json',
})
const body = JSON.parse(String(init.body)) as {
const body = JSON.parse(String(init?.body)) as {
events: Array<{
event_id: string
source_app: string
@@ -94,7 +96,7 @@ describe('audit dual-write', () => {
it('does not throw when portal ingest fails', () => {
vi.stubGlobal(
'fetch',
vi.fn(async () => {
vi.fn<typeof fetch>(async () => {
throw new Error('network down')
}),
)
@@ -3,18 +3,15 @@
*/
import type { BillmanagerSyncAccount } from './context.js'
import type { SyncFromBillmanagerOptions, SyncFromBillmanagerResult } from './sync.js'
import type { SyncFromBillmanagerOptions } from './sync.js'
import { billmanagerAdapter } from '../providers/billmanager-adapter.js'
import { runAccountSync } from '../providers/sync-job.js'
import { runAccountSync, type RunAccountSyncResult } from '../providers/sync-job.js'
export interface RunBillmanagerAccountSyncResult extends SyncFromBillmanagerResult {
ok: true
logId: string
}
export type RunBillmanagerAccountSyncResult = RunAccountSyncResult
export async function runBillmanagerAccountSync(
account: BillmanagerSyncAccount,
opts: SyncFromBillmanagerOptions = {},
): Promise<RunBillmanagerAccountSyncResult> {
): Promise<RunAccountSyncResult> {
return runAccountSync(billmanagerAdapter, account, opts)
}
+6 -1
View File
@@ -9,7 +9,12 @@ export interface SyncResult {
vpsCount: number
paymentsCount: number
tariffsCount: number
balance: { balance?: number; currency?: string } | null
balance: {
balance?: number
currency?: string
enoughmoneyto?: string
realbalance?: string
} | null
syncSummary: SyncSummary
newTariffs: { name: string; price: string; providerId: string }[]
}
+1 -11
View File
@@ -30,20 +30,10 @@ function roundRate(n: number): number {
return Math.round(n * 100) / 100
}
function mapBillingCycle(cycle: string | undefined): {
tariffType: string
dailyRate: number | null
monthlyRate: number | null
} {
const c = String(cycle ?? '').toLowerCase()
return { tariffType: c.includes('day') ? 'daily' : 'monthly', dailyRate: null, monthlyRate: null }
}
function ratesFromTotal(
total: number,
cycle: string | undefined,
): { tariffType: string; dailyRate: number | null; monthlyRate: number | null } {
const base = mapBillingCycle(cycle)
const c = String(cycle ?? '').toLowerCase()
if (c.includes('day')) {
return { tariffType: 'daily', dailyRate: roundRate(total), monthlyRate: null }
@@ -253,7 +243,7 @@ export function mapVpsRecordToVps(
currency,
dailyRate: rates.dailyRate,
monthlyRate: rates.monthlyRate,
createdAt: dateToIso(detail.date_created),
createdAt: dateToIso(serviceDetail?.date_created),
paidUntil: dateToIso(detail.next_due ?? service.next_due),
notes: label ? `${label} [veesp-${externalId}]` : `veesp-${externalId}`,
}
+3 -2
View File
@@ -62,6 +62,7 @@ export interface VeespVmDetail extends VeespVmListItem {
}
export interface VeespIpItem {
id?: string | number
ip?: string
address?: string
ipaddress?: string
@@ -207,7 +208,7 @@ export function isVpsService(service: VeespServiceListItem, vpsCategoryIds?: Set
return false
}
function unwrapKeyedList<T extends Record<string, unknown>>(raw: unknown): T[] {
function unwrapKeyedList<T>(raw: unknown): T[] {
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return []
const out: T[] = []
for (const [key, item] of Object.entries(raw as Record<string, unknown>)) {
@@ -218,7 +219,7 @@ function unwrapKeyedList<T extends Record<string, unknown>>(raw: unknown): T[] {
}
if (typeof item !== 'object') continue
const row = item as Record<string, unknown>
out.push({ ...row, id: row.id ?? key } as T)
out.push({ ...row, id: row.id ?? key } as unknown as T)
}
return out
}