mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-08-29 20:17:36 +08:00
fix: 修正下载器卡片属性透传 (#714)
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
defineOptions({ inheritAttrs: false })
|
||||
|
||||
import api from '@/api'
|
||||
import { formatFileSize } from '@/@core/utils/formatters'
|
||||
import type { DownloaderConf, DownloaderInfo } from '@/api/types'
|
||||
import { getLogoUrl } from '@/utils/imageUtils'
|
||||
import { mergeProps } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { downloaderDict } from '@/api/constants'
|
||||
import { useBackground } from '@/composables/useBackground'
|
||||
@@ -122,7 +125,7 @@ onUnmounted(() => {
|
||||
<template>
|
||||
<VHover v-slot="hover">
|
||||
<VCard
|
||||
v-bind="hover.props"
|
||||
v-bind="mergeProps($attrs, hover.props)"
|
||||
variant="tonal"
|
||||
class="app-card-shell app-card-colorful"
|
||||
:style="{ '--app-card-accent-rgb': accentRgb }"
|
||||
@@ -146,7 +149,10 @@ onUnmounted(() => {
|
||||
/>
|
||||
<span class="app-card-summary__title text-h6">{{ downloader.name }}</span>
|
||||
</div>
|
||||
<div v-if="downloaderDict[downloader.type] && props.downloader.enabled" class="app-card-summary__meta text-sm">
|
||||
<div
|
||||
v-if="downloaderDict[downloader.type] && props.downloader.enabled"
|
||||
class="app-card-summary__meta text-sm"
|
||||
>
|
||||
<span class="app-card-summary__meta-item">{{ `↑ ${formatFileSize(upload_rate, 1)}/s` }}</span>
|
||||
<span class="app-card-summary__meta-item">{{ `↓ ${formatFileSize(download_rate, 1)}/s` }}</span>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
import DownloaderCard from '@/components/cards/DownloaderCard.vue'
|
||||
import { renderWithProviders } from '@tests/support/render'
|
||||
import { defineComponent, h, ref } from 'vue'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
vi.mock('@/api', () => ({
|
||||
default: {
|
||||
get: vi.fn(),
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('@/composables/useBackground', () => ({
|
||||
useBackground: () => ({
|
||||
useConditionalDataRefresh: () => ({ stop: vi.fn() }),
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock('@/composables/useCardAccentColor', () => ({
|
||||
useCardAccentColor: () => ({
|
||||
accentRgb: ref('141, 81, 249'),
|
||||
imageRef: ref(),
|
||||
updateAccentColor: vi.fn(),
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock('@/utils/imageUtils', () => ({
|
||||
getLogoUrl: () => '/downloader.png',
|
||||
}))
|
||||
|
||||
const passthroughStub = (name: string, tag = 'div') =>
|
||||
defineComponent({
|
||||
name,
|
||||
inheritAttrs: false,
|
||||
setup(_props, { attrs, slots }) {
|
||||
return () => h(tag, attrs, slots.default?.())
|
||||
},
|
||||
})
|
||||
|
||||
const VHoverStub = defineComponent({
|
||||
name: 'VHover',
|
||||
inheritAttrs: false,
|
||||
setup(_props, { slots }) {
|
||||
return () => slots.default?.({ props: { onMouseenter: hoverMouseenter } })
|
||||
},
|
||||
})
|
||||
|
||||
const hoverMouseenter = vi.fn()
|
||||
|
||||
const VCardStub = passthroughStub('VCard', 'article')
|
||||
|
||||
const globalStubs = {
|
||||
IconBtn: passthroughStub('IconBtn', 'button'),
|
||||
VBadge: passthroughStub('VBadge', 'span'),
|
||||
VCard: VCardStub,
|
||||
VCardText: passthroughStub('VCardText'),
|
||||
VDialogCloseBtn: passthroughStub('VDialogCloseBtn', 'button'),
|
||||
VHover: VHoverStub,
|
||||
VIcon: passthroughStub('VIcon', 'span'),
|
||||
VImg: defineComponent({
|
||||
name: 'VImg',
|
||||
props: { src: String },
|
||||
setup(props, { attrs }) {
|
||||
return () => h('img', { ...attrs, src: props.src })
|
||||
},
|
||||
}),
|
||||
}
|
||||
|
||||
const downloader = {
|
||||
name: 'qb-main',
|
||||
type: 'qbittorrent',
|
||||
default: true,
|
||||
enabled: false,
|
||||
config: {},
|
||||
}
|
||||
|
||||
describe('DownloaderCard', () => {
|
||||
it('places draggable attributes on the card DOM instead of the hover wrapper', async () => {
|
||||
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
||||
const externalMouseenter = vi.fn()
|
||||
hoverMouseenter.mockClear()
|
||||
const Harness = defineComponent({
|
||||
setup() {
|
||||
return () =>
|
||||
h(DownloaderCard, {
|
||||
downloader,
|
||||
downloaders: [downloader],
|
||||
allowRefresh: false,
|
||||
'data-draggable': 'true',
|
||||
'aria-label': 'qb-main-card',
|
||||
class: 'draggable-item',
|
||||
onMouseenter: externalMouseenter,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
const { container } = await renderWithProviders(Harness, {
|
||||
global: { stubs: globalStubs },
|
||||
})
|
||||
|
||||
const card = container.querySelector('article')
|
||||
expect(card).toBeInTheDocument()
|
||||
expect(card).toHaveAttribute('data-draggable', 'true')
|
||||
expect(card).toHaveAttribute('aria-label', 'qb-main-card')
|
||||
expect(card).toHaveClass('draggable-item', 'app-card-shell', 'app-card-colorful')
|
||||
expect(container.querySelectorAll('[data-draggable]')).toHaveLength(1)
|
||||
card?.dispatchEvent(new MouseEvent('mouseenter'))
|
||||
expect(externalMouseenter).toHaveBeenCalledOnce()
|
||||
expect(hoverMouseenter).toHaveBeenCalledOnce()
|
||||
|
||||
const attributeWarnings = warn.mock.calls.filter(([message]) =>
|
||||
String(message).includes('Extraneous non-props attributes'),
|
||||
)
|
||||
expect(attributeWarnings).toHaveLength(0)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user