This commit is contained in:
pa
2026-03-12 16:57:51 +09:00
parent c72209f56d
commit 08e160ff69
39 changed files with 3407 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { mount } from '@vue/test-utils';
const mocks = vi.hoisted(() => ({
discordStore: {
setDiscordActive: vi.fn(),
setDiscordInstance: vi.fn(),
setDiscordHideInvite: vi.fn(),
setDiscordJoinButton: vi.fn(),
setDiscordHideImage: vi.fn(),
setDiscordShowPlatform: vi.fn(),
setDiscordWorldIntegration: vi.fn(),
setDiscordWorldNameAsDiscordStatus: vi.fn(),
saveDiscordOption: vi.fn(),
discordActive: { __v_isRef: true, value: true },
discordInstance: { __v_isRef: true, value: true },
discordHideInvite: { __v_isRef: true, value: false },
discordJoinButton: { __v_isRef: true, value: true },
discordHideImage: { __v_isRef: true, value: false },
discordShowPlatform: { __v_isRef: true, value: true },
discordWorldIntegration: { __v_isRef: true, value: true },
discordWorldNameAsDiscordStatus: { __v_isRef: true, value: false }
},
showVRChatConfig: vi.fn()
}));
vi.mock('pinia', async (i) => ({ ...(await i()), storeToRefs: (s) => s }));
vi.mock('vue-i18n', () => ({ useI18n: () => ({ t: (k) => k }) }));
vi.mock('../../../../../stores', () => ({
useDiscordPresenceSettingsStore: () => mocks.discordStore,
useAdvancedSettingsStore: () => ({ showVRChatConfig: (...a) => mocks.showVRChatConfig(...a) })
}));
vi.mock('../../SimpleSwitch.vue', () => ({
default: {
props: ['label', 'disabled'],
emits: ['change'],
template:
'<div data-testid="simple-switch" :data-label="label" :data-disabled="disabled"><button class="emit-change" @click="$emit(\'change\', true)" /></div>'
}
}));
import DiscordPresenceTab from '../DiscordPresenceTab.vue';
describe('DiscordPresenceTab.vue', () => {
beforeEach(() => {
mocks.discordStore.discordActive.value = true;
mocks.discordStore.discordInstance.value = true;
mocks.discordStore.setDiscordActive.mockClear();
mocks.discordStore.saveDiscordOption.mockClear();
mocks.showVRChatConfig.mockClear();
});
it('opens VRChat config and handles switch changes', async () => {
const wrapper = mount(DiscordPresenceTab);
const tooltipRow = wrapper
.findAll('div.options-container-item')
.find((node) => node.text().includes('view.settings.discord_presence.discord_presence.enable_tooltip'));
await tooltipRow.trigger('click');
expect(mocks.showVRChatConfig).toHaveBeenCalledTimes(1);
await wrapper.findAll('.emit-change')[0].trigger('click');
expect(mocks.discordStore.setDiscordActive).toHaveBeenCalledTimes(1);
expect(mocks.discordStore.saveDiscordOption).toHaveBeenCalled();
});
it('passes disabled state to dependent switches when discord is disabled', () => {
mocks.discordStore.discordActive.value = false;
const wrapper = mount(DiscordPresenceTab);
const worldIntegration = wrapper
.findAll('[data-testid="simple-switch"]')
.find((node) =>
node.attributes('data-label')?.includes('world_integration')
);
expect(worldIntegration?.attributes('data-disabled')).toBe('true');
});
});

View File

@@ -0,0 +1,31 @@
import { describe, expect, it, vi } from 'vitest';
import { mount } from '@vue/test-utils';
vi.mock('../../WristOverlaySettings.vue', () => ({
default: {
emits: ['open-feed-filters'],
template:
'<button data-testid="open-filters" @click="$emit(\'open-feed-filters\')">open</button>'
}
}));
vi.mock('../../../dialogs/FeedFiltersDialog.vue', () => ({
default: {
props: ['feedFiltersDialogMode'],
template: '<div data-testid="feed-dialog" :data-mode="feedFiltersDialogMode" />'
}
}));
import WristOverlayTab from '../WristOverlayTab.vue';
describe('WristOverlayTab.vue', () => {
it('sets feed dialog mode to wrist when child emits open-feed-filters', async () => {
const wrapper = mount(WristOverlayTab);
expect(wrapper.get('[data-testid="feed-dialog"]').attributes('data-mode')).toBe('');
await wrapper.get('[data-testid="open-filters"]').trigger('click');
expect(wrapper.get('[data-testid="feed-dialog"]').attributes('data-mode')).toBe('wrist');
});
});

View File

@@ -0,0 +1,57 @@
import { describe, expect, it, vi } from 'vitest';
import { mount } from '@vue/test-utils';
vi.mock('../../../../components/ui/switch', () => ({
Switch: {
props: ['modelValue', 'disabled'],
emits: ['update:modelValue'],
template:
'<button data-testid="switch" :data-disabled="disabled" @click="$emit(\'update:modelValue\', !modelValue)">switch</button>'
}
}));
vi.mock('lucide-vue-next', () => ({
Info: { template: '<i data-testid="info" />' }
}));
import SimpleSwitch from '../SimpleSwitch.vue';
describe('SimpleSwitch.vue', () => {
it('emits change when inner switch updates', async () => {
const wrapper = mount(SimpleSwitch, {
props: {
label: 'Label',
value: false
},
global: {
stubs: {
TooltipWrapper: { template: '<span data-testid="tooltip"><slot /></span>' }
}
}
});
await wrapper.get('[data-testid="switch"]').trigger('click');
expect(wrapper.emitted('change')).toEqual([[true]]);
});
it('applies long label style and renders tooltip', () => {
const wrapper = mount(SimpleSwitch, {
props: {
label: 'Long',
value: true,
longLabel: true,
tooltip: 'tip',
disabled: true
},
global: {
stubs: {
TooltipWrapper: { template: '<span data-testid="tooltip"><slot /></span>' }
}
}
});
expect(wrapper.get('.name').attributes('style')).toContain('width: 300px');
expect(wrapper.find('[data-testid="tooltip"]').exists()).toBe(true);
expect(wrapper.get('[data-testid="switch"]').attributes('data-disabled')).toBe('true');
});
});

