mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-08-10 16:13:28 +08:00
test: clean up expected console output (#604)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import SiteAddEditDialog from '@/components/dialog/SiteAddEditDialog.vue'
|
||||
import DialogCloseBtn from '@/@core/components/DialogCloseBtn.vue'
|
||||
import { getActiveRequestsCount } from '@/utils/requestOptimizer'
|
||||
import { fireEvent, screen, waitFor } from '@testing-library/vue'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { createSite, createSiteDownloader } from '@tests/support/factories/site'
|
||||
@@ -11,7 +12,7 @@ import {
|
||||
} from '@tests/support/msw/handlers/site'
|
||||
import { server } from '@tests/support/msw/server'
|
||||
import { renderWithProviders } from '@tests/support/render'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
done: vi.fn(),
|
||||
@@ -30,8 +31,10 @@ vi.mock('@/api/nprogress', () => ({
|
||||
startNProgress: mocks.start,
|
||||
}))
|
||||
|
||||
async function renderDialog(oper: 'add' | 'edit', siteid?: number) {
|
||||
async function renderDialog(oper: 'add' | 'edit', siteid?: number, downloaders = [createSiteDownloader()]) {
|
||||
const events = { close: vi.fn(), save: vi.fn() }
|
||||
const downloaderRequested = vi.fn()
|
||||
server.use(siteDownloadersHandler(downloaders, 200, downloaderRequested))
|
||||
const result = await renderWithProviders(SiteAddEditDialog, {
|
||||
props: {
|
||||
modelValue: true,
|
||||
@@ -42,22 +45,17 @@ async function renderDialog(oper: 'add' | 'edit', siteid?: number) {
|
||||
},
|
||||
global: { components: { VDialogCloseBtn: DialogCloseBtn } },
|
||||
})
|
||||
await waitFor(() => expect(downloaderRequested).toHaveBeenCalledOnce())
|
||||
await waitFor(() => expect(getActiveRequestsCount()).toBe(0))
|
||||
return { ...result, events }
|
||||
}
|
||||
|
||||
describe('SiteAddEditDialog', () => {
|
||||
beforeEach(() => {
|
||||
server.use(siteDownloadersHandler())
|
||||
})
|
||||
|
||||
it('creates a site with the entered form values and loaded downloader', async () => {
|
||||
const saved = vi.fn()
|
||||
server.use(
|
||||
siteDownloadersHandler([createSiteDownloader({ name: '下载器 A' })]),
|
||||
addSiteHandler({ success: true }, 200, saved),
|
||||
)
|
||||
server.use(addSiteHandler({ success: true }, 200, saved))
|
||||
const user = userEvent.setup()
|
||||
const { events } = await renderDialog('add')
|
||||
const { events } = await renderDialog('add', undefined, [createSiteDownloader({ name: '下载器 A' })])
|
||||
|
||||
await user.type(screen.getByLabelText('站点地址'), 'https://new.example.com/')
|
||||
await fireEvent.update(screen.getByLabelText('RSS地址'), 'https://new.example.com/rss')
|
||||
@@ -125,6 +123,7 @@ describe('SiteAddEditDialog', () => {
|
||||
})
|
||||
|
||||
it('restores progress and keeps the dialog open after an HTTP creation failure', async () => {
|
||||
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
server.use(addSiteHandler({ message: '服务异常', success: false }, 500))
|
||||
const user = userEvent.setup()
|
||||
const { events } = await renderDialog('add')
|
||||
@@ -135,6 +134,7 @@ describe('SiteAddEditDialog', () => {
|
||||
await waitFor(() => expect(mocks.done).toHaveBeenCalledOnce())
|
||||
expect(events.save).not.toHaveBeenCalled()
|
||||
expect(mocks.toastSuccess).not.toHaveBeenCalled()
|
||||
expect(consoleError).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it('restores numeric flags and API mode when editing a rate-limited site', async () => {
|
||||
@@ -148,8 +148,8 @@ describe('SiteAddEditDialog', () => {
|
||||
render: 0,
|
||||
token: 'token',
|
||||
})
|
||||
server.use(siteDetailsHandler(site.id, site), siteDownloadersHandler([createSiteDownloader({ name: '下载器 A' })]))
|
||||
await renderDialog('edit', site.id)
|
||||
server.use(siteDetailsHandler(site.id, site))
|
||||
await renderDialog('edit', site.id, [createSiteDownloader({ name: '下载器 A' })])
|
||||
|
||||
expect(await screen.findByText(site.name)).toBeInTheDocument()
|
||||
expect(screen.getByLabelText('使用代理访问')).toBeChecked()
|
||||
@@ -178,6 +178,7 @@ describe('SiteAddEditDialog', () => {
|
||||
['business', 200, { message: '不允许更新', success: false }, '限流站点 更新失败:不允许更新'],
|
||||
['HTTP', 500, { message: '服务异常', success: false }, '限流站点 更新失败!'],
|
||||
])('keeps the dialog open on %s update failure', async (_case, status, response, message) => {
|
||||
const consoleError = status === 500 ? vi.spyOn(console, 'error').mockImplementation(() => {}) : undefined
|
||||
const site = createSite({ name: '限流站点' })
|
||||
server.use(siteDetailsHandler(site.id, site), updateSiteHandler(response, status))
|
||||
const { events } = await renderDialog('edit', site.id)
|
||||
@@ -187,6 +188,7 @@ describe('SiteAddEditDialog', () => {
|
||||
await waitFor(() => expect(mocks.toastError).toHaveBeenCalledWith(message))
|
||||
expect(events.save).not.toHaveBeenCalled()
|
||||
expect(mocks.done).toHaveBeenCalledOnce()
|
||||
if (status === 500) expect(consoleError).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it('emits close from the dialog close button', async () => {
|
||||
|
||||
@@ -90,6 +90,7 @@ describe('SiteCookieUpdateDialog', () => {
|
||||
['detail', { detail: '站点不存在' }, '站点不存在'],
|
||||
['message', { message: '认证服务异常' }, '认证服务异常'],
|
||||
])('shows an HTTP %s response and restores pending state', async (_case, body, message) => {
|
||||
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
server.use(http.post('http://localhost/api/v1/site/cookie/701', () => HttpResponse.json(body, { status: 500 })))
|
||||
const user = userEvent.setup()
|
||||
await renderDialog()
|
||||
@@ -100,6 +101,7 @@ describe('SiteCookieUpdateDialog', () => {
|
||||
await waitFor(() => expect(mocks.toastError).toHaveBeenCalledWith(`Cookie 站点 更新失败:${message}`))
|
||||
expect(screen.getByRole('button', { name: '开始更新' })).toBeEnabled()
|
||||
expect(screen.queryByRole('status')).not.toBeInTheDocument()
|
||||
expect(consoleError).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it('disables the update action while the request is pending and restores it afterward', async () => {
|
||||
|
||||
@@ -83,15 +83,23 @@ describe('SiteImportDialog', () => {
|
||||
expect(screen.getByLabelText('选择文件')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it.each([
|
||||
['invalid JSON', brokenJsonFile(), '文件解析失败,请检查文件格式'],
|
||||
['non-array JSON', jsonFile({ name: 'single' }), '文件格式无效,请检查文件内容'],
|
||||
])('rejects %s', async (_case, file, message) => {
|
||||
it('rejects invalid JSON', async () => {
|
||||
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
await renderDialog()
|
||||
|
||||
await chooseFile(file)
|
||||
await chooseFile(brokenJsonFile())
|
||||
|
||||
await waitFor(() => expect(mocks.toastError).toHaveBeenCalledWith(message))
|
||||
await waitFor(() => expect(mocks.toastError).toHaveBeenCalledWith('文件解析失败,请检查文件格式'))
|
||||
expect(screen.getByLabelText('选择文件')).toBeInTheDocument()
|
||||
expect(consoleError).toHaveBeenCalledWith('Parse file error:', expect.any(SyntaxError))
|
||||
})
|
||||
|
||||
it('rejects non-array JSON', async () => {
|
||||
await renderDialog()
|
||||
|
||||
await chooseFile(jsonFile({ name: 'single' }))
|
||||
|
||||
await waitFor(() => expect(mocks.toastError).toHaveBeenCalledWith('文件格式无效,请检查文件内容'))
|
||||
expect(screen.getByLabelText('选择文件')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
@@ -169,6 +177,7 @@ describe('SiteImportDialog', () => {
|
||||
})
|
||||
|
||||
it('reports partial success and preserves the HTTP error message', async () => {
|
||||
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
const sites = [createSite({ name: '成功站点' }), createSite({ name: '失败站点' })]
|
||||
let requestIndex = 0
|
||||
server.use(
|
||||
@@ -188,6 +197,7 @@ describe('SiteImportDialog', () => {
|
||||
expect(mocks.toastError).toHaveBeenCalledWith('导入完成,成功 1 个,失败 1 个')
|
||||
await fireEvent.click(screen.getByText('失败站点 - 错误详情'))
|
||||
expect(await screen.findByText('Request failed with status code 500')).toBeInTheDocument()
|
||||
expect(consoleError).toHaveBeenCalledWith('Import site 失败站点 failed:', expect.any(Error))
|
||||
})
|
||||
|
||||
it('does not start a request when every record is invalid', async () => {
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { MediaInfo, MediaSeason, NotExistMediaInfo } from '@/api/types'
|
||||
import DialogCloseBtn from '@/@core/components/DialogCloseBtn.vue'
|
||||
import SubscribeSeasonDialog from '@/components/dialog/SubscribeSeasonDialog.vue'
|
||||
import type { SubscribeMode } from '@/composables/useMediaSubscribe'
|
||||
import { getActiveRequestsCount } from '@/utils/requestOptimizer'
|
||||
import { fireEvent, screen, waitFor, within } from '@testing-library/vue'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { createMediaInfo, createMediaSeason, createNotExistMediaInfo } from '@tests/support/factories/media'
|
||||
@@ -14,7 +15,7 @@ import {
|
||||
import { server } from '@tests/support/msw/server'
|
||||
import { renderWithProviders } from '@tests/support/render'
|
||||
import { flushPromises } from '@vue/test-utils'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
/** 季订阅弹窗测试属性。 */
|
||||
interface SeasonDialogProps {
|
||||
@@ -102,9 +103,8 @@ async function settleRequests() {
|
||||
}
|
||||
|
||||
describe('SubscribeSeasonDialog', () => {
|
||||
beforeEach(() => {
|
||||
vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
vi.spyOn(console, 'warn').mockImplementation(() => {})
|
||||
afterEach(async () => {
|
||||
await waitFor(() => expect(getActiveRequestsCount()).toBe(0))
|
||||
})
|
||||
|
||||
it('loads the default TMDB seasons once with exact requests and renders season states', async () => {
|
||||
@@ -250,7 +250,9 @@ describe('SubscribeSeasonDialog', () => {
|
||||
},
|
||||
'tmdb:source-7306',
|
||||
],
|
||||
] as const)('uses the %s media identifier without requesting TMDB groups', async (_label, overrides, mediaId) => {
|
||||
] as const)('uses the %s media identifier without requesting TMDB groups', async (label, overrides, mediaId) => {
|
||||
const consoleWarn =
|
||||
label === 'source-only TMDB' ? vi.spyOn(console, 'warn').mockImplementation(() => {}) : undefined
|
||||
const media = createTvMedia(overrides)
|
||||
const requested = vi.fn()
|
||||
server.use(
|
||||
@@ -264,6 +266,7 @@ describe('SubscribeSeasonDialog', () => {
|
||||
await settleRequests()
|
||||
expect(requested).toHaveBeenCalledOnce()
|
||||
expect(requested.mock.calls[0][0].searchParams.get('mediaid')).toBe(mediaId)
|
||||
if (label === 'source-only TMDB') expect(consoleWarn).toHaveBeenCalledWith('tmdbid is not set or is empty')
|
||||
})
|
||||
|
||||
it.each([
|
||||
@@ -417,6 +420,7 @@ describe('SubscribeSeasonDialog', () => {
|
||||
})
|
||||
|
||||
it('exits Loading after the default season request fails', async () => {
|
||||
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
const media = createTvMedia({ tmdb_id: 7310 })
|
||||
const requested = vi.fn()
|
||||
server.use(
|
||||
@@ -431,9 +435,11 @@ describe('SubscribeSeasonDialog', () => {
|
||||
|
||||
expect(document.querySelector('.initial-loading-container')).not.toBeInTheDocument()
|
||||
expect(screen.getByText(`${media.title} 未查询到季集信息`)).toBeInTheDocument()
|
||||
expect(consoleError).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it('keeps season selection usable when the missing-state request fails', async () => {
|
||||
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
const media = createTvMedia({ tmdb_id: 7313 })
|
||||
const missingRequested = vi.fn()
|
||||
server.use(
|
||||
@@ -452,9 +458,11 @@ describe('SubscribeSeasonDialog', () => {
|
||||
|
||||
expect(events.subscribe).toHaveBeenCalledOnce()
|
||||
expect(events.subscribe.mock.calls[0][1]).toEqual({})
|
||||
expect(consoleError).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it('keeps season selection usable when optional episode groups fail to load', async () => {
|
||||
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
const media = createTvMedia({ tmdb_id: 7314 })
|
||||
const groupsRequested = vi.fn()
|
||||
server.use(
|
||||
@@ -473,6 +481,7 @@ describe('SubscribeSeasonDialog', () => {
|
||||
|
||||
expect(events.subscribe).toHaveBeenCalledOnce()
|
||||
expect(screen.getByRole('button', { name: /^默认/ })).toBeInTheDocument()
|
||||
expect(consoleError).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it('renders the successful empty state and emits close without submitting', async () => {
|
||||
|
||||
@@ -1420,6 +1420,7 @@ describe('glass optical surface discovery', () => {
|
||||
})
|
||||
|
||||
it('publishes only the current pending preparation failure identity', async () => {
|
||||
const consoleWarn = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
||||
const three = await import('three')
|
||||
const pendingWallpaperUrl = ref('')
|
||||
const pendingWallpaperRevision = ref(0)
|
||||
@@ -1445,6 +1446,10 @@ describe('glass optical surface discovery', () => {
|
||||
pendingWallpaperUrl.value = 'https://example.com/wallpaper-next.jpg'
|
||||
await vi.waitFor(() => expect(renderer?.failedWallpaperRevision.value).toBe(51))
|
||||
|
||||
expect(consoleWarn).toHaveBeenCalledWith(
|
||||
'玻璃光学壁纸预备失败,继续使用当前纹理:',
|
||||
expect.objectContaining({ message: 'pending source failed' }),
|
||||
)
|
||||
expect(renderer?.failedWallpaperUrl.value).toBe('https://example.com/wallpaper-next.jpg')
|
||||
expect(renderer?.failedWallpaperPreparationKey.value).toContain('frosted:balanced:')
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
type SubscribeMode,
|
||||
useMediaSubscribe,
|
||||
} from '@/composables/useMediaSubscribe'
|
||||
import { getActiveRequestsCount } from '@/utils/requestOptimizer'
|
||||
import { fireEvent, screen, waitFor } from '@testing-library/vue'
|
||||
import { createSubscribe, createSubscribeMovie, createSubscribeTv } from '@tests/support/factories/subscribe'
|
||||
import {
|
||||
@@ -18,8 +19,9 @@ import {
|
||||
} from '@tests/support/msw/handlers/subscribe'
|
||||
import { server } from '@tests/support/msw/server'
|
||||
import { renderWithProviders } from '@tests/support/render'
|
||||
import { flushPromises } from '@vue/test-utils'
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
cacheStatus: vi.fn(),
|
||||
@@ -223,6 +225,11 @@ describe('useMediaSubscribe entry flows', () => {
|
||||
mocks.openSharedDialog.mockReturnValue({ close: vi.fn(), id: 1, updateProps: vi.fn() })
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await flushPromises()
|
||||
await waitFor(() => expect(getActiveRequestsCount()).toBe(0))
|
||||
})
|
||||
|
||||
it('creates a normal movie subscription and synchronizes public state', async () => {
|
||||
const media = createSubscribeMovie({ title: '普通电影', tmdb_id: 101, year: '2025' })
|
||||
const created = vi.fn()
|
||||
@@ -302,7 +309,7 @@ describe('useMediaSubscribe entry flows', () => {
|
||||
expect(mocks.toastSuccess).toHaveBeenCalledOnce()
|
||||
expect(mocks.toastError).not.toHaveBeenCalled()
|
||||
expect(mocks.openSharedDialog).not.toHaveBeenCalled()
|
||||
consoleLog.mockRestore()
|
||||
expect(consoleLog).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it('opens the mode chooser for an existing movie and creates the selected mode', async () => {
|
||||
@@ -544,7 +551,7 @@ describe('useMediaSubscribe entry flows', () => {
|
||||
['business failure', 200, { message: 'duplicate', success: false }],
|
||||
['HTTP failure', 500, { message: 'server down', success: false }],
|
||||
])('keeps state unchanged when create returns a %s', async (_case, status, response) => {
|
||||
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
const consoleError = status === 500 ? vi.spyOn(console, 'error').mockImplementation(() => {}) : undefined
|
||||
server.use(createSubscribeHandler(response, status))
|
||||
await renderSubscribeHarness({ media: createSubscribeMovie({ tmdb_id: 107 }) })
|
||||
|
||||
@@ -555,14 +562,14 @@ describe('useMediaSubscribe entry flows', () => {
|
||||
expect(mocks.cacheStatus).not.toHaveBeenCalled()
|
||||
expect(mocks.openSharedDialog).not.toHaveBeenCalled()
|
||||
expect(mocks.doneProgress).toHaveBeenCalledOnce()
|
||||
consoleError.mockRestore()
|
||||
if (status === 500) expect(consoleError).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it.each([
|
||||
['business failure', 200, { message: 'delete rejected', success: false }],
|
||||
['HTTP failure', 500, { message: 'server down', success: false }],
|
||||
])('keeps subscription state when removal returns a %s', async (_case, status, response) => {
|
||||
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
const consoleError = status === 500 ? vi.spyOn(console, 'error').mockImplementation(() => {}) : undefined
|
||||
const deleted = vi.fn()
|
||||
server.use(deleteSubscribeByMediaHandler('tmdb:108', response, status, url => deleted(url)))
|
||||
await renderSubscribeHarness({
|
||||
@@ -586,14 +593,14 @@ describe('useMediaSubscribe entry flows', () => {
|
||||
expect(screen.getByTestId('modes')).toHaveTextContent('"2":"best_version"')
|
||||
expect(mocks.cacheStatus).not.toHaveBeenCalled()
|
||||
expect(mocks.doneProgress).toHaveBeenCalledOnce()
|
||||
consoleError.mockRestore()
|
||||
if (status === 500) expect(consoleError).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it.each([
|
||||
['business failure', 200, { message: 'update rejected', success: false }],
|
||||
['HTTP failure', 500, { message: 'server down', success: false }],
|
||||
])('keeps the subscribed mode when an update returns a %s', async (_case, status, response) => {
|
||||
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
const consoleError = status === 500 ? vi.spyOn(console, 'error').mockImplementation(() => {}) : undefined
|
||||
const media = createSubscribeTv({ title: '模式更新失败剧集', tmdb_id: 110 })
|
||||
const updated = vi.fn()
|
||||
server.use(
|
||||
@@ -621,7 +628,7 @@ describe('useMediaSubscribe entry flows', () => {
|
||||
expect(screen.getByTestId('modes')).toHaveTextContent('"2":"normal"')
|
||||
expect(mocks.cacheStatus).not.toHaveBeenCalled()
|
||||
expect(mocks.doneProgress).toHaveBeenCalledOnce()
|
||||
consoleError.mockRestore()
|
||||
if (status === 500) expect(consoleError).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it('maps a 404 query to missing and propagates other HTTP errors', async () => {
|
||||
|
||||
@@ -15,6 +15,7 @@ describe('useVersionChecker', () => {
|
||||
})
|
||||
|
||||
it('没有可用 Service Worker 时保留版本不一致的清缓存兜底', async () => {
|
||||
const consoleLog = vi.spyOn(console, 'log').mockImplementation(() => {})
|
||||
const { checkVersion } = useVersionChecker()
|
||||
|
||||
await checkVersion('version-that-never-matches-the-build')
|
||||
@@ -35,5 +36,9 @@ describe('useVersionChecker', () => {
|
||||
timeout: false,
|
||||
}),
|
||||
)
|
||||
expect(consoleLog.mock.calls).toEqual([
|
||||
[expect.stringMatching(/^\[VersionChecker\] 检测到版本不一致:/)],
|
||||
['[VersionChecker] 无 Service Worker, 直接显示通知'],
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -83,8 +83,6 @@ export function initializeRequestOptimizer(axiosInstance: any) {
|
||||
return Promise.reject(error)
|
||||
},
|
||||
)
|
||||
|
||||
console.log('Request optimizer initialized - all requests will be auto-managed')
|
||||
}
|
||||
|
||||
// 获取当前活跃请求数量(调试用)
|
||||
|
||||
@@ -152,6 +152,7 @@ describe('dashboard media server cards', () => {
|
||||
[MediaServerPlaying, 'mediaserver/playing', '暂无继续观看记录'],
|
||||
[MediaServerLibrary, 'mediaserver/library', '暂无媒体库数据'],
|
||||
])('keeps the successful empty snapshot when %s later fails', async (component, endpoint, emptyText) => {
|
||||
const consoleLog = vi.spyOn(console, 'log').mockImplementation(() => {})
|
||||
let endpointReads = 0
|
||||
mocks.apiGet.mockImplementation((url: string) => {
|
||||
if (url === 'system/setting/MediaServers') return { data: { value: [{ enabled: true, name: 'home' }] } }
|
||||
@@ -172,6 +173,7 @@ describe('dashboard media server cards', () => {
|
||||
expect(screen.getByText(emptyText)).toBeInTheDocument()
|
||||
expect(screen.queryByText('媒体服务器数据加载失败')).not.toBeInTheDocument()
|
||||
expect(await screen.findByRole('button', { name: '刷新失败,当前显示上次数据' })).toBeInTheDocument()
|
||||
expect(consoleLog).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it.each([
|
||||
@@ -179,6 +181,7 @@ describe('dashboard media server cards', () => {
|
||||
[MediaServerPlaying, 'mediaserver/playing', '恢复的继续观看'],
|
||||
[MediaServerLibrary, 'mediaserver/library', '恢复的媒体库'],
|
||||
])('shows a retry state when %s fails without a snapshot', async (component, endpoint, recoveredText) => {
|
||||
const consoleLog = vi.spyOn(console, 'log').mockImplementation(() => {})
|
||||
let endpointReads = 0
|
||||
let shouldFail = true
|
||||
mocks.apiGet.mockImplementation((url: string) => {
|
||||
@@ -202,6 +205,7 @@ describe('dashboard media server cards', () => {
|
||||
await fireEvent.click(screen.getByRole('button', { name: '媒体服务器数据加载失败' }))
|
||||
expect(await screen.findByText(recoveredText)).toBeInTheDocument()
|
||||
expect(endpointReads).toBe(failedReads + 1)
|
||||
expect(consoleLog).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it('restores the last successful library snapshot before F5 revalidation completes', async () => {
|
||||
@@ -256,6 +260,7 @@ describe('dashboard media server cards', () => {
|
||||
})
|
||||
|
||||
it('keeps continue-watching content when a warm refresh fails', async () => {
|
||||
const consoleLog = vi.spyOn(console, 'log').mockImplementation(() => {})
|
||||
const refresh = deferred<Array<{ id: string; title: string }>>()
|
||||
let playingReads = 0
|
||||
mocks.apiGet.mockImplementation((url: string) => {
|
||||
@@ -281,9 +286,11 @@ describe('dashboard media server cards', () => {
|
||||
await new Promise(resolve => setTimeout(resolve, 0))
|
||||
expect(screen.getByText('旧继续观看')).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: '刷新失败,当前显示上次数据' })).toBeInTheDocument()
|
||||
expect(consoleLog).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it('keeps recent-library content when a warm refresh fails', async () => {
|
||||
const consoleLog = vi.spyOn(console, 'log').mockImplementation(() => {})
|
||||
const refresh = deferred<Array<{ id: string; title: string }>>()
|
||||
let latestReads = 0
|
||||
mocks.apiGet.mockImplementation((url: string) => {
|
||||
@@ -307,9 +314,11 @@ describe('dashboard media server cards', () => {
|
||||
await new Promise(resolve => setTimeout(resolve, 0))
|
||||
expect(screen.getByText('旧最近入库')).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: '刷新失败,当前显示上次数据' })).toBeInTheDocument()
|
||||
expect(consoleLog).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it('keeps media-library content when a warm refresh fails', async () => {
|
||||
const consoleLog = vi.spyOn(console, 'log').mockImplementation(() => {})
|
||||
const refresh = deferred<Array<{ id: string; name: string }>>()
|
||||
let libraryReads = 0
|
||||
mocks.apiGet.mockImplementation((url: string) => {
|
||||
@@ -330,6 +339,7 @@ describe('dashboard media server cards', () => {
|
||||
await new Promise(resolve => setTimeout(resolve, 0))
|
||||
expect(screen.getByText('旧媒体库')).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: '刷新失败,当前显示上次数据' })).toBeInTheDocument()
|
||||
expect(consoleLog).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it('replaces the media-library snapshot atomically after a warm refresh', async () => {
|
||||
|
||||
Reference in New Issue
Block a user