// @vitest-environment jsdom import { beforeEach, describe, expect, it, vi } from 'vitest' import { mount } from '@vue/test-utils' import { defineComponent } from 'vue' import ArcoVue from '@arco-design/web-vue' const mockSettingsStore = vi.hoisted(() => ({ gatewayAutoStart: { enabled: true, include: ['default'], exclude: [] as string[] }, saveSection: vi.fn().mockResolvedValue(undefined), updateLocal: vi.fn((section: string, values: Record) => { if (section === 'gatewayAutoStart') { mockSettingsStore.gatewayAutoStart = { ...mockSettingsStore.gatewayAutoStart, ...values } } }), })) const mockProfilesStore = vi.hoisted(() => ({ profiles: [{ name: 'default' }, { name: 'reviewer' }, { name: 'scratch' }], })) vi.mock('@/stores/hermes/settings', () => ({ useSettingsStore: () => mockSettingsStore, })) vi.mock('@/stores/hermes/profiles', () => ({ useProfilesStore: () => mockProfilesStore, })) vi.mock('vue-i18n', () => ({ useI18n: () => ({ t: (key: string) => key, }), })) vi.mock('@/composables/useMessage', () => ({ useMessage: () => ({ success: vi.fn(), error: vi.fn() }), })) import GatewayAutoStartSettings from '@/components/hermes/settings/GatewayAutoStartSettings.vue' // A single click has to stand in for a full Arco dropdown interaction: the // multi-select yields a duplicated name (normalizeProfileList must dedupe it) // and the mode select flips between 'include' and 'all'. const ASelectStub = defineComponent({ name: 'Select', props: { modelValue: { type: [String, Array], default: '' }, multiple: Boolean, placeholder: String, }, emits: ['update:modelValue'], template: ``, methods: { onClick() { this.$emit( 'update:modelValue', this.multiple ? ['default', 'reviewer', 'default'] : this.modelValue === 'include' ? 'all' : 'include', ) }, }, }) // `app.use(ArcoVue)` registers components globally, so stubs only match Arco's // internal component names, not the kebab-case template tags. const arcoGlobal = { plugins: [ArcoVue], stubs: { Select: ASelectStub }, } /** The SettingRow whose label renders as `label`. */ function rowByLabel(wrapper: any, label: string) { const row = wrapper .findAll('.setting-row') .find((node: any) => node.get('.setting-row-label').text() === label) if (!row) throw new Error(`no SettingRow labelled "${label}"`) return row } describe('GatewayAutoStartSettings', () => { beforeEach(() => { vi.clearAllMocks() mockSettingsStore.gatewayAutoStart = { enabled: true, include: ['default'], exclude: [] } }) it('saves gateway auto-start enabled and include-list settings through app config section', async () => { const wrapper = mount(GatewayAutoStartSettings, { global: { plugins: arcoGlobal.plugins, stubs: { ...arcoGlobal.stubs, SettingRow: { props: ['label', 'hint'], template: '
{{ label }}
', }, }, }, }) expect(wrapper.text()).toContain('settings.gatewayAutoStart.title') await rowByLabel(wrapper, 'settings.gatewayAutoStart.enabled').get('.arco-switch').trigger('click') await Promise.resolve() expect(mockSettingsStore.updateLocal).toHaveBeenCalledWith('gatewayAutoStart', { enabled: false }) expect(mockSettingsStore.saveSection).toHaveBeenCalledWith('gatewayAutoStart', { enabled: false }, { restart: false }) const includeSelect = rowByLabel(wrapper, 'settings.gatewayAutoStart.include').get('.gateway-profile-select') await includeSelect.trigger('click') await Promise.resolve() expect(mockSettingsStore.saveSection).toHaveBeenLastCalledWith( 'gatewayAutoStart', { include: ['default', 'reviewer'], exclude: null }, { restart: false }, ) await rowByLabel(wrapper, 'settings.gatewayAutoStart.mode').get('.gateway-mode').trigger('click') await Promise.resolve() expect(mockSettingsStore.saveSection).toHaveBeenLastCalledWith( 'gatewayAutoStart', { include: null }, { restart: false }, ) }) })