mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-09 09:46:44 +08:00
fix(notification): handle empty channel configuration
This commit is contained in:
@@ -83,7 +83,7 @@ type NotificationConfigInput = Partial<NotificationConf> & {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface NotificationConfigResponse {
|
interface NotificationConfigResponse {
|
||||||
value?: NotificationConfigInput[]
|
value?: NotificationConfigInput[] | null
|
||||||
}
|
}
|
||||||
|
|
||||||
type NotificationLoadState = 'idle' | 'loading' | 'ready' | 'error'
|
type NotificationLoadState = 'idle' | 'loading' | 'ready' | 'error'
|
||||||
@@ -184,8 +184,9 @@ function normalizeNotification(notification: NotificationConfigInput, index: num
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeNotificationList(value: NotificationConfigInput[] = []) {
|
/** 将后端尚未创建的空配置与已有渠道统一为可编辑列表。 */
|
||||||
return value.map((notification, index) => normalizeNotification(notification, index))
|
function normalizeNotificationList(value?: NotificationConfigInput[] | null) {
|
||||||
|
return (value ?? []).map((notification, index) => normalizeNotification(notification, index))
|
||||||
}
|
}
|
||||||
|
|
||||||
function notificationNameKey(name: string) {
|
function notificationNameKey(name: string) {
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ const templateFixture = {
|
|||||||
subscribeComplete: '{}',
|
subscribeComplete: '{}',
|
||||||
}
|
}
|
||||||
|
|
||||||
function mockLoadedSettings(channels = notificationsFixture) {
|
function mockLoadedSettings(channels: typeof notificationsFixture | null = notificationsFixture) {
|
||||||
mocks.apiGet.mockImplementation((endpoint: string) => {
|
mocks.apiGet.mockImplementation((endpoint: string) => {
|
||||||
if (endpoint === 'system/setting/Notifications') {
|
if (endpoint === 'system/setting/Notifications') {
|
||||||
return { success: true, data: { value: structuredClone(channels) } }
|
return { success: true, data: { value: structuredClone(channels) } }
|
||||||
@@ -178,6 +178,27 @@ describe('AccountSettingNotification', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('treats a null notification configuration as empty and allows the first channel to be saved', async () => {
|
||||||
|
mockLoadedSettings(null)
|
||||||
|
const user = userEvent.setup()
|
||||||
|
await renderNotificationSettings()
|
||||||
|
|
||||||
|
await waitFor(() => expect(mocks.apiGet).toHaveBeenCalledWith('system/setting/Notifications'))
|
||||||
|
expect(screen.queryByText('加载通知渠道失败,请刷新后重试')).not.toBeInTheDocument()
|
||||||
|
|
||||||
|
const channelCard = getCard('通知渠道')
|
||||||
|
await user.click(channelCard.getAllByRole('button').at(-1)!)
|
||||||
|
await user.click(await screen.findByText('Telegram', { selector: '.v-list-item-title' }))
|
||||||
|
expect(screen.getByText('通知1 / telegram')).toBeInTheDocument()
|
||||||
|
|
||||||
|
await user.click(channelCard.getByRole('button', { name: '保存' }))
|
||||||
|
await waitFor(() =>
|
||||||
|
expect(mocks.apiPost).toHaveBeenCalledWith('notification/config', [
|
||||||
|
expect.objectContaining({ id: expect.any(String), name: '通知1', type: 'telegram' }),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
it('creates a unique automatic channel name, removes channels, and saves the current order once', async () => {
|
it('creates a unique automatic channel name, removes channels, and saves the current order once', async () => {
|
||||||
const user = userEvent.setup()
|
const user = userEvent.setup()
|
||||||
await renderNotificationSettings()
|
await renderNotificationSettings()
|
||||||
|
|||||||
Reference in New Issue
Block a user