mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-06 16:16:42 +08:00
test: 统一前端测试夹具与发布工具链 (#704)
This commit is contained in:
@@ -13,6 +13,7 @@ import {
|
||||
import { server } from '@tests/support/msw/server'
|
||||
import { renderWithProviders } from '@tests/support/render'
|
||||
import { HttpResponse, http } from 'msw'
|
||||
import { apiJson } from '@tests/support/msw/response'
|
||||
import { defineComponent, h, reactive, ref } from 'vue'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
@@ -206,8 +207,8 @@ function installSearchHandlers(
|
||||
tv: tvSiteListUrl,
|
||||
}[mediaType]
|
||||
server.use(
|
||||
http.get(siteListUrl, () => HttpResponse.json(sites)),
|
||||
http.get(selectedSitesUrl, () => HttpResponse.json({ data: { value: selected }, success: true })),
|
||||
http.get(siteListUrl, () => apiJson(sites)),
|
||||
http.get(selectedSitesUrl, () => apiJson({ value: selected })),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -548,7 +549,7 @@ describe('MediaCard', () => {
|
||||
it('falls back to global search when site settings cannot provide active selections', async () => {
|
||||
server.use(
|
||||
http.get(movieSiteListUrl, () => HttpResponse.json({ message: 'temporary failure' }, { status: 500 })),
|
||||
http.get(selectedSitesUrl, () => HttpResponse.json({ success: true })),
|
||||
http.get(selectedSitesUrl, () => apiJson(null)),
|
||||
)
|
||||
const media = createMediaInfo({ title: '站点失败搜索', tmdb_id: 9503 })
|
||||
const { container } = await renderCard(media)
|
||||
@@ -607,7 +608,7 @@ describe('MediaCard', () => {
|
||||
it('opens active sites with an empty selection when the saved setting fails', async () => {
|
||||
server.use(
|
||||
http.get(movieSiteListUrl, () =>
|
||||
HttpResponse.json([
|
||||
apiJson([
|
||||
{
|
||||
domain: 'fallback.example',
|
||||
downloader: 'default',
|
||||
@@ -655,7 +656,7 @@ describe('MediaCard', () => {
|
||||
subscribeListRequest,
|
||||
),
|
||||
http.get(new URL('system/setting/public/DefaultTvSubscribeConfig', API_BASE_URL).href, () =>
|
||||
HttpResponse.json({ data: { value: { best_version: 0 } }, success: true }),
|
||||
apiJson({ value: { best_version: 0 } }),
|
||||
),
|
||||
)
|
||||
const { container } = await renderCard(media)
|
||||
@@ -703,7 +704,7 @@ describe('MediaCard', () => {
|
||||
{ id: 92, media_id: 'other', media_source: 'bilibili', season: 5, type: '电视剧' },
|
||||
]),
|
||||
http.get(new URL('system/setting/public/DefaultTvSubscribeConfig', API_BASE_URL).href, () =>
|
||||
HttpResponse.json({ data: { value: {} }, success: true }),
|
||||
apiJson({ value: {} }),
|
||||
),
|
||||
)
|
||||
const { container } = await renderCard(media)
|
||||
@@ -758,7 +759,7 @@ describe('MediaCard', () => {
|
||||
mediaExistsHandler({ data: { item: {} }, success: true }),
|
||||
subscribeListHandler(subscribes),
|
||||
http.get(new URL('system/setting/public/DefaultTvSubscribeConfig', API_BASE_URL).href, () =>
|
||||
HttpResponse.json({ data: { value: {} }, success: true }),
|
||||
apiJson({ value: {} }),
|
||||
),
|
||||
)
|
||||
const { container } = await renderCard(media)
|
||||
|
||||
@@ -5,6 +5,7 @@ import userEvent from '@testing-library/user-event'
|
||||
import { server } from '@tests/support/msw/server'
|
||||
import { renderWithProviders } from '@tests/support/render'
|
||||
import { HttpResponse, http, type JsonBodyType } from 'msw'
|
||||
import { apiJson } from '@tests/support/msw/response'
|
||||
import { defineComponent, h, type PropType } from 'vue'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
@@ -185,12 +186,12 @@ function createDeferred<T>() {
|
||||
|
||||
function directoriesHandler(directories: TransferDirectoryConf[]) {
|
||||
return http.get(new URL('system/setting/public/Directories', API_BASE_URL).href, () =>
|
||||
HttpResponse.json({ data: { value: directories }, success: true }),
|
||||
apiJson({ value: directories }),
|
||||
)
|
||||
}
|
||||
|
||||
function downloadersHandler(downloaders: Array<{ name: string; type: string }> = []) {
|
||||
return http.get(new URL('download/clients', API_BASE_URL).href, () => HttpResponse.json(downloaders))
|
||||
return http.get(new URL('download/clients', API_BASE_URL).href, () => apiJson(downloaders))
|
||||
}
|
||||
|
||||
function downloadHandler(
|
||||
@@ -201,7 +202,9 @@ function downloadHandler(
|
||||
) {
|
||||
return http.post(new URL(endpoint, API_BASE_URL).href, async ({ request }) => {
|
||||
await onRequest(await request.json())
|
||||
return HttpResponse.json(await response, { status })
|
||||
const body = await response
|
||||
if (status >= 400) return HttpResponse.json(body, { status })
|
||||
return HttpResponse.json(body, { status })
|
||||
})
|
||||
}
|
||||
|
||||
@@ -320,7 +323,7 @@ describe('AddDownloadDialog submissions', () => {
|
||||
|
||||
it('submits a directly entered media ID through v-model', async () => {
|
||||
const submitted = vi.fn()
|
||||
server.use(downloadHandler('download/add', { data: null, success: true }, 200, submitted))
|
||||
server.use(downloadHandler('download/add', { data: null, message: '', success: true }, 200, submitted))
|
||||
const user = userEvent.setup()
|
||||
|
||||
await renderDialog({
|
||||
@@ -376,7 +379,7 @@ describe('AddDownloadDialog submissions', () => {
|
||||
expect(submitted).toHaveBeenCalledOnce()
|
||||
expect(mocks.startNProgress).toHaveBeenCalledOnce()
|
||||
|
||||
deferred.resolve({ data: null, success: true })
|
||||
deferred.resolve({ data: null, message: '', success: true })
|
||||
await waitFor(() => expect(events.done).toHaveBeenCalledWith(torrent.enclosure))
|
||||
|
||||
expect(mocks.toastSuccess).toHaveBeenCalledWith('测试站 测试种子 下载成功!')
|
||||
@@ -386,7 +389,7 @@ describe('AddDownloadDialog submissions', () => {
|
||||
|
||||
it('submits the selected album namespace for a music torrent without media context', async () => {
|
||||
const submitted = vi.fn()
|
||||
server.use(downloadHandler('download/add', { data: null, success: true }, 200, submitted))
|
||||
server.use(downloadHandler('download/add', { data: null, message: '', success: true }, 200, submitted))
|
||||
const user = userEvent.setup()
|
||||
|
||||
await renderDialog({
|
||||
@@ -493,7 +496,7 @@ describe('AddDownloadDialog submissions', () => {
|
||||
|
||||
it('uses the source-native identity carried by a torrent without auxiliary ID fallback', async () => {
|
||||
const submitted = vi.fn()
|
||||
server.use(downloadHandler('download/add', { data: null, success: true }, 200, submitted))
|
||||
server.use(downloadHandler('download/add', { data: null, message: '', success: true }, 200, submitted))
|
||||
const torrent = createTorrent({ media_id: 'tt0111161', media_source: 'imdb' })
|
||||
const user = userEvent.setup()
|
||||
|
||||
@@ -509,7 +512,7 @@ describe('AddDownloadDialog submissions', () => {
|
||||
|
||||
it('uses download/ for an existing media without locking unrelated optional fields', async () => {
|
||||
const submitted = vi.fn()
|
||||
server.use(downloadHandler('download/', { data: null, success: true }, 200, submitted))
|
||||
server.use(downloadHandler('download/', { data: null, message: '', success: true }, 200, submitted))
|
||||
const media = createMedia()
|
||||
const torrent = createTorrent()
|
||||
const user = userEvent.setup()
|
||||
@@ -540,7 +543,7 @@ describe('AddDownloadDialog submissions', () => {
|
||||
success: false,
|
||||
})
|
||||
}
|
||||
return HttpResponse.json({ data: { download_id: 'collection-download' }, success: true })
|
||||
return apiJson({ download_id: 'collection-download' })
|
||||
}),
|
||||
)
|
||||
mocks.confirm.mockResolvedValue(true)
|
||||
|
||||
@@ -5,6 +5,7 @@ import userEvent from '@testing-library/user-event'
|
||||
import { server } from '@tests/support/msw/server'
|
||||
import { renderWithProviders } from '@tests/support/render'
|
||||
import { HttpResponse, http, type JsonBodyType } from 'msw'
|
||||
import { apiJson } from '@tests/support/msw/response'
|
||||
import { defineComponent, h, type PropType } from 'vue'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
@@ -151,7 +152,7 @@ function createDeferred<T>() {
|
||||
|
||||
function directoriesHandler(directories: TransferDirectoryConf[]) {
|
||||
return http.get(new URL('system/setting/public/Directories', API_BASE_URL).href, () =>
|
||||
HttpResponse.json({ data: { value: directories }, success: true }),
|
||||
apiJson({ value: directories }),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -162,7 +163,9 @@ function subtitleDownloadHandler(
|
||||
) {
|
||||
return http.post(new URL('download/subtitle', API_BASE_URL).href, async ({ request }) => {
|
||||
await onRequest(await request.json())
|
||||
return HttpResponse.json(await response, { status })
|
||||
const body = await response
|
||||
if (status >= 400) return HttpResponse.json(body, { status })
|
||||
return HttpResponse.json(body, { status })
|
||||
})
|
||||
}
|
||||
|
||||
@@ -277,7 +280,7 @@ describe('AddSubtitleDownloadDialog submissions', () => {
|
||||
|
||||
it('submits a directly entered media ID through v-model', async () => {
|
||||
const submitted = vi.fn()
|
||||
server.use(subtitleDownloadHandler({ data: null, success: true }, 200, submitted))
|
||||
server.use(subtitleDownloadHandler({ data: null, message: '', success: true }, 200, submitted))
|
||||
const user = userEvent.setup()
|
||||
|
||||
await renderDialog({ mediaId: null, recognizeSource: 'douban' })
|
||||
@@ -294,7 +297,7 @@ describe('AddSubtitleDownloadDialog submissions', () => {
|
||||
|
||||
it('reveals advanced options and submits the selected media source identity', async () => {
|
||||
const submitted = vi.fn()
|
||||
server.use(subtitleDownloadHandler({ data: null, success: true }, 200, submitted))
|
||||
server.use(subtitleDownloadHandler({ data: null, message: '', success: true }, 200, submitted))
|
||||
const user = userEvent.setup()
|
||||
|
||||
await renderDialog({ mediaId: '84', mediaSource: 'themoviedb' })
|
||||
@@ -348,7 +351,7 @@ describe('AddSubtitleDownloadDialog submissions', () => {
|
||||
expect(submitted).toHaveBeenCalledOnce()
|
||||
expect(mocks.startNProgress).toHaveBeenCalledOnce()
|
||||
|
||||
deferred.resolve({ data: null, success: true })
|
||||
deferred.resolve({ data: null, message: '', success: true })
|
||||
await waitFor(() => expect(events.done).toHaveBeenCalledWith(expectedEnclosure))
|
||||
|
||||
expect(mocks.toastSuccess).toHaveBeenCalledWith('字幕站 测试字幕 字幕下载成功!')
|
||||
@@ -358,7 +361,7 @@ describe('AddSubtitleDownloadDialog submissions', () => {
|
||||
|
||||
it('submits the exact-search identity passed by the resource result', async () => {
|
||||
const submitted = vi.fn()
|
||||
server.use(subtitleDownloadHandler({ data: null, success: true }, 200, submitted))
|
||||
server.use(subtitleDownloadHandler({ data: null, message: '', success: true }, 200, submitted))
|
||||
const user = userEvent.setup()
|
||||
|
||||
await renderDialog({ mediaId: '84', mediaSource: 'themoviedb', recognizeSource: 'douban' })
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
import { server } from '@tests/support/msw/server'
|
||||
import { renderWithProviders } from '@tests/support/render'
|
||||
import { HttpResponse, http } from 'msw'
|
||||
import { apiJson } from '@tests/support/msw/response'
|
||||
import { defineComponent, h, onMounted, ref, type PropType } from 'vue'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
@@ -207,9 +208,9 @@ describe('DownloadHistoryDialog', () => {
|
||||
http.get(downloadApiUrls.history, ({ request }) => {
|
||||
const page = new URL(request.url).searchParams.get('page') ?? ''
|
||||
requestedPages.push(page)
|
||||
if (page === '1') return HttpResponse.json([first])
|
||||
if (page === '2') return HttpResponse.json([second])
|
||||
return HttpResponse.json([])
|
||||
if (page === '1') return apiJson([first])
|
||||
if (page === '2') return apiJson([second])
|
||||
return apiJson([])
|
||||
}),
|
||||
)
|
||||
const user = userEvent.setup()
|
||||
@@ -262,7 +263,7 @@ describe('DownloadHistoryDialog', () => {
|
||||
http.get(downloadApiUrls.history, () => {
|
||||
requestCount += 1
|
||||
if (requestCount === 1) return HttpResponse.json({}, { status: 500 })
|
||||
return HttpResponse.json([item])
|
||||
return apiJson([item])
|
||||
}),
|
||||
)
|
||||
const user = userEvent.setup()
|
||||
|
||||
@@ -7,6 +7,7 @@ import { addSiteHandler, siteApiUrls } from '@tests/support/msw/handlers/site'
|
||||
import { server } from '@tests/support/msw/server'
|
||||
import { renderWithProviders } from '@tests/support/render'
|
||||
import { HttpResponse, http } from 'msw'
|
||||
import { apiJson } from '@tests/support/msw/response'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
@@ -183,7 +184,7 @@ describe('SiteImportDialog', () => {
|
||||
server.use(
|
||||
http.post(siteApiUrls.list, () => {
|
||||
requestIndex += 1
|
||||
if (requestIndex === 1) return HttpResponse.json({ success: true })
|
||||
if (requestIndex === 1) return apiJson(null)
|
||||
return HttpResponse.json({ message: '第二站请求失败', success: false }, { status: 500 })
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -9,6 +9,7 @@ import { siteApiUrls, siteCategoriesHandler, siteResourcesHandler } from '@tests
|
||||
import { server } from '@tests/support/msw/server'
|
||||
import { renderWithProviders } from '@tests/support/render'
|
||||
import { HttpResponse, http } from 'msw'
|
||||
import { apiJson } from '@tests/support/msw/response'
|
||||
import { defineComponent, h, type Component, type PropType } from 'vue'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
@@ -128,13 +129,13 @@ describe('SiteResourceDialog', () => {
|
||||
const keyword = new URL(request.url).searchParams.get('keyword')
|
||||
if (keyword) {
|
||||
latestRequested()
|
||||
return HttpResponse.json(await latestResponse.promise)
|
||||
return apiJson(await latestResponse.promise)
|
||||
}
|
||||
|
||||
oldRequested()
|
||||
await oldResponse.promise
|
||||
return oldStatus === 200
|
||||
? HttpResponse.json([createTorrentInfo({ title: '旧条件结果' })])
|
||||
? apiJson([createTorrentInfo({ title: '旧条件结果' })])
|
||||
: HttpResponse.json({ detail: 'stale failure' }, { status: oldStatus })
|
||||
}),
|
||||
)
|
||||
@@ -176,7 +177,7 @@ describe('SiteResourceDialog', () => {
|
||||
attempts += 1
|
||||
if (attempts === 1) return HttpResponse.json({ detail: 'temporary failure' }, { status: 500 })
|
||||
|
||||
return HttpResponse.json([createTorrentInfo({ title: '重试恢复结果' })])
|
||||
return apiJson([createTorrentInfo({ title: '重试恢复结果' })])
|
||||
}),
|
||||
)
|
||||
const user = userEvent.setup()
|
||||
@@ -207,7 +208,7 @@ describe('SiteResourceDialog', () => {
|
||||
siteCategoriesHandler(501, []),
|
||||
http.get(siteApiUrls.resources(501), () => {
|
||||
attempts += 1
|
||||
if (attempts === 1) return HttpResponse.json([createTorrentInfo({ title: '已有资源' })])
|
||||
if (attempts === 1) return apiJson([createTorrentInfo({ title: '已有资源' })])
|
||||
|
||||
return HttpResponse.json({ detail: 'temporary failure' }, { status: 500 })
|
||||
}),
|
||||
@@ -283,8 +284,8 @@ describe('SiteResourceDialog', () => {
|
||||
siteCategoriesHandler(501, []),
|
||||
http.get(siteApiUrls.resources(501), async () => {
|
||||
requestCount += 1
|
||||
if (requestCount === 1) return HttpResponse.json([])
|
||||
return HttpResponse.json(await nextResponse.promise)
|
||||
if (requestCount === 1) return apiJson([])
|
||||
return apiJson(await nextResponse.promise)
|
||||
}),
|
||||
)
|
||||
const user = userEvent.setup()
|
||||
|
||||
@@ -6,6 +6,7 @@ import { server } from '@tests/support/msw/server'
|
||||
import { subscribeApiUrls, subscribeFilesHandler } from '@tests/support/msw/handlers/subscribe'
|
||||
import { renderWithProviders } from '@tests/support/render'
|
||||
import { HttpResponse, http, type JsonBodyType } from 'msw'
|
||||
import { apiJson } from '@tests/support/msw/response'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
@@ -437,7 +438,7 @@ describe('SubscribeFilesDialog', () => {
|
||||
http.get(subscribeApiUrls.filesById(3102), () => {
|
||||
requestCount += 1
|
||||
if (requestCount === 1) return HttpResponse.json({}, { status: 500 })
|
||||
return HttpResponse.json(info as unknown as JsonBodyType)
|
||||
return apiJson(info as unknown as JsonBodyType)
|
||||
}),
|
||||
)
|
||||
const user = userEvent.setup()
|
||||
@@ -456,7 +457,7 @@ describe('SubscribeFilesDialog', () => {
|
||||
const deferred = createDeferred<JsonBodyType>()
|
||||
server.use(
|
||||
http.get(subscribeApiUrls.filesById(3116), async () => {
|
||||
return HttpResponse.json(await deferred.promise)
|
||||
return apiJson(await deferred.promise)
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
import { server } from '@tests/support/msw/server'
|
||||
import { renderWithProviders } from '@tests/support/render'
|
||||
import { HttpResponse, http, type JsonBodyType } from 'msw'
|
||||
import { apiJson } from '@tests/support/msw/response'
|
||||
import { defineComponent, h, onMounted, ref, type PropType } from 'vue'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
@@ -246,9 +247,9 @@ describe('SubscribeHistoryDialog', () => {
|
||||
const url = new URL(request.url)
|
||||
const page = url.searchParams.get('page') ?? ''
|
||||
requestedPages.push(page)
|
||||
if (page === '1') return HttpResponse.json([first])
|
||||
if (page === '2') return HttpResponse.json([second])
|
||||
return HttpResponse.json([])
|
||||
if (page === '1') return apiJson([first])
|
||||
if (page === '2') return apiJson([second])
|
||||
return apiJson([])
|
||||
}),
|
||||
)
|
||||
const user = userEvent.setup()
|
||||
@@ -283,7 +284,7 @@ describe('SubscribeHistoryDialog', () => {
|
||||
const url = new URL(request.url)
|
||||
requestedPages.push(url.searchParams.get('page') ?? '')
|
||||
if (requestedPages.length === 1) return HttpResponse.json({ detail: 'failed' }, { status: 500 })
|
||||
return HttpResponse.json([recovered])
|
||||
return apiJson([recovered])
|
||||
}),
|
||||
)
|
||||
const user = userEvent.setup()
|
||||
@@ -305,7 +306,7 @@ describe('SubscribeHistoryDialog', () => {
|
||||
server.use(
|
||||
http.get(subscribeApiUrls.historyByType('电影'), async () => {
|
||||
requested()
|
||||
return HttpResponse.json(await pending.promise)
|
||||
return apiJson(await pending.promise)
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -329,13 +330,13 @@ describe('SubscribeHistoryDialog', () => {
|
||||
],
|
||||
['音乐', createHistory({ name: '重新订阅专辑', type: '音乐' }), '正在重新订阅 重新订阅专辑...'],
|
||||
] as const)('shows the %s pending copy and emits save only after success', async (type, item, progressText) => {
|
||||
const pending = createDeferred<{ success: boolean }>()
|
||||
const pending = createDeferred<null>()
|
||||
let payload: JsonBodyType | undefined
|
||||
server.use(
|
||||
subscribeHistoryHandler(type, [item]),
|
||||
http.post(subscribeApiUrls.create, async ({ request }) => {
|
||||
payload = (await request.json()) as JsonBodyType
|
||||
return HttpResponse.json(await pending.promise)
|
||||
return apiJson(await pending.promise)
|
||||
}),
|
||||
)
|
||||
const user = userEvent.setup()
|
||||
@@ -346,7 +347,7 @@ describe('SubscribeHistoryDialog', () => {
|
||||
|
||||
expect(await screen.findByRole('status')).toHaveTextContent(progressText)
|
||||
expect(events.save).not.toHaveBeenCalled()
|
||||
pending.resolve({ success: true })
|
||||
pending.resolve(null)
|
||||
await waitFor(() => expect(events.save).toHaveBeenCalledOnce())
|
||||
|
||||
expect(payload).toEqual(item)
|
||||
|
||||
@@ -5,7 +5,8 @@ import { useUserStore } from '@/stores/user'
|
||||
import { screen, waitFor } from '@testing-library/vue'
|
||||
import { renderWithProviders } from '@tests/support/render'
|
||||
import { server } from '@tests/support/msw/server'
|
||||
import { http, HttpResponse } from 'msw'
|
||||
import { http } from 'msw'
|
||||
import { apiJson } from '@tests/support/msw/response'
|
||||
import { defineComponent, h } from 'vue'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
@@ -31,7 +32,7 @@ function createNavItem(overrides: Partial<PluginSidebarNavItem> = {}): PluginSid
|
||||
}
|
||||
|
||||
function sidebarNavHandler(items: PluginSidebarNavItem[]) {
|
||||
return http.get(SIDEBAR_NAV_URL, () => HttpResponse.json(items))
|
||||
return http.get(SIDEBAR_NAV_URL, () => apiJson(items))
|
||||
}
|
||||
|
||||
async function renderAppCenter(items: PluginSidebarNavItem[], permissions: Record<string, unknown> = {}) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
} from '@tests/support/msw/handlers/discover'
|
||||
import { server } from '@tests/support/msw/server'
|
||||
import { HttpResponse, http } from 'msw'
|
||||
import { apiJson } from '@tests/support/msw/response'
|
||||
import { defineComponent, h, ref, unref, type ComputedRef, type Ref } from 'vue'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
@@ -364,7 +365,7 @@ describe('discover page', () => {
|
||||
server.use(
|
||||
http.get(discoverApiUrls.sources, () => {
|
||||
requested()
|
||||
return HttpResponse.json(sources)
|
||||
return apiJson(sources)
|
||||
}),
|
||||
)
|
||||
await renderDiscover()
|
||||
@@ -388,7 +389,8 @@ describe('discover page', () => {
|
||||
server.use(
|
||||
http.get(discoverApiUrls.sources, () => {
|
||||
requested()
|
||||
return HttpResponse.json(status === 200 ? [createSource('缓存来源', 'cached')] : [], { status })
|
||||
if (status >= 400) return HttpResponse.json([], { status })
|
||||
return apiJson([createSource('缓存来源', 'cached')])
|
||||
}),
|
||||
)
|
||||
await renderDiscover()
|
||||
@@ -417,7 +419,7 @@ describe('discover page', () => {
|
||||
server.use(
|
||||
http.get(discoverApiUrls.sources, () => {
|
||||
requested()
|
||||
return HttpResponse.json(sources)
|
||||
return apiJson(sources)
|
||||
}),
|
||||
)
|
||||
await renderDiscover()
|
||||
|
||||
@@ -11,7 +11,8 @@ import {
|
||||
saveRecommendConfigHandler,
|
||||
} from '@tests/support/msw/handlers/recommend'
|
||||
import { server } from '@tests/support/msw/server'
|
||||
import { HttpResponse, http } from 'msw'
|
||||
import { http } from 'msw'
|
||||
import { apiJson } from '@tests/support/msw/response'
|
||||
import { defineComponent, nextTick, ref, type Ref } from 'vue'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
@@ -111,7 +112,7 @@ async function renderKeptAliveRecommend() {
|
||||
function dynamicRecommendSources(getSources: () => RecommendSource[], onRequest = vi.fn()) {
|
||||
return http.get(recommendApiUrls.sources, () => {
|
||||
onRequest()
|
||||
return HttpResponse.json(getSources())
|
||||
return apiJson(getSources())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -183,7 +184,7 @@ describe('recommend page', () => {
|
||||
http.get(recommendApiUrls.sources, async () => {
|
||||
requested()
|
||||
await responseGate
|
||||
return HttpResponse.json([{ api_path: 'recommend/completed', name: '请求完成来源', type: '扩展' }])
|
||||
return apiJson([{ api_path: 'recommend/completed', name: '请求完成来源', type: '扩展' }])
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ import { createMediaInfo } from '@tests/support/factories/media'
|
||||
import { recommendApiUrls, recommendMediaHandler } from '@tests/support/msw/handlers/recommend'
|
||||
import { server } from '@tests/support/msw/server'
|
||||
import { renderWithProviders } from '@tests/support/render'
|
||||
import { http, HttpResponse } from 'msw'
|
||||
import { http } from 'msw'
|
||||
import { apiJson } from '@tests/support/msw/response'
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
@@ -148,7 +149,7 @@ describe('MediaRecommend', () => {
|
||||
|
||||
expect(await screen.findByText('快照推荐')).toBeInTheDocument()
|
||||
await waitFor(() => expect(requested).toHaveBeenCalledOnce())
|
||||
resolveRequest?.(HttpResponse.json([createMediaInfo({ title: '刷新推荐' })]))
|
||||
resolveRequest?.(apiJson([createMediaInfo({ title: '刷新推荐' })]))
|
||||
expect(await screen.findByText('刷新推荐')).toBeInTheDocument()
|
||||
second.unmount()
|
||||
})
|
||||
@@ -324,7 +325,7 @@ describe('MediaRecommend', () => {
|
||||
|
||||
await fireEvent.click(screen.getByRole('button', { name: '停用慢请求推荐' }))
|
||||
setInterval.mockClear()
|
||||
resolveRequest?.(HttpResponse.json([createMediaInfo({ title: '迟到推荐' })]))
|
||||
resolveRequest?.(apiJson([createMediaInfo({ title: '迟到推荐' })]))
|
||||
await waitFor(() => expect(getActiveRequestsCount()).toBe(0))
|
||||
await new Promise(resolve => window.setTimeout(resolve, 0))
|
||||
|
||||
@@ -380,7 +381,7 @@ describe('MediaRecommend', () => {
|
||||
await fireEvent.click(screen.getByRole('button', { name: '恢复切源推荐' }))
|
||||
expect(setInterval).not.toHaveBeenCalledWith(expect.any(Function), 8000)
|
||||
|
||||
resolveMovies?.(HttpResponse.json([createMediaInfo({ title: '切源完成' })]))
|
||||
resolveMovies?.(apiJson([createMediaInfo({ title: '切源完成' })]))
|
||||
await waitFor(() => expect(getActiveRequestsCount()).toBe(0))
|
||||
await screen.findByText('切源完成')
|
||||
|
||||
@@ -435,7 +436,7 @@ describe('MediaRecommend', () => {
|
||||
|
||||
expect(await screen.findByText('初始结果')).toBeInTheDocument()
|
||||
await waitFor(() => expect(resolveMovies).toBeTypeOf('function'))
|
||||
resolveMovies?.(HttpResponse.json([createMediaInfo({ title: '过期结果' })]))
|
||||
resolveMovies?.(apiJson([createMediaInfo({ title: '过期结果' })]))
|
||||
await waitFor(() => expect(getActiveRequestsCount()).toBe(0))
|
||||
await new Promise(resolve => window.setTimeout(resolve, 0))
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import { createMediaInfo } from '@tests/support/factories/media'
|
||||
import { server } from '@tests/support/msw/server'
|
||||
import { renderWithProviders } from '@tests/support/render'
|
||||
import { HttpResponse, http, type JsonBodyType } from 'msw'
|
||||
import { apiJson } from '@tests/support/msw/response'
|
||||
import { defineComponent, h, onMounted, ref, type PropType } from 'vue'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
@@ -178,7 +179,7 @@ describe('MediaCardListView', () => {
|
||||
server.use(
|
||||
http.get(LIST_URL, ({ request }) => {
|
||||
requests.push(new URL(request.url))
|
||||
return HttpResponse.json([createMediaInfo({ title: '内部页码结果' })])
|
||||
return apiJson([createMediaInfo({ title: '内部页码结果' })])
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -198,7 +199,7 @@ describe('MediaCardListView', () => {
|
||||
server.use(
|
||||
http.get(LIST_URL, ({ request }) => {
|
||||
requests.push(new URL(request.url))
|
||||
return HttpResponse.json([createMediaInfo({ title: '多来源结果' })])
|
||||
return apiJson([createMediaInfo({ title: '多来源结果' })])
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -216,7 +217,7 @@ describe('MediaCardListView', () => {
|
||||
http.get(LIST_URL, ({ request }) => {
|
||||
const page = new URL(request.url).searchParams.get('page') ?? ''
|
||||
requestedPages.push(page)
|
||||
return HttpResponse.json([createMediaInfo({ title: '单页媒体' })])
|
||||
return apiJson([createMediaInfo({ title: '单页媒体' })])
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -233,7 +234,7 @@ describe('MediaCardListView', () => {
|
||||
http.get(LIST_URL, ({ request }) => {
|
||||
const page = new URL(request.url).searchParams.get('page') ?? ''
|
||||
requestedPages.push(page)
|
||||
return HttpResponse.json([createMediaInfo({ title: page === '1' ? '未满屏第一页' : '未满屏第二页' })])
|
||||
return apiJson([createMediaInfo({ title: page === '1' ? '未满屏第一页' : '未满屏第二页' })])
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -260,7 +261,7 @@ describe('MediaCardListView', () => {
|
||||
{ media_id: 'media-43', title: '不同 media_id' },
|
||||
]
|
||||
const response = [base, { ...base, title: '完全重复项' }, ...variants.map(variant => ({ ...base, ...variant }))]
|
||||
server.use(http.get(LIST_URL, () => HttpResponse.json(response as unknown as JsonBodyType)))
|
||||
server.use(http.get(LIST_URL, () => apiJson(response as unknown as JsonBodyType)))
|
||||
|
||||
await renderList()
|
||||
|
||||
@@ -285,7 +286,7 @@ describe('MediaCardListView', () => {
|
||||
tmdb_id: undefined,
|
||||
}),
|
||||
)
|
||||
server.use(http.get(LIST_URL, () => HttpResponse.json(response as unknown as JsonBodyType)))
|
||||
server.use(http.get(LIST_URL, () => apiJson(response as unknown as JsonBodyType)))
|
||||
|
||||
await renderList()
|
||||
|
||||
@@ -302,7 +303,7 @@ describe('MediaCardListView', () => {
|
||||
createMediaInfo({ media_id: undefined, media_source: undefined, title: '无标识媒体 A', tmdb_id: undefined }),
|
||||
createMediaInfo({ media_id: undefined, media_source: undefined, title: '无标识媒体 B', tmdb_id: undefined }),
|
||||
]
|
||||
server.use(http.get(LIST_URL, () => HttpResponse.json(response as unknown as JsonBodyType)))
|
||||
server.use(http.get(LIST_URL, () => apiJson(response as unknown as JsonBodyType)))
|
||||
|
||||
await renderList()
|
||||
|
||||
@@ -321,9 +322,9 @@ describe('MediaCardListView', () => {
|
||||
http.get(LIST_URL, ({ request }) => {
|
||||
const page = new URL(request.url).searchParams.get('page') ?? ''
|
||||
requestedPages.push(page)
|
||||
if (page === '1') return HttpResponse.json([first, second] as unknown as JsonBodyType)
|
||||
if (page === '2') return HttpResponse.json([{ ...first, title: '第二页全重复' }] as unknown as JsonBodyType)
|
||||
return HttpResponse.json([later] as unknown as JsonBodyType)
|
||||
if (page === '1') return apiJson([first, second] as unknown as JsonBodyType)
|
||||
if (page === '2') return apiJson([{ ...first, title: '第二页全重复' }] as unknown as JsonBodyType)
|
||||
return apiJson([later] as unknown as JsonBodyType)
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -345,10 +346,10 @@ describe('MediaCardListView', () => {
|
||||
const page = new URL(request.url).searchParams.get('page') ?? ''
|
||||
requestedPages.push(page)
|
||||
if (page === '1') {
|
||||
return HttpResponse.json([first, { ...first, title: '页内重复 A' }, second] as unknown as JsonBodyType)
|
||||
return apiJson([first, { ...first, title: '页内重复 A' }, second] as unknown as JsonBodyType)
|
||||
}
|
||||
if (page === '2') return HttpResponse.json([between] as unknown as JsonBodyType)
|
||||
return HttpResponse.json([{ ...second }, { ...first }] as unknown as JsonBodyType)
|
||||
if (page === '2') return apiJson([between] as unknown as JsonBodyType)
|
||||
return apiJson([{ ...second }, { ...first }] as unknown as JsonBodyType)
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -362,7 +363,7 @@ describe('MediaCardListView', () => {
|
||||
|
||||
it('marks an empty first page as the pagination terminal state', async () => {
|
||||
setScrollHeight(() => 900)
|
||||
server.use(http.get(LIST_URL, () => HttpResponse.json([])))
|
||||
server.use(http.get(LIST_URL, () => apiJson([])))
|
||||
|
||||
await renderList()
|
||||
|
||||
@@ -372,7 +373,7 @@ describe('MediaCardListView', () => {
|
||||
|
||||
it('renders HTTP 200 plus an empty array as ordinary no-data rather than a network error', async () => {
|
||||
setScrollHeight(() => 900)
|
||||
server.use(http.get(LIST_URL, () => HttpResponse.json([])))
|
||||
server.use(http.get(LIST_URL, () => apiJson([])))
|
||||
|
||||
await renderList()
|
||||
|
||||
@@ -389,7 +390,7 @@ describe('MediaCardListView', () => {
|
||||
const page = new URL(request.url).searchParams.get('page') ?? ''
|
||||
requestedPages.push(page)
|
||||
if (requestedPages.length === 1) return HttpResponse.json({ detail: 'failed' }, { status: 500 })
|
||||
return HttpResponse.json([createMediaInfo({ title: '首载重试成功' })])
|
||||
return apiJson([createMediaInfo({ title: '首载重试成功' })])
|
||||
}),
|
||||
)
|
||||
const user = userEvent.setup()
|
||||
@@ -412,10 +413,10 @@ describe('MediaCardListView', () => {
|
||||
http.get(LIST_URL, ({ request }) => {
|
||||
const page = new URL(request.url).searchParams.get('page') ?? ''
|
||||
requestedPages.push(page)
|
||||
if (page === '1') return HttpResponse.json([createMediaInfo({ title: '保留第一页' })])
|
||||
if (page === '1') return apiJson([createMediaInfo({ title: '保留第一页' })])
|
||||
pageTwoAttempts += 1
|
||||
if (pageTwoAttempts === 1) return HttpResponse.json({ detail: 'failed' }, { status: 500 })
|
||||
return HttpResponse.json([createMediaInfo({ title: '第二页重试成功' })])
|
||||
return apiJson([createMediaInfo({ title: '第二页重试成功' })])
|
||||
}),
|
||||
)
|
||||
const user = userEvent.setup()
|
||||
@@ -438,7 +439,7 @@ describe('MediaCardListView', () => {
|
||||
http.get(LIST_URL, async ({ request }) => {
|
||||
requests.push(new URL(request.url))
|
||||
await gate.promise
|
||||
return HttpResponse.json([createMediaInfo({ title: '在途请求结果' })])
|
||||
return apiJson([createMediaInfo({ title: '在途请求结果' })])
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
import { server } from '@tests/support/msw/server'
|
||||
import { renderWithProviders } from '@tests/support/render'
|
||||
import { HttpResponse, http } from 'msw'
|
||||
import { apiJson } from '@tests/support/msw/response'
|
||||
import { defineComponent, h, type PropType } from 'vue'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
@@ -137,8 +138,8 @@ interface RenderDetailOptions {
|
||||
|
||||
function installSiteHandlers(sites: Site[] = [], selected: number[] = [], type = '电影') {
|
||||
server.use(
|
||||
http.get(type === '电视剧' ? tvSiteListUrl : movieSiteListUrl, () => HttpResponse.json(sites)),
|
||||
http.get(selectedSitesUrl, () => HttpResponse.json({ data: { value: selected }, success: true })),
|
||||
http.get(type === '电视剧' ? tvSiteListUrl : movieSiteListUrl, () => apiJson(sites)),
|
||||
http.get(selectedSitesUrl, () => apiJson({ value: selected })),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -593,8 +594,8 @@ describe('MediaDetailView detail and actions', () => {
|
||||
const site = createSubscribeSite({ id: 92, is_active: true, name: '空设置站点' })
|
||||
await renderDetail()
|
||||
server.use(
|
||||
http.get(movieSiteListUrl, () => HttpResponse.json([site])),
|
||||
http.get(selectedSitesUrl, () => HttpResponse.json({ data: {}, success: true })),
|
||||
http.get(movieSiteListUrl, () => apiJson([site])),
|
||||
http.get(selectedSitesUrl, () => apiJson({})),
|
||||
)
|
||||
|
||||
await fireEvent.click(screen.getByRole('button', { name: /搜索字幕/ }))
|
||||
@@ -1112,7 +1113,7 @@ describe('MediaDetailView subscriptions, seasons, and episode groups', () => {
|
||||
staleRequest()
|
||||
const response = await staleSeasons.promise
|
||||
staleResponseReturned.resolve()
|
||||
return HttpResponse.json(response)
|
||||
return apiJson(response)
|
||||
}),
|
||||
mediaGroupSeasonsHandler('group-b', [createMediaSeason({ season_number: 2 })]),
|
||||
)
|
||||
@@ -1163,12 +1164,12 @@ describe('MediaDetailView subscriptions, seasons, and episode groups', () => {
|
||||
staleMissingRequest()
|
||||
const response = await staleMissing.promise
|
||||
staleMissingReturned.resolve()
|
||||
return HttpResponse.json(response)
|
||||
return apiJson(response)
|
||||
}
|
||||
if (payload.episode_group === 'group-b') {
|
||||
return HttpResponse.json([createNotExistMediaInfo({ episodes: [2], season: 1, total_episode: 2 })])
|
||||
return apiJson([createNotExistMediaInfo({ episodes: [2], season: 1, total_episode: 2 })])
|
||||
}
|
||||
return HttpResponse.json([])
|
||||
return apiJson([])
|
||||
}),
|
||||
http.post(mediaApiUrls.existsRemote, async ({ request }) => {
|
||||
const payload = (await request.json()) as Record<string, unknown>
|
||||
@@ -1176,13 +1177,13 @@ describe('MediaDetailView subscriptions, seasons, and episode groups', () => {
|
||||
staleRemoteRequest()
|
||||
const response = await staleRemoteExists.promise
|
||||
staleRemoteReturned.resolve()
|
||||
return HttpResponse.json(response)
|
||||
return apiJson(response)
|
||||
}
|
||||
return HttpResponse.json(payload.episode_group === 'group-b' ? { 1: [2] } : {})
|
||||
return apiJson(payload.episode_group === 'group-b' ? { 1: [2] } : {})
|
||||
}),
|
||||
http.get(new URL('tmdb/8712/1', API_BASE_URL).href, ({ request }) => {
|
||||
const group = new URL(request.url).searchParams.get('episode_group')
|
||||
return HttpResponse.json([
|
||||
return apiJson([
|
||||
createTmdbEpisode({ episode_number: 1, name: `${group} 第一集`, season_number: 1 }),
|
||||
createTmdbEpisode({ episode_number: 2, name: `${group} 第二集`, season_number: 1 }),
|
||||
])
|
||||
@@ -1254,10 +1255,10 @@ describe('MediaDetailView subscriptions, seasons, and episode groups', () => {
|
||||
staleRequest()
|
||||
const response = await staleEpisodes.promise
|
||||
staleResponseReturned.resolve()
|
||||
return HttpResponse.json(response)
|
||||
return apiJson(response)
|
||||
}
|
||||
currentRequest()
|
||||
return HttpResponse.json([createTmdbEpisode({ episode_number: 1, name: 'B 组第一集', season_number: 1 })])
|
||||
return apiJson([createTmdbEpisode({ episode_number: 1, name: 'B 组第一集', season_number: 1 })])
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import userEvent from '@testing-library/user-event'
|
||||
import { server } from '@tests/support/msw/server'
|
||||
import { renderWithProviders } from '@tests/support/render'
|
||||
import { HttpResponse, http } from 'msw'
|
||||
import { apiJson } from '@tests/support/msw/response'
|
||||
import { defineComponent, h, onMounted, ref, type PropType } from 'vue'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
@@ -112,9 +113,7 @@ describe('PersonCardListView', () => {
|
||||
|
||||
it('loads people with the configured prefetch margin', async () => {
|
||||
server.use(
|
||||
http.get(LIST_URL, () =>
|
||||
HttpResponse.json([{ id: 101, name: '探索人物', source: 'themoviedb' } satisfies Person]),
|
||||
),
|
||||
http.get(LIST_URL, () => apiJson([{ id: 101, name: '探索人物', source: 'themoviedb' } satisfies Person])),
|
||||
)
|
||||
|
||||
await renderList()
|
||||
@@ -129,7 +128,7 @@ describe('PersonCardListView', () => {
|
||||
server.use(
|
||||
http.get(LIST_URL, ({ request }) => {
|
||||
requests.push(new URL(request.url))
|
||||
return HttpResponse.json([{ id: 303, name: '多来源人物', source: 'themoviedb' } satisfies Person])
|
||||
return apiJson([{ id: 303, name: '多来源人物', source: 'themoviedb' } satisfies Person])
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -146,7 +145,7 @@ describe('PersonCardListView', () => {
|
||||
http.get(LIST_URL, () => {
|
||||
requests++
|
||||
if (requests === 1) return HttpResponse.json({ detail: 'failed' }, { status: 500 })
|
||||
return HttpResponse.json([{ id: 202, name: '人物重试结果', source: 'themoviedb' } satisfies Person])
|
||||
return apiJson([{ id: 202, name: '人物重试结果', source: 'themoviedb' } satisfies Person])
|
||||
}),
|
||||
)
|
||||
const user = userEvent.setup()
|
||||
|
||||
@@ -4,6 +4,7 @@ import { fireEvent, screen, waitFor } from '@testing-library/vue'
|
||||
import { server } from '@tests/support/msw/server'
|
||||
import { renderWithProviders } from '@tests/support/render'
|
||||
import { HttpResponse, http } from 'msw'
|
||||
import { apiJson } from '@tests/support/msw/response'
|
||||
import { defineComponent, h, type PropType, ref } from 'vue'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
@@ -75,7 +76,8 @@ const PersonCardStub = defineComponent({
|
||||
function personResponse(people: Person[], status = 200, onRequest: () => void = () => {}) {
|
||||
return http.get(API_URL, () => {
|
||||
onRequest()
|
||||
return HttpResponse.json(people, { status })
|
||||
if (status >= 400) return HttpResponse.json(people, { status })
|
||||
return apiJson(people, { status })
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import { fireEvent, screen, waitFor, within } from '@testing-library/vue'
|
||||
import { server } from '@tests/support/msw/server'
|
||||
import { renderWithProviders } from '@tests/support/render'
|
||||
import { HttpResponse, http, type JsonBodyType } from 'msw'
|
||||
import { apiFailureJson, apiJson } from '@tests/support/msw/response'
|
||||
import { computed, defineComponent, h, nextTick, unref, type ComputedRef, type PropType, type Ref } from 'vue'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
@@ -384,20 +385,18 @@ interface ListResponses {
|
||||
|
||||
function registerListHandlers(responses: ListResponses = {}) {
|
||||
server.use(
|
||||
http.get(apiUrls.order, () =>
|
||||
HttpResponse.json({ data: { value: responses.order ?? [] }, success: true } as JsonBodyType),
|
||||
),
|
||||
http.get(apiUrls.folders, async () => HttpResponse.json((await responses.folders?.()) ?? {})),
|
||||
http.get(apiUrls.order, () => apiJson({ value: responses.order ?? [] })),
|
||||
http.get(apiUrls.folders, async () => apiJson((await responses.folders?.()) ?? {})),
|
||||
http.get(apiUrls.list, async ({ request }) => {
|
||||
const state = new URL(request.url).searchParams.get('state')
|
||||
const plugins = state === 'installed' ? await responses.installed?.() : await responses.market?.()
|
||||
return HttpResponse.json((plugins ?? []) as unknown as JsonBodyType, {
|
||||
return apiJson((plugins ?? []) as unknown as JsonBodyType, {
|
||||
status: state === 'installed' ? (responses.installedStatus ?? 200) : (responses.marketStatus ?? 200),
|
||||
})
|
||||
}),
|
||||
http.get(apiUrls.statistic, async () => HttpResponse.json((await responses.statistic?.()) ?? {})),
|
||||
http.get(apiUrls.statistic, async () => apiJson((await responses.statistic?.()) ?? {})),
|
||||
http.get(apiUrls.runtime, async () =>
|
||||
HttpResponse.json(
|
||||
apiJson(
|
||||
(await responses.runtime?.()) ?? {
|
||||
failed_count: 0,
|
||||
generation: 0,
|
||||
@@ -406,10 +405,10 @@ function registerListHandlers(responses: ListResponses = {}) {
|
||||
},
|
||||
),
|
||||
),
|
||||
http.get(apiUrls.sidebar, () => HttpResponse.json([])),
|
||||
http.get(apiUrls.sidebar, () => apiJson([])),
|
||||
http.get(apiUrls.rating, async ({ request }) => {
|
||||
const ids = new URL(request.url).searchParams.get('plugin_ids')?.split(',').filter(Boolean) ?? []
|
||||
return HttpResponse.json(((await responses.rating?.(ids)) ?? {}) as unknown as JsonBodyType)
|
||||
return apiJson(((await responses.rating?.(ids)) ?? {}) as unknown as JsonBodyType)
|
||||
}),
|
||||
)
|
||||
}
|
||||
@@ -760,7 +759,7 @@ describe('PluginCardListView loading and request ownership', () => {
|
||||
const state = new URL(request.url).searchParams.get('state')
|
||||
const plugins =
|
||||
state === 'installed' ? [createPlugin({ id: 'Recovered', installed: true, plugin_name: '重试恢复插件' })] : []
|
||||
return HttpResponse.json(plugins as unknown as JsonBodyType)
|
||||
return apiJson(plugins as unknown as JsonBodyType)
|
||||
}),
|
||||
)
|
||||
await fireEvent.click(screen.getByRole('button', { name: '重试' }))
|
||||
@@ -844,7 +843,7 @@ describe('PluginCardListView loading and request ownership', () => {
|
||||
const state = new URL(request.url).searchParams.get('state')
|
||||
const plugins =
|
||||
state === 'market' ? [createPlugin({ id: 'MarketRecovered', plugin_name: '市场重试恢复插件' })] : []
|
||||
return HttpResponse.json(plugins as unknown as JsonBodyType)
|
||||
return apiJson(plugins as unknown as JsonBodyType)
|
||||
}),
|
||||
)
|
||||
await fireEvent.click(screen.getByRole('button', { name: '重试' }))
|
||||
@@ -1217,7 +1216,7 @@ describe('PluginCardListView installed filtering and host callbacks', () => {
|
||||
getDialogEvents().changed()
|
||||
await waitFor(() => expect(marketRequests).toBeGreaterThan(requestsAfterSave))
|
||||
|
||||
server.use(http.get(apiUrls.install('Available'), () => HttpResponse.json({ data: null, success: true })))
|
||||
server.use(http.get(apiUrls.install('Available'), () => apiJson(null)))
|
||||
await fireEvent.click(screen.getByRole('button', { name: 'installed-Available' }))
|
||||
await waitFor(() => expect(sidebarStore.ensureSidebarNav).toHaveBeenCalledWith(true))
|
||||
await waitForRequestsToFinish()
|
||||
@@ -1237,7 +1236,7 @@ describe('PluginCardListView installed filtering and host callbacks', () => {
|
||||
http.get(apiUrls.install('MarketInstall'), async () => {
|
||||
await installGate.promise
|
||||
installed = true
|
||||
return HttpResponse.json({ data: null, success: true })
|
||||
return apiJson(null)
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -1272,7 +1271,7 @@ describe('PluginCardListView search installation', () => {
|
||||
http.get(apiUrls.install('SearchPlugin'), () => {
|
||||
installRequests += 1
|
||||
return mode === 'business'
|
||||
? HttpResponse.json({ message: 'Rejected', success: false })
|
||||
? apiFailureJson('Rejected')
|
||||
: HttpResponse.json({ message: 'HTTP failure' }, { status: 500 })
|
||||
}),
|
||||
)
|
||||
@@ -1330,7 +1329,7 @@ describe('PluginCardListView search installation', () => {
|
||||
http.get(apiUrls.install('SearchPlugin'), ({ request }) => {
|
||||
installUrl = new URL(request.url)
|
||||
installed = true
|
||||
return HttpResponse.json({ data: null, success: true })
|
||||
return apiJson(null)
|
||||
}),
|
||||
)
|
||||
const sidebarStore = usePluginSidebarNavStore(pinia)
|
||||
@@ -1370,7 +1369,7 @@ describe('PluginCardListView search installation', () => {
|
||||
http.get(apiUrls.install('PendingPlugin'), async () => {
|
||||
await installGate.promise
|
||||
installed = true
|
||||
return HttpResponse.json({ data: null, success: true })
|
||||
return apiJson(null)
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -1400,7 +1399,7 @@ describe('PluginCardListView search installation', () => {
|
||||
http.get(apiUrls.install('DuplicatePlugin'), async () => {
|
||||
installRequests += 1
|
||||
await installGate.promise
|
||||
return HttpResponse.json({ data: null, success: true })
|
||||
return apiJson(null)
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -1432,11 +1431,7 @@ describe('PluginCardListView search installation', () => {
|
||||
market: () => [target],
|
||||
})
|
||||
await waitForRequestsToFinish()
|
||||
server.use(
|
||||
http.get(apiUrls.install('SlowRollbackPlugin'), () =>
|
||||
HttpResponse.json({ message: '依赖安装失败', success: false }),
|
||||
),
|
||||
)
|
||||
server.use(http.get(apiUrls.install('SlowRollbackPlugin'), () => apiFailureJson('依赖安装失败')))
|
||||
|
||||
getDynamicButtonConfig().onClick()
|
||||
await getDialogEvents()['open-plugin'](target)
|
||||
@@ -1453,9 +1448,7 @@ describe('PluginCardListView search installation', () => {
|
||||
const target = createPlugin({ id: 'FailedPlugin', plugin_name: '失败插件' })
|
||||
await renderList({ installed: () => [stable], market: () => [target] })
|
||||
await waitForRequestsToFinish()
|
||||
server.use(
|
||||
http.get(apiUrls.install('FailedPlugin'), () => HttpResponse.json({ message: '依赖安装失败', success: false })),
|
||||
)
|
||||
server.use(http.get(apiUrls.install('FailedPlugin'), () => apiFailureJson('依赖安装失败')))
|
||||
|
||||
getDynamicButtonConfig().onClick()
|
||||
await getDialogEvents()['open-plugin'](target)
|
||||
@@ -1525,7 +1518,7 @@ describe('PluginCardListView folders and persistence', () => {
|
||||
})
|
||||
await screen.findByText('plugin:已安装插件')
|
||||
await waitForRequestsToFinish()
|
||||
server.use(http.post(apiUrls.folders, () => HttpResponse.json({ message: '保存被拒绝', success: false })))
|
||||
server.use(http.post(apiUrls.folders, () => apiFailureJson('保存被拒绝')))
|
||||
|
||||
getDynamicMenuItem('plugin.newFolder').action()
|
||||
const events = getDialogEvents()
|
||||
@@ -1543,7 +1536,7 @@ describe('PluginCardListView folders and persistence', () => {
|
||||
await renderList({ folders: () => ({ Existing: [] }) })
|
||||
await screen.findByText('folder:Existing')
|
||||
await waitForRequestsToFinish()
|
||||
server.use(http.post(apiUrls.folders, () => HttpResponse.json({ data: null, success: true })))
|
||||
server.use(http.post(apiUrls.folders, () => apiJson(null)))
|
||||
|
||||
getDynamicMenuItem('plugin.newFolder').action()
|
||||
const events = getDialogEvents()
|
||||
@@ -1568,7 +1561,7 @@ describe('PluginCardListView folders and persistence', () => {
|
||||
})
|
||||
await screen.findByText('folder:Tools')
|
||||
await waitForRequestsToFinish()
|
||||
server.use(http.post(apiUrls.folders, () => HttpResponse.json({ data: null, success: true })))
|
||||
server.use(http.post(apiUrls.folders, () => apiJson(null)))
|
||||
|
||||
await fireEvent.click(screen.getByRole('button', { name: 'configure-folder-Tools' }))
|
||||
await waitFor(() => expect(screen.getByLabelText('folder-color-Tools')).toHaveTextContent('#ff0000'))
|
||||
@@ -1597,7 +1590,7 @@ describe('PluginCardListView folders and persistence', () => {
|
||||
saveAttempt += 1
|
||||
return saveAttempt === 2
|
||||
? HttpResponse.json({ message: 'HTTP failure' }, { status: 500 })
|
||||
: HttpResponse.json({ message: 'Rejected', success: false })
|
||||
: apiFailureJson('Rejected')
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -1626,9 +1619,7 @@ describe('PluginCardListView folders and persistence', () => {
|
||||
await waitForRequestsToFinish()
|
||||
server.use(
|
||||
http.post(apiUrls.folders, () =>
|
||||
saveSucceeds
|
||||
? HttpResponse.json({ data: null, success: true })
|
||||
: HttpResponse.json({ message: 'Rejected' }, { status: 500 }),
|
||||
saveSucceeds ? apiJson(null) : HttpResponse.json({ message: 'Rejected' }, { status: 500 }),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -1664,11 +1655,9 @@ describe('PluginCardListView folders and persistence', () => {
|
||||
server.use(
|
||||
http.post(apiUrls.order, async ({ request }) => {
|
||||
savedOrder = await request.json()
|
||||
return orderSucceeds
|
||||
? HttpResponse.json({ data: null, success: true })
|
||||
: HttpResponse.json({ message: 'Rejected', success: false })
|
||||
return orderSucceeds ? apiJson(null) : apiFailureJson('Rejected')
|
||||
}),
|
||||
http.post(apiUrls.folders, () => HttpResponse.json({ data: null, success: true })),
|
||||
http.post(apiUrls.folders, () => apiJson(null)),
|
||||
)
|
||||
|
||||
getHeaderButton('mdi-sort-variant').action?.()
|
||||
@@ -1712,17 +1701,17 @@ describe('PluginCardListView folders and persistence', () => {
|
||||
server.use(
|
||||
http.get(apiUrls.order, () => {
|
||||
orderReads += 1
|
||||
return HttpResponse.json({ data: { value: persistedOrder }, success: true })
|
||||
return apiJson({ value: persistedOrder })
|
||||
}),
|
||||
http.get(apiUrls.folders, () => {
|
||||
folderReads += 1
|
||||
return HttpResponse.json({ Tools: [] })
|
||||
return apiJson({ Tools: [] })
|
||||
}),
|
||||
http.post(apiUrls.order, async ({ request }) => {
|
||||
persistedOrder = (await request.json()) as unknown[]
|
||||
return HttpResponse.json({ data: null, success: true })
|
||||
return apiJson(null)
|
||||
}),
|
||||
http.post(apiUrls.folders, () => HttpResponse.json({ message: 'Rejected', success: false })),
|
||||
http.post(apiUrls.folders, () => apiFailureJson('Rejected')),
|
||||
)
|
||||
|
||||
getHeaderButton('mdi-sort-variant').action?.()
|
||||
@@ -1762,15 +1751,15 @@ describe('PluginCardListView folders and persistence', () => {
|
||||
server.use(
|
||||
http.get(apiUrls.order, () => {
|
||||
orderReads += 1
|
||||
return HttpResponse.json({ data: { value: persistedOrder }, success: true })
|
||||
return apiJson({ value: persistedOrder })
|
||||
}),
|
||||
http.get(apiUrls.folders, () => {
|
||||
folderReads += 1
|
||||
return HttpResponse.json({ Tools: ['Plugin-A', 'Plugin-B'] })
|
||||
return apiJson({ Tools: ['Plugin-A', 'Plugin-B'] })
|
||||
}),
|
||||
http.post(apiUrls.order, async ({ request }) => {
|
||||
persistedOrder = (await request.json()) as unknown[]
|
||||
return HttpResponse.json({ data: null, success: true })
|
||||
return apiJson(null)
|
||||
}),
|
||||
http.post(apiUrls.folders, () => HttpResponse.json({ message: 'Rejected' }, { status: 500 })),
|
||||
)
|
||||
@@ -1800,12 +1789,8 @@ describe('PluginCardListView folders and persistence', () => {
|
||||
await screen.findByText('folder:Tools')
|
||||
await waitForRequestsToFinish()
|
||||
server.use(
|
||||
http.post(apiUrls.order, () => HttpResponse.json({ data: null, success: true })),
|
||||
http.post(apiUrls.folders, () =>
|
||||
folderSaveSucceeds
|
||||
? HttpResponse.json({ data: null, success: true })
|
||||
: HttpResponse.json({ message: 'Rejected', success: false }),
|
||||
),
|
||||
http.post(apiUrls.order, () => apiJson(null)),
|
||||
http.post(apiUrls.folders, () => (folderSaveSucceeds ? apiJson(null) : apiFailureJson('Rejected'))),
|
||||
)
|
||||
|
||||
getHeaderButton('mdi-sort-variant').action?.()
|
||||
@@ -1845,12 +1830,8 @@ describe('PluginCardListView folders and persistence', () => {
|
||||
await screen.findByText('folder:Tools')
|
||||
await waitForRequestsToFinish()
|
||||
server.use(
|
||||
http.post(apiUrls.order, () =>
|
||||
orderSucceeds
|
||||
? HttpResponse.json({ data: null, success: true })
|
||||
: HttpResponse.json({ message: 'Rejected', success: false }),
|
||||
),
|
||||
http.post(apiUrls.folders, () => HttpResponse.json({ data: null, success: true })),
|
||||
http.post(apiUrls.order, () => (orderSucceeds ? apiJson(null) : apiFailureJson('Rejected'))),
|
||||
http.post(apiUrls.folders, () => apiJson(null)),
|
||||
)
|
||||
|
||||
await fireEvent.click(screen.getByRole('button', { name: 'open-folder-Tools' }))
|
||||
|
||||
@@ -306,6 +306,62 @@ function createModelFieldStub(name: string) {
|
||||
})
|
||||
}
|
||||
|
||||
/** 保留选择值契约,排除 Vuetify 菜单动画和定位对设置业务测试的影响。 */
|
||||
const SelectFieldStub = defineComponent({
|
||||
name: 'VSelectStub',
|
||||
props: {
|
||||
disabled: { type: Boolean, default: false },
|
||||
itemTitle: { type: String, default: 'title' },
|
||||
itemValue: { type: String, default: 'value' },
|
||||
items: { type: Array, default: () => [] },
|
||||
label: { type: String, default: '' },
|
||||
modelValue: { default: null },
|
||||
multiple: { type: Boolean, default: false },
|
||||
},
|
||||
emits: ['update:modelValue'],
|
||||
setup(props, { emit }) {
|
||||
const itemValue = (item: unknown) => {
|
||||
if (!item || typeof item !== 'object') return item
|
||||
return (item as Record<string, unknown>)[props.itemValue]
|
||||
}
|
||||
const itemTitle = (item: unknown) => {
|
||||
if (!item || typeof item !== 'object') return String(item ?? '')
|
||||
return String((item as Record<string, unknown>)[props.itemTitle] ?? '')
|
||||
}
|
||||
const findItemValue = (value: string) => props.items.map(itemValue).find(item => String(item) === value)
|
||||
|
||||
return () =>
|
||||
h('label', [
|
||||
h('span', props.label),
|
||||
h(
|
||||
'select',
|
||||
{
|
||||
'aria-label': props.label,
|
||||
disabled: props.disabled,
|
||||
multiple: props.multiple,
|
||||
onChange: (event: Event) => {
|
||||
const select = event.target as HTMLSelectElement
|
||||
if (props.multiple) {
|
||||
const selectedValues = Array.from(select.selectedOptions, option => findItemValue(option.value))
|
||||
emit('update:modelValue', selectedValues)
|
||||
return
|
||||
}
|
||||
emit('update:modelValue', findItemValue(select.value))
|
||||
},
|
||||
...(props.multiple ? {} : { value: String(props.modelValue ?? '') }),
|
||||
},
|
||||
props.items.map(item => {
|
||||
const value = itemValue(item)
|
||||
const selected = props.multiple
|
||||
? (props.modelValue as unknown[] | null)?.some(modelValue => String(modelValue) === String(value))
|
||||
: String(props.modelValue ?? '') === String(value)
|
||||
return h('option', { selected, value: String(value) }, itemTitle(item))
|
||||
}),
|
||||
),
|
||||
])
|
||||
},
|
||||
})
|
||||
|
||||
const CronFieldStub = createModelFieldStub('VCronFieldStub')
|
||||
const PathFieldStub = createModelFieldStub('VPathFieldStub')
|
||||
|
||||
@@ -314,7 +370,7 @@ async function renderSettings(props: { active?: boolean } = {}) {
|
||||
props,
|
||||
global: {
|
||||
components: { VCronField: CronFieldStub, VPathField: PathFieldStub },
|
||||
stubs: { VDialogCloseBtn: true },
|
||||
stubs: { VDialogCloseBtn: true, VSelect: SelectFieldStub },
|
||||
},
|
||||
stubActions: false,
|
||||
})
|
||||
@@ -327,7 +383,7 @@ function getBasicCard() {
|
||||
}
|
||||
|
||||
function getSettingsCard(title: string) {
|
||||
const card = screen.getByText(title).closest('.v-card')
|
||||
const card = screen.getByText(title, { selector: '.v-card-title' }).closest('.v-card')
|
||||
expect(card).not.toBeNull()
|
||||
return within(card as HTMLElement)
|
||||
}
|
||||
@@ -340,7 +396,17 @@ async function openAdvancedTab(tab: string) {
|
||||
|
||||
async function selectOption(label: string, option: string) {
|
||||
const user = userEvent.setup()
|
||||
await user.click(screen.getByLabelText(label))
|
||||
const control = screen.getByLabelText(label)
|
||||
if (control instanceof HTMLSelectElement) {
|
||||
if (control.multiple) {
|
||||
const nextOption = within(control).getByRole('option', { name: option }) as HTMLOptionElement
|
||||
await user.selectOptions(control, nextOption.value)
|
||||
} else {
|
||||
await user.selectOptions(control, option)
|
||||
}
|
||||
return
|
||||
}
|
||||
await user.click(control)
|
||||
await user.click(await screen.findByRole('option', { name: option }))
|
||||
}
|
||||
|
||||
@@ -954,8 +1020,12 @@ describe('AccountSettingSystem', () => {
|
||||
]) {
|
||||
await fireEvent.click(dialog.getByLabelText(label))
|
||||
}
|
||||
await user.click(dialog.getByLabelText('Fanart语言'))
|
||||
await user.click(await screen.findByRole('option', { name: '日文' }))
|
||||
const fanartLanguages = dialog.getByLabelText('Fanart语言')
|
||||
expect(fanartLanguages).toHaveValue(['zh', 'en'])
|
||||
await selectOption('Fanart语言', '日文')
|
||||
await waitFor(() => expect(fanartLanguages).toHaveValue(['zh', 'en', 'ja']))
|
||||
await user.deselectOptions(fanartLanguages, 'en')
|
||||
await waitFor(() => expect(fanartLanguages).toHaveValue(['zh', 'ja']))
|
||||
await fireEvent.click(dialog.getByRole('button', { name: '保存' }))
|
||||
|
||||
await waitFor(() => expect(screen.queryByRole('dialog')).not.toBeInTheDocument())
|
||||
@@ -963,7 +1033,7 @@ describe('AccountSettingSystem', () => {
|
||||
expect.objectContaining({
|
||||
ACOUSTID_API_KEY: 'acoustid-key',
|
||||
FANART_ENABLE: true,
|
||||
FANART_LANG: 'zh,en,ja',
|
||||
FANART_LANG: 'zh,ja',
|
||||
MEDIA_RECOGNIZE_SHARE: false,
|
||||
META_CACHE_EXPIRE: '48',
|
||||
MUSIC_COVER_PROXY: 'https://music.example',
|
||||
|
||||
@@ -8,6 +8,7 @@ import { subscribeApiUrls, subscribeListHandler } from '@tests/support/msw/handl
|
||||
import { server } from '@tests/support/msw/server'
|
||||
import { renderWithProviders } from '@tests/support/render'
|
||||
import { HttpResponse, http } from 'msw'
|
||||
import { apiJson } from '@tests/support/msw/response'
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
@@ -142,7 +143,8 @@ function sequenceSubscribeList(responses: Array<{ body: Subscribe[]; status?: nu
|
||||
onRequest()
|
||||
const response = responses[Math.min(index, responses.length - 1)]
|
||||
index += 1
|
||||
return HttpResponse.json(response.body, { status: response.status ?? 200 })
|
||||
if ((response.status ?? 200) >= 400) return HttpResponse.json(response.body, { status: response.status })
|
||||
return apiJson(response.body, { status: response.status ?? 200 })
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import { server } from '@tests/support/msw/server'
|
||||
import { renderWithProviders } from '@tests/support/render'
|
||||
import { flushPromises } from '@vue/test-utils'
|
||||
import { HttpResponse, http } from 'msw'
|
||||
import { apiJson } from '@tests/support/msw/response'
|
||||
import { defineComponent, h, onMounted, ref, type PropType } from 'vue'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
@@ -196,7 +197,7 @@ describe('SubscribePopularView', () => {
|
||||
: url.searchParams.get('sort_type') === 'time'
|
||||
? '最新热门结果'
|
||||
: '默认热门结果'
|
||||
return HttpResponse.json([createSubscribeMovie({ title })])
|
||||
return apiJson([createSubscribeMovie({ title })])
|
||||
}),
|
||||
)
|
||||
const user = userEvent.setup()
|
||||
@@ -232,9 +233,9 @@ describe('SubscribePopularView', () => {
|
||||
http.get(subscribeApiUrls.popular, ({ request }) => {
|
||||
const page = new URL(request.url).searchParams.get('page') ?? ''
|
||||
requestedPages.push(page)
|
||||
if (page === '1') return HttpResponse.json([first])
|
||||
if (page === '2') return HttpResponse.json([second])
|
||||
return HttpResponse.json([])
|
||||
if (page === '1') return apiJson([first])
|
||||
if (page === '2') return apiJson([second])
|
||||
return apiJson([])
|
||||
}),
|
||||
)
|
||||
const user = userEvent.setup()
|
||||
@@ -260,11 +261,11 @@ describe('SubscribePopularView', () => {
|
||||
http.get(subscribeApiUrls.popular, ({ request }) => {
|
||||
const page = new URL(request.url).searchParams.get('page') ?? ''
|
||||
requestedPages.push(page)
|
||||
if (page === '1') return HttpResponse.json([first])
|
||||
if (page === '1') return apiJson([first])
|
||||
if (page === '2') {
|
||||
return HttpResponse.json([{ ...first, title: '第一页跨页重复项' }, second])
|
||||
return apiJson([{ ...first, title: '第一页跨页重复项' }, second])
|
||||
}
|
||||
return HttpResponse.json([
|
||||
return apiJson([
|
||||
{ ...second, title: '第二页乱序重复项' },
|
||||
{ ...first, title: '第一页乱序重复项' },
|
||||
{ ...first, title: '第一页页内重复项' },
|
||||
@@ -320,7 +321,7 @@ describe('SubscribePopularView', () => {
|
||||
http.get(subscribeApiUrls.popular, ({ request }) => {
|
||||
const page = new URL(request.url).searchParams.get('page') ?? ''
|
||||
requestedPages.push(page)
|
||||
return HttpResponse.json(page === '1' ? [first] : [second])
|
||||
return apiJson(page === '1' ? [first] : [second])
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -371,7 +372,7 @@ describe('SubscribePopularView', () => {
|
||||
const page = new URL(request.url).searchParams.get('page') ?? ''
|
||||
requestedPages.push(page)
|
||||
if (requestedPages.length === 1) return HttpResponse.json({ detail: 'failed' }, { status: 500 })
|
||||
return HttpResponse.json([createSubscribeMovie({ title: '热门首载重试成功' })])
|
||||
return apiJson([createSubscribeMovie({ title: '热门首载重试成功' })])
|
||||
}),
|
||||
)
|
||||
const user = userEvent.setup()
|
||||
@@ -395,10 +396,10 @@ describe('SubscribePopularView', () => {
|
||||
http.get(subscribeApiUrls.popular, ({ request }) => {
|
||||
const page = new URL(request.url).searchParams.get('page') ?? ''
|
||||
requestedPages.push(page)
|
||||
if (page === '1') return HttpResponse.json([first])
|
||||
if (page === '1') return apiJson([first])
|
||||
pageTwoAttempts += 1
|
||||
if (pageTwoAttempts === 1) return HttpResponse.json({ detail: 'failed' }, { status: 500 })
|
||||
return HttpResponse.json([second])
|
||||
return apiJson([second])
|
||||
}),
|
||||
)
|
||||
const user = userEvent.setup()
|
||||
@@ -427,9 +428,9 @@ describe('SubscribePopularView', () => {
|
||||
if (!url.searchParams.has('genre_id')) {
|
||||
await gate.promise
|
||||
staleResponse()
|
||||
return HttpResponse.json([createSubscribeMovie({ title: '过期热门结果' })])
|
||||
return apiJson([createSubscribeMovie({ title: '过期热门结果' })])
|
||||
}
|
||||
return HttpResponse.json([createSubscribeMovie({ title: '新筛选热门结果' })])
|
||||
return apiJson([createSubscribeMovie({ title: '新筛选热门结果' })])
|
||||
}),
|
||||
)
|
||||
const user = userEvent.setup()
|
||||
|
||||
@@ -8,6 +8,7 @@ import { server } from '@tests/support/msw/server'
|
||||
import { renderWithProviders } from '@tests/support/render'
|
||||
import { flushPromises } from '@vue/test-utils'
|
||||
import { HttpResponse, http } from 'msw'
|
||||
import { apiJson } from '@tests/support/msw/response'
|
||||
import { defineComponent, h, onMounted, ref, type PropType } from 'vue'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
@@ -213,7 +214,7 @@ describe('SubscribeShareView', () => {
|
||||
: url.searchParams.get('sort_type') === 'count'
|
||||
? '热门分享结果'
|
||||
: '默认分享结果'
|
||||
return HttpResponse.json([createSubscribeShare({ share_title: shareTitle })])
|
||||
return apiJson([createSubscribeShare({ share_title: shareTitle })])
|
||||
}),
|
||||
)
|
||||
const user = userEvent.setup()
|
||||
@@ -249,9 +250,9 @@ describe('SubscribeShareView', () => {
|
||||
http.get(subscribeApiUrls.shares, ({ request }) => {
|
||||
const page = new URL(request.url).searchParams.get('page') ?? ''
|
||||
requestedPages.push(page)
|
||||
if (page === '1') return HttpResponse.json([first])
|
||||
if (page === '2') return HttpResponse.json([second])
|
||||
return HttpResponse.json([])
|
||||
if (page === '1') return apiJson([first])
|
||||
if (page === '2') return apiJson([second])
|
||||
return apiJson([])
|
||||
}),
|
||||
)
|
||||
const user = userEvent.setup()
|
||||
@@ -280,7 +281,7 @@ describe('SubscribeShareView', () => {
|
||||
http.get(subscribeApiUrls.shares, ({ request }) => {
|
||||
const page = new URL(request.url).searchParams.get('page') ?? ''
|
||||
requestedPages.push(page)
|
||||
return HttpResponse.json(page === '1' ? [first] : [second])
|
||||
return apiJson(page === '1' ? [first] : [second])
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -332,7 +333,7 @@ describe('SubscribeShareView', () => {
|
||||
const url = new URL(request.url)
|
||||
requests.push(url)
|
||||
const keyword = url.searchParams.get('name') ?? ''
|
||||
return HttpResponse.json([
|
||||
return apiJson([
|
||||
createSubscribeShare({ share_title: keyword === '新关键字' ? '新关键字分享' : '旧关键字分享' }),
|
||||
])
|
||||
}),
|
||||
@@ -371,7 +372,7 @@ describe('SubscribeShareView', () => {
|
||||
const page = new URL(request.url).searchParams.get('page') ?? ''
|
||||
requestedPages.push(page)
|
||||
if (requestedPages.length === 1) return HttpResponse.json({ detail: 'failed' }, { status: 500 })
|
||||
return HttpResponse.json([createSubscribeShare({ share_title: '分享首载重试成功' })])
|
||||
return apiJson([createSubscribeShare({ share_title: '分享首载重试成功' })])
|
||||
}),
|
||||
)
|
||||
const user = userEvent.setup()
|
||||
@@ -395,10 +396,10 @@ describe('SubscribeShareView', () => {
|
||||
http.get(subscribeApiUrls.shares, ({ request }) => {
|
||||
const page = new URL(request.url).searchParams.get('page') ?? ''
|
||||
requestedPages.push(page)
|
||||
if (page === '1') return HttpResponse.json([first])
|
||||
if (page === '1') return apiJson([first])
|
||||
pageTwoAttempts += 1
|
||||
if (pageTwoAttempts === 1) return HttpResponse.json({ detail: 'failed' }, { status: 500 })
|
||||
return HttpResponse.json([second])
|
||||
return apiJson([second])
|
||||
}),
|
||||
)
|
||||
const user = userEvent.setup()
|
||||
@@ -427,9 +428,9 @@ describe('SubscribeShareView', () => {
|
||||
if (url.searchParams.get('name') === '旧关键字') {
|
||||
await gate.promise
|
||||
staleResponse()
|
||||
return HttpResponse.json([createSubscribeShare({ share_title: '过期关键字分享' })])
|
||||
return apiJson([createSubscribeShare({ share_title: '过期关键字分享' })])
|
||||
}
|
||||
return HttpResponse.json([createSubscribeShare({ share_title: '新关键字实时分享' })])
|
||||
return apiJson([createSubscribeShare({ share_title: '新关键字实时分享' })])
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user