fix(tests): enhance fetch mocks and type safety in settings and audit tests
Docker / build (push) Failing after 30s
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:
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 }[]
|
||||
}
|
||||
|
||||
@@ -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}`,
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user