test: trim redundant test coverage

This commit is contained in:
wonfen
2026-08-19 10:24:37 +08:00
parent 807f9a206d
commit e15ddab542
38 changed files with 194 additions and 4259 deletions
@@ -1,173 +0,0 @@
// @vitest-environment jsdom
import {
cleanup,
fireEvent,
render,
screen,
waitFor,
} from '@testing-library/react'
import i18next from 'i18next'
import { initReactI18next } from 'react-i18next'
import { afterEach, beforeAll, expect, it, vi } from 'vitest'
import {
getSnapshotNotices,
hideNotice,
showNotice,
} from '@/services/notice-service'
import { NoticeManager } from './notice-manager'
const writeText = vi.fn((_text: string) => Promise.resolve())
const restartCore = vi.hoisted(() => vi.fn(() => Promise.resolve()))
const installService = vi.hoisted(() => vi.fn(() => Promise.resolve()))
const getRuntimeState = vi.hoisted(() => vi.fn())
vi.mock('@/services/cmds', () => ({
restartCore,
installService,
getRuntimeState,
}))
vi.mock('@/utils/get-system', () => ({ default: () => 'macos' }))
beforeAll(async () => {
await i18next.use(initReactI18next).init({
lng: 'en',
resources: {
en: {
translation: {
settings: {
modals: {
backup: {
messages: { backupFailed: 'Backup failed: {{error}}' },
},
},
},
},
},
},
interpolation: { escapeValue: false },
})
Object.defineProperty(navigator, 'clipboard', {
value: { writeText },
configurable: true,
})
})
afterEach(() => {
restartCore.mockClear()
restartCore.mockImplementation(() => Promise.resolve())
installService.mockClear()
installService.mockImplementation(() => Promise.resolve())
getRuntimeState.mockReset()
getRuntimeState.mockResolvedValue({ mode: 'Service', serviceUsable: true })
cleanup()
getSnapshotNotices().forEach((notice) => hideNotice(notice.id))
writeText.mockClear()
})
const noticeText = () => screen.getByRole('alert').textContent ?? ''
it('renders a failure detail that fits, in full', () => {
showNotice.error({ code: 'CORE_START_FAILED', detail: 'connection refused' })
render(<NoticeManager />)
expect(noticeText()).toContain('connection refused')
})
it('shortens an unbounded detail', () => {
showNotice.error({
code: 'SERVICE_INSTALL_FAILED',
detail: `${'x'.repeat(4000)} tail`,
})
render(<NoticeManager />)
expect(noticeText().length).toBeLessThanOrEqual(501)
expect(noticeText()).not.toContain('tail')
expect(noticeText()).toContain('…')
})
it('shortens a detail a caller interpolated into its own message', () => {
showNotice.error('profiles.page.feedback.notices.emergencyRefreshFailed', {
message: 'y'.repeat(4000),
})
render(<NoticeManager />)
expect(noticeText().length).toBeLessThanOrEqual(501)
expect(noticeText()).toContain('…')
})
it('renders a failure a caller interpolated, not [object Object]', () => {
showNotice.error('settings.modals.backup.messages.backupFailed', {
error: { code: 'BACKUP_FAILED', detail: 'webdav returned 401' },
})
render(<NoticeManager />)
expect(noticeText()).toBe('Backup failed: webdav returned 401')
})
it('renders a failure inside a descriptor, not [object Object]', () => {
showNotice.error({
key: 'settings.modals.backup.messages.backupFailed',
params: { error: { code: 'BACKUP_FAILED', detail: 'webdav returned 401' } },
})
render(<NoticeManager />)
expect(noticeText()).toBe('Backup failed: webdav returned 401')
})
it('leaves the ordinary lifetime alone where there is nothing to offer', () => {
showNotice.error({ code: 'CORE_START_FAILED', detail: 'connection refused' })
expect(getSnapshotNotices().at(-1)?.duration).toBeGreaterThan(0)
})
it('finds the code a caller interpolated into its own message', () => {
showNotice.error('settings.modals.backup.messages.backupFailed', {
error: { code: 'SYSPROXY_GUARD_STOPPED', detail: 'the guard gave up' },
})
expect(getSnapshotNotices().at(-1)?.code).toBe('SYSPROXY_GUARD_STOPPED')
})
it('shows one notice per code, replacing rather than stacking', async () => {
showNotice.error({ code: 'SYSPROXY_GUARD_STOPPED', detail: 'first' })
showNotice.error({ code: 'SYSPROXY_GUARD_STOPPED', detail: 'second' })
render(<NoticeManager />)
expect(screen.getAllByRole('alert')).toHaveLength(1)
expect(screen.getByRole('alert').textContent).toContain('second')
})
it('remembers which way the user was asking, for whoever acts on it next', () => {
showNotice.error({
code: 'SYSPROXY_GUARD_STOPPED',
detail: 'admin privileges required to modify system proxy',
operation: 'systemProxyEnable',
})
expect(getSnapshotNotices().at(-1)?.operation).toBe('systemProxyEnable')
})
it('copies the whole detail, not the shortened one', async () => {
const detail = `${'x'.repeat(4000)} tail`
showNotice.error({ code: 'SERVICE_INSTALL_FAILED', detail })
render(<NoticeManager />)
fireEvent.contextMenu(screen.getByRole('alert'))
await waitFor(() => expect(writeText).toHaveBeenCalledOnce())
expect(writeText).toHaveBeenCalledWith(detail)
})
it('copies the whole message when the caller interpolated the detail', async () => {
const detail = 'y'.repeat(4000)
showNotice.error('profiles.page.feedback.notices.emergencyRefreshFailed', {
message: detail,
})
render(<NoticeManager />)
fireEvent.contextMenu(screen.getByRole('alert'))
await waitFor(() => expect(writeText).toHaveBeenCalledOnce())
expect(writeText.mock.calls[0]?.[0]).toContain(detail)
})
@@ -1,350 +0,0 @@
// @vitest-environment jsdom
import {
act,
cleanup,
fireEvent,
render,
screen,
waitFor,
} from '@testing-library/react'
import i18next from 'i18next'
import { initReactI18next } from 'react-i18next'
import { afterEach, beforeAll, expect, it, vi } from 'vitest'
import type { PendingFailure } from '@/services/cmds'
import { getSnapshotNotices, hideNotice } from '@/services/notice-service'
import { clearServiceRequest, requestService } from '@/services/service-request'
const reported = (key: string) =>
getSnapshotNotices().some(
(notice) =>
notice.i18n?.key === key ||
Object.values(notice.i18n?.params ?? {}).some(
(param) =>
typeof param === 'object' &&
param !== null &&
'key' in param &&
(param as { key?: unknown }).key === key,
),
)
import { SysproxyPrivilegeDialog } from './sysproxy-privilege-dialog'
const restartCore = vi.hoisted(() => vi.fn(() => Promise.resolve()))
const installService = vi.hoisted(() => vi.fn(() => Promise.resolve()))
const getRuntimeState = vi.hoisted(() => vi.fn())
const getPendingFailures = vi.hoisted(() => vi.fn())
const patchVergeConfig = vi.hoisted(() => vi.fn(() => Promise.resolve()))
const onFocusChanged = vi.hoisted(() => vi.fn(() => Promise.resolve(() => {})))
vi.mock('@/services/cmds', () => ({
restartCore,
installService,
getRuntimeState,
getPendingFailures,
patchVergeConfig,
}))
vi.mock('@tauri-apps/api/window', () => ({
getCurrentWindow: () => ({ onFocusChanged }),
}))
let onSubscribed: (() => void) | undefined
vi.mock('@/services/events', () => ({
subscribeVergeEvents: (
_handlers: Record<string, () => void>,
subscribed?: () => void,
) => {
onSubscribed = subscribed
return () => {}
},
}))
const failure = (
code: string,
operation: PendingFailure['operation'] = 'systemProxyEnable',
): PendingFailure => ({
code,
detail: 'admin privileges required to modify system proxy',
operation,
sequence: 1,
})
beforeAll(async () => {
await i18next.use(initReactI18next).init({
lng: 'en',
resources: { en: { translation: {} } },
interpolation: { escapeValue: false },
})
})
afterEach(() => {
restartCore.mockClear()
restartCore.mockImplementation(() => Promise.resolve())
installService.mockClear()
installService.mockImplementation(() => Promise.resolve())
getRuntimeState.mockReset()
getRuntimeState.mockResolvedValue({ mode: 'Service', serviceUsable: true })
getPendingFailures.mockReset()
patchVergeConfig.mockClear()
patchVergeConfig.mockImplementation(() => Promise.resolve())
onSubscribed = undefined
clearServiceRequest()
cleanup()
getSnapshotNotices().forEach((notice) => hideNotice(notice.id))
})
const showing = async (
code: string,
operation: PendingFailure['operation'] = 'systemProxyEnable',
) => {
getPendingFailures.mockResolvedValue([failure(code, operation)])
render(<SysproxyPrivilegeDialog />)
onSubscribed?.()
await screen.findByRole('dialog')
}
const clickPrimary = (name: string) =>
fireEvent.click(screen.getByRole('button', { name }))
it('offers to install the service when the write was refused', async () => {
await showing('SYSPROXY_PRIVILEGE_REQUIRED')
expect(
screen.getByRole('button', {
name: 'settings.sections.proxyControl.actions.installService',
}),
).toBeTruthy()
})
it('offers only a restart when the service is already there', async () => {
await showing('SYSPROXY_SIDECAR_WHILE_SERVICE_READY')
expect(
screen.getByRole('button', {
name: 'settings.sections.proxyControl.actions.switchToServiceMode',
}),
).toBeTruthy()
expect(
screen.queryByRole('button', {
name: 'settings.sections.proxyControl.actions.installService',
}),
).toBeNull()
})
it('installs the service, restarts into it, and makes the request again', async () => {
await showing('SYSPROXY_PRIVILEGE_REQUIRED')
clickPrimary('settings.sections.proxyControl.actions.installService')
await waitFor(() => expect(installService).toHaveBeenCalledOnce())
await waitFor(() => expect(restartCore).toHaveBeenCalledOnce())
await waitFor(() =>
expect(patchVergeConfig).toHaveBeenCalledWith({
enable_system_proxy: true,
}),
)
await waitFor(() =>
expect(
reported(
'settings.sections.proxyControl.messages.installedProxyRestored',
),
).toBe(true),
)
})
it('replays the direction that was asked for, not always “on”', async () => {
await showing('SYSPROXY_PRIVILEGE_REQUIRED', 'systemProxyDisable')
clickPrimary('settings.sections.proxyControl.actions.installService')
await waitFor(() =>
expect(patchVergeConfig).toHaveBeenCalledWith({
enable_system_proxy: false,
}),
)
})
it('changes nothing when nobody asked for a proxy state', async () => {
await showing('SYSPROXY_PRIVILEGE_REQUIRED', 'systemProxyRestore')
clickPrimary('settings.sections.proxyControl.actions.installService')
await waitFor(() => expect(restartCore).toHaveBeenCalledOnce())
expect(patchVergeConfig).not.toHaveBeenCalled()
await waitFor(() =>
expect(
reported('settings.sections.proxyControl.messages.installedCheckProxy'),
).toBe(true),
)
})
it('does not install again when only the restart is needed', async () => {
await showing('SYSPROXY_SIDECAR_WHILE_SERVICE_READY')
clickPrimary('settings.sections.proxyControl.actions.switchToServiceMode')
await waitFor(() => expect(restartCore).toHaveBeenCalledOnce())
expect(installService).not.toHaveBeenCalled()
})
it('checks what actually happened rather than trusting the restart', async () => {
getRuntimeState.mockResolvedValue({ mode: 'Sidecar', serviceUsable: true })
await showing('SYSPROXY_PRIVILEGE_REQUIRED')
clickPrimary('settings.sections.proxyControl.actions.installService')
await waitFor(() =>
expect(
reported(
'settings.sections.proxyControl.messages.installedCoreNotOnService',
),
).toBe(true),
)
})
const deferred = () => {
let resolve!: () => void
const promise = new Promise<void>((r) => {
resolve = r
})
return { promise, resolve }
}
it('says which part of the wait it is in, rather than looking stuck', async () => {
const installing = deferred()
const restarting = deferred()
const applying = deferred()
installService.mockImplementation(() => installing.promise)
restartCore.mockImplementation(() => restarting.promise)
patchVergeConfig.mockImplementation(() => applying.promise)
await showing('SYSPROXY_PRIVILEGE_REQUIRED')
clickPrimary('settings.sections.proxyControl.actions.installService')
await screen.findByText('layout.components.sysproxyPrivilege.installing')
installing.resolve()
await screen.findByText('layout.components.sysproxyPrivilege.restarting')
restarting.resolve()
await screen.findByText('layout.components.sysproxyPrivilege.applying')
applying.resolve()
await waitFor(() => expect(screen.queryByRole('dialog')).toBeNull())
})
it('does not claim to be installing when only a restart is needed', async () => {
const restarting = deferred()
restartCore.mockImplementation(() => restarting.promise)
await showing('SYSPROXY_SIDECAR_WHILE_SERVICE_READY')
clickPrimary('settings.sections.proxyControl.actions.switchToServiceMode')
await screen.findByText('layout.components.sysproxyPrivilege.restarting')
expect(
screen.queryByText('layout.components.sysproxyPrivilege.installing'),
).toBeNull()
restarting.resolve()
})
it('offers no way out while the installer is holding a password prompt', async () => {
const installing = deferred()
installService.mockImplementation(() => installing.promise)
await showing('SYSPROXY_PRIVILEGE_REQUIRED')
clickPrimary('settings.sections.proxyControl.actions.installService')
await screen.findByText('layout.components.sysproxyPrivilege.installing')
expect(
screen.queryByRole('button', {
name: 'layout.components.sysproxyPrivilege.later',
}),
).toBeNull()
installing.resolve()
})
it('closes once the core is on the service, whatever the table still says', async () => {
await showing('SYSPROXY_PRIVILEGE_REQUIRED')
clickPrimary('settings.sections.proxyControl.actions.installService')
await waitFor(() => expect(screen.queryByRole('dialog')).toBeNull())
})
it('stays open when the core did not reach the service', async () => {
getRuntimeState.mockResolvedValue({ mode: 'Sidecar', serviceUsable: false })
await showing('SYSPROXY_PRIVILEGE_REQUIRED')
clickPrimary('settings.sections.proxyControl.actions.installService')
await waitFor(() => expect(restartCore).toHaveBeenCalledOnce())
expect(screen.getByRole('dialog')).toBeTruthy()
})
it('does not go on to restart when the install itself failed', async () => {
installService.mockRejectedValue({
code: 'SERVICE_INSTALL_FAILED',
detail: 'user cancelled',
})
await showing('SYSPROXY_PRIVILEGE_REQUIRED')
clickPrimary('settings.sections.proxyControl.actions.installService')
await waitFor(() => expect(installService).toHaveBeenCalledOnce())
expect(restartCore).not.toHaveBeenCalled()
expect(getRuntimeState).not.toHaveBeenCalled()
expect(screen.getByRole('dialog')).toBeTruthy()
})
it('closes on “later” without touching the machine', async () => {
await showing('SYSPROXY_PRIVILEGE_REQUIRED')
clickPrimary('layout.components.sysproxyPrivilege.later')
await waitFor(() => expect(screen.queryByRole('dialog')).toBeNull())
expect(installService).not.toHaveBeenCalled()
expect(restartCore).not.toHaveBeenCalled()
})
it('answers a switch that asked outright, with no failure to go on', async () => {
getPendingFailures.mockResolvedValue([])
render(<SysproxyPrivilegeDialog />)
onSubscribed?.()
act(() =>
requestService({
reason: 'tunNeedsService',
restore: { enable_tun_mode: true },
}),
)
await screen.findByText('layout.components.sysproxyPrivilege.tunMessage')
clickPrimary('settings.sections.proxyControl.actions.installService')
await waitFor(() => expect(installService).toHaveBeenCalledOnce())
await waitFor(() =>
expect(patchVergeConfig).toHaveBeenCalledWith({ enable_tun_mode: true }),
)
await waitFor(() => expect(screen.queryByRole('dialog')).toBeNull())
})
it('shows what the user is doing now over what the table still holds', async () => {
await showing('SYSPROXY_PRIVILEGE_REQUIRED')
act(() => requestService({ reason: 'tunNeedsService' }))
await screen.findByText('layout.components.sysproxyPrivilege.tunMessage')
})
it('changes nothing when a switch asked without saying what for', async () => {
getPendingFailures.mockResolvedValue([])
render(<SysproxyPrivilegeDialog />)
onSubscribed?.()
act(() => requestService({ reason: 'tunNeedsService' }))
await screen.findByRole('dialog')
clickPrimary('settings.sections.proxyControl.actions.installService')
await waitFor(() => expect(restartCore).toHaveBeenCalledOnce())
expect(patchVergeConfig).not.toHaveBeenCalled()
})
@@ -1,120 +0,0 @@
import { describe, expect, test } from 'vitest'
import {
resolveEmptyListReason,
resolveProxyListState,
} from './proxy-empty-state-model'
const settled = {
isProfilesPending: false,
isProxyViewPending: false,
isRunningModePending: false,
}
const subscribed = {
current: 'a',
items: [{ uid: 'a', type: 'remote' }],
}
describe('resolveProxyListState', () => {
test('direct mode is its own outcome, not an empty list', () => {
const state = resolveProxyListState({
...settled,
mode: 'direct',
profiles: { current: undefined, items: [] },
})
expect(state).toEqual({ kind: 'direct' })
})
test('anything still loading outranks every verdict about emptiness', () => {
for (const pending of [
{ isProfilesPending: true },
{ isProxyViewPending: true },
{ isRunningModePending: true },
]) {
const state = resolveProxyListState({
...settled,
...pending,
mode: 'rule',
profiles: { current: undefined, items: [] },
})
expect(state).toEqual({ kind: 'loading' })
}
})
test('no subscription at all is reported before anything about proxies', () => {
const state = resolveProxyListState({
...settled,
mode: 'rule',
profiles: { current: undefined, items: [{ uid: 'a', type: 'merge' }] },
})
expect(state).toEqual({ kind: 'empty', reason: 'no-subscriptions' })
})
test('a subscription that is not the active one is its own explanation', () => {
const state = resolveProxyListState({
...settled,
mode: 'rule',
profiles: { current: 'other', items: [{ uid: 'a', type: 'remote' }] },
})
expect(state).toEqual({ kind: 'empty', reason: 'inactive-subscription' })
})
test('with a usable subscription it defers to the list rather than guessing', () => {
// The point of the split: this function no longer has an opinion on whether the
// renderer will find anything, because the two opinions used to disagree.
for (const mode of ['rule', 'script', 'global']) {
expect(
resolveProxyListState({ ...settled, mode, profiles: subscribed }),
).toEqual({
kind: 'render',
})
}
})
test('it asks nothing about the proxy view at all', () => {
// Guarding the shape, not just the behaviour: reintroducing a proxyView input here is
// how the second, divergent derivation came back.
const inputs = Object.keys({
...settled,
mode: 'rule',
profiles: subscribed,
})
expect(inputs).not.toContain('proxyView')
expect(inputs).not.toContain('isChainMode')
})
})
describe('resolveEmptyListReason', () => {
test('a stopped core explains an empty list better than the list does', () => {
expect(
resolveEmptyListReason({
runningMode: 'NotRunning',
isProxyViewError: false,
}),
).toBe('core-unavailable')
})
test('a failed proxy fetch is reported as the core being unavailable', () => {
expect(
resolveEmptyListReason({
runningMode: 'Sidecar',
isProxyViewError: true,
}),
).toBe('core-unavailable')
})
test('a running core with a clean fetch means the profile simply has nothing', () => {
expect(
resolveEmptyListReason({
runningMode: 'Sidecar',
isProxyViewError: false,
}),
).toBe('no-proxy-info')
})
})
@@ -1,55 +0,0 @@
import { describe, expect, test } from 'vitest'
import { hasRenderableItems, type IRenderItem } from './use-render-list'
const group = (hidden = false) =>
({ name: 'Proxies', hidden }) as unknown as IRenderItem['group']
const header = (hidden = false): IRenderItem => ({
type: 0,
key: 'header',
group: group(hidden),
})
const member = (key: string): IRenderItem => ({
type: 2,
key,
group: group(),
})
const memberColumn = (key: string): IRenderItem => ({
type: 4,
key,
group: group(),
})
describe('hasRenderableItems', () => {
test('an empty list has nothing to show', () => {
expect(hasRenderableItems([])).toBe(false)
})
test('chain mode is answered by the chain list itself', () => {
// Rendered rows, not group types, determine whether chain mode is empty.
expect(hasRenderableItems([member('chain:a')])).toBe(true)
expect(hasRenderableItems([memberColumn('chain-col:a')])).toBe(true)
})
test('a visible group counts even before it is expanded', () => {
expect(hasRenderableItems([header()])).toBe(true)
})
test('hidden groups alone are not content', () => {
expect(hasRenderableItems([header(true), header(true)])).toBe(false)
})
test('one visible group among hidden ones is enough', () => {
expect(hasRenderableItems([header(true), header(), header(true)])).toBe(
true,
)
})
test('rows inside a hidden but expanded group are still rows on screen', () => {
// Visible member rows mean the page is not empty even without a visible group header.
expect(hasRenderableItems([header(true), member('member:a')])).toBe(true)
})
})
@@ -1,145 +0,0 @@
// @vitest-environment jsdom
import {
cleanup,
fireEvent,
render,
screen,
waitFor,
} from '@testing-library/react'
import { afterEach, expect, it, vi } from 'vitest'
import { getSnapshotNotices, hideNotice } from '@/services/notice-service'
import {
clearServiceRequest,
getServiceRequest,
} from '@/services/service-request'
import ProxyControlSwitches from './proxy-control-switches'
const patchVerge = vi.hoisted(() => vi.fn(() => Promise.resolve()))
const mutateVerge = vi.hoisted(() => vi.fn())
const isTunModeAvailable = vi.hoisted(() => ({ current: false }))
const tunEnabled = vi.hoisted(() => ({ current: false }))
vi.mock('react-i18next', () => ({
useTranslation: () => ({ t: (key: string) => key }),
}))
vi.mock('@/hooks/use-verge', () => ({
useVerge: () => ({
verge: { enable_tun_mode: tunEnabled.current },
mutateVerge,
patchVerge,
}),
}))
vi.mock('@/hooks/use-system-state', () => ({
useSystemState: () => ({
runState: { serviceUsable: false },
isTunModeAvailable: isTunModeAvailable.current,
}),
}))
vi.mock('@/hooks/use-system-proxy-state', () => ({
useSystemProxyState: () => ({
indicator: false,
toggleSystemProxy: vi.fn(),
}),
}))
vi.mock('@/hooks/use-service-uninstaller', () => ({
useServiceUninstaller: () => ({ uninstallServiceAndStartSidecar: vi.fn() }),
}))
vi.mock('@/components/setting/mods/sysproxy-viewer', () => ({
SysproxyViewer: () => null,
}))
vi.mock('@/components/setting/mods/tun-viewer', () => ({
TunViewer: () => null,
}))
afterEach(() => {
patchVerge.mockClear()
mutateVerge.mockClear()
isTunModeAvailable.current = false
tunEnabled.current = false
clearServiceRequest()
getSnapshotNotices().forEach((notice) => hideNotice(notice.id))
cleanup()
})
const renderTun = () =>
render(
<ProxyControlSwitches label="settings.sections.system.toggles.tunMode" />,
)
const theSwitch = () => screen.getByRole('switch') as HTMLInputElement
const flip = () => fireEvent.click(theSwitch())
it('asks for the service when TUN cannot work, saying what it was for', async () => {
renderTun()
flip()
await waitFor(() =>
expect(getServiceRequest()).toEqual({
reason: 'tunNeedsService',
restore: { enable_tun_mode: true },
}),
)
expect(patchVerge).not.toHaveBeenCalled()
})
it('leaves the switch where it was until something can carry the request', async () => {
renderTun()
flip()
await waitFor(() => expect(theSwitch().checked).toBe(false))
})
it('patches directly when the service can already carry it', async () => {
isTunModeAvailable.current = true
renderTun()
flip()
await waitFor(() =>
expect(patchVerge).toHaveBeenCalledWith({ enable_tun_mode: true }),
)
expect(getServiceRequest()).toBeNull()
})
it('no longer offers a separate install button', () => {
renderTun()
expect(
screen.queryByLabelText(
'settings.sections.proxyControl.actions.installService',
),
).toBeNull()
})
it('does not ask for a service in order to turn TUN off', async () => {
tunEnabled.current = true
renderTun()
flip()
await waitFor(() =>
expect(patchVerge).toHaveBeenCalledWith({ enable_tun_mode: false }),
)
expect(getServiceRequest()).toBeNull()
})
it('says nothing beside the dialog it just opened', async () => {
const onError = vi.fn()
render(
<ProxyControlSwitches
label="settings.sections.system.toggles.tunMode"
onError={onError}
/>,
)
flip()
await waitFor(() => expect(getServiceRequest()).not.toBeNull())
await waitFor(() => expect(theSwitch().checked).toBe(false))
expect(onError).not.toHaveBeenCalled()
expect(getSnapshotNotices()).toEqual([])
})