mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-23 06:10:32 +00:00
refactor: split retry+diagnostics tests, drop redundant useRemoteCombo return interface
- Split retryAndDiagnostics.test.ts into retry.test.ts + diagnostics.test.ts so each test file mirrors its source file - Add explicit ERR_CANCELED test case in retry.test.ts - Drop UseRemoteComboResult interface — useRemoteCombo has a single caller, inferring the return shape removes redundant type definition (per @christian-byrne)
This commit is contained in:
@@ -1,71 +1,8 @@
|
||||
import { AxiosError, AxiosHeaders } from 'axios'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { getBackoff, isRetriableError } from '@/base/remote/retry'
|
||||
import { summarizeError, summarizePayload } from '@/base/remote/diagnostics'
|
||||
|
||||
describe('getBackoff', () => {
|
||||
it('grows exponentially from 1s', () => {
|
||||
expect(getBackoff(1)).toBe(2000)
|
||||
expect(getBackoff(2)).toBe(4000)
|
||||
expect(getBackoff(3)).toBe(8000)
|
||||
expect(getBackoff(4)).toBe(16000)
|
||||
})
|
||||
|
||||
it('caps at 16s for higher attempt counts', () => {
|
||||
expect(getBackoff(5)).toBe(16000)
|
||||
expect(getBackoff(10)).toBe(16000)
|
||||
expect(getBackoff(100)).toBe(16000)
|
||||
})
|
||||
})
|
||||
|
||||
describe('isRetriableError', () => {
|
||||
function axiosErrorWithStatus(status: number): AxiosError {
|
||||
return new AxiosError(
|
||||
`HTTP ${status}`,
|
||||
'ERR_BAD_RESPONSE',
|
||||
undefined,
|
||||
undefined,
|
||||
{
|
||||
status,
|
||||
statusText: '',
|
||||
headers: {},
|
||||
config: { headers: new AxiosHeaders() },
|
||||
data: null
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
it('retries non-axios errors (e.g. unexpected throws)', () => {
|
||||
expect(isRetriableError(new Error('boom'))).toBe(true)
|
||||
expect(isRetriableError('string error')).toBe(true)
|
||||
expect(isRetriableError(undefined)).toBe(true)
|
||||
})
|
||||
|
||||
it('retries axios errors with no response (network failures)', () => {
|
||||
const err = new AxiosError('Network Error', 'ERR_NETWORK')
|
||||
expect(isRetriableError(err)).toBe(true)
|
||||
})
|
||||
|
||||
it('retries 5xx responses', () => {
|
||||
expect(isRetriableError(axiosErrorWithStatus(500))).toBe(true)
|
||||
expect(isRetriableError(axiosErrorWithStatus(502))).toBe(true)
|
||||
expect(isRetriableError(axiosErrorWithStatus(503))).toBe(true)
|
||||
})
|
||||
|
||||
it('retries 408 (request timeout) and 429 (too many requests)', () => {
|
||||
expect(isRetriableError(axiosErrorWithStatus(408))).toBe(true)
|
||||
expect(isRetriableError(axiosErrorWithStatus(429))).toBe(true)
|
||||
})
|
||||
|
||||
it('does not retry other 4xx responses', () => {
|
||||
expect(isRetriableError(axiosErrorWithStatus(400))).toBe(false)
|
||||
expect(isRetriableError(axiosErrorWithStatus(401))).toBe(false)
|
||||
expect(isRetriableError(axiosErrorWithStatus(403))).toBe(false)
|
||||
expect(isRetriableError(axiosErrorWithStatus(404))).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('summarizeError', () => {
|
||||
it('extracts message, code and status from an axios error', () => {
|
||||
const err = new AxiosError(
|
||||
71
src/base/remote/retry.test.ts
Normal file
71
src/base/remote/retry.test.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { AxiosError, AxiosHeaders } from 'axios'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { getBackoff, isRetriableError } from '@/base/remote/retry'
|
||||
|
||||
describe('getBackoff', () => {
|
||||
it('grows exponentially from 1s', () => {
|
||||
expect(getBackoff(1)).toBe(2000)
|
||||
expect(getBackoff(2)).toBe(4000)
|
||||
expect(getBackoff(3)).toBe(8000)
|
||||
expect(getBackoff(4)).toBe(16000)
|
||||
})
|
||||
|
||||
it('caps at 16s for higher attempt counts', () => {
|
||||
expect(getBackoff(5)).toBe(16000)
|
||||
expect(getBackoff(10)).toBe(16000)
|
||||
expect(getBackoff(100)).toBe(16000)
|
||||
})
|
||||
})
|
||||
|
||||
describe('isRetriableError', () => {
|
||||
function axiosErrorWithStatus(status: number): AxiosError {
|
||||
return new AxiosError(
|
||||
`HTTP ${status}`,
|
||||
'ERR_BAD_RESPONSE',
|
||||
undefined,
|
||||
undefined,
|
||||
{
|
||||
status,
|
||||
statusText: '',
|
||||
headers: {},
|
||||
config: { headers: new AxiosHeaders() },
|
||||
data: null
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
it('retries non-axios errors (e.g. unexpected throws)', () => {
|
||||
expect(isRetriableError(new Error('boom'))).toBe(true)
|
||||
expect(isRetriableError('string error')).toBe(true)
|
||||
expect(isRetriableError(undefined)).toBe(true)
|
||||
})
|
||||
|
||||
it('retries axios errors with no response (network failures)', () => {
|
||||
const err = new AxiosError('Network Error', 'ERR_NETWORK')
|
||||
expect(isRetriableError(err)).toBe(true)
|
||||
})
|
||||
|
||||
it('does not retry canceled axios requests (ERR_CANCELED)', () => {
|
||||
const err = new AxiosError('canceled', 'ERR_CANCELED')
|
||||
expect(isRetriableError(err)).toBe(false)
|
||||
})
|
||||
|
||||
it('retries 5xx responses', () => {
|
||||
expect(isRetriableError(axiosErrorWithStatus(500))).toBe(true)
|
||||
expect(isRetriableError(axiosErrorWithStatus(502))).toBe(true)
|
||||
expect(isRetriableError(axiosErrorWithStatus(503))).toBe(true)
|
||||
})
|
||||
|
||||
it('retries 408 (request timeout) and 429 (too many requests)', () => {
|
||||
expect(isRetriableError(axiosErrorWithStatus(408))).toBe(true)
|
||||
expect(isRetriableError(axiosErrorWithStatus(429))).toBe(true)
|
||||
})
|
||||
|
||||
it('does not retry other 4xx responses', () => {
|
||||
expect(isRetriableError(axiosErrorWithStatus(400))).toBe(false)
|
||||
expect(isRetriableError(axiosErrorWithStatus(401))).toBe(false)
|
||||
expect(isRetriableError(axiosErrorWithStatus(403))).toBe(false)
|
||||
expect(isRetriableError(axiosErrorWithStatus(404))).toBe(false)
|
||||
})
|
||||
})
|
||||
@@ -1,5 +1,5 @@
|
||||
import { computed, ref, toValue, watch } from 'vue'
|
||||
import type { ComputedRef, MaybeRefOrGetter, Ref } from 'vue'
|
||||
import type { MaybeRefOrGetter, Ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import {
|
||||
@@ -23,22 +23,7 @@ interface UseRemoteComboArgs {
|
||||
enabled?: MaybeRefOrGetter<boolean>
|
||||
}
|
||||
|
||||
interface UseRemoteComboResult {
|
||||
isOpen: Ref<boolean>
|
||||
searchQuery: Ref<string>
|
||||
items: ComputedRef<DropdownItemShape[]>
|
||||
filteredItems: ComputedRef<DropdownItemShape[]>
|
||||
isLoading: ComputedRef<boolean>
|
||||
isFetching: ComputedRef<boolean>
|
||||
errorMessage: ComputedRef<string | null>
|
||||
refresh: () => Promise<void>
|
||||
select: (id: string) => void
|
||||
selectedValue: Ref<string | undefined>
|
||||
fieldLabel: ComputedRef<string>
|
||||
previewType: ComputedRef<RemoteComboPreviewType>
|
||||
}
|
||||
|
||||
export function useRemoteCombo(args: UseRemoteComboArgs): UseRemoteComboResult {
|
||||
export function useRemoteCombo(args: UseRemoteComboArgs) {
|
||||
const { t } = useI18n()
|
||||
const isOpen = ref(false)
|
||||
const searchQuery = ref('')
|
||||
|
||||
Reference in New Issue
Block a user