From 7b1aa93148d5cb019f6687dff821c4660aac1231 Mon Sep 17 00:00:00 2001 From: "chihao.ou" Date: Wed, 7 Oct 2026 14:50:53 +0800 Subject: [PATCH] fix(groups): preserve numeric values when editing RPM overrides --- .../admin/group/GroupRPMOverridesModal.vue | 5 +- .../GroupRPMOverridesModal.edit.spec.ts | 47 +++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 frontend/src/components/admin/group/__tests__/GroupRPMOverridesModal.edit.spec.ts diff --git a/frontend/src/components/admin/group/GroupRPMOverridesModal.vue b/frontend/src/components/admin/group/GroupRPMOverridesModal.vue index 4398780143..ad480017d0 100644 --- a/frontend/src/components/admin/group/GroupRPMOverridesModal.vue +++ b/frontend/src/components/admin/group/GroupRPMOverridesModal.vue @@ -356,8 +356,9 @@ const handleAddLocal = () => { } const updateLocalRpm = (userId: number, value: string) => { - const num = parseInt(value, 10) - if (isNaN(num) || num < 0) return + if (!value.trim()) return + const num = Number(value) + if (!Number.isInteger(num) || num < 0) return const entry = localEntries.value.find(e => e.user_id === userId) if (entry) entry.rpm_override = num } diff --git a/frontend/src/components/admin/group/__tests__/GroupRPMOverridesModal.edit.spec.ts b/frontend/src/components/admin/group/__tests__/GroupRPMOverridesModal.edit.spec.ts new file mode 100644 index 0000000000..45b9d2e700 --- /dev/null +++ b/frontend/src/components/admin/group/__tests__/GroupRPMOverridesModal.edit.spec.ts @@ -0,0 +1,47 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import { enableAutoUnmount, flushPromises, mount } from '@vue/test-utils' +import type { AdminGroup } from '@/types' +import GroupRPMOverridesModal from '../GroupRPMOverridesModal.vue' + +const mocks = vi.hoisted(() => ({ getGroupRPMOverrides: vi.fn(), batchSetGroupRPMOverrides: vi.fn() })) +vi.mock('@/api/admin', () => ({ adminAPI: { groups: mocks } })) +vi.mock('@/stores/app', () => ({ useAppStore: () => ({ showSuccess: vi.fn(), showError: vi.fn() }) })) +vi.mock('vue-i18n', () => ({ useI18n: () => ({ t: (key: string) => key }) })) +enableAutoUnmount(afterEach) + +beforeEach(() => { + vi.resetAllMocks() + mocks.getGroupRPMOverrides.mockResolvedValue([ + { user_id: 7, user_email: 'user@example.com', user_name: '', user_status: 'active', rpm_override: 100 } + ]) +}) + +async function openEditor() { + const wrapper = mount(GroupRPMOverridesModal, { + props: { show: false, group: { id: 1, name: 'Group', platform: 'openai' } as AdminGroup }, + global: { stubs: { + BaseDialog: { props: ['show'], template: '
' }, + Icon: true, PlatformIcon: true, Pagination: true + } } + }) + await wrapper.setProps({ show: true }) + await flushPromises() + return wrapper +} + +describe('existing RPM override edits', () => { + it.each(['', '1.5', '-1'])('does not save invalid RPM %j', async (value) => { + const wrapper = await openEditor() + await wrapper.get('tbody input[type="number"]').setValue(value) + expect(wrapper.findAll('button').some(button => button.text() === 'common.save')).toBe(false) + expect(mocks.batchSetGroupRPMOverrides).not.toHaveBeenCalled() + }) + + it.each([['0', 0], ['200', 200], ['1e3', 1000]])('saves %s as %i', async (input, expected) => { + const wrapper = await openEditor() + await wrapper.get('tbody input[type="number"]').setValue(input) + await wrapper.findAll('button').find(button => button.text() === 'common.save')!.trigger('click') + await flushPromises() + expect(mocks.batchSetGroupRPMOverrides).toHaveBeenCalledWith(1, [{ user_id: 7, rpm_override: expected }]) + }) +})