View File

@@ -0,0 +1,127 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { mount } from '@vue/test-utils';
const mocks = vi.hoisted(() => ({
notificationsStore: {
openVR: { value: true },
setOpenVR: vi.fn()
},
wristStore: {
overlayWrist: { value: true },
hidePrivateFromFeed: { value: false },
openVRAlways: { value: false },
overlaybutton: { value: false },
overlayHand: { value: '1' },
vrBackgroundEnabled: { value: false },
minimalFeed: { value: false },
hideDevicesFromFeed: { value: false },
vrOverlayCpuUsage: { value: false },
hideUptimeFromFeed: { value: false },
pcUptimeOnFeed: { value: false },
setOverlayWrist: vi.fn(),
setHidePrivateFromFeed: vi.fn(),
setOpenVRAlways: vi.fn(),
setOverlaybutton: vi.fn(),
setOverlayHand: vi.fn(),
setVrBackgroundEnabled: vi.fn(),
setMinimalFeed: vi.fn(),
setHideDevicesFromFeed: vi.fn(),
setVrOverlayCpuUsage: vi.fn(),
setHideUptimeFromFeed: vi.fn(),
setPcUptimeOnFeed: vi.fn()
},
saveOpenVROption: vi.fn()
}));
vi.mock('pinia', async (i) => ({ ...(await i()), storeToRefs: (s) => s }));
vi.mock('vue-i18n', () => ({ useI18n: () => ({ t: (k) => k }) }));
vi.mock('../../../../stores', () => ({
useNotificationsSettingsStore: () => mocks.notificationsStore,
useWristOverlaySettingsStore: () => mocks.wristStore,
useVrStore: () => ({ saveOpenVROption: (...a) => mocks.saveOpenVROption(...a) })
}));
vi.mock('@/components/ui/button', () => ({
Button: {
props: ['disabled'],
emits: ['click'],
template:
'<button data-testid="filters-btn" :disabled="disabled" @click="$emit(\'click\')"><slot /></button>'
}
}));
vi.mock('../../../../components/ui/radio-group', () => ({
RadioGroup: {
props: ['modelValue', 'disabled'],
emits: ['update:modelValue'],
template:
'<div data-testid="radio-group" :data-disabled="disabled"><button data-testid="radio-false" @click="$emit(\'update:modelValue\', \'false\')" /><button data-testid="radio-true" @click="$emit(\'update:modelValue\', \'true\')" /><slot /></div>'
},
RadioGroupItem: { template: '<div />' }
}));
vi.mock('../../../../components/ui/toggle-group', () => ({
ToggleGroup: {
emits: ['update:model-value'],
template:
'<div data-testid="toggle-group"><button data-testid="toggle-right" @click="$emit(\'update:model-value\', \'2\')" /><slot /></div>'
},
ToggleGroupItem: { template: '<div><slot /></div>' }
}));
vi.mock('../SimpleSwitch.vue', () => ({
default: {
props: ['label'],
emits: ['change'],
template:
'<div data-testid="simple-switch" :data-label="label"><button class="emit-change" @click="$emit(\'change\', true)" /></div>'
}
}));
import WristOverlaySettings from '../WristOverlaySettings.vue';
describe('WristOverlaySettings.vue', () => {
beforeEach(() => {
mocks.notificationsStore.openVR.value = true;
mocks.wristStore.overlayWrist.value = true;
mocks.wristStore.openVRAlways.value = false;
mocks.wristStore.overlaybutton.value = false;
mocks.notificationsStore.setOpenVR.mockClear();
mocks.wristStore.setOpenVRAlways.mockClear();
mocks.wristStore.setOverlaybutton.mockClear();
mocks.wristStore.setOverlayHand.mockClear();
mocks.saveOpenVROption.mockClear();
});
it('emits open-feed-filters and handles switch/radio/toggle updates', async () => {
const wrapper = mount(WristOverlaySettings);
await wrapper.get('[data-testid="filters-btn"]').trigger('click');
expect(wrapper.emitted('open-feed-filters')).toBeTruthy();
await wrapper.findAll('.emit-change')[0].trigger('click');
expect(mocks.notificationsStore.setOpenVR).toHaveBeenCalledTimes(1);
expect(mocks.saveOpenVROption).toHaveBeenCalled();
const radioGroups = wrapper.findAll('[data-testid="radio-group"]');
await radioGroups[0].get('[data-testid="radio-true"]').trigger('click');
expect(mocks.wristStore.setOpenVRAlways).toHaveBeenCalledTimes(1);
await radioGroups[1].get('[data-testid="radio-true"]').trigger('click');
expect(mocks.wristStore.setOverlaybutton).toHaveBeenCalledTimes(1);
await wrapper.get('[data-testid="toggle-right"]').trigger('click');
expect(mocks.wristStore.setOverlayHand).toHaveBeenCalledWith('2');
});
it('does not toggle openVRAlways when the value is unchanged', async () => {
mocks.wristStore.openVRAlways.value = true;
const wrapper = mount(WristOverlaySettings);
const firstRadio = wrapper.findAll('[data-testid="radio-group"]')[0];
await firstRadio.get('[data-testid="radio-true"]').trigger('click');
expect(mocks.wristStore.setOpenVRAlways).not.toHaveBeenCalled();
});
});