mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-11-10 04:12:08 +08:00
test: trim redundant test coverage
This commit is contained in:
@@ -1,98 +0,0 @@
|
||||
// @vitest-environment jsdom
|
||||
import { renderHook } from '@testing-library/react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { useForgetSelection, useRecordSelection } from './use-record-selection'
|
||||
|
||||
const recordSelectedNode = vi.hoisted(() => vi.fn(() => Promise.resolve()))
|
||||
const forgetSelectedNode = vi.hoisted(() => vi.fn(() => Promise.resolve()))
|
||||
|
||||
vi.mock('@/services/cmds', () => ({ forgetSelectedNode, recordSelectedNode }))
|
||||
|
||||
const record = (groupName: string, proxyName: string) => {
|
||||
const { result } = renderHook(() => useRecordSelection())
|
||||
result.current(groupName, proxyName)
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
recordSelectedNode.mockClear()
|
||||
forgetSelectedNode.mockClear()
|
||||
})
|
||||
|
||||
describe('useForgetSelection', () => {
|
||||
it('sends only the group name', () => {
|
||||
const { result } = renderHook(() => useForgetSelection())
|
||||
|
||||
result.current('Proxy')
|
||||
|
||||
expect(forgetSelectedNode).toHaveBeenCalledWith('Proxy')
|
||||
})
|
||||
|
||||
it('resolves after the clear request finishes', async () => {
|
||||
let resolveForget!: () => void
|
||||
forgetSelectedNode.mockImplementationOnce(
|
||||
() => new Promise<void>((resolve) => (resolveForget = resolve)),
|
||||
)
|
||||
const { result } = renderHook(() => useForgetSelection())
|
||||
|
||||
const forget = result.current('Proxy')
|
||||
let settled = false
|
||||
forget.then(() => {
|
||||
settled = true
|
||||
})
|
||||
|
||||
await Promise.resolve()
|
||||
expect(settled).toBe(false)
|
||||
|
||||
resolveForget()
|
||||
await forget
|
||||
expect(settled).toBe(true)
|
||||
})
|
||||
|
||||
it('reports a failed clear without throwing at the caller', async () => {
|
||||
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
forgetSelectedNode.mockRejectedValueOnce(new Error('no profile'))
|
||||
const { result } = renderHook(() => useForgetSelection())
|
||||
|
||||
expect(() => result.current('Proxy')).not.toThrow()
|
||||
|
||||
await vi.waitFor(() => expect(consoleError).toHaveBeenCalled())
|
||||
consoleError.mockRestore()
|
||||
})
|
||||
})
|
||||
|
||||
describe('useRecordSelection', () => {
|
||||
it('sends only the group and the node', () => {
|
||||
record('Proxy', 'Node A')
|
||||
|
||||
expect(recordSelectedNode).toHaveBeenCalledWith('Proxy', 'Node A')
|
||||
})
|
||||
|
||||
it('does not derive anything from a rendered selection list', () => {
|
||||
// Pair-wise writes let the backend merge concurrent choices against fresh state.
|
||||
record('Proxy', 'Node A')
|
||||
record('Fallback', 'Node C')
|
||||
|
||||
expect(recordSelectedNode).toHaveBeenNthCalledWith(1, 'Proxy', 'Node A')
|
||||
expect(recordSelectedNode).toHaveBeenNthCalledWith(2, 'Fallback', 'Node C')
|
||||
})
|
||||
|
||||
it('is stable across renders, so callers may hold it in a dependency array', () => {
|
||||
const { result, rerender } = renderHook(() => useRecordSelection())
|
||||
const first = result.current
|
||||
|
||||
rerender()
|
||||
|
||||
expect(result.current).toBe(first)
|
||||
})
|
||||
|
||||
it('reports a failed write without throwing at the caller', async () => {
|
||||
// Persistence failure cannot roll back a core selection that already succeeded.
|
||||
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
recordSelectedNode.mockRejectedValueOnce(new Error('no profile'))
|
||||
|
||||
expect(() => record('Proxy', 'Node A')).not.toThrow()
|
||||
|
||||
await vi.waitFor(() => expect(consoleError).toHaveBeenCalled())
|
||||
})
|
||||
})
|
||||
@@ -1,147 +0,0 @@
|
||||
// @vitest-environment jsdom
|
||||
import { act, cleanup, renderHook } from '@testing-library/react'
|
||||
import { afterEach, beforeEach, expect, it, vi } from 'vitest'
|
||||
|
||||
import { useSystemProxyState } from './use-system-proxy-state'
|
||||
|
||||
const patchVergeConfig = vi.hoisted(() => vi.fn())
|
||||
const mutateVerge = vi.hoisted(() => vi.fn())
|
||||
const getCacheData = vi.hoisted(() => vi.fn())
|
||||
const revalidateQueries = vi.hoisted(() => vi.fn())
|
||||
|
||||
const CACHED: IVergeConfig = { enable_system_proxy: false } as IVergeConfig
|
||||
|
||||
vi.mock('@/hooks/use-verge', () => ({
|
||||
useVerge: () => ({ verge: CACHED, mutateVerge }),
|
||||
}))
|
||||
vi.mock('@/hooks/use-displayed-mixed-port', () => ({
|
||||
useDisplayedMixedPort: () => 7897,
|
||||
}))
|
||||
vi.mock('@/providers/app-data-context', () => ({
|
||||
useSystemData: () => ({ sysproxy: undefined }),
|
||||
}))
|
||||
vi.mock('@/services/cmds', () => ({
|
||||
getAutotemProxy: vi.fn(),
|
||||
getEmbeddedServerPort: vi.fn(),
|
||||
patchVergeConfig,
|
||||
}))
|
||||
vi.mock('tauri-plugin-mihomo-api', () => ({
|
||||
closeAllConnections: vi.fn(() => Promise.resolve()),
|
||||
}))
|
||||
vi.mock('@/services/query-client', () => ({
|
||||
useQuery: () => ({ data: undefined }),
|
||||
getCacheData,
|
||||
revalidateQueries,
|
||||
}))
|
||||
|
||||
beforeEach(() => {
|
||||
patchVergeConfig.mockReset()
|
||||
mutateVerge.mockReset()
|
||||
getCacheData.mockReset()
|
||||
getCacheData.mockReturnValue(CACHED)
|
||||
revalidateQueries.mockReset()
|
||||
revalidateQueries.mockResolvedValue([])
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
cleanup()
|
||||
})
|
||||
|
||||
const lastWrite = () => {
|
||||
const call = mutateVerge.mock.calls[mutateVerge.mock.calls.length - 1]?.[0]
|
||||
return typeof call === 'function' ? call(CACHED) : call
|
||||
}
|
||||
|
||||
it('puts the cache back when the toggle fails', async () => {
|
||||
patchVergeConfig.mockRejectedValue({
|
||||
code: 'SYSPROXY_PRIVILEGE_REQUIRED',
|
||||
detail: 'refused',
|
||||
})
|
||||
const { result } = renderHook(() => useSystemProxyState())
|
||||
|
||||
await act(async () => {
|
||||
await expect(result.current.toggleSystemProxy(true)).rejects.toBeTruthy()
|
||||
})
|
||||
|
||||
expect(lastWrite()).toMatchObject({ enable_system_proxy: false })
|
||||
})
|
||||
|
||||
it('falls back to what the last successful click reached, not to where the run began', async () => {
|
||||
patchVergeConfig.mockResolvedValueOnce(undefined).mockRejectedValueOnce({
|
||||
code: 'SYSPROXY_PRIVILEGE_REQUIRED',
|
||||
detail: 'refused',
|
||||
})
|
||||
getCacheData.mockReturnValue({ enable_system_proxy: true } as IVergeConfig)
|
||||
const { result } = renderHook(() => useSystemProxyState())
|
||||
|
||||
await act(async () => {
|
||||
const inFlight = result.current.toggleSystemProxy(false)
|
||||
void result.current.toggleSystemProxy(true)
|
||||
await expect(inFlight).rejects.toBeTruthy()
|
||||
})
|
||||
|
||||
expect(lastWrite()).toMatchObject({ enable_system_proxy: false })
|
||||
})
|
||||
|
||||
it('lets a revalidation failure surface when the toggle itself worked', async () => {
|
||||
patchVergeConfig.mockResolvedValue(undefined)
|
||||
revalidateQueries.mockRejectedValue(new Error('network gone'))
|
||||
const { result } = renderHook(() => useSystemProxyState())
|
||||
|
||||
await act(async () => {
|
||||
await expect(result.current.toggleSystemProxy(true)).rejects.toThrow(
|
||||
'network gone',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('reports the failure the backend classified, not a revalidation that failed after it', async () => {
|
||||
patchVergeConfig.mockRejectedValue({
|
||||
code: 'SYSPROXY_PRIVILEGE_REQUIRED',
|
||||
detail: 'refused',
|
||||
})
|
||||
revalidateQueries.mockRejectedValue(new Error('network gone'))
|
||||
const { result } = renderHook(() => useSystemProxyState())
|
||||
|
||||
await act(async () => {
|
||||
await expect(result.current.toggleSystemProxy(true)).rejects.toMatchObject({
|
||||
code: 'SYSPROXY_PRIVILEGE_REQUIRED',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('revalidates the config it wrote to, not only the two proxy reads', async () => {
|
||||
patchVergeConfig.mockResolvedValue(undefined)
|
||||
const { result } = renderHook(() => useSystemProxyState())
|
||||
|
||||
await act(async () => {
|
||||
await result.current.toggleSystemProxy(true)
|
||||
})
|
||||
|
||||
expect(revalidateQueries).toHaveBeenCalledWith([
|
||||
['getVergeConfig'],
|
||||
['getSystemProxy'],
|
||||
['getAutotemProxy'],
|
||||
])
|
||||
})
|
||||
|
||||
it('drops a click queued behind one that failed', async () => {
|
||||
let rejectFirst: ((reason: unknown) => void) | undefined
|
||||
patchVergeConfig.mockImplementationOnce(
|
||||
() =>
|
||||
new Promise((_resolve, reject) => {
|
||||
rejectFirst = reject
|
||||
}),
|
||||
)
|
||||
const { result } = renderHook(() => useSystemProxyState())
|
||||
|
||||
let inFlight: Promise<unknown> = Promise.resolve()
|
||||
await act(async () => {
|
||||
inFlight = result.current.toggleSystemProxy(true)
|
||||
void result.current.toggleSystemProxy(false)
|
||||
rejectFirst?.({ code: 'SYSPROXY_PRIVILEGE_REQUIRED', detail: 'refused' })
|
||||
await expect(inFlight).rejects.toBeTruthy()
|
||||
})
|
||||
|
||||
expect(patchVergeConfig).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
@@ -1,32 +0,0 @@
|
||||
// @vitest-environment jsdom
|
||||
import { act, renderHook, waitFor } from '@testing-library/react'
|
||||
import { beforeEach, expect, test, vi } from 'vitest'
|
||||
|
||||
import { setPreloadConfig } from '@/services/preload'
|
||||
|
||||
import { useUpdate } from './use-update'
|
||||
|
||||
const check = vi.hoisted(() => vi.fn())
|
||||
|
||||
vi.mock('@tauri-apps/plugin-updater', () => ({ check }))
|
||||
|
||||
beforeEach(() => {
|
||||
localStorage.clear()
|
||||
setPreloadConfig({ auto_check_update: false } as IVergeConfig)
|
||||
check.mockReset()
|
||||
})
|
||||
|
||||
test('manual update check works when automatic checks are disabled', async () => {
|
||||
const availableUpdate = { version: '9.9.9' }
|
||||
check.mockResolvedValueOnce(availableUpdate)
|
||||
const { result } = renderHook(() => useUpdate())
|
||||
|
||||
let checked
|
||||
await act(async () => {
|
||||
checked = await result.current.checkUpdate()
|
||||
})
|
||||
|
||||
expect(check).toHaveBeenCalledOnce()
|
||||
expect(checked).toEqual({ data: availableUpdate })
|
||||
await waitFor(() => expect(result.current.lastCheckUpdate).not.toBeNull())
|
||||
})
|
||||
Reference in New Issue
Block a user