mirror of
https://github.com/vrcx-team/VRCX.git
synced 2026-04-06 00:32:02 +02:00
355 lines
12 KiB
JavaScript
355 lines
12 KiB
JavaScript
|
|
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
|
import { createPinia, setActivePinia } from 'pinia';
|
|
import { ref } from 'vue';
|
|
|
|
import en from '../../localization/en.json';
|
|
|
|
vi.mock('../../views/Feed/Feed.vue', () => ({
|
|
default: { template: '<div />' }
|
|
}));
|
|
vi.mock('../../views/Feed/columns.jsx', () => ({ columns: [] }));
|
|
vi.mock('../../plugins/router', () => ({
|
|
router: {
|
|
beforeEach: vi.fn(),
|
|
push: vi.fn(),
|
|
replace: vi.fn(),
|
|
currentRoute: ref({ path: '/', name: '', meta: {} }),
|
|
isReady: vi.fn().mockResolvedValue(true)
|
|
},
|
|
initRouter: vi.fn()
|
|
}));
|
|
vi.mock('vue-router', async (importOriginal) => {
|
|
const actual = await importOriginal();
|
|
return {
|
|
...actual,
|
|
useRouter: vi.fn(() => ({
|
|
push: vi.fn(),
|
|
replace: vi.fn(),
|
|
currentRoute: ref({ path: '/', name: '', meta: {} })
|
|
}))
|
|
};
|
|
});
|
|
vi.mock('../../plugins/interopApi', () => ({ initInteropApi: vi.fn() }));
|
|
vi.mock('../../services/database', () => ({
|
|
database: new Proxy(
|
|
{},
|
|
{
|
|
get: (_target, prop) => {
|
|
if (prop === '__esModule') return false;
|
|
return vi.fn().mockResolvedValue(null);
|
|
}
|
|
}
|
|
)
|
|
}));
|
|
vi.mock('../../services/config', () => ({
|
|
default: {
|
|
init: vi.fn(),
|
|
getString: vi.fn().mockResolvedValue('{}'),
|
|
setString: vi.fn(),
|
|
getBool: vi.fn().mockImplementation((_k, d) => d ?? false),
|
|
setBool: vi.fn(),
|
|
getInt: vi.fn().mockImplementation((_k, d) => d ?? 0),
|
|
setInt: vi.fn(),
|
|
getFloat: vi.fn().mockImplementation((_k, d) => d ?? 0),
|
|
setFloat: vi.fn(),
|
|
getObject: vi.fn().mockReturnValue(null),
|
|
setObject: vi.fn(),
|
|
getArray: vi.fn().mockReturnValue([]),
|
|
setArray: vi.fn(),
|
|
remove: vi.fn()
|
|
}
|
|
}));
|
|
vi.mock('../../services/jsonStorage', () => ({ default: vi.fn() }));
|
|
vi.mock('../../services/watchState', () => ({
|
|
watchState: { isLoggedIn: false }
|
|
}));
|
|
vi.mock('vue-i18n', async (importOriginal) => {
|
|
const actual = await importOriginal();
|
|
const i18n = actual.createI18n({
|
|
locale: 'en',
|
|
fallbackLocale: 'en',
|
|
legacy: false,
|
|
missingWarn: false,
|
|
fallbackWarn: false,
|
|
messages: { en }
|
|
});
|
|
return {
|
|
...actual,
|
|
useI18n: () => i18n.global
|
|
};
|
|
});
|
|
|
|
const mockShowUserDialog = vi.fn();
|
|
const mockShowAvatarDialog = vi.fn();
|
|
const mockShowGroupDialog = vi.fn();
|
|
const mockShowWorldDialog = vi.fn();
|
|
const mockGetInstanceFromShortName = vi.fn();
|
|
const mockGroupStrictsearch = vi.fn();
|
|
|
|
vi.mock('../user', () => ({
|
|
useUserStore: () => ({
|
|
cachedUsers: new Map(),
|
|
showUserDialogHistory: new Set(),
|
|
currentUser: ref({ id: 'usr_me', homeLocation: '' })
|
|
})
|
|
}));
|
|
vi.mock('../avatar', () => ({
|
|
useAvatarStore: () => ({})
|
|
}));
|
|
vi.mock('../group', () => ({
|
|
useGroupStore: () => ({})
|
|
}));
|
|
vi.mock('../world', () => ({
|
|
useWorldStore: () => ({})
|
|
}));
|
|
|
|
vi.mock('../friend', () => ({
|
|
useFriendStore: () => ({
|
|
friends: new Map()
|
|
})
|
|
}));
|
|
vi.mock('../modal', () => ({
|
|
useModalStore: () => ({
|
|
prompt: vi.fn().mockResolvedValue({ ok: false, value: '' })
|
|
})
|
|
}));
|
|
vi.mock('../settings/appearance', () => ({
|
|
useAppearanceSettingsStore: () => ({
|
|
appLanguage: 'en'
|
|
})
|
|
}));
|
|
|
|
function makeApiMock() {
|
|
return {
|
|
instanceRequest: {
|
|
getInstanceFromShortName: (...args) =>
|
|
mockGetInstanceFromShortName(...args)
|
|
},
|
|
userRequest: {
|
|
getUsers: vi.fn().mockResolvedValue({ json: [] })
|
|
},
|
|
groupRequest: {
|
|
groupStrictsearch: (...args) => mockGroupStrictsearch(...args)
|
|
},
|
|
queryRequest: {},
|
|
miscRequest: {}
|
|
};
|
|
}
|
|
vi.mock('../../api', () => makeApiMock());
|
|
vi.mock('../../api/', () => makeApiMock());
|
|
|
|
vi.mock('../../coordinators/userCoordinator', () => ({
|
|
showUserDialog: (...args) => mockShowUserDialog(...args),
|
|
lookupUser: vi.fn(),
|
|
applyUser: vi.fn()
|
|
}));
|
|
vi.mock('../../coordinators/avatarCoordinator', () => ({
|
|
showAvatarDialog: (...args) => mockShowAvatarDialog(...args),
|
|
getAvatarName: vi.fn()
|
|
}));
|
|
vi.mock('../../coordinators/groupCoordinator', () => ({
|
|
showGroupDialog: (...args) => mockShowGroupDialog(...args)
|
|
}));
|
|
vi.mock('../../coordinators/worldCoordinator', () => ({
|
|
showWorldDialog: (...args) => mockShowWorldDialog(...args)
|
|
}));
|
|
|
|
vi.mock('vue-sonner', () => ({
|
|
toast: {
|
|
success: vi.fn(),
|
|
error: vi.fn(),
|
|
warning: vi.fn(),
|
|
dismiss: vi.fn()
|
|
}
|
|
}));
|
|
|
|
import { useSearchStore } from '../search';
|
|
|
|
describe('useSearchStore', () => {
|
|
let store;
|
|
|
|
beforeEach(() => {
|
|
setActivePinia(createPinia());
|
|
store = useSearchStore();
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe('directAccessParse', () => {
|
|
test('returns false for empty input', () => {
|
|
expect(store.directAccessParse('')).toBe(false);
|
|
expect(store.directAccessParse(null)).toBe(false);
|
|
expect(store.directAccessParse(undefined)).toBe(false);
|
|
});
|
|
|
|
test('opens user dialog for usr_ prefix', () => {
|
|
store.directAccessParse('usr_abc123');
|
|
expect(mockShowUserDialog).toHaveBeenCalledWith('usr_abc123');
|
|
});
|
|
|
|
test('opens user dialog for 10-char alphanumeric ID', () => {
|
|
store.directAccessParse('Ab3dEf7h9J');
|
|
expect(mockShowUserDialog).toHaveBeenCalledWith('Ab3dEf7h9J');
|
|
});
|
|
|
|
test('opens avatar dialog for avtr_ prefix', () => {
|
|
store.directAccessParse('avtr_abc123');
|
|
expect(mockShowAvatarDialog).toHaveBeenCalledWith('avtr_abc123');
|
|
});
|
|
|
|
test('opens avatar dialog for b_ prefix', () => {
|
|
store.directAccessParse('b_something');
|
|
expect(mockShowAvatarDialog).toHaveBeenCalledWith('b_something');
|
|
});
|
|
|
|
test('opens group dialog for grp_ prefix', () => {
|
|
store.directAccessParse('grp_abc123');
|
|
expect(mockShowGroupDialog).toHaveBeenCalledWith('grp_abc123');
|
|
});
|
|
|
|
test('parses vrchat.com user URL', () => {
|
|
store.directAccessParse('https://vrchat.com/home/user/usr_abc123');
|
|
expect(mockShowUserDialog).toHaveBeenCalledWith('usr_abc123');
|
|
});
|
|
|
|
test('parses vrchat.com avatar URL', () => {
|
|
store.directAccessParse(
|
|
'https://vrchat.com/home/avatar/avtr_abc123'
|
|
);
|
|
expect(mockShowAvatarDialog).toHaveBeenCalledWith('avtr_abc123');
|
|
});
|
|
|
|
test('parses vrchat.com group URL', () => {
|
|
store.directAccessParse('https://vrchat.com/home/group/grp_abc123');
|
|
expect(mockShowGroupDialog).toHaveBeenCalledWith('grp_abc123');
|
|
});
|
|
|
|
test('parses vrc.group short URL', () => {
|
|
mockGroupStrictsearch.mockResolvedValue({ json: [] });
|
|
store.directAccessParse('https://vrc.group/ABC.1234');
|
|
expect(mockGroupStrictsearch).toHaveBeenCalledWith({
|
|
query: 'ABC.1234'
|
|
});
|
|
});
|
|
|
|
test('parses group short code (e.g. ABCD.1234)', () => {
|
|
mockGroupStrictsearch.mockResolvedValue({ json: [] });
|
|
store.directAccessParse('ABCD.1234');
|
|
expect(mockGroupStrictsearch).toHaveBeenCalledWith({
|
|
query: 'ABCD.1234'
|
|
});
|
|
});
|
|
|
|
test('returns false for unrecognized input', () => {
|
|
expect(store.directAccessParse('hello world')).toBe(false);
|
|
});
|
|
|
|
test('returns false for short vrchat URL with insufficient path segments', () => {
|
|
expect(store.directAccessParse('https://vrchat.com/home')).toBe(
|
|
false
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('directAccessWorld', () => {
|
|
test('returns false for unrecognized input', () => {
|
|
expect(store.directAccessWorld('hello')).toBe(false);
|
|
});
|
|
|
|
test('opens world dialog for wrld_ prefix', () => {
|
|
store.directAccessWorld('wrld_abc123:12345~friends');
|
|
expect(mockShowWorldDialog).toHaveBeenCalledWith(
|
|
'wrld_abc123:12345~friends'
|
|
);
|
|
});
|
|
|
|
test('opens world dialog for wld_ prefix', () => {
|
|
store.directAccessWorld('wld_abc');
|
|
expect(mockShowWorldDialog).toHaveBeenCalledWith('wld_abc');
|
|
});
|
|
|
|
test('opens world dialog for o_ prefix', () => {
|
|
store.directAccessWorld('o_test123');
|
|
expect(mockShowWorldDialog).toHaveBeenCalledWith('o_test123');
|
|
});
|
|
|
|
test('handles wrld_ with &instanceId= by internally rewriting to URL', () => {
|
|
store.directAccessWorld('wrld_abc&instanceId=123');
|
|
expect(mockShowWorldDialog).toHaveBeenCalledWith('wrld_abc:123');
|
|
});
|
|
|
|
test('resolves 8-char shortName via API', async () => {
|
|
mockGetInstanceFromShortName.mockResolvedValue({
|
|
json: { location: 'wrld_abc:123', shortName: 'AbCdEfGh' }
|
|
});
|
|
await store.directAccessWorld('AbCdEfGh');
|
|
expect(mockGetInstanceFromShortName).toHaveBeenCalledWith({
|
|
shortName: 'AbCdEfGh'
|
|
});
|
|
expect(mockShowWorldDialog).toHaveBeenCalledWith(
|
|
'wrld_abc:123',
|
|
'AbCdEfGh'
|
|
);
|
|
});
|
|
|
|
test('resolves vrch.at short URL via API', async () => {
|
|
mockGetInstanceFromShortName.mockResolvedValue({
|
|
json: { location: 'wrld_abc:123', shortName: 'XyZ12345' }
|
|
});
|
|
await store.directAccessWorld('https://vrch.at/XyZ12345');
|
|
expect(mockGetInstanceFromShortName).toHaveBeenCalledWith({
|
|
shortName: 'XyZ12345'
|
|
});
|
|
expect(mockShowWorldDialog).toHaveBeenCalledWith(
|
|
'wrld_abc:123',
|
|
'XyZ12345'
|
|
);
|
|
});
|
|
|
|
test('parses vrchat.com/home/world/ URL', () => {
|
|
store.directAccessWorld(
|
|
'https://vrchat.com/home/world/wrld_abc123'
|
|
);
|
|
expect(mockShowWorldDialog).toHaveBeenCalledWith('wrld_abc123');
|
|
});
|
|
|
|
test('parses launch URL with worldId only', () => {
|
|
store.directAccessWorld(
|
|
'https://vrchat.com/home/launch?worldId=wrld_abc'
|
|
);
|
|
expect(mockShowWorldDialog).toHaveBeenCalledWith('wrld_abc');
|
|
});
|
|
|
|
test('parses launch URL with worldId and instanceId', () => {
|
|
store.directAccessWorld(
|
|
'https://vrchat.com/home/launch?worldId=wrld_abc&instanceId=123'
|
|
);
|
|
expect(mockShowWorldDialog).toHaveBeenCalledWith('wrld_abc:123');
|
|
});
|
|
|
|
test('parses launch URL with shortName via API', async () => {
|
|
mockGetInstanceFromShortName.mockResolvedValue({
|
|
json: {
|
|
location: 'wrld_abc:123',
|
|
shortName: 'myShort1'
|
|
}
|
|
});
|
|
await store.directAccessWorld(
|
|
'https://vrchat.com/home/launch?worldId=wrld_abc&instanceId=123&shortName=myShort1'
|
|
);
|
|
expect(mockGetInstanceFromShortName).toHaveBeenCalledWith({
|
|
shortName: 'myShort1'
|
|
});
|
|
expect(mockShowWorldDialog).toHaveBeenCalledWith(
|
|
'wrld_abc:123',
|
|
'myShort1'
|
|
);
|
|
});
|
|
|
|
test('handles /home/ relative path by prepending https://vrchat.com', () => {
|
|
store.directAccessWorld('/home/world/wrld_relpath');
|
|
expect(mockShowWorldDialog).toHaveBeenCalledWith('wrld_relpath');
|
|
});
|
|
});
|
|
});
